changeset 223:60c3ab698350

merged.
author "Rex Tsai <chihchun@kalug.linux.org.tw>"
date Tue, 04 Nov 2008 18:34:00 +0800
parents 4a051d178456 (diff) 93f29a185851 (current diff)
children 8e9f2848f8cd
files
diffstat 15 files changed, 847 insertions(+), 253 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sun Nov 02 11:59:31 2008 +0800
+++ b/.hgignore	Tue Nov 04 18:34:00 2008 +0800
@@ -7,6 +7,7 @@
 *.html
 *.sh
 *.txt
+*-dump.yaml
 excel
 perl
 samples
--- a/Ikariam.pm	Sun Nov 02 11:59:31 2008 +0800
+++ b/Ikariam.pm	Tue Nov 04 18:34:00 2008 +0800
@@ -116,33 +116,11 @@
         user => $user,
         pass => $pass,
         debug => undef,
-        buildingIDs => {
-            townHall =>  0,
-            townhall =>  0,
-            port =>  3,
-            academy =>  4,
-            shipyard =>  5,
-            barracks =>  6,
-            warehouse =>  7,
-            wall =>  8,
-            tavern =>  9,
-            museum =>  10,
-            palace =>  11,
-            embassy =>  12,
-            branchOffice =>  13,
-            workshop =>  15,
-            'workshop-army' =>  15,
-            'workshop-fleet' =>  15,
-            safehouse =>  16,
-            palaceColony =>  17,
-            resource =>  1,
-            tradegood =>  2
-        }
     };
 
 
     # if debug
-    # LWP::Debug::level('+trace');
+    LWP::Debug::level('+trace');
 
     $self->{mech}->cookie_jar(HTTP::Cookies->new(file => "/tmp/ikariam-cookies.txt", autosave => 1));
     $self->{mech}->default_headers->push_header('Accept-Encoding', 'deflate');
@@ -312,23 +290,18 @@
                 delete($info{'ally'}) 
             } else {
                 my $href = $extractor->find(sprintf('//li[@id="cityLocation%s"]//li[@class="ally"]/a/@href', $i));
-                # http://s2.ikariam.tw/index.php?view=allyPage&allyId=264&oldView=island&id=569
                 if($href =~ /&allyId=(\d+)&/) {
                     $info{'allyId'} = $1;
                 }
             }
 
             # Ally Id
-
             my $href = $extractor->find(sprintf('//li[@id="cityLocation%s"]//a[@class="messageSend"]/@href', $i));
-            # ?view=sendMessage&type=0&with=20204&destinationCityId=64165&oldView=island
             if ($href =~ /with=(\d+)&destinationCityId=(\d+)/) {
                 $info{'user'} = $1;
                 $info{'cityId'} = $2;
-            # ?view=sendAllyMessage&allyId=1192&oldView=island&id=721
             } else {
-                # 聯盟
-                # this is me.
+                # 聯盟 this is me.
                 my $id = $extractor->find(sprintf('//li[@id="cityLocation%s"]/a/@id', $i));
                 if($id =~ /city_(\d+)/) {
                     $info{'user'} = undef; # FIXME
@@ -372,6 +345,7 @@
     }
 }
 
+
 # for tavern only
 sub set {
     my $self = shift;
@@ -391,13 +365,171 @@
          $self->{mech}->submit_form(
                  form_number => 1,
                  fields      => {
-                 amount => $self->{'cities'}->{$cityId}->{$type}->{maxValue},
-                 }
+                         amount => $self->{'cities'}->{$cityId}->{$type}->{maxValue},
+                     }
                  );
  
     }
 }
 
+sub is_shipyard_upgrading {
+    my $self = shift;
+    my $cityId = shift;
+    my $type = "shipyard";
+
+    my $position = -1;
+    my @locations = @{$self->{'cities'}->{$cityId}->{locations}};
+    foreach (1..2) {
+        $position = $_ if($locations[$_] eq $type);
+    }
+
+    if($position != -1) {
+        my $res = $self->{mech}->get (sprintf("http://%s/index.php?view=%s&id=%s&position=%d", $self->{server}, $type, $cityId, $position));
+        if(defined(Ikariam::Extractor->new(content => $res->content)->find('//div[@class="isUpgrading"]'))) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+    return 0;
+}
+
+sub is_navy_trainning {
+    my $self = shift;
+    my $cityId = shift;
+    my $type = "shipyard";
+
+    my $position = -1;
+    my @locations = @{$self->{'cities'}->{$cityId}->{locations}};
+    foreach (1..2) {
+        $position = $_ if($locations[$_] eq $type);
+    }
+
+    if($position != -1) {
+        my $res = $self->{mech}->get (sprintf("http://%s/index.php?view=%s&id=%s&position=%d", $self->{server}, $type, $cityId, $position));
+        if(defined(Ikariam::Extractor->new(content => $res->content)->find('//div[@id="unitConstructionList"]//h4'))) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+    # FIXME we can not found the shipyard
+    return 0;
+}
+
+sub buildShips {
+    my $self = shift;
+    my $shipType = shift;
+    my $cityId = shift;
+    my $type = 'shipyard';
+
+    warn("buildShips $shipType");
+    my $position = -1;
+    my @locations = @{$self->{'cities'}->{$cityId}->{locations}};
+    foreach (1..2) {
+        $position = $_ if($locations[$_] eq $type);
+    }
+
+    if($position != -1) {
+        my $res = $self->{mech}->get (sprintf("http://%s/index.php?view=%s&id=%s&position=%d", $self->{server}, $type, $cityId, $position));
+        $self->{mech}->submit_form(
+                form_number => 1,
+                fields      => {
+                    $shipType => 1,
+                }
+                );
+    }
+}
+
+sub is_army_trainning {
+    my $self = shift;
+    my $cityId = shift;
+    my $type = "barracks";
+
+    my $position = -1;
+    my @locations = @{$self->{'cities'}->{$cityId}->{locations}};
+    foreach (2..$#locations) {
+        $position = $_ if($locations[$_] eq $type);
+    }
+
+    if($position != -1) {
+        my $res = $self->{mech}->get (sprintf("http://%s/index.php?view=%s&id=%s&position=%d", $self->{server}, $type, $cityId, $position));
+        if(defined(Ikariam::Extractor->new(content => $res->content)->find('//div[@id="unitConstructionList"]//h4'))) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+    # FIXME we can not found the shipyard
+    return 0;
+}
+
+sub is_barracks_upgrading {
+    my $self = shift;
+    my $cityId = shift;
+    my $type = 'barracks';
+
+    my $position = -1;
+    my @locations = @{$self->{'cities'}->{$cityId}->{locations}};
+    foreach (2..$#locations) {
+        $position = $_ if($locations[$_] eq $type);
+    }
+
+    if($position != -1) {
+        my $res = $self->{mech}->get (sprintf("http://%s/index.php?view=%s&id=%s&position=%d", $self->{server}, $type, $cityId, $position));
+        if(defined(Ikariam::Extractor->new(content => $res->content)->find('//div[@class="isUpgrading"]'))) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+    return 0;
+}
+
+sub buildUnits {
+    my $self = shift;
+    my $unitType = shift;
+    my $cityId = shift;
+    my $type = 'barracks';
+
+    warn("buildShips $unitType");
+    my $position = -1;
+    my @locations = @{$self->{'cities'}->{$cityId}->{locations}};
+    foreach (2..$#locations) {
+        $position = $_ if($locations[$_] eq $type);
+    }
+
+    if($position != -1) {
+        my $res = $self->{mech}->get (sprintf("http://%s/index.php?view=%s&id=%s&position=%d", $self->{server}, $type, $cityId, $position));
+        $self->{mech}->submit_form(
+                form_number => 1,
+                fields      => {
+                    $unitType => 1,
+                }
+                );
+    }
+}
+
+sub buildSpy {
+    my $self = shift;
+    my $unitType = shift;
+    my $cityId = shift;
+    my $type = 'safehouse';
+
+    my $position = -1;
+    my @locations = @{$self->{'cities'}->{$cityId}->{locations}};
+    foreach (2..$#locations) {
+        $position = $_ if($locations[$_] eq $type);
+    }
+
+    if($position != -1) {
+        my $res = $self->{mech}->get (sprintf("http://%s/index.php?view=%s&id=%s&position=%d", $self->{server}, $type, $cityId, $position));
+        my $url = 
+            Ikariam::Extractor->new(content => $res->content)->find(sprintf('//div[@class="forminput"]/a/@href'));
+        $self->{mech}->get($url) if(defined($url));
+    }
+}
+
 sub build {
     my $self = shift;
     my $type = shift;
@@ -412,16 +544,27 @@
     }
 
     if($position == -1) {
-        foreach (0..$#locations) {
-            # XXX
-            next if($_ <= 2 && ($self->{buildingIDs}->{$type} ne "workshop-fleet" &&
-                    $self->{buildingIDs}->{$type} ne "shipyard"));
-            if($locations[$_] eq undef) {
-                my $res = $self->{mech}->get(sprintf('http://%s/index.php?action=CityScreen&function=build&id=%s&position=%s&building=%d', 
-                        $self->{server}, $cityId, $_, $self->{buildingIDs}->{$type} ));
-                last;
+        my $targetPosition = undef;
+        if($type eq "wall") {
+            # 14 is wall.
+            $targetPosition = 14;
+        } else {
+            foreach (0..13) {
+                next if($_ <= 2 && ($type ne "workshop-fleet" &&
+                            $type ne "shipyard"));
+
+                if($locations[$_] eq undef) {
+                    $targetPosition = $_;
+                    last;
+                }
             }
         }
+        
+        my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=buildingGround&id=%s&position=%s', 
+                        $self->{server}, $cityId, $targetPosition));
+        my $url = 
+            Ikariam::Extractor->new(content => $res->content)->find(sprintf('//li[@class="building %s"]//a/@href', $type));
+        $self->{mech}->get($url) if(defined($url));
     } else {
         my $res = $self->{mech}->get (sprintf("http://%s/index.php?view=%s&id=%s&position=%d", $self->{server}, $type, $cityId, $position));
         my $url = Ikariam::Extractor->new(content => $res->content)->find('//a[@title="升級建築物"]/@href');
@@ -433,7 +576,7 @@
     my $self = shift;
     my $param = shift;
     # defense.
-    die("run $param not implemented yet.");
+    warn ("run $param not implemented yet.");
 }
 
 sub research
@@ -474,11 +617,19 @@
         $self->{mech}->submit_form(
                 form_number => 1,
                 fields      => {
-                cargo_army_302 => '2',
-                }
+                        cargo_army_302 => '3', # 劍士
+                    }
                 );
     } else {
-        warn ($treaty);
+        # put the id in the friends.txt file.
+        Ikariam::Cities->has_a(user => 'Ikariam::User');
+        my $city = Ikariam::Cities->retrieve($cityId);
+        my $sheep = $city->user;
+
+        open(OUT, ">>friends.txt") or Carp::carp("can not open friends.txt");
+        print OUT $sheep->name . "\n";
+        close(OUT);
+        Carp::carp($treaty);
     }
 }
 
@@ -607,7 +758,6 @@
             }
         }
     }
-    # print(Dumper($self->{'military'}));
 }
 
 sub checkMilitaryAdvisorReportView {
@@ -619,7 +769,7 @@
     my %report;
 
     $report{id} = $combatId;
-    my $c = $extractor->{doc}->toString(1);
+    my $c = $extractor->{doc}->toString(0);
     
     # FIXME 城鎮  6 級)的城牆( 2 級)為防禦部隊增加了 7% 的防禦力。
     while($c =~ /城鎮\s+(\d+)/gs) {
@@ -846,6 +996,7 @@
         $self->checkArmies($cityId);
         $self->checkTavern($cityId);
     }
+    # $self->checkFriends();
     return $self->{'cities'};
 }
 
@@ -895,30 +1046,29 @@
         # o 最佳軍營等級
         # a 攻擊力
         # d 防守力
-        # A 
-        # D 
+        # A 攻擊力加成
+        # D 防守力加成
         # s 耐力
         # c 種類
-        # v speed
-        # x 加成 Assault, Resistance
-        Slinger => {n=>"Slinger",p=>1,w=>40,b=>"12m",u=>8,m=>1,o=>4,a=>7,d=>6,A=>2,D=>2,s=>10,c=>"Human",v=>20},
-        Swordsman => {n=>"Swordsman",p=>2,w=>47,S=>16,b=>"17m",u=>16,m=>3,o=>5,a=>18,d=>14,A=>4,D=>3,s=>12,c=>"Human",v=>20,x=>"Assault"},
-        Phalanx => {n=>"Phalanx",p=>4,w=>104,S=>64,b=>"40m",u=>24,m=>4,o=>7,a=>24,d=>40,A=>6,D=>10,s=>14,c=>"Human",v=>20,x=>"Resistance"},
-        Ram => {n=>"Ram",p=>8,w=>198,S=>128,b=>"42m",u=>52,m=>5,o=>8,a=>14,d=>18,A=>3,D=>4,s=>16,c=>"Machina",v=>20,x=>"Ram"},
-        Archer => {n=>"Archer",p=>4,w=>172,S=>86,b=>"49m",u=>32,m=>7,o=>10,a=>40,d=>40,A=>10,D=>10,s=>12,c=>"Human",v=>20},
-        Catapult => {n=>"Catapult",p=>10,w=>342,S=>232,b=>"49m",u=>72,m=>10,o=>14,a=>36,d=>28,A=>9,D=>7,s=>16,c=>"Machina",v=>20,x=>"Ram"},
-        Gunsman => {n=>"Gunsman",i=>"marksman",p=>7,w=>355,S=>154,b=>"1h 23m",u=>58,m=>14,o=>18,a=>80,d=>64,A=>18,D=>14,s=>10,c=>"Human",v=>20},
-        Mortar => {n=>"Mortar",p=>12,w=>1325,S=>938,b=>"1h 53m",u=>128,m=>19,o=>21,a=>64,d=>64,A=>15,D=>15,s=>16,c=>"Machina",v=>20,x=>"Ram"},
-        SteamGiant => {n=>"SteamGiant",i=>"steamgiant",p=>6,w=>1150,S=>716,b=>"1h 45m",u=>68,m=>16,o=>20,a=>100,d=>140,A=>20,D=>30,s=>14,c=>"Machina",v=>20,x=>"Resistance"},
-        Gyrocopter => {n=>"Gyrocopter",p=>8,w=>1250,S=>670,b=>"1h 2m",u=>97,m=>12,o=>16,a=>112,d=>112,A=>25,D=>25,s=>12,c=>"Machina",v=>20},
-        Bombardier => {n=>"Bombardier",p=>24,w=>2270,S=>878,b=>"2h 10m",u=>228,m=>22,o=>24,a=>200,d=>165,A=>45,D=>35,s=>14,c=>"Machina",v=>20,x=>"Assault"},
-        Doctor => {n=>"Doctor",i=>"medic",p=>6,w=>640,C=>361,b=>"1h 2m",u=>244,m=>11,o=>12,a=>4,d=>28,A=>0,D=>0,s=>14,c=>"Human",v=>20,x=>"Healer"},
-        Cook => {n=>"Cook",p=>4,w=>520,W=>103,b=>"38m",u=>138,m=>8,o=>8,a=>6,d=>26,A=>0,D=>0,s=>16,c=>"Human",v=>20,x=>"Regeneration"}
+        # v Speed
+        # x 攻防加成 Assault, Resistance
+        Slinger => {n => "Slinger", p => 1, w => 40, b => "12m", u => 8, m => 1, o => 4, a => 7, d => 6, A => 2, D => 2, s => 10, c => "Human", v => 20}, 
+        Swordsman => {n => "Swordsman", p => 2, w => 47, S => 16, b => "17m", u => 16, m => 3, o => 5, a => 18, d => 14, A => 4, D => 3, s => 12, c => "Human", v => 20, x => "Assault"}, 
+        Phalanx => {n => "Phalanx", p => 4, w => 104, S => 64, b => "40m", u => 24, m => 4, o => 7, a => 24, d => 40, A => 6, D => 10, s => 14, c => "Human", v => 20, x => "Resistance"}, 
+        Ram => {n => "Ram", p => 8, w => 198, S => 128, b => "42m", u => 52, m => 5, o => 8, a => 14, d => 18, A => 3, D => 4, s => 16, c => "Machina", v => 20, x => "Ram"}, 
+        Archer => {n => "Archer", p => 4, w => 172, S => 86, b => "49m", u => 32, m => 7, o => 10, a => 40, d => 40, A => 10, D => 10, s => 12, c => "Human", v => 20}, 
+        Catapult => {n => "Catapult", p => 10, w => 342, S => 232, b => "49m", u => 72, m => 10, o => 14, a => 36, d => 28, A => 9, D => 7, s => 16, c => "Machina", v => 20, x => "Ram"}, 
+        Gunsman => {n => "Gunsman", i => "marksman", p => 7, w => 355, S => 154, b => "1h 23m", u => 58, m => 14, o => 18, a => 80, d => 64, A => 18, D => 14, s => 10, c => "Human", v => 20}, 
+        Mortar => {n => "Mortar", p => 12, w => 1325, S => 938, b => "1h 53m", u => 128, m => 19, o => 21, a => 64, d => 64, A => 15, D => 15, s => 16, c => "Machina", v => 20, x => "Ram"}, 
+        SteamGiant => {n => "SteamGiant", i => "steamgiant", p => 6, w => 1150, S => 716, b => "1h 45m", u => 68, m => 16, o => 20, a => 100, d => 140, A => 20, D => 30, s => 14, c => "Machina", v => 20, x => "Resistance"}, 
+        Gyrocopter => {n => "Gyrocopter", p => 8, w => 1250, S => 670, b => "1h 2m", u => 97, m => 12, o => 16, a => 112, d => 112, A => 25, D => 25, s => 12, c => "Machina", v => 20}, 
+        Bombardier => {n => "Bombardier", p => 24, w => 2270, S => 878, b => "2h 10m", u => 228, m => 22, o => 24, a => 200, d => 165, A => 45, D => 35, s => 14, c => "Machina", v => 20, x => "Assault"}, 
+        Doctor => {n => "Doctor", i => "medic", p => 6, w => 640, C => 361, b => "1h 2m", u => 244, m => 11, o => 12, a => 4, d => 28, A => 0, D => 0, s => 14, c => "Human", v => 20, x => "Healer"}, 
+        Cook => {n => "Cook", p => 4, w => 520, W => 103, b => "38m", u => 138, m => 8, o => 8, a => 6, d => 26, A => 0, D => 0, s => 16, c => "Human", v => 20, x => "Regeneration"}
     };
 
     my $cost = 0;
     foreach(keys(%{$cities->{$cityId}->{army}})) {
-        # printf("%s %d = %d\n", $_, $cities->{$cityId}->{army}->{$_},  $cities->{$cityId}->{army}->{$_} * $troops->{$_}->{u});
         $cost += $cities->{$cityId}->{army}->{$_} * $troops->{$_}->{u};
     }
     return $cost;
@@ -1002,6 +1152,7 @@
     }
     foreach(@cities) {
         $self->{'cities'}->{$_} = {};
+        $self->{'cities'}->{$_}->{id} = $_;
     }
 }
 
--- a/agent.pl	Sun Nov 02 11:59:31 2008 +0800
+++ b/agent.pl	Tue Nov 04 18:34:00 2008 +0800
@@ -36,17 +36,70 @@
     return ($city->{buildings}->{wall} >= $city->{buildings}->{townHall} ?  1 : 0);
 }
 
+sub is_academy_enough {
+    my ($self, $city) = @_;
+    return ($city->{buildings}->{academy} >= 6 ?  1 : 0);
+}
+
+sub is_embassy_enough {
+    my ($self, $city) = @_;
+    return ($city->{buildings}->{embassy} >= 6 ?  1 : 0);
+}
+
+sub is_museum_enough {
+    my ($self, $city) = @_;
+    return ($city->{buildings}->{museum} >= 2 ?  1 : 0);
+}
+
 sub is_space_enough {
     my ($self, $city) = @_;
     # The maximum town hall is level 20, then we build new town
     return 1 if($city->{buildings}->{townHall} >= 20);
     # TODO 應該以 成長率 * 升級所需時間計算
     # 6 hours earlier, we upgrade the twonHall.
-    return ($city->{space}->{total} <= ($city->{space}->{occupied} + ($city->{growth}*6)) ?  0 : 1)
+    return ($city->{space}->{total} <= ($city->{space}->{occupied} + ($city->{growth}*8)) ?  0 : 1)
+}
+
+sub is_safehouse_enough {
+    my ($self, $city) = @_;
+    return 0 if(!defined($city->{buildings}->{safehouse}));
+    return (($city->{buildings}->{townHall} <= ($city->{buildings}->{safehouse} + 4)) ? 0 : 1);
+}
+
+sub is_warehouse_enough {
+    my ($self, $city) = @_;
+    my @warehouse = (qw/undef undef 0 4 9 16 18 19 20 21 22 23 24 25/);
+    my @cities = keys(%{$self->{ikariam}->{cities}});
+    my $nextCities = ($#cities + 1) + 1;
+
+    Carp::carp(sprintf("Required warehouse level %s for next city (%s), current is %s\n", $warehouse[$nextCities], $nextCities, $city->{buildings}->{warehouse}));
+    return 0 if(!defined($city->{buildings}->{warehouse}));
+    return ($city->{buildings}->{warehouse} >= $warehouse[$nextCities]) ? 1 : 0;
+}
+
+
+sub is_warehouse_enougn_for_governorsresidence {
+    my ($self, $city) = @_;
+    my @warehouse = (qw/undef undef 0 4 9 16 18 19 20 21 22 23 24 25/);
+    my @cities = keys(%{$self->{ikariam}->{cities}});
+    my $citiesNumber = $#cities + 1;
+
+    Carp::carp(sprintf("Required warehouse level %s for %s cities, current is %s\n", $warehouse[$citiesNumber], $citiesNumber, $city->{buildings}->{warehouse}));
+    return 0 if(!defined($city->{buildings}->{warehouse}));
+    return ($city->{buildings}->{warehouse} >= $warehouse[$citiesNumber]) ? 1 : 0;
 }
 
 sub is_corruption {
     my ($self, $city) = @_;
+    return ($city->{corruption} > 0) ? 1 : 0;
+}
+
+sub is_any_corruption {
+    my ($self, $city) = @_;
+
+    foreach (keys(%{$self->{ikariam}->{cities}})) {
+        return 1 if ($self->{ikariam}->{cities}->{$_}->{corruption} > 0);
+    }
     return 0;
 }
 
@@ -71,24 +124,6 @@
     return ($city->{tavern}->{maxValue} == $city->{tavern}->{iniValue} ? 1 : 0);
 }
 
-sub is_warehouse_enough {
-    my ($self, $city) = @_;
-    # TODO 以速率計算容納率
-    return 1;
-}
-
-sub is_risk {
-    my ($self, $city) = @_;
-    # TODO 計算可搶劫比例, 城牆防護, 軍事分數
-    # 
-    # my $capture = $city->{buildings}->{townHall} * ($city->{buildings}->{townHall} - 1) * $city->{resource}->gold / 10000;
-    # 計算軍人消耗
-    # 方陣兵, 1.58 軍分, 24 維護費
-    # 劍士, 4.64 軍分, 16 維護費
-    # army_score_main > (occupied * 0.3)
-    return 0;
-}
-
 sub is_gold_enoughforcargo {
     my ($self, $city) = @_;
     my @cargoCost = qw/160 244 396 812 1240 1272 1832 1888 3848 3972 5204 5384 6868 7120 8864 9200 11268 11712 14108 14680 23320 24288 28664 29880 34956 36468 42348 44212 51024 53308 61236 64024 73096 76468 87020 91088 103224 116524 122072 137432 180060 202132 211964 237444 249108 278276 292076 306623 321963 338138 355198 373191 392171 412195 433320 455612 479135 503962 530166 557828 587031 617863 650420 684802 721113 759466 799981 842783 888005 935790 986286 1039654 1096062 1155689 1218724 1285369 1355837 1430353 1509159 1592508 1680670 1773932 1872597 1976989 2087448 2204338 2328045 2458976 2597567 2744276 2899594 3064040 3238163 3422550 3617820 3824635 4043693 4275738 4521561 4782000 5057946 5350345 5660202 5988585 6336630 6705540 7096598 7511164 7950683 8416694 8910828 9434823 9990523 10579889 11205006 11868090 12571498 13317734 14109462 14949514/;
@@ -119,7 +154,7 @@
     return (defined($self->{'ikariam'}->{research}->{1030}) ?  1 : 0);
 }
 
-sub is_culturalexchange_researched {
+sub is_foreigncultures_researched {
     my ($self) = @_;
     return (defined($self->{'ikariam'}->{research}->{1040}) ?  1 : 0);
 }
@@ -129,6 +164,11 @@
     return (defined($self->{'ikariam'}->{research}->{1060}) ?  1 : 0);
 }
 
+sub is_conservation_researched {
+    my ($self) = @_;
+    return (defined($self->{'ikariam'}->{research}->{2010}) ?  1 : 0);
+}
+
 sub is_wealth_researched {
     my ($self) = @_;
     return (defined($self->{'ikariam'}->{research}->{2030}) ?  1 : 0);
@@ -172,35 +212,83 @@
 sub is_barracks_level_enough {
     my ($self, $city) = @_;
     return 0 if(!defined($city->{buildings}->{barracks}));
-    # 方陣兵需要 level 4
-    # optimum is 5
-    return ($city->{buildings}->{barracks} >= 4 ? 1 : 0);
+    if($city->{buildings}->{townHall} >= 10) {
+        # optimum is 5
+        return ($city->{buildings}->{barracks} >= 5 ? 1 : 0);
+    } else {
+        # 方陣兵需要 level 4
+        return ($city->{buildings}->{barracks} >= 4 ? 1 : 0);
+    }
 }
 
 sub is_shipyard_level_enough {
     my ($self, $city) = @_;
     return 0 if(!defined($city->{buildings}->{shipyard}));
-    # optimum is 5
-    return ($city->{buildings}->{shipyard} >= 3 ? 1 : 0);
-    return 0;
+    if ($self->is_greekfire_researched() eq 1) {
+        return ($city->{buildings}->{shipyard} >= 5 ? 1 : 0);
+    } else {
+        return ($city->{buildings}->{shipyard} >= 3 ? 1 : 0);
+    }
+}
+
+sub is_shipyard_upgrading {
+    my ($self, $city) = @_;
+    return $self->{'ikariam'}->is_shipyard_upgrading($city->{id});
+}
+
+sub is_navy_trainning {
+    my ($self, $city) = @_;
+    return $self->{'ikariam'}->is_navy_trainning($city->{id});
 }
 
-sub rule_engagement
-{
+sub train_navy {
     my ($self, $city) = @_;
-    # TODO
-    # 計算距離, 可搶劫比例, 是否有聯盟, 軍事分數 (win rate)
+    my $cityId = $city->{id};
+    # TODO, 依照升級比例算 CP 值最高
+    if($self->is_greekfire_researched() eq 1 && $city->{buildings}->{shipyard} >= 5) {
+        # ok, we can build Flamethrower.
+        if(defined($city->{'fleet'}->{Flamethrower}) && ($city->{'fleet'}->{Flamethrower} > 0)
+                && ($city->{'fleet'}->{BallistaShip} / $city->{'fleet'}->{Flamethrower}) <= (1.5/1)) {
+            return 213; # 強弩船
+        } else {
+            return 211; # 噴火船
+        }
+    } else {
+        return 213; # 強弩船
+    }
 }
 
-sub rule_resource
-{
-    # TODO 
+sub is_barracks_upgrading {
+    my ($self, $city) = @_;
+    return $self->{ikariam}->is_barracks_upgrading($city->{id});
+}
+
+sub is_army_trainning {
+    my ($self, $city) = @_;
+    return $self->{ikariam}->is_army_trainning($city->{id});
+}
+sub train_army {
+    my ($self, $city) = @_;
+    my $cityId = $city->{id};
+
+    # TODO, 依照升級比例算 CP 值最高
+    my $assault = 'Swordsman';
+    my $resistance = 'Phalanx';
+
+    # ok, we can build Flamethrower.
+    if(($city->{'army'}->{$assault} / $city->{'army'}->{$resistance}) <= (2/1)) {
+        return 302; # Swordsman
+    } else {
+        return 303; # Phalanx
+    }
 }
 
 # navy
-sub rule_navyExpenditure
+sub is_navyExpenditure_available
 {
-    my ($self, $cityId) = @_;
+    my ($self, $city) = @_;
+    my $cityId = $city->{id};
+
     # move this to somewhere else.
     my $workersRatio = {
         'citizens' => 0.4,
@@ -212,19 +300,23 @@
     my $netincome = $self->{'ikariam'}->getNetIncome($cityId);
     
     # 軍費為 兩成 淨收入
-    # 陸軍佔用 0.8
-    # 海軍佔用 0.2
-    my $militaryExpenditure = int($netincome * 0.2 * 0.2);
+    # 陸軍佔用 0.3
+    # 海軍佔用 0.7
+    my $militaryExpenditure = int($netincome * 0.2 * 0.7);
 
     if($currentCost < $militaryExpenditure) {
         printf("Current navy expenditure total=%s, affordable %s\n", $currentCost, $militaryExpenditure);
+        return 1;
     }
+    return 0;
 }
 
 # army
-sub rule_milityExpenditure
+sub is_milityExpenditure_available
 {
-    my ($self, $cityId) = @_;
+    my ($self, $city) = @_;
+    my $cityId = $city->{id};
+
     # move this to somewhere else.
     my $workersRatio = {
         'citizens' => 0.4,
@@ -236,14 +328,18 @@
     my $netincome = $self->{'ikariam'}->getNetIncome($cityId);
     
     # 軍費為 兩成 淨收入
-    # 陸軍佔用 0.8
-    # 海軍佔用 0.2
-    my $militaryExpenditure = int($netincome * 0.2 * 0.8);
+    # 陸軍佔用 0.3
+    # 海軍佔用 0.7
+
+    my $militaryExpenditure = int($netincome * 0.2 * 0.3);
 
     if($currentCost < $militaryExpenditure) {
-        printf("Current army expenditure total=%s, affordable %s\n", $currentCost, $militaryExpenditure);
+        Carp::carp("Current army expenditure total=%s, affordable %s\n", $currentCost, $militaryExpenditure);
+        return 1;
     }
+    return 0;
 }
+
 1; 
 
 
@@ -258,9 +354,7 @@
 my $rules = Ikariam::Cities::Rules->new($i);
 # blanace resources, arrange defance 
 my $tree  = LoadFile('overall.yaml');
-my $decision;
-$decision->{parse_path} = [];
-$decision->{parse_answer} = undef;
+my $decision; $decision->{parse_path} = []; $decision->{parse_answer} = undef;
 my $action = ParseTree($tree, $rules, $decision);
 triggerAction($action, (keys(%$cities))[0]) if(defined($action));
 # print STDERR Dump($decision) if(defined($verbose));
@@ -270,8 +364,7 @@
     printf("%s http://%s/index.php?view=city&id=%d\n", 
         $cities->{$cityId}->{name}, $::server, $cityId);
     printf("construction: %s\n", $cities->{$cityId}->{construction});
-    
-    # foreach my $thing (qw/resources space wars buildings citizens army fleet/) {
+
     foreach my $thing (qw/resources space buildings citizens army fleet/) {
         printf("<%s>\n", uc($thing));
         foreach my $i (keys(%{$cities->{$cityId}->{$thing}})) {
@@ -283,25 +376,30 @@
 
     # maybe this should be moved to Rules.
     $i->blanceHurmanResource($cityId);
-    # milityExpenditure
-    $rules->rule_milityExpenditure($cityId);
-    $rules->rule_navyExpenditure($cityId);
+ 
+    # build spy
+    $i->buildSpy('spy', $cityId);
+
+    # build military!
+    $tree  = LoadFile('military.yaml');
+    $cities->{$cityId}->{parse_path} = [];
+    $cities->{$cityId}->{parse_answer} = undef;
+    if (my $action = ParseTree($tree, $rules, $cities->{$cityId})) {
+        triggerAction($action, $cityId);
+    }
+    DumpFile("military-$cityId-dump.yaml", $cities->{$cityId});
 
     # build and upgrade for cities
     $tree  = LoadFile('city.yaml');
     $cities->{$cityId}->{parse_path} = [];
     $cities->{$cityId}->{parse_answer} = undef;
-    while (my $action = ParseTree($tree, $rules, $cities->{$cityId})) {
+    if (my $action = ParseTree($tree, $rules, $cities->{$cityId})) {
         triggerAction($action, $cityId);
-        last;
     }
-    # Debug
-    # print(Dump($cities->{$cityId}->{parse_path})) if(defined($verbose));
+    DumpFile("city-$cityId-dump.yaml", $cities->{$cityId});
 }
-# print(Dump($cities)) if(defined($verbose));
-DumpFile("cities-dump.yaml", $cities);
 DumpFile("research-dump.yaml", $i->{'research'});
-DumpFile("military-dump.yaml", $i->{'military'});
+DumpFile("wares-dump.yaml", $i->{'military'});
 
 $i->logout;
 
--- a/city.yaml	Sun Nov 02 11:59:31 2008 +0800
+++ b/city.yaml	Tue Nov 04 18:34:00 2008 +0800
@@ -1,3 +1,4 @@
+# TODO adjust human resources
 ---
 # city level
 # 基本建設規則
@@ -5,63 +6,64 @@
 - is_attacked:
     # we are in Peace :D
     0:
-      # adjust human resources
       - is_constructing:
          0:
-            # XXX: 這樣會一口氣買同等城市數量的船耶
+            # FIXME: 這樣會一口氣買同等城市數量的船耶, 應拉出至全國金錢考量
             # - is_gold_enoughforcargo:
                # 1: increaseTransporter
-            - is_space_enough:
+            - is_corruption:
+               1:
+                  - is_warehouse_enougn_for_governorsresidence:
+                     0: build_warehouse
+                     1: build_palaceColony
+            - is_any_corruption:
                0: 
-                  - is_resource_enoghforHall:
-                     1: build_townHall
-            - is_wall_enough:
-               0: build_wall
-            - is_corruption:
-               1: build_governorsresidence
-            # 倉庫庫存量
-            - is_warehouse_enough:
-               0: build_warehouse
-            - is_happiness:
-               0:
-                  - is_winepress_researched:
-                     1:
-                        - is_tavern_available:
-                           0: build_tavern
-                           1: 
-                              - is_bacchanal:
-                                 0: set_tavern
-                                 1: build_tavern
-            # TODO
-            # http://ikariam.wikia.com/wiki/List_of_buildings
-            # http://ikariam.wikia.com/wiki/Technology_Tree
-            # is_conservation_researched
-            # -build_warehouse
-            # build_academy
-            # build_palace (Expansion, Capital only)
-            # build_embassy (副城, 不建)
-            - is_risk:
-               1: 
-                  - is_professionalarmy_researched:
-                     1:
-                        - is_shipyard_level_enough:
-                           0: build_shipyard
-                        - is_barracks_level_enough:
-                           0: build_barracks
+                  - is_space_enough:
+                     0: 
+                        - is_resource_enoghforHall:
+                           1: build_townHall
+                  - is_wall_enough:
+                     0: build_wall
+                  - is_happiness:
+                     0:
+                        - is_winepress_researched:
+                           1:
+                              - is_tavern_available:
+                                 0: build_tavern
+                                 1: 
+                                    - is_bacchanal:
+                                       0: set_tavern
+                                       1: build_tavern
                   - is_shipyard_level_enough:
-                     0: 
-                        - is_drydock_researched: 
-                           # requireed more army ?
+                     0:
+                        - is_professionalarmy_researched:
                            1: build_shipyard
-                  #    - build one boat
-# 應該把 Barracks 建到最佳等級
-            # 要蓋到何種程度?
-            # is_invention_researched
-            #    1: 
-            #       - build_workshop 
-            # is_espionage_researched
-            #    1: 
-            #       - build_hideout
-            # is_culturalexchange_resaerched
-            #    1: 
-            #       - build_museum
+                  - is_barracks_level_enough:
+                     0:
+                        - is_professionalarmy_researched:
+                           1: build_barracks
+                  - is_safehouse_enough:
+                     0:
+                        - is_espionage_researched:
+                           1: build_safehouse
+                  - is_warehouse_enough:
+                     0:
+                        - is_conservation_researched:
+                           1: build_warehouse
+                           0: build_academy
+                  - is_academy_enough:
+                     0: build_academy
+                  # 大使館
+                  - is_embassy_enough:
+                     0:
+                        - is_foreigncultures_researched:
+                           1: build_embassy 
+                  - is_museum_enough:
+                     0:
+                        - is_culturalexchange_resaerched:
+                           1: build_museum
+
+# 水晶島應該建設 
+# is_invention_researched
+#    1: 
+#       - build_workshop 
--- a/freeland.pl	Sun Nov 02 11:59:31 2008 +0800
+++ b/freeland.pl	Tue Nov 04 18:34:00 2008 +0800
@@ -7,10 +7,10 @@
 my @tradegoodText = qw/NULL 葡萄酒 大理石 水晶 硫磺/;
 my @wonderText = qw/NULL 赫菲斯拓斯的熔爐 蓋亞的神殿 狄奧尼索斯的花園 雅典娜的神殿 赫秘士的神殿 阿瑞斯的要塞 波賽頓的神殿 克羅瑟斯的神殿/;
 
-if($#ARGV != 1) {
-    die("Usage: $0 x y\n");
+if($#ARGV != 2) {
+    die("Usage: $0 x y tradegood (1 葡萄酒, 2 大理石, 3 水晶, 4 硫磺/)\n");
 }
-my ($x, $y) = @ARGV;
+my ($x, $y, $tradegood) = @ARGV;
 
 my @location = (($x + 6), ($x - 6), ($y + 6), ($y - 6));
 
@@ -27,7 +27,7 @@
 
 # 
 my @islands = Ikariam::Island->retrieve_from_sql(qq{
-        tradegood == 2
+        tradegood == $tradegood
     AND people < 16
     AND x <= $location[0]
     AND x >= $location[1]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/military.yaml	Tue Nov 04 18:34:00 2008 +0800
@@ -0,0 +1,54 @@
+---
+- is_attacked:
+   0:
+      - is_navyExpenditure_available:
+         1:
+            - is_professionalarmy_researched:
+               1:
+                  - is_shipyard_level_enough:
+                     0: 
+                        - is_constructing:
+                           0: 
+                              - is_any_corruption:
+                                 0: build_shipyard
+                     1:
+                        - is_shipyard_upgrading:
+                           0:
+                              - is_navy_trainning:
+                                 0:
+                                    - train_navy:
+                                       211: buildShips_211
+                                       212: buildShips_212
+                                       213: buildShips_213
+                                       214: buildShips_214
+                                       215: buildShips_215
+                                       216: buildShips_216
+      - is_milityExpenditure_available:
+         1:
+            - is_professionalarmy_researched:
+               1:
+                  - is_barracks_level_enough:
+                     0:
+                        - is_constructing:
+                           0: 
+                              - is_any_corruption:
+                                 0: build_barracks
+                     1:
+                        - is_barracks_upgrading:
+                           0:
+                              - is_army_trainning:
+                                 0:
+                                    - train_army:
+                                       301: buildUnits_301
+                                       302: buildUnits_302
+                                       303: buildUnits_303
+                                       304: buildUnits_304
+                                       305: buildUnits_305
+                                       306: buildUnits_306
+                                       307: buildUnits_307
+                                       308: buildUnits_308
+                                       309: buildUnits_309
+                                       310: buildUnits_310
+                                       311: buildUnits_311
+                                       312: buildUnits_312
+                                       313: buildUnits_313
--- a/overall.yaml	Sun Nov 02 11:59:31 2008 +0800
+++ b/overall.yaml	Tue Nov 04 18:34:00 2008 +0800
@@ -30,4 +30,3 @@
         0: research_seafaring
         
    1: run_defence
-   # we are being attacked!!!!!!!!!!!!!
--- a/pyikriam/buildings.py	Sun Nov 02 11:59:31 2008 +0800
+++ b/pyikriam/buildings.py	Tue Nov 04 18:34:00 2008 +0800
@@ -1,6 +1,9 @@
 from lazy.www import c
 from lxml import etree
 from StringIO import StringIO
+from sync_utils import sync_tagclass, sync_tagvalue
+from sync_utils import sync_tagcount, sync_tagclass_start_appear
+from sync_utils import ikariam_zh_timeval
 
 class position(object):
     def __init__(self, build_type, city_id, idx, baseurl):
@@ -16,11 +19,87 @@
     def get_page(self):
         page = c(self._baseurl).get(self._params).get_content()
         return page
+
+    def sync(self):
+        page = self.get_page()
+        parser = etree.HTMLParser(encoding='utf8')
+        page_dom = etree.parse(StringIO(page), parser)
+
+        self._sync(page_dom)
+        pass
     pass
 
-class townhall(position):
+## \brief Base class of all building class.
+#
+# This class extract information from page of building.  That are
+# information all buildings have.
+#
+class building(position):
     class_patterns = {
-        'level': 'buildingLevel',
+        'level': 'buildingLevel'
+        }
+    appear_patterns = {
+        'is_upgrading': 'isUpgrading'
+        }
+    upgrade_res_patterns = {
+        'wood': 'wood',
+        'marble': 'marble',
+        'crystal': 'glass'
+        }
+
+    def _sync(self, page_dom):
+        sync_tagclass(self, building.class_patterns, page_dom)
+
+        sync_tagclass_start_appear(self, building.appear_patterns, page_dom)
+
+        xpath_upgrade = '/descendant::ul[@class=\'actions\']/li[@class=\'upgrade\']/a'
+        anodes = page_dom.xpath(xpath_upgrade)
+        if len(anodes) == 1:
+            anode = anodes[0]
+            self._upgrade_uri = anode.get('href')
+        else:
+            self._upgrade_uri = None
+            pass
+
+        self.upgrade_wood = 0
+        self.upgrade_marble = 0
+        self.upgrade_crystal = 0
+        self.upgrade_time = 0
+        self.upgrade_countdown = 0
+
+        if self.is_upgrading:
+            xpath_countdown = '/descendant::div[@id=\'upgradeCountDown\']/text()'
+            value = page_dom.xpath(xpath_countdown)[0]
+            self.upgrade_countdown = ikariam_zh_timeval(value)
+        else:
+            xpath_res = '/descendant::div[@class=\'content\']/ul[@class=\'resources\']/li[starts-with(@class, \'%s\')]/text()'
+
+            for resname, clzname in building.upgrade_res_patterns.items():
+                xpath = xpath_res % (clzname)
+                txts = page_dom.xpath(xpath)
+                if len(txts) == 1:
+                    value = txts[0].strip()
+                    setattr(self, 'upgrade_' + resname, int(value))
+                    pass
+                pass
+
+            xpath_time = xpath_res % ('time')
+            txts = page_dom.xpath(xpath_time)
+            if len(txts) == 1:
+                value = txts[0].strip()
+                self.upgrade_time = ikariam_zh_timeval(value)
+                pass
+            pass
+        pass
+
+    def upgrade(self):
+        url = self._baseurl + self._upgrade_uri
+        page = c(url).get().get_content()
+        pass
+    pass
+
+class townhall(building):
+    class_patterns = {
         'occupied': 'value occupied',
         'rooms': 'value total',
         }
@@ -29,7 +108,8 @@
         'happiness': 'happiness',
         'interest_base': 'base',
         'interest_research': 'research1',
-        'interest_capital': 'capital'
+        'interest_capital': 'capital',
+        'overpopulation': 'cat overpopulation'
         }
     count_patterns = {
         'pop_citizens': 'citizens',
@@ -37,67 +117,140 @@
         'pop_specialworkers': 'specialworkers',
         'pop_scientists': 'scientists'
         }
-    appear_patterns = {
-        'is_upgrading': 'isUpgrading'
-        }
     
     def __init__(self, city_id, idx, baseurl):
         super(townhall, self).__init__('townhall', city_id, idx, baseurl)
         pass
 
-    def _sync(self, page):
-        parser = etree.HTMLParser(encoding='utf8')
-        page_dom = etree.parse(StringIO(page), parser)
+    def _sync(self, page_dom):
+        sync_tagclass(self, townhall.class_patterns, page_dom)
+
+        sync_tagvalue(self, townhall.value_patterns, page_dom)
+
+        sync_tagcount(self, townhall.count_patterns, page_dom)
+
+        super(townhall, self)._sync(page_dom)
+        pass
+    pass
 
-        xpath_building = '/html/body/descendant::*[@class=\'%s\']/text()'
-        for name, clzname in self.class_patterns.items():
-            path = xpath_building % (clzname)
-            value = page_dom.xpath(path)[0]
-            setattr(self, name, value)
+class academy(building):
+    def __init__(self, city_id, idx, baseurl):
+        super(academy, self).__init__('academy', city_id, idx, baseurl)
+        pass
+
+    def _sync(self, page_dom):
+        xpath_research_name = '/descendant::*[@class=\'researchName\']/a'
+        anodes = page_dom.xpath(xpath_research_name)
+        if len(anodes) == 1:
+            anode = anodes[0]
+            self.researching = anode.get('title')
+            xpath_countdown = '/descendant::div[@id=\'researchCountDown\']/text()'
+            txtnodes = page_dom.xpath(xpath_countdown)
+            self.researching_countdown = ikariam_zh_timeval(txtnodes[0])
+        else:
+            self.researching = None
+            self.researching_countdown = None
             pass
 
-        xpath_value = '/html/body/descendant::*[starts-with(@class,\'%s\')]/descendant::*[@class=\'value\']/text()'
-        for name, clzname in self.value_patterns.items():
-            path = xpath_value % (clzname)
-            value = page_dom.xpath(path)[0]
-            setattr(self, name, value)
+        super(academy, self)._sync(page_dom)
+        pass
+    pass
+
+class warehouse(building):
+    def __init__(self, city_id, idx, baseurl):
+        super(warehouse, self).__init__('warehouse', city_id, idx, baseurl)
+        pass
+    pass
+
+class barracks(building):
+    def __init__(self, city_id, idx, baseurl):
+        super(barracks, self).__init__('barracks', city_id, idx, baseurl)
+        pass
+    pass
+
+class branchoffice(building):
+    def __init__(self, city_id, idx, baseurl):
+        super(branchoffice, self).__init__('branchoffice', city_id, idx, baseurl)
+        pass
+    pass
+
+class port(building):
+    def __init__(self, city_id, idx, baseurl):
+        super(port, self).__init__('port', city_id, idx, baseurl)
+        pass
+    pass
+
+class wall(building):
+    def __init__(self, city_id, idx, baseurl):
+        super(wall, self).__init__('wall', city_id, idx, baseurl)
+        pass
+    pass
+
+class shipyard(building):
+    def __init__(self, city_id, idx, baseurl):
+        super(shipyard, self).__init__('shipyard', city_id, idx, baseurl)
+        pass
+    pass
+
+class empty_pos(position):
+    res_patterns = {
+        'wood': 'wood',
+        'marble': 'marble',
+        'crystal': 'glass'
+        }
+
+    def _sync(self, page_dom):
+        self.building_info = None
+        self.res_wood = 0
+        self.res_marble = 0
+        self.res_crystal = 0
+        self.building_time = 0
+        self._building_uri = None
+
+        xpath_building = '/descendant::div[@class=\'buildinginfo\']/h4/text()'
+        buildings = page_dom.xpath(xpath_building)
+        if len(buildings) == 1:
+            self.building_info = buildings[0]
             pass
 
-        xpath_count = '/html/body/descendant::*[starts-with(@class,\'%s\')]/descendant::*[@class=\'count\']/text()'
-        for name, clzname in self.count_patterns.items():
-            path = xpath_count % (clzname)
-            value = page_dom.xpath(path)[0]
-            setattr(self, name, value)
-            pass
-
-        xpath_appear = '/html/body/descendant::*[starts-with(@class,\'%s\')]'
-        for name, clzname in self.appear_patterns.items():
-            path = xpath_appear % (clzname)
-            cnt = len(page_dom.xpath(path))
-            if cnt != 0:
-                setattr(self, name, True)
-            else:
-                setattr(self, name, False)
+        xpath_costs = '/descendant::div[@class=\'costs\']/ul/li[@class=\'%s\']/text()'
+        for res, ptn in empty_pos.res_patterns.items():
+            xpath = xpath_costs % (ptn)
+            txts = page_dom.xpath(xpath)
+            if len(txts) == 1:
+                value = int(txts[0])
+                setattr(self, 'res_' + res, value)
                 pass
             pass
 
-        xpath_upgrade = '/descendant::ul[@class=\'actions\']/li[@class=\'upgrade\']/a'
-        anodes = page_dom.xpath(xpath_upgrade)
+        xpath = xpath_costs % ('time')
+        txts = page_dom.xpath(xpath)
+        if len(txts) == 1:
+            value = ikariam_zh_timeval(txts[0])
+            self.building_time = value
+            pass
+
+        xpath_button = '/descendant::a[@class=\'button build\']'
+        anodes = page_dom.xpath(xpath_button)
         if len(anodes) == 1:
-            anode = anodes[0]
-            self.upgrade_uri = anode.get('href')
-        else:
-            self.upgrade_uri = None
+            self._building_uri = anodes[0].get('href')
             pass
         pass
 
-    def sync(self):
-        page = self.get_page()
-        self._sync(page)
-        pass
-
-    def upgrade(self):
-        url = self._baseurl + self.upgrade_uri
+    def build(self):
+        url = self._baseurl + self._building_uri
         page = c(url).get().get_content()
         pass
     pass
+
+class land(empty_pos):
+    def __init__(self, city_id, idx, baseurl):
+        super(land, self).__init__('land', city_id, idx, baseurl)
+        pass
+    pass
+
+class shore(empty_pos):
+    def __init__(self, city_id, idx, baseurl):
+        super(shore, self).__init__('shore', city_id, idx, baseurl)
+        pass
+    pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pyikriam/createAccount.py	Tue Nov 04 18:34:00 2008 +0800
@@ -0,0 +1,47 @@
+import urllib2,urllib
+
+from ikariam import fake_moz
+from lazy.www import c
+
+class CreateAccount:
+    """
+    For create sheep to cheat. take care of the ip address & email check by yourself.
+    """
+    def __init__(self,account,email,password,server):
+        self.account=account
+        self.password=password
+        self.server=server
+        self.email=email
+        headers=[('Referer','http://'+self.server[self.server.find('.')+1:]+'/register.php')]
+        self.browser = fake_moz(headers)
+        urllib2.install_opener(self.browser)
+        pass
+
+    def ca(self):
+        self.baseurl='http://'+self.server
+        params = {
+        "function":"createAvatar",\
+        "name":self.account,\
+        "email":self.email,\
+        "password":self.password,\
+        "agb":"on"}
+        self.ret=c(self.baseurl+'/index.php?action=newPlayer').get(params).get_content()
+        pass
+
+class confirme:
+    def __init__(self,confirmeurl):
+        self.confirmeurl=confirmeurl
+        self.browser = fake_moz()
+        urllib2.install_opener(self.browser)
+        pass
+
+    def run(self):
+        self.ret=c(self.confirmeurl).get().get_content()
+        pass
+
+"""
+ikariamca=CreateAccount('someac','kevin@butyshop.com','contest123','s2.ikariam.tw')
+a=ikariamca.ca()
+confirme("http://s2.ikariam.tw/index.php?action=newPlayer&function=validateEmail&hash=c239c92a94690066078ca95c993d348b&id=70997").run()
+"""
+
--- a/pyikriam/example.py	Sun Nov 02 11:59:31 2008 +0800
+++ b/pyikriam/example.py	Tue Nov 04 18:34:00 2008 +0800
@@ -1,4 +1,5 @@
 import sys
+import buildings
 from ikariam import Ikariam
 
 if len(sys.argv) != 2:
@@ -21,14 +22,16 @@
 print 'marble is ' + city.marble
 print 'crystal is ' + city.crystal
 print 'sulfur is ' + city.sulfur
-print 'positions ' + repr(city.positions)
 
-city.positions[0].sync()
-city_attrs = ('level', 'occupied', 'rooms', 'growth', 'happiness',
-              'interest_base', 'interest_research', 'interest_capital',
-              'pop_citizens', 'pop_woodworkers', 'pop_specialworkers',
-              'pop_scientists', 'is_upgrading', 'upgrade_uri')
-for city_attr in city_attrs:
-    value = getattr(city.positions[0], city_attr)
-    print 'positions[0].%s is %s' % (city_attr, str(value))
-    pass
+for idx, pos in enumerate(city.positions):
+    if not isinstance(pos, buildings.position):
+        continue
+    pos.sync()
+    building_attrs  = filter(lambda attr: not attr[0].startswith('_'),
+                             pos.__dict__.items())
+    building_attrs.sort(key=lambda x: x[0])
+    print
+    print 'positions[%d]' % (idx)
+    for building_attr, value in building_attrs:
+        print '\t%s: %s' % (building_attr, repr(value))
+        pass
--- a/pyikriam/ikariam.py	Sun Nov 02 11:59:31 2008 +0800
+++ b/pyikriam/ikariam.py	Tue Nov 04 18:34:00 2008 +0800
@@ -11,34 +11,34 @@
 class fake_moz(object):
     __metaclass__ = decorator
 
-    def __init__(self):
+    def __init__(self,headers=0):
+        fakeheaders=[('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.8.1.12pre) Gecko/20071220 BonEcho/2.0.0.12pre')]
+        if headers:
+            fakeheaders=fakeheaders+headers
         super(fake_moz, self).__init__()
         cookie_jar = cookielib.LWPCookieJar()
         cookie_proc = urllib2.HTTPCookieProcessor(cookie_jar)
         opener = urllib2.build_opener(cookie_proc)
-        opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.8.1.12pre) Gecko/20071220 BonEcho/2.0.0.12pre')]
+        opener.addheaders = fakeheaders 
         fake_moz.set_backend(self, opener)
         self.cookie_jar = cookie_jar
         pass
     pass
 
-
 class Ikariam:
 
     cities = {}
     COOKIEFILE = '/tmp/ikariam.lwp'
 
     def __init__(self):
-        browser = fake_moz()
-        self.browser = browser
-        self._cookie_jar = browser.cookie_jar
+        self.browser = fake_moz()
+        self._cookie_jar = self.browser.cookie_jar
 
         if os.path.isfile(self.COOKIEFILE):
             self._cookie_jar.load(self.COOKIEFILE)
             pass
  
-        urllib2.install_opener(browser)
-
+        urllib2.install_opener(self.browser)
 	self.confdata=LoadConfigfile().cd
         self.baseurl='http://'+self.confdata['server']
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pyikriam/sync_utils.py	Tue Nov 04 18:34:00 2008 +0800
@@ -0,0 +1,72 @@
+## \file
+# \brief Sync information of objects with DOM trees of respective pages.
+#
+
+import re as _re
+
+def sync_tagclass(obj, patterns, page_dom):
+    xpath_building = '/html/body/descendant::*[@class=\'%s\']/text()'
+    for name, clzname in patterns.items():
+        path = xpath_building % (clzname)
+        value = float(page_dom.xpath(path)[0])
+        setattr(obj, name, value)
+        pass
+    pass
+
+def sync_tagvalue(obj, patterns, page_dom):
+    xpath_value = '/html/body/descendant::*[starts-with(@class,\'%s\')]/descendant::*[@class=\'value\']/text()'
+    for name, clzname in patterns.items():
+        path = xpath_value % (clzname)
+        value = float(page_dom.xpath(path)[0])
+        setattr(obj, name, value)
+        pass
+    pass
+
+def sync_tagcount(obj, patterns, page_dom):
+    xpath_count = '/html/body/descendant::*[starts-with(@class,\'%s\')]/descendant::*[@class=\'count\']/text()'
+    for name, clzname in patterns.items():
+        path = xpath_count % (clzname)
+        value = int(page_dom.xpath(path)[0])
+        setattr(obj, name, value)
+        pass
+    pass
+
+def sync_tagclass_start_appear(obj, patterns, page_dom):
+    xpath_appear = '/html/body/descendant::*[starts-with(@class,\'%s\')]'
+    for name, clzname in patterns.items():
+        path = xpath_appear % (clzname)
+        cnt = len(page_dom.xpath(path))
+        if cnt != 0:
+            setattr(obj, name, True)
+        else:
+            setattr(obj, name, False)
+            pass
+        pass
+    pass
+
+_reo_tv = _re.compile(u'(([0-9]+)\u6642)? ?(([0-9]+)\u5206)? ?(([0-9]+)\u79d2)?')
+## \brief Translate timeval in Chinese text format to integer seconds.
+#
+def ikariam_zh_timeval(tv_str):
+    tmo = _reo_tv.match(tv_str)
+    if not tmo:
+        raise SyntaxError, \
+            '%s is an invalid time interval string' % (repr(tv_str))
+    tv = 0
+
+    value = tmo.group(2)        # hour
+    if value:
+        tv = tv + int(value) * 3600
+        pass
+    
+    value = tmo.group(4)        # minute
+    if value:
+        tv = tv + int(value) * 60
+        pass
+    
+    value = tmo.group(6)        # second
+    if value:
+        tv = tv + int(value)
+        pass
+
+    return tv
--- a/scan.pl	Sun Nov 02 11:59:31 2008 +0800
+++ b/scan.pl	Tue Nov 04 18:34:00 2008 +0800
@@ -28,7 +28,7 @@
         $c->update();
 
         my $user = Ikariam::User->retrieve($h_city->{'user'});
-        next if (defined($user) && defined($user->time) && $user->time le (time - 60*60*1));
+        next if (defined($user) && defined($user->time) && $user->time le (time - 30*60*1));
 
         saveUser($h_city->{owner});
     }
@@ -65,7 +65,7 @@
 
     # Save for member of ally 
     my $ally = Ikariam::Ally->retrieve($allyId);
-    if(!defined($ally) || $ally->time le (time - 60*60*1)) {
+    if(!defined($ally) || $ally->time le (time - 30*60*1)) {
         my $h_ally = $::i->viewAlly($allyId);
         $h_ally->{'time'} = time;
         if(defined($ally)) {
@@ -107,7 +107,7 @@
 
     foreach my $h_island (@islands)
     {
-        printf("checking island %d\n", $h_island->{id});
+        # printf("checking island %d\n", $h_island->{id});
 
         my $island;
         if($island = Ikariam::Island->retrieve($h_island->{id})) {
@@ -119,7 +119,7 @@
         }
 
         # scanning the island
-        if($island->time le (time - 60*60*6))
+        if($island->time le (time - 30*60*6))
         {
             my @cities = $i->viewIsland($h_island->{id});
             saveCities($h_island->{id}, @cities);
--- a/warfare.pl	Sun Nov 02 11:59:31 2008 +0800
+++ b/warfare.pl	Tue Nov 04 18:34:00 2008 +0800
@@ -50,7 +50,16 @@
 
 sub is_transporters_available {
     my ($self, $city) = @_;
-    return ($city->{transporters}->{avail} > 0) ? 1 : 0;
+    # we keep 10 transporters for prize
+    return ($city->{transporters}->{avail} > 10) ? 1 : 0;
+}
+
+sub is_port_available {
+    my ($self, $city) = @_;
+    foreach(1..2) {
+        return 1 if($city->{locations}[$_] eq 'port');
+    }
+    return 0;
 }
 
 sub is_army_available {
@@ -101,8 +110,10 @@
         # we attack one city maximum 4 times a day.
         next if($c >= 4);
 
+        my $capture = $city->citylevel * ($city->citylevel - 1) * $sheep->trader_score_secondary / 10000;
+        next if($capture < 1500);
+
         # {
-            my $capture = $city->citylevel * ($city->citylevel - 1) * $sheep->trader_score_secondary / 10000;
             my $line = sprintf("%d %s [%d,%d] %s (%d) %s Attacked %d", 
                 $capture, $city->status, 
                 $island->x, $island->y,
@@ -135,6 +146,7 @@
 $i->login;
 my $cities = $i->check;
 $i->checkMilitaryAdvisorCombatReports();
+$i->checkFriends();
 
 foreach my $cityId (keys(%$cities)) {
     print Dump($i->{'military'});
--- a/warfare.yaml	Sun Nov 02 11:59:31 2008 +0800
+++ b/warfare.yaml	Tue Nov 04 18:34:00 2008 +0800
@@ -5,5 +5,7 @@
           1:
              - is_transporters_available:
                 1:
-                   - is_army_available:
-                      1: engagement
+                   - is_port_available:
+                      1:
+                         - is_army_available:
+                            1: engagement