Merge lp:~widelands-dev/widelands/storages_garrisons into lp:widelands

Proposed by cghislai
Status: Work in progress
Proposed branch: lp:~widelands-dev/widelands/storages_garrisons
Merge into: lp:widelands
Diff against target: 11158 lines (+5369/-2734) (has conflicts)
103 files modified
global/militarysites/barracks.empire/conf (+4/-2)
global/militarysites/barrier.barbarians/conf (+5/-3)
global/militarysites/barrier.empire/conf (+5/-3)
global/militarysites/castle.atlanteans/conf (+4/-2)
global/militarysites/castle.empire/conf (+5/-3)
global/militarysites/citadel.barbarians/conf (+5/-3)
global/militarysites/donjon.barbarians/conf (+5/-3)
global/militarysites/fortress.barbarians/conf (+5/-3)
global/militarysites/fortress.empire/conf (+5/-3)
global/militarysites/guardhall.atlanteans/conf (+4/-2)
global/militarysites/guardhouse.atlanteans/conf (+3/-1)
global/militarysites/high_tower.atlanteans/conf (+5/-3)
global/militarysites/outpost.empire/conf (+5/-3)
global/militarysites/sentry.barbarians/conf (+4/-2)
global/militarysites/sentry.empire/conf (+4/-2)
global/militarysites/small_tower.atlanteans/conf (+5/-3)
global/militarysites/stronghold.barbarians/conf (+5/-3)
global/militarysites/tower.atlanteans/conf (+6/-4)
global/militarysites/tower.empire/conf (+5/-4)
src/ai/defaultai.cc (+43/-56)
src/ai/defaultai.h (+1/-1)
src/economy/economy.cc (+69/-70)
src/economy/economy.h (+11/-8)
src/economy/idleworkersupply.cc (+3/-3)
src/economy/idleworkersupply.h (+3/-1)
src/economy/portdock.cc (+2/-2)
src/economy/request.cc (+21/-9)
src/economy/request.h (+10/-3)
src/economy/supply.h (+4/-2)
src/economy/transfer.cc (+1/-0)
src/economy/ware_instance.cc (+11/-11)
src/economy/warehousesupply.h (+0/-76)
src/logic/attackable.h (+0/-84)
src/logic/building.h (+3/-0)
src/logic/findimmovable.cc (+2/-2)
src/logic/game.cc (+2/-1)
src/logic/game.h (+2/-1)
src/logic/garrison.h (+227/-0)
src/logic/garrisonhandler.cc (+925/-0)
src/logic/garrisonhandler.h (+262/-0)
src/logic/item_ware_descr.h (+2/-2)
src/logic/militarysite.cc (+159/-173)
src/logic/militarysite.h (+14/-96)
src/logic/player.cc (+24/-21)
src/logic/player.h (+1/-1)
src/logic/playercommand.cc (+29/-29)
src/logic/playercommand.h (+9/-8)
src/logic/production_program.cc (+12/-5)
src/logic/productionsite.cc (+1/-1)
src/logic/soldier.cc (+35/-20)
src/logic/soldiercontrol.h (+0/-119)
src/logic/storage.h (+195/-0)
src/logic/storagehandler.cc (+1127/-0)
src/logic/storagehandler.h (+247/-0)
src/logic/trainingsite.cc (+97/-220)
src/logic/trainingsite.h (+14/-36)
src/logic/warehouse.cc (+111/-459)
src/logic/warehouse.h (+19/-115)
src/logic/worker.cc (+19/-19)
src/logic/worker.h (+3/-0)
src/map_io/widelands_map_buildingdata_data_packet.cc (+750/-561)
src/map_io/widelands_map_buildingdata_data_packet.h (+18/-0)
src/scripting/lua_game.cc (+13/-18)
src/scripting/lua_map.cc (+219/-72)
src/scripting/lua_map.h (+73/-15)
src/wui/attack_box.h (+0/-1)
src/wui/buildingwindow.cc (+4/-4)
src/wui/fieldaction.cc (+3/-4)
src/wui/garrisonpanel.cc (+137/-0)
src/wui/garrisonpanel.h (+65/-0)
src/wui/military_box.h (+0/-1)
src/wui/militarysitewindow.cc (+4/-2)
src/wui/soldiercapacitycontrol.cc (+10/-40)
src/wui/soldiercapacitycontrol.h (+35/-11)
src/wui/soldierlist.cc (+14/-212)
src/wui/soldierlist.h (+70/-10)
src/wui/stock_menu.cc (+11/-14)
src/wui/trainingsitewindow.cc (+4/-6)
src/wui/warehousewindow.cc (+23/-8)
tribes/atlanteans/castle/conf (+3/-1)
tribes/atlanteans/guardhall/conf (+3/-1)
tribes/atlanteans/guardhouse/conf (+2/-0)
tribes/atlanteans/headquarters/conf (+4/-0)
tribes/atlanteans/high_tower/conf (+6/-4)
tribes/atlanteans/small_tower/conf (+3/-1)
tribes/atlanteans/tower/conf (+5/-3)
tribes/barbarians/barrier/conf (+4/-2)
tribes/barbarians/citadel/conf (+5/-3)
tribes/barbarians/donjon/conf (+5/-3)
tribes/barbarians/fortress/conf (+5/-3)
tribes/barbarians/headquarters/conf (+5/-1)
tribes/barbarians/headquarters_interim/conf (+5/-1)
tribes/barbarians/sentry/conf (+3/-1)
tribes/barbarians/stronghold/conf (+6/-4)
tribes/empire/barracks/conf (+4/-2)
tribes/empire/barrier/conf (+5/-3)
tribes/empire/castle/conf (+5/-3)
tribes/empire/fortress/conf (+5/-3)
tribes/empire/headquarters/conf (+5/-1)
tribes/empire/headquarters_shipwreck/conf (+5/-1)
tribes/empire/outpost/conf (+5/-3)
tribes/empire/sentry/conf (+4/-2)
tribes/empire/tower/conf (+5/-3)
Text conflict in src/logic/militarysite.cc
Text conflict in src/logic/soldier.cc
Text conflict in src/logic/warehouse.cc
Text conflict in src/logic/warehouse.h
Text conflict in src/scripting/lua_game.cc
Text conflict in src/wui/warehousewindow.cc
To merge this branch: bzr merge lp:~widelands-dev/widelands/storages_garrisons
Reviewer Review Type Date Requested Status
SirVer Needs Fixing
Review via email: mp+178704@code.launchpad.net

Description of the change

I'm not finished working on it yet, but I already put it on review so you can check changes and suggest design changes.

This is a refactoring in order to separate storages (entities storing wares/workers) from the warehouse class and garrisons (entities storing soldiers with control) from the militarysites/trainingsites.

I try to commit only playable revisions. Please note that post-b17 savegames may not be compatible.
My plan is to move portdock stuff out of warehouse class and add a an optional garrison on warehouses for headquarters.

To post a comment you must log in.
Revision history for this message
SirVer (sirver) wrote :

that is a lot of code. I will review after I am done with the log_messages one.

Revision history for this message
cghislai (charlyghislain) wrote :

You don't have to review the whole thing now. At the very best I would appreciate knowing if I am in the wrong before putting much time in it.
The important files are new interfaces (storage.h garrison.h) and how they are used (militarysite.cc warehouse.cc)

Revision history for this message
SirVer (sirver) wrote :

Thanks, the pointer to the files to look at was very good. In general I think this is a great change and improves the design a lot - it also shows further places for refactoring which were much harder to see before this change. Here are some thoughts:

class Storage:
looks good. Could you use more empty lines to separate the methods? Also, it feels like wares and workers are disjunct, so maybe you can make a HasWares and HasWorkers Interface (those are the names I choose for Lua, consistency would be preferred, but not needed). I see that you use a lot of interfaces here - be aware that you cannot use double inheritance freely in the code as we static_cast a lot around and this breaks with double inheritance.

class Garrison:
I do not understand how you want to deal trainingssites with this one. It seems to implement the interface needed for warfare which will not be supported by trainingssites/warehouses. Otherwise looks good - then interface is a bit thicker than I would like it to be - but this is not your design error, but was there before. Maybe we can slim it out a bit later on.

About the use case: Interfaces are not a as good an idea in C++ than in Java. C++ does not have the concept and therefore creates storage for the classes. This leads to problems like the diamond inheritance[1]. This can be worked around using virtual inheritance, but then you can no longer static_cast your class pointers around. My suggestion for the design here would be to use composition [2] instead - and I would probably add getters into Building that return nullptr_t - productionsites and so on can then overwrite these getters to return correct values. So, by default a Building does not has_wares, nor has_workers nor has_soldiers, but some specialized buildings can overwrite these then.

[1] http://en.wikipedia.org/wiki/Diamond_inheritance#The_diamond_problem
[2] http://en.wikipedia.org/wiki/Composition_over_inheritance

review: Needs Fixing
Revision history for this message
SirVer (sirver) wrote :

This change would still be awesome to have in Widelands. Charly, you are not by any chance taking things on again soon?

Revision history for this message
cghislai (charlyghislain) wrote :

Im working on the fh1 branch, but I will have a look into that afterwards.

On Sun, Jul 20, 2014 at 9:56 PM, SirVer <email address hidden> wrote:

> This change would still be awesome to have in Widelands. Charly, you are
> not by any chance taking things on again soon?
> --
>
> https://code.launchpad.net/~widelands-dev/widelands/storages_garrisons/+merge/178704
> You proposed lp:~widelands-dev/widelands/storages_garrisons for merging.
>

Revision history for this message
SirVer (sirver) wrote :

Cool. I am working on getting rid of the old font renderer too in https://code.launchpad.net/~widelands-dev/widelands/text_area_richtext . Maybe we can join forces.

Revision history for this message
cghislai (charlyghislain) wrote :

Yep

Ill push my code as soons as I have this last bug gone with the editbox.

On Mon, Jul 21, 2014 at 6:53 AM, SirVer <email address hidden> wrote:

> Cool. I am working on getting rid of the old font renderer too in
> https://code.launchpad.net/~widelands-dev/widelands/text_area_richtext .
> Maybe we can join forces.
>
> --
>
> https://code.launchpad.net/~widelands-dev/widelands/storages_garrisons/+merge/178704
> You proposed lp:~widelands-dev/widelands/storages_garrisons for merging.
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'global/militarysites/barracks.empire/conf'
--- global/militarysites/barracks.empire/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/barracks.empire/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=small1size=small
2heal_per_second=60 # very low -> smallest building2buildable=no
3
4[garrison]
3conquers=65conquers=6
4max_soldiers=16max_soldiers=1
5buildable=no
6prefer_heroes=false7prefer_heroes=false
8heal_per_second=60
79
8[idle]10[idle]
9pics=../../../tribes/empire/barracks/barracks_i_??.png11pics=../../../tribes/empire/barracks/barracks_i_??.png
1012
=== modified file 'global/militarysites/barrier.barbarians/conf'
--- global/militarysites/barrier.barbarians/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/barrier.barbarians/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=medium1size=medium
2buildable=no
3
4[garrison]
5conquers=8
2max_soldiers=56max_soldiers=5
7prefer_heroes=true
3heal_per_second=1308heal_per_second=130
4conquers=8
5buildable=no
6prefer_heroes=true
79
8[idle]10[idle]
9pics=../../../tribes/barbarians/barrier/barrier_i_??.png11pics=../../../tribes/barbarians/barrier/barrier_i_??.png
1012
=== modified file 'global/militarysites/barrier.empire/conf'
--- global/militarysites/barrier.empire/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/barrier.empire/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=medium1size=medium
2buildable=no
3
4[garrison]
5conquers=8
2max_soldiers=56max_soldiers=5
7prefer_heroes=true
3heal_per_second=1308heal_per_second=130
4conquers=8
5buildable=no
6prefer_heroes=true
79
8[idle]10[idle]
9pics=../../../tribes/empire/barrier/barrier_i_??.png11pics=../../../tribes/empire/barrier/barrier_i_??.png
1012
=== modified file 'global/militarysites/castle.atlanteans/conf'
--- global/militarysites/castle.atlanteans/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/castle.atlanteans/conf 2013-08-10 10:53:03 +0000
@@ -1,8 +1,10 @@
1size=big1size=big
2max_soldiers=122buildable=no
3
4[garrison]
3heal_per_second=2005heal_per_second=200
4conquers=126conquers=12
5buildable=no7max_soldiers=12
6prefer_heroes=true8prefer_heroes=true
79
8[idle]10[idle]
911
=== modified file 'global/militarysites/castle.empire/conf'
--- global/militarysites/castle.empire/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/castle.empire/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=big1size=big
2buildable=no
3
4[garrison]
5conquers=12
2max_soldiers=126max_soldiers=12
7prefer_heroes=true
3heal_per_second=2208heal_per_second=220
4conquers=12
5buildable=no
6prefer_heroes=true
79
8[idle]10[idle]
9pics=../../../tribes/empire/castle/castle_i_??.png11pics=../../../tribes/empire/castle/castle_i_??.png
1012
=== modified file 'global/militarysites/citadel.barbarians/conf'
--- global/militarysites/citadel.barbarians/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/citadel.barbarians/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=big1size=big
2buildable=no
3
4[garrison]
5conquers=12
2max_soldiers=126max_soldiers=12
7prefer_heroes=true
3heal_per_second=2208heal_per_second=220
4conquers=12
5buildable=no
6prefer_heroes=true
79
8[idle]10[idle]
9pics=../../../tribes/barbarians/citadel/citadel_i_??.png11pics=../../../tribes/barbarians/citadel/citadel_i_??.png
1012
=== modified file 'global/militarysites/donjon.barbarians/conf'
--- global/militarysites/donjon.barbarians/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/donjon.barbarians/conf 2013-08-10 10:53:03 +0000
@@ -1,10 +1,12 @@
1size=medium1size=medium
2max_soldiers=5
3heal_per_second=150
4conquers=8
5vision_range=172vision_range=17
6buildable=no3buildable=no
4
5[garrison]
6conquers=8
7max_soldiers=5
7prefer_heroes=true8prefer_heroes=true
9heal_per_second=150
810
9[idle]11[idle]
10pics=../../../tribes/barbarians/donjon/donjon_i_??.png12pics=../../../tribes/barbarians/donjon/donjon_i_??.png
1113
=== modified file 'global/militarysites/fortress.barbarians/conf'
--- global/militarysites/fortress.barbarians/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/fortress.barbarians/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=big1size=big
2buildable=no
3
4[garrison]
5conquers=11
2max_soldiers=86max_soldiers=8
7prefer_heroes=true
3heal_per_second=1708heal_per_second=170
4conquers=11
5buildable=no
6prefer_heroes=true
79
8[idle]10[idle]
9pics=../../../tribes/barbarians/fortress/fortress_i_??.png11pics=../../../tribes/barbarians/fortress/fortress_i_??.png
1012
=== modified file 'global/militarysites/fortress.empire/conf'
--- global/militarysites/fortress.empire/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/fortress.empire/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=big1size=big
2buildable=no
3
4[garrison]
5conquers=11
2max_soldiers=86max_soldiers=8
7prefer_heroes=true
3heal_per_second=1708heal_per_second=170
4conquers=11
5buildable=no
6prefer_heroes=true
79
8[idle]10[idle]
9pics=../../../tribes/empire/fortress/fortress_i_??.png11pics=../../../tribes/empire/fortress/fortress_i_??.png
1012
=== modified file 'global/militarysites/guardhall.atlanteans/conf'
--- global/militarysites/guardhall.atlanteans/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/guardhall.atlanteans/conf 2013-08-10 10:53:03 +0000
@@ -1,8 +1,10 @@
1size=medium1size=medium
2max_soldiers=72buildable=no
3
4[garrison]
3heal_per_second=1405heal_per_second=140
4conquers=76conquers=7
5buildable=no7max_soldiers=7
6prefer_heroes=true8prefer_heroes=true
79
8[idle]10[idle]
911
=== modified file 'global/militarysites/guardhouse.atlanteans/conf'
--- global/militarysites/guardhouse.atlanteans/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/guardhouse.atlanteans/conf 2013-08-10 10:53:03 +0000
@@ -1,8 +1,10 @@
1size=small1size=small
2buildable=no
3
4[garrison]
2heal_per_second=755heal_per_second=75
3conquers=66conquers=6
4max_soldiers=27max_soldiers=2
5buildable=no
6prefer_heroes=false8prefer_heroes=false
79
8[idle]10[idle]
911
=== modified file 'global/militarysites/high_tower.atlanteans/conf'
--- global/militarysites/high_tower.atlanteans/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/high_tower.atlanteans/conf 2013-08-10 10:53:03 +0000
@@ -1,10 +1,12 @@
1size=medium1size=medium
2max_soldiers=5
3heal_per_second=170
4conquers=9
5vision_range=212vision_range=21
6buildable=no3buildable=no
4
5[garrison]
6conquers=9
7max_soldiers=5
7prefer_heroes=true8prefer_heroes=true
9heal_per_second=170
810
9[idle]11[idle]
10pics=../../../tribes/atlanteans/high_tower/high_tower_i_??.png12pics=../../../tribes/atlanteans/high_tower/high_tower_i_??.png
1113
=== modified file 'global/militarysites/outpost.empire/conf'
--- global/militarysites/outpost.empire/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/outpost.empire/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=medium1size=medium
2buildable=no
3
4[garrison]
5conquers=7
2max_soldiers=36max_soldiers=3
7prefer_heroes=false
3heal_per_second=1008heal_per_second=100
4conquers=7
5buildable=no
6prefer_heroes=false
79
8[idle]10[idle]
9pics=../../../tribes/empire/outpost/outpost_i_??.png11pics=../../../tribes/empire/outpost/outpost_i_??.png
1012
=== modified file 'global/militarysites/sentry.barbarians/conf'
--- global/militarysites/sentry.barbarians/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/sentry.barbarians/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=small1size=small
2heal_per_second=802buildable=no
3
4[garrison]
3conquers=65conquers=6
4max_soldiers=26max_soldiers=2
5buildable=no
6prefer_heroes=false7prefer_heroes=false
8heal_per_second=80
79
8[idle]10[idle]
9pics=../../../tribes/barbarians/sentry/sentry_i_??.png11pics=../../../tribes/barbarians/sentry/sentry_i_??.png
1012
=== modified file 'global/militarysites/sentry.empire/conf'
--- global/militarysites/sentry.empire/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/sentry.empire/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=small1size=small
2heal_per_second=802buildable=no
3
4[garrison]
3conquers=65conquers=6
4max_soldiers=26max_soldiers=2
5buildable=no
6prefer_heroes=false7prefer_heroes=false
8heal_per_second=80
79
8[idle]10[idle]
9pics=../../../tribes/empire/sentry/sentry_i_??.png11pics=../../../tribes/empire/sentry/sentry_i_??.png
1012
=== modified file 'global/militarysites/small_tower.atlanteans/conf'
--- global/militarysites/small_tower.atlanteans/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/small_tower.atlanteans/conf 2013-08-10 10:53:03 +0000
@@ -1,10 +1,12 @@
1size=small1size=small
2vision_range=13
3buildable=no
4
5[garrison]
2heal_per_second=1006heal_per_second=100
3conquers=57conquers=5
4vision_range=13
5max_soldiers=38max_soldiers=3
6buildable=no9prefer_heroes=true
7prefer_heroes=false
810
9[idle]11[idle]
10pics=../../../tribes/atlanteans/small_tower/small_tower_i_??.png12pics=../../../tribes/atlanteans/small_tower/small_tower_i_??.png
1113
=== modified file 'global/militarysites/stronghold.barbarians/conf'
--- global/militarysites/stronghold.barbarians/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/stronghold.barbarians/conf 2013-08-10 10:53:03 +0000
@@ -1,9 +1,11 @@
1size=medium1size=medium
2buildable=no
3
4[garrison]
5conquers=7
2max_soldiers=36max_soldiers=3
7prefer_heroes=false
3heal_per_second=1108heal_per_second=110
4conquers=7
5buildable=no
6prefer_heroes=false
79
8[idle]10[idle]
9pics=../../../tribes/barbarians/stronghold/stronghold_i_??.png11pics=../../../tribes/barbarians/stronghold/stronghold_i_??.png
1012
=== modified file 'global/militarysites/tower.atlanteans/conf'
--- global/militarysites/tower.atlanteans/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/tower.atlanteans/conf 2013-08-10 10:53:03 +0000
@@ -1,10 +1,12 @@
1size=medium1size=medium
2max_soldiers=42vision_range=17
3buildable=no
4
5[garrison]
3heal_per_second=1206heal_per_second=120
4conquers=97conquers=9
5vision_range=178max_soldiers=4
6buildable=no9prefer_heroes=false
7prefer_heroes=true
810
9[idle]11[idle]
10pics=../../../tribes/atlanteans/tower/tower_i_??.png12pics=../../../tribes/atlanteans/tower/tower_i_??.png
1113
=== modified file 'global/militarysites/tower.empire/conf'
--- global/militarysites/tower.empire/conf 2013-06-11 16:37:44 +0000
+++ global/militarysites/tower.empire/conf 2013-08-10 10:53:03 +0000
@@ -1,10 +1,11 @@
1size=medium1size=medium
2buildable=no
3
4[garrison]
5conquers=9
2max_soldiers=56max_soldiers=5
7prefer_heroes=true
3heal_per_second=1508heal_per_second=150
4conquers=9
5vision_range=19
6buildable=no
7prefer_heroes=true
89
9[idle]10[idle]
10pics=../../../tribes/empire/tower/tower_i_??.png11pics=../../../tribes/empire/tower/tower_i_??.png
1112
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2013-07-26 20:19:36 +0000
+++ src/ai/defaultai.cc 2013-08-10 10:53:03 +0000
@@ -72,7 +72,7 @@
72 next_attack_consideration_due(300000),72 next_attack_consideration_due(300000),
73 inhibit_road_building (0),73 inhibit_road_building (0),
74 time_of_last_construction (0),74 time_of_last_construction (0),
75 numof_warehouses (0)75 numof_storages (0)
76{}76{}
7777
78DefaultAI::~DefaultAI()78DefaultAI::~DefaultAI()
@@ -577,7 +577,7 @@
577577
578 if (v > 0)578 if (v > 0)
579 field.military_influence +=579 field.military_influence +=
580 v * v * militarysite->soldierCapacity();580 v * v * militarysite->get_garrison()->soldierCapacity();
581 }581 }
582582
583 if (dynamic_cast<const ProductionSite *>(building))583 if (dynamic_cast<const ProductionSite *>(building))
@@ -626,7 +626,7 @@
626626
627 if (v > 0)627 if (v > 0)
628 field.military_influence +=628 field.military_influence +=
629 v * v * militarysite->soldierCapacity();629 v * v * militarysite->get_garrison()->soldierCapacity();
630 }630 }
631 }631 }
632 }632 }
@@ -881,8 +881,8 @@
881 // Check if the produced wares are needed881 // Check if the produced wares are needed
882 Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));882 Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));
883 container_iterate(std::list<EconomyObserver *>, economies, l) {883 container_iterate(std::list<EconomyObserver *>, economies, l) {
884 // Don't check if the economy has no warehouse.884 // Don't check if the economy has no storage.
885 if ((*l.current)->economy.warehouses().empty())885 if ((*l.current)->economy.storages().empty())
886 continue;886 continue;
887 if ((*l.current)->economy.needs_ware(wt))887 if ((*l.current)->economy.needs_ware(wt))
888 prio += 1 + wares.at(bo.outputs.at(0)).preciousness;888 prio += 1 + wares.at(bo.outputs.at(0)).preciousness;
@@ -918,8 +918,8 @@
918 // the ware they're refreshing918 // the ware they're refreshing
919 Ware_Index wt(static_cast<size_t>(bo.production_hint));919 Ware_Index wt(static_cast<size_t>(bo.production_hint));
920 container_iterate(std::list<EconomyObserver *>, economies, l) {920 container_iterate(std::list<EconomyObserver *>, economies, l) {
921 // Don't check if the economy has no warehouse.921 // Don't check if the economy has no storages.
922 if ((*l.current)->economy.warehouses().empty())922 if ((*l.current)->economy.storages().empty())
923 continue;923 continue;
924 if ((*l.current)->economy.needs_ware(wt)) {924 if ((*l.current)->economy.needs_ware(wt)) {
925 prio += wares.at(bo.production_hint).preciousness * inout * 2;925 prio += wares.at(bo.production_hint).preciousness * inout * 2;
@@ -964,8 +964,8 @@
964964
965 // Check if the produced wares are needed965 // Check if the produced wares are needed
966 container_iterate(std::list<EconomyObserver *>, economies, l) {966 container_iterate(std::list<EconomyObserver *>, economies, l) {
967 // Don't check if the economy has no warehouse.967 // Don't check if the economy has no storages.
968 if ((*l.current)->economy.warehouses().empty())968 if ((*l.current)->economy.storages().empty())
969 continue;969 continue;
970 for (uint32_t m = 0; m < bo.outputs.size(); ++m) {970 for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
971 Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));971 Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));
@@ -1056,7 +1056,7 @@
1056 // needed for soldier training) near the frontier.1056 // needed for soldier training) near the frontier.
1057 prio += productionsites.size() + mines.size();1057 prio += productionsites.size() + mines.size();
1058 prio += militarysites.size() / 3;1058 prio += militarysites.size() / 3;
1059 prio -= (bo.cnt_under_construction + numof_warehouses) * 35;1059 prio -= (bo.cnt_under_construction + numof_storages) * 35;
1060 prio *= 2;1060 prio *= 2;
10611061
1062 // take care about borders and enemies1062 // take care about borders and enemies
@@ -1880,13 +1880,13 @@
18801880
1881 if (map.find_fields(Area<FCoords>(f, vision), 0, find_unowned) == 0) {1881 if (map.find_fields(Area<FCoords>(f, vision), 0, find_unowned) == 0) {
1882 // If no enemy in sight - decrease the number of stationed soldiers1882 // If no enemy in sight - decrease the number of stationed soldiers
1883 // as long as it is > 1 - BUT take care that there is a warehouse in the1883 // as long as it is > 1 - BUT take care that there is a storage in the
1884 // same economy where the thrown out soldiers can go to.1884 // same economy where the thrown out soldiers can go to.
1885 if (ms->economy().warehouses().size()) {1885 if (ms->economy().storages().size()) {
1886 uint32_t const j = ms->soldierCapacity();1886 uint32_t const j = ms->get_garrison()->soldierCapacity();
1887 if (MilitarySite::kPrefersRookies != ms->get_soldier_preference())1887 if (Garrison::SoldierPref::Rookies != ms->get_garrison()->get_soldier_preference())
1888 {1888 {
1889 game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersRookies);1889 game().send_player_militarysite_set_soldier_preference(*ms, Garrison::SoldierPref::Rookies);
1890 }1890 }
1891 else1891 else
1892 if (j > 1)1892 if (j > 1)
@@ -1912,7 +1912,7 @@
1912 // the destruction of the flag avoids that defaultAI will have1912 // the destruction of the flag avoids that defaultAI will have
1913 // too many unused roads - if needed the road will be rebuild1913 // too many unused roads - if needed the road will be rebuild
1914 // directly.1914 // directly.
1915 if (static_cast<int32_t>(ms->maxSoldierCapacity() * 4) < bf.military_influence) {1915 if (static_cast<int32_t>(ms->get_garrison()->maxSoldierCapacity() * 4) < bf.military_influence) {
1916 if (ms->get_playercaps() & Widelands::Building::PCap_Dismantle) {1916 if (ms->get_playercaps() & Widelands::Building::PCap_Dismantle) {
1917 flags_to_be_removed.push_back(ms->base_flag().get_position());1917 flags_to_be_removed.push_back(ms->base_flag().get_position());
1918 game().send_player_dismantle(*ms);1918 game().send_player_dismantle(*ms);
@@ -1964,12 +1964,12 @@
1964 } else {1964 } else {
1965 // If an enemy is in sight and the number of stationed soldier is not1965 // If an enemy is in sight and the number of stationed soldier is not
1966 // at maximum - set it to maximum.1966 // at maximum - set it to maximum.
1967 uint32_t const j = ms->maxSoldierCapacity();1967 uint32_t const j = ms->get_garrison()->maxSoldierCapacity();
1968 uint32_t const k = ms->soldierCapacity();1968 uint32_t const k = ms->get_garrison()->soldierCapacity();
1969 if (j > k)1969 if (j > k)
1970 game().send_player_change_soldier_capacity(*ms, j - k);1970 game().send_player_change_soldier_capacity(*ms, j - k);
1971 if (MilitarySite::kPrefersHeroes != ms->get_soldier_preference())1971 if (Garrison::SoldierPref::Heroes != ms->get_garrison()->get_soldier_preference())
1972 game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersHeroes);1972 game().send_player_militarysite_set_soldier_preference(*ms, Garrison::SoldierPref::Heroes);
1973 changed = true;1973 changed = true;
1974 }1974 }
1975 reorder:;1975 reorder:;
@@ -2182,7 +2182,7 @@
2182 militarysites.back().bo = &bo;2182 militarysites.back().bo = &bo;
2183 militarysites.back().checks = bo.desc->get_size();2183 militarysites.back().checks = bo.desc->get_size();
2184 } else if (bo.type == BuildingObserver::WAREHOUSE)2184 } else if (bo.type == BuildingObserver::WAREHOUSE)
2185 ++numof_warehouses;2185 ++numof_storages;
2186 }2186 }
2187}2187}
21882188
@@ -2244,8 +2244,8 @@
2244 break;2244 break;
2245 }2245 }
2246 } else if (bo.type == BuildingObserver::WAREHOUSE) {2246 } else if (bo.type == BuildingObserver::WAREHOUSE) {
2247 assert(numof_warehouses > 0);2247 assert(numof_storages > 0);
2248 --numof_warehouses;2248 --numof_storages;
2249 }2249 }
2250 }2250 }
2251 m_buildable_changed = true;2251 m_buildable_changed = true;
@@ -2310,41 +2310,28 @@
2310 map.find_immovables2310 map.find_immovables
2311 (Area<FCoords>(f, vision), &immovables, FindImmovableAttackable());2311 (Area<FCoords>(f, vision), &immovables, FindImmovableAttackable());
23122312
2313 for (uint32_t j = 0; j < immovables.size(); ++j)2313 for (uint32_t j = 0; j < immovables.size(); ++j) {
2314 if (upcast(MilitarySite, bld, immovables.at(j).object)) {2314 if (upcast(GarrisonOwner, go, immovables.at(j).object)) {
2315 if (!player->is_hostile(bld->owner()))2315 if (!player->is_hostile(go->get_garrison()->owner())) {
2316 continue;2316 continue;
2317 if (bld->canAttack()) {2317 }
2318 int32_t ta = player->findAttackSoldiers(bld->base_flag());2318 if (!go->get_garrison()->canAttack()) {
2319 if (type == NORMAL)2319 continue;
2320 ta = ta * 2 / 3;2320 }
2321 if (ta < 1)2321 int32_t ta = player->findAttackSoldiers(go->get_building()->base_flag());
2322 continue;2322 if (type == NORMAL)
23232323 ta = ta * 2 / 3;
2324 int32_t const tc = ta - bld->presentSoldiers().size();2324 if (ta < 1)
2325 if (tc > chance) {2325 continue;
2326 target = bld;2326
2327 chance = tc;2327 int32_t const tc = ta - go->get_garrison()->presentSoldiers().size();
2328 attackers = ta;2328 if (tc > chance) {
2329 }2329 target = go->get_building();
2330 }2330 chance = tc;
2331 } else if (upcast(Warehouse, wh, immovables.at(j).object)) {2331 attackers = ta;
2332 if (!player->is_hostile(wh->owner()))
2333 continue;
2334 if (wh->canAttack()) {
2335 int32_t ta = player->findAttackSoldiers(wh->base_flag());
2336 if (ta < 1)
2337 continue;
2338
2339 // extra priority push!
2340 int32_t tc = ta * 2;
2341 if (tc > chance) {
2342 target = wh;
2343 chance = tc;
2344 attackers = ta;
2345 }
2346 }2332 }
2347 }2333 }
2334 }
23482335
2349 // Reenque militarysite at the end of list2336 // Reenque militarysite at the end of list
2350 militarysites.push_back(militarysites.front());2337 militarysites.push_back(militarysites.front());
23512338
=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h 2013-07-26 20:19:36 +0000
+++ src/ai/defaultai.h 2013-08-10 10:53:03 +0000
@@ -191,7 +191,7 @@
191 int32_t inhibit_road_building;191 int32_t inhibit_road_building;
192 int32_t time_of_last_construction;192 int32_t time_of_last_construction;
193193
194 uint16_t numof_warehouses;194 uint16_t numof_storages;
195};195};
196196
197#endif197#endif
198198
=== modified file 'src/economy/economy.cc'
--- src/economy/economy.cc 2013-07-26 20:19:36 +0000
+++ src/economy/economy.cc 2013-08-10 10:53:03 +0000
@@ -27,11 +27,10 @@
27#include "economy/route.h"27#include "economy/route.h"
28#include "economy/routeastar.h"28#include "economy/routeastar.h"
29#include "economy/router.h"29#include "economy/router.h"
30#include "economy/warehousesupply.h"
31#include "logic/game.h"30#include "logic/game.h"
32#include "logic/player.h"31#include "logic/player.h"
32#include "logic/storage.h"
33#include "logic/tribe.h"33#include "logic/tribe.h"
34#include "logic/warehouse.h"
35#include "upcast.h"34#include "upcast.h"
36#include "wexception.h"35#include "wexception.h"
3736
@@ -78,8 +77,8 @@
78 log("Warning: Economy still has requests left on destruction\n");77 log("Warning: Economy still has requests left on destruction\n");
79 if (m_flags.size())78 if (m_flags.size())
80 log("Warning: Economy still has flags left on destruction\n");79 log("Warning: Economy still has flags left on destruction\n");
81 if (m_warehouses.size())80 if (m_storages.size())
82 log("Warning: Economy still has warehouses left on destruction\n");81 log("Warning: Economy still has storages left on destruction\n");
8382
84 delete[] m_ware_target_quantities;83 delete[] m_ware_target_quantities;
85 delete[] m_worker_target_quantities;84 delete[] m_worker_target_quantities;
@@ -214,22 +213,22 @@
214};213};
215214
216/**215/**
217 * Find the warehouse closest to the given starting flag.216 * Find the storage owner closest to the given starting flag.
218 *217 *
219 * If the search was successful and \p route is non-null,218 * If the search was successful and \p route is non-null,
220 * a route is also computed.219 * a route is also computed.
221 *220 *
222 * \param start starting flag221 * \param start starting flag
223 * \param type whether to path-find as if the path were for a ware222 * \param type whether to path-find as if the path were for a ware
224 * \param route if non-null, fill in a route to the warehouse223 * \param route if non-null, fill in a route to the storage
225 * \param cost_cutoff if positive, find paths of at most224 * \param cost_cutoff if positive, find paths of at most
226 * that length (in milliseconds)225 * that length (in milliseconds)
227 */226 */
228Warehouse * Economy::find_closest_warehouse227StorageOwner* Economy::find_closest_storage
229 (Flag & start, WareWorker type, Route * route, uint32_t cost_cutoff,228 (Flag & start, WareWorker type, Route * route, uint32_t cost_cutoff,
230 const Economy::WarehouseAcceptFn & acceptfn)229 const Economy::StorageAcceptFn & acceptfn)
231{230{
232 if (!warehouses().size())231 if (!storages().size())
233 return 0;232 return 0;
234233
235 // A-star with zero estimator = Dijkstra234 // A-star with zero estimator = Dijkstra
@@ -243,11 +242,11 @@
243 return 0;242 return 0;
244243
245 Flag & flag = current->base_flag();244 Flag & flag = current->base_flag();
246 if (upcast(Warehouse, warehouse, flag.get_building())) {245 if (upcast(StorageOwner, storage_owner, flag.get_building())) {
247 if (!acceptfn || acceptfn(*warehouse)) {246 if (!acceptfn || acceptfn(storage_owner)) {
248 if (route)247 if (route)
249 astar.routeto(flag, *route);248 astar.routeto(flag, *route);
250 return warehouse;249 return storage_owner;
251 }250 }
252 }251 }
253 }252 }
@@ -368,7 +367,7 @@
368367
369/**368/**
370 * Call this whenever a ware is destroyed or consumed, e.g. food has been369 * Call this whenever a ware is destroyed or consumed, e.g. food has been
371 * eaten or a warehouse has been destroyed.370 * eaten or a storage has been destroyed.
372 * This is also called when a ware is removed from the economy through trade or371 * This is also called when a ware is removed from the economy through trade or
373 * a split of the Economy.372 * a split of the Economy.
374*/373*/
@@ -397,32 +396,32 @@
397}396}
398397
399/**398/**
400 * Add the warehouse to our list of warehouses.399 * Add the storage to our list of storages.
401 * This also adds the wares in the warehouse to the economy. However, if wares400 * This also adds the wares in the storage to the economy. However, if wares
402 * are added to the warehouse in the future, add_wares() must be called.401 * are added to the storage in the future, add_wares() must be called.
403*/402*/
404void Economy::add_warehouse(Warehouse & wh)403void Economy::add_storage(Storage & storage)
405{404{
406 m_warehouses.push_back(&wh);405 m_storages.push_back(&storage);
407}406}
408407
409/**408/**
410 * Remove the warehouse and its wares from the economy.409 * Remove the storage and its wares from the economy.
411*/410*/
412void Economy::remove_warehouse(Warehouse & wh)411void Economy::remove_storage(Storage & storage)
413{412{
414 for (size_t i = 0; i < m_warehouses.size(); ++i)413 for (size_t i = 0; i < m_storages.size(); ++i)
415 if (m_warehouses[i] == &wh) {414 if (m_storages[i] == &storage) {
416 m_warehouses[i] = *m_warehouses.rbegin();415 m_storages[i] = *m_storages.rbegin();
417 m_warehouses.pop_back();416 m_storages.pop_back();
418 return;417 return;
419 }418 }
420419
421420
422 // This assert was modified, since on loading, warehouses might try to421 // This assert was modified, since on loading, storages might try to
423 // remove themselves from their own economy, though they weren't added422 // remove themselves from their own economy, though they weren't added
424 // (since they weren't initialized)423 // (since they weren't initialized)
425 assert(m_warehouses.empty());424 assert(m_storages.empty());
426}425}
427426
428/**427/**
@@ -495,8 +494,8 @@
495bool Economy::needs_ware(Ware_Index const ware_type) const {494bool Economy::needs_ware(Ware_Index const ware_type) const {
496 uint32_t const t = ware_target_quantity(ware_type).permanent;495 uint32_t const t = ware_target_quantity(ware_type).permanent;
497 uint32_t quantity = 0;496 uint32_t quantity = 0;
498 container_iterate_const(std::vector<Warehouse *>, m_warehouses, wh) {497 container_iterate_const(std::vector<Storage *>, m_storages, storage) {
499 quantity += (*wh)->get_wares().stock(ware_type);498 quantity += (*storage)->get_wares().stock(ware_type);
500 if (t <= quantity)499 if (t <= quantity)
501 return false;500 return false;
502 }501 }
@@ -507,8 +506,8 @@
507bool Economy::needs_worker(Ware_Index const worker_type) const {506bool Economy::needs_worker(Ware_Index const worker_type) const {
508 uint32_t const t = worker_target_quantity(worker_type).permanent;507 uint32_t const t = worker_target_quantity(worker_type).permanent;
509 uint32_t quantity = 0;508 uint32_t quantity = 0;
510 container_iterate_const(std::vector<Warehouse *>, m_warehouses, wh) {509 container_iterate_const(std::vector<Storage *>, m_storages, storage) {
511 quantity += (*wh)->get_workers().stock(worker_type);510 quantity += (*storage)->get_workers().stock(worker_type);
512 if (t <= quantity)511 if (t <= quantity)
513 return false;512 return false;
514 }513 }
@@ -796,7 +795,7 @@
796795
797/**796/**
798 * Check whether there is a supply for the given request. If the request is a797 * Check whether there is a supply for the given request. If the request is a
799 * worker request without supply, attempt to create a new worker in a warehouse.798 * worker request without supply, attempt to create a new worker in a storage.
800 */799 */
801void Economy::_create_requested_worker(Game & game, Ware_Index index)800void Economy::_create_requested_worker(Game & game, Ware_Index index)
802{801{
@@ -820,7 +819,7 @@
820 return;819 return;
821820
822 // We have worker demand that is not fulfilled by supplies821 // We have worker demand that is not fulfilled by supplies
823 // Find warehouses where we can create the required workers,822 // Find storages where we can create the required workers,
824 // and collect stats about existing build prerequisites823 // and collect stats about existing build prerequisites
825 const Tribe_Descr & tribe = owner().tribe();824 const Tribe_Descr & tribe = owner().tribe();
826 const Worker_Descr & w_desc = *tribe.get_worker_descr(index);825 const Worker_Descr & w_desc = *tribe.get_worker_descr(index);
@@ -830,20 +829,20 @@
830829
831 total_available.insert(total_available.begin(), cost.size(), 0);830 total_available.insert(total_available.begin(), cost.size(), 0);
832831
833 for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {832 for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
834 Warehouse * wh = m_warehouses[n_wh];833 Storage * storage = m_storages[storage_idx];
835834
836 uint32_t planned = wh->get_planned_workers(game, index);835 uint32_t planned = storage->get_planned_workers(game, index);
837 total_planned += planned;836 total_planned += planned;
838837
839 while (wh->can_create_worker(game, index)) {838 while (storage->can_create_worker(game, index)) {
840 wh->create_worker(game, index);839 storage->create_worker(game, index);
841 if (!--demand)840 if (!--demand)
842 return;841 return;
843 }842 }
844843
845 std::vector<uint32_t> wh_available =844 std::vector<uint32_t> wh_available =
846 wh->calc_available_for_worker(game, index);845 storage->calc_available_for_worker(game, index);
847 assert(wh_available.size() == total_available.size());846 assert(wh_available.size() == total_available.size());
848847
849 for (uint32_t idx = 0; idx < total_available.size(); ++idx)848 for (uint32_t idx = 0; idx < total_available.size(); ++idx)
@@ -870,25 +869,25 @@
870 // there are supplies for (otherwise, cyclic transportation might happen)869 // there are supplies for (otherwise, cyclic transportation might happen)
871 // Note that supplies might suddenly disappear outside our control because870 // Note that supplies might suddenly disappear outside our control because
872 // of loss of land or silly player actions.871 // of loss of land or silly player actions.
873 for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {872 for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
874 Warehouse * wh = m_warehouses[n_wh];873 Storage * storage = m_storages[storage_idx];
875874
876 uint32_t planned = wh->get_planned_workers(game, index);875 uint32_t planned = storage->get_planned_workers(game, index);
877 uint32_t reduce = std::min(planned, total_planned - can_create);876 uint32_t reduce = std::min(planned, total_planned - can_create);
878 wh->plan_workers(game, index, planned - reduce);877 storage->plan_workers(game, index, planned - reduce);
879 total_planned -= reduce;878 total_planned -= reduce;
880 }879 }
881 } else if (total_planned < demand) {880 } else if (total_planned < demand) {
882 uint32_t plan_goal = std::min(can_create, demand);881 uint32_t plan_goal = std::min(can_create, demand);
883882
884 for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {883 for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
885 Warehouse * wh = m_warehouses[n_wh];884 Storage * storage = m_storages[storage_idx];
886 uint32_t supply =885 uint32_t supply =
887 wh->calc_available_for_worker(game, index)[scarcest_idx];886 storage->calc_available_for_worker(game, index)[scarcest_idx];
888887
889 total_planned -= wh->get_planned_workers(game, index);888 total_planned -= storage->get_planned_workers(game, index);
890 uint32_t plan = std::min(supply, plan_goal - total_planned);889 uint32_t plan = std::min(supply, plan_goal - total_planned);
891 wh->plan_workers(game, index, plan);890 storage->plan_workers(game, index, plan);
892 total_planned += plan;891 total_planned += plan;
893 }892 }
894 }893 }
@@ -896,11 +895,11 @@
896895
897/**896/**
898 * Walk all Requests and find requests of workers than aren't supplied. Then897 * Walk all Requests and find requests of workers than aren't supplied. Then
899 * try to create the worker at warehouses.898 * try to create the worker at storages.
900 */899 */
901void Economy::_create_requested_workers(Game & game)900void Economy::_create_requested_workers(Game & game)
902{901{
903 if (!warehouses().size())902 if (!storages().size())
904 return;903 return;
905904
906 const Tribe_Descr & tribe = owner().tribe();905 const Tribe_Descr & tribe = owner().tribe();
@@ -920,23 +919,23 @@
920/**919/**
921 * Helper function for \ref _handle_active_supplies920 * Helper function for \ref _handle_active_supplies
922 */921 */
923static bool accept_warehouse_if_policy922static bool accept_storage_if_policy
924 (Warehouse & wh, WareWorker type,923 (StorageOwner* storage, WareWorker type,
925 Ware_Index ware, Warehouse::StockPolicy policy)924 Ware_Index ware, Storage::StockPolicy policy)
926{925{
927 return wh.get_stock_policy(type, ware) == policy;926 return storage->get_storage()->get_stock_policy(type, ware) == policy;
928}927}
929928
930/**929/**
931 * Send all active supplies (wares that are outside on the road network without930 * Send all active supplies (wares that are outside on the road network without
932 * being sent to a specific request) to a warehouse.931 * being sent to a specific request) to a storage.
933 */932 */
934void Economy::_handle_active_supplies(Game & game)933void Economy::_handle_active_supplies(Game & game)
935{934{
936 if (!warehouses().size())935 if (!storages().size())
937 return;936 return;
938937
939 typedef std::vector<std::pair<Supply *, Warehouse *> > Assignments;938 typedef std::vector<std::pair<Supply *, StorageOwner *> > Assignments;
940 Assignments assignments;939 Assignments assignments;
941940
942 for (uint32_t idx = 0; idx < m_supplies.get_nrsupplies(); ++idx) {941 for (uint32_t idx = 0; idx < m_supplies.get_nrsupplies(); ++idx) {
@@ -950,38 +949,38 @@
950949
951 bool haveprefer = false;950 bool haveprefer = false;
952 bool havenormal = false;951 bool havenormal = false;
953 for (uint32_t nwh = 0; nwh < m_warehouses.size(); ++nwh) {952 for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
954 Warehouse * wh = m_warehouses[nwh];953 Storage * storage = m_storages[storage_idx];
955 Warehouse::StockPolicy policy = wh->get_stock_policy(type, ware);954 Storage::StockPolicy policy = storage->get_stock_policy(type, ware);
956 if (policy == Warehouse::SP_Prefer) {955 if (policy == Storage::StockPolicy::Prefer) {
957 haveprefer = true;956 haveprefer = true;
958 break;957 break;
959 }958 }
960 if (policy == Warehouse::SP_Normal)959 if (policy == Storage::StockPolicy::Normal)
961 havenormal = true;960 havenormal = true;
962 }961 }
963 if (!havenormal && !haveprefer && type == wwWARE)962 if (!havenormal && !haveprefer && type == wwWARE)
964 continue;963 continue;
965964
966 Warehouse * wh = find_closest_warehouse965 StorageOwner * storage_owner = find_closest_storage
967 (supply.get_position(game)->base_flag(), type, 0, 0,966 (supply.get_position(game)->base_flag(), type, 0, 0,
968 (!haveprefer && !havenormal)967 (!haveprefer && !havenormal)
969 ?968 ?
970 WarehouseAcceptFn()969 StorageAcceptFn()
971 :970 :
972 boost::bind971 boost::bind
973 (&accept_warehouse_if_policy,972 (&accept_storage_if_policy,
974 _1, type, ware,973 _1, type, ware,
975 haveprefer ? Warehouse::SP_Prefer : Warehouse::SP_Normal));974 haveprefer ? Storage::StockPolicy::Prefer : Storage::StockPolicy::Normal));
976975
977 if (!wh) {976 if (!storage_owner) {
978 log977 log
979 ("Warning: Economy::_handle_active_supplies "978 ("Warning: Economy::_handle_active_supplies "
980 "didn't find warehouse\n");979 "didn't find storage\n");
981 return;980 return;
982 }981 }
983982
984 assignments.push_back(std::make_pair(&supply, wh));983 assignments.push_back(std::make_pair(&supply, storage_owner));
985 }984 }
986985
987 // Actually start with the transfers in a separate second phase,986 // Actually start with the transfers in a separate second phase,
@@ -991,10 +990,10 @@
991 ss.Unsigned32(0x02decafa); // appears as facade02 in sync stream990 ss.Unsigned32(0x02decafa); // appears as facade02 in sync stream
992 ss.Unsigned32(assignments.size());991 ss.Unsigned32(assignments.size());
993992
993 // FIXME CGH check thats working
994 container_iterate_const(Assignments, assignments, it) {994 container_iterate_const(Assignments, assignments, it) {
995 ss.Unsigned32(it.current->first->get_position(game)->serial());995 ss.Unsigned32(it.current->first->get_position(game)->serial());
996 ss.Unsigned32(it.current->second->serial());996 ss.Unsigned32(it.current->second->get_building()->serial());
997
998 it.current->first->send_to_storage(game, it.current->second);997 it.current->first->send_to_storage(game, it.current->second);
999 }998 }
1000}999}
10011000
=== modified file 'src/economy/economy.h'
--- src/economy/economy.h 2013-07-26 20:19:36 +0000
+++ src/economy/economy.h 2013-08-10 10:53:03 +0000
@@ -34,12 +34,15 @@
3434
3535
36namespace Widelands {36namespace Widelands {
37
38class StorageOwner;
39
40class Storage;
37struct Player;41struct Player;
38struct Game;42struct Game;
39struct Flag;43struct Flag;
40struct Route;44struct Route;
41struct RSPairStruct;45struct RSPairStruct;
42class Warehouse;
43struct Request;46struct Request;
44struct Supply;47struct Supply;
45struct Router;48struct Router;
@@ -102,11 +105,11 @@
102 WareWorker type,105 WareWorker type,
103 int32_t cost_cutoff = -1);106 int32_t cost_cutoff = -1);
104107
105 typedef boost::function<bool (Warehouse &)> WarehouseAcceptFn;108 typedef boost::function<bool (StorageOwner *)> StorageAcceptFn;
106 Warehouse * find_closest_warehouse109 StorageOwner * find_closest_storage
107 (Flag & start, WareWorker type = wwWORKER, Route * route = 0,110 (Flag & start, WareWorker type = wwWORKER, Route * route = 0,
108 uint32_t cost_cutoff = 0,111 uint32_t cost_cutoff = 0,
109 const WarehouseAcceptFn & acceptfn = WarehouseAcceptFn());112 const StorageAcceptFn & acceptfn = StorageAcceptFn());
110113
111 std::vector<Flag *>::size_type get_nrflags() const {return m_flags.size();}114 std::vector<Flag *>::size_type get_nrflags() const {return m_flags.size();}
112 void add_flag(Flag &);115 void add_flag(Flag &);
@@ -122,9 +125,9 @@
122 void add_workers(Ware_Index, uint32_t count = 1);125 void add_workers(Ware_Index, uint32_t count = 1);
123 void remove_workers(Ware_Index, uint32_t count = 1);126 void remove_workers(Ware_Index, uint32_t count = 1);
124127
125 void add_warehouse(Warehouse &);128 void add_storage(Storage &);
126 void remove_warehouse(Warehouse &);129 void remove_storage(Storage &);
127 const std::vector<Warehouse *>& warehouses() const {return m_warehouses;}130 const std::vector<Storage *>& storages() const {return m_storages;}
128131
129 void add_request(Request &);132 void add_request(Request &);
130 void remove_request(Request &);133 void remove_request(Request &);
@@ -208,7 +211,7 @@
208 Flags m_flags;211 Flags m_flags;
209 WareList m_wares; ///< virtual storage with all wares in this Economy212 WareList m_wares; ///< virtual storage with all wares in this Economy
210 WareList m_workers; ///< virtual storage with all workers in this Economy213 WareList m_workers; ///< virtual storage with all workers in this Economy
211 std::vector<Warehouse *> m_warehouses;214 std::vector<Storage *> m_storages;
212215
213 RequestList m_requests; ///< requests216 RequestList m_requests; ///< requests
214 SupplyList m_supplies;217 SupplyList m_supplies;
215218
=== modified file 'src/economy/idleworkersupply.cc'
--- src/economy/idleworkersupply.cc 2013-07-26 20:19:36 +0000
+++ src/economy/idleworkersupply.cc 2013-08-10 10:53:03 +0000
@@ -25,8 +25,8 @@
25#include "logic/player.h"25#include "logic/player.h"
26#include "logic/requirements.h"26#include "logic/requirements.h"
27#include "logic/soldier.h"27#include "logic/soldier.h"
28#include "logic/storage.h"
28#include "logic/tribe.h"29#include "logic/tribe.h"
29#include "logic/warehouse.h"
30#include "logic/worker.h"30#include "logic/worker.h"
31#include "wexception.h"31#include "wexception.h"
3232
@@ -126,12 +126,12 @@
126 return m_worker;126 return m_worker;
127}127}
128128
129void IdleWorkerSupply::send_to_storage(Game & game, Warehouse * wh)129void IdleWorkerSupply::send_to_storage(Game & game, StorageOwner * storage_owner)
130{130{
131 assert(!has_storage());131 assert(!has_storage());
132132
133 Transfer * t = new Transfer(game, m_worker);133 Transfer * t = new Transfer(game, m_worker);
134 t->set_destination(*wh);134 t->set_destination(*storage_owner->get_building());
135 m_worker.start_task_transfer(game, t);135 m_worker.start_task_transfer(game, t);
136}136}
137137
138138
=== modified file 'src/economy/idleworkersupply.h'
--- src/economy/idleworkersupply.h 2013-07-26 20:19:36 +0000
+++ src/economy/idleworkersupply.h 2013-08-10 10:53:03 +0000
@@ -23,6 +23,8 @@
23#include "economy/supply.h"23#include "economy/supply.h"
2424
25namespace Widelands {25namespace Widelands {
26
27class StorageOwner;
26class Worker;28class Worker;
27class Economy;29class Economy;
2830
@@ -36,7 +38,7 @@
36 virtual bool is_active() const throw ();38 virtual bool is_active() const throw ();
37 virtual bool has_storage() const throw ();39 virtual bool has_storage() const throw ();
38 virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;40 virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
39 virtual void send_to_storage(Game &, Warehouse * wh);41 virtual void send_to_storage(Game &, StorageOwner * storage_owner);
4042
41 virtual uint32_t nr_supplies(const Game &, const Request &) const;43 virtual uint32_t nr_supplies(const Game &, const Request &) const;
42 virtual WareInstance & launch_item(Game &, const Request &);44 virtual WareInstance & launch_item(Game &, const Request &);
4345
=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc 2013-07-26 20:19:36 +0000
+++ src/economy/portdock.cc 2013-08-10 10:53:03 +0000
@@ -488,7 +488,7 @@
488 // Put all wares from the WaresQueues back into the warehouse488 // Put all wares from the WaresQueues back into the warehouse
489 const std::vector<WaresQueue *> & l_expedition_wares = m_warehouse->get_wares_queue_vector();489 const std::vector<WaresQueue *> & l_expedition_wares = m_warehouse->get_wares_queue_vector();
490 for (uint8_t i = 0; i < l_expedition_wares.size(); ++i) {490 for (uint8_t i = 0; i < l_expedition_wares.size(); ++i) {
491 m_warehouse->insert_wares(l_expedition_wares.at(i)->get_ware(), l_expedition_wares.at(i)->get_filled());491 m_warehouse->get_storage()->insert_wares(l_expedition_wares.at(i)->get_ware(), l_expedition_wares.at(i)->get_filled());
492 l_expedition_wares.at(i)->set_filled(0);492 l_expedition_wares.at(i)->set_filled(0);
493 l_expedition_wares.at(i)->set_max_fill(0);493 l_expedition_wares.at(i)->set_max_fill(0);
494 }494 }
@@ -501,7 +501,7 @@
501 } else {501 } else {
502 Worker * temp = ew.at(i)->worker;502 Worker * temp = ew.at(i)->worker;
503 ew.at(i)->worker = 0;503 ew.at(i)->worker = 0;
504 m_warehouse->incorporate_worker(game, *temp);504 m_warehouse->get_storage()->incorporate_worker(game, *temp);
505 }505 }
506 }506 }
507 // Reset expedition workers list507 // Reset expedition workers list
508508
=== modified file 'src/economy/request.cc'
--- src/economy/request.cc 2013-07-26 20:19:36 +0000
+++ src/economy/request.cc 2013-08-10 10:53:03 +0000
@@ -28,8 +28,8 @@
28#include "logic/player.h"28#include "logic/player.h"
29#include "logic/productionsite.h"29#include "logic/productionsite.h"
30#include "logic/soldier.h"30#include "logic/soldier.h"
31#include "logic/storage.h"
31#include "logic/tribe.h"32#include "logic/tribe.h"
32#include "logic/warehouse.h"
33#include "logic/worker.h"33#include "logic/worker.h"
34#include "map_io/widelands_map_map_object_loader.h"34#include "map_io/widelands_map_map_object_loader.h"
35#include "map_io/widelands_map_map_object_saver.h"35#include "map_io/widelands_map_map_object_saver.h"
@@ -50,22 +50,27 @@
50 (PlayerImmovable & _target,50 (PlayerImmovable & _target,
51 Ware_Index const index,51 Ware_Index const index,
52 callback_t const cbfn,52 callback_t const cbfn,
53 WareWorker const w)53 WareWorker const w,
54 callback_tranfert_t const transfer_cb)
54 :55 :
55 m_type (w),56 m_type (w),
56 m_target (_target),57 m_target (_target),
57 m_target_building (dynamic_cast<Building *>(&_target)),58 m_target_building (dynamic_cast<Building *>(&_target)),
58 m_target_productionsite (dynamic_cast<ProductionSite *>(&_target)),59 m_target_productionsite (dynamic_cast<ProductionSite *>(&_target)),
59 m_target_warehouse (dynamic_cast<Warehouse *>(&_target)),60 m_target_storage (nullptr),
60 m_target_constructionsite (dynamic_cast<ConstructionSite *>(&_target)),61 m_target_constructionsite (dynamic_cast<ConstructionSite *>(&_target)),
61 m_economy (_target.get_economy()),62 m_economy (_target.get_economy()),
62 m_index (index),63 m_index (index),
63 m_count (1),64 m_count (1),
64 m_callbackfn (cbfn),65 m_callbackfn (cbfn),
66 m_transfer_cb (transfer_cb),
65 m_required_time (_target.owner().egbase().get_gametime()),67 m_required_time (_target.owner().egbase().get_gametime()),
66 m_required_interval(0),68 m_required_interval(0),
67 m_last_request_time(m_required_time)69 m_last_request_time(m_required_time)
68{70{
71 if (upcast(StorageOwner, storage_owner, &_target)) {
72 m_target_storage = storage_owner->get_storage();
73 }
69 assert(m_type == wwWARE or m_type == wwWORKER);74 assert(m_type == wwWARE or m_type == wwWORKER);
70 if (w == wwWARE and _target.owner().tribe().get_nrwares() <= index)75 if (w == wwWARE and _target.owner().tribe().get_nrwares() <= index)
71 throw wexception76 throw wexception
@@ -354,8 +359,8 @@
354 modifier = m_target_building->get_priority(get_type(), get_index());359 modifier = m_target_building->get_priority(get_type(), get_index());
355 if (m_target_constructionsite)360 if (m_target_constructionsite)
356 is_construction_site = true;361 is_construction_site = true;
357 else if (m_target_warehouse)362 else if (m_target_storage)
358 // if warehouse calculated a priority use it363 // if storage calculated a priority use it
359 // else lower priority based on cost364 // else lower priority based on cost
360 return365 return
361 modifier != 100 ? modifier :366 modifier != 100 ? modifier :
@@ -404,7 +409,7 @@
404 pri = m_target_building->get_priority(get_type(), get_index());409 pri = m_target_building->get_priority(get_type(), get_index());
405 if (m_target_constructionsite)410 if (m_target_constructionsite)
406 return pri + 3;411 return pri + 3;
407 else if (m_target_warehouse)412 else if (m_target_storage)
408 return pri - 2;413 return pri - 2;
409 }414 }
410 return pri;415 return pri;
@@ -486,10 +491,13 @@
486 Worker & s = supp.launch_worker(game, *this);491 Worker & s = supp.launch_worker(game, *this);
487 ss.Unsigned32(s.serial());492 ss.Unsigned32(s.serial());
488 t = new Transfer(game, *this, s);493 t = new Transfer(game, *this, s);
494 if (m_transfer_cb) {
495 (*m_transfer_cb)(game, *this, m_index, &s, m_target);
496 }
489 } else {497 } else {
490 // Begin the transfer of an item. The item itself is passive.498 // Begin the transfer of an item. The item itself is passive.
491 // launch_item() ensures the WareInstance is transported out of the499 // launch_item() ensures the WareInstance is transported out of the
492 // warehouse. Once it's on the flag, the flag code will decide what to500 // storage. Once it's on the flag, the flag code will decide what to
493 // do with it.501 // do with it.
494 WareInstance & item = supp.launch_item(game, *this);502 WareInstance & item = supp.launch_item(game, *this);
495 ss.Unsigned32(item.serial());503 ss.Unsigned32(item.serial());
@@ -533,7 +541,7 @@
533 *541 *
534 * Re-open the request.542 * Re-open the request.
535*/543*/
536void Request::transfer_fail(Game &, Transfer & t) {544void Request::transfer_fail(Game & game, Transfer & t) {
537 bool const wasopen = is_open();545 bool const wasopen = is_open();
538546
539 t.m_worker = 0;547 t.m_worker = 0;
@@ -541,8 +549,12 @@
541549
542 remove_transfer(find_transfer(t));550 remove_transfer(find_transfer(t));
543551
544 if (!wasopen)552 if (!wasopen) {
545 m_economy->add_request(*this);553 m_economy->add_request(*this);
554 }
555 if (m_transfer_cb) {
556 m_transfer_cb(game, *this, m_index, nullptr, m_target);
557 }
546}558}
547559
548/// Cancel the transfer with the given index.560/// Cancel the transfer with the given index.
549561
=== modified file 'src/economy/request.h'
--- src/economy/request.h 2013-07-25 21:05:20 +0000
+++ src/economy/request.h 2013-08-10 10:53:03 +0000
@@ -20,6 +20,8 @@
20#ifndef REQUEST_H20#ifndef REQUEST_H
21#define REQUEST_H21#define REQUEST_H
2222
23#include <functional>
24
23#include "logic/requirements.h"25#include "logic/requirements.h"
24#include "logic/wareworker.h"26#include "logic/wareworker.h"
25#include "logic/widelands.h"27#include "logic/widelands.h"
@@ -39,11 +41,11 @@
39class RequestList;41class RequestList;
40struct Requirements;42struct Requirements;
41struct Supply;43struct Supply;
44class Storage;
42struct Transfer;45struct Transfer;
43class Worker;46class Worker;
44class Building;47class Building;
45class ProductionSite;48class ProductionSite;
46class Warehouse;
47class ConstructionSite;49class ConstructionSite;
4850
49/**51/**
@@ -63,8 +65,12 @@
6365
64 typedef void (*callback_t)66 typedef void (*callback_t)
65 (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);67 (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
68 typedef void (*callback_tranfert_t)
69 (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
6670
67 Request(PlayerImmovable & target, Ware_Index, callback_t, WareWorker);71 Request
72 (PlayerImmovable & target, Ware_Index, callback_t, WareWorker,
73 callback_tranfert_t transfer_cb = nullptr);
68 ~Request();74 ~Request();
6975
70 PlayerImmovable & target() const throw () {return m_target;}76 PlayerImmovable & target() const throw () {return m_target;}
@@ -120,7 +126,7 @@
120 // are filled with nulls.126 // are filled with nulls.
121 Building * m_target_building;127 Building * m_target_building;
122 ProductionSite * m_target_productionsite;128 ProductionSite * m_target_productionsite;
123 Warehouse * m_target_warehouse;129 Storage * m_target_storage;
124 ConstructionSite * m_target_constructionsite;130 ConstructionSite * m_target_constructionsite;
125131
126 Economy * m_economy;132 Economy * m_economy;
@@ -128,6 +134,7 @@
128 uint32_t m_count; // how many do we need in total134 uint32_t m_count; // how many do we need in total
129135
130 callback_t m_callbackfn; // called on request success136 callback_t m_callbackfn; // called on request success
137 callback_tranfert_t m_transfer_cb; // called on worker transfer start/cancel
131138
132 // when do we need the first ware (can be in the past)139 // when do we need the first ware (can be in the past)
133 int32_t m_required_time;140 int32_t m_required_time;
134141
=== modified file 'src/economy/supply.h'
--- src/economy/supply.h 2013-07-26 19:16:51 +0000
+++ src/economy/supply.h 2013-08-10 10:53:03 +0000
@@ -25,10 +25,12 @@
2525
26namespace Widelands {26namespace Widelands {
2727
28class StorageOwner;
29
28struct PlayerImmovable;30struct PlayerImmovable;
29struct Game;31struct Game;
30struct Request;32struct Request;
31class Warehouse;33class StorageOwner;
32struct Ware_Index;34struct Ware_Index;
33class WareInstance;35class WareInstance;
34class Worker;36class Worker;
@@ -77,7 +79,7 @@
77 * Sets up all the required transfers; assumes that \ref has_storage79 * Sets up all the required transfers; assumes that \ref has_storage
78 * returns \c false.80 * returns \c false.
79 */81 */
80 virtual void send_to_storage(Game &, Warehouse * wh) = 0;82 virtual void send_to_storage(Game &, StorageOwner * storage_owner) = 0;
8183
82 /**84 /**
83 * \return the number of items or workers that can be launched right85 * \return the number of items or workers that can be launched right
8486
=== modified file 'src/economy/transfer.cc'
--- src/economy/transfer.cc 2013-07-26 20:19:36 +0000
+++ src/economy/transfer.cc 2013-08-10 10:53:03 +0000
@@ -191,6 +191,7 @@
191 Flag & curflag(m_route.get_flag(m_game, 0));191 Flag & curflag(m_route.get_flag(m_game, 0));
192 Flag & nextflag(m_route.get_flag(m_game, 1));192 Flag & nextflag(m_route.get_flag(m_game, 1));
193 if (!curflag.get_road(nextflag)) {193 if (!curflag.get_road(nextflag)) {
194 //FIXME CGH
194 upcast(Warehouse, wh, curflag.get_building());195 upcast(Warehouse, wh, curflag.get_building());
195 assert(wh);196 assert(wh);
196197
197198
=== modified file 'src/economy/ware_instance.cc'
--- src/economy/ware_instance.cc 2013-07-26 20:19:36 +0000
+++ src/economy/ware_instance.cc 2013-08-10 10:53:03 +0000
@@ -27,8 +27,8 @@
27#include "economy/transfer.h"27#include "economy/transfer.h"
28#include "logic/game.h"28#include "logic/game.h"
29#include "logic/ship.h"29#include "logic/ship.h"
30#include "logic/storage.h"
30#include "logic/tribe.h"31#include "logic/tribe.h"
31#include "logic/warehouse.h"
32#include "logic/worker.h"32#include "logic/worker.h"
33#include "map_io/widelands_map_map_object_loader.h"33#include "map_io/widelands_map_map_object_loader.h"
34#include "map_io/widelands_map_map_object_saver.h"34#include "map_io/widelands_map_map_object_saver.h"
@@ -54,7 +54,7 @@
54 virtual bool is_active() const throw ();54 virtual bool is_active() const throw ();
55 virtual bool has_storage() const throw ();55 virtual bool has_storage() const throw ();
56 virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;56 virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
57 virtual void send_to_storage(Game &, Warehouse * wh);57 virtual void send_to_storage(Game &, StorageOwner * wh);
5858
59 virtual uint32_t nr_supplies(const Game &, const Request &) const;59 virtual uint32_t nr_supplies(const Game &, const Request &) const;
60 virtual WareInstance & launch_item(Game &, const Request &);60 virtual WareInstance & launch_item(Game &, const Request &);
@@ -166,12 +166,12 @@
166 throw wexception("IdleWareSupply::launch_worker makes no sense");166 throw wexception("IdleWareSupply::launch_worker makes no sense");
167}167}
168168
169void IdleWareSupply::send_to_storage(Game & game, Warehouse * wh)169void IdleWareSupply::send_to_storage(Game & game, StorageOwner * storage_owner)
170{170{
171 assert(!has_storage());171 assert(!has_storage());
172172
173 Transfer * t = new Transfer(game, m_ware);173 Transfer * t = new Transfer(game, m_ware);
174 t->set_destination(*wh);174 t->set_destination(*storage_owner->get_building());
175 m_ware.set_transfer(game, *t);175 m_ware.set_transfer(game, *t);
176}176}
177177
@@ -290,8 +290,8 @@
290290
291/**291/**
292 * Performs the state updates necessary for the current location:292 * Performs the state updates necessary for the current location:
293 * - if it's a building, acknowledge the Request or incorporate into warehouse293 * - if it's a building, acknowledge the Request or incorporate into strage
294 * - if it's a flag and we have no request, start the return to warehouse timer294 * - if it's a flag and we have no request, start the return to storage timer
295 * and issue a Supply295 * and issue a Supply
296 *296 *
297 * \note \ref update() may result in the deletion of this object.297 * \note \ref update() may result in the deletion of this object.
@@ -405,22 +405,22 @@
405 return;405 return;
406 }406 }
407407
408 // There are some situations where we might end up in a warehouse408 // There are some situations where we might end up in a storage
409 // as part of a requested route, and we need to move out of it409 // as part of a requested route, and we need to move out of it
410 // again, e.g.:410 // again, e.g.:
411 // - we were requested just when we were being carried into the411 // - we were requested just when we were being carried into the
412 // warehouse412 // storage
413 // - we were carried into a harbour/warehouse to be413 // - we were carried into a harbour/warehouse to be
414 // shipped across the sea, but a better, land-based route has been414 // shipped across the sea, but a better, land-based route has been
415 // found415 // found
416 if (upcast(Warehouse, warehouse, &building)) {416 if (upcast(StorageOwner, storage_owner, &building)) {
417 warehouse->do_launch_item(game, *this);417 storage_owner->get_storage()->do_launch_ware(game, *this);
418 return;418 return;
419 }419 }
420420
421 throw wexception421 throw wexception
422 ("MO(%u): ware(%s): do not know how to move from building %u (%s at (%u,%u)) "422 ("MO(%u): ware(%s): do not know how to move from building %u (%s at (%u,%u)) "
423 "to %u (%s) -> not a warehouse!",423 "to %u (%s) -> not a storage owner!",
424 serial(), m_descr->name().c_str(), building.serial(),424 serial(), m_descr->name().c_str(), building.serial(),
425 building.name().c_str(), building.get_position().x,425 building.name().c_str(), building.get_position().x,
426 building.get_position().y, nextstep->serial(),426 building.get_position().y, nextstep->serial(),
427427
=== removed file 'src/economy/warehousesupply.h'
--- src/economy/warehousesupply.h 2013-07-26 20:19:36 +0000
+++ src/economy/warehousesupply.h 1970-01-01 00:00:00 +0000
@@ -1,76 +0,0 @@
1/*
2 * Copyright (C) 2008-2010 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef WAREHOUSESUPPLY_H
21#define WAREHOUSESUPPLY_H
22
23#include "logic/warelist.h"
24#include "logic/wareworker.h"
25#include "economy/supply.h"
26
27namespace Widelands {
28
29/*
30WarehouseSupply is the implementation of Supply that is used by Warehouses.
31It also manages the list of wares in the warehouse.
32*/
33struct WarehouseSupply : public Supply {
34 WarehouseSupply(Warehouse * const wh) : m_economy(0), m_warehouse(wh) {}
35 virtual ~WarehouseSupply();
36
37 void set_economy(Economy *);
38
39 void set_nrworkers(Ware_Index);
40 void set_nrwares (Ware_Index);
41
42 const WareList & get_wares () const {return m_wares;}
43 const WareList & get_workers() const {return m_workers;}
44 uint32_t stock_wares (Ware_Index const i) const {
45 return m_wares .stock(i);
46 }
47 uint32_t stock_workers(Ware_Index const i) const {
48 return m_workers.stock(i);
49 }
50 void add_wares (Ware_Index, uint32_t count);
51 void remove_wares (Ware_Index, uint32_t count);
52 void add_workers (Ware_Index, uint32_t count);
53 void remove_workers(Ware_Index, uint32_t count);
54
55 // Supply implementation
56 virtual PlayerImmovable * get_position(Game &);
57 virtual bool is_active() const throw ();
58 virtual bool has_storage() const throw ();
59 virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
60
61 virtual void send_to_storage(Game &, Warehouse * wh);
62 virtual uint32_t nr_supplies(const Game &, const Request &) const;
63 virtual WareInstance & launch_item(Game &, const Request &);
64 virtual Worker & launch_worker(Game &, const Request &);
65
66private:
67 Economy * m_economy;
68 WareList m_wares;
69 WareList m_workers; // we use this to keep the soldiers
70 Warehouse * m_warehouse;
71};
72
73}
74
75
76#endif
770
=== removed file 'src/logic/attackable.h'
--- src/logic/attackable.h 2012-02-15 21:25:34 +0000
+++ src/logic/attackable.h 1970-01-01 00:00:00 +0000
@@ -1,84 +0,0 @@
1/*
2 * Copyright (C) 2008-2009 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef ATTACKABLE_H
21#define ATTACKABLE_H
22
23namespace Widelands {
24
25struct Player;
26class Soldier;
27
28enum {
29 /**
30 * This is the maximum radius that a military building can protect
31 * in the sense that an enemy soldier that enters the player's territory
32 * will call \ref Attackable::aggressor if it is that close.
33 */
34 MaxProtectionRadius = 25
35};
36
37/**
38 * Buildings can implement this interface to indicate that
39 * they can be attacked.
40 */
41struct Attackable {
42 /**
43 * Return the player that owns this attackable.
44 */
45 virtual Player & owner() const = 0;
46
47 /**
48 * Determines whether this building can be attacked right now.
49 *
50 * This should only return false for military sites that have not
51 * been occupied yet.
52 */
53 virtual bool canAttack() = 0;
54
55 /**
56 * Called by an enemy soldier that enters a node with distance
57 * less than or equal to \ref MaxProtectionRadius from the building.
58 *
59 * This allows the building to send protective forces to intercept
60 * the soldier.
61 */
62 virtual void aggressor(Soldier &) = 0;
63
64 /**
65 * Called by a soldier who is standing on the building's flag
66 * to attack the building.
67 *
68 * The building must send a soldier for defense, and return \c true.
69 * Otherwise, i.e. if the building cannot defend itself anymore,
70 * it must destroy itself or turn over to the attacking player,
71 * and return \c false.
72 *
73 * \return \c true if a soldier was launched in defense of the building,
74 * or \c false if the building cannot defend itself any longer.
75 */
76 virtual bool attack(Soldier &) = 0;
77
78protected:
79 virtual ~Attackable() {}
80};
81
82}
83
84#endif
850
=== modified file 'src/logic/building.h'
--- src/logic/building.h 2013-08-08 19:55:12 +0000
+++ src/logic/building.h 2013-08-10 10:53:03 +0000
@@ -258,6 +258,9 @@
258 void set_defeating_player(Player_Number const player_number) {258 void set_defeating_player(Player_Number const player_number) {
259 m_defeating_player = player_number;259 m_defeating_player = player_number;
260 }260 }
261 Player_Number get_defeating_player() {
262 return m_defeating_player;
263 }
261264
262 void add_worker(Worker &);265 void add_worker(Worker &);
263 void remove_worker(Worker &);266 void remove_worker(Worker &);
264267
=== modified file 'src/logic/findimmovable.cc'
--- src/logic/findimmovable.cc 2013-07-26 20:19:36 +0000
+++ src/logic/findimmovable.cc 2013-08-10 10:53:03 +0000
@@ -20,7 +20,6 @@
20#include "logic/findimmovable.h"20#include "logic/findimmovable.h"
2121
22#include "economy/flag.h"22#include "economy/flag.h"
23#include "logic/attackable.h"
24#include "logic/immovable.h"23#include "logic/immovable.h"
25#include "logic/militarysite.h"24#include "logic/militarysite.h"
26#include "upcast.h"25#include "upcast.h"
@@ -61,7 +60,8 @@
61}60}
6261
63bool FindImmovableAttackable ::accept(const BaseImmovable & imm) const {62bool FindImmovableAttackable ::accept(const BaseImmovable & imm) const {
64 return dynamic_cast<Attackable const *>(&imm);63 upcast(const GarrisonOwner, go, &imm);
64 return (go && go->get_garrison()->canAttack());
65}65}
6666
67bool FindImmovableByDescr::accept(const BaseImmovable & baseimm) const {67bool FindImmovableByDescr::accept(const BaseImmovable & baseimm) const {
6868
=== modified file 'src/logic/game.cc'
--- src/logic/game.cc 2013-08-07 12:32:36 +0000
+++ src/logic/game.cc 2013-08-10 10:53:03 +0000
@@ -781,7 +781,8 @@
781 (get_gametime(), building.owner().player_number(), building));781 (get_gametime(), building.owner().player_number(), building));
782}782}
783783
784void Game::send_player_militarysite_set_soldier_preference (Building & building, uint8_t my_preference)784void Game::send_player_militarysite_set_soldier_preference
785 (Building & building, Garrison::SoldierPref my_preference)
785{786{
786 send_player_command787 send_player_command
787 (*new Cmd_MilitarySiteSetSoldierPreference788 (*new Cmd_MilitarySiteSetSoldierPreference
788789
=== modified file 'src/logic/game.h'
--- src/logic/game.h 2013-08-07 12:32:36 +0000
+++ src/logic/game.h 2013-08-10 10:53:03 +0000
@@ -22,6 +22,7 @@
2222
23#include "logic/cmd_queue.h"23#include "logic/cmd_queue.h"
24#include "logic/editor_game_base.h"24#include "logic/editor_game_base.h"
25#include "logic/garrison.h"
25#include "md5.h"26#include "md5.h"
26#include "random.h"27#include "random.h"
27#include "save_handler.h"28#include "save_handler.h"
@@ -152,7 +153,7 @@
152 void send_player_build_road (int32_t, Path &);153 void send_player_build_road (int32_t, Path &);
153 void send_player_flagaction (Flag &);154 void send_player_flagaction (Flag &);
154 void send_player_start_stop_building (Building &);155 void send_player_start_stop_building (Building &);
155 void send_player_militarysite_set_soldier_preference (Building &, uint8_t preference);156 void send_player_militarysite_set_soldier_preference (Building &, Garrison::SoldierPref preference);
156 void send_player_start_or_cancel_expedition (Building &);157 void send_player_start_or_cancel_expedition (Building &);
157158
158 void send_player_enhance_building (Building &, Building_Index);159 void send_player_enhance_building (Building &, Building_Index);
159160
=== added file 'src/logic/garrison.h'
--- src/logic/garrison.h 1970-01-01 00:00:00 +0000
+++ src/logic/garrison.h 2013-08-10 10:53:03 +0000
@@ -0,0 +1,227 @@
1/*
2 * Copyright (C) 2008-2009 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef GARRISON_H
21#define GARRISON_H
22
23#include <vector>
24
25#include "logic/widelands.h"
26
27namespace Widelands {
28
29class Building;
30
31
32class Building;
33class Editor_Game_Base;
34class Game;
35struct Player;
36class Soldier;
37
38enum {
39 /**
40 * This is the maximum radius that a military building can protect
41 * in the sense that an enemy soldier that enters the player's territory
42 * will call \ref Attackable::aggressor if it is that close.
43 */
44 MaxProtectionRadius = 25
45};
46/**
47 * A garrison represents a bunch of soldiers. Garrisons are owned by GarrisonOwner
48 * buildings. This interface provides various methods to deal with soldier control
49 * and attacks.
50 */
51class Garrison {
52public:
53 enum SoldierPref : uint8_t {
54 None,
55 Rookies,
56 Heroes,
57 };
58 /**
59 * Return the player that owns this attackable.
60 */
61 virtual Player & owner() const = 0;
62
63 /**
64 * Determines whether this building can be attacked right now.
65 *
66 * This should only return false for military sites that have not
67 * been occupied yet, or by passivve garrison such as training sites.
68 */
69 virtual bool canAttack() const = 0;
70
71 /**
72 * Called by an enemy soldier that enters a node with distance
73 * less than or equal to \ref MaxProtectionRadius from the building.
74 *
75 * This allows the building to send protective forces to intercept
76 * the soldier.
77 */
78 virtual void aggressor(Soldier &) = 0;
79
80 /**
81 * Called by a soldier who is standing on the building's flag
82 * to attack the building.
83 *
84 * The building must send a soldier for defense, and return \c true.
85 * Otherwise, i.e. if the building cannot defend itself anymore,
86 * it must destroy itself or turn over to the attacking player,
87 * and return \c false.
88 *
89 * \return \c true if a soldier was launched in defense of the building,
90 * or \c false if the building cannot defend itself any longer.
91 */
92 virtual bool attack(Soldier &) = 0;
93
94 virtual bool is_passive() = 0;
95
96 virtual Building& get_building() = 0;
97
98 /**
99 * \return a list of soldiers that are currently present in the building.
100 */
101 virtual const std::vector<Soldier *> presentSoldiers() const = 0;
102
103 /**
104 * \return a list of soldiers that are currently stationed in the building.
105 * That is, all soldiers occupying a slot in the garrison.
106 */
107 virtual const std::vector<Soldier *> stationedSoldiers() const = 0;
108
109 /**
110 * \return the minimum number of soldiers that this building can be
111 * configured to hold.
112 */
113 virtual uint32_t minSoldierCapacity() const = 0;
114
115 /**
116 * \return the maximum number of soldiers that this building can be
117 * configured to hold.
118 */
119 virtual uint32_t maxSoldierCapacity() const = 0;
120
121 /**
122 * \return the number of soldiers this building is configured to hold
123 * right now.
124 */
125 virtual uint32_t soldierCapacity() const = 0;
126
127 /**
128 * Sets the capacity for soldiers of this building.
129 *
130 * New soldiers will be requested and old soldiers will be evicted
131 * as necessary.
132 */
133 virtual void setSoldierCapacity(uint32_t capacity) = 0;
134 void changeSoldierCapacity(int32_t const difference) {
135 uint32_t const old_capacity = soldierCapacity();
136 uint32_t const new_capacity =
137 std::min
138 (static_cast<uint32_t>
139 (std::max
140 (static_cast<int32_t>(old_capacity) + difference,
141 static_cast<int32_t>(minSoldierCapacity()))),
142 static_cast<uint32_t>(maxSoldierCapacity()));
143 if (old_capacity != new_capacity)
144 setSoldierCapacity(new_capacity);
145 }
146 /**
147 * Evict the given soldier from the building immediately,
148 * without changing the building's capacity.
149 *
150 * \note This has no effect if the soldier is currently involved in a battle
151 * or otherwise blocked from leaving the building.
152 */
153 virtual void dropSoldier(Soldier &) = 0;
154
155 /**
156 * Add a new soldier into this site. Returns -1 if there is no space
157 * for him, 0 on success
158 */
159 virtual int incorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
160
161 /**
162 * Remove a soldier from the internal list. Most SoldierControls will be
163 * informed by the soldier when it is removed, but WareHouses for example
164 * will not.
165 */
166 virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
167
168 /**
169 * Returns the conquer radius of this garrison
170 */
171 virtual uint32_t conquerRadius() const = 0;
172 /**
173 * Set the soldier preference. Heroes or rookies?
174 */
175 virtual void set_soldier_preference(SoldierPref p) = 0;
176 /**
177 * \return the current soldier preference
178 */
179 virtual SoldierPref get_soldier_preference() const = 0;
180 /**
181 * Try to send the given soldier to attack the fiven target building.
182 * This will fail if the soldier already has a job.
183 */
184 virtual void sendAttacker(Soldier & soldier, Building & target, uint8_t retreat) = 0;
185};
186
187
188/**
189 * A Garrison owner holds a garrison. This interface is to be implemented by
190 * buildings that want to store some soldiers. The GarrionHandler Garrison
191 * implementation may be used as the Garrison provider.
192 */
193class GarrisonOwner {
194public:
195 /**
196 * \return the garrison instance
197 */
198 virtual Garrison* get_garrison() const = 0;
199 /**
200 * @return the building owning the garrison
201 */
202 virtual Building* get_building() = 0;
203 /**
204 * Called when the garrison has been lost. \param defeating is set to the
205 * enemy owner, or this owner if we keep military presence. if \param captured,
206 * the enemy captured the building and a new one must be force built.
207 *
208 * Will not be called by passive garrisons
209 */
210 virtual void garrison_lost(Game & game, Player_Number defeating, bool captured) = 0;
211 /**
212 * Called when the garrison is occupied. You may light up the fire now
213 *
214 * Will not be called by passive garrison
215 */
216 virtual void garrison_occupied() = 0;
217 /**
218 * Called on the new site when a site has been conquered
219 *
220 * Will not be called by passive garrison
221 */
222 virtual void reinit_after_conqueral(Game & game) = 0;
223};
224
225}
226
227#endif
0228
=== added file 'src/logic/garrisonhandler.cc'
--- src/logic/garrisonhandler.cc 1970-01-01 00:00:00 +0000
+++ src/logic/garrisonhandler.cc 2013-08-10 10:53:03 +0000
@@ -0,0 +1,925 @@
1/*
2* Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
3*
4* This program is free software; you can redistribute it and/or
5* modify it under the terms of the GNU General Public License
6* as published by the Free Software Foundation; either version 2
7* of the License, or (at your option) any later version.
8*
9* This program is distributed in the hope that it will be useful,
10* but WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12* GNU General Public License for more details.
13*
14* You should have received a copy of the GNU General Public License
15* along with this program; if not, write to the Free Software
16* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*
18*/
19
20#include "logic/garrisonhandler.h"
21
22#include <functional>
23#include <memory>
24#include <vector>
25
26#include <boost/foreach.hpp>
27#include <boost/format.hpp>
28
29#include "container_iterate.h"
30#include "economy/flag.h"
31#include "economy/request.h"
32#include "log.h"
33#include "logic/building.h"
34#include "logic/findbob.h"
35#include "logic/instances.h"
36#include "logic/militarysite.h"
37#include "logic/player.h"
38#include "logic/soldier.h"
39#include "upcast.h"
40
41namespace Widelands {
42
43GarrisonHandler::GarrisonHandler
44 (Building& building, uint32_t min_soldiers, uint32_t max_soldiers, uint32_t conquer_radius,
45 uint32_t heal_per_second, SoldierPref soldier_pref, bool passive)
46: Garrison(),
47m_building(building),
48m_min_capacity(min_soldiers),
49m_max_capacity(max_soldiers),
50m_capacity(max_soldiers),
51m_passive(passive),
52m_heal_per_second(heal_per_second),
53m_last_heal_time(0),
54m_conquer_radius(conquer_radius),
55m_didconquer(false),
56m_soldier_preference(soldier_pref),
57m_last_swap_soldiers_time(0),
58m_try_soldier_upgrade(false),
59m_doing_upgrade_request(false)
60{
61 assert(is_a(GarrisonOwner, &m_building));
62}
63
64GarrisonHandler::~GarrisonHandler()
65{
66 assert(m_normal_soldier_request.get() == nullptr);
67 assert(m_upgrade_soldier_request.get() == nullptr);
68}
69
70void GarrisonHandler::load_finish(Editor_Game_Base& egbase)
71{
72 // If our soldiers array is empty (old savegame), fill it with soldiers
73 // found in building
74 if (m_soldiers.empty()) {
75 container_iterate_const(std::vector<Worker *>, m_building.get_workers(), i) {
76 if (upcast(Soldier, soldier, *i.current)) {
77 if (m_soldiers.size() < m_capacity) {
78 m_soldiers.push_back(soldier);
79 } else {
80 break;
81 }
82 }
83 }
84 }
85}
86
87void GarrisonHandler::init(Editor_Game_Base & egbase)
88{
89 // Ensure all soldiers are fresh and give them a new task
90 upcast(Game, game, &egbase);
91 container_iterate_const(std::vector<Soldier *>, m_soldiers, i) {
92 Soldier* soldier = *i.current;
93 assert(!soldier->get_state()); // Should be newly created.
94 soldier->set_location_initially(m_building);
95 if (game) {
96 if (m_passive) {
97 soldier->start_task_idle(*game, 0, -1);
98 } else {
99 soldier->start_task_buildingwork(*game);
100 }
101 }
102 }
103 // Update requests and timers
104 update_soldier_request();
105 m_last_heal_time = egbase.get_gametime();
106}
107
108void GarrisonHandler::reinit_after_conqueral(Game& game)
109{
110 m_soldier_requirements = Requirements();
111 conquer_area(game);
112 update_soldier_request();
113}
114
115void GarrisonHandler::cleanup(Editor_Game_Base& egbase)
116{
117 if (m_didconquer && !m_passive) {
118 egbase.unconquer_area
119 (Player_Area<Area<FCoords> >
120 (owner().player_number(),
121 Area<FCoords>(egbase.map().get_fcoords(m_building.get_position()), m_conquer_radius)),
122 m_building.get_defeating_player());
123 }
124}
125
126void GarrisonHandler::cleanup_requests(Editor_Game_Base&)
127{
128 m_normal_soldier_request.reset();
129 m_upgrade_soldier_request.reset();
130}
131
132
133int32_t GarrisonHandler::act(Game& game)
134{
135 const int32_t timeofgame = game.get_gametime();
136 int32_t next_act = -1;
137 // Ensure requests integrity
138 if (m_normal_soldier_request && m_upgrade_soldier_request)
139 {
140 throw wexception("GarrisonHandler::act: Two soldier requests are ongoing -- should never happen!\n");
141 }
142 // Update requests periodically
143 bool full = stationedSoldiers().size() >= m_capacity;
144 if (!full && !m_doing_upgrade_request && !m_normal_soldier_request) {
145 // if we miss soldiers
146 update_soldier_request();
147 } else {
148 // If we may issue a new upgrade request
149 int32_t time_since_last_swap = (timeofgame - m_last_swap_soldiers_time);
150 if (time_since_last_swap > GARRISON_SWAP_TIMEOUT) {
151 time_since_last_swap = timeofgame;
152 update_soldier_request();
153 if (next_act < 0 || next_act > GARRISON_SWAP_TIMEOUT) {
154 next_act = GARRISON_SWAP_TIMEOUT;
155 }
156 }
157 }
158
159 // Calculate the amount of heal point to distribute
160 uint32_t to_heal_amount = static_cast<uint32_t>
161 ((timeofgame - m_last_heal_time) * m_heal_per_second / 1000);
162 const std::vector<Soldier*> soldiers = presentSoldiers();
163 BOOST_FOREACH(Soldier* soldier, soldiers) {
164 uint32_t to_heal = soldier->get_max_hitpoints() - soldier->get_current_hitpoints();
165 if (to_heal > to_heal_amount) to_heal = to_heal_amount;
166 if (to_heal > 0) {
167 soldier->heal(to_heal);
168 to_heal_amount -= to_heal;
169 // Act once/s while healing
170 if (next_act < 0 || next_act > 1000) {
171 next_act = 1000;
172 }
173 }
174 if (to_heal_amount <= 0) break;
175 }
176 m_last_heal_time = timeofgame;
177 // Act once/5s when idle
178 if (next_act < 0) {
179 next_act = 5000;
180 }
181 return next_act;
182}
183
184void GarrisonHandler::popSoldier(Soldier* soldier)
185{
186 // Pop the soldier and update requests
187 popSoldierJob(soldier, nullptr, nullptr);
188 update_soldier_request();
189}
190
191void GarrisonHandler::set_economy(Economy * const e)
192{
193 // update requests
194 if (m_normal_soldier_request && e)
195 m_normal_soldier_request->set_economy(e);
196 if (m_upgrade_soldier_request && e)
197 m_upgrade_soldier_request->set_economy(e);
198}
199
200
201
202bool GarrisonHandler::get_garrison_work(Game& game, Soldier* soldier)
203{
204 // Evict soldiers that have returned home if the capacity is too low
205 if (m_capacity < stationedSoldiers().size()) {
206 evict_soldier(game, soldier);
207 return true;
208 }
209
210 bool stayhome;
211 uint8_t retreat;
212 if (Map_Object* enemy = popSoldierJob(soldier, &stayhome, &retreat)) {
213 if (upcast(Building, building, enemy)) {
214 soldier->start_task_attack(game, *building, retreat);
215 return true;
216 } else if (upcast(Soldier, opponent, enemy)) {
217 if (!opponent->getBattle()) {
218 soldier->start_task_defense(game, stayhome, retreat);
219 if (stayhome)
220 opponent->send_signal(game, "sleep");
221 return true;
222 }
223 } else
224 throw wexception("GarrisonHandler::get_garrison_work: bad SoldierJob");
225 }
226 return false;
227}
228
229void GarrisonHandler::set_soldier_requirements(Requirements req)
230{
231 m_soldier_requirements = req;
232}
233
234//
235// Garrison implementation
236//
237
238Player& GarrisonHandler::owner() const
239{
240 return m_building.owner();
241}
242
243bool GarrisonHandler::canAttack() const
244{
245 return m_didconquer && !m_passive;
246}
247
248void GarrisonHandler::aggressor(Soldier& enemy)
249{
250 Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
251 Map & map = game.map();
252 // Do not react if enemy is occupied or too far away
253 if
254 (enemy.get_owner() == &owner() || enemy.getBattle()
255 || m_conquer_radius <= map.calc_distance
256 (enemy.get_position(), m_building.get_position()))
257 {
258 return;
259 }
260
261 // Do not react if enemy is at our door
262 if
263 (map.find_bobs
264 (Area<FCoords>(map.get_fcoords(m_building.base_flag().get_position()), 2), 0,
265 FindBobEnemySoldier(&owner())))
266 {
267 return;
268 }
269
270 // Send some soldiers to defend, keeping min capacity inside
271 // This will send 1 soldier out to defend each time agressor()
272 // is called //FIXME?
273 const std::vector<Soldier*>& presents = presentSoldiers();
274 if (presents.size() > m_min_capacity) {
275 container_iterate_const(std::vector<Soldier *>, presents, i) {
276 if (!haveSoldierJob(**i.current)) {
277 SoldierJob sj;
278 sj.soldier = *i.current;
279 sj.enemy = &enemy;
280 sj.stayhome = false;
281 sj.retreat = owner().get_retreat_percentage();
282 m_soldierjobs.push_back(sj);
283 (*i.current)->update_task_buildingwork(game);
284 return;
285 }
286 }
287 }
288
289 // Inform the player, that we are under attack by adding a new entry to the
290 // message queue - a sound will automatically be played.
291 inform_owner(game, InfoType::AGGRESSSED);
292}
293
294bool GarrisonHandler::attack(Soldier& enemy)
295{
296 Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
297
298 const std::vector<Soldier*>& present = presentSoldiers();
299 Soldier * defender = 0;
300
301 if (!present.empty()) {
302 // Find soldier with greatest hitpoints
303 uint32_t current_max = 0;
304 container_iterate_const(std::vector<Soldier *>, present, i) {
305 if ((*i.current)->get_current_hitpoints() > current_max) {
306 defender = *i.current;
307 current_max = defender->get_current_hitpoints();
308 }
309 }
310 } else {
311 // If one of our stationed soldiers is currently walking into the
312 // building, give us another chance.
313 const std::vector<Soldier *>& stationed = stationedSoldiers();
314 container_iterate_const(std::vector<Soldier *>, stationed, i) {
315 if ((*i.current)->get_position() == m_building.get_position()) {
316 defender = *i.current;
317 break;
318 }
319 }
320 }
321
322 if (defender) {
323 popSoldierJob(defender); // defense overrides all other jobs
324
325 SoldierJob sj;
326 sj.soldier = defender;
327 sj.enemy = &enemy;
328 sj.stayhome = true;
329 sj.retreat = 0; // Flag defenders could not retreat
330 m_soldierjobs.push_back(sj);
331
332 defender->update_task_buildingwork(game);
333
334 // Inform the player, that we are under attack by adding a new entry to
335 // the message queue - a sound will automatically be played.
336 inform_owner(game, InfoType::UNDER_ATTACK);
337 return true;
338 }
339
340 // The enemy has defeated our forces, we should inform the player
341 // Code for handling change of owner are handled in the garrison
342 // owner class.
343 upcast(GarrisonOwner, go, &m_building);
344 if (military_presence_kept(game)) {
345 inform_owner(game, InfoType::GARRISON_LOST);
346 go->garrison_lost(game, owner().player_number(), false);
347 } else {
348 inform_owner(game, InfoType::GARRISON_CAPTURED);
349 go->garrison_lost(game, enemy.owner().player_number(), true);
350 }
351 return false;
352}
353
354bool GarrisonHandler::is_passive()
355{
356 return m_passive;
357}
358
359Building& GarrisonHandler::get_building()
360{
361 return m_building;
362}
363
364
365
366const std::vector< Soldier* > GarrisonHandler::presentSoldiers() const
367{
368 std::vector<Soldier *> present_soldiers;
369 container_iterate_const(std::vector<Soldier*>, m_soldiers, i) {
370 if (isPresent(**i.current)) {
371 present_soldiers.push_back(*i.current);
372 }
373 }
374 return present_soldiers;
375}
376
377const std::vector< Soldier* > GarrisonHandler::stationedSoldiers() const
378{
379 return m_soldiers;
380}
381
382uint32_t GarrisonHandler::minSoldierCapacity() const
383{
384 return m_min_capacity;
385}
386
387uint32_t GarrisonHandler::maxSoldierCapacity() const
388{
389 return m_max_capacity;
390}
391
392uint32_t GarrisonHandler::soldierCapacity() const
393{
394 return m_capacity;
395}
396
397void GarrisonHandler::setSoldierCapacity(uint32_t capacity)
398{
399 assert(minSoldierCapacity() <= capacity);
400 assert (capacity <= maxSoldierCapacity());
401 assert(m_capacity != capacity);
402 m_capacity = capacity;
403 update_soldier_request();
404}
405
406void GarrisonHandler::dropSoldier(Soldier& soldier)
407{
408 Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
409
410 if (!isPresent(soldier)) {
411 // This can happen when the "drop soldier" player command is delayed
412 // by network delay or a client has bugs.
413 return;
414 }
415 // Ensure min capacity is respected
416 if (presentSoldiers().size() <= minSoldierCapacity()) {
417 return;
418 }
419 // Drop the soldier and update requests
420 evict_soldier(game, &soldier);
421 update_soldier_request();
422}
423
424int GarrisonHandler::incorporateSoldier(Editor_Game_Base& egbase, Soldier& s)
425{
426 // Adjust the soldier location if required.
427 if (s.get_location(egbase) != &m_building)
428 {
429 s.set_location(&m_building);
430 }
431 m_soldiers.push_back(&s);
432
433 upcast(Game, game, &egbase);
434 // If it's the first soldier, conquer the area
435 if (!m_passive && !m_didconquer) {
436 conquer_area(egbase);
437 if (game) {
438 inform_owner(*game, InfoType::GARRISON_OCCUPIED);
439 }
440 upcast(GarrisonOwner, go, &m_building);
441 go->garrison_occupied();
442 }
443
444 // Bind the worker into this house, hide him on the map
445 if (game) {
446 s.reset_tasks(*game);
447 if (m_passive) {
448 s.start_task_idle(*game, 0, -1);
449 } else {
450 s.start_task_buildingwork(*game);
451 }
452 }
453 // Make sure the request count is reduced or the request is deleted.
454 update_soldier_request();
455 return 0;
456}
457
458int GarrisonHandler::outcorporateSoldier(Editor_Game_Base&, Soldier&)
459{
460 // not needed
461 log("CGH Outcorporate called\n");
462 return -1;
463}
464
465uint32_t GarrisonHandler::conquerRadius() const
466{
467 return m_conquer_radius;
468}
469
470void GarrisonHandler::set_soldier_preference(GarrisonHandler::SoldierPref p)
471{
472 assert(SoldierPref::Heroes == p || SoldierPref::Rookies == p);
473 m_soldier_preference = p;
474 update_normal_soldier_request();
475}
476
477
478void GarrisonHandler::sendAttacker(Soldier& soldier, Building& target, uint8_t retreat)
479{
480 assert(isPresent(soldier));
481
482 if (haveSoldierJob(soldier)) {
483 return;
484 }
485
486 SoldierJob sj;
487 sj.soldier = &soldier;
488 sj.enemy = &target;
489 sj.stayhome = false;
490 sj.retreat = retreat;
491 m_soldierjobs.push_back(sj);
492
493 soldier.update_task_buildingwork(ref_cast<Game, Editor_Game_Base>(owner().egbase()));
494}
495
496//
497// Private helper methods
498//
499void GarrisonHandler::inform_owner(Game& game, GarrisonHandler::InfoType info)
500{
501 if (m_passive) {
502 return;
503 }
504 std::string message;
505 std::string message_id;
506 std::string message_title;
507 std::string building_name = m_building.descname();
508 switch (info) {
509 case InfoType::AGGRESSSED:
510 message =
511 (boost::format
512 (_("Your %s discovered an aggressor")) % building_name)
513 .str();
514 message_id = "under_attack";
515 message_title = _("You are under attack");
516 break;
517 case InfoType::UNDER_ATTACK:
518 message =
519 (boost::format
520 (_("Your %s is under attack")) % building_name)
521 .str();
522 message_id = "under_attack";
523 message_title = _("You are under attack");
524 break;
525 case InfoType::GARRISON_LOST:
526 message =
527 (boost::format
528 (_("The enemy defeated your soldiers and destroyed your %s")) % building_name)
529 .str();
530 message_id = "garrison_lost";
531 message_title = _("Garrison lost");
532 break;
533 case InfoType::GARRISON_CAPTURED:
534 message =
535 (boost::format
536 (_("The enemy defeated your soldiers and captured your %s")) % building_name)
537 .str();
538 message_id = "garrison_lost";
539 message_title = _("Garrison captured");
540 break;
541 case InfoType::GARRISON_OCCUPIED:
542 message =
543 (boost::format
544 (_("Your soldier occupied your %s")) % building_name)
545 .str();
546 message_id = "garrison_occupied";
547 message_title = _("Garrison occupied");
548 break;
549 default:
550 assert(false);
551 }
552 m_building.send_message(game, message_id, message_title, message);
553}
554
555bool GarrisonHandler::isPresent(Soldier& soldier) const
556{
557 if
558 (soldier.get_location(owner().egbase()) != &m_building
559 || soldier.get_position() != m_building.get_position())
560 {
561 return false;
562 }
563 // Present soldiers are working for the garrison only if it is not passive
564 if (!m_passive) {
565 return
566 soldier.get_state() == soldier.get_state(Worker::taskBuildingwork);
567 }
568 return true;
569}
570
571void GarrisonHandler::conquer_area(Editor_Game_Base& egbase)
572{
573 assert(!m_didconquer);
574 egbase.conquer_area
575 (Player_Area<Area<FCoords> >
576 (owner().player_number(),
577 Area<FCoords>
578 (egbase.map().get_fcoords(m_building.get_position()), m_conquer_radius)));
579 m_didconquer = true;
580}
581
582bool GarrisonHandler::military_presence_kept(Game& game)
583{
584 // collect information about immovables in the area
585 std::vector<ImmovableFound> immovables;
586
587 // Search in a radius of 3 (needed for big militarysites)
588 FCoords const fc = game.map().get_fcoords(m_building.get_position());
589 game.map().find_immovables(Area<FCoords>(fc, 3), &immovables);
590
591 for (uint32_t i = 0; i < immovables.size(); ++i) {
592 upcast(GarrisonOwner, go, immovables[i].object);
593 if (!go) {
594 continue;
595 }
596 Garrison* g = go->get_garrison();
597 upcast(GarrisonOwner, mygo, &m_building);
598 // NOCOM I changed the logic here to check for any stationed soldier
599 // and not for m_didconquer. So a msite with all slots empty and soldiers
600 // on their way won't keep military presence anymore.
601
602 // Presence kept if any non-empty garrison with higher conquer radius
603 // and owned by our owner is nearby
604 if
605 (mygo != go
606 && owner().player_number() == g->owner().player_number()
607 && conquerRadius() < g->conquerRadius()
608 && !g->stationedSoldiers().empty())
609 {
610 return true;
611 }
612 }
613 return false;
614}
615
616//FIXME CGH use a cleaner way without polling required
617void GarrisonHandler::update_soldier_request(bool upgraded_in)
618{
619/*
620 * I have update_soldier_request
621 * update_upgrade_soldier_request
622 * update_normal_soldier_request
623 *
624 * The first one handles state switching between site fill (normal more)
625 * and grabbing soldiers with proper training (upgrade mode). The last
626 * two actually make the requests.
627 *
628 * The input parameter incd is true, if we just incorporated a new soldier
629 * as a result of an upgrade request. In such cases, we will re-arm the
630 * upgrade request.
631 */
632 const uint32_t capacity = soldierCapacity();
633 const uint32_t stationed = stationedSoldiers().size();
634
635 if (m_doing_upgrade_request) {
636 if (upgraded_in && m_upgrade_soldier_request) {// update requests always ask for one soldier at time!
637 m_upgrade_soldier_request.reset();
638 }
639 if (capacity > stationed) {
640 // Somebody is killing my soldiers in the middle of upgrade
641 // or I have kicked out his predecessor already.
642 if
643 ((m_upgrade_soldier_request)
644 && (m_upgrade_soldier_request->is_open() || 0 == m_upgrade_soldier_request->get_count()))
645 {
646 // Economy was not able to find the soldiers I need.
647 // I can safely drop the upgrade request and go to fill mode.
648 m_upgrade_soldier_request.reset();
649 }
650 if (!m_upgrade_soldier_request) {
651 //phoo -- I can safely request new soldiers.
652 m_doing_upgrade_request = false;
653 update_normal_soldier_request();
654 }
655 // else -- ohno please help me! Player is in trouble -- evil grin
656 // An upgraded soldier is on his way, but since we only make one request
657 // at a time, we have to wait for him to arrive before doing another
658 // request to fill capacity.
659 //FIXME
660 } else if (capacity < stationed) {// player is reducing capacity
661 drop_least_suited_soldier();
662 } else {// capacity == stationed size
663 update_upgrade_soldier_request();
664 }
665 } else {// not doing upgrade request
666 if ((capacity != stationed) or (m_normal_soldier_request)) {
667 update_normal_soldier_request();
668 }
669 if ((capacity == stationed) && (! m_normal_soldier_request) && !m_passive) {
670 // Our site is full, we might try to get upgraded soldiers
671 // TODO not allowed for passive garrison for now
672 if (presentSoldiers().size() == capacity && capacity > m_min_capacity) {
673 m_doing_upgrade_request = true;
674 }
675 }
676 }
677}
678
679void GarrisonHandler::update_normal_soldier_request()
680{
681 // Request new soldiers if needed
682 std::vector<Soldier*> soldiers = stationedSoldiers();
683 if (soldiers.size() < m_capacity) {
684 if (!m_normal_soldier_request) {
685 // No ongoing request, fill a new one
686 Request* r = new Request
687 (m_building, m_building.tribe().safe_worker_index("soldier"),
688 GarrisonHandler::request_soldier_callback, wwWORKER);
689 r->set_requirements(m_soldier_requirements);
690 m_normal_soldier_request.reset(r);
691 }
692 // Already an ongoing request, update counts
693 m_normal_soldier_request->set_count(m_capacity - soldiers.size());
694 } else {
695 // No new soldier required. Destroy request if there is one
696 m_normal_soldier_request.reset();
697 }
698 // Evict present soldiers if required
699 const std::vector<Soldier *>& present = presentSoldiers();
700 if (present.size() > m_capacity) {
701 Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
702 for (uint32_t i = 0; i < present.size() - m_capacity; ++i) {
703 Soldier * soldier = present[i];
704 evict_soldier(game, soldier);
705 }
706 }
707}
708
709void GarrisonHandler::update_upgrade_soldier_request()
710{
711 bool reqirement_changed = update_upgrade_requirements();
712 // Update the requirements
713 if (!m_try_soldier_upgrade) {
714 return;
715 }
716 // Do not perform a new request if someone is on his way
717 // or if we are going to request the same thing
718 if (m_upgrade_soldier_request) {
719 if (!m_upgrade_soldier_request->is_open()) {
720 // upgraded soldier is on his way
721 return;
722 }
723 if (!reqirement_changed && m_upgrade_soldier_request->get_count() > 0) {
724 // Current request is still valid
725 return;
726 }
727 }
728 // Issue a new request
729 Request* r = new Request
730 (m_building, m_building.tribe().safe_worker_index("soldier"),
731 GarrisonHandler::request_soldier_callback, wwWORKER,
732 GarrisonHandler::request_soldier_transfer_callback);
733 // Honor soldier requirements if set by the garrison owner
734 RequireAnd upgrade_requirement;
735 upgrade_requirement.add(m_soldier_requirements);
736 upgrade_requirement.add(m_soldier_upgrade_requirements);
737 r->set_requirements(upgrade_requirement);
738 r->set_count(1);
739 m_upgrade_soldier_request.reset(r);
740}
741
742void GarrisonHandler::request_soldier_callback
743 (Game& game, Request&, Ware_Index, Worker* w, PlayerImmovable& pi)
744{
745 Soldier& s = ref_cast<Soldier, Worker>(*w);
746 upcast(GarrisonOwner, go, &pi);
747 upcast(GarrisonHandler, gh, go->get_garrison());
748
749 if (!gh->m_doing_upgrade_request) {
750 gh->incorporateSoldier(game, s);
751 } else {
752 gh->incorporateUpgradedSoldier(game, s);
753 }
754}
755
756void GarrisonHandler::request_soldier_transfer_callback
757 (Game&, Request&, Ware_Index, Worker* w, PlayerImmovable& pi)
758{
759 Soldier& s = ref_cast<Soldier, Worker>(*w);
760 upcast(GarrisonOwner, go, &pi);
761 upcast(GarrisonHandler, gh, go->get_garrison());
762
763 if (gh->m_doing_upgrade_request) {
764 gh->drop_least_suited_soldier(&s);
765 }
766}
767
768bool GarrisonHandler::update_upgrade_requirements()
769{
770 int32_t soldier_upgrade_required_min = m_soldier_upgrade_requirements.getMin();
771 int32_t soldier_upgrade_required_max = m_soldier_upgrade_requirements.getMax();
772
773 if
774 (SoldierPref::Heroes != m_soldier_preference
775 && SoldierPref::Rookies != m_soldier_preference)
776 {
777 m_try_soldier_upgrade = false;
778 return false;
779 }
780
781 // Find the level of the soldier that is currently least-suited.
782 Soldier * worst_guy = find_least_suited_soldier();
783 if (worst_guy == nullptr) {
784 // There could be no soldier in the militarysite right now. No reason to freak out.
785 return false;
786 }
787 int32_t wg_level = worst_guy->get_level(atrTotal);
788
789 // Micro-optimization: I assume that the majority of military sites have only level-zero
790 // soldiers and prefer rookies. Handle them separately.
791 if (m_soldier_preference == SoldierPref::Rookies && wg_level == 0) {
792 m_try_soldier_upgrade = false;
793 return false;
794 }
795 m_try_soldier_upgrade = true;
796
797 // Now I actually build the new requirements.
798 int32_t reqmin = SoldierPref::Heroes == m_soldier_preference ? 1 + wg_level : 0;
799 int32_t reqmax = SoldierPref::Heroes == m_soldier_preference ? SHRT_MAX : wg_level - 1;
800
801 bool maxchanged = reqmax != soldier_upgrade_required_max;
802 bool minchanged = reqmin != soldier_upgrade_required_min;
803
804 if (maxchanged or minchanged) {
805 m_soldier_upgrade_requirements = RequireAttribute(atrTotal, reqmin, reqmax);
806 return true;
807 }
808 return false;
809}
810
811bool GarrisonHandler::incorporateUpgradedSoldier(Editor_Game_Base& egbase, Soldier& s)
812{
813 // Call to drop_least routine has side effects: it tries to drop a soldier. Order is important!
814 assert(isPresent(s));
815 std::vector<Soldier*> stationned = stationedSoldiers();
816 if (stationned.size() < m_capacity || drop_least_suited_soldier(&s)) {
817 Game & game = ref_cast<Game, Editor_Game_Base>(egbase);
818 s.set_location(&m_building);
819 m_soldiers.push_back(&s);
820 s.reset_tasks(game);
821 if (!m_passive) {
822 s.start_task_buildingwork(game);
823 } else {
824 s.start_task_idle(game, 0, -1);
825 }
826 // Reset timer for new request
827 m_upgrade_soldier_request.reset();
828 m_last_swap_soldiers_time = game.get_gametime();
829 return true;
830 }
831 return false;
832}
833
834Soldier* GarrisonHandler::find_least_suited_soldier()
835{
836 const std::vector<Soldier *>& present = presentSoldiers();
837 const int32_t multiplier = m_soldier_preference == SoldierPref::Heroes ? -1 : 1;
838 int worst_soldier_level = INT_MIN;
839 Soldier * worst_soldier = nullptr;
840 BOOST_FOREACH(Soldier * sld, present)
841 {
842 int this_soldier_level = multiplier * static_cast<int> (sld->get_level(atrTotal));
843 if (this_soldier_level > worst_soldier_level)
844 {
845 worst_soldier_level = this_soldier_level;
846 worst_soldier = sld;
847 }
848 }
849 return worst_soldier;
850}
851
852bool GarrisonHandler::drop_least_suited_soldier(Soldier* newguy)
853{
854 const std::vector<Soldier *>& present = presentSoldiers();
855 // Don't drop under the minimum capacity if new guy is not here yet
856 if (newguy == nullptr && present.size() <= m_min_capacity) {
857 return false;
858 }
859 Soldier * kickoutCandidate = find_least_suited_soldier();
860
861 // If the arriving guy is worse than worst present, I wont't release.
862 if (newguy != nullptr && kickoutCandidate != nullptr) {
863 int32_t old_level = kickoutCandidate->get_level(atrTotal);
864 int32_t new_level = newguy->get_level(atrTotal);
865 if (m_soldier_preference == SoldierPref::Heroes && old_level >= new_level) {
866 return false;
867 } else if (m_soldier_preference == SoldierPref::Rookies && old_level <= new_level) {
868 return false;
869 }
870 }
871
872 // Now I know that the new guy is worthy.
873 if (kickoutCandidate != nullptr) {
874 Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
875 evict_soldier(game, kickoutCandidate);
876 return true;
877 }
878 return false;
879}
880
881bool GarrisonHandler::haveSoldierJob(Soldier& soldier) const
882{
883 container_iterate_const(std::vector<SoldierJob>, m_soldierjobs, i) {
884 if (i.current->soldier == &soldier) {
885 return true;
886 }
887 }
888 return false;
889}
890
891Map_Object* GarrisonHandler::popSoldierJob(Soldier* soldier, bool* stayhome, uint8_t* retreat)
892{
893 container_iterate(std::vector<SoldierJob>, m_soldierjobs, i)
894 if (i.current->soldier == soldier) {
895 Map_Object * const enemy = i.current->enemy.get(owner().egbase());
896 if (stayhome)
897 *stayhome = i.current->stayhome;
898 if (retreat)
899 *retreat = i.current->retreat;
900 m_soldierjobs.erase(i.current);
901 return enemy;
902 }
903 return 0;
904}
905
906void GarrisonHandler::evict_soldier(Game& game, Soldier* s)
907{
908 assert(s);
909 upcast(StorageOwner, storage_owner, &m_building);
910 std::vector<Soldier*>::iterator it;
911 for (it = m_soldiers.begin(); it != m_soldiers.end(); ++it) {
912 if ((*it)->serial() == s->serial()) {
913 m_soldiers.erase(it);
914 s->reset_tasks(game);
915 if (storage_owner) {
916 storage_owner->get_storage()->incorporate_worker(game, *s);
917 } else {
918 s->start_task_leavebuilding(game, true);
919 }
920 return;
921 }
922 }
923}
924
925}
0926
=== added file 'src/logic/garrisonhandler.h'
--- src/logic/garrisonhandler.h 1970-01-01 00:00:00 +0000
+++ src/logic/garrisonhandler.h 2013-08-10 10:53:03 +0000
@@ -0,0 +1,262 @@
1/*
2 * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef GARRISON_HANDLER_H
21#define GARRISON_HANDLER_H
22
23#include "logic/instances.h"
24#include "logic/garrison.h"
25#include "logic/requirements.h"
26#include "logic/worker.h"
27
28namespace Widelands {
29
30struct Building;
31struct Request;
32class Soldier;
33
34#define GARRISON_SWAP_TIMEOUT 20000
35/**
36 * Implementation of the Garrison interface to used by GarrisonOwner.
37 */
38class GarrisonHandler : public Garrison {
39friend struct Map_Buildingdata_Data_Packet;
40public:
41 /**
42 * Create a new garrison handler
43 * \param building The building that holds this garrison. Must implements GarrisonOwner
44 * \param min_soldiers The minimum soldiers to be present in the garrison
45 * \param max_soldiers The maximum soldiers that can be present in this garrison
46 * \param conquer_radius The radius of the area conqered by this garrison
47 * \param heal_per_second The speed at which soldiers will be healed
48 * \param soldier_pref The soldier preference for rookies or heroes
49 * \param passive A passive garrison is only helpful to keep some soldiers around. It can't
50 * attack nor be attacked. I think of training site or ships
51 */
52 GarrisonHandler
53 (Building& building, uint32_t min_soldiers, uint32_t max_soldiers,
54 uint32_t conquer_radius, uint32_t heal_per_second, SoldierPref soldier_pref,
55 bool passive = false);
56 virtual ~GarrisonHandler();
57
58 void load_finish(Editor_Game_Base &);
59 /**
60 * Must be called once
61 */
62 void init(Editor_Game_Base &);
63 /**
64 * Must be called once after conqueral
65 */
66 void reinit_after_conqueral(Game & game);
67 /**
68 * Cleanup handled objects
69 */
70 void cleanup(Editor_Game_Base &);
71 /**
72 * Eequests must be cleaned up after the building has
73 * been cleaned up, hence this seperate function.
74 */
75 void cleanup_requests(Editor_Game_Base &);
76 /**
77 * Must be called regularly. It is not time dependant though.
78 * \Return the time when the next act should occur
79 */
80 int32_t act(Game &);
81 /**
82 * Must be called when the owner building changes economy
83 */
84 void set_economy(Economy * const e);
85 /**
86 * Pop the given soldier out of the building, while keeping it
87 * in the garrion.
88 */
89 void popSoldier(Soldier* soldier);
90 /**
91 * Get some work for a soldier that asks for it
92 */
93 bool get_garrison_work(Game & game, Soldier* soldier);
94 /**
95 * Set the requirements for that soldier. This will be used when filling
96 * request for soldiers.
97 */
98 void set_soldier_requirements(Requirements req);
99
100 // Garrison implementation
101 virtual Player & owner() const;
102 virtual bool canAttack() const;
103 virtual void aggressor(Soldier &);
104 virtual bool attack(Soldier &);
105 virtual bool is_passive();
106 virtual Building& get_building();
107 virtual const std::vector<Soldier *> presentSoldiers() const;
108 virtual const std::vector<Soldier *> stationedSoldiers() const;
109 virtual uint32_t minSoldierCapacity() const;
110 virtual uint32_t maxSoldierCapacity() const;
111 virtual uint32_t soldierCapacity() const;
112 virtual void setSoldierCapacity(uint32_t capacity);
113 virtual void dropSoldier(Soldier &);
114 virtual int incorporateSoldier(Editor_Game_Base &, Soldier &);
115 virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &);
116 virtual uint32_t conquerRadius() const;
117 virtual void set_soldier_preference(SoldierPref p);
118 virtual SoldierPref get_soldier_preference() const {
119 return m_soldier_preference;
120 }
121 virtual void sendAttacker(Soldier & soldier, Building & target, uint8_t retreat);
122
123
124private:
125 enum class InfoType : uint8_t {
126 AGGRESSSED,
127 UNDER_ATTACK,
128 GARRISON_LOST,
129 GARRISON_CAPTURED,
130 GARRISON_OCCUPIED
131 };
132 // Helper methods
133 /**
134 * Sends a message to the owner
135 */
136 void inform_owner(Game&, InfoType);
137 /**
138 * Check if a soldier is actually present in building
139 */
140 bool isPresent(Soldier &) const;
141 /**
142 * Conquers the area once a soldier occupied the site
143 */
144 void conquer_area(Editor_Game_Base &);
145 /**
146 * Check if we keep military influence once our garrison
147 * has been conquered
148 */
149 bool military_presence_kept(Game &);
150 /**
151 * Update the soldier requests. If upgraded_incorporated, a soldier
152 * requested by an upgrade request has just been incorporated. This
153 * method handle requesting for normal case (filling slots) or for
154 * upgrading to a better suited soldier
155 */
156 void update_soldier_request(bool upgraded_incorporated = false);
157 /**
158 * Request new soldiers or evict some to fill the capacity
159 */
160 void update_normal_soldier_request();
161 /* There are two kinds of soldier requests: "normal", which is used whenever the military site needs
162 * more soldiers, and "upgrade" which is used when there is a preference for either heroes or
163 * rookies.
164 *
165 * In case of normal requests, the military site is filled. In case of upgrade requests, only one guy
166 * is exchanged at a time.
167 *
168 * There would be more efficient ways to get well trained soldiers. Now, new buildings appearing in battle
169 * field are more vulnerable at the beginning. This is intentional. The purpose of this upgrade thing is
170 * to reduce the benefits of site micromanagement. The intention is not to make gameplay easier
171 * in other ways.
172 */
173 void update_upgrade_soldier_request();
174 /**
175 * The callback function, called whenever one of our soldier requested arrived
176 */
177 static void request_soldier_callback
178 (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
179 /**
180 * The transfer callback function, called whenever one of our requested
181 * soldier started to move towards the garrison
182 */
183 static void request_soldier_transfer_callback
184 (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
185 /*
186 * When upgrading soldiers, we do not ask for just any soldiers, but soldiers
187 * that are better than what we already have. This routine sets the requirements
188 * used by the request.
189 *
190 * The routine returns true if upgrade request thresholds have changed. This information could be
191 * used to decide whether the soldier-Request should be upgraded. Additionally, the m_try_soldier_upgrade
192 * field will be set so to know if an attempt to get better soldier sould be performed.
193 */
194 bool update_upgrade_requirements();
195 /**
196 * Called when an upgraded soldier comes to join the garrison
197 */
198 bool incorporateUpgradedSoldier(Editor_Game_Base & game, Soldier & s);
199 /**
200 * Find the least suited soldier for this garrison. We don't play
201 * in the same league
202 */
203 Soldier * find_least_suited_soldier();
204 /**
205 * Try to drop the lease suited soldier, return true on success.
206 * If a new soldier s has arrived, extra care will be taken to not drop
207 * anyone if the new one is even worst
208 */
209 bool drop_least_suited_soldier(Soldier * s = nullptr);
210 /**
211 * Return true if we hold a running job for that soldied
212 */
213 bool haveSoldierJob(Soldier &) const;
214 /**
215 * \return the enemy, if any, that the given soldier was scheduled
216 * to attack, and remove the job.
217 */
218 Map_Object * popSoldierJob(Soldier *, bool * stayhome = 0, uint8_t * retreat = 0);
219
220 void evict_soldier(Game&, Soldier*);
221
222 // Basic fields
223 Building& m_building;
224 uint32_t m_min_capacity;
225 uint32_t m_max_capacity;
226 uint32_t m_capacity;
227 bool m_passive;
228 std::vector<Soldier*> m_soldiers;
229
230 // Healing
231 uint32_t m_heal_per_second;
232 uint32_t m_last_heal_time;
233
234 // Requests
235 Requirements m_soldier_requirements; // This is used to grab a bunch of soldiers: Anything goes
236 RequireAttribute m_soldier_upgrade_requirements; // This is used when exchanging soldiers.
237 std::unique_ptr<Request> m_normal_soldier_request; // filling the site
238 std::unique_ptr<Request> m_upgrade_soldier_request; // seeking for better soldiers
239
240 // Conqueral
241 uint32_t m_conquer_radius;
242 bool m_didconquer;
243
244 // Job
245 struct SoldierJob {
246 Soldier * soldier;
247 Object_Ptr enemy;
248 bool stayhome;
249 uint8_t retreat;
250 };
251 std::vector<SoldierJob> m_soldierjobs;
252
253 // Soldier preferences
254 SoldierPref m_soldier_preference;
255 uint32_t m_last_swap_soldiers_time;
256 bool m_try_soldier_upgrade; // optimization -- if everybody is zero-level, do not downgrade
257 bool m_doing_upgrade_request;
258};
259
260}
261
262#endif
0263
=== modified file 'src/logic/item_ware_descr.h'
--- src/logic/item_ware_descr.h 2013-07-26 20:19:36 +0000
+++ src/logic/item_ware_descr.h 2013-08-10 10:53:03 +0000
@@ -41,7 +41,7 @@
41namespace Widelands {41namespace Widelands {
4242
43/**43/**
44 * Wares can be stored in warehouses. They can be transferred across an44 * Wares can be stored in storages. They can be transferred across an
45 * Economy. They can be traded.45 * Economy. They can be traded.
46 * Both items (lumber, stone, ...) and workers are considered wares.46 * Both items (lumber, stone, ...) and workers are considered wares.
47 * Every ware has a unique name. Note that an item must not have the same47 * Every ware has a unique name. Note that an item must not have the same
@@ -75,7 +75,7 @@
75 /// \return ware's localized descriptive text75 /// \return ware's localized descriptive text
76 const std::string & helptext() const throw () {return m_helptext;}76 const std::string & helptext() const throw () {return m_helptext;}
7777
78 /// How much of the ware type that an economy should store in warehouses.78 /// How much of the ware type that an economy should store in storages.
79 /// The special value std::numeric_limits<uint32_t>::max() means that the79 /// The special value std::numeric_limits<uint32_t>::max() means that the
80 /// the target quantity of this ware type will never be checked and should80 /// the target quantity of this ware type will never be checked and should
81 /// not be configurable.81 /// not be configurable.
8282
=== modified file 'src/logic/militarysite.cc'
--- src/logic/militarysite.cc 2013-08-08 19:55:12 +0000
+++ src/logic/militarysite.cc 2013-08-10 10:53:03 +0000
@@ -21,8 +21,10 @@
2121
22#include <clocale>22#include <clocale>
23#include <cstdio>23#include <cstdio>
24#include <memory>
2425
25#include <boost/foreach.hpp>26#include <boost/foreach.hpp>
27#include <boost/format.hpp>
26#include <libintl.h>28#include <libintl.h>
2729
28#include "economy/flag.h"30#include "economy/flag.h"
@@ -33,6 +35,7 @@
33#include "logic/editor_game_base.h"35#include "logic/editor_game_base.h"
34#include "logic/findbob.h"36#include "logic/findbob.h"
35#include "logic/game.h"37#include "logic/game.h"
38#include "logic/garrisonhandler.h"
36#include "logic/message_queue.h"39#include "logic/message_queue.h"
37#include "logic/player.h"40#include "logic/player.h"
38#include "logic/soldier.h"41#include "logic/soldier.h"
@@ -55,13 +58,13 @@
55m_num_soldiers (0),58m_num_soldiers (0),
56m_heal_per_second (0)59m_heal_per_second (0)
57{60{
58 m_conquer_radius = global_s.get_safe_int("conquers");61 Section& garrison_s = prof.get_safe_section("garrison");
59 m_num_soldiers = global_s.get_safe_int("max_soldiers");62 m_conquer_radius = garrison_s.get_safe_int("conquers");
60 m_heal_per_second = global_s.get_safe_int("heal_per_second");63 m_num_soldiers = garrison_s.get_safe_int("max_soldiers");
64 m_heal_per_second = garrison_s.get_safe_int("heal_per_second");
61 if (m_conquer_radius > 0)65 if (m_conquer_radius > 0)
62 m_workarea_info[m_conquer_radius].insert(descname() + _(" conquer"));66 m_workarea_info[m_conquer_radius].insert(descname() + _(" conquer"));
63 m_prefers_heroes_at_start = global_s.get_safe_bool("prefer_heroes");67 m_prefers_heroes_at_start = garrison_s.get_safe_bool("prefer_heroes");
64
65}68}
6669
67/**70/**
@@ -83,96 +86,45 @@
83*/86*/
8487
85MilitarySite::MilitarySite(const MilitarySite_Descr & ms_descr) :88MilitarySite::MilitarySite(const MilitarySite_Descr & ms_descr) :
86ProductionSite(ms_descr),89ProductionSite(ms_descr)
87m_didconquer (false),
88m_capacity (ms_descr.get_max_number_of_soldiers()),
89m_nexthealtime(0),
90m_soldier_preference(ms_descr.m_prefers_heroes_at_start ? kPrefersHeroes : kPrefersRookies),
91m_soldier_upgrade_try(false)
92{90{
93 m_next_swap_soldiers_time = 0;91 GarrisonHandler* gh = new GarrisonHandler
92 (*this, 1,
93 descr().get_max_number_of_soldiers(),
94 descr().get_conquers(), descr().get_heal_per_second(),
95 descr().m_prefers_heroes_at_start ? GarrisonHandler::SoldierPref::Heroes
96 : GarrisonHandler::SoldierPref::Rookies);
97 m_garrison.reset(gh);
94}98}
9599
96
97MilitarySite::~MilitarySite()100MilitarySite::~MilitarySite()
98{101{
99 assert(!m_normal_soldier_request);
100 assert(!m_upgrade_soldier_request);
101}102}
102103
103104void MilitarySite::load_finish(Editor_Game_Base& egbase)
104/**
105===============
106Display number of soldiers.
107===============
108*/
109std::string MilitarySite::get_statistics_string()
110{105{
111 char buffer[255];106 Widelands::Building::load_finish(egbase);
112 std::string str;107 m_garrison->load_finish(egbase);
113 uint32_t present = presentSoldiers().size();
114 uint32_t total = stationedSoldiers().size();
115
116 if (present == total) {
117 snprintf
118 (buffer, sizeof(buffer),
119 ngettext("%u soldier", "%u soldiers", total),
120 total);
121 } else {
122 snprintf
123 (buffer, sizeof(buffer),
124 ngettext("%u(+%u) soldier", "%u(+%u) soldiers", total),
125 present, total - present);
126 }
127 str = buffer;
128
129 if (m_capacity > total) {
130 snprintf(buffer, sizeof(buffer), " (+%u)", m_capacity - total);
131 str += buffer;
132 }
133
134 return str;
135}108}
136109
137
138void MilitarySite::init(Editor_Game_Base & egbase)110void MilitarySite::init(Editor_Game_Base & egbase)
139{111{
140 ProductionSite::init(egbase);112 ProductionSite::init(egbase);
141113 m_garrison->init(egbase);
142 upcast(Game, game, &egbase);114 upcast(Game, game, &egbase);
143115
144 const std::vector<Worker*>& ws = get_workers();116 const std::vector<Worker*>& ws = get_workers();
145 container_iterate_const(std::vector<Worker *>, ws, i)117 container_iterate_const(std::vector<Worker *>, ws, i) {
146 if (upcast(Soldier, soldier, *i.current)) {118 if (upcast(Soldier, soldier, *i.current)) {
147 soldier->set_location_initially(*this);119 soldier->set_location_initially(*this);
148 assert(!soldier->get_state()); // Should be newly created.120 m_garrison->incorporateSoldier(egbase, *soldier);
149 if (game)
150 soldier->start_task_buildingwork(*game);
151 }121 }
152 update_soldier_request();122 }
153123 if (game) {
154 // schedule the first healing
155 m_nexthealtime = egbase.get_gametime() + 1000;
156 if (game)
157 schedule_act(*game, 1000);124 schedule_act(*game, 1000);
158}125 }
159126}
160127
161/**
162===============
163Change the economy for the wares queues.
164Note that the workers are dealt with in the PlayerImmovable code.
165===============
166*/
167void MilitarySite::set_economy(Economy * const e)
168{
169 ProductionSite::set_economy(e);
170
171 if (m_normal_soldier_request && e)
172 m_normal_soldier_request->set_economy(e);
173 if (m_upgrade_soldier_request && e)
174 m_upgrade_soldier_request->set_economy(e);
175}
176128
177/**129/**
178===============130===============
@@ -181,16 +133,12 @@
181*/133*/
182void MilitarySite::cleanup(Editor_Game_Base & egbase)134void MilitarySite::cleanup(Editor_Game_Base & egbase)
183{135{
184 // unconquer land136 // Order matters. Building needed to unconquer, building
185 if (m_didconquer)137 // cleanup will trigger new requests in garrison, garrison
186 egbase.unconquer_area138 // cleanup will destroy them
187 (Player_Area<Area<FCoords> >139 m_garrison->cleanup(egbase);
188 (owner().player_number(),
189 Area<FCoords>
190 (egbase.map().get_fcoords(get_position()), get_conquers())),
191 m_defeating_player);
192
193 ProductionSite::cleanup(egbase);140 ProductionSite::cleanup(egbase);
141<<<<<<< TREE
194142
195 // Note that removing workers during ProductionSite::cleanup can generate143 // Note that removing workers during ProductionSite::cleanup can generate
196 // new requests; that's why we delete it at the end of this function.144 // new requests; that's why we delete it at the end of this function.
@@ -538,6 +486,9 @@
538 // reason, hoping that all stationed soldiers would be present.486 // reason, hoping that all stationed soldiers would be present.
539 }487 }
540 }488 }
489=======
490 m_garrison->cleanup_requests(egbase);
491>>>>>>> MERGE-SOURCE
541}492}
542493
543/*494/*
@@ -554,60 +505,53 @@
554 // Maybe a new queueing system like MilitaryAct could be introduced.505 // Maybe a new queueing system like MilitaryAct could be introduced.
555506
556 ProductionSite::act(game, data);507 ProductionSite::act(game, data);
557508 m_garrison->act(game);
558 const int32_t timeofgame = game.get_gametime();509 schedule_act(game, 1000);
559 if (m_normal_soldier_request && m_upgrade_soldier_request)510}
560 {511
561 throw wexception("MilitarySite::act: Two soldier requests are ongoing -- should never happen!\n");512/**
562 }513===============
563514Display number of soldiers.
564 // I do not get a callback when stationed, non-present soldier returns --515===============
565 // Therefore I must poll in some occasions. Let's do that rather infrequently,516*/
566 // to keep the game lightweight.517std::string MilitarySite::get_statistics_string()
567518{
568 //TODO: I would need two new callbacks, to get rid ot this polling.519 std::string str;
569 if (timeofgame > m_next_swap_soldiers_time)520 uint32_t present = m_garrison->presentSoldiers().size();
570 {521 uint32_t total = m_garrison->stationedSoldiers().size();
571 m_next_swap_soldiers_time = timeofgame + (m_soldier_upgrade_try ? 20000 : 100000);522 uint32_t capacity = m_garrison->soldierCapacity();
572 update_soldier_request();523
573 }524 if (present == total) {
574525 str =
575 if (m_nexthealtime <= game.get_gametime()) {526 (boost::format
576 uint32_t total_heal = descr().get_heal_per_second();527 (ngettext(_("%u soldier"), _("%u soldiers"), total)) % total)
577 std::vector<Soldier *> soldiers = presentSoldiers();528 .str();
578529 } else {
579 for (uint32_t i = 0; i < soldiers.size(); ++i) {530 str =
580 Soldier & s = *soldiers[i];531 (boost::format
581532 (ngettext(_("%u(+%u) soldier"), _("%u(+%u) soldiers"), present))
582 // The healing algorithm is totally arbitrary533 % present % (total - present))
583 if (s.get_current_hitpoints() < s.get_max_hitpoints()) {534 .str();
584 s.heal(total_heal);535 }
585 break;536
586 }537 if (capacity > total) {
587 }538 str += (boost::format(" (+%u)") % (capacity - total)).str();
588539 }
589 m_nexthealtime = game.get_gametime() + 1000;540
590 schedule_act(game, 1000);541 return str;
591 }542}
592}543
593544/**
594545===============
595/**546Change the economy for the wares queues.
596 * The worker is about to be removed.547Note that the workers are dealt with in the PlayerImmovable code.
597 *548===============
598 * After the removal of the worker, check whether we need to request549*/
599 * new soldiers.550void MilitarySite::set_economy(Economy * const e)
600 */551{
601void MilitarySite::remove_worker(Worker & w)552 ProductionSite::set_economy(e);
602{553 m_garrison->set_economy(e);
603 ProductionSite::remove_worker(w);554}
604
605 if (upcast(Soldier, soldier, &w))
606 popSoldierJob(soldier, 0, 0);
607
608 update_soldier_request();
609}
610
611555
612/**556/**
613 * Called by soldiers in the building.557 * Called by soldiers in the building.
@@ -615,41 +559,13 @@
615bool MilitarySite::get_building_work(Game & game, Worker & worker, bool)559bool MilitarySite::get_building_work(Game & game, Worker & worker, bool)
616{560{
617 if (upcast(Soldier, soldier, &worker)) {561 if (upcast(Soldier, soldier, &worker)) {
618 // Evict soldiers that have returned home if the capacity is too low562 return m_garrison->get_garrison_work(game, soldier);
619 if (m_capacity < presentSoldiers().size()) {
620 worker.reset_tasks(game);
621 worker.start_task_leavebuilding(game, true);
622 return true;
623 }
624
625 bool stayhome;
626 uint8_t retreat;
627 if
628 (Map_Object * const enemy
629 =
630 popSoldierJob(soldier, &stayhome, &retreat))
631 {
632 if (upcast(Building, building, enemy)) {
633 soldier->start_task_attack
634 (game, *building, retreat);
635 return true;
636 } else if (upcast(Soldier, opponent, enemy)) {
637 if (!opponent->getBattle()) {
638 soldier->start_task_defense
639 (game, stayhome, retreat);
640 if (stayhome)
641 opponent->send_signal(game, "sleep");
642 return true;
643 }
644 } else
645 throw wexception("MilitarySite::get_building_work: bad SoldierJob");
646 }
647 }563 }
648
649 return false;564 return false;
650}565}
651566
652567
568<<<<<<< TREE
653/**569/**
654 * \return \c true if the soldier is currently present and idle in the building.570 * \return \c true if the soldier is currently present and idle in the building.
655 */571 */
@@ -885,7 +801,28 @@
885801
886 // Now we destroy the old building before we place the new one.802 // Now we destroy the old building before we place the new one.
887 set_defeating_player(enemy.owner().player_number());803 set_defeating_player(enemy.owner().player_number());
804=======
805Garrison* MilitarySite::get_garrison() const
806{
807 return m_garrison.get();
808}
809
810Building* MilitarySite::get_building()
811{
812 return this;
813}
814
815void MilitarySite::garrison_occupied()
816{
817 start_animation(owner().egbase(), descr().get_animation("idle"));
818}
819
820void MilitarySite::garrison_lost(Game& game, Widelands::Player_Number defeating, bool captured)
821{
822 if (!captured) {
823>>>>>>> MERGE-SOURCE
888 schedule_destroy(game);824 schedule_destroy(game);
825<<<<<<< TREE
889826
890 enemyplayer->force_building(coords, former_buildings);827 enemyplayer->force_building(coords, former_buildings);
891 BaseImmovable * const newimm = game.map()[coords].get_immovable();828 BaseImmovable * const newimm = game.map()[coords].get_immovable();
@@ -907,17 +844,64 @@
907844
908 return false;845 return false;
909 }846 }
847=======
848 return;
849 }
850 // The enemy conquers the building
851 // In fact we do not conquer it, but place a new building of same type at
852 // the old location.
853 Player * enemyplayer = game.get_player(defeating);
854 const Tribe_Descr & enemytribe = enemyplayer->tribe();
855
856 // Add suffix to all descr in former buildings in cases
857 // the new owner comes from another tribe
858 Building_Descr::FormerBuildings former_buildings;
859 BOOST_FOREACH(const Building_Descr * old_descr, m_old_buildings) {
860 std::string bldname = old_descr->name();
861 // Has this building already a suffix? == conquered building?
862 std::string::size_type const dot = bldname.rfind('.');
863 if (dot >= bldname.size()) {
864 // Add suffix, if the new owner uses another tribe than we.
865 if (enemytribe.name() != owner().tribe().name())
866 bldname += "." + owner().tribe().name();
867 } else if (enemytribe.name() == bldname.substr(dot + 1, bldname.size()))
868 bldname = bldname.substr(0, dot);
869 Building_Index bldi = enemytribe.safe_building_index(bldname.c_str());
870 const Building_Descr * former_descr = enemytribe.get_building_descr(bldi);
871 former_buildings.push_back(former_descr);
872 }
873
874 const Coords coords = get_position();
875 // Now we destroy the old building before we place the new one.
876 set_defeating_player(defeating);
877 schedule_destroy(game);
878
879 enemyplayer->force_building(coords, former_buildings);
880 BaseImmovable * const newimm = game.map()[coords].get_immovable();
881 upcast(GarrisonOwner, go, newimm);
882 go->reinit_after_conqueral(game);
883
884 // Of course we should inform the victorious player as well
885 upcast(Building, new_building, newimm);
886 std::string message =
887 (boost::format
888 (_("Your soldiers defeated the enemy at the %s."))
889 % new_building->descname())
890 .str();
891 new_building->send_message
892 (game, "site_defeated",
893 _("Enemy at site defeated!"),
894 message);
895>>>>>>> MERGE-SOURCE
910}896}
911897
912/// Initialises the militarysite after it was "conquered" (the old was replaced)898void MilitarySite::reinit_after_conqueral(Game& game)
913void MilitarySite::reinit_after_conqueration(Game & game)
914{899{
915 clear_requirements();900 m_garrison->reinit_after_conqueral(game);
916 conquer_area(game);
917 update_soldier_request();
918 start_animation(game, descr().get_animation("idle"));901 start_animation(game, descr().get_animation("idle"));
919}902}
920903
904<<<<<<< TREE
921/// Calculates whether the military presence is still kept and \returns true if.905/// Calculates whether the military presence is still kept and \returns true if.
922bool MilitarySite::military_presence_kept(Game & game)906bool MilitarySite::military_presence_kept(Game & game)
923{907{
@@ -1103,4 +1087,6 @@
1103 m_next_swap_soldiers_time = 0;1087 m_next_swap_soldiers_time = 0;
1104}1088}
11051089
1090=======
1091>>>>>>> MERGE-SOURCE
1106}1092}
11071093
=== modified file 'src/logic/militarysite.h'
--- src/logic/militarysite.h 2013-07-26 20:19:36 +0000
+++ src/logic/militarysite.h 2013-08-10 10:53:03 +0000
@@ -20,10 +20,10 @@
20#ifndef MILITARYSITE_H20#ifndef MILITARYSITE_H
21#define MILITARYSITE_H21#define MILITARYSITE_H
2222
23#include "logic/attackable.h"23#include "logic/garrison.h"
24#include "logic/garrisonhandler.h"
24#include "logic/productionsite.h"25#include "logic/productionsite.h"
25#include "logic/requirements.h"26#include "logic/requirements.h"
26#include "logic/soldiercontrol.h"
2727
28namespace Widelands {28namespace Widelands {
2929
@@ -53,121 +53,39 @@
53};53};
5454
55class MilitarySite :55class MilitarySite :
56 public ProductionSite, public SoldierControl, public Attackable56 public ProductionSite, public GarrisonOwner
57{57{
58 friend struct Map_Buildingdata_Data_Packet;58 friend struct Map_Buildingdata_Data_Packet;
59 MO_DESCR(MilitarySite_Descr);59 MO_DESCR(MilitarySite_Descr);
6060
61public:61public:
62 // I assume elsewhere, that enum SoldierPreference fits to uint8_t.
63 enum SoldierPreference : uint8_t {
64 kNoPreference,
65 kPrefersRookies,
66 kPrefersHeroes,
67 };
68
69 MilitarySite(const MilitarySite_Descr &);62 MilitarySite(const MilitarySite_Descr &);
70 virtual ~MilitarySite();63 virtual ~MilitarySite();
7164
72 char const * type_name() const throw () {return "militarysite";}65 void load_finish(Editor_Game_Base &);
73 virtual std::string get_statistics_string();
74
75 virtual void init(Editor_Game_Base &);66 virtual void init(Editor_Game_Base &);
76 virtual void cleanup(Editor_Game_Base &);67 virtual void cleanup(Editor_Game_Base &);
77 virtual void act(Game &, uint32_t data);68 virtual void act(Game &, uint32_t data);
78 virtual void remove_worker(Worker &);69
70 char const * type_name() const throw () {return "militarysite";}
71 virtual std::string get_statistics_string();
7972
80 virtual void set_economy(Economy *);73 virtual void set_economy(Economy *);
81 virtual bool get_building_work(Game &, Worker &, bool success);74 virtual bool get_building_work(Game &, Worker &, bool success);
8275
83 // Begin implementation of SoldierControl76 // GarrisonOwner implementation
84 virtual std::vector<Soldier *> presentSoldiers() const;77 virtual Garrison* get_garrison() const;
85 virtual std::vector<Soldier *> stationedSoldiers() const;78 virtual Building* get_building();
86 virtual uint32_t minSoldierCapacity() const throw ();79 virtual void garrison_occupied();
87 virtual uint32_t maxSoldierCapacity() const throw ();80 virtual void garrison_lost(Game & game, Player_Number defeating, bool captured);
88 virtual uint32_t soldierCapacity() const;81 virtual void reinit_after_conqueral(Game& game);
89 virtual void setSoldierCapacity(uint32_t capacity);
90 virtual void dropSoldier(Soldier &);
91 virtual int incorporateSoldier(Editor_Game_Base & game, Soldier & s);
92 // End implementation of SoldierControl
93
94 // Begin implementation of Attackable
95 virtual Player & owner() const {return Building::owner();}
96 virtual bool canAttack();
97 virtual void aggressor(Soldier &);
98 virtual bool attack (Soldier &);
99 // End implementation of Attackable
100
101 /**
102 * Launch the given soldier on an attack towards the given
103 * target building.
104 */
105 void sendAttacker(Soldier &, Building &, uint8_t);
106
107 /// This methods are helper for use at configure this site.
108 void set_requirements (const Requirements &);
109 void clear_requirements();
110 const Requirements & get_requirements () const {
111 return m_soldier_requirements;
112 }
113
114 void reinit_after_conqueration(Game &);
115
116 void update_soldier_request(bool i = false);
117
118 void set_soldier_preference(SoldierPreference);
119 SoldierPreference get_soldier_preference() const {
120 return m_soldier_preference;
121 }
12282
123protected:83protected:
124 void conquer_area(Editor_Game_Base &);
125
126 virtual void create_options_window84 virtual void create_options_window
127 (Interactive_GameBase &, UI::Window * & registry);85 (Interactive_GameBase &, UI::Window * & registry);
12886
129private:87private:
130 bool isPresent(Soldier &) const;88 std::unique_ptr<GarrisonHandler> m_garrison;
131 static void request_soldier_callback
132 (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
133
134 Map_Object * popSoldierJob
135 (Soldier *, bool * stayhome = 0, uint8_t * retreat = 0);
136 bool haveSoldierJob(Soldier &);
137 bool military_presence_kept(Game &);
138 void informPlayer(Game &, bool discovered = false);
139 bool update_upgrade_requirements();
140 void update_normal_soldier_request();
141 void update_upgrade_soldier_request();
142 bool incorporateUpgradedSoldier(Editor_Game_Base & game, Soldier & s);
143 Soldier * find_least_suited_soldier();
144 bool drop_least_suited_soldier(bool new_has_arrived, Soldier * s);
145
146
147private:
148 Requirements m_soldier_requirements; // This is used to grab a bunch of soldiers: Anything goes
149 RequireAttribute m_soldier_upgrade_requirements; // This is used when exchanging soldiers.
150 std::unique_ptr<Request> m_normal_soldier_request; // filling the site
151 std::unique_ptr<Request> m_upgrade_soldier_request; // seeking for better soldiers
152 bool m_didconquer;
153 uint32_t m_capacity;
154
155 /**
156 * Next gametime where we should heal something.
157 */
158 int32_t m_nexthealtime;
159
160 struct SoldierJob {
161 Soldier * soldier;
162 Object_Ptr enemy;
163 bool stayhome;
164 uint8_t retreat;
165 };
166 std::vector<SoldierJob> m_soldierjobs;
167 SoldierPreference m_soldier_preference;
168 int32_t m_next_swap_soldiers_time;
169 bool m_soldier_upgrade_try; // optimization -- if everybody is zero-level, do not downgrade
170 bool m_doing_upgrade_request;
171};89};
17290
173}91}
17492
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2013-08-08 20:02:13 +0000
+++ src/logic/player.cc 2013-08-10 10:53:03 +0000
@@ -38,7 +38,6 @@
38#include "logic/militarysite.h"38#include "logic/militarysite.h"
39#include "logic/playercommand.h"39#include "logic/playercommand.h"
40#include "logic/soldier.h"40#include "logic/soldier.h"
41#include "logic/soldiercontrol.h"
42#include "logic/trainingsite.h"41#include "logic/trainingsite.h"
43#include "logic/tribe.h"42#include "logic/tribe.h"
44#include "logic/warehouse.h"43#include "logic/warehouse.h"
@@ -699,12 +698,14 @@
699698
700void Player::military_site_set_soldier_preference(PlayerImmovable & imm, uint8_t m_soldier_preference)699void Player::military_site_set_soldier_preference(PlayerImmovable & imm, uint8_t m_soldier_preference)
701{700{
702 if (&imm.owner() == this)701 if (&imm.owner() == this) {
703 if (upcast(MilitarySite, milsite, &imm))702 if (upcast(GarrisonOwner, go, &imm)) {
704 milsite->set_soldier_preference(static_cast<MilitarySite::SoldierPreference>(m_soldier_preference));703 Garrison* const garrison = go->get_garrison();
704 garrison->set_soldier_preference(static_cast<Garrison::SoldierPref>(m_soldier_preference));
705 }
706 }
705}707}
706708
707
708/*709/*
709 * enhance this building, remove it, but give the constructionsite710 * enhance this building, remove it, but give the constructionsite
710 * an idea of enhancing711 * an idea of enhancing
@@ -867,8 +868,9 @@
867 return;868 return;
868 if (soldier.get_worker_type() != Worker_Descr::SOLDIER)869 if (soldier.get_worker_type() != Worker_Descr::SOLDIER)
869 return;870 return;
870 if (upcast(SoldierControl, ctrl, &imm))871 if (upcast(GarrisonOwner, go, &imm)) {
871 ctrl->dropSoldier(soldier);872 go->get_garrison()->dropSoldier(soldier);
873 }
872}874}
873875
874/*876/*
@@ -926,9 +928,10 @@
926928
927 container_iterate_const(std::vector<BaseImmovable *>, flags, i) {929 container_iterate_const(std::vector<BaseImmovable *>, flags, i) {
928 const Flag * attackerflag = static_cast<Flag *>(*i.current);930 const Flag * attackerflag = static_cast<Flag *>(*i.current);
929 const MilitarySite * ms = static_cast<MilitarySite *>(attackerflag->get_building());931 GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(attackerflag->get_building());
930 std::vector<Soldier *> const present = ms->presentSoldiers();932 Garrison * garrison = go->get_garrison();
931 uint32_t const nr_staying = ms->minSoldierCapacity();933 std::vector<Soldier *> const present = garrison->presentSoldiers();
934 uint32_t const nr_staying = garrison->minSoldierCapacity();
932 uint32_t const nr_present = present.size();935 uint32_t const nr_present = present.size();
933 if (nr_staying < nr_present) {936 if (nr_staying < nr_present) {
934 uint32_t const nr_taken =937 uint32_t const nr_taken =
@@ -964,8 +967,8 @@
964 log("enemyflagaction: count is 0\n");967 log("enemyflagaction: count is 0\n");
965 else if (is_hostile(flag.owner()))968 else if (is_hostile(flag.owner()))
966 if (Building * const building = flag.get_building())969 if (Building * const building = flag.get_building())
967 if (upcast(Attackable, attackable, building))970 if (upcast(GarrisonOwner, go, building))
968 if (attackable->canAttack()) {971 if (go->get_garrison()->canAttack()) {
969 std::vector<Soldier *> attackers;972 std::vector<Soldier *> attackers;
970 findAttackSoldiers(flag, &attackers, count);973 findAttackSoldiers(flag, &attackers, count);
971 assert(attackers.size() <= count);974 assert(attackers.size() <= count);
@@ -975,10 +978,10 @@
975 retreat = std::min978 retreat = std::min
976 (retreat, tribe().get_military_data().get_max_retreat());979 (retreat, tribe().get_military_data().get_max_retreat());
977980
978 container_iterate_const(std::vector<Soldier *>, attackers, i)981 container_iterate_const(std::vector<Soldier *>, attackers, i) {
979 ref_cast<MilitarySite, PlayerImmovable>982 upcast(GarrisonOwner, igo, (*i.current)->get_location(egbase()));
980 (*(*i.current)->get_location(egbase()))983 igo->get_garrison()->sendAttacker(**i.current, *building, retreat);
981 .sendAttacker(**i.current, *building, retreat);984 }
982 }985 }
983}986}
984987
@@ -1177,13 +1180,13 @@
11771180
1178 const uint32_t nrecos = get_nr_economies();1181 const uint32_t nrecos = get_nr_economies();
1179 for (uint32_t i = 0; i < nrecos; ++i) {1182 for (uint32_t i = 0; i < nrecos; ++i) {
1180 const std::vector<Widelands::Warehouse *> & warehouses =1183 const std::vector<Widelands::Storage *> & storages =
1181 get_economy_by_number(i)->warehouses();1184 get_economy_by_number(i)->storages();
11821185
1183 for1186 for
1184 (std::vector<Widelands::Warehouse *>::const_iterator it =1187 (std::vector<Widelands::Storage *>::const_iterator it =
1185 warehouses.begin();1188 storages.begin();
1186 it != warehouses.end();1189 it != storages.end();
1187 ++it)1190 ++it)
1188 {1191 {
1189 const Widelands::WareList & wares = (*it)->get_wares();1192 const Widelands::WareList & wares = (*it)->get_wares();
11901193
=== modified file 'src/logic/player.h'
--- src/logic/player.h 2013-08-01 10:51:41 +0000
+++ src/logic/player.h 2013-08-10 10:53:03 +0000
@@ -638,7 +638,7 @@
638 std::vector< std::vector<uint32_t> > m_ware_consumptions;638 std::vector< std::vector<uint32_t> > m_ware_consumptions;
639639
640 /**640 /**
641 * Statistics of wares stored inside of warehouses over the641 * Statistics of wares stored inside of storages over the
642 * life of the game, indexed as642 * life of the game, indexed as
643 * m_ware_stocks[ware_id][time_index]643 * m_ware_stocks[ware_id][time_index]
644 */644 */
645645
=== modified file 'src/logic/playercommand.cc'
--- src/logic/playercommand.cc 2013-08-07 12:32:36 +0000
+++ src/logic/playercommand.cc 2013-08-10 10:53:03 +0000
@@ -525,7 +525,7 @@
525PlayerCommand (0, des.Unsigned8())525PlayerCommand (0, des.Unsigned8())
526{526{
527 serial = des.Unsigned32();527 serial = des.Unsigned32();
528 preference = des.Unsigned8();528 preference = static_cast<Garrison::SoldierPref>(des.Unsigned8());
529}529}
530530
531void Cmd_MilitarySiteSetSoldierPreference::serialize (StreamWrite & ser)531void Cmd_MilitarySiteSetSoldierPreference::serialize (StreamWrite & ser)
@@ -533,7 +533,7 @@
533 ser.Unsigned8 (PLCMD_MILITARYSITESETSOLDIERPREFERENCE);533 ser.Unsigned8 (PLCMD_MILITARYSITESETSOLDIERPREFERENCE);
534 ser.Unsigned8 (sender());534 ser.Unsigned8 (sender());
535 ser.Unsigned32(serial);535 ser.Unsigned32(serial);
536 ser.Unsigned8 (preference);536 ser.Unsigned8 (static_cast<uint8_t>(preference));
537}537}
538538
539void Cmd_MilitarySiteSetSoldierPreference::execute (Game & game)539void Cmd_MilitarySiteSetSoldierPreference::execute (Game & game)
@@ -554,7 +554,7 @@
554554
555 // Now serial555 // Now serial
556 const Map_Object & obj = *egbase.objects().get_object(serial);556 const Map_Object & obj = *egbase.objects().get_object(serial);
557 fw.Unsigned8(preference);557 fw.Unsigned8(static_cast<uint8_t>(preference));
558 fw.Unsigned32(mos.get_object_file_index(obj));558 fw.Unsigned32(mos.get_object_file_index(obj));
559}559}
560560
@@ -566,7 +566,7 @@
566 const uint16_t packet_version = fr.Unsigned16();566 const uint16_t packet_version = fr.Unsigned16();
567 if (packet_version == PLAYER_CMD_SOLDIERPREFERENCE_VERSION) {567 if (packet_version == PLAYER_CMD_SOLDIERPREFERENCE_VERSION) {
568 PlayerCommand::Read(fr, egbase, mol);568 PlayerCommand::Read(fr, egbase, mol);
569 preference = fr.Unsigned8();569 preference = static_cast<Garrison::SoldierPref>(fr.Unsigned8());
570 const uint32_t building_serial = fr.Unsigned32();570 const uint32_t building_serial = fr.Unsigned32();
571 try {571 try {
572 serial = mol.get<Map_Object>(building_serial).serial();572 serial = mol.get<Map_Object>(building_serial).serial();
@@ -1724,8 +1724,8 @@
1724{1724{
1725 if (upcast(Building, building, game.objects().get_object(serial)))1725 if (upcast(Building, building, game.objects().get_object(serial)))
1726 if (&building->owner() == game.get_player(sender()))1726 if (&building->owner() == game.get_player(sender()))
1727 if (upcast(SoldierControl, ctrl, building))1727 if (upcast(GarrisonOwner, go, building))
1728 ctrl->changeSoldierCapacity(val);1728 go->get_garrison()->changeSoldierCapacity(val);
1729}1729}
17301730
1731void Cmd_ChangeSoldierCapacity::serialize (StreamWrite & ser)1731void Cmd_ChangeSoldierCapacity::serialize (StreamWrite & ser)
@@ -2023,18 +2023,18 @@
2023/*** struct Cmd_SetStockPolicy ***/2023/*** struct Cmd_SetStockPolicy ***/
2024Cmd_SetStockPolicy::Cmd_SetStockPolicy2024Cmd_SetStockPolicy::Cmd_SetStockPolicy
2025 (int32_t time, Player_Number p,2025 (int32_t time, Player_Number p,
2026 Warehouse & wh, bool isworker, Ware_Index ware,2026 StorageOwner & storage_owner, bool isworker, Ware_Index ware,
2027 Warehouse::StockPolicy policy)2027 Storage::StockPolicy policy)
2028: PlayerCommand(time, p)2028: PlayerCommand(time, p)
2029{2029{
2030 m_warehouse = wh.serial();2030 m_storage_owner = storage_owner.get_building()->serial();
2031 m_isworker = isworker;2031 m_isworker = isworker;
2032 m_ware = ware;2032 m_ware = ware;
2033 m_policy = policy;2033 m_policy = policy;
2034}2034}
20352035
2036Cmd_SetStockPolicy::Cmd_SetStockPolicy()2036Cmd_SetStockPolicy::Cmd_SetStockPolicy()
2037: PlayerCommand(), m_warehouse(0), m_isworker(false), m_policy()2037: PlayerCommand(), m_storage_owner(0), m_isworker(false), m_policy()
2038{2038{
2039}2039}
20402040
@@ -2047,20 +2047,20 @@
2047{2047{
2048 // Sanitize data that could have come from the network2048 // Sanitize data that could have come from the network
2049 if (Player * plr = game.get_player(sender())) {2049 if (Player * plr = game.get_player(sender())) {
2050 if (upcast(Warehouse, warehouse, game.objects().get_object(m_warehouse)))2050 if (upcast(StorageOwner, storage_owner, game.objects().get_object(m_storage_owner)))
2051 {2051 {
2052 if (&warehouse->owner() != plr) {2052 if (&storage_owner->get_building()->owner() != plr) {
2053 log2053 log
2054 ("Cmd_SetStockPolicy: sender %u, but warehouse owner %u\n",2054 ("Cmd_SetStockPolicy: sender %u, but storage owner %u\n",
2055 sender(), warehouse->owner().player_number());2055 sender(), storage_owner->get_building()->owner().player_number());
2056 return;2056 return;
2057 }2057 }
20582058
2059 switch (m_policy) {2059 switch (m_policy) {
2060 case Warehouse::SP_Normal:2060 case Storage::StockPolicy::Normal:
2061 case Warehouse::SP_Prefer:2061 case Storage::StockPolicy::Prefer:
2062 case Warehouse::SP_DontStock:2062 case Storage::StockPolicy::DontStock:
2063 case Warehouse::SP_Remove:2063 case Storage::StockPolicy::Remove:
2064 break;2064 break;
2065 default:2065 default:
2066 log2066 log
@@ -2069,7 +2069,7 @@
2069 return;2069 return;
2070 }2070 }
20712071
2072 const Tribe_Descr & tribe = warehouse->tribe();2072 const Tribe_Descr & tribe = storage_owner->get_building()->tribe();
2073 if (m_isworker) {2073 if (m_isworker) {
2074 if (!(m_ware < tribe.get_nrworkers())) {2074 if (!(m_ware < tribe.get_nrworkers())) {
2075 log2075 log
@@ -2077,7 +2077,7 @@
2077 sender(), m_ware.value());2077 sender(), m_ware.value());
2078 return;2078 return;
2079 }2079 }
2080 warehouse->set_worker_policy(m_ware, m_policy);2080 storage_owner->get_storage()->set_worker_policy(m_ware, m_policy);
2081 } else {2081 } else {
2082 if (!(m_ware < tribe.get_nrwares())) {2082 if (!(m_ware < tribe.get_nrwares())) {
2083 log2083 log
@@ -2085,7 +2085,7 @@
2085 sender(), m_ware.value());2085 sender(), m_ware.value());
2086 return;2086 return;
2087 }2087 }
2088 warehouse->set_ware_policy(m_ware, m_policy);2088 storage_owner->get_storage()->set_ware_policy(m_ware, m_policy);
2089 }2089 }
2090 }2090 }
2091 }2091 }
@@ -2094,20 +2094,20 @@
2094Cmd_SetStockPolicy::Cmd_SetStockPolicy(StreamRead & des)2094Cmd_SetStockPolicy::Cmd_SetStockPolicy(StreamRead & des)
2095 : PlayerCommand(0, des.Unsigned8())2095 : PlayerCommand(0, des.Unsigned8())
2096{2096{
2097 m_warehouse = des.Unsigned32();2097 m_storage_owner = des.Unsigned32();
2098 m_isworker = des.Unsigned8();2098 m_isworker = des.Unsigned8();
2099 m_ware = Ware_Index(des.Unsigned8());2099 m_ware = Ware_Index(des.Unsigned8());
2100 m_policy = static_cast<Warehouse::StockPolicy>(des.Unsigned8());2100 m_policy = static_cast<Storage::StockPolicy>(des.Unsigned8());
2101}2101}
21022102
2103void Cmd_SetStockPolicy::serialize(StreamWrite & ser)2103void Cmd_SetStockPolicy::serialize(StreamWrite & ser)
2104{2104{
2105 ser.Unsigned8(PLCMD_SETSTOCKPOLICY);2105 ser.Unsigned8(PLCMD_SETSTOCKPOLICY);
2106 ser.Unsigned8(sender());2106 ser.Unsigned8(sender());
2107 ser.Unsigned32(m_warehouse);2107 ser.Unsigned32(m_storage_owner);
2108 ser.Unsigned8(m_isworker);2108 ser.Unsigned8(m_isworker);
2109 ser.Unsigned8(m_ware.value());2109 ser.Unsigned8(m_ware.value());
2110 ser.Unsigned8(m_policy);2110 ser.Unsigned8(static_cast<uint8_t>(m_policy));
2111}2111}
21122112
2113#define PLAYER_CMD_SETSTOCKPOLICY_VERSION 12113#define PLAYER_CMD_SETSTOCKPOLICY_VERSION 1
@@ -2119,10 +2119,10 @@
2119 if (version != PLAYER_CMD_SETSTOCKPOLICY_VERSION)2119 if (version != PLAYER_CMD_SETSTOCKPOLICY_VERSION)
2120 throw game_data_error("unknown/unhandled version %u", version);2120 throw game_data_error("unknown/unhandled version %u", version);
2121 PlayerCommand::Read(fr, egbase, mol);2121 PlayerCommand::Read(fr, egbase, mol);
2122 m_warehouse = fr.Unsigned32();2122 m_storage_owner = fr.Unsigned32();
2123 m_isworker = fr.Unsigned8();2123 m_isworker = fr.Unsigned8();
2124 m_ware = Ware_Index(fr.Unsigned8());2124 m_ware = Ware_Index(fr.Unsigned8());
2125 m_policy = static_cast<Warehouse::StockPolicy>(fr.Unsigned8());2125 m_policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
2126 } catch (const std::exception & e) {2126 } catch (const std::exception & e) {
2127 throw game_data_error("Cmd_SetStockPolicy: %s", e.what());2127 throw game_data_error("Cmd_SetStockPolicy: %s", e.what());
2128 }2128 }
@@ -2133,10 +2133,10 @@
2133{2133{
2134 fw.Unsigned8(PLAYER_CMD_SETSTOCKPOLICY_VERSION);2134 fw.Unsigned8(PLAYER_CMD_SETSTOCKPOLICY_VERSION);
2135 PlayerCommand::Write(fw, egbase, mos);2135 PlayerCommand::Write(fw, egbase, mos);
2136 fw.Unsigned32(m_warehouse);2136 fw.Unsigned32(m_storage_owner);
2137 fw.Unsigned8(m_isworker);2137 fw.Unsigned8(m_isworker);
2138 fw.Unsigned8(m_ware.value());2138 fw.Unsigned8(m_ware.value());
2139 fw.Unsigned8(m_policy);2139 fw.Unsigned8(static_cast<uint8_t>(m_policy));
2140}2140}
21412141
2142}2142}
21432143
=== modified file 'src/logic/playercommand.h'
--- src/logic/playercommand.h 2013-08-05 14:05:21 +0000
+++ src/logic/playercommand.h 2013-08-10 10:53:03 +0000
@@ -24,8 +24,8 @@
24#include "economy/flag.h"24#include "economy/flag.h"
25#include "logic/message_id.h"25#include "logic/message_id.h"
26#include "logic/path.h"26#include "logic/path.h"
27#include "logic/storage.h"
27#include "logic/trainingsite.h"28#include "logic/trainingsite.h"
28#include "logic/warehouse.h"
29#include "logic/worker.h"29#include "logic/worker.h"
3030
31namespace Widelands {31namespace Widelands {
@@ -196,7 +196,8 @@
196196
197struct Cmd_MilitarySiteSetSoldierPreference : public PlayerCommand {197struct Cmd_MilitarySiteSetSoldierPreference : public PlayerCommand {
198 Cmd_MilitarySiteSetSoldierPreference() : PlayerCommand(), serial(0) {} // For savegame loading198 Cmd_MilitarySiteSetSoldierPreference() : PlayerCommand(), serial(0) {} // For savegame loading
199 Cmd_MilitarySiteSetSoldierPreference (const int32_t t, const Player_Number p, Building & b, uint8_t prefs)199 Cmd_MilitarySiteSetSoldierPreference
200 (const int32_t t, const Player_Number p, Building & b, Garrison::SoldierPref prefs)
200 : PlayerCommand(t, p), serial(b.serial()), preference(prefs)201 : PlayerCommand(t, p), serial(b.serial()), preference(prefs)
201 {}202 {}
202203
@@ -212,7 +213,7 @@
212213
213private:214private:
214 Serial serial;215 Serial serial;
215 uint8_t preference;216 Garrison::SoldierPref preference;
216};217};
217struct Cmd_StartOrCancelExpedition : public PlayerCommand {218struct Cmd_StartOrCancelExpedition : public PlayerCommand {
218 Cmd_StartOrCancelExpedition() : PlayerCommand() {} // For savegame loading219 Cmd_StartOrCancelExpedition() : PlayerCommand() {} // For savegame loading
@@ -764,13 +765,13 @@
764};765};
765766
766/**767/**
767 * Command to change the stock policy for a ware or worker in a warehouse.768 * Command to change the stock policy for a ware or worker in a storage.
768 */769 */
769struct Cmd_SetStockPolicy : PlayerCommand {770struct Cmd_SetStockPolicy : PlayerCommand {
770 Cmd_SetStockPolicy771 Cmd_SetStockPolicy
771 (int32_t time, Player_Number p,772 (int32_t time, Player_Number p,
772 Warehouse & wh, bool isworker, Ware_Index ware,773 StorageOwner & storage_owner, bool isworker, Ware_Index ware,
773 Warehouse::StockPolicy policy);774 Storage::StockPolicy policy);
774775
775 virtual uint8_t id() const;776 virtual uint8_t id() const;
776777
@@ -786,10 +787,10 @@
786 void Read (FileRead &, Editor_Game_Base &, Map_Map_Object_Loader &);787 void Read (FileRead &, Editor_Game_Base &, Map_Map_Object_Loader &);
787788
788private:789private:
789 Serial m_warehouse;790 Serial m_storage_owner;
790 bool m_isworker;791 bool m_isworker;
791 Ware_Index m_ware;792 Ware_Index m_ware;
792 Warehouse::StockPolicy m_policy;793 Storage::StockPolicy m_policy;
793};794};
794795
795}796}
796797
=== modified file 'src/logic/production_program.cc'
--- src/logic/production_program.cc 2013-08-08 19:55:12 +0000
+++ src/logic/production_program.cc 2013-08-10 10:53:03 +0000
@@ -32,12 +32,12 @@
32#include "logic/findnode.h"32#include "logic/findnode.h"
33#include "logic/game.h"33#include "logic/game.h"
34#include "logic/game_data_error.h"34#include "logic/game_data_error.h"
35#include "logic/garrison.h"
35#include "logic/mapregion.h"36#include "logic/mapregion.h"
36#include "logic/message_queue.h"37#include "logic/message_queue.h"
37#include "logic/player.h"38#include "logic/player.h"
38#include "logic/productionsite.h"39#include "logic/productionsite.h"
39#include "logic/soldier.h"40#include "logic/soldier.h"
40#include "logic/soldiercontrol.h"
41#include "logic/trainingsite.h"41#include "logic/trainingsite.h"
42#include "logic/tribe.h"42#include "logic/tribe.h"
43#include "logic/worker_program.h"43#include "logic/worker_program.h"
@@ -1274,8 +1274,13 @@
1274void ProductionProgram::ActCheck_Soldier::execute1274void ProductionProgram::ActCheck_Soldier::execute
1275 (Game & game, ProductionSite & ps) const1275 (Game & game, ProductionSite & ps) const
1276{1276{
1277 SoldierControl & ctrl = dynamic_cast<SoldierControl &>(ps);1277 GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(&ps);
1278 const std::vector<Soldier *> soldiers = ctrl.presentSoldiers();1278 if (!go) {
1279 log("CGH no garrison owner for %s %u\n", ps.descr().descname().c_str(), ps.serial());
1280 return;
1281 }
1282 Garrison* ga = go->get_garrison();
1283 const std::vector<Soldier *> soldiers = ga->presentSoldiers();
1279 const std::vector<Soldier *>::const_iterator soldiers_end = soldiers.end();1284 const std::vector<Soldier *>::const_iterator soldiers_end = soldiers.end();
12801285
1281 ps.molog(" Checking soldier (%u) level %d)\n", attribute, level);1286 ps.molog(" Checking soldier (%u) level %d)\n", attribute, level);
@@ -1360,8 +1365,10 @@
1360void ProductionProgram::ActTrain::execute1365void ProductionProgram::ActTrain::execute
1361 (Game & game, ProductionSite & ps) const1366 (Game & game, ProductionSite & ps) const
1362{1367{
1363 SoldierControl & ctrl = dynamic_cast<SoldierControl &>(ps);1368 GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(&ps);
1364 const std::vector<Soldier *> soldiers = ctrl.presentSoldiers();1369 assert(go);
1370 const Garrison* ga = go->get_garrison();
1371 const std::vector<Soldier *> soldiers = ga->presentSoldiers();
1365 const std::vector<Soldier *>::const_iterator soldiers_end =1372 const std::vector<Soldier *>::const_iterator soldiers_end =
1366 soldiers.end();1373 soldiers.end();
1367 std::vector<Soldier *>::const_iterator it = soldiers.begin();1374 std::vector<Soldier *>::const_iterator it = soldiers.begin();
13681375
=== modified file 'src/logic/productionsite.cc'
--- src/logic/productionsite.cc 2013-07-26 20:19:36 +0000
+++ src/logic/productionsite.cc 2013-08-10 10:53:03 +0000
@@ -113,7 +113,7 @@
113 } catch (const _wexception & e) {113 } catch (const _wexception & e) {
114 throw wexception("%s=\"%s\": %s", v->get_name(), v->get_string(), e.what());114 throw wexception("%s=\"%s\": %s", v->get_name(), v->get_string(), e.what());
115 }115 }
116 if (working_positions().empty() and not global_s.has_val("max_soldiers"))116 if (working_positions().empty() and prof.get_section("garrison") == nullptr)
117 throw wexception("no working/soldier positions");117 throw wexception("no working/soldier positions");
118118
119 // Get programs119 // Get programs
120120
=== modified file 'src/logic/soldier.cc'
--- src/logic/soldier.cc 2013-08-07 03:51:32 +0000
+++ src/logic/soldier.cc 2013-08-10 10:53:03 +0000
@@ -28,7 +28,6 @@
28#include "graphic/graphic.h"28#include "graphic/graphic.h"
29#include "graphic/rendertarget.h"29#include "graphic/rendertarget.h"
30#include "helper.h"30#include "helper.h"
31#include "logic/attackable.h"
32#include "logic/battle.h"31#include "logic/battle.h"
33#include "logic/building.h"32#include "logic/building.h"
34#include "logic/checkstep.h"33#include "logic/checkstep.h"
@@ -38,11 +37,11 @@
38#include "logic/findnode.h"37#include "logic/findnode.h"
39#include "logic/game.h"38#include "logic/game.h"
40#include "logic/game_data_error.h"39#include "logic/game_data_error.h"
40#include "logic/garrison.h"
41#include "logic/message_queue.h"41#include "logic/message_queue.h"
42#include "logic/militarysite.h"42#include "logic/militarysite.h"
43#include "logic/player.h"43#include "logic/player.h"
44#include "logic/tribe.h"44#include "logic/tribe.h"
45#include "logic/warehouse.h"
46#include "map_io/widelands_map_map_object_loader.h"45#include "map_io/widelands_map_map_object_loader.h"
47#include "map_io/widelands_map_map_object_saver.h"46#include "map_io/widelands_map_map_object_saver.h"
48#include "profile/profile.h"47#include "profile/profile.h"
@@ -764,7 +763,11 @@
764struct FindNodeOwned {763struct FindNodeOwned {
765 FindNodeOwned(Player_Number owner) : m_owner(owner)764 FindNodeOwned(Player_Number owner) : m_owner(owner)
766 {};765 {};
766<<<<<<< TREE
767 bool accept(const Map&, const FCoords& coords) const {767 bool accept(const Map&, const FCoords& coords) const {
768=======
769 bool accept(const Map &, const FCoords & coords) const {
770>>>>>>> MERGE-SOURCE
768 return (coords.field->get_owned_by() == m_owner);771 return (coords.field->get_owned_by() == m_owner);
769 }772 }
770private:773private:
@@ -789,8 +792,6 @@
789void Soldier::start_task_attack792void Soldier::start_task_attack
790 (Game & game, Building & building, uint8_t retreat)793 (Game & game, Building & building, uint8_t retreat)
791{794{
792 //dynamic_cast<const Attackable &>(building);
793
794 push_task(game, taskAttack);795 push_task(game, taskAttack);
795 State & state = top_state();796 State & state = top_state();
796 state.objvar1 = &building;797 state.objvar1 = &building;
@@ -960,13 +961,8 @@
960961
961 // Count remaining defenders962 // Count remaining defenders
962 if (enemy) {963 if (enemy) {
963 if (upcast(MilitarySite, ms, enemy)) {964 if (upcast(GarrisonOwner, garrison_owner, enemy)) {
964 defenders = ms->presentSoldiers().size();965 defenders = garrison_owner->get_garrison()->presentSoldiers().size();
965 }
966 if (upcast(Warehouse, wh, enemy)) {
967 Requirements noreq;
968 defenders = wh->count_workers
969 (game, wh->tribe().worker_index("soldier"), noreq);
970 }966 }
971 // Any enemy soldier at baseflag count as defender.967 // Any enemy soldier at baseflag count as defender.
972 std::vector<Bob *> soldiers;968 std::vector<Bob *> soldiers;
@@ -996,6 +992,7 @@
996 BaseImmovable * const newimm = game.map()[state.coords].get_immovable();992 BaseImmovable * const newimm = game.map()[state.coords].get_immovable();
997 upcast(MilitarySite, newsite, newimm);993 upcast(MilitarySite, newsite, newimm);
998 if (newsite and (&newsite->owner() == &owner())) {994 if (newsite and (&newsite->owner() == &owner())) {
995<<<<<<< TREE
999 if (upcast(SoldierControl, ctrl, newsite)) {996 if (upcast(SoldierControl, ctrl, newsite)) {
1000 state.objvar1 = 0;997 state.objvar1 = 0;
1001 // We may also have our location destroyed in between998 // We may also have our location destroyed in between
@@ -1011,6 +1008,20 @@
1011 newsite->update_soldier_request();1008 newsite->update_soldier_request();
1012 return schedule_act(game, 10);1009 return schedule_act(game, 10);
1013 }1010 }
1011=======
1012 state.objvar1 = 0;
1013 if
1014 (newsite->get_garrison()->stationedSoldiers().size()
1015 < newsite->get_garrison()->soldierCapacity() and
1016 location->base_flag().get_position()
1017 !=
1018 newsite ->base_flag().get_position())
1019 {
1020 molog("[attack] enemy belongs to us now, move in\n");
1021 pop_task(game);
1022 set_location(newsite);
1023 return schedule_act(game, 10);
1024>>>>>>> MERGE-SOURCE
1014 }1025 }
1015 }1026 }
1016 }1027 }
@@ -1040,12 +1051,12 @@
1040 }1051 }
1041 }1052 }
10421053
1043 upcast(Attackable, attackable, enemy);1054 upcast(GarrisonOwner, garrison_o, enemy);
1044 assert(attackable);1055 assert(garrison_o);
10451056
1046 molog("[attack] attacking target building\n");1057 molog("[attack] attacking target building\n");
1047 // give the enemy soldier some time to act1058 // give the enemy soldier some time to act
1048 schedule_act(game, attackable->attack(*this) ? 1000 : 10);1059 schedule_act(game, garrison_o->get_garrison()->attack(*this) ? 1000 : 10);
1049}1060}
10501061
1051void Soldier::attack_pop(Game & game, State &)1062void Soldier::attack_pop(Game & game, State &)
@@ -1789,13 +1800,17 @@
1789 CheckStepWalkOn(descr().movecaps(), false),1800 CheckStepWalkOn(descr().movecaps(), false),
1790 FindImmovableAttackable());1801 FindImmovableAttackable());
17911802
1792 container_iterate_const(std::vector<BaseImmovable *>, attackables, i)1803 container_iterate_const(std::vector<BaseImmovable *>, attackables, i) {
1804 const BaseImmovable* base_imm = *i.current;
1793 if1805 if
1794 (ref_cast<PlayerImmovable const, BaseImmovable const>(**i.current)1806 (ref_cast<PlayerImmovable const, BaseImmovable const>(*base_imm)
1795 .get_owner()->player_number()1807 .get_owner()->player_number() == land_owner)
1796 ==1808 {
1797 land_owner)1809 if (upcast(const GarrisonOwner, go, base_imm)) {
1798 dynamic_cast<Attackable &>(**i.current).aggressor(*this);1810 go->get_garrison()->aggressor(*this);
1811 }
1812 }
1813 }
1799 }1814 }
1800}1815}
18011816
18021817
=== removed file 'src/logic/soldiercontrol.h'
--- src/logic/soldiercontrol.h 2012-02-15 21:25:34 +0000
+++ src/logic/soldiercontrol.h 1970-01-01 00:00:00 +0000
@@ -1,119 +0,0 @@
1/*
2 * Copyright (C) 2008 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef SOLDIERCONTROL_H
21#define SOLDIERCONTROL_H
22
23#include <vector>
24
25namespace Widelands {
26
27class Soldier;
28
29/**
30 * This interface is implemented by buildings that explicitly house soldiers.
31 *
32 * It is used to implement queries for building UI and to implement commands
33 * that change the soldiers stationed in a building.
34 *
35 * Soldiers are \em stationed in a building if that building is their
36 * \ref Worker::location. Stationed soldiers are \em present in a building
37 * if their current position is inside the building. So for a TrainingSite,
38 * the two concepts are equal. However, they're different for a MilitarySite,
39 * where soldiers can be outside in combat.
40 */
41struct SoldierControl {
42 /**
43 * \return a list of soldiers that are currently present in the building.
44 */
45 virtual std::vector<Soldier *> presentSoldiers() const = 0;
46
47 /**
48 * \return a list of soldiers that are currently stationed in the building.
49 */
50 virtual std::vector<Soldier *> stationedSoldiers() const = 0;
51
52 /**
53 * \return the minimum number of soldiers that this building can be
54 * configured to hold.
55 */
56 virtual uint32_t minSoldierCapacity() const = 0;
57
58 /**
59 * \return the maximum number of soldiers that this building can be
60 * configured to hold.
61 */
62 virtual uint32_t maxSoldierCapacity() const = 0;
63
64 /**
65 * \return the number of soldiers this building is configured to hold
66 * right now.
67 */
68 virtual uint32_t soldierCapacity() const = 0;
69
70 /**
71 * Sets the capacity for soldiers of this building.
72 *
73 * New soldiers will be requested and old soldiers will be evicted
74 * as necessary.
75 */
76 virtual void setSoldierCapacity(uint32_t capacity) = 0;
77
78 void changeSoldierCapacity(int32_t const difference) {
79 uint32_t const old_capacity = soldierCapacity();
80 uint32_t const new_capacity =
81 std::min
82 (static_cast<uint32_t>
83 (std::max
84 (static_cast<int32_t>(old_capacity) + difference,
85 static_cast<int32_t>(minSoldierCapacity()))),
86 maxSoldierCapacity());
87 if (old_capacity != new_capacity)
88 setSoldierCapacity(new_capacity);
89 }
90
91 /**
92 * Evict the given soldier from the building immediately,
93 * without changing the building's capacity.
94 *
95 * \note This has no effect if the soldier is currently involved in a battle
96 * or otherwise blocked from leaving the building.
97 */
98 virtual void dropSoldier(Soldier &) = 0;
99
100 /**
101 * Add a new soldier into this site. Returns -1 if there is no space
102 * for him, 0 on success
103 */
104 virtual int incorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
105
106 /**
107 * Remove a soldier from the internal list. Most SoldierControls will be
108 * informed by the soldier when it is removed, but WareHouses for example
109 * will not.
110 */
111 virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &) {return 0;}
112
113protected:
114 virtual ~SoldierControl() {}
115};
116
117}
118
119#endif // SOLDIERCONTROL_H
1200
=== added file 'src/logic/storage.h'
--- src/logic/storage.h 1970-01-01 00:00:00 +0000
+++ src/logic/storage.h 2013-08-10 10:53:03 +0000
@@ -0,0 +1,195 @@
1/*
2 * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef STORAGE_H
21#define STORAGE_H
22
23#include <vector>
24
25#include "logic/requirements.h"
26#include "logic/wareworker.h"
27#include "logic/widelands.h"
28
29namespace Widelands {
30
31class Building;
32class Worker;
33class Editor_Game_Base;
34class Game;
35class WareInstance;
36class WareList;
37class Player;
38
39/**
40 * A storage represents wares and workers stocks. It is owned by StrorageOwner buildings.
41 * This interface contains various method used to deal with wares requests, prioriies
42 * and disponibility.
43 */
44class Storage {
45public:
46 /**
47 * Each ware and worker type has an associated per-storage
48 * stock policy that defines whether it will be stocked by this
49 * warehouse.
50 *
51 * \note The values of this enum are written directly into savegames,
52 * so be careful when changing them.
53 */
54 enum class StockPolicy : uint8_t {
55 /**
56 * The default policy allows stocking wares without any special priority.
57 */
58 Normal = 0,
59
60 /**
61 * As long as there are warehouses with this policy for a ware, all
62 * available unstocked supplies will be transferred to warehouses
63 * with this policy.
64 */
65 Prefer = 1,
66
67 /**
68 * If a ware has this stock policy, no new items of this ware will enter
69 * the warehouse.
70 */
71 DontStock = 2,
72
73 /**
74 * Like \ref SP_DontStock, but in addition, existing stock of this ware
75 * will be transported out of the warehouse over time.
76 */
77 Remove = 3,
78 };
79
80 /**
81 * \return the player that own this storage
82 */
83 virtual Player & owner() const = 0;
84 /**
85 * \return the wares present in this storage
86 */
87 virtual const WareList & get_wares() const = 0;
88 /**
89 * \return the workers present in this storage
90 */
91 virtual const WareList & get_workers() const = 0;
92 /**
93 * Increase the stock of the specified ware type
94 */
95 virtual void insert_wares (Ware_Index, uint32_t count) = 0;
96 /**
97 * Decrease the stock of the specified ware type
98 */
99 virtual void remove_wares (Ware_Index, uint32_t count) = 0;
100 /**
101 * Increase the stock of the specified worker type
102 */
103 virtual void insert_workers(Ware_Index, uint32_t count) = 0;
104 /**
105 * Decrease the stock of the specified worker type
106 */
107 virtual void remove_workers(Ware_Index, uint32_t count) = 0;
108 /**
109 * Get a specified ware from the storage.
110 * \return the wareinstance
111 */
112 virtual WareInstance & launch_ware(Game &, Ware_Index) = 0;
113 /**
114 * Launch a ware already instanciated
115 */
116 virtual void do_launch_ware(Game &, WareInstance&) = 0;
117 /**
118 * Adds the specified ware to the storage. The ware might
119 * be removed from the game following this call.
120 */
121 virtual void incorporate_ware(Editor_Game_Base &, WareInstance &) = 0;
122 /**
123 * Get the specified worker from the storage.
124 * \return the worker
125 */
126 virtual Worker & launch_worker(Game &, Ware_Index, const Requirements & = Requirements()) = 0;
127 /**
128 * Adds the specified worker to the storage. The worker might
129 * be removed from the game following this call.
130 */
131 virtual void incorporate_worker(Editor_Game_Base &, Worker &) = 0;
132 /**
133 * \return the storage stock policy for the specified ware
134 */
135 virtual StockPolicy get_ware_policy(Ware_Index ware) const = 0;
136 /**
137 * \return the storage stock policy for the specified worker
138 */
139 virtual StockPolicy get_worker_policy(Ware_Index ware) const = 0;
140 /**
141 * \return the sotrage stock policy for the specified ware or worker
142 */
143 virtual StockPolicy get_stock_policy(WareWorker waretype, Ware_Index wareindex) const = 0;
144 /**
145 * Set the storage stock policy for the specified ware
146 */
147 virtual void set_ware_policy(Ware_Index ware, StockPolicy policy) = 0;
148 /**
149 * Set the storage stock policy for the specified worker
150 */
151 virtual void set_worker_policy(Ware_Index ware, StockPolicy policy) = 0;
152 /**
153 * Return true if the storage has all requirement in stock to create
154 * the specified worker
155 */
156 virtual bool can_create_worker(Game& game, Ware_Index ware_index) = 0;
157 /**
158 * Create a worker.
159 */
160 virtual void create_worker(Game& game, Ware_Index worker_idx) = 0;
161 /**
162 * Return the amount of planned worker of the given worker idx
163 */
164 virtual uint32_t get_planned_workers(Game &, Ware_Index index) const = 0;
165 /**
166 * Plan to create the specified workers
167 */
168 virtual void plan_workers(Game &, Ware_Index index, uint32_t amount) = 0;
169 /**
170 * Calculate the supply of wares available to this warehouse in each of the
171 * buildcost items for the given worker.
172 *
173 * This is the current stock plus any incoming transfers.
174 */
175 virtual std::vector<uint32_t> calc_available_for_worker(Game &, Ware_Index index) const = 0;
176};
177
178/**
179 * A Storage owner holds a sorage instance.
180 */
181class StorageOwner {
182public:
183 /**
184 * Return the storage instance
185 */
186 virtual Storage* get_storage() const = 0;
187 /**
188 * Return the building owning the storage
189 */
190 virtual Building* get_building() = 0;
191};
192
193}
194
195#endif
0196
=== added file 'src/logic/storagehandler.cc'
--- src/logic/storagehandler.cc 1970-01-01 00:00:00 +0000
+++ src/logic/storagehandler.cc 2013-08-10 10:53:03 +0000
@@ -0,0 +1,1127 @@
1/*
2 * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include "logic/storagehandler.h"
21
22#include <utility>
23
24#include <boost/foreach.hpp>
25
26#include "economy/economy.h"
27#include "economy/flag.h"
28#include "helper.h"
29#include "logic/player.h"
30#include "logic/soldier.h"
31#include "upcast.h"
32
33namespace Widelands {
34
35//************************************************************
36// CLASS Storage Handler
37//************************************************************
38
39StorageHandler::StorageHandler(Building& building)
40: m_building(building),
41 m_supply(new StorageSupply(this))
42{
43}
44
45StorageHandler::~StorageHandler()
46{
47}
48
49
50void StorageHandler::init(Editor_Game_Base&)
51{
52 Ware_Index const nr_wares = owner().tribe().get_nrwares ();
53 Ware_Index const nr_workers = owner().tribe().get_nrworkers();
54 m_supply->set_nrwares (nr_wares);
55 m_supply->set_nrworkers(nr_workers);
56 m_ware_policy.resize(nr_wares.value(), Storage::StockPolicy::Normal);
57 m_worker_policy.resize(nr_workers.value(), Storage::StockPolicy::Normal);
58
59 // Init autospawn
60 const std::vector <Widelands::Ware_Index> worker_types_without_cost =
61 owner().tribe().worker_types_without_cost();
62 BOOST_FOREACH(Ware_Index idx, worker_types_without_cost) {
63 const Worker_Descr & worker_descr = *owner().tribe().get_worker_descr(idx);
64 if (not worker_descr.is_buildable()) {
65 continue;
66 }
67 if (!owner().is_worker_type_allowed(idx)) {
68 continue;
69 }
70 if (worker_descr.buildcost().empty()) {
71 // Workers of this type can be spawned in warehouses. Start it.
72 add_worker_spawn(idx);
73 }
74 }
75}
76
77void StorageHandler::load_finish(Editor_Game_Base&)
78{
79 // Ensure consistency of PlannedWorker requests
80 uint32_t pwidx = 0;
81 while (pwidx < m_planned_workers.size()) {
82 if (!load_finish_planned_workers(m_planned_workers[pwidx])) {
83 m_planned_workers[pwidx].cleanup();
84 m_planned_workers.erase(m_planned_workers.begin() + pwidx);
85 } else {
86 pwidx++;
87 }
88 }
89 // Verify autospawning for free workers
90 const std::vector <Widelands::Ware_Index> worker_types_without_cost =
91 owner().tribe().worker_types_without_cost();
92 BOOST_FOREACH(Ware_Index idx, worker_types_without_cost) {
93 if (!owner().is_worker_type_allowed(idx)) {
94 continue;
95 }
96 if (is_worker_spawn_set(idx)) {
97 continue;
98 }
99 add_worker_spawn(idx);
100 log
101 ("WARNING: player %u is allowed to create worker type %s but his "
102 "%s %u at (%i, %i) does not have spawning set for that "
103 "worker type; setting it to default values\n",
104 owner().player_number(),
105 owner().tribe().get_worker_descr(idx)->descname().c_str(),
106 m_building.descname().c_str(), m_building.serial(),
107 m_building.get_position().x, m_building.get_position().y);
108 }
109}
110
111
112void StorageHandler::cleanup(Editor_Game_Base&)
113{
114 while (!m_planned_workers.empty()) {
115 m_planned_workers.back().cleanup();
116 m_planned_workers.pop_back();
117 }
118}
119
120//TODO return a value so the owner can schedule_act
121uint32_t StorageHandler::act(Game& game)
122{
123 uint32_t gametime = static_cast<uint32_t>(game.get_gametime());
124 uint32_t spawn_act = update_spawns(game, gametime);
125 uint32_t removal_act = update_removals(game, gametime);
126 // Update planned workers; this is to update the request amounts and
127 // check because whether we suddenly can produce a requested worker. This
128 // is mostly previously available wares may become unavailable due to
129 // secondary requests.
130 update_all_planned_workers(game);
131 // Act in 5 sec, or before if timers will run down
132 uint32_t min_act = 5000;
133 if (spawn_act > 0 && spawn_act < min_act) {
134 min_act = spawn_act;
135 }
136 if (removal_act > 0 && removal_act < min_act) {
137 min_act = removal_act;
138 }
139 return min_act;
140}
141
142void StorageHandler::set_economy(Economy* economy)
143{
144 Economy * const old = m_building.get_economy();
145
146 if (old == economy) {
147 return;
148 }
149
150 if (old) {
151 old->remove_storage(*this);
152 }
153
154 m_supply->set_economy(economy);
155
156 container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, pw_it) {
157 container_iterate_const(std::vector<Request *>, pw_it.current->requests, req_it) {
158 (*req_it.current)->set_economy(economy);
159 }
160 }
161
162 if (economy) {
163 economy->add_storage(*this);
164 }
165}
166
167uint32_t StorageHandler::count_workers(Game& game, Ware_Index idx, const Requirements& req)
168{
169 uint32_t stock = m_supply->stock_workers(idx);
170 if (stock <= 0) {
171 return stock;
172 }
173 uint32_t matching = 0;
174 // Get list of those for which we stored the attributes
175 // This is similar logic than in launch_worker
176 std::vector<const StockedWorkerAtr*> workers_with_atr;
177 BOOST_FOREACH(StockedWorkerAtr& atr, m_stocked_workers_atr) {
178 if (atr.index == idx) {
179 workers_with_atr.push_back(&atr);
180 }
181 }
182 // First check those without atr
183 Worker* w;
184 bool checkpass = false;
185 const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(idx);
186 if (stock > workers_with_atr.size()) {
187 w = &workerdescr.create(game, owner(), &m_building, m_building.get_position());
188 checkpass = req.check(*w);
189 if (checkpass) {
190 matching += stock - workers_with_atr.size();
191 }
192 w->remove(game);
193 }
194 // Check with our atr
195 // TODO CGH use smarter way of storing atr, maybe with map
196 BOOST_FOREACH(const StockedWorkerAtr* atr, workers_with_atr) {
197 w = create_with_atr(game, *atr);
198 checkpass = req.check(*w);
199 if (checkpass) {
200 matching++;
201 }
202 w->remove(game);
203 }
204 return matching;
205}
206
207
208void StorageHandler::launch_all_workers(Game & game, bool exp_only, const WareList& excluded)
209{
210 if (!exp_only) {
211 for (Ware_Index id = Ware_Index::First(); id < m_supply->get_workers().get_nrwareids(); ++id) {
212 if (excluded.stock(id)) {
213 continue;
214 }
215 const uint32_t stock = m_supply->get_workers().stock(id);
216 if (stock > 0) {
217 for (uint32_t i = 0; i < stock; ++i) {
218 launch_worker(game, id).start_task_leavebuilding(game, true);
219 }
220 }
221 }
222 return;
223 }
224 BOOST_FOREACH(StockedWorkerAtr atr, m_stocked_workers_atr) {
225 if (excluded.stock(atr.index)) {
226 continue;
227 }
228 if (m_supply->get_workers().stock(atr.index) <= 0) {
229 continue;
230 }
231 Worker* w = create_with_atr(game, atr);
232 w->start_task_leavebuilding(game, true);
233 m_supply->remove_workers(atr.index, 1);
234 }
235}
236
237void StorageHandler::add_ware_spawn
238 (const Ware_Index idx, uint32_t interval, uint32_t stock_max, uint32_t counter, bool dont_exceed)
239{
240 if (m_spawn_wares.count(idx)) {
241 remove_ware_spawn(idx);
242 }
243 if (dont_exceed) {
244 std::vector<uint32_t> values = {interval, interval, stock_max};
245 m_spawn_wares.insert(std::make_pair(idx, values));
246 } else {
247 std::vector<uint32_t> values = {interval, interval, stock_max, counter};
248 m_spawn_wares.insert(std::make_pair(idx, values));
249 }
250}
251
252void StorageHandler::remove_ware_spawn(const Ware_Index idx)
253{
254 m_spawn_wares.erase(idx);
255}
256bool StorageHandler::is_ware_spawn_set(Ware_Index idx)
257{
258 return m_spawn_wares.count(idx);
259}
260
261
262void StorageHandler::add_worker_spawn
263 (const Ware_Index idx, uint32_t interval, uint32_t stock_max, uint32_t counter, bool dont_exceed)
264{
265 if (m_spawn_workers.count(idx)) {
266 remove_worker_spawn(idx);
267 }
268 if (dont_exceed) {
269 std::vector<uint32_t> values = {interval, interval, stock_max};
270 m_spawn_workers.insert(std::make_pair(idx, values));
271 } else {
272 std::vector<uint32_t> values = {interval, interval, stock_max, counter};
273 m_spawn_workers.insert(std::make_pair(idx, values));
274 }
275}
276
277void StorageHandler::remove_worker_spawn(const Ware_Index idx)
278{
279 m_spawn_workers.erase(idx);
280}
281bool StorageHandler::is_worker_spawn_set(Ware_Index idx)
282{
283 return m_spawn_workers.count(idx);
284}
285
286//
287//
288// Storage implementation
289//
290//
291
292Player& StorageHandler::owner() const
293{
294 return m_building.owner();
295}
296
297const WareList& StorageHandler::get_wares() const
298{
299 return m_supply->get_wares();
300}
301
302const WareList& StorageHandler::get_workers() const
303{
304 return m_supply->get_workers();
305}
306
307void StorageHandler::insert_wares(Ware_Index idx, uint32_t count)
308{
309 m_supply->add_wares(idx, count);
310}
311
312void StorageHandler::remove_wares(Ware_Index idx, uint32_t count)
313{
314 m_supply->remove_wares(idx, count);
315}
316
317void StorageHandler::insert_workers(Ware_Index idx, uint32_t count)
318{
319 m_supply->add_workers(idx, count);
320}
321
322void StorageHandler::remove_workers(Ware_Index idx, uint32_t count)
323{
324 m_supply->remove_workers(idx, count);
325}
326
327WareInstance& StorageHandler::launch_ware(Game& game, Ware_Index idx)
328{
329 WareInstance & item = *new WareInstance(idx, owner().tribe().get_ware_descr(idx));
330 item.init(game);
331 do_launch_ware(game, item);
332
333 m_supply->remove_wares(idx, 1);
334
335 return item;
336}
337
338
339void StorageHandler::do_launch_ware(Game& game, WareInstance& ware_inst)
340{
341 // Create a carrier
342 Ware_Index const carrierid = owner().tribe().worker_index("carrier");
343 const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(carrierid);
344
345 Worker & worker = workerdescr.create(game, owner(), &m_building, m_building.get_position());
346
347 // Yup, this is cheating.
348 if (m_supply->stock_workers(carrierid))
349 m_supply->remove_workers(carrierid, 1);
350
351 // Setup the carrier
352 worker.start_task_dropoff(game, ware_inst);
353}
354
355
356void StorageHandler::incorporate_ware(Editor_Game_Base& egbase, WareInstance& item)
357{
358 m_supply->add_wares(item.descr_index(), 1);
359 return item.destroy(egbase);
360}
361
362Worker& StorageHandler::launch_worker(Game& game, Ware_Index idx, const Requirements& req)
363{
364 do {
365 uint32_t stock = m_supply->stock_workers(idx);
366 if (stock > 0) {
367 // Get list of those for which we stored the attributes, as pointers to actual objects
368 // TODO smarter storage for atrs
369 std::vector<const StockedWorkerAtr*> workers_with_atr;
370 for
371 (std::vector<StockedWorkerAtr>::iterator it = m_stocked_workers_atr.begin();
372 it != m_stocked_workers_atr.end(); ++it)
373 {
374 if (it->index == idx) {
375 workers_with_atr.push_back(&(*it));
376 }
377 }
378 // First check if one without atr is enough
379 Worker* w;
380 if (stock > workers_with_atr.size()) {
381 const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(idx);
382 w = &workerdescr.create(game, owner(), &m_building, m_building.get_position());
383 if (req.check(*w)) {
384 m_supply->remove_workers(idx, 1);
385 return *w;
386 }
387 }
388 // Check with our atr
389 BOOST_FOREACH(const StockedWorkerAtr* atr, workers_with_atr) {
390 w = create_with_atr(game, *atr);
391 if (req.check(*w)) {
392 // We need to find back our atr in original vector to erase it
393 bool removed = false;
394 for
395 (std::vector<StockedWorkerAtr>::iterator it = m_stocked_workers_atr.begin();
396 it != m_stocked_workers_atr.end(); ++it)
397 {
398 if (&(*it) == atr) {
399 m_stocked_workers_atr.erase(it);
400 removed = true;
401 break;
402 }
403 }
404 assert(removed);
405 m_supply->remove_workers(idx, 1);
406 return *w;
407 }
408 }
409 }
410 // Check if we got the tools to create a new one
411 if (can_create_worker(game, idx)) {
412 // don't want to use an upgraded worker, so create new one.
413 create_worker(game, idx);
414 } else {
415 idx = owner().tribe().get_worker_descr(idx)->becomes();
416 }
417 } while (idx != Ware_Index::Null());
418
419 throw wexception
420 ("StorageHandler::launch_worker: worker does not actually exist");
421}
422
423void StorageHandler::incorporate_worker(Editor_Game_Base& egbase, Worker& w)
424{
425 assert(w.get_owner() == &owner());
426 // Rescue carried ware
427 if (WareInstance * const item = w.fetch_carried_item(egbase)) {
428 incorporate_ware(egbase, *item);
429 }
430 // Add to supply
431 Ware_Index worker_index = owner().tribe().worker_index(w.name().c_str());
432 m_supply->add_workers(worker_index, 1);
433
434 // Store the attributes.
435 // FIXME CGH handle soldiers : hp & healing
436 StockedWorkerAtr* atr = store_worker_atr(w);
437 if (atr != nullptr) {
438 m_stocked_workers_atr.push_back(*atr);
439 }
440 // Destroy the instance
441 w.remove(egbase);
442}
443
444Storage::StockPolicy StorageHandler::get_ware_policy(Ware_Index ware) const
445{
446 assert(ware.value() < m_ware_policy.size());
447 return m_ware_policy[ware.value()];
448}
449
450Storage::StockPolicy StorageHandler::get_worker_policy(Ware_Index ware) const
451{
452 assert(ware.value() < m_worker_policy.size());
453 return m_worker_policy[ware.value()];
454}
455
456Storage::StockPolicy StorageHandler::get_stock_policy(WareWorker waretype, Ware_Index wareindex) const
457{
458 if (waretype == wwWORKER)
459 return get_worker_policy(wareindex);
460 else
461 return get_ware_policy(wareindex);
462}
463
464void StorageHandler::set_ware_policy(Ware_Index ware, Storage::StockPolicy policy)
465{
466 assert(ware.value() < m_ware_policy.size());
467 m_ware_policy[ware.value()] = policy;
468}
469
470void StorageHandler::set_worker_policy(Ware_Index ware, Storage::StockPolicy policy)
471{
472 assert(ware.value() < m_worker_policy.size());
473 m_worker_policy[ware.value()] = policy;
474}
475
476bool StorageHandler::can_create_worker(Game&, Ware_Index worker_idx)
477{
478 if (not (worker_idx < m_supply->get_workers().get_nrwareids())) {
479 throw wexception
480 ("worker type %d does not exists (max is %d)",
481 worker_idx.value(), m_supply->get_workers().get_nrwareids().value());
482 }
483
484 const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(worker_idx);
485 assert(&w_desc);
486 if (not w_desc.is_buildable()) {
487 return false;
488 }
489
490 // see if we have the resources
491 const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
492 container_iterate_const(Worker_Descr::Buildcost, buildcost, it) {
493 const std::string & input_name = it.current->first;
494 if (Ware_Index id_w = owner().tribe().ware_index(input_name)) {
495 if (m_supply->stock_wares (id_w) < it.current->second)
496 return false;
497 } else if ((id_w = owner().tribe().worker_index(input_name))) {
498 if (m_supply->stock_workers(id_w) < it.current->second)
499 return false;
500 } else
501 throw wexception
502 ("worker type %s needs \"%s\" to be built but that is neither "
503 "a ware type nor a worker type defined in the tribe %s",
504 w_desc.descname().c_str(), input_name.c_str(),
505 owner().tribe().name().c_str());
506 }
507 return true;
508}
509
510void StorageHandler::create_worker(Game& game, Ware_Index worker_idx)
511{
512 assert(can_create_worker (game, worker_idx));
513
514 const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(worker_idx);
515 const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
516 container_iterate_const(Worker_Descr::Buildcost, buildcost, i) {
517 const std::string & input = i.current->first;
518 if (Ware_Index const id_ware = owner().tribe().ware_index(input)) {
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: