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
1=== modified file 'global/militarysites/barracks.empire/conf'
2--- global/militarysites/barracks.empire/conf 2013-06-11 16:37:44 +0000
3+++ global/militarysites/barracks.empire/conf 2013-08-10 10:53:03 +0000
4@@ -1,9 +1,11 @@
5 size=small
6-heal_per_second=60 # very low -> smallest building
7+buildable=no
8+
9+[garrison]
10 conquers=6
11 max_soldiers=1
12-buildable=no
13 prefer_heroes=false
14+heal_per_second=60
15
16 [idle]
17 pics=../../../tribes/empire/barracks/barracks_i_??.png
18
19=== modified file 'global/militarysites/barrier.barbarians/conf'
20--- global/militarysites/barrier.barbarians/conf 2013-06-11 16:37:44 +0000
21+++ global/militarysites/barrier.barbarians/conf 2013-08-10 10:53:03 +0000
22@@ -1,9 +1,11 @@
23 size=medium
24+buildable=no
25+
26+[garrison]
27+conquers=8
28 max_soldiers=5
29+prefer_heroes=true
30 heal_per_second=130
31-conquers=8
32-buildable=no
33-prefer_heroes=true
34
35 [idle]
36 pics=../../../tribes/barbarians/barrier/barrier_i_??.png
37
38=== modified file 'global/militarysites/barrier.empire/conf'
39--- global/militarysites/barrier.empire/conf 2013-06-11 16:37:44 +0000
40+++ global/militarysites/barrier.empire/conf 2013-08-10 10:53:03 +0000
41@@ -1,9 +1,11 @@
42 size=medium
43+buildable=no
44+
45+[garrison]
46+conquers=8
47 max_soldiers=5
48+prefer_heroes=true
49 heal_per_second=130
50-conquers=8
51-buildable=no
52-prefer_heroes=true
53
54 [idle]
55 pics=../../../tribes/empire/barrier/barrier_i_??.png
56
57=== modified file 'global/militarysites/castle.atlanteans/conf'
58--- global/militarysites/castle.atlanteans/conf 2013-06-11 16:37:44 +0000
59+++ global/militarysites/castle.atlanteans/conf 2013-08-10 10:53:03 +0000
60@@ -1,8 +1,10 @@
61 size=big
62-max_soldiers=12
63+buildable=no
64+
65+[garrison]
66 heal_per_second=200
67 conquers=12
68-buildable=no
69+max_soldiers=12
70 prefer_heroes=true
71
72 [idle]
73
74=== modified file 'global/militarysites/castle.empire/conf'
75--- global/militarysites/castle.empire/conf 2013-06-11 16:37:44 +0000
76+++ global/militarysites/castle.empire/conf 2013-08-10 10:53:03 +0000
77@@ -1,9 +1,11 @@
78 size=big
79+buildable=no
80+
81+[garrison]
82+conquers=12
83 max_soldiers=12
84+prefer_heroes=true
85 heal_per_second=220
86-conquers=12
87-buildable=no
88-prefer_heroes=true
89
90 [idle]
91 pics=../../../tribes/empire/castle/castle_i_??.png
92
93=== modified file 'global/militarysites/citadel.barbarians/conf'
94--- global/militarysites/citadel.barbarians/conf 2013-06-11 16:37:44 +0000
95+++ global/militarysites/citadel.barbarians/conf 2013-08-10 10:53:03 +0000
96@@ -1,9 +1,11 @@
97 size=big
98+buildable=no
99+
100+[garrison]
101+conquers=12
102 max_soldiers=12
103+prefer_heroes=true
104 heal_per_second=220
105-conquers=12
106-buildable=no
107-prefer_heroes=true
108
109 [idle]
110 pics=../../../tribes/barbarians/citadel/citadel_i_??.png
111
112=== modified file 'global/militarysites/donjon.barbarians/conf'
113--- global/militarysites/donjon.barbarians/conf 2013-06-11 16:37:44 +0000
114+++ global/militarysites/donjon.barbarians/conf 2013-08-10 10:53:03 +0000
115@@ -1,10 +1,12 @@
116 size=medium
117-max_soldiers=5
118-heal_per_second=150
119-conquers=8
120 vision_range=17
121 buildable=no
122+
123+[garrison]
124+conquers=8
125+max_soldiers=5
126 prefer_heroes=true
127+heal_per_second=150
128
129 [idle]
130 pics=../../../tribes/barbarians/donjon/donjon_i_??.png
131
132=== modified file 'global/militarysites/fortress.barbarians/conf'
133--- global/militarysites/fortress.barbarians/conf 2013-06-11 16:37:44 +0000
134+++ global/militarysites/fortress.barbarians/conf 2013-08-10 10:53:03 +0000
135@@ -1,9 +1,11 @@
136 size=big
137+buildable=no
138+
139+[garrison]
140+conquers=11
141 max_soldiers=8
142+prefer_heroes=true
143 heal_per_second=170
144-conquers=11
145-buildable=no
146-prefer_heroes=true
147
148 [idle]
149 pics=../../../tribes/barbarians/fortress/fortress_i_??.png
150
151=== modified file 'global/militarysites/fortress.empire/conf'
152--- global/militarysites/fortress.empire/conf 2013-06-11 16:37:44 +0000
153+++ global/militarysites/fortress.empire/conf 2013-08-10 10:53:03 +0000
154@@ -1,9 +1,11 @@
155 size=big
156+buildable=no
157+
158+[garrison]
159+conquers=11
160 max_soldiers=8
161+prefer_heroes=true
162 heal_per_second=170
163-conquers=11
164-buildable=no
165-prefer_heroes=true
166
167 [idle]
168 pics=../../../tribes/empire/fortress/fortress_i_??.png
169
170=== modified file 'global/militarysites/guardhall.atlanteans/conf'
171--- global/militarysites/guardhall.atlanteans/conf 2013-06-11 16:37:44 +0000
172+++ global/militarysites/guardhall.atlanteans/conf 2013-08-10 10:53:03 +0000
173@@ -1,8 +1,10 @@
174 size=medium
175-max_soldiers=7
176+buildable=no
177+
178+[garrison]
179 heal_per_second=140
180 conquers=7
181-buildable=no
182+max_soldiers=7
183 prefer_heroes=true
184
185 [idle]
186
187=== modified file 'global/militarysites/guardhouse.atlanteans/conf'
188--- global/militarysites/guardhouse.atlanteans/conf 2013-06-11 16:37:44 +0000
189+++ global/militarysites/guardhouse.atlanteans/conf 2013-08-10 10:53:03 +0000
190@@ -1,8 +1,10 @@
191 size=small
192+buildable=no
193+
194+[garrison]
195 heal_per_second=75
196 conquers=6
197 max_soldiers=2
198-buildable=no
199 prefer_heroes=false
200
201 [idle]
202
203=== modified file 'global/militarysites/high_tower.atlanteans/conf'
204--- global/militarysites/high_tower.atlanteans/conf 2013-06-11 16:37:44 +0000
205+++ global/militarysites/high_tower.atlanteans/conf 2013-08-10 10:53:03 +0000
206@@ -1,10 +1,12 @@
207 size=medium
208-max_soldiers=5
209-heal_per_second=170
210-conquers=9
211 vision_range=21
212 buildable=no
213+
214+[garrison]
215+conquers=9
216+max_soldiers=5
217 prefer_heroes=true
218+heal_per_second=170
219
220 [idle]
221 pics=../../../tribes/atlanteans/high_tower/high_tower_i_??.png
222
223=== modified file 'global/militarysites/outpost.empire/conf'
224--- global/militarysites/outpost.empire/conf 2013-06-11 16:37:44 +0000
225+++ global/militarysites/outpost.empire/conf 2013-08-10 10:53:03 +0000
226@@ -1,9 +1,11 @@
227 size=medium
228+buildable=no
229+
230+[garrison]
231+conquers=7
232 max_soldiers=3
233+prefer_heroes=false
234 heal_per_second=100
235-conquers=7
236-buildable=no
237-prefer_heroes=false
238
239 [idle]
240 pics=../../../tribes/empire/outpost/outpost_i_??.png
241
242=== modified file 'global/militarysites/sentry.barbarians/conf'
243--- global/militarysites/sentry.barbarians/conf 2013-06-11 16:37:44 +0000
244+++ global/militarysites/sentry.barbarians/conf 2013-08-10 10:53:03 +0000
245@@ -1,9 +1,11 @@
246 size=small
247-heal_per_second=80
248+buildable=no
249+
250+[garrison]
251 conquers=6
252 max_soldiers=2
253-buildable=no
254 prefer_heroes=false
255+heal_per_second=80
256
257 [idle]
258 pics=../../../tribes/barbarians/sentry/sentry_i_??.png
259
260=== modified file 'global/militarysites/sentry.empire/conf'
261--- global/militarysites/sentry.empire/conf 2013-06-11 16:37:44 +0000
262+++ global/militarysites/sentry.empire/conf 2013-08-10 10:53:03 +0000
263@@ -1,9 +1,11 @@
264 size=small
265-heal_per_second=80
266+buildable=no
267+
268+[garrison]
269 conquers=6
270 max_soldiers=2
271-buildable=no
272 prefer_heroes=false
273+heal_per_second=80
274
275 [idle]
276 pics=../../../tribes/empire/sentry/sentry_i_??.png
277
278=== modified file 'global/militarysites/small_tower.atlanteans/conf'
279--- global/militarysites/small_tower.atlanteans/conf 2013-06-11 16:37:44 +0000
280+++ global/militarysites/small_tower.atlanteans/conf 2013-08-10 10:53:03 +0000
281@@ -1,10 +1,12 @@
282 size=small
283+vision_range=13
284+buildable=no
285+
286+[garrison]
287 heal_per_second=100
288 conquers=5
289-vision_range=13
290 max_soldiers=3
291-buildable=no
292-prefer_heroes=false
293+prefer_heroes=true
294
295 [idle]
296 pics=../../../tribes/atlanteans/small_tower/small_tower_i_??.png
297
298=== modified file 'global/militarysites/stronghold.barbarians/conf'
299--- global/militarysites/stronghold.barbarians/conf 2013-06-11 16:37:44 +0000
300+++ global/militarysites/stronghold.barbarians/conf 2013-08-10 10:53:03 +0000
301@@ -1,9 +1,11 @@
302 size=medium
303+buildable=no
304+
305+[garrison]
306+conquers=7
307 max_soldiers=3
308+prefer_heroes=false
309 heal_per_second=110
310-conquers=7
311-buildable=no
312-prefer_heroes=false
313
314 [idle]
315 pics=../../../tribes/barbarians/stronghold/stronghold_i_??.png
316
317=== modified file 'global/militarysites/tower.atlanteans/conf'
318--- global/militarysites/tower.atlanteans/conf 2013-06-11 16:37:44 +0000
319+++ global/militarysites/tower.atlanteans/conf 2013-08-10 10:53:03 +0000
320@@ -1,10 +1,12 @@
321 size=medium
322-max_soldiers=4
323+vision_range=17
324+buildable=no
325+
326+[garrison]
327 heal_per_second=120
328 conquers=9
329-vision_range=17
330-buildable=no
331-prefer_heroes=true
332+max_soldiers=4
333+prefer_heroes=false
334
335 [idle]
336 pics=../../../tribes/atlanteans/tower/tower_i_??.png
337
338=== modified file 'global/militarysites/tower.empire/conf'
339--- global/militarysites/tower.empire/conf 2013-06-11 16:37:44 +0000
340+++ global/militarysites/tower.empire/conf 2013-08-10 10:53:03 +0000
341@@ -1,10 +1,11 @@
342 size=medium
343+buildable=no
344+
345+[garrison]
346+conquers=9
347 max_soldiers=5
348+prefer_heroes=true
349 heal_per_second=150
350-conquers=9
351-vision_range=19
352-buildable=no
353-prefer_heroes=true
354
355 [idle]
356 pics=../../../tribes/empire/tower/tower_i_??.png
357
358=== modified file 'src/ai/defaultai.cc'
359--- src/ai/defaultai.cc 2013-07-26 20:19:36 +0000
360+++ src/ai/defaultai.cc 2013-08-10 10:53:03 +0000
361@@ -72,7 +72,7 @@
362 next_attack_consideration_due(300000),
363 inhibit_road_building (0),
364 time_of_last_construction (0),
365- numof_warehouses (0)
366+ numof_storages (0)
367 {}
368
369 DefaultAI::~DefaultAI()
370@@ -577,7 +577,7 @@
371
372 if (v > 0)
373 field.military_influence +=
374- v * v * militarysite->soldierCapacity();
375+ v * v * militarysite->get_garrison()->soldierCapacity();
376 }
377
378 if (dynamic_cast<const ProductionSite *>(building))
379@@ -626,7 +626,7 @@
380
381 if (v > 0)
382 field.military_influence +=
383- v * v * militarysite->soldierCapacity();
384+ v * v * militarysite->get_garrison()->soldierCapacity();
385 }
386 }
387 }
388@@ -881,8 +881,8 @@
389 // Check if the produced wares are needed
390 Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));
391 container_iterate(std::list<EconomyObserver *>, economies, l) {
392- // Don't check if the economy has no warehouse.
393- if ((*l.current)->economy.warehouses().empty())
394+ // Don't check if the economy has no storage.
395+ if ((*l.current)->economy.storages().empty())
396 continue;
397 if ((*l.current)->economy.needs_ware(wt))
398 prio += 1 + wares.at(bo.outputs.at(0)).preciousness;
399@@ -918,8 +918,8 @@
400 // the ware they're refreshing
401 Ware_Index wt(static_cast<size_t>(bo.production_hint));
402 container_iterate(std::list<EconomyObserver *>, economies, l) {
403- // Don't check if the economy has no warehouse.
404- if ((*l.current)->economy.warehouses().empty())
405+ // Don't check if the economy has no storages.
406+ if ((*l.current)->economy.storages().empty())
407 continue;
408 if ((*l.current)->economy.needs_ware(wt)) {
409 prio += wares.at(bo.production_hint).preciousness * inout * 2;
410@@ -964,8 +964,8 @@
411
412 // Check if the produced wares are needed
413 container_iterate(std::list<EconomyObserver *>, economies, l) {
414- // Don't check if the economy has no warehouse.
415- if ((*l.current)->economy.warehouses().empty())
416+ // Don't check if the economy has no storages.
417+ if ((*l.current)->economy.storages().empty())
418 continue;
419 for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
420 Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));
421@@ -1056,7 +1056,7 @@
422 // needed for soldier training) near the frontier.
423 prio += productionsites.size() + mines.size();
424 prio += militarysites.size() / 3;
425- prio -= (bo.cnt_under_construction + numof_warehouses) * 35;
426+ prio -= (bo.cnt_under_construction + numof_storages) * 35;
427 prio *= 2;
428
429 // take care about borders and enemies
430@@ -1880,13 +1880,13 @@
431
432 if (map.find_fields(Area<FCoords>(f, vision), 0, find_unowned) == 0) {
433 // If no enemy in sight - decrease the number of stationed soldiers
434- // as long as it is > 1 - BUT take care that there is a warehouse in the
435+ // as long as it is > 1 - BUT take care that there is a storage in the
436 // same economy where the thrown out soldiers can go to.
437- if (ms->economy().warehouses().size()) {
438- uint32_t const j = ms->soldierCapacity();
439- if (MilitarySite::kPrefersRookies != ms->get_soldier_preference())
440+ if (ms->economy().storages().size()) {
441+ uint32_t const j = ms->get_garrison()->soldierCapacity();
442+ if (Garrison::SoldierPref::Rookies != ms->get_garrison()->get_soldier_preference())
443 {
444- game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersRookies);
445+ game().send_player_militarysite_set_soldier_preference(*ms, Garrison::SoldierPref::Rookies);
446 }
447 else
448 if (j > 1)
449@@ -1912,7 +1912,7 @@
450 // the destruction of the flag avoids that defaultAI will have
451 // too many unused roads - if needed the road will be rebuild
452 // directly.
453- if (static_cast<int32_t>(ms->maxSoldierCapacity() * 4) < bf.military_influence) {
454+ if (static_cast<int32_t>(ms->get_garrison()->maxSoldierCapacity() * 4) < bf.military_influence) {
455 if (ms->get_playercaps() & Widelands::Building::PCap_Dismantle) {
456 flags_to_be_removed.push_back(ms->base_flag().get_position());
457 game().send_player_dismantle(*ms);
458@@ -1964,12 +1964,12 @@
459 } else {
460 // If an enemy is in sight and the number of stationed soldier is not
461 // at maximum - set it to maximum.
462- uint32_t const j = ms->maxSoldierCapacity();
463- uint32_t const k = ms->soldierCapacity();
464+ uint32_t const j = ms->get_garrison()->maxSoldierCapacity();
465+ uint32_t const k = ms->get_garrison()->soldierCapacity();
466 if (j > k)
467 game().send_player_change_soldier_capacity(*ms, j - k);
468- if (MilitarySite::kPrefersHeroes != ms->get_soldier_preference())
469- game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersHeroes);
470+ if (Garrison::SoldierPref::Heroes != ms->get_garrison()->get_soldier_preference())
471+ game().send_player_militarysite_set_soldier_preference(*ms, Garrison::SoldierPref::Heroes);
472 changed = true;
473 }
474 reorder:;
475@@ -2182,7 +2182,7 @@
476 militarysites.back().bo = &bo;
477 militarysites.back().checks = bo.desc->get_size();
478 } else if (bo.type == BuildingObserver::WAREHOUSE)
479- ++numof_warehouses;
480+ ++numof_storages;
481 }
482 }
483
484@@ -2244,8 +2244,8 @@
485 break;
486 }
487 } else if (bo.type == BuildingObserver::WAREHOUSE) {
488- assert(numof_warehouses > 0);
489- --numof_warehouses;
490+ assert(numof_storages > 0);
491+ --numof_storages;
492 }
493 }
494 m_buildable_changed = true;
495@@ -2310,41 +2310,28 @@
496 map.find_immovables
497 (Area<FCoords>(f, vision), &immovables, FindImmovableAttackable());
498
499- for (uint32_t j = 0; j < immovables.size(); ++j)
500- if (upcast(MilitarySite, bld, immovables.at(j).object)) {
501- if (!player->is_hostile(bld->owner()))
502- continue;
503- if (bld->canAttack()) {
504- int32_t ta = player->findAttackSoldiers(bld->base_flag());
505- if (type == NORMAL)
506- ta = ta * 2 / 3;
507- if (ta < 1)
508- continue;
509-
510- int32_t const tc = ta - bld->presentSoldiers().size();
511- if (tc > chance) {
512- target = bld;
513- chance = tc;
514- attackers = ta;
515- }
516- }
517- } else if (upcast(Warehouse, wh, immovables.at(j).object)) {
518- if (!player->is_hostile(wh->owner()))
519- continue;
520- if (wh->canAttack()) {
521- int32_t ta = player->findAttackSoldiers(wh->base_flag());
522- if (ta < 1)
523- continue;
524-
525- // extra priority push!
526- int32_t tc = ta * 2;
527- if (tc > chance) {
528- target = wh;
529- chance = tc;
530- attackers = ta;
531- }
532+ for (uint32_t j = 0; j < immovables.size(); ++j) {
533+ if (upcast(GarrisonOwner, go, immovables.at(j).object)) {
534+ if (!player->is_hostile(go->get_garrison()->owner())) {
535+ continue;
536+ }
537+ if (!go->get_garrison()->canAttack()) {
538+ continue;
539+ }
540+ int32_t ta = player->findAttackSoldiers(go->get_building()->base_flag());
541+ if (type == NORMAL)
542+ ta = ta * 2 / 3;
543+ if (ta < 1)
544+ continue;
545+
546+ int32_t const tc = ta - go->get_garrison()->presentSoldiers().size();
547+ if (tc > chance) {
548+ target = go->get_building();
549+ chance = tc;
550+ attackers = ta;
551 }
552 }
553+ }
554
555 // Reenque militarysite at the end of list
556 militarysites.push_back(militarysites.front());
557
558=== modified file 'src/ai/defaultai.h'
559--- src/ai/defaultai.h 2013-07-26 20:19:36 +0000
560+++ src/ai/defaultai.h 2013-08-10 10:53:03 +0000
561@@ -191,7 +191,7 @@
562 int32_t inhibit_road_building;
563 int32_t time_of_last_construction;
564
565- uint16_t numof_warehouses;
566+ uint16_t numof_storages;
567 };
568
569 #endif
570
571=== modified file 'src/economy/economy.cc'
572--- src/economy/economy.cc 2013-07-26 20:19:36 +0000
573+++ src/economy/economy.cc 2013-08-10 10:53:03 +0000
574@@ -27,11 +27,10 @@
575 #include "economy/route.h"
576 #include "economy/routeastar.h"
577 #include "economy/router.h"
578-#include "economy/warehousesupply.h"
579 #include "logic/game.h"
580 #include "logic/player.h"
581+#include "logic/storage.h"
582 #include "logic/tribe.h"
583-#include "logic/warehouse.h"
584 #include "upcast.h"
585 #include "wexception.h"
586
587@@ -78,8 +77,8 @@
588 log("Warning: Economy still has requests left on destruction\n");
589 if (m_flags.size())
590 log("Warning: Economy still has flags left on destruction\n");
591- if (m_warehouses.size())
592- log("Warning: Economy still has warehouses left on destruction\n");
593+ if (m_storages.size())
594+ log("Warning: Economy still has storages left on destruction\n");
595
596 delete[] m_ware_target_quantities;
597 delete[] m_worker_target_quantities;
598@@ -214,22 +213,22 @@
599 };
600
601 /**
602- * Find the warehouse closest to the given starting flag.
603+ * Find the storage owner closest to the given starting flag.
604 *
605 * If the search was successful and \p route is non-null,
606 * a route is also computed.
607 *
608 * \param start starting flag
609 * \param type whether to path-find as if the path were for a ware
610- * \param route if non-null, fill in a route to the warehouse
611+ * \param route if non-null, fill in a route to the storage
612 * \param cost_cutoff if positive, find paths of at most
613 * that length (in milliseconds)
614 */
615-Warehouse * Economy::find_closest_warehouse
616+StorageOwner* Economy::find_closest_storage
617 (Flag & start, WareWorker type, Route * route, uint32_t cost_cutoff,
618- const Economy::WarehouseAcceptFn & acceptfn)
619+ const Economy::StorageAcceptFn & acceptfn)
620 {
621- if (!warehouses().size())
622+ if (!storages().size())
623 return 0;
624
625 // A-star with zero estimator = Dijkstra
626@@ -243,11 +242,11 @@
627 return 0;
628
629 Flag & flag = current->base_flag();
630- if (upcast(Warehouse, warehouse, flag.get_building())) {
631- if (!acceptfn || acceptfn(*warehouse)) {
632+ if (upcast(StorageOwner, storage_owner, flag.get_building())) {
633+ if (!acceptfn || acceptfn(storage_owner)) {
634 if (route)
635 astar.routeto(flag, *route);
636- return warehouse;
637+ return storage_owner;
638 }
639 }
640 }
641@@ -368,7 +367,7 @@
642
643 /**
644 * Call this whenever a ware is destroyed or consumed, e.g. food has been
645- * eaten or a warehouse has been destroyed.
646+ * eaten or a storage has been destroyed.
647 * This is also called when a ware is removed from the economy through trade or
648 * a split of the Economy.
649 */
650@@ -397,32 +396,32 @@
651 }
652
653 /**
654- * Add the warehouse to our list of warehouses.
655- * This also adds the wares in the warehouse to the economy. However, if wares
656- * are added to the warehouse in the future, add_wares() must be called.
657+ * Add the storage to our list of storages.
658+ * This also adds the wares in the storage to the economy. However, if wares
659+ * are added to the storage in the future, add_wares() must be called.
660 */
661-void Economy::add_warehouse(Warehouse & wh)
662+void Economy::add_storage(Storage & storage)
663 {
664- m_warehouses.push_back(&wh);
665+ m_storages.push_back(&storage);
666 }
667
668 /**
669- * Remove the warehouse and its wares from the economy.
670+ * Remove the storage and its wares from the economy.
671 */
672-void Economy::remove_warehouse(Warehouse & wh)
673+void Economy::remove_storage(Storage & storage)
674 {
675- for (size_t i = 0; i < m_warehouses.size(); ++i)
676- if (m_warehouses[i] == &wh) {
677- m_warehouses[i] = *m_warehouses.rbegin();
678- m_warehouses.pop_back();
679+ for (size_t i = 0; i < m_storages.size(); ++i)
680+ if (m_storages[i] == &storage) {
681+ m_storages[i] = *m_storages.rbegin();
682+ m_storages.pop_back();
683 return;
684 }
685
686
687- // This assert was modified, since on loading, warehouses might try to
688+ // This assert was modified, since on loading, storages might try to
689 // remove themselves from their own economy, though they weren't added
690 // (since they weren't initialized)
691- assert(m_warehouses.empty());
692+ assert(m_storages.empty());
693 }
694
695 /**
696@@ -495,8 +494,8 @@
697 bool Economy::needs_ware(Ware_Index const ware_type) const {
698 uint32_t const t = ware_target_quantity(ware_type).permanent;
699 uint32_t quantity = 0;
700- container_iterate_const(std::vector<Warehouse *>, m_warehouses, wh) {
701- quantity += (*wh)->get_wares().stock(ware_type);
702+ container_iterate_const(std::vector<Storage *>, m_storages, storage) {
703+ quantity += (*storage)->get_wares().stock(ware_type);
704 if (t <= quantity)
705 return false;
706 }
707@@ -507,8 +506,8 @@
708 bool Economy::needs_worker(Ware_Index const worker_type) const {
709 uint32_t const t = worker_target_quantity(worker_type).permanent;
710 uint32_t quantity = 0;
711- container_iterate_const(std::vector<Warehouse *>, m_warehouses, wh) {
712- quantity += (*wh)->get_workers().stock(worker_type);
713+ container_iterate_const(std::vector<Storage *>, m_storages, storage) {
714+ quantity += (*storage)->get_workers().stock(worker_type);
715 if (t <= quantity)
716 return false;
717 }
718@@ -796,7 +795,7 @@
719
720 /**
721 * Check whether there is a supply for the given request. If the request is a
722- * worker request without supply, attempt to create a new worker in a warehouse.
723+ * worker request without supply, attempt to create a new worker in a storage.
724 */
725 void Economy::_create_requested_worker(Game & game, Ware_Index index)
726 {
727@@ -820,7 +819,7 @@
728 return;
729
730 // We have worker demand that is not fulfilled by supplies
731- // Find warehouses where we can create the required workers,
732+ // Find storages where we can create the required workers,
733 // and collect stats about existing build prerequisites
734 const Tribe_Descr & tribe = owner().tribe();
735 const Worker_Descr & w_desc = *tribe.get_worker_descr(index);
736@@ -830,20 +829,20 @@
737
738 total_available.insert(total_available.begin(), cost.size(), 0);
739
740- for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
741- Warehouse * wh = m_warehouses[n_wh];
742+ for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
743+ Storage * storage = m_storages[storage_idx];
744
745- uint32_t planned = wh->get_planned_workers(game, index);
746+ uint32_t planned = storage->get_planned_workers(game, index);
747 total_planned += planned;
748
749- while (wh->can_create_worker(game, index)) {
750- wh->create_worker(game, index);
751+ while (storage->can_create_worker(game, index)) {
752+ storage->create_worker(game, index);
753 if (!--demand)
754 return;
755 }
756
757 std::vector<uint32_t> wh_available =
758- wh->calc_available_for_worker(game, index);
759+ storage->calc_available_for_worker(game, index);
760 assert(wh_available.size() == total_available.size());
761
762 for (uint32_t idx = 0; idx < total_available.size(); ++idx)
763@@ -870,25 +869,25 @@
764 // there are supplies for (otherwise, cyclic transportation might happen)
765 // Note that supplies might suddenly disappear outside our control because
766 // of loss of land or silly player actions.
767- for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
768- Warehouse * wh = m_warehouses[n_wh];
769+ for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
770+ Storage * storage = m_storages[storage_idx];
771
772- uint32_t planned = wh->get_planned_workers(game, index);
773+ uint32_t planned = storage->get_planned_workers(game, index);
774 uint32_t reduce = std::min(planned, total_planned - can_create);
775- wh->plan_workers(game, index, planned - reduce);
776+ storage->plan_workers(game, index, planned - reduce);
777 total_planned -= reduce;
778 }
779 } else if (total_planned < demand) {
780 uint32_t plan_goal = std::min(can_create, demand);
781
782- for (uint32_t n_wh = 0; n_wh < warehouses().size(); ++n_wh) {
783- Warehouse * wh = m_warehouses[n_wh];
784+ for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
785+ Storage * storage = m_storages[storage_idx];
786 uint32_t supply =
787- wh->calc_available_for_worker(game, index)[scarcest_idx];
788+ storage->calc_available_for_worker(game, index)[scarcest_idx];
789
790- total_planned -= wh->get_planned_workers(game, index);
791+ total_planned -= storage->get_planned_workers(game, index);
792 uint32_t plan = std::min(supply, plan_goal - total_planned);
793- wh->plan_workers(game, index, plan);
794+ storage->plan_workers(game, index, plan);
795 total_planned += plan;
796 }
797 }
798@@ -896,11 +895,11 @@
799
800 /**
801 * Walk all Requests and find requests of workers than aren't supplied. Then
802- * try to create the worker at warehouses.
803+ * try to create the worker at storages.
804 */
805 void Economy::_create_requested_workers(Game & game)
806 {
807- if (!warehouses().size())
808+ if (!storages().size())
809 return;
810
811 const Tribe_Descr & tribe = owner().tribe();
812@@ -920,23 +919,23 @@
813 /**
814 * Helper function for \ref _handle_active_supplies
815 */
816-static bool accept_warehouse_if_policy
817- (Warehouse & wh, WareWorker type,
818- Ware_Index ware, Warehouse::StockPolicy policy)
819+static bool accept_storage_if_policy
820+ (StorageOwner* storage, WareWorker type,
821+ Ware_Index ware, Storage::StockPolicy policy)
822 {
823- return wh.get_stock_policy(type, ware) == policy;
824+ return storage->get_storage()->get_stock_policy(type, ware) == policy;
825 }
826
827 /**
828 * Send all active supplies (wares that are outside on the road network without
829- * being sent to a specific request) to a warehouse.
830+ * being sent to a specific request) to a storage.
831 */
832 void Economy::_handle_active_supplies(Game & game)
833 {
834- if (!warehouses().size())
835+ if (!storages().size())
836 return;
837
838- typedef std::vector<std::pair<Supply *, Warehouse *> > Assignments;
839+ typedef std::vector<std::pair<Supply *, StorageOwner *> > Assignments;
840 Assignments assignments;
841
842 for (uint32_t idx = 0; idx < m_supplies.get_nrsupplies(); ++idx) {
843@@ -950,38 +949,38 @@
844
845 bool haveprefer = false;
846 bool havenormal = false;
847- for (uint32_t nwh = 0; nwh < m_warehouses.size(); ++nwh) {
848- Warehouse * wh = m_warehouses[nwh];
849- Warehouse::StockPolicy policy = wh->get_stock_policy(type, ware);
850- if (policy == Warehouse::SP_Prefer) {
851+ for (uint32_t storage_idx = 0; storage_idx < m_storages.size(); ++storage_idx) {
852+ Storage * storage = m_storages[storage_idx];
853+ Storage::StockPolicy policy = storage->get_stock_policy(type, ware);
854+ if (policy == Storage::StockPolicy::Prefer) {
855 haveprefer = true;
856 break;
857 }
858- if (policy == Warehouse::SP_Normal)
859+ if (policy == Storage::StockPolicy::Normal)
860 havenormal = true;
861 }
862 if (!havenormal && !haveprefer && type == wwWARE)
863 continue;
864
865- Warehouse * wh = find_closest_warehouse
866+ StorageOwner * storage_owner = find_closest_storage
867 (supply.get_position(game)->base_flag(), type, 0, 0,
868 (!haveprefer && !havenormal)
869 ?
870- WarehouseAcceptFn()
871+ StorageAcceptFn()
872 :
873 boost::bind
874- (&accept_warehouse_if_policy,
875+ (&accept_storage_if_policy,
876 _1, type, ware,
877- haveprefer ? Warehouse::SP_Prefer : Warehouse::SP_Normal));
878+ haveprefer ? Storage::StockPolicy::Prefer : Storage::StockPolicy::Normal));
879
880- if (!wh) {
881+ if (!storage_owner) {
882 log
883 ("Warning: Economy::_handle_active_supplies "
884- "didn't find warehouse\n");
885+ "didn't find storage\n");
886 return;
887 }
888
889- assignments.push_back(std::make_pair(&supply, wh));
890+ assignments.push_back(std::make_pair(&supply, storage_owner));
891 }
892
893 // Actually start with the transfers in a separate second phase,
894@@ -991,10 +990,10 @@
895 ss.Unsigned32(0x02decafa); // appears as facade02 in sync stream
896 ss.Unsigned32(assignments.size());
897
898+ // FIXME CGH check thats working
899 container_iterate_const(Assignments, assignments, it) {
900 ss.Unsigned32(it.current->first->get_position(game)->serial());
901- ss.Unsigned32(it.current->second->serial());
902-
903+ ss.Unsigned32(it.current->second->get_building()->serial());
904 it.current->first->send_to_storage(game, it.current->second);
905 }
906 }
907
908=== modified file 'src/economy/economy.h'
909--- src/economy/economy.h 2013-07-26 20:19:36 +0000
910+++ src/economy/economy.h 2013-08-10 10:53:03 +0000
911@@ -34,12 +34,15 @@
912
913
914 namespace Widelands {
915+
916+class StorageOwner;
917+
918+class Storage;
919 struct Player;
920 struct Game;
921 struct Flag;
922 struct Route;
923 struct RSPairStruct;
924-class Warehouse;
925 struct Request;
926 struct Supply;
927 struct Router;
928@@ -102,11 +105,11 @@
929 WareWorker type,
930 int32_t cost_cutoff = -1);
931
932- typedef boost::function<bool (Warehouse &)> WarehouseAcceptFn;
933- Warehouse * find_closest_warehouse
934+ typedef boost::function<bool (StorageOwner *)> StorageAcceptFn;
935+ StorageOwner * find_closest_storage
936 (Flag & start, WareWorker type = wwWORKER, Route * route = 0,
937 uint32_t cost_cutoff = 0,
938- const WarehouseAcceptFn & acceptfn = WarehouseAcceptFn());
939+ const StorageAcceptFn & acceptfn = StorageAcceptFn());
940
941 std::vector<Flag *>::size_type get_nrflags() const {return m_flags.size();}
942 void add_flag(Flag &);
943@@ -122,9 +125,9 @@
944 void add_workers(Ware_Index, uint32_t count = 1);
945 void remove_workers(Ware_Index, uint32_t count = 1);
946
947- void add_warehouse(Warehouse &);
948- void remove_warehouse(Warehouse &);
949- const std::vector<Warehouse *>& warehouses() const {return m_warehouses;}
950+ void add_storage(Storage &);
951+ void remove_storage(Storage &);
952+ const std::vector<Storage *>& storages() const {return m_storages;}
953
954 void add_request(Request &);
955 void remove_request(Request &);
956@@ -208,7 +211,7 @@
957 Flags m_flags;
958 WareList m_wares; ///< virtual storage with all wares in this Economy
959 WareList m_workers; ///< virtual storage with all workers in this Economy
960- std::vector<Warehouse *> m_warehouses;
961+ std::vector<Storage *> m_storages;
962
963 RequestList m_requests; ///< requests
964 SupplyList m_supplies;
965
966=== modified file 'src/economy/idleworkersupply.cc'
967--- src/economy/idleworkersupply.cc 2013-07-26 20:19:36 +0000
968+++ src/economy/idleworkersupply.cc 2013-08-10 10:53:03 +0000
969@@ -25,8 +25,8 @@
970 #include "logic/player.h"
971 #include "logic/requirements.h"
972 #include "logic/soldier.h"
973+#include "logic/storage.h"
974 #include "logic/tribe.h"
975-#include "logic/warehouse.h"
976 #include "logic/worker.h"
977 #include "wexception.h"
978
979@@ -126,12 +126,12 @@
980 return m_worker;
981 }
982
983-void IdleWorkerSupply::send_to_storage(Game & game, Warehouse * wh)
984+void IdleWorkerSupply::send_to_storage(Game & game, StorageOwner * storage_owner)
985 {
986 assert(!has_storage());
987
988 Transfer * t = new Transfer(game, m_worker);
989- t->set_destination(*wh);
990+ t->set_destination(*storage_owner->get_building());
991 m_worker.start_task_transfer(game, t);
992 }
993
994
995=== modified file 'src/economy/idleworkersupply.h'
996--- src/economy/idleworkersupply.h 2013-07-26 20:19:36 +0000
997+++ src/economy/idleworkersupply.h 2013-08-10 10:53:03 +0000
998@@ -23,6 +23,8 @@
999 #include "economy/supply.h"
1000
1001 namespace Widelands {
1002+
1003+class StorageOwner;
1004 class Worker;
1005 class Economy;
1006
1007@@ -36,7 +38,7 @@
1008 virtual bool is_active() const throw ();
1009 virtual bool has_storage() const throw ();
1010 virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
1011- virtual void send_to_storage(Game &, Warehouse * wh);
1012+ virtual void send_to_storage(Game &, StorageOwner * storage_owner);
1013
1014 virtual uint32_t nr_supplies(const Game &, const Request &) const;
1015 virtual WareInstance & launch_item(Game &, const Request &);
1016
1017=== modified file 'src/economy/portdock.cc'
1018--- src/economy/portdock.cc 2013-07-26 20:19:36 +0000
1019+++ src/economy/portdock.cc 2013-08-10 10:53:03 +0000
1020@@ -488,7 +488,7 @@
1021 // Put all wares from the WaresQueues back into the warehouse
1022 const std::vector<WaresQueue *> & l_expedition_wares = m_warehouse->get_wares_queue_vector();
1023 for (uint8_t i = 0; i < l_expedition_wares.size(); ++i) {
1024- m_warehouse->insert_wares(l_expedition_wares.at(i)->get_ware(), l_expedition_wares.at(i)->get_filled());
1025+ m_warehouse->get_storage()->insert_wares(l_expedition_wares.at(i)->get_ware(), l_expedition_wares.at(i)->get_filled());
1026 l_expedition_wares.at(i)->set_filled(0);
1027 l_expedition_wares.at(i)->set_max_fill(0);
1028 }
1029@@ -501,7 +501,7 @@
1030 } else {
1031 Worker * temp = ew.at(i)->worker;
1032 ew.at(i)->worker = 0;
1033- m_warehouse->incorporate_worker(game, *temp);
1034+ m_warehouse->get_storage()->incorporate_worker(game, *temp);
1035 }
1036 }
1037 // Reset expedition workers list
1038
1039=== modified file 'src/economy/request.cc'
1040--- src/economy/request.cc 2013-07-26 20:19:36 +0000
1041+++ src/economy/request.cc 2013-08-10 10:53:03 +0000
1042@@ -28,8 +28,8 @@
1043 #include "logic/player.h"
1044 #include "logic/productionsite.h"
1045 #include "logic/soldier.h"
1046+#include "logic/storage.h"
1047 #include "logic/tribe.h"
1048-#include "logic/warehouse.h"
1049 #include "logic/worker.h"
1050 #include "map_io/widelands_map_map_object_loader.h"
1051 #include "map_io/widelands_map_map_object_saver.h"
1052@@ -50,22 +50,27 @@
1053 (PlayerImmovable & _target,
1054 Ware_Index const index,
1055 callback_t const cbfn,
1056- WareWorker const w)
1057+ WareWorker const w,
1058+ callback_tranfert_t const transfer_cb)
1059 :
1060 m_type (w),
1061 m_target (_target),
1062 m_target_building (dynamic_cast<Building *>(&_target)),
1063 m_target_productionsite (dynamic_cast<ProductionSite *>(&_target)),
1064- m_target_warehouse (dynamic_cast<Warehouse *>(&_target)),
1065+ m_target_storage (nullptr),
1066 m_target_constructionsite (dynamic_cast<ConstructionSite *>(&_target)),
1067 m_economy (_target.get_economy()),
1068 m_index (index),
1069 m_count (1),
1070 m_callbackfn (cbfn),
1071+ m_transfer_cb (transfer_cb),
1072 m_required_time (_target.owner().egbase().get_gametime()),
1073 m_required_interval(0),
1074 m_last_request_time(m_required_time)
1075 {
1076+ if (upcast(StorageOwner, storage_owner, &_target)) {
1077+ m_target_storage = storage_owner->get_storage();
1078+ }
1079 assert(m_type == wwWARE or m_type == wwWORKER);
1080 if (w == wwWARE and _target.owner().tribe().get_nrwares() <= index)
1081 throw wexception
1082@@ -354,8 +359,8 @@
1083 modifier = m_target_building->get_priority(get_type(), get_index());
1084 if (m_target_constructionsite)
1085 is_construction_site = true;
1086- else if (m_target_warehouse)
1087- // if warehouse calculated a priority use it
1088+ else if (m_target_storage)
1089+ // if storage calculated a priority use it
1090 // else lower priority based on cost
1091 return
1092 modifier != 100 ? modifier :
1093@@ -404,7 +409,7 @@
1094 pri = m_target_building->get_priority(get_type(), get_index());
1095 if (m_target_constructionsite)
1096 return pri + 3;
1097- else if (m_target_warehouse)
1098+ else if (m_target_storage)
1099 return pri - 2;
1100 }
1101 return pri;
1102@@ -486,10 +491,13 @@
1103 Worker & s = supp.launch_worker(game, *this);
1104 ss.Unsigned32(s.serial());
1105 t = new Transfer(game, *this, s);
1106+ if (m_transfer_cb) {
1107+ (*m_transfer_cb)(game, *this, m_index, &s, m_target);
1108+ }
1109 } else {
1110 // Begin the transfer of an item. The item itself is passive.
1111 // launch_item() ensures the WareInstance is transported out of the
1112- // warehouse. Once it's on the flag, the flag code will decide what to
1113+ // storage. Once it's on the flag, the flag code will decide what to
1114 // do with it.
1115 WareInstance & item = supp.launch_item(game, *this);
1116 ss.Unsigned32(item.serial());
1117@@ -533,7 +541,7 @@
1118 *
1119 * Re-open the request.
1120 */
1121-void Request::transfer_fail(Game &, Transfer & t) {
1122+void Request::transfer_fail(Game & game, Transfer & t) {
1123 bool const wasopen = is_open();
1124
1125 t.m_worker = 0;
1126@@ -541,8 +549,12 @@
1127
1128 remove_transfer(find_transfer(t));
1129
1130- if (!wasopen)
1131+ if (!wasopen) {
1132 m_economy->add_request(*this);
1133+ }
1134+ if (m_transfer_cb) {
1135+ m_transfer_cb(game, *this, m_index, nullptr, m_target);
1136+ }
1137 }
1138
1139 /// Cancel the transfer with the given index.
1140
1141=== modified file 'src/economy/request.h'
1142--- src/economy/request.h 2013-07-25 21:05:20 +0000
1143+++ src/economy/request.h 2013-08-10 10:53:03 +0000
1144@@ -20,6 +20,8 @@
1145 #ifndef REQUEST_H
1146 #define REQUEST_H
1147
1148+#include <functional>
1149+
1150 #include "logic/requirements.h"
1151 #include "logic/wareworker.h"
1152 #include "logic/widelands.h"
1153@@ -39,11 +41,11 @@
1154 class RequestList;
1155 struct Requirements;
1156 struct Supply;
1157+class Storage;
1158 struct Transfer;
1159 class Worker;
1160 class Building;
1161 class ProductionSite;
1162-class Warehouse;
1163 class ConstructionSite;
1164
1165 /**
1166@@ -63,8 +65,12 @@
1167
1168 typedef void (*callback_t)
1169 (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
1170+ typedef void (*callback_tranfert_t)
1171+ (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
1172
1173- Request(PlayerImmovable & target, Ware_Index, callback_t, WareWorker);
1174+ Request
1175+ (PlayerImmovable & target, Ware_Index, callback_t, WareWorker,
1176+ callback_tranfert_t transfer_cb = nullptr);
1177 ~Request();
1178
1179 PlayerImmovable & target() const throw () {return m_target;}
1180@@ -120,7 +126,7 @@
1181 // are filled with nulls.
1182 Building * m_target_building;
1183 ProductionSite * m_target_productionsite;
1184- Warehouse * m_target_warehouse;
1185+ Storage * m_target_storage;
1186 ConstructionSite * m_target_constructionsite;
1187
1188 Economy * m_economy;
1189@@ -128,6 +134,7 @@
1190 uint32_t m_count; // how many do we need in total
1191
1192 callback_t m_callbackfn; // called on request success
1193+ callback_tranfert_t m_transfer_cb; // called on worker transfer start/cancel
1194
1195 // when do we need the first ware (can be in the past)
1196 int32_t m_required_time;
1197
1198=== modified file 'src/economy/supply.h'
1199--- src/economy/supply.h 2013-07-26 19:16:51 +0000
1200+++ src/economy/supply.h 2013-08-10 10:53:03 +0000
1201@@ -25,10 +25,12 @@
1202
1203 namespace Widelands {
1204
1205+class StorageOwner;
1206+
1207 struct PlayerImmovable;
1208 struct Game;
1209 struct Request;
1210-class Warehouse;
1211+class StorageOwner;
1212 struct Ware_Index;
1213 class WareInstance;
1214 class Worker;
1215@@ -77,7 +79,7 @@
1216 * Sets up all the required transfers; assumes that \ref has_storage
1217 * returns \c false.
1218 */
1219- virtual void send_to_storage(Game &, Warehouse * wh) = 0;
1220+ virtual void send_to_storage(Game &, StorageOwner * storage_owner) = 0;
1221
1222 /**
1223 * \return the number of items or workers that can be launched right
1224
1225=== modified file 'src/economy/transfer.cc'
1226--- src/economy/transfer.cc 2013-07-26 20:19:36 +0000
1227+++ src/economy/transfer.cc 2013-08-10 10:53:03 +0000
1228@@ -191,6 +191,7 @@
1229 Flag & curflag(m_route.get_flag(m_game, 0));
1230 Flag & nextflag(m_route.get_flag(m_game, 1));
1231 if (!curflag.get_road(nextflag)) {
1232+ //FIXME CGH
1233 upcast(Warehouse, wh, curflag.get_building());
1234 assert(wh);
1235
1236
1237=== modified file 'src/economy/ware_instance.cc'
1238--- src/economy/ware_instance.cc 2013-07-26 20:19:36 +0000
1239+++ src/economy/ware_instance.cc 2013-08-10 10:53:03 +0000
1240@@ -27,8 +27,8 @@
1241 #include "economy/transfer.h"
1242 #include "logic/game.h"
1243 #include "logic/ship.h"
1244+#include "logic/storage.h"
1245 #include "logic/tribe.h"
1246-#include "logic/warehouse.h"
1247 #include "logic/worker.h"
1248 #include "map_io/widelands_map_map_object_loader.h"
1249 #include "map_io/widelands_map_map_object_saver.h"
1250@@ -54,7 +54,7 @@
1251 virtual bool is_active() const throw ();
1252 virtual bool has_storage() const throw ();
1253 virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
1254- virtual void send_to_storage(Game &, Warehouse * wh);
1255+ virtual void send_to_storage(Game &, StorageOwner * wh);
1256
1257 virtual uint32_t nr_supplies(const Game &, const Request &) const;
1258 virtual WareInstance & launch_item(Game &, const Request &);
1259@@ -166,12 +166,12 @@
1260 throw wexception("IdleWareSupply::launch_worker makes no sense");
1261 }
1262
1263-void IdleWareSupply::send_to_storage(Game & game, Warehouse * wh)
1264+void IdleWareSupply::send_to_storage(Game & game, StorageOwner * storage_owner)
1265 {
1266 assert(!has_storage());
1267
1268 Transfer * t = new Transfer(game, m_ware);
1269- t->set_destination(*wh);
1270+ t->set_destination(*storage_owner->get_building());
1271 m_ware.set_transfer(game, *t);
1272 }
1273
1274@@ -290,8 +290,8 @@
1275
1276 /**
1277 * Performs the state updates necessary for the current location:
1278- * - if it's a building, acknowledge the Request or incorporate into warehouse
1279- * - if it's a flag and we have no request, start the return to warehouse timer
1280+ * - if it's a building, acknowledge the Request or incorporate into strage
1281+ * - if it's a flag and we have no request, start the return to storage timer
1282 * and issue a Supply
1283 *
1284 * \note \ref update() may result in the deletion of this object.
1285@@ -405,22 +405,22 @@
1286 return;
1287 }
1288
1289- // There are some situations where we might end up in a warehouse
1290+ // There are some situations where we might end up in a storage
1291 // as part of a requested route, and we need to move out of it
1292 // again, e.g.:
1293 // - we were requested just when we were being carried into the
1294- // warehouse
1295+ // storage
1296 // - we were carried into a harbour/warehouse to be
1297 // shipped across the sea, but a better, land-based route has been
1298 // found
1299- if (upcast(Warehouse, warehouse, &building)) {
1300- warehouse->do_launch_item(game, *this);
1301+ if (upcast(StorageOwner, storage_owner, &building)) {
1302+ storage_owner->get_storage()->do_launch_ware(game, *this);
1303 return;
1304 }
1305
1306 throw wexception
1307 ("MO(%u): ware(%s): do not know how to move from building %u (%s at (%u,%u)) "
1308- "to %u (%s) -> not a warehouse!",
1309+ "to %u (%s) -> not a storage owner!",
1310 serial(), m_descr->name().c_str(), building.serial(),
1311 building.name().c_str(), building.get_position().x,
1312 building.get_position().y, nextstep->serial(),
1313
1314=== removed file 'src/economy/warehousesupply.h'
1315--- src/economy/warehousesupply.h 2013-07-26 20:19:36 +0000
1316+++ src/economy/warehousesupply.h 1970-01-01 00:00:00 +0000
1317@@ -1,76 +0,0 @@
1318-/*
1319- * Copyright (C) 2008-2010 by the Widelands Development Team
1320- *
1321- * This program is free software; you can redistribute it and/or
1322- * modify it under the terms of the GNU General Public License
1323- * as published by the Free Software Foundation; either version 2
1324- * of the License, or (at your option) any later version.
1325- *
1326- * This program is distributed in the hope that it will be useful,
1327- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1328- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1329- * GNU General Public License for more details.
1330- *
1331- * You should have received a copy of the GNU General Public License
1332- * along with this program; if not, write to the Free Software
1333- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1334- *
1335- */
1336-
1337-#ifndef WAREHOUSESUPPLY_H
1338-#define WAREHOUSESUPPLY_H
1339-
1340-#include "logic/warelist.h"
1341-#include "logic/wareworker.h"
1342-#include "economy/supply.h"
1343-
1344-namespace Widelands {
1345-
1346-/*
1347-WarehouseSupply is the implementation of Supply that is used by Warehouses.
1348-It also manages the list of wares in the warehouse.
1349-*/
1350-struct WarehouseSupply : public Supply {
1351- WarehouseSupply(Warehouse * const wh) : m_economy(0), m_warehouse(wh) {}
1352- virtual ~WarehouseSupply();
1353-
1354- void set_economy(Economy *);
1355-
1356- void set_nrworkers(Ware_Index);
1357- void set_nrwares (Ware_Index);
1358-
1359- const WareList & get_wares () const {return m_wares;}
1360- const WareList & get_workers() const {return m_workers;}
1361- uint32_t stock_wares (Ware_Index const i) const {
1362- return m_wares .stock(i);
1363- }
1364- uint32_t stock_workers(Ware_Index const i) const {
1365- return m_workers.stock(i);
1366- }
1367- void add_wares (Ware_Index, uint32_t count);
1368- void remove_wares (Ware_Index, uint32_t count);
1369- void add_workers (Ware_Index, uint32_t count);
1370- void remove_workers(Ware_Index, uint32_t count);
1371-
1372- // Supply implementation
1373- virtual PlayerImmovable * get_position(Game &);
1374- virtual bool is_active() const throw ();
1375- virtual bool has_storage() const throw ();
1376- virtual void get_ware_type(WareWorker & type, Ware_Index & ware) const;
1377-
1378- virtual void send_to_storage(Game &, Warehouse * wh);
1379- virtual uint32_t nr_supplies(const Game &, const Request &) const;
1380- virtual WareInstance & launch_item(Game &, const Request &);
1381- virtual Worker & launch_worker(Game &, const Request &);
1382-
1383-private:
1384- Economy * m_economy;
1385- WareList m_wares;
1386- WareList m_workers; // we use this to keep the soldiers
1387- Warehouse * m_warehouse;
1388-};
1389-
1390-}
1391-
1392-
1393-#endif
1394
1395=== removed file 'src/logic/attackable.h'
1396--- src/logic/attackable.h 2012-02-15 21:25:34 +0000
1397+++ src/logic/attackable.h 1970-01-01 00:00:00 +0000
1398@@ -1,84 +0,0 @@
1399-/*
1400- * Copyright (C) 2008-2009 by the Widelands Development Team
1401- *
1402- * This program is free software; you can redistribute it and/or
1403- * modify it under the terms of the GNU General Public License
1404- * as published by the Free Software Foundation; either version 2
1405- * of the License, or (at your option) any later version.
1406- *
1407- * This program is distributed in the hope that it will be useful,
1408- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1409- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1410- * GNU General Public License for more details.
1411- *
1412- * You should have received a copy of the GNU General Public License
1413- * along with this program; if not, write to the Free Software
1414- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1415- *
1416- */
1417-
1418-#ifndef ATTACKABLE_H
1419-#define ATTACKABLE_H
1420-
1421-namespace Widelands {
1422-
1423-struct Player;
1424-class Soldier;
1425-
1426-enum {
1427- /**
1428- * This is the maximum radius that a military building can protect
1429- * in the sense that an enemy soldier that enters the player's territory
1430- * will call \ref Attackable::aggressor if it is that close.
1431- */
1432- MaxProtectionRadius = 25
1433-};
1434-
1435-/**
1436- * Buildings can implement this interface to indicate that
1437- * they can be attacked.
1438- */
1439-struct Attackable {
1440- /**
1441- * Return the player that owns this attackable.
1442- */
1443- virtual Player & owner() const = 0;
1444-
1445- /**
1446- * Determines whether this building can be attacked right now.
1447- *
1448- * This should only return false for military sites that have not
1449- * been occupied yet.
1450- */
1451- virtual bool canAttack() = 0;
1452-
1453- /**
1454- * Called by an enemy soldier that enters a node with distance
1455- * less than or equal to \ref MaxProtectionRadius from the building.
1456- *
1457- * This allows the building to send protective forces to intercept
1458- * the soldier.
1459- */
1460- virtual void aggressor(Soldier &) = 0;
1461-
1462- /**
1463- * Called by a soldier who is standing on the building's flag
1464- * to attack the building.
1465- *
1466- * The building must send a soldier for defense, and return \c true.
1467- * Otherwise, i.e. if the building cannot defend itself anymore,
1468- * it must destroy itself or turn over to the attacking player,
1469- * and return \c false.
1470- *
1471- * \return \c true if a soldier was launched in defense of the building,
1472- * or \c false if the building cannot defend itself any longer.
1473- */
1474- virtual bool attack(Soldier &) = 0;
1475-
1476-protected:
1477- virtual ~Attackable() {}
1478-};
1479-
1480-}
1481-
1482-#endif
1483
1484=== modified file 'src/logic/building.h'
1485--- src/logic/building.h 2013-08-08 19:55:12 +0000
1486+++ src/logic/building.h 2013-08-10 10:53:03 +0000
1487@@ -258,6 +258,9 @@
1488 void set_defeating_player(Player_Number const player_number) {
1489 m_defeating_player = player_number;
1490 }
1491+ Player_Number get_defeating_player() {
1492+ return m_defeating_player;
1493+ }
1494
1495 void add_worker(Worker &);
1496 void remove_worker(Worker &);
1497
1498=== modified file 'src/logic/findimmovable.cc'
1499--- src/logic/findimmovable.cc 2013-07-26 20:19:36 +0000
1500+++ src/logic/findimmovable.cc 2013-08-10 10:53:03 +0000
1501@@ -20,7 +20,6 @@
1502 #include "logic/findimmovable.h"
1503
1504 #include "economy/flag.h"
1505-#include "logic/attackable.h"
1506 #include "logic/immovable.h"
1507 #include "logic/militarysite.h"
1508 #include "upcast.h"
1509@@ -61,7 +60,8 @@
1510 }
1511
1512 bool FindImmovableAttackable ::accept(const BaseImmovable & imm) const {
1513- return dynamic_cast<Attackable const *>(&imm);
1514+ upcast(const GarrisonOwner, go, &imm);
1515+ return (go && go->get_garrison()->canAttack());
1516 }
1517
1518 bool FindImmovableByDescr::accept(const BaseImmovable & baseimm) const {
1519
1520=== modified file 'src/logic/game.cc'
1521--- src/logic/game.cc 2013-08-07 12:32:36 +0000
1522+++ src/logic/game.cc 2013-08-10 10:53:03 +0000
1523@@ -781,7 +781,8 @@
1524 (get_gametime(), building.owner().player_number(), building));
1525 }
1526
1527-void Game::send_player_militarysite_set_soldier_preference (Building & building, uint8_t my_preference)
1528+void Game::send_player_militarysite_set_soldier_preference
1529+ (Building & building, Garrison::SoldierPref my_preference)
1530 {
1531 send_player_command
1532 (*new Cmd_MilitarySiteSetSoldierPreference
1533
1534=== modified file 'src/logic/game.h'
1535--- src/logic/game.h 2013-08-07 12:32:36 +0000
1536+++ src/logic/game.h 2013-08-10 10:53:03 +0000
1537@@ -22,6 +22,7 @@
1538
1539 #include "logic/cmd_queue.h"
1540 #include "logic/editor_game_base.h"
1541+#include "logic/garrison.h"
1542 #include "md5.h"
1543 #include "random.h"
1544 #include "save_handler.h"
1545@@ -152,7 +153,7 @@
1546 void send_player_build_road (int32_t, Path &);
1547 void send_player_flagaction (Flag &);
1548 void send_player_start_stop_building (Building &);
1549- void send_player_militarysite_set_soldier_preference (Building &, uint8_t preference);
1550+ void send_player_militarysite_set_soldier_preference (Building &, Garrison::SoldierPref preference);
1551 void send_player_start_or_cancel_expedition (Building &);
1552
1553 void send_player_enhance_building (Building &, Building_Index);
1554
1555=== added file 'src/logic/garrison.h'
1556--- src/logic/garrison.h 1970-01-01 00:00:00 +0000
1557+++ src/logic/garrison.h 2013-08-10 10:53:03 +0000
1558@@ -0,0 +1,227 @@
1559+/*
1560+ * Copyright (C) 2008-2009 by the Widelands Development Team
1561+ *
1562+ * This program is free software; you can redistribute it and/or
1563+ * modify it under the terms of the GNU General Public License
1564+ * as published by the Free Software Foundation; either version 2
1565+ * of the License, or (at your option) any later version.
1566+ *
1567+ * This program is distributed in the hope that it will be useful,
1568+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1569+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1570+ * GNU General Public License for more details.
1571+ *
1572+ * You should have received a copy of the GNU General Public License
1573+ * along with this program; if not, write to the Free Software
1574+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1575+ *
1576+ */
1577+
1578+#ifndef GARRISON_H
1579+#define GARRISON_H
1580+
1581+#include <vector>
1582+
1583+#include "logic/widelands.h"
1584+
1585+namespace Widelands {
1586+
1587+class Building;
1588+
1589+
1590+class Building;
1591+class Editor_Game_Base;
1592+class Game;
1593+struct Player;
1594+class Soldier;
1595+
1596+enum {
1597+ /**
1598+ * This is the maximum radius that a military building can protect
1599+ * in the sense that an enemy soldier that enters the player's territory
1600+ * will call \ref Attackable::aggressor if it is that close.
1601+ */
1602+ MaxProtectionRadius = 25
1603+};
1604+/**
1605+ * A garrison represents a bunch of soldiers. Garrisons are owned by GarrisonOwner
1606+ * buildings. This interface provides various methods to deal with soldier control
1607+ * and attacks.
1608+ */
1609+class Garrison {
1610+public:
1611+ enum SoldierPref : uint8_t {
1612+ None,
1613+ Rookies,
1614+ Heroes,
1615+ };
1616+ /**
1617+ * Return the player that owns this attackable.
1618+ */
1619+ virtual Player & owner() const = 0;
1620+
1621+ /**
1622+ * Determines whether this building can be attacked right now.
1623+ *
1624+ * This should only return false for military sites that have not
1625+ * been occupied yet, or by passivve garrison such as training sites.
1626+ */
1627+ virtual bool canAttack() const = 0;
1628+
1629+ /**
1630+ * Called by an enemy soldier that enters a node with distance
1631+ * less than or equal to \ref MaxProtectionRadius from the building.
1632+ *
1633+ * This allows the building to send protective forces to intercept
1634+ * the soldier.
1635+ */
1636+ virtual void aggressor(Soldier &) = 0;
1637+
1638+ /**
1639+ * Called by a soldier who is standing on the building's flag
1640+ * to attack the building.
1641+ *
1642+ * The building must send a soldier for defense, and return \c true.
1643+ * Otherwise, i.e. if the building cannot defend itself anymore,
1644+ * it must destroy itself or turn over to the attacking player,
1645+ * and return \c false.
1646+ *
1647+ * \return \c true if a soldier was launched in defense of the building,
1648+ * or \c false if the building cannot defend itself any longer.
1649+ */
1650+ virtual bool attack(Soldier &) = 0;
1651+
1652+ virtual bool is_passive() = 0;
1653+
1654+ virtual Building& get_building() = 0;
1655+
1656+ /**
1657+ * \return a list of soldiers that are currently present in the building.
1658+ */
1659+ virtual const std::vector<Soldier *> presentSoldiers() const = 0;
1660+
1661+ /**
1662+ * \return a list of soldiers that are currently stationed in the building.
1663+ * That is, all soldiers occupying a slot in the garrison.
1664+ */
1665+ virtual const std::vector<Soldier *> stationedSoldiers() const = 0;
1666+
1667+ /**
1668+ * \return the minimum number of soldiers that this building can be
1669+ * configured to hold.
1670+ */
1671+ virtual uint32_t minSoldierCapacity() const = 0;
1672+
1673+ /**
1674+ * \return the maximum number of soldiers that this building can be
1675+ * configured to hold.
1676+ */
1677+ virtual uint32_t maxSoldierCapacity() const = 0;
1678+
1679+ /**
1680+ * \return the number of soldiers this building is configured to hold
1681+ * right now.
1682+ */
1683+ virtual uint32_t soldierCapacity() const = 0;
1684+
1685+ /**
1686+ * Sets the capacity for soldiers of this building.
1687+ *
1688+ * New soldiers will be requested and old soldiers will be evicted
1689+ * as necessary.
1690+ */
1691+ virtual void setSoldierCapacity(uint32_t capacity) = 0;
1692+ void changeSoldierCapacity(int32_t const difference) {
1693+ uint32_t const old_capacity = soldierCapacity();
1694+ uint32_t const new_capacity =
1695+ std::min
1696+ (static_cast<uint32_t>
1697+ (std::max
1698+ (static_cast<int32_t>(old_capacity) + difference,
1699+ static_cast<int32_t>(minSoldierCapacity()))),
1700+ static_cast<uint32_t>(maxSoldierCapacity()));
1701+ if (old_capacity != new_capacity)
1702+ setSoldierCapacity(new_capacity);
1703+ }
1704+ /**
1705+ * Evict the given soldier from the building immediately,
1706+ * without changing the building's capacity.
1707+ *
1708+ * \note This has no effect if the soldier is currently involved in a battle
1709+ * or otherwise blocked from leaving the building.
1710+ */
1711+ virtual void dropSoldier(Soldier &) = 0;
1712+
1713+ /**
1714+ * Add a new soldier into this site. Returns -1 if there is no space
1715+ * for him, 0 on success
1716+ */
1717+ virtual int incorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
1718+
1719+ /**
1720+ * Remove a soldier from the internal list. Most SoldierControls will be
1721+ * informed by the soldier when it is removed, but WareHouses for example
1722+ * will not.
1723+ */
1724+ virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
1725+
1726+ /**
1727+ * Returns the conquer radius of this garrison
1728+ */
1729+ virtual uint32_t conquerRadius() const = 0;
1730+ /**
1731+ * Set the soldier preference. Heroes or rookies?
1732+ */
1733+ virtual void set_soldier_preference(SoldierPref p) = 0;
1734+ /**
1735+ * \return the current soldier preference
1736+ */
1737+ virtual SoldierPref get_soldier_preference() const = 0;
1738+ /**
1739+ * Try to send the given soldier to attack the fiven target building.
1740+ * This will fail if the soldier already has a job.
1741+ */
1742+ virtual void sendAttacker(Soldier & soldier, Building & target, uint8_t retreat) = 0;
1743+};
1744+
1745+
1746+/**
1747+ * A Garrison owner holds a garrison. This interface is to be implemented by
1748+ * buildings that want to store some soldiers. The GarrionHandler Garrison
1749+ * implementation may be used as the Garrison provider.
1750+ */
1751+class GarrisonOwner {
1752+public:
1753+ /**
1754+ * \return the garrison instance
1755+ */
1756+ virtual Garrison* get_garrison() const = 0;
1757+ /**
1758+ * @return the building owning the garrison
1759+ */
1760+ virtual Building* get_building() = 0;
1761+ /**
1762+ * Called when the garrison has been lost. \param defeating is set to the
1763+ * enemy owner, or this owner if we keep military presence. if \param captured,
1764+ * the enemy captured the building and a new one must be force built.
1765+ *
1766+ * Will not be called by passive garrisons
1767+ */
1768+ virtual void garrison_lost(Game & game, Player_Number defeating, bool captured) = 0;
1769+ /**
1770+ * Called when the garrison is occupied. You may light up the fire now
1771+ *
1772+ * Will not be called by passive garrison
1773+ */
1774+ virtual void garrison_occupied() = 0;
1775+ /**
1776+ * Called on the new site when a site has been conquered
1777+ *
1778+ * Will not be called by passive garrison
1779+ */
1780+ virtual void reinit_after_conqueral(Game & game) = 0;
1781+};
1782+
1783+}
1784+
1785+#endif
1786
1787=== added file 'src/logic/garrisonhandler.cc'
1788--- src/logic/garrisonhandler.cc 1970-01-01 00:00:00 +0000
1789+++ src/logic/garrisonhandler.cc 2013-08-10 10:53:03 +0000
1790@@ -0,0 +1,925 @@
1791+/*
1792+* Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
1793+*
1794+* This program is free software; you can redistribute it and/or
1795+* modify it under the terms of the GNU General Public License
1796+* as published by the Free Software Foundation; either version 2
1797+* of the License, or (at your option) any later version.
1798+*
1799+* This program is distributed in the hope that it will be useful,
1800+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1801+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1802+* GNU General Public License for more details.
1803+*
1804+* You should have received a copy of the GNU General Public License
1805+* along with this program; if not, write to the Free Software
1806+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1807+*
1808+*/
1809+
1810+#include "logic/garrisonhandler.h"
1811+
1812+#include <functional>
1813+#include <memory>
1814+#include <vector>
1815+
1816+#include <boost/foreach.hpp>
1817+#include <boost/format.hpp>
1818+
1819+#include "container_iterate.h"
1820+#include "economy/flag.h"
1821+#include "economy/request.h"
1822+#include "log.h"
1823+#include "logic/building.h"
1824+#include "logic/findbob.h"
1825+#include "logic/instances.h"
1826+#include "logic/militarysite.h"
1827+#include "logic/player.h"
1828+#include "logic/soldier.h"
1829+#include "upcast.h"
1830+
1831+namespace Widelands {
1832+
1833+GarrisonHandler::GarrisonHandler
1834+ (Building& building, uint32_t min_soldiers, uint32_t max_soldiers, uint32_t conquer_radius,
1835+ uint32_t heal_per_second, SoldierPref soldier_pref, bool passive)
1836+: Garrison(),
1837+m_building(building),
1838+m_min_capacity(min_soldiers),
1839+m_max_capacity(max_soldiers),
1840+m_capacity(max_soldiers),
1841+m_passive(passive),
1842+m_heal_per_second(heal_per_second),
1843+m_last_heal_time(0),
1844+m_conquer_radius(conquer_radius),
1845+m_didconquer(false),
1846+m_soldier_preference(soldier_pref),
1847+m_last_swap_soldiers_time(0),
1848+m_try_soldier_upgrade(false),
1849+m_doing_upgrade_request(false)
1850+{
1851+ assert(is_a(GarrisonOwner, &m_building));
1852+}
1853+
1854+GarrisonHandler::~GarrisonHandler()
1855+{
1856+ assert(m_normal_soldier_request.get() == nullptr);
1857+ assert(m_upgrade_soldier_request.get() == nullptr);
1858+}
1859+
1860+void GarrisonHandler::load_finish(Editor_Game_Base& egbase)
1861+{
1862+ // If our soldiers array is empty (old savegame), fill it with soldiers
1863+ // found in building
1864+ if (m_soldiers.empty()) {
1865+ container_iterate_const(std::vector<Worker *>, m_building.get_workers(), i) {
1866+ if (upcast(Soldier, soldier, *i.current)) {
1867+ if (m_soldiers.size() < m_capacity) {
1868+ m_soldiers.push_back(soldier);
1869+ } else {
1870+ break;
1871+ }
1872+ }
1873+ }
1874+ }
1875+}
1876+
1877+void GarrisonHandler::init(Editor_Game_Base & egbase)
1878+{
1879+ // Ensure all soldiers are fresh and give them a new task
1880+ upcast(Game, game, &egbase);
1881+ container_iterate_const(std::vector<Soldier *>, m_soldiers, i) {
1882+ Soldier* soldier = *i.current;
1883+ assert(!soldier->get_state()); // Should be newly created.
1884+ soldier->set_location_initially(m_building);
1885+ if (game) {
1886+ if (m_passive) {
1887+ soldier->start_task_idle(*game, 0, -1);
1888+ } else {
1889+ soldier->start_task_buildingwork(*game);
1890+ }
1891+ }
1892+ }
1893+ // Update requests and timers
1894+ update_soldier_request();
1895+ m_last_heal_time = egbase.get_gametime();
1896+}
1897+
1898+void GarrisonHandler::reinit_after_conqueral(Game& game)
1899+{
1900+ m_soldier_requirements = Requirements();
1901+ conquer_area(game);
1902+ update_soldier_request();
1903+}
1904+
1905+void GarrisonHandler::cleanup(Editor_Game_Base& egbase)
1906+{
1907+ if (m_didconquer && !m_passive) {
1908+ egbase.unconquer_area
1909+ (Player_Area<Area<FCoords> >
1910+ (owner().player_number(),
1911+ Area<FCoords>(egbase.map().get_fcoords(m_building.get_position()), m_conquer_radius)),
1912+ m_building.get_defeating_player());
1913+ }
1914+}
1915+
1916+void GarrisonHandler::cleanup_requests(Editor_Game_Base&)
1917+{
1918+ m_normal_soldier_request.reset();
1919+ m_upgrade_soldier_request.reset();
1920+}
1921+
1922+
1923+int32_t GarrisonHandler::act(Game& game)
1924+{
1925+ const int32_t timeofgame = game.get_gametime();
1926+ int32_t next_act = -1;
1927+ // Ensure requests integrity
1928+ if (m_normal_soldier_request && m_upgrade_soldier_request)
1929+ {
1930+ throw wexception("GarrisonHandler::act: Two soldier requests are ongoing -- should never happen!\n");
1931+ }
1932+ // Update requests periodically
1933+ bool full = stationedSoldiers().size() >= m_capacity;
1934+ if (!full && !m_doing_upgrade_request && !m_normal_soldier_request) {
1935+ // if we miss soldiers
1936+ update_soldier_request();
1937+ } else {
1938+ // If we may issue a new upgrade request
1939+ int32_t time_since_last_swap = (timeofgame - m_last_swap_soldiers_time);
1940+ if (time_since_last_swap > GARRISON_SWAP_TIMEOUT) {
1941+ time_since_last_swap = timeofgame;
1942+ update_soldier_request();
1943+ if (next_act < 0 || next_act > GARRISON_SWAP_TIMEOUT) {
1944+ next_act = GARRISON_SWAP_TIMEOUT;
1945+ }
1946+ }
1947+ }
1948+
1949+ // Calculate the amount of heal point to distribute
1950+ uint32_t to_heal_amount = static_cast<uint32_t>
1951+ ((timeofgame - m_last_heal_time) * m_heal_per_second / 1000);
1952+ const std::vector<Soldier*> soldiers = presentSoldiers();
1953+ BOOST_FOREACH(Soldier* soldier, soldiers) {
1954+ uint32_t to_heal = soldier->get_max_hitpoints() - soldier->get_current_hitpoints();
1955+ if (to_heal > to_heal_amount) to_heal = to_heal_amount;
1956+ if (to_heal > 0) {
1957+ soldier->heal(to_heal);
1958+ to_heal_amount -= to_heal;
1959+ // Act once/s while healing
1960+ if (next_act < 0 || next_act > 1000) {
1961+ next_act = 1000;
1962+ }
1963+ }
1964+ if (to_heal_amount <= 0) break;
1965+ }
1966+ m_last_heal_time = timeofgame;
1967+ // Act once/5s when idle
1968+ if (next_act < 0) {
1969+ next_act = 5000;
1970+ }
1971+ return next_act;
1972+}
1973+
1974+void GarrisonHandler::popSoldier(Soldier* soldier)
1975+{
1976+ // Pop the soldier and update requests
1977+ popSoldierJob(soldier, nullptr, nullptr);
1978+ update_soldier_request();
1979+}
1980+
1981+void GarrisonHandler::set_economy(Economy * const e)
1982+{
1983+ // update requests
1984+ if (m_normal_soldier_request && e)
1985+ m_normal_soldier_request->set_economy(e);
1986+ if (m_upgrade_soldier_request && e)
1987+ m_upgrade_soldier_request->set_economy(e);
1988+}
1989+
1990+
1991+
1992+bool GarrisonHandler::get_garrison_work(Game& game, Soldier* soldier)
1993+{
1994+ // Evict soldiers that have returned home if the capacity is too low
1995+ if (m_capacity < stationedSoldiers().size()) {
1996+ evict_soldier(game, soldier);
1997+ return true;
1998+ }
1999+
2000+ bool stayhome;
2001+ uint8_t retreat;
2002+ if (Map_Object* enemy = popSoldierJob(soldier, &stayhome, &retreat)) {
2003+ if (upcast(Building, building, enemy)) {
2004+ soldier->start_task_attack(game, *building, retreat);
2005+ return true;
2006+ } else if (upcast(Soldier, opponent, enemy)) {
2007+ if (!opponent->getBattle()) {
2008+ soldier->start_task_defense(game, stayhome, retreat);
2009+ if (stayhome)
2010+ opponent->send_signal(game, "sleep");
2011+ return true;
2012+ }
2013+ } else
2014+ throw wexception("GarrisonHandler::get_garrison_work: bad SoldierJob");
2015+ }
2016+ return false;
2017+}
2018+
2019+void GarrisonHandler::set_soldier_requirements(Requirements req)
2020+{
2021+ m_soldier_requirements = req;
2022+}
2023+
2024+//
2025+// Garrison implementation
2026+//
2027+
2028+Player& GarrisonHandler::owner() const
2029+{
2030+ return m_building.owner();
2031+}
2032+
2033+bool GarrisonHandler::canAttack() const
2034+{
2035+ return m_didconquer && !m_passive;
2036+}
2037+
2038+void GarrisonHandler::aggressor(Soldier& enemy)
2039+{
2040+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
2041+ Map & map = game.map();
2042+ // Do not react if enemy is occupied or too far away
2043+ if
2044+ (enemy.get_owner() == &owner() || enemy.getBattle()
2045+ || m_conquer_radius <= map.calc_distance
2046+ (enemy.get_position(), m_building.get_position()))
2047+ {
2048+ return;
2049+ }
2050+
2051+ // Do not react if enemy is at our door
2052+ if
2053+ (map.find_bobs
2054+ (Area<FCoords>(map.get_fcoords(m_building.base_flag().get_position()), 2), 0,
2055+ FindBobEnemySoldier(&owner())))
2056+ {
2057+ return;
2058+ }
2059+
2060+ // Send some soldiers to defend, keeping min capacity inside
2061+ // This will send 1 soldier out to defend each time agressor()
2062+ // is called //FIXME?
2063+ const std::vector<Soldier*>& presents = presentSoldiers();
2064+ if (presents.size() > m_min_capacity) {
2065+ container_iterate_const(std::vector<Soldier *>, presents, i) {
2066+ if (!haveSoldierJob(**i.current)) {
2067+ SoldierJob sj;
2068+ sj.soldier = *i.current;
2069+ sj.enemy = &enemy;
2070+ sj.stayhome = false;
2071+ sj.retreat = owner().get_retreat_percentage();
2072+ m_soldierjobs.push_back(sj);
2073+ (*i.current)->update_task_buildingwork(game);
2074+ return;
2075+ }
2076+ }
2077+ }
2078+
2079+ // Inform the player, that we are under attack by adding a new entry to the
2080+ // message queue - a sound will automatically be played.
2081+ inform_owner(game, InfoType::AGGRESSSED);
2082+}
2083+
2084+bool GarrisonHandler::attack(Soldier& enemy)
2085+{
2086+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
2087+
2088+ const std::vector<Soldier*>& present = presentSoldiers();
2089+ Soldier * defender = 0;
2090+
2091+ if (!present.empty()) {
2092+ // Find soldier with greatest hitpoints
2093+ uint32_t current_max = 0;
2094+ container_iterate_const(std::vector<Soldier *>, present, i) {
2095+ if ((*i.current)->get_current_hitpoints() > current_max) {
2096+ defender = *i.current;
2097+ current_max = defender->get_current_hitpoints();
2098+ }
2099+ }
2100+ } else {
2101+ // If one of our stationed soldiers is currently walking into the
2102+ // building, give us another chance.
2103+ const std::vector<Soldier *>& stationed = stationedSoldiers();
2104+ container_iterate_const(std::vector<Soldier *>, stationed, i) {
2105+ if ((*i.current)->get_position() == m_building.get_position()) {
2106+ defender = *i.current;
2107+ break;
2108+ }
2109+ }
2110+ }
2111+
2112+ if (defender) {
2113+ popSoldierJob(defender); // defense overrides all other jobs
2114+
2115+ SoldierJob sj;
2116+ sj.soldier = defender;
2117+ sj.enemy = &enemy;
2118+ sj.stayhome = true;
2119+ sj.retreat = 0; // Flag defenders could not retreat
2120+ m_soldierjobs.push_back(sj);
2121+
2122+ defender->update_task_buildingwork(game);
2123+
2124+ // Inform the player, that we are under attack by adding a new entry to
2125+ // the message queue - a sound will automatically be played.
2126+ inform_owner(game, InfoType::UNDER_ATTACK);
2127+ return true;
2128+ }
2129+
2130+ // The enemy has defeated our forces, we should inform the player
2131+ // Code for handling change of owner are handled in the garrison
2132+ // owner class.
2133+ upcast(GarrisonOwner, go, &m_building);
2134+ if (military_presence_kept(game)) {
2135+ inform_owner(game, InfoType::GARRISON_LOST);
2136+ go->garrison_lost(game, owner().player_number(), false);
2137+ } else {
2138+ inform_owner(game, InfoType::GARRISON_CAPTURED);
2139+ go->garrison_lost(game, enemy.owner().player_number(), true);
2140+ }
2141+ return false;
2142+}
2143+
2144+bool GarrisonHandler::is_passive()
2145+{
2146+ return m_passive;
2147+}
2148+
2149+Building& GarrisonHandler::get_building()
2150+{
2151+ return m_building;
2152+}
2153+
2154+
2155+
2156+const std::vector< Soldier* > GarrisonHandler::presentSoldiers() const
2157+{
2158+ std::vector<Soldier *> present_soldiers;
2159+ container_iterate_const(std::vector<Soldier*>, m_soldiers, i) {
2160+ if (isPresent(**i.current)) {
2161+ present_soldiers.push_back(*i.current);
2162+ }
2163+ }
2164+ return present_soldiers;
2165+}
2166+
2167+const std::vector< Soldier* > GarrisonHandler::stationedSoldiers() const
2168+{
2169+ return m_soldiers;
2170+}
2171+
2172+uint32_t GarrisonHandler::minSoldierCapacity() const
2173+{
2174+ return m_min_capacity;
2175+}
2176+
2177+uint32_t GarrisonHandler::maxSoldierCapacity() const
2178+{
2179+ return m_max_capacity;
2180+}
2181+
2182+uint32_t GarrisonHandler::soldierCapacity() const
2183+{
2184+ return m_capacity;
2185+}
2186+
2187+void GarrisonHandler::setSoldierCapacity(uint32_t capacity)
2188+{
2189+ assert(minSoldierCapacity() <= capacity);
2190+ assert (capacity <= maxSoldierCapacity());
2191+ assert(m_capacity != capacity);
2192+ m_capacity = capacity;
2193+ update_soldier_request();
2194+}
2195+
2196+void GarrisonHandler::dropSoldier(Soldier& soldier)
2197+{
2198+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
2199+
2200+ if (!isPresent(soldier)) {
2201+ // This can happen when the "drop soldier" player command is delayed
2202+ // by network delay or a client has bugs.
2203+ return;
2204+ }
2205+ // Ensure min capacity is respected
2206+ if (presentSoldiers().size() <= minSoldierCapacity()) {
2207+ return;
2208+ }
2209+ // Drop the soldier and update requests
2210+ evict_soldier(game, &soldier);
2211+ update_soldier_request();
2212+}
2213+
2214+int GarrisonHandler::incorporateSoldier(Editor_Game_Base& egbase, Soldier& s)
2215+{
2216+ // Adjust the soldier location if required.
2217+ if (s.get_location(egbase) != &m_building)
2218+ {
2219+ s.set_location(&m_building);
2220+ }
2221+ m_soldiers.push_back(&s);
2222+
2223+ upcast(Game, game, &egbase);
2224+ // If it's the first soldier, conquer the area
2225+ if (!m_passive && !m_didconquer) {
2226+ conquer_area(egbase);
2227+ if (game) {
2228+ inform_owner(*game, InfoType::GARRISON_OCCUPIED);
2229+ }
2230+ upcast(GarrisonOwner, go, &m_building);
2231+ go->garrison_occupied();
2232+ }
2233+
2234+ // Bind the worker into this house, hide him on the map
2235+ if (game) {
2236+ s.reset_tasks(*game);
2237+ if (m_passive) {
2238+ s.start_task_idle(*game, 0, -1);
2239+ } else {
2240+ s.start_task_buildingwork(*game);
2241+ }
2242+ }
2243+ // Make sure the request count is reduced or the request is deleted.
2244+ update_soldier_request();
2245+ return 0;
2246+}
2247+
2248+int GarrisonHandler::outcorporateSoldier(Editor_Game_Base&, Soldier&)
2249+{
2250+ // not needed
2251+ log("CGH Outcorporate called\n");
2252+ return -1;
2253+}
2254+
2255+uint32_t GarrisonHandler::conquerRadius() const
2256+{
2257+ return m_conquer_radius;
2258+}
2259+
2260+void GarrisonHandler::set_soldier_preference(GarrisonHandler::SoldierPref p)
2261+{
2262+ assert(SoldierPref::Heroes == p || SoldierPref::Rookies == p);
2263+ m_soldier_preference = p;
2264+ update_normal_soldier_request();
2265+}
2266+
2267+
2268+void GarrisonHandler::sendAttacker(Soldier& soldier, Building& target, uint8_t retreat)
2269+{
2270+ assert(isPresent(soldier));
2271+
2272+ if (haveSoldierJob(soldier)) {
2273+ return;
2274+ }
2275+
2276+ SoldierJob sj;
2277+ sj.soldier = &soldier;
2278+ sj.enemy = &target;
2279+ sj.stayhome = false;
2280+ sj.retreat = retreat;
2281+ m_soldierjobs.push_back(sj);
2282+
2283+ soldier.update_task_buildingwork(ref_cast<Game, Editor_Game_Base>(owner().egbase()));
2284+}
2285+
2286+//
2287+// Private helper methods
2288+//
2289+void GarrisonHandler::inform_owner(Game& game, GarrisonHandler::InfoType info)
2290+{
2291+ if (m_passive) {
2292+ return;
2293+ }
2294+ std::string message;
2295+ std::string message_id;
2296+ std::string message_title;
2297+ std::string building_name = m_building.descname();
2298+ switch (info) {
2299+ case InfoType::AGGRESSSED:
2300+ message =
2301+ (boost::format
2302+ (_("Your %s discovered an aggressor")) % building_name)
2303+ .str();
2304+ message_id = "under_attack";
2305+ message_title = _("You are under attack");
2306+ break;
2307+ case InfoType::UNDER_ATTACK:
2308+ message =
2309+ (boost::format
2310+ (_("Your %s is under attack")) % building_name)
2311+ .str();
2312+ message_id = "under_attack";
2313+ message_title = _("You are under attack");
2314+ break;
2315+ case InfoType::GARRISON_LOST:
2316+ message =
2317+ (boost::format
2318+ (_("The enemy defeated your soldiers and destroyed your %s")) % building_name)
2319+ .str();
2320+ message_id = "garrison_lost";
2321+ message_title = _("Garrison lost");
2322+ break;
2323+ case InfoType::GARRISON_CAPTURED:
2324+ message =
2325+ (boost::format
2326+ (_("The enemy defeated your soldiers and captured your %s")) % building_name)
2327+ .str();
2328+ message_id = "garrison_lost";
2329+ message_title = _("Garrison captured");
2330+ break;
2331+ case InfoType::GARRISON_OCCUPIED:
2332+ message =
2333+ (boost::format
2334+ (_("Your soldier occupied your %s")) % building_name)
2335+ .str();
2336+ message_id = "garrison_occupied";
2337+ message_title = _("Garrison occupied");
2338+ break;
2339+ default:
2340+ assert(false);
2341+ }
2342+ m_building.send_message(game, message_id, message_title, message);
2343+}
2344+
2345+bool GarrisonHandler::isPresent(Soldier& soldier) const
2346+{
2347+ if
2348+ (soldier.get_location(owner().egbase()) != &m_building
2349+ || soldier.get_position() != m_building.get_position())
2350+ {
2351+ return false;
2352+ }
2353+ // Present soldiers are working for the garrison only if it is not passive
2354+ if (!m_passive) {
2355+ return
2356+ soldier.get_state() == soldier.get_state(Worker::taskBuildingwork);
2357+ }
2358+ return true;
2359+}
2360+
2361+void GarrisonHandler::conquer_area(Editor_Game_Base& egbase)
2362+{
2363+ assert(!m_didconquer);
2364+ egbase.conquer_area
2365+ (Player_Area<Area<FCoords> >
2366+ (owner().player_number(),
2367+ Area<FCoords>
2368+ (egbase.map().get_fcoords(m_building.get_position()), m_conquer_radius)));
2369+ m_didconquer = true;
2370+}
2371+
2372+bool GarrisonHandler::military_presence_kept(Game& game)
2373+{
2374+ // collect information about immovables in the area
2375+ std::vector<ImmovableFound> immovables;
2376+
2377+ // Search in a radius of 3 (needed for big militarysites)
2378+ FCoords const fc = game.map().get_fcoords(m_building.get_position());
2379+ game.map().find_immovables(Area<FCoords>(fc, 3), &immovables);
2380+
2381+ for (uint32_t i = 0; i < immovables.size(); ++i) {
2382+ upcast(GarrisonOwner, go, immovables[i].object);
2383+ if (!go) {
2384+ continue;
2385+ }
2386+ Garrison* g = go->get_garrison();
2387+ upcast(GarrisonOwner, mygo, &m_building);
2388+ // NOCOM I changed the logic here to check for any stationed soldier
2389+ // and not for m_didconquer. So a msite with all slots empty and soldiers
2390+ // on their way won't keep military presence anymore.
2391+
2392+ // Presence kept if any non-empty garrison with higher conquer radius
2393+ // and owned by our owner is nearby
2394+ if
2395+ (mygo != go
2396+ && owner().player_number() == g->owner().player_number()
2397+ && conquerRadius() < g->conquerRadius()
2398+ && !g->stationedSoldiers().empty())
2399+ {
2400+ return true;
2401+ }
2402+ }
2403+ return false;
2404+}
2405+
2406+//FIXME CGH use a cleaner way without polling required
2407+void GarrisonHandler::update_soldier_request(bool upgraded_in)
2408+{
2409+/*
2410+ * I have update_soldier_request
2411+ * update_upgrade_soldier_request
2412+ * update_normal_soldier_request
2413+ *
2414+ * The first one handles state switching between site fill (normal more)
2415+ * and grabbing soldiers with proper training (upgrade mode). The last
2416+ * two actually make the requests.
2417+ *
2418+ * The input parameter incd is true, if we just incorporated a new soldier
2419+ * as a result of an upgrade request. In such cases, we will re-arm the
2420+ * upgrade request.
2421+ */
2422+ const uint32_t capacity = soldierCapacity();
2423+ const uint32_t stationed = stationedSoldiers().size();
2424+
2425+ if (m_doing_upgrade_request) {
2426+ if (upgraded_in && m_upgrade_soldier_request) {// update requests always ask for one soldier at time!
2427+ m_upgrade_soldier_request.reset();
2428+ }
2429+ if (capacity > stationed) {
2430+ // Somebody is killing my soldiers in the middle of upgrade
2431+ // or I have kicked out his predecessor already.
2432+ if
2433+ ((m_upgrade_soldier_request)
2434+ && (m_upgrade_soldier_request->is_open() || 0 == m_upgrade_soldier_request->get_count()))
2435+ {
2436+ // Economy was not able to find the soldiers I need.
2437+ // I can safely drop the upgrade request and go to fill mode.
2438+ m_upgrade_soldier_request.reset();
2439+ }
2440+ if (!m_upgrade_soldier_request) {
2441+ //phoo -- I can safely request new soldiers.
2442+ m_doing_upgrade_request = false;
2443+ update_normal_soldier_request();
2444+ }
2445+ // else -- ohno please help me! Player is in trouble -- evil grin
2446+ // An upgraded soldier is on his way, but since we only make one request
2447+ // at a time, we have to wait for him to arrive before doing another
2448+ // request to fill capacity.
2449+ //FIXME
2450+ } else if (capacity < stationed) {// player is reducing capacity
2451+ drop_least_suited_soldier();
2452+ } else {// capacity == stationed size
2453+ update_upgrade_soldier_request();
2454+ }
2455+ } else {// not doing upgrade request
2456+ if ((capacity != stationed) or (m_normal_soldier_request)) {
2457+ update_normal_soldier_request();
2458+ }
2459+ if ((capacity == stationed) && (! m_normal_soldier_request) && !m_passive) {
2460+ // Our site is full, we might try to get upgraded soldiers
2461+ // TODO not allowed for passive garrison for now
2462+ if (presentSoldiers().size() == capacity && capacity > m_min_capacity) {
2463+ m_doing_upgrade_request = true;
2464+ }
2465+ }
2466+ }
2467+}
2468+
2469+void GarrisonHandler::update_normal_soldier_request()
2470+{
2471+ // Request new soldiers if needed
2472+ std::vector<Soldier*> soldiers = stationedSoldiers();
2473+ if (soldiers.size() < m_capacity) {
2474+ if (!m_normal_soldier_request) {
2475+ // No ongoing request, fill a new one
2476+ Request* r = new Request
2477+ (m_building, m_building.tribe().safe_worker_index("soldier"),
2478+ GarrisonHandler::request_soldier_callback, wwWORKER);
2479+ r->set_requirements(m_soldier_requirements);
2480+ m_normal_soldier_request.reset(r);
2481+ }
2482+ // Already an ongoing request, update counts
2483+ m_normal_soldier_request->set_count(m_capacity - soldiers.size());
2484+ } else {
2485+ // No new soldier required. Destroy request if there is one
2486+ m_normal_soldier_request.reset();
2487+ }
2488+ // Evict present soldiers if required
2489+ const std::vector<Soldier *>& present = presentSoldiers();
2490+ if (present.size() > m_capacity) {
2491+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
2492+ for (uint32_t i = 0; i < present.size() - m_capacity; ++i) {
2493+ Soldier * soldier = present[i];
2494+ evict_soldier(game, soldier);
2495+ }
2496+ }
2497+}
2498+
2499+void GarrisonHandler::update_upgrade_soldier_request()
2500+{
2501+ bool reqirement_changed = update_upgrade_requirements();
2502+ // Update the requirements
2503+ if (!m_try_soldier_upgrade) {
2504+ return;
2505+ }
2506+ // Do not perform a new request if someone is on his way
2507+ // or if we are going to request the same thing
2508+ if (m_upgrade_soldier_request) {
2509+ if (!m_upgrade_soldier_request->is_open()) {
2510+ // upgraded soldier is on his way
2511+ return;
2512+ }
2513+ if (!reqirement_changed && m_upgrade_soldier_request->get_count() > 0) {
2514+ // Current request is still valid
2515+ return;
2516+ }
2517+ }
2518+ // Issue a new request
2519+ Request* r = new Request
2520+ (m_building, m_building.tribe().safe_worker_index("soldier"),
2521+ GarrisonHandler::request_soldier_callback, wwWORKER,
2522+ GarrisonHandler::request_soldier_transfer_callback);
2523+ // Honor soldier requirements if set by the garrison owner
2524+ RequireAnd upgrade_requirement;
2525+ upgrade_requirement.add(m_soldier_requirements);
2526+ upgrade_requirement.add(m_soldier_upgrade_requirements);
2527+ r->set_requirements(upgrade_requirement);
2528+ r->set_count(1);
2529+ m_upgrade_soldier_request.reset(r);
2530+}
2531+
2532+void GarrisonHandler::request_soldier_callback
2533+ (Game& game, Request&, Ware_Index, Worker* w, PlayerImmovable& pi)
2534+{
2535+ Soldier& s = ref_cast<Soldier, Worker>(*w);
2536+ upcast(GarrisonOwner, go, &pi);
2537+ upcast(GarrisonHandler, gh, go->get_garrison());
2538+
2539+ if (!gh->m_doing_upgrade_request) {
2540+ gh->incorporateSoldier(game, s);
2541+ } else {
2542+ gh->incorporateUpgradedSoldier(game, s);
2543+ }
2544+}
2545+
2546+void GarrisonHandler::request_soldier_transfer_callback
2547+ (Game&, Request&, Ware_Index, Worker* w, PlayerImmovable& pi)
2548+{
2549+ Soldier& s = ref_cast<Soldier, Worker>(*w);
2550+ upcast(GarrisonOwner, go, &pi);
2551+ upcast(GarrisonHandler, gh, go->get_garrison());
2552+
2553+ if (gh->m_doing_upgrade_request) {
2554+ gh->drop_least_suited_soldier(&s);
2555+ }
2556+}
2557+
2558+bool GarrisonHandler::update_upgrade_requirements()
2559+{
2560+ int32_t soldier_upgrade_required_min = m_soldier_upgrade_requirements.getMin();
2561+ int32_t soldier_upgrade_required_max = m_soldier_upgrade_requirements.getMax();
2562+
2563+ if
2564+ (SoldierPref::Heroes != m_soldier_preference
2565+ && SoldierPref::Rookies != m_soldier_preference)
2566+ {
2567+ m_try_soldier_upgrade = false;
2568+ return false;
2569+ }
2570+
2571+ // Find the level of the soldier that is currently least-suited.
2572+ Soldier * worst_guy = find_least_suited_soldier();
2573+ if (worst_guy == nullptr) {
2574+ // There could be no soldier in the militarysite right now. No reason to freak out.
2575+ return false;
2576+ }
2577+ int32_t wg_level = worst_guy->get_level(atrTotal);
2578+
2579+ // Micro-optimization: I assume that the majority of military sites have only level-zero
2580+ // soldiers and prefer rookies. Handle them separately.
2581+ if (m_soldier_preference == SoldierPref::Rookies && wg_level == 0) {
2582+ m_try_soldier_upgrade = false;
2583+ return false;
2584+ }
2585+ m_try_soldier_upgrade = true;
2586+
2587+ // Now I actually build the new requirements.
2588+ int32_t reqmin = SoldierPref::Heroes == m_soldier_preference ? 1 + wg_level : 0;
2589+ int32_t reqmax = SoldierPref::Heroes == m_soldier_preference ? SHRT_MAX : wg_level - 1;
2590+
2591+ bool maxchanged = reqmax != soldier_upgrade_required_max;
2592+ bool minchanged = reqmin != soldier_upgrade_required_min;
2593+
2594+ if (maxchanged or minchanged) {
2595+ m_soldier_upgrade_requirements = RequireAttribute(atrTotal, reqmin, reqmax);
2596+ return true;
2597+ }
2598+ return false;
2599+}
2600+
2601+bool GarrisonHandler::incorporateUpgradedSoldier(Editor_Game_Base& egbase, Soldier& s)
2602+{
2603+ // Call to drop_least routine has side effects: it tries to drop a soldier. Order is important!
2604+ assert(isPresent(s));
2605+ std::vector<Soldier*> stationned = stationedSoldiers();
2606+ if (stationned.size() < m_capacity || drop_least_suited_soldier(&s)) {
2607+ Game & game = ref_cast<Game, Editor_Game_Base>(egbase);
2608+ s.set_location(&m_building);
2609+ m_soldiers.push_back(&s);
2610+ s.reset_tasks(game);
2611+ if (!m_passive) {
2612+ s.start_task_buildingwork(game);
2613+ } else {
2614+ s.start_task_idle(game, 0, -1);
2615+ }
2616+ // Reset timer for new request
2617+ m_upgrade_soldier_request.reset();
2618+ m_last_swap_soldiers_time = game.get_gametime();
2619+ return true;
2620+ }
2621+ return false;
2622+}
2623+
2624+Soldier* GarrisonHandler::find_least_suited_soldier()
2625+{
2626+ const std::vector<Soldier *>& present = presentSoldiers();
2627+ const int32_t multiplier = m_soldier_preference == SoldierPref::Heroes ? -1 : 1;
2628+ int worst_soldier_level = INT_MIN;
2629+ Soldier * worst_soldier = nullptr;
2630+ BOOST_FOREACH(Soldier * sld, present)
2631+ {
2632+ int this_soldier_level = multiplier * static_cast<int> (sld->get_level(atrTotal));
2633+ if (this_soldier_level > worst_soldier_level)
2634+ {
2635+ worst_soldier_level = this_soldier_level;
2636+ worst_soldier = sld;
2637+ }
2638+ }
2639+ return worst_soldier;
2640+}
2641+
2642+bool GarrisonHandler::drop_least_suited_soldier(Soldier* newguy)
2643+{
2644+ const std::vector<Soldier *>& present = presentSoldiers();
2645+ // Don't drop under the minimum capacity if new guy is not here yet
2646+ if (newguy == nullptr && present.size() <= m_min_capacity) {
2647+ return false;
2648+ }
2649+ Soldier * kickoutCandidate = find_least_suited_soldier();
2650+
2651+ // If the arriving guy is worse than worst present, I wont't release.
2652+ if (newguy != nullptr && kickoutCandidate != nullptr) {
2653+ int32_t old_level = kickoutCandidate->get_level(atrTotal);
2654+ int32_t new_level = newguy->get_level(atrTotal);
2655+ if (m_soldier_preference == SoldierPref::Heroes && old_level >= new_level) {
2656+ return false;
2657+ } else if (m_soldier_preference == SoldierPref::Rookies && old_level <= new_level) {
2658+ return false;
2659+ }
2660+ }
2661+
2662+ // Now I know that the new guy is worthy.
2663+ if (kickoutCandidate != nullptr) {
2664+ Game & game = ref_cast<Game, Editor_Game_Base>(owner().egbase());
2665+ evict_soldier(game, kickoutCandidate);
2666+ return true;
2667+ }
2668+ return false;
2669+}
2670+
2671+bool GarrisonHandler::haveSoldierJob(Soldier& soldier) const
2672+{
2673+ container_iterate_const(std::vector<SoldierJob>, m_soldierjobs, i) {
2674+ if (i.current->soldier == &soldier) {
2675+ return true;
2676+ }
2677+ }
2678+ return false;
2679+}
2680+
2681+Map_Object* GarrisonHandler::popSoldierJob(Soldier* soldier, bool* stayhome, uint8_t* retreat)
2682+{
2683+ container_iterate(std::vector<SoldierJob>, m_soldierjobs, i)
2684+ if (i.current->soldier == soldier) {
2685+ Map_Object * const enemy = i.current->enemy.get(owner().egbase());
2686+ if (stayhome)
2687+ *stayhome = i.current->stayhome;
2688+ if (retreat)
2689+ *retreat = i.current->retreat;
2690+ m_soldierjobs.erase(i.current);
2691+ return enemy;
2692+ }
2693+ return 0;
2694+}
2695+
2696+void GarrisonHandler::evict_soldier(Game& game, Soldier* s)
2697+{
2698+ assert(s);
2699+ upcast(StorageOwner, storage_owner, &m_building);
2700+ std::vector<Soldier*>::iterator it;
2701+ for (it = m_soldiers.begin(); it != m_soldiers.end(); ++it) {
2702+ if ((*it)->serial() == s->serial()) {
2703+ m_soldiers.erase(it);
2704+ s->reset_tasks(game);
2705+ if (storage_owner) {
2706+ storage_owner->get_storage()->incorporate_worker(game, *s);
2707+ } else {
2708+ s->start_task_leavebuilding(game, true);
2709+ }
2710+ return;
2711+ }
2712+ }
2713+}
2714+
2715+}
2716
2717=== added file 'src/logic/garrisonhandler.h'
2718--- src/logic/garrisonhandler.h 1970-01-01 00:00:00 +0000
2719+++ src/logic/garrisonhandler.h 2013-08-10 10:53:03 +0000
2720@@ -0,0 +1,262 @@
2721+/*
2722+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
2723+ *
2724+ * This program is free software; you can redistribute it and/or
2725+ * modify it under the terms of the GNU General Public License
2726+ * as published by the Free Software Foundation; either version 2
2727+ * of the License, or (at your option) any later version.
2728+ *
2729+ * This program is distributed in the hope that it will be useful,
2730+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2731+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2732+ * GNU General Public License for more details.
2733+ *
2734+ * You should have received a copy of the GNU General Public License
2735+ * along with this program; if not, write to the Free Software
2736+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2737+ *
2738+ */
2739+
2740+#ifndef GARRISON_HANDLER_H
2741+#define GARRISON_HANDLER_H
2742+
2743+#include "logic/instances.h"
2744+#include "logic/garrison.h"
2745+#include "logic/requirements.h"
2746+#include "logic/worker.h"
2747+
2748+namespace Widelands {
2749+
2750+struct Building;
2751+struct Request;
2752+class Soldier;
2753+
2754+#define GARRISON_SWAP_TIMEOUT 20000
2755+/**
2756+ * Implementation of the Garrison interface to used by GarrisonOwner.
2757+ */
2758+class GarrisonHandler : public Garrison {
2759+friend struct Map_Buildingdata_Data_Packet;
2760+public:
2761+ /**
2762+ * Create a new garrison handler
2763+ * \param building The building that holds this garrison. Must implements GarrisonOwner
2764+ * \param min_soldiers The minimum soldiers to be present in the garrison
2765+ * \param max_soldiers The maximum soldiers that can be present in this garrison
2766+ * \param conquer_radius The radius of the area conqered by this garrison
2767+ * \param heal_per_second The speed at which soldiers will be healed
2768+ * \param soldier_pref The soldier preference for rookies or heroes
2769+ * \param passive A passive garrison is only helpful to keep some soldiers around. It can't
2770+ * attack nor be attacked. I think of training site or ships
2771+ */
2772+ GarrisonHandler
2773+ (Building& building, uint32_t min_soldiers, uint32_t max_soldiers,
2774+ uint32_t conquer_radius, uint32_t heal_per_second, SoldierPref soldier_pref,
2775+ bool passive = false);
2776+ virtual ~GarrisonHandler();
2777+
2778+ void load_finish(Editor_Game_Base &);
2779+ /**
2780+ * Must be called once
2781+ */
2782+ void init(Editor_Game_Base &);
2783+ /**
2784+ * Must be called once after conqueral
2785+ */
2786+ void reinit_after_conqueral(Game & game);
2787+ /**
2788+ * Cleanup handled objects
2789+ */
2790+ void cleanup(Editor_Game_Base &);
2791+ /**
2792+ * Eequests must be cleaned up after the building has
2793+ * been cleaned up, hence this seperate function.
2794+ */
2795+ void cleanup_requests(Editor_Game_Base &);
2796+ /**
2797+ * Must be called regularly. It is not time dependant though.
2798+ * \Return the time when the next act should occur
2799+ */
2800+ int32_t act(Game &);
2801+ /**
2802+ * Must be called when the owner building changes economy
2803+ */
2804+ void set_economy(Economy * const e);
2805+ /**
2806+ * Pop the given soldier out of the building, while keeping it
2807+ * in the garrion.
2808+ */
2809+ void popSoldier(Soldier* soldier);
2810+ /**
2811+ * Get some work for a soldier that asks for it
2812+ */
2813+ bool get_garrison_work(Game & game, Soldier* soldier);
2814+ /**
2815+ * Set the requirements for that soldier. This will be used when filling
2816+ * request for soldiers.
2817+ */
2818+ void set_soldier_requirements(Requirements req);
2819+
2820+ // Garrison implementation
2821+ virtual Player & owner() const;
2822+ virtual bool canAttack() const;
2823+ virtual void aggressor(Soldier &);
2824+ virtual bool attack(Soldier &);
2825+ virtual bool is_passive();
2826+ virtual Building& get_building();
2827+ virtual const std::vector<Soldier *> presentSoldiers() const;
2828+ virtual const std::vector<Soldier *> stationedSoldiers() const;
2829+ virtual uint32_t minSoldierCapacity() const;
2830+ virtual uint32_t maxSoldierCapacity() const;
2831+ virtual uint32_t soldierCapacity() const;
2832+ virtual void setSoldierCapacity(uint32_t capacity);
2833+ virtual void dropSoldier(Soldier &);
2834+ virtual int incorporateSoldier(Editor_Game_Base &, Soldier &);
2835+ virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &);
2836+ virtual uint32_t conquerRadius() const;
2837+ virtual void set_soldier_preference(SoldierPref p);
2838+ virtual SoldierPref get_soldier_preference() const {
2839+ return m_soldier_preference;
2840+ }
2841+ virtual void sendAttacker(Soldier & soldier, Building & target, uint8_t retreat);
2842+
2843+
2844+private:
2845+ enum class InfoType : uint8_t {
2846+ AGGRESSSED,
2847+ UNDER_ATTACK,
2848+ GARRISON_LOST,
2849+ GARRISON_CAPTURED,
2850+ GARRISON_OCCUPIED
2851+ };
2852+ // Helper methods
2853+ /**
2854+ * Sends a message to the owner
2855+ */
2856+ void inform_owner(Game&, InfoType);
2857+ /**
2858+ * Check if a soldier is actually present in building
2859+ */
2860+ bool isPresent(Soldier &) const;
2861+ /**
2862+ * Conquers the area once a soldier occupied the site
2863+ */
2864+ void conquer_area(Editor_Game_Base &);
2865+ /**
2866+ * Check if we keep military influence once our garrison
2867+ * has been conquered
2868+ */
2869+ bool military_presence_kept(Game &);
2870+ /**
2871+ * Update the soldier requests. If upgraded_incorporated, a soldier
2872+ * requested by an upgrade request has just been incorporated. This
2873+ * method handle requesting for normal case (filling slots) or for
2874+ * upgrading to a better suited soldier
2875+ */
2876+ void update_soldier_request(bool upgraded_incorporated = false);
2877+ /**
2878+ * Request new soldiers or evict some to fill the capacity
2879+ */
2880+ void update_normal_soldier_request();
2881+ /* There are two kinds of soldier requests: "normal", which is used whenever the military site needs
2882+ * more soldiers, and "upgrade" which is used when there is a preference for either heroes or
2883+ * rookies.
2884+ *
2885+ * In case of normal requests, the military site is filled. In case of upgrade requests, only one guy
2886+ * is exchanged at a time.
2887+ *
2888+ * There would be more efficient ways to get well trained soldiers. Now, new buildings appearing in battle
2889+ * field are more vulnerable at the beginning. This is intentional. The purpose of this upgrade thing is
2890+ * to reduce the benefits of site micromanagement. The intention is not to make gameplay easier
2891+ * in other ways.
2892+ */
2893+ void update_upgrade_soldier_request();
2894+ /**
2895+ * The callback function, called whenever one of our soldier requested arrived
2896+ */
2897+ static void request_soldier_callback
2898+ (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
2899+ /**
2900+ * The transfer callback function, called whenever one of our requested
2901+ * soldier started to move towards the garrison
2902+ */
2903+ static void request_soldier_transfer_callback
2904+ (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
2905+ /*
2906+ * When upgrading soldiers, we do not ask for just any soldiers, but soldiers
2907+ * that are better than what we already have. This routine sets the requirements
2908+ * used by the request.
2909+ *
2910+ * The routine returns true if upgrade request thresholds have changed. This information could be
2911+ * used to decide whether the soldier-Request should be upgraded. Additionally, the m_try_soldier_upgrade
2912+ * field will be set so to know if an attempt to get better soldier sould be performed.
2913+ */
2914+ bool update_upgrade_requirements();
2915+ /**
2916+ * Called when an upgraded soldier comes to join the garrison
2917+ */
2918+ bool incorporateUpgradedSoldier(Editor_Game_Base & game, Soldier & s);
2919+ /**
2920+ * Find the least suited soldier for this garrison. We don't play
2921+ * in the same league
2922+ */
2923+ Soldier * find_least_suited_soldier();
2924+ /**
2925+ * Try to drop the lease suited soldier, return true on success.
2926+ * If a new soldier s has arrived, extra care will be taken to not drop
2927+ * anyone if the new one is even worst
2928+ */
2929+ bool drop_least_suited_soldier(Soldier * s = nullptr);
2930+ /**
2931+ * Return true if we hold a running job for that soldied
2932+ */
2933+ bool haveSoldierJob(Soldier &) const;
2934+ /**
2935+ * \return the enemy, if any, that the given soldier was scheduled
2936+ * to attack, and remove the job.
2937+ */
2938+ Map_Object * popSoldierJob(Soldier *, bool * stayhome = 0, uint8_t * retreat = 0);
2939+
2940+ void evict_soldier(Game&, Soldier*);
2941+
2942+ // Basic fields
2943+ Building& m_building;
2944+ uint32_t m_min_capacity;
2945+ uint32_t m_max_capacity;
2946+ uint32_t m_capacity;
2947+ bool m_passive;
2948+ std::vector<Soldier*> m_soldiers;
2949+
2950+ // Healing
2951+ uint32_t m_heal_per_second;
2952+ uint32_t m_last_heal_time;
2953+
2954+ // Requests
2955+ Requirements m_soldier_requirements; // This is used to grab a bunch of soldiers: Anything goes
2956+ RequireAttribute m_soldier_upgrade_requirements; // This is used when exchanging soldiers.
2957+ std::unique_ptr<Request> m_normal_soldier_request; // filling the site
2958+ std::unique_ptr<Request> m_upgrade_soldier_request; // seeking for better soldiers
2959+
2960+ // Conqueral
2961+ uint32_t m_conquer_radius;
2962+ bool m_didconquer;
2963+
2964+ // Job
2965+ struct SoldierJob {
2966+ Soldier * soldier;
2967+ Object_Ptr enemy;
2968+ bool stayhome;
2969+ uint8_t retreat;
2970+ };
2971+ std::vector<SoldierJob> m_soldierjobs;
2972+
2973+ // Soldier preferences
2974+ SoldierPref m_soldier_preference;
2975+ uint32_t m_last_swap_soldiers_time;
2976+ bool m_try_soldier_upgrade; // optimization -- if everybody is zero-level, do not downgrade
2977+ bool m_doing_upgrade_request;
2978+};
2979+
2980+}
2981+
2982+#endif
2983
2984=== modified file 'src/logic/item_ware_descr.h'
2985--- src/logic/item_ware_descr.h 2013-07-26 20:19:36 +0000
2986+++ src/logic/item_ware_descr.h 2013-08-10 10:53:03 +0000
2987@@ -41,7 +41,7 @@
2988 namespace Widelands {
2989
2990 /**
2991- * Wares can be stored in warehouses. They can be transferred across an
2992+ * Wares can be stored in storages. They can be transferred across an
2993 * Economy. They can be traded.
2994 * Both items (lumber, stone, ...) and workers are considered wares.
2995 * Every ware has a unique name. Note that an item must not have the same
2996@@ -75,7 +75,7 @@
2997 /// \return ware's localized descriptive text
2998 const std::string & helptext() const throw () {return m_helptext;}
2999
3000- /// How much of the ware type that an economy should store in warehouses.
3001+ /// How much of the ware type that an economy should store in storages.
3002 /// The special value std::numeric_limits<uint32_t>::max() means that the
3003 /// the target quantity of this ware type will never be checked and should
3004 /// not be configurable.
3005
3006=== modified file 'src/logic/militarysite.cc'
3007--- src/logic/militarysite.cc 2013-08-08 19:55:12 +0000
3008+++ src/logic/militarysite.cc 2013-08-10 10:53:03 +0000
3009@@ -21,8 +21,10 @@
3010
3011 #include <clocale>
3012 #include <cstdio>
3013+#include <memory>
3014
3015 #include <boost/foreach.hpp>
3016+#include <boost/format.hpp>
3017 #include <libintl.h>
3018
3019 #include "economy/flag.h"
3020@@ -33,6 +35,7 @@
3021 #include "logic/editor_game_base.h"
3022 #include "logic/findbob.h"
3023 #include "logic/game.h"
3024+#include "logic/garrisonhandler.h"
3025 #include "logic/message_queue.h"
3026 #include "logic/player.h"
3027 #include "logic/soldier.h"
3028@@ -55,13 +58,13 @@
3029 m_num_soldiers (0),
3030 m_heal_per_second (0)
3031 {
3032- m_conquer_radius = global_s.get_safe_int("conquers");
3033- m_num_soldiers = global_s.get_safe_int("max_soldiers");
3034- m_heal_per_second = global_s.get_safe_int("heal_per_second");
3035+ Section& garrison_s = prof.get_safe_section("garrison");
3036+ m_conquer_radius = garrison_s.get_safe_int("conquers");
3037+ m_num_soldiers = garrison_s.get_safe_int("max_soldiers");
3038+ m_heal_per_second = garrison_s.get_safe_int("heal_per_second");
3039 if (m_conquer_radius > 0)
3040 m_workarea_info[m_conquer_radius].insert(descname() + _(" conquer"));
3041- m_prefers_heroes_at_start = global_s.get_safe_bool("prefer_heroes");
3042-
3043+ m_prefers_heroes_at_start = garrison_s.get_safe_bool("prefer_heroes");
3044 }
3045
3046 /**
3047@@ -83,96 +86,45 @@
3048 */
3049
3050 MilitarySite::MilitarySite(const MilitarySite_Descr & ms_descr) :
3051-ProductionSite(ms_descr),
3052-m_didconquer (false),
3053-m_capacity (ms_descr.get_max_number_of_soldiers()),
3054-m_nexthealtime(0),
3055-m_soldier_preference(ms_descr.m_prefers_heroes_at_start ? kPrefersHeroes : kPrefersRookies),
3056-m_soldier_upgrade_try(false)
3057+ProductionSite(ms_descr)
3058 {
3059- m_next_swap_soldiers_time = 0;
3060+ GarrisonHandler* gh = new GarrisonHandler
3061+ (*this, 1,
3062+ descr().get_max_number_of_soldiers(),
3063+ descr().get_conquers(), descr().get_heal_per_second(),
3064+ descr().m_prefers_heroes_at_start ? GarrisonHandler::SoldierPref::Heroes
3065+ : GarrisonHandler::SoldierPref::Rookies);
3066+ m_garrison.reset(gh);
3067 }
3068
3069-
3070 MilitarySite::~MilitarySite()
3071 {
3072- assert(!m_normal_soldier_request);
3073- assert(!m_upgrade_soldier_request);
3074 }
3075
3076-
3077-/**
3078-===============
3079-Display number of soldiers.
3080-===============
3081-*/
3082-std::string MilitarySite::get_statistics_string()
3083+void MilitarySite::load_finish(Editor_Game_Base& egbase)
3084 {
3085- char buffer[255];
3086- std::string str;
3087- uint32_t present = presentSoldiers().size();
3088- uint32_t total = stationedSoldiers().size();
3089-
3090- if (present == total) {
3091- snprintf
3092- (buffer, sizeof(buffer),
3093- ngettext("%u soldier", "%u soldiers", total),
3094- total);
3095- } else {
3096- snprintf
3097- (buffer, sizeof(buffer),
3098- ngettext("%u(+%u) soldier", "%u(+%u) soldiers", total),
3099- present, total - present);
3100- }
3101- str = buffer;
3102-
3103- if (m_capacity > total) {
3104- snprintf(buffer, sizeof(buffer), " (+%u)", m_capacity - total);
3105- str += buffer;
3106- }
3107-
3108- return str;
3109+ Widelands::Building::load_finish(egbase);
3110+ m_garrison->load_finish(egbase);
3111 }
3112
3113-
3114 void MilitarySite::init(Editor_Game_Base & egbase)
3115 {
3116 ProductionSite::init(egbase);
3117-
3118+ m_garrison->init(egbase);
3119 upcast(Game, game, &egbase);
3120
3121 const std::vector<Worker*>& ws = get_workers();
3122- container_iterate_const(std::vector<Worker *>, ws, i)
3123+ container_iterate_const(std::vector<Worker *>, ws, i) {
3124 if (upcast(Soldier, soldier, *i.current)) {
3125 soldier->set_location_initially(*this);
3126- assert(!soldier->get_state()); // Should be newly created.
3127- if (game)
3128- soldier->start_task_buildingwork(*game);
3129+ m_garrison->incorporateSoldier(egbase, *soldier);
3130 }
3131- update_soldier_request();
3132-
3133- // schedule the first healing
3134- m_nexthealtime = egbase.get_gametime() + 1000;
3135- if (game)
3136+ }
3137+ if (game) {
3138 schedule_act(*game, 1000);
3139-}
3140-
3141-
3142-/**
3143-===============
3144-Change the economy for the wares queues.
3145-Note that the workers are dealt with in the PlayerImmovable code.
3146-===============
3147-*/
3148-void MilitarySite::set_economy(Economy * const e)
3149-{
3150- ProductionSite::set_economy(e);
3151-
3152- if (m_normal_soldier_request && e)
3153- m_normal_soldier_request->set_economy(e);
3154- if (m_upgrade_soldier_request && e)
3155- m_upgrade_soldier_request->set_economy(e);
3156-}
3157+ }
3158+}
3159+
3160
3161 /**
3162 ===============
3163@@ -181,16 +133,12 @@
3164 */
3165 void MilitarySite::cleanup(Editor_Game_Base & egbase)
3166 {
3167- // unconquer land
3168- if (m_didconquer)
3169- egbase.unconquer_area
3170- (Player_Area<Area<FCoords> >
3171- (owner().player_number(),
3172- Area<FCoords>
3173- (egbase.map().get_fcoords(get_position()), get_conquers())),
3174- m_defeating_player);
3175-
3176+ // Order matters. Building needed to unconquer, building
3177+ // cleanup will trigger new requests in garrison, garrison
3178+ // cleanup will destroy them
3179+ m_garrison->cleanup(egbase);
3180 ProductionSite::cleanup(egbase);
3181+<<<<<<< TREE
3182
3183 // Note that removing workers during ProductionSite::cleanup can generate
3184 // new requests; that's why we delete it at the end of this function.
3185@@ -538,6 +486,9 @@
3186 // reason, hoping that all stationed soldiers would be present.
3187 }
3188 }
3189+=======
3190+ m_garrison->cleanup_requests(egbase);
3191+>>>>>>> MERGE-SOURCE
3192 }
3193
3194 /*
3195@@ -554,60 +505,53 @@
3196 // Maybe a new queueing system like MilitaryAct could be introduced.
3197
3198 ProductionSite::act(game, data);
3199-
3200- const int32_t timeofgame = game.get_gametime();
3201- if (m_normal_soldier_request && m_upgrade_soldier_request)
3202- {
3203- throw wexception("MilitarySite::act: Two soldier requests are ongoing -- should never happen!\n");
3204- }
3205-
3206- // I do not get a callback when stationed, non-present soldier returns --
3207- // Therefore I must poll in some occasions. Let's do that rather infrequently,
3208- // to keep the game lightweight.
3209-
3210- //TODO: I would need two new callbacks, to get rid ot this polling.
3211- if (timeofgame > m_next_swap_soldiers_time)
3212- {
3213- m_next_swap_soldiers_time = timeofgame + (m_soldier_upgrade_try ? 20000 : 100000);
3214- update_soldier_request();
3215- }
3216-
3217- if (m_nexthealtime <= game.get_gametime()) {
3218- uint32_t total_heal = descr().get_heal_per_second();
3219- std::vector<Soldier *> soldiers = presentSoldiers();
3220-
3221- for (uint32_t i = 0; i < soldiers.size(); ++i) {
3222- Soldier & s = *soldiers[i];
3223-
3224- // The healing algorithm is totally arbitrary
3225- if (s.get_current_hitpoints() < s.get_max_hitpoints()) {
3226- s.heal(total_heal);
3227- break;
3228- }
3229- }
3230-
3231- m_nexthealtime = game.get_gametime() + 1000;
3232- schedule_act(game, 1000);
3233- }
3234-}
3235-
3236-
3237-/**
3238- * The worker is about to be removed.
3239- *
3240- * After the removal of the worker, check whether we need to request
3241- * new soldiers.
3242- */
3243-void MilitarySite::remove_worker(Worker & w)
3244-{
3245- ProductionSite::remove_worker(w);
3246-
3247- if (upcast(Soldier, soldier, &w))
3248- popSoldierJob(soldier, 0, 0);
3249-
3250- update_soldier_request();
3251-}
3252-
3253+ m_garrison->act(game);
3254+ schedule_act(game, 1000);
3255+}
3256+
3257+/**
3258+===============
3259+Display number of soldiers.
3260+===============
3261+*/
3262+std::string MilitarySite::get_statistics_string()
3263+{
3264+ std::string str;
3265+ uint32_t present = m_garrison->presentSoldiers().size();
3266+ uint32_t total = m_garrison->stationedSoldiers().size();
3267+ uint32_t capacity = m_garrison->soldierCapacity();
3268+
3269+ if (present == total) {
3270+ str =
3271+ (boost::format
3272+ (ngettext(_("%u soldier"), _("%u soldiers"), total)) % total)
3273+ .str();
3274+ } else {
3275+ str =
3276+ (boost::format
3277+ (ngettext(_("%u(+%u) soldier"), _("%u(+%u) soldiers"), present))
3278+ % present % (total - present))
3279+ .str();
3280+ }
3281+
3282+ if (capacity > total) {
3283+ str += (boost::format(" (+%u)") % (capacity - total)).str();
3284+ }
3285+
3286+ return str;
3287+}
3288+
3289+/**
3290+===============
3291+Change the economy for the wares queues.
3292+Note that the workers are dealt with in the PlayerImmovable code.
3293+===============
3294+*/
3295+void MilitarySite::set_economy(Economy * const e)
3296+{
3297+ ProductionSite::set_economy(e);
3298+ m_garrison->set_economy(e);
3299+}
3300
3301 /**
3302 * Called by soldiers in the building.
3303@@ -615,41 +559,13 @@
3304 bool MilitarySite::get_building_work(Game & game, Worker & worker, bool)
3305 {
3306 if (upcast(Soldier, soldier, &worker)) {
3307- // Evict soldiers that have returned home if the capacity is too low
3308- if (m_capacity < presentSoldiers().size()) {
3309- worker.reset_tasks(game);
3310- worker.start_task_leavebuilding(game, true);
3311- return true;
3312- }
3313-
3314- bool stayhome;
3315- uint8_t retreat;
3316- if
3317- (Map_Object * const enemy
3318- =
3319- popSoldierJob(soldier, &stayhome, &retreat))
3320- {
3321- if (upcast(Building, building, enemy)) {
3322- soldier->start_task_attack
3323- (game, *building, retreat);
3324- return true;
3325- } else if (upcast(Soldier, opponent, enemy)) {
3326- if (!opponent->getBattle()) {
3327- soldier->start_task_defense
3328- (game, stayhome, retreat);
3329- if (stayhome)
3330- opponent->send_signal(game, "sleep");
3331- return true;
3332- }
3333- } else
3334- throw wexception("MilitarySite::get_building_work: bad SoldierJob");
3335- }
3336+ return m_garrison->get_garrison_work(game, soldier);
3337 }
3338-
3339 return false;
3340 }
3341
3342
3343+<<<<<<< TREE
3344 /**
3345 * \return \c true if the soldier is currently present and idle in the building.
3346 */
3347@@ -885,7 +801,28 @@
3348
3349 // Now we destroy the old building before we place the new one.
3350 set_defeating_player(enemy.owner().player_number());
3351+=======
3352+Garrison* MilitarySite::get_garrison() const
3353+{
3354+ return m_garrison.get();
3355+}
3356+
3357+Building* MilitarySite::get_building()
3358+{
3359+ return this;
3360+}
3361+
3362+void MilitarySite::garrison_occupied()
3363+{
3364+ start_animation(owner().egbase(), descr().get_animation("idle"));
3365+}
3366+
3367+void MilitarySite::garrison_lost(Game& game, Widelands::Player_Number defeating, bool captured)
3368+{
3369+ if (!captured) {
3370+>>>>>>> MERGE-SOURCE
3371 schedule_destroy(game);
3372+<<<<<<< TREE
3373
3374 enemyplayer->force_building(coords, former_buildings);
3375 BaseImmovable * const newimm = game.map()[coords].get_immovable();
3376@@ -907,17 +844,64 @@
3377
3378 return false;
3379 }
3380+=======
3381+ return;
3382+ }
3383+ // The enemy conquers the building
3384+ // In fact we do not conquer it, but place a new building of same type at
3385+ // the old location.
3386+ Player * enemyplayer = game.get_player(defeating);
3387+ const Tribe_Descr & enemytribe = enemyplayer->tribe();
3388+
3389+ // Add suffix to all descr in former buildings in cases
3390+ // the new owner comes from another tribe
3391+ Building_Descr::FormerBuildings former_buildings;
3392+ BOOST_FOREACH(const Building_Descr * old_descr, m_old_buildings) {
3393+ std::string bldname = old_descr->name();
3394+ // Has this building already a suffix? == conquered building?
3395+ std::string::size_type const dot = bldname.rfind('.');
3396+ if (dot >= bldname.size()) {
3397+ // Add suffix, if the new owner uses another tribe than we.
3398+ if (enemytribe.name() != owner().tribe().name())
3399+ bldname += "." + owner().tribe().name();
3400+ } else if (enemytribe.name() == bldname.substr(dot + 1, bldname.size()))
3401+ bldname = bldname.substr(0, dot);
3402+ Building_Index bldi = enemytribe.safe_building_index(bldname.c_str());
3403+ const Building_Descr * former_descr = enemytribe.get_building_descr(bldi);
3404+ former_buildings.push_back(former_descr);
3405+ }
3406+
3407+ const Coords coords = get_position();
3408+ // Now we destroy the old building before we place the new one.
3409+ set_defeating_player(defeating);
3410+ schedule_destroy(game);
3411+
3412+ enemyplayer->force_building(coords, former_buildings);
3413+ BaseImmovable * const newimm = game.map()[coords].get_immovable();
3414+ upcast(GarrisonOwner, go, newimm);
3415+ go->reinit_after_conqueral(game);
3416+
3417+ // Of course we should inform the victorious player as well
3418+ upcast(Building, new_building, newimm);
3419+ std::string message =
3420+ (boost::format
3421+ (_("Your soldiers defeated the enemy at the %s."))
3422+ % new_building->descname())
3423+ .str();
3424+ new_building->send_message
3425+ (game, "site_defeated",
3426+ _("Enemy at site defeated!"),
3427+ message);
3428+>>>>>>> MERGE-SOURCE
3429 }
3430
3431-/// Initialises the militarysite after it was "conquered" (the old was replaced)
3432-void MilitarySite::reinit_after_conqueration(Game & game)
3433+void MilitarySite::reinit_after_conqueral(Game& game)
3434 {
3435- clear_requirements();
3436- conquer_area(game);
3437- update_soldier_request();
3438+ m_garrison->reinit_after_conqueral(game);
3439 start_animation(game, descr().get_animation("idle"));
3440 }
3441
3442+<<<<<<< TREE
3443 /// Calculates whether the military presence is still kept and \returns true if.
3444 bool MilitarySite::military_presence_kept(Game & game)
3445 {
3446@@ -1103,4 +1087,6 @@
3447 m_next_swap_soldiers_time = 0;
3448 }
3449
3450+=======
3451+>>>>>>> MERGE-SOURCE
3452 }
3453
3454=== modified file 'src/logic/militarysite.h'
3455--- src/logic/militarysite.h 2013-07-26 20:19:36 +0000
3456+++ src/logic/militarysite.h 2013-08-10 10:53:03 +0000
3457@@ -20,10 +20,10 @@
3458 #ifndef MILITARYSITE_H
3459 #define MILITARYSITE_H
3460
3461-#include "logic/attackable.h"
3462+#include "logic/garrison.h"
3463+#include "logic/garrisonhandler.h"
3464 #include "logic/productionsite.h"
3465 #include "logic/requirements.h"
3466-#include "logic/soldiercontrol.h"
3467
3468 namespace Widelands {
3469
3470@@ -53,121 +53,39 @@
3471 };
3472
3473 class MilitarySite :
3474- public ProductionSite, public SoldierControl, public Attackable
3475+ public ProductionSite, public GarrisonOwner
3476 {
3477 friend struct Map_Buildingdata_Data_Packet;
3478 MO_DESCR(MilitarySite_Descr);
3479
3480 public:
3481- // I assume elsewhere, that enum SoldierPreference fits to uint8_t.
3482- enum SoldierPreference : uint8_t {
3483- kNoPreference,
3484- kPrefersRookies,
3485- kPrefersHeroes,
3486- };
3487-
3488 MilitarySite(const MilitarySite_Descr &);
3489 virtual ~MilitarySite();
3490
3491- char const * type_name() const throw () {return "militarysite";}
3492- virtual std::string get_statistics_string();
3493-
3494+ void load_finish(Editor_Game_Base &);
3495 virtual void init(Editor_Game_Base &);
3496 virtual void cleanup(Editor_Game_Base &);
3497 virtual void act(Game &, uint32_t data);
3498- virtual void remove_worker(Worker &);
3499+
3500+ char const * type_name() const throw () {return "militarysite";}
3501+ virtual std::string get_statistics_string();
3502
3503 virtual void set_economy(Economy *);
3504 virtual bool get_building_work(Game &, Worker &, bool success);
3505
3506- // Begin implementation of SoldierControl
3507- virtual std::vector<Soldier *> presentSoldiers() const;
3508- virtual std::vector<Soldier *> stationedSoldiers() const;
3509- virtual uint32_t minSoldierCapacity() const throw ();
3510- virtual uint32_t maxSoldierCapacity() const throw ();
3511- virtual uint32_t soldierCapacity() const;
3512- virtual void setSoldierCapacity(uint32_t capacity);
3513- virtual void dropSoldier(Soldier &);
3514- virtual int incorporateSoldier(Editor_Game_Base & game, Soldier & s);
3515- // End implementation of SoldierControl
3516-
3517- // Begin implementation of Attackable
3518- virtual Player & owner() const {return Building::owner();}
3519- virtual bool canAttack();
3520- virtual void aggressor(Soldier &);
3521- virtual bool attack (Soldier &);
3522- // End implementation of Attackable
3523-
3524- /**
3525- * Launch the given soldier on an attack towards the given
3526- * target building.
3527- */
3528- void sendAttacker(Soldier &, Building &, uint8_t);
3529-
3530- /// This methods are helper for use at configure this site.
3531- void set_requirements (const Requirements &);
3532- void clear_requirements();
3533- const Requirements & get_requirements () const {
3534- return m_soldier_requirements;
3535- }
3536-
3537- void reinit_after_conqueration(Game &);
3538-
3539- void update_soldier_request(bool i = false);
3540-
3541- void set_soldier_preference(SoldierPreference);
3542- SoldierPreference get_soldier_preference() const {
3543- return m_soldier_preference;
3544- }
3545+ // GarrisonOwner implementation
3546+ virtual Garrison* get_garrison() const;
3547+ virtual Building* get_building();
3548+ virtual void garrison_occupied();
3549+ virtual void garrison_lost(Game & game, Player_Number defeating, bool captured);
3550+ virtual void reinit_after_conqueral(Game& game);
3551
3552 protected:
3553- void conquer_area(Editor_Game_Base &);
3554-
3555 virtual void create_options_window
3556 (Interactive_GameBase &, UI::Window * & registry);
3557
3558 private:
3559- bool isPresent(Soldier &) const;
3560- static void request_soldier_callback
3561- (Game &, Request &, Ware_Index, Worker *, PlayerImmovable &);
3562-
3563- Map_Object * popSoldierJob
3564- (Soldier *, bool * stayhome = 0, uint8_t * retreat = 0);
3565- bool haveSoldierJob(Soldier &);
3566- bool military_presence_kept(Game &);
3567- void informPlayer(Game &, bool discovered = false);
3568- bool update_upgrade_requirements();
3569- void update_normal_soldier_request();
3570- void update_upgrade_soldier_request();
3571- bool incorporateUpgradedSoldier(Editor_Game_Base & game, Soldier & s);
3572- Soldier * find_least_suited_soldier();
3573- bool drop_least_suited_soldier(bool new_has_arrived, Soldier * s);
3574-
3575-
3576-private:
3577- Requirements m_soldier_requirements; // This is used to grab a bunch of soldiers: Anything goes
3578- RequireAttribute m_soldier_upgrade_requirements; // This is used when exchanging soldiers.
3579- std::unique_ptr<Request> m_normal_soldier_request; // filling the site
3580- std::unique_ptr<Request> m_upgrade_soldier_request; // seeking for better soldiers
3581- bool m_didconquer;
3582- uint32_t m_capacity;
3583-
3584- /**
3585- * Next gametime where we should heal something.
3586- */
3587- int32_t m_nexthealtime;
3588-
3589- struct SoldierJob {
3590- Soldier * soldier;
3591- Object_Ptr enemy;
3592- bool stayhome;
3593- uint8_t retreat;
3594- };
3595- std::vector<SoldierJob> m_soldierjobs;
3596- SoldierPreference m_soldier_preference;
3597- int32_t m_next_swap_soldiers_time;
3598- bool m_soldier_upgrade_try; // optimization -- if everybody is zero-level, do not downgrade
3599- bool m_doing_upgrade_request;
3600+ std::unique_ptr<GarrisonHandler> m_garrison;
3601 };
3602
3603 }
3604
3605=== modified file 'src/logic/player.cc'
3606--- src/logic/player.cc 2013-08-08 20:02:13 +0000
3607+++ src/logic/player.cc 2013-08-10 10:53:03 +0000
3608@@ -38,7 +38,6 @@
3609 #include "logic/militarysite.h"
3610 #include "logic/playercommand.h"
3611 #include "logic/soldier.h"
3612-#include "logic/soldiercontrol.h"
3613 #include "logic/trainingsite.h"
3614 #include "logic/tribe.h"
3615 #include "logic/warehouse.h"
3616@@ -699,12 +698,14 @@
3617
3618 void Player::military_site_set_soldier_preference(PlayerImmovable & imm, uint8_t m_soldier_preference)
3619 {
3620- if (&imm.owner() == this)
3621- if (upcast(MilitarySite, milsite, &imm))
3622- milsite->set_soldier_preference(static_cast<MilitarySite::SoldierPreference>(m_soldier_preference));
3623+ if (&imm.owner() == this) {
3624+ if (upcast(GarrisonOwner, go, &imm)) {
3625+ Garrison* const garrison = go->get_garrison();
3626+ garrison->set_soldier_preference(static_cast<Garrison::SoldierPref>(m_soldier_preference));
3627+ }
3628+ }
3629 }
3630
3631-
3632 /*
3633 * enhance this building, remove it, but give the constructionsite
3634 * an idea of enhancing
3635@@ -867,8 +868,9 @@
3636 return;
3637 if (soldier.get_worker_type() != Worker_Descr::SOLDIER)
3638 return;
3639- if (upcast(SoldierControl, ctrl, &imm))
3640- ctrl->dropSoldier(soldier);
3641+ if (upcast(GarrisonOwner, go, &imm)) {
3642+ go->get_garrison()->dropSoldier(soldier);
3643+ }
3644 }
3645
3646 /*
3647@@ -926,9 +928,10 @@
3648
3649 container_iterate_const(std::vector<BaseImmovable *>, flags, i) {
3650 const Flag * attackerflag = static_cast<Flag *>(*i.current);
3651- const MilitarySite * ms = static_cast<MilitarySite *>(attackerflag->get_building());
3652- std::vector<Soldier *> const present = ms->presentSoldiers();
3653- uint32_t const nr_staying = ms->minSoldierCapacity();
3654+ GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(attackerflag->get_building());
3655+ Garrison * garrison = go->get_garrison();
3656+ std::vector<Soldier *> const present = garrison->presentSoldiers();
3657+ uint32_t const nr_staying = garrison->minSoldierCapacity();
3658 uint32_t const nr_present = present.size();
3659 if (nr_staying < nr_present) {
3660 uint32_t const nr_taken =
3661@@ -964,8 +967,8 @@
3662 log("enemyflagaction: count is 0\n");
3663 else if (is_hostile(flag.owner()))
3664 if (Building * const building = flag.get_building())
3665- if (upcast(Attackable, attackable, building))
3666- if (attackable->canAttack()) {
3667+ if (upcast(GarrisonOwner, go, building))
3668+ if (go->get_garrison()->canAttack()) {
3669 std::vector<Soldier *> attackers;
3670 findAttackSoldiers(flag, &attackers, count);
3671 assert(attackers.size() <= count);
3672@@ -975,10 +978,10 @@
3673 retreat = std::min
3674 (retreat, tribe().get_military_data().get_max_retreat());
3675
3676- container_iterate_const(std::vector<Soldier *>, attackers, i)
3677- ref_cast<MilitarySite, PlayerImmovable>
3678- (*(*i.current)->get_location(egbase()))
3679- .sendAttacker(**i.current, *building, retreat);
3680+ container_iterate_const(std::vector<Soldier *>, attackers, i) {
3681+ upcast(GarrisonOwner, igo, (*i.current)->get_location(egbase()));
3682+ igo->get_garrison()->sendAttacker(**i.current, *building, retreat);
3683+ }
3684 }
3685 }
3686
3687@@ -1177,13 +1180,13 @@
3688
3689 const uint32_t nrecos = get_nr_economies();
3690 for (uint32_t i = 0; i < nrecos; ++i) {
3691- const std::vector<Widelands::Warehouse *> & warehouses =
3692- get_economy_by_number(i)->warehouses();
3693+ const std::vector<Widelands::Storage *> & storages =
3694+ get_economy_by_number(i)->storages();
3695
3696 for
3697- (std::vector<Widelands::Warehouse *>::const_iterator it =
3698- warehouses.begin();
3699- it != warehouses.end();
3700+ (std::vector<Widelands::Storage *>::const_iterator it =
3701+ storages.begin();
3702+ it != storages.end();
3703 ++it)
3704 {
3705 const Widelands::WareList & wares = (*it)->get_wares();
3706
3707=== modified file 'src/logic/player.h'
3708--- src/logic/player.h 2013-08-01 10:51:41 +0000
3709+++ src/logic/player.h 2013-08-10 10:53:03 +0000
3710@@ -638,7 +638,7 @@
3711 std::vector< std::vector<uint32_t> > m_ware_consumptions;
3712
3713 /**
3714- * Statistics of wares stored inside of warehouses over the
3715+ * Statistics of wares stored inside of storages over the
3716 * life of the game, indexed as
3717 * m_ware_stocks[ware_id][time_index]
3718 */
3719
3720=== modified file 'src/logic/playercommand.cc'
3721--- src/logic/playercommand.cc 2013-08-07 12:32:36 +0000
3722+++ src/logic/playercommand.cc 2013-08-10 10:53:03 +0000
3723@@ -525,7 +525,7 @@
3724 PlayerCommand (0, des.Unsigned8())
3725 {
3726 serial = des.Unsigned32();
3727- preference = des.Unsigned8();
3728+ preference = static_cast<Garrison::SoldierPref>(des.Unsigned8());
3729 }
3730
3731 void Cmd_MilitarySiteSetSoldierPreference::serialize (StreamWrite & ser)
3732@@ -533,7 +533,7 @@
3733 ser.Unsigned8 (PLCMD_MILITARYSITESETSOLDIERPREFERENCE);
3734 ser.Unsigned8 (sender());
3735 ser.Unsigned32(serial);
3736- ser.Unsigned8 (preference);
3737+ ser.Unsigned8 (static_cast<uint8_t>(preference));
3738 }
3739
3740 void Cmd_MilitarySiteSetSoldierPreference::execute (Game & game)
3741@@ -554,7 +554,7 @@
3742
3743 // Now serial
3744 const Map_Object & obj = *egbase.objects().get_object(serial);
3745- fw.Unsigned8(preference);
3746+ fw.Unsigned8(static_cast<uint8_t>(preference));
3747 fw.Unsigned32(mos.get_object_file_index(obj));
3748 }
3749
3750@@ -566,7 +566,7 @@
3751 const uint16_t packet_version = fr.Unsigned16();
3752 if (packet_version == PLAYER_CMD_SOLDIERPREFERENCE_VERSION) {
3753 PlayerCommand::Read(fr, egbase, mol);
3754- preference = fr.Unsigned8();
3755+ preference = static_cast<Garrison::SoldierPref>(fr.Unsigned8());
3756 const uint32_t building_serial = fr.Unsigned32();
3757 try {
3758 serial = mol.get<Map_Object>(building_serial).serial();
3759@@ -1724,8 +1724,8 @@
3760 {
3761 if (upcast(Building, building, game.objects().get_object(serial)))
3762 if (&building->owner() == game.get_player(sender()))
3763- if (upcast(SoldierControl, ctrl, building))
3764- ctrl->changeSoldierCapacity(val);
3765+ if (upcast(GarrisonOwner, go, building))
3766+ go->get_garrison()->changeSoldierCapacity(val);
3767 }
3768
3769 void Cmd_ChangeSoldierCapacity::serialize (StreamWrite & ser)
3770@@ -2023,18 +2023,18 @@
3771 /*** struct Cmd_SetStockPolicy ***/
3772 Cmd_SetStockPolicy::Cmd_SetStockPolicy
3773 (int32_t time, Player_Number p,
3774- Warehouse & wh, bool isworker, Ware_Index ware,
3775- Warehouse::StockPolicy policy)
3776+ StorageOwner & storage_owner, bool isworker, Ware_Index ware,
3777+ Storage::StockPolicy policy)
3778 : PlayerCommand(time, p)
3779 {
3780- m_warehouse = wh.serial();
3781+ m_storage_owner = storage_owner.get_building()->serial();
3782 m_isworker = isworker;
3783 m_ware = ware;
3784 m_policy = policy;
3785 }
3786
3787 Cmd_SetStockPolicy::Cmd_SetStockPolicy()
3788-: PlayerCommand(), m_warehouse(0), m_isworker(false), m_policy()
3789+: PlayerCommand(), m_storage_owner(0), m_isworker(false), m_policy()
3790 {
3791 }
3792
3793@@ -2047,20 +2047,20 @@
3794 {
3795 // Sanitize data that could have come from the network
3796 if (Player * plr = game.get_player(sender())) {
3797- if (upcast(Warehouse, warehouse, game.objects().get_object(m_warehouse)))
3798+ if (upcast(StorageOwner, storage_owner, game.objects().get_object(m_storage_owner)))
3799 {
3800- if (&warehouse->owner() != plr) {
3801+ if (&storage_owner->get_building()->owner() != plr) {
3802 log
3803- ("Cmd_SetStockPolicy: sender %u, but warehouse owner %u\n",
3804- sender(), warehouse->owner().player_number());
3805+ ("Cmd_SetStockPolicy: sender %u, but storage owner %u\n",
3806+ sender(), storage_owner->get_building()->owner().player_number());
3807 return;
3808 }
3809
3810 switch (m_policy) {
3811- case Warehouse::SP_Normal:
3812- case Warehouse::SP_Prefer:
3813- case Warehouse::SP_DontStock:
3814- case Warehouse::SP_Remove:
3815+ case Storage::StockPolicy::Normal:
3816+ case Storage::StockPolicy::Prefer:
3817+ case Storage::StockPolicy::DontStock:
3818+ case Storage::StockPolicy::Remove:
3819 break;
3820 default:
3821 log
3822@@ -2069,7 +2069,7 @@
3823 return;
3824 }
3825
3826- const Tribe_Descr & tribe = warehouse->tribe();
3827+ const Tribe_Descr & tribe = storage_owner->get_building()->tribe();
3828 if (m_isworker) {
3829 if (!(m_ware < tribe.get_nrworkers())) {
3830 log
3831@@ -2077,7 +2077,7 @@
3832 sender(), m_ware.value());
3833 return;
3834 }
3835- warehouse->set_worker_policy(m_ware, m_policy);
3836+ storage_owner->get_storage()->set_worker_policy(m_ware, m_policy);
3837 } else {
3838 if (!(m_ware < tribe.get_nrwares())) {
3839 log
3840@@ -2085,7 +2085,7 @@
3841 sender(), m_ware.value());
3842 return;
3843 }
3844- warehouse->set_ware_policy(m_ware, m_policy);
3845+ storage_owner->get_storage()->set_ware_policy(m_ware, m_policy);
3846 }
3847 }
3848 }
3849@@ -2094,20 +2094,20 @@
3850 Cmd_SetStockPolicy::Cmd_SetStockPolicy(StreamRead & des)
3851 : PlayerCommand(0, des.Unsigned8())
3852 {
3853- m_warehouse = des.Unsigned32();
3854+ m_storage_owner = des.Unsigned32();
3855 m_isworker = des.Unsigned8();
3856 m_ware = Ware_Index(des.Unsigned8());
3857- m_policy = static_cast<Warehouse::StockPolicy>(des.Unsigned8());
3858+ m_policy = static_cast<Storage::StockPolicy>(des.Unsigned8());
3859 }
3860
3861 void Cmd_SetStockPolicy::serialize(StreamWrite & ser)
3862 {
3863 ser.Unsigned8(PLCMD_SETSTOCKPOLICY);
3864 ser.Unsigned8(sender());
3865- ser.Unsigned32(m_warehouse);
3866+ ser.Unsigned32(m_storage_owner);
3867 ser.Unsigned8(m_isworker);
3868 ser.Unsigned8(m_ware.value());
3869- ser.Unsigned8(m_policy);
3870+ ser.Unsigned8(static_cast<uint8_t>(m_policy));
3871 }
3872
3873 #define PLAYER_CMD_SETSTOCKPOLICY_VERSION 1
3874@@ -2119,10 +2119,10 @@
3875 if (version != PLAYER_CMD_SETSTOCKPOLICY_VERSION)
3876 throw game_data_error("unknown/unhandled version %u", version);
3877 PlayerCommand::Read(fr, egbase, mol);
3878- m_warehouse = fr.Unsigned32();
3879+ m_storage_owner = fr.Unsigned32();
3880 m_isworker = fr.Unsigned8();
3881 m_ware = Ware_Index(fr.Unsigned8());
3882- m_policy = static_cast<Warehouse::StockPolicy>(fr.Unsigned8());
3883+ m_policy = static_cast<Storage::StockPolicy>(fr.Unsigned8());
3884 } catch (const std::exception & e) {
3885 throw game_data_error("Cmd_SetStockPolicy: %s", e.what());
3886 }
3887@@ -2133,10 +2133,10 @@
3888 {
3889 fw.Unsigned8(PLAYER_CMD_SETSTOCKPOLICY_VERSION);
3890 PlayerCommand::Write(fw, egbase, mos);
3891- fw.Unsigned32(m_warehouse);
3892+ fw.Unsigned32(m_storage_owner);
3893 fw.Unsigned8(m_isworker);
3894 fw.Unsigned8(m_ware.value());
3895- fw.Unsigned8(m_policy);
3896+ fw.Unsigned8(static_cast<uint8_t>(m_policy));
3897 }
3898
3899 }
3900
3901=== modified file 'src/logic/playercommand.h'
3902--- src/logic/playercommand.h 2013-08-05 14:05:21 +0000
3903+++ src/logic/playercommand.h 2013-08-10 10:53:03 +0000
3904@@ -24,8 +24,8 @@
3905 #include "economy/flag.h"
3906 #include "logic/message_id.h"
3907 #include "logic/path.h"
3908+#include "logic/storage.h"
3909 #include "logic/trainingsite.h"
3910-#include "logic/warehouse.h"
3911 #include "logic/worker.h"
3912
3913 namespace Widelands {
3914@@ -196,7 +196,8 @@
3915
3916 struct Cmd_MilitarySiteSetSoldierPreference : public PlayerCommand {
3917 Cmd_MilitarySiteSetSoldierPreference() : PlayerCommand(), serial(0) {} // For savegame loading
3918- Cmd_MilitarySiteSetSoldierPreference (const int32_t t, const Player_Number p, Building & b, uint8_t prefs)
3919+ Cmd_MilitarySiteSetSoldierPreference
3920+ (const int32_t t, const Player_Number p, Building & b, Garrison::SoldierPref prefs)
3921 : PlayerCommand(t, p), serial(b.serial()), preference(prefs)
3922 {}
3923
3924@@ -212,7 +213,7 @@
3925
3926 private:
3927 Serial serial;
3928- uint8_t preference;
3929+ Garrison::SoldierPref preference;
3930 };
3931 struct Cmd_StartOrCancelExpedition : public PlayerCommand {
3932 Cmd_StartOrCancelExpedition() : PlayerCommand() {} // For savegame loading
3933@@ -764,13 +765,13 @@
3934 };
3935
3936 /**
3937- * Command to change the stock policy for a ware or worker in a warehouse.
3938+ * Command to change the stock policy for a ware or worker in a storage.
3939 */
3940 struct Cmd_SetStockPolicy : PlayerCommand {
3941 Cmd_SetStockPolicy
3942 (int32_t time, Player_Number p,
3943- Warehouse & wh, bool isworker, Ware_Index ware,
3944- Warehouse::StockPolicy policy);
3945+ StorageOwner & storage_owner, bool isworker, Ware_Index ware,
3946+ Storage::StockPolicy policy);
3947
3948 virtual uint8_t id() const;
3949
3950@@ -786,10 +787,10 @@
3951 void Read (FileRead &, Editor_Game_Base &, Map_Map_Object_Loader &);
3952
3953 private:
3954- Serial m_warehouse;
3955+ Serial m_storage_owner;
3956 bool m_isworker;
3957 Ware_Index m_ware;
3958- Warehouse::StockPolicy m_policy;
3959+ Storage::StockPolicy m_policy;
3960 };
3961
3962 }
3963
3964=== modified file 'src/logic/production_program.cc'
3965--- src/logic/production_program.cc 2013-08-08 19:55:12 +0000
3966+++ src/logic/production_program.cc 2013-08-10 10:53:03 +0000
3967@@ -32,12 +32,12 @@
3968 #include "logic/findnode.h"
3969 #include "logic/game.h"
3970 #include "logic/game_data_error.h"
3971+#include "logic/garrison.h"
3972 #include "logic/mapregion.h"
3973 #include "logic/message_queue.h"
3974 #include "logic/player.h"
3975 #include "logic/productionsite.h"
3976 #include "logic/soldier.h"
3977-#include "logic/soldiercontrol.h"
3978 #include "logic/trainingsite.h"
3979 #include "logic/tribe.h"
3980 #include "logic/worker_program.h"
3981@@ -1274,8 +1274,13 @@
3982 void ProductionProgram::ActCheck_Soldier::execute
3983 (Game & game, ProductionSite & ps) const
3984 {
3985- SoldierControl & ctrl = dynamic_cast<SoldierControl &>(ps);
3986- const std::vector<Soldier *> soldiers = ctrl.presentSoldiers();
3987+ GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(&ps);
3988+ if (!go) {
3989+ log("CGH no garrison owner for %s %u\n", ps.descr().descname().c_str(), ps.serial());
3990+ return;
3991+ }
3992+ Garrison* ga = go->get_garrison();
3993+ const std::vector<Soldier *> soldiers = ga->presentSoldiers();
3994 const std::vector<Soldier *>::const_iterator soldiers_end = soldiers.end();
3995
3996 ps.molog(" Checking soldier (%u) level %d)\n", attribute, level);
3997@@ -1360,8 +1365,10 @@
3998 void ProductionProgram::ActTrain::execute
3999 (Game & game, ProductionSite & ps) const
4000 {
4001- SoldierControl & ctrl = dynamic_cast<SoldierControl &>(ps);
4002- const std::vector<Soldier *> soldiers = ctrl.presentSoldiers();
4003+ GarrisonOwner * go = dynamic_cast<GarrisonOwner *>(&ps);
4004+ assert(go);
4005+ const Garrison* ga = go->get_garrison();
4006+ const std::vector<Soldier *> soldiers = ga->presentSoldiers();
4007 const std::vector<Soldier *>::const_iterator soldiers_end =
4008 soldiers.end();
4009 std::vector<Soldier *>::const_iterator it = soldiers.begin();
4010
4011=== modified file 'src/logic/productionsite.cc'
4012--- src/logic/productionsite.cc 2013-07-26 20:19:36 +0000
4013+++ src/logic/productionsite.cc 2013-08-10 10:53:03 +0000
4014@@ -113,7 +113,7 @@
4015 } catch (const _wexception & e) {
4016 throw wexception("%s=\"%s\": %s", v->get_name(), v->get_string(), e.what());
4017 }
4018- if (working_positions().empty() and not global_s.has_val("max_soldiers"))
4019+ if (working_positions().empty() and prof.get_section("garrison") == nullptr)
4020 throw wexception("no working/soldier positions");
4021
4022 // Get programs
4023
4024=== modified file 'src/logic/soldier.cc'
4025--- src/logic/soldier.cc 2013-08-07 03:51:32 +0000
4026+++ src/logic/soldier.cc 2013-08-10 10:53:03 +0000
4027@@ -28,7 +28,6 @@
4028 #include "graphic/graphic.h"
4029 #include "graphic/rendertarget.h"
4030 #include "helper.h"
4031-#include "logic/attackable.h"
4032 #include "logic/battle.h"
4033 #include "logic/building.h"
4034 #include "logic/checkstep.h"
4035@@ -38,11 +37,11 @@
4036 #include "logic/findnode.h"
4037 #include "logic/game.h"
4038 #include "logic/game_data_error.h"
4039+#include "logic/garrison.h"
4040 #include "logic/message_queue.h"
4041 #include "logic/militarysite.h"
4042 #include "logic/player.h"
4043 #include "logic/tribe.h"
4044-#include "logic/warehouse.h"
4045 #include "map_io/widelands_map_map_object_loader.h"
4046 #include "map_io/widelands_map_map_object_saver.h"
4047 #include "profile/profile.h"
4048@@ -764,7 +763,11 @@
4049 struct FindNodeOwned {
4050 FindNodeOwned(Player_Number owner) : m_owner(owner)
4051 {};
4052+<<<<<<< TREE
4053 bool accept(const Map&, const FCoords& coords) const {
4054+=======
4055+ bool accept(const Map &, const FCoords & coords) const {
4056+>>>>>>> MERGE-SOURCE
4057 return (coords.field->get_owned_by() == m_owner);
4058 }
4059 private:
4060@@ -789,8 +792,6 @@
4061 void Soldier::start_task_attack
4062 (Game & game, Building & building, uint8_t retreat)
4063 {
4064- //dynamic_cast<const Attackable &>(building);
4065-
4066 push_task(game, taskAttack);
4067 State & state = top_state();
4068 state.objvar1 = &building;
4069@@ -960,13 +961,8 @@
4070
4071 // Count remaining defenders
4072 if (enemy) {
4073- if (upcast(MilitarySite, ms, enemy)) {
4074- defenders = ms->presentSoldiers().size();
4075- }
4076- if (upcast(Warehouse, wh, enemy)) {
4077- Requirements noreq;
4078- defenders = wh->count_workers
4079- (game, wh->tribe().worker_index("soldier"), noreq);
4080+ if (upcast(GarrisonOwner, garrison_owner, enemy)) {
4081+ defenders = garrison_owner->get_garrison()->presentSoldiers().size();
4082 }
4083 // Any enemy soldier at baseflag count as defender.
4084 std::vector<Bob *> soldiers;
4085@@ -996,6 +992,7 @@
4086 BaseImmovable * const newimm = game.map()[state.coords].get_immovable();
4087 upcast(MilitarySite, newsite, newimm);
4088 if (newsite and (&newsite->owner() == &owner())) {
4089+<<<<<<< TREE
4090 if (upcast(SoldierControl, ctrl, newsite)) {
4091 state.objvar1 = 0;
4092 // We may also have our location destroyed in between
4093@@ -1011,6 +1008,20 @@
4094 newsite->update_soldier_request();
4095 return schedule_act(game, 10);
4096 }
4097+=======
4098+ state.objvar1 = 0;
4099+ if
4100+ (newsite->get_garrison()->stationedSoldiers().size()
4101+ < newsite->get_garrison()->soldierCapacity() and
4102+ location->base_flag().get_position()
4103+ !=
4104+ newsite ->base_flag().get_position())
4105+ {
4106+ molog("[attack] enemy belongs to us now, move in\n");
4107+ pop_task(game);
4108+ set_location(newsite);
4109+ return schedule_act(game, 10);
4110+>>>>>>> MERGE-SOURCE
4111 }
4112 }
4113 }
4114@@ -1040,12 +1051,12 @@
4115 }
4116 }
4117
4118- upcast(Attackable, attackable, enemy);
4119- assert(attackable);
4120+ upcast(GarrisonOwner, garrison_o, enemy);
4121+ assert(garrison_o);
4122
4123 molog("[attack] attacking target building\n");
4124 // give the enemy soldier some time to act
4125- schedule_act(game, attackable->attack(*this) ? 1000 : 10);
4126+ schedule_act(game, garrison_o->get_garrison()->attack(*this) ? 1000 : 10);
4127 }
4128
4129 void Soldier::attack_pop(Game & game, State &)
4130@@ -1789,13 +1800,17 @@
4131 CheckStepWalkOn(descr().movecaps(), false),
4132 FindImmovableAttackable());
4133
4134- container_iterate_const(std::vector<BaseImmovable *>, attackables, i)
4135+ container_iterate_const(std::vector<BaseImmovable *>, attackables, i) {
4136+ const BaseImmovable* base_imm = *i.current;
4137 if
4138- (ref_cast<PlayerImmovable const, BaseImmovable const>(**i.current)
4139- .get_owner()->player_number()
4140- ==
4141- land_owner)
4142- dynamic_cast<Attackable &>(**i.current).aggressor(*this);
4143+ (ref_cast<PlayerImmovable const, BaseImmovable const>(*base_imm)
4144+ .get_owner()->player_number() == land_owner)
4145+ {
4146+ if (upcast(const GarrisonOwner, go, base_imm)) {
4147+ go->get_garrison()->aggressor(*this);
4148+ }
4149+ }
4150+ }
4151 }
4152 }
4153
4154
4155=== removed file 'src/logic/soldiercontrol.h'
4156--- src/logic/soldiercontrol.h 2012-02-15 21:25:34 +0000
4157+++ src/logic/soldiercontrol.h 1970-01-01 00:00:00 +0000
4158@@ -1,119 +0,0 @@
4159-/*
4160- * Copyright (C) 2008 by the Widelands Development Team
4161- *
4162- * This program is free software; you can redistribute it and/or
4163- * modify it under the terms of the GNU General Public License
4164- * as published by the Free Software Foundation; either version 2
4165- * of the License, or (at your option) any later version.
4166- *
4167- * This program is distributed in the hope that it will be useful,
4168- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4169- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4170- * GNU General Public License for more details.
4171- *
4172- * You should have received a copy of the GNU General Public License
4173- * along with this program; if not, write to the Free Software
4174- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
4175- *
4176- */
4177-
4178-#ifndef SOLDIERCONTROL_H
4179-#define SOLDIERCONTROL_H
4180-
4181-#include <vector>
4182-
4183-namespace Widelands {
4184-
4185-class Soldier;
4186-
4187-/**
4188- * This interface is implemented by buildings that explicitly house soldiers.
4189- *
4190- * It is used to implement queries for building UI and to implement commands
4191- * that change the soldiers stationed in a building.
4192- *
4193- * Soldiers are \em stationed in a building if that building is their
4194- * \ref Worker::location. Stationed soldiers are \em present in a building
4195- * if their current position is inside the building. So for a TrainingSite,
4196- * the two concepts are equal. However, they're different for a MilitarySite,
4197- * where soldiers can be outside in combat.
4198- */
4199-struct SoldierControl {
4200- /**
4201- * \return a list of soldiers that are currently present in the building.
4202- */
4203- virtual std::vector<Soldier *> presentSoldiers() const = 0;
4204-
4205- /**
4206- * \return a list of soldiers that are currently stationed in the building.
4207- */
4208- virtual std::vector<Soldier *> stationedSoldiers() const = 0;
4209-
4210- /**
4211- * \return the minimum number of soldiers that this building can be
4212- * configured to hold.
4213- */
4214- virtual uint32_t minSoldierCapacity() const = 0;
4215-
4216- /**
4217- * \return the maximum number of soldiers that this building can be
4218- * configured to hold.
4219- */
4220- virtual uint32_t maxSoldierCapacity() const = 0;
4221-
4222- /**
4223- * \return the number of soldiers this building is configured to hold
4224- * right now.
4225- */
4226- virtual uint32_t soldierCapacity() const = 0;
4227-
4228- /**
4229- * Sets the capacity for soldiers of this building.
4230- *
4231- * New soldiers will be requested and old soldiers will be evicted
4232- * as necessary.
4233- */
4234- virtual void setSoldierCapacity(uint32_t capacity) = 0;
4235-
4236- void changeSoldierCapacity(int32_t const difference) {
4237- uint32_t const old_capacity = soldierCapacity();
4238- uint32_t const new_capacity =
4239- std::min
4240- (static_cast<uint32_t>
4241- (std::max
4242- (static_cast<int32_t>(old_capacity) + difference,
4243- static_cast<int32_t>(minSoldierCapacity()))),
4244- maxSoldierCapacity());
4245- if (old_capacity != new_capacity)
4246- setSoldierCapacity(new_capacity);
4247- }
4248-
4249- /**
4250- * Evict the given soldier from the building immediately,
4251- * without changing the building's capacity.
4252- *
4253- * \note This has no effect if the soldier is currently involved in a battle
4254- * or otherwise blocked from leaving the building.
4255- */
4256- virtual void dropSoldier(Soldier &) = 0;
4257-
4258- /**
4259- * Add a new soldier into this site. Returns -1 if there is no space
4260- * for him, 0 on success
4261- */
4262- virtual int incorporateSoldier(Editor_Game_Base &, Soldier &) = 0;
4263-
4264- /**
4265- * Remove a soldier from the internal list. Most SoldierControls will be
4266- * informed by the soldier when it is removed, but WareHouses for example
4267- * will not.
4268- */
4269- virtual int outcorporateSoldier(Editor_Game_Base &, Soldier &) {return 0;}
4270-
4271-protected:
4272- virtual ~SoldierControl() {}
4273-};
4274-
4275-}
4276-
4277-#endif // SOLDIERCONTROL_H
4278
4279=== added file 'src/logic/storage.h'
4280--- src/logic/storage.h 1970-01-01 00:00:00 +0000
4281+++ src/logic/storage.h 2013-08-10 10:53:03 +0000
4282@@ -0,0 +1,195 @@
4283+/*
4284+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
4285+ *
4286+ * This program is free software; you can redistribute it and/or
4287+ * modify it under the terms of the GNU General Public License
4288+ * as published by the Free Software Foundation; either version 2
4289+ * of the License, or (at your option) any later version.
4290+ *
4291+ * This program is distributed in the hope that it will be useful,
4292+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4293+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4294+ * GNU General Public License for more details.
4295+ *
4296+ * You should have received a copy of the GNU General Public License
4297+ * along with this program; if not, write to the Free Software
4298+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
4299+ *
4300+ */
4301+
4302+#ifndef STORAGE_H
4303+#define STORAGE_H
4304+
4305+#include <vector>
4306+
4307+#include "logic/requirements.h"
4308+#include "logic/wareworker.h"
4309+#include "logic/widelands.h"
4310+
4311+namespace Widelands {
4312+
4313+class Building;
4314+class Worker;
4315+class Editor_Game_Base;
4316+class Game;
4317+class WareInstance;
4318+class WareList;
4319+class Player;
4320+
4321+/**
4322+ * A storage represents wares and workers stocks. It is owned by StrorageOwner buildings.
4323+ * This interface contains various method used to deal with wares requests, prioriies
4324+ * and disponibility.
4325+ */
4326+class Storage {
4327+public:
4328+ /**
4329+ * Each ware and worker type has an associated per-storage
4330+ * stock policy that defines whether it will be stocked by this
4331+ * warehouse.
4332+ *
4333+ * \note The values of this enum are written directly into savegames,
4334+ * so be careful when changing them.
4335+ */
4336+ enum class StockPolicy : uint8_t {
4337+ /**
4338+ * The default policy allows stocking wares without any special priority.
4339+ */
4340+ Normal = 0,
4341+
4342+ /**
4343+ * As long as there are warehouses with this policy for a ware, all
4344+ * available unstocked supplies will be transferred to warehouses
4345+ * with this policy.
4346+ */
4347+ Prefer = 1,
4348+
4349+ /**
4350+ * If a ware has this stock policy, no new items of this ware will enter
4351+ * the warehouse.
4352+ */
4353+ DontStock = 2,
4354+
4355+ /**
4356+ * Like \ref SP_DontStock, but in addition, existing stock of this ware
4357+ * will be transported out of the warehouse over time.
4358+ */
4359+ Remove = 3,
4360+ };
4361+
4362+ /**
4363+ * \return the player that own this storage
4364+ */
4365+ virtual Player & owner() const = 0;
4366+ /**
4367+ * \return the wares present in this storage
4368+ */
4369+ virtual const WareList & get_wares() const = 0;
4370+ /**
4371+ * \return the workers present in this storage
4372+ */
4373+ virtual const WareList & get_workers() const = 0;
4374+ /**
4375+ * Increase the stock of the specified ware type
4376+ */
4377+ virtual void insert_wares (Ware_Index, uint32_t count) = 0;
4378+ /**
4379+ * Decrease the stock of the specified ware type
4380+ */
4381+ virtual void remove_wares (Ware_Index, uint32_t count) = 0;
4382+ /**
4383+ * Increase the stock of the specified worker type
4384+ */
4385+ virtual void insert_workers(Ware_Index, uint32_t count) = 0;
4386+ /**
4387+ * Decrease the stock of the specified worker type
4388+ */
4389+ virtual void remove_workers(Ware_Index, uint32_t count) = 0;
4390+ /**
4391+ * Get a specified ware from the storage.
4392+ * \return the wareinstance
4393+ */
4394+ virtual WareInstance & launch_ware(Game &, Ware_Index) = 0;
4395+ /**
4396+ * Launch a ware already instanciated
4397+ */
4398+ virtual void do_launch_ware(Game &, WareInstance&) = 0;
4399+ /**
4400+ * Adds the specified ware to the storage. The ware might
4401+ * be removed from the game following this call.
4402+ */
4403+ virtual void incorporate_ware(Editor_Game_Base &, WareInstance &) = 0;
4404+ /**
4405+ * Get the specified worker from the storage.
4406+ * \return the worker
4407+ */
4408+ virtual Worker & launch_worker(Game &, Ware_Index, const Requirements & = Requirements()) = 0;
4409+ /**
4410+ * Adds the specified worker to the storage. The worker might
4411+ * be removed from the game following this call.
4412+ */
4413+ virtual void incorporate_worker(Editor_Game_Base &, Worker &) = 0;
4414+ /**
4415+ * \return the storage stock policy for the specified ware
4416+ */
4417+ virtual StockPolicy get_ware_policy(Ware_Index ware) const = 0;
4418+ /**
4419+ * \return the storage stock policy for the specified worker
4420+ */
4421+ virtual StockPolicy get_worker_policy(Ware_Index ware) const = 0;
4422+ /**
4423+ * \return the sotrage stock policy for the specified ware or worker
4424+ */
4425+ virtual StockPolicy get_stock_policy(WareWorker waretype, Ware_Index wareindex) const = 0;
4426+ /**
4427+ * Set the storage stock policy for the specified ware
4428+ */
4429+ virtual void set_ware_policy(Ware_Index ware, StockPolicy policy) = 0;
4430+ /**
4431+ * Set the storage stock policy for the specified worker
4432+ */
4433+ virtual void set_worker_policy(Ware_Index ware, StockPolicy policy) = 0;
4434+ /**
4435+ * Return true if the storage has all requirement in stock to create
4436+ * the specified worker
4437+ */
4438+ virtual bool can_create_worker(Game& game, Ware_Index ware_index) = 0;
4439+ /**
4440+ * Create a worker.
4441+ */
4442+ virtual void create_worker(Game& game, Ware_Index worker_idx) = 0;
4443+ /**
4444+ * Return the amount of planned worker of the given worker idx
4445+ */
4446+ virtual uint32_t get_planned_workers(Game &, Ware_Index index) const = 0;
4447+ /**
4448+ * Plan to create the specified workers
4449+ */
4450+ virtual void plan_workers(Game &, Ware_Index index, uint32_t amount) = 0;
4451+ /**
4452+ * Calculate the supply of wares available to this warehouse in each of the
4453+ * buildcost items for the given worker.
4454+ *
4455+ * This is the current stock plus any incoming transfers.
4456+ */
4457+ virtual std::vector<uint32_t> calc_available_for_worker(Game &, Ware_Index index) const = 0;
4458+};
4459+
4460+/**
4461+ * A Storage owner holds a sorage instance.
4462+ */
4463+class StorageOwner {
4464+public:
4465+ /**
4466+ * Return the storage instance
4467+ */
4468+ virtual Storage* get_storage() const = 0;
4469+ /**
4470+ * Return the building owning the storage
4471+ */
4472+ virtual Building* get_building() = 0;
4473+};
4474+
4475+}
4476+
4477+#endif
4478
4479=== added file 'src/logic/storagehandler.cc'
4480--- src/logic/storagehandler.cc 1970-01-01 00:00:00 +0000
4481+++ src/logic/storagehandler.cc 2013-08-10 10:53:03 +0000
4482@@ -0,0 +1,1127 @@
4483+/*
4484+ * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
4485+ *
4486+ * This program is free software; you can redistribute it and/or
4487+ * modify it under the terms of the GNU General Public License
4488+ * as published by the Free Software Foundation; either version 2
4489+ * of the License, or (at your option) any later version.
4490+ *
4491+ * This program is distributed in the hope that it will be useful,
4492+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4493+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4494+ * GNU General Public License for more details.
4495+ *
4496+ * You should have received a copy of the GNU General Public License
4497+ * along with this program; if not, write to the Free Software
4498+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
4499+ *
4500+ */
4501+
4502+#include "logic/storagehandler.h"
4503+
4504+#include <utility>
4505+
4506+#include <boost/foreach.hpp>
4507+
4508+#include "economy/economy.h"
4509+#include "economy/flag.h"
4510+#include "helper.h"
4511+#include "logic/player.h"
4512+#include "logic/soldier.h"
4513+#include "upcast.h"
4514+
4515+namespace Widelands {
4516+
4517+//************************************************************
4518+// CLASS Storage Handler
4519+//************************************************************
4520+
4521+StorageHandler::StorageHandler(Building& building)
4522+: m_building(building),
4523+ m_supply(new StorageSupply(this))
4524+{
4525+}
4526+
4527+StorageHandler::~StorageHandler()
4528+{
4529+}
4530+
4531+
4532+void StorageHandler::init(Editor_Game_Base&)
4533+{
4534+ Ware_Index const nr_wares = owner().tribe().get_nrwares ();
4535+ Ware_Index const nr_workers = owner().tribe().get_nrworkers();
4536+ m_supply->set_nrwares (nr_wares);
4537+ m_supply->set_nrworkers(nr_workers);
4538+ m_ware_policy.resize(nr_wares.value(), Storage::StockPolicy::Normal);
4539+ m_worker_policy.resize(nr_workers.value(), Storage::StockPolicy::Normal);
4540+
4541+ // Init autospawn
4542+ const std::vector <Widelands::Ware_Index> worker_types_without_cost =
4543+ owner().tribe().worker_types_without_cost();
4544+ BOOST_FOREACH(Ware_Index idx, worker_types_without_cost) {
4545+ const Worker_Descr & worker_descr = *owner().tribe().get_worker_descr(idx);
4546+ if (not worker_descr.is_buildable()) {
4547+ continue;
4548+ }
4549+ if (!owner().is_worker_type_allowed(idx)) {
4550+ continue;
4551+ }
4552+ if (worker_descr.buildcost().empty()) {
4553+ // Workers of this type can be spawned in warehouses. Start it.
4554+ add_worker_spawn(idx);
4555+ }
4556+ }
4557+}
4558+
4559+void StorageHandler::load_finish(Editor_Game_Base&)
4560+{
4561+ // Ensure consistency of PlannedWorker requests
4562+ uint32_t pwidx = 0;
4563+ while (pwidx < m_planned_workers.size()) {
4564+ if (!load_finish_planned_workers(m_planned_workers[pwidx])) {
4565+ m_planned_workers[pwidx].cleanup();
4566+ m_planned_workers.erase(m_planned_workers.begin() + pwidx);
4567+ } else {
4568+ pwidx++;
4569+ }
4570+ }
4571+ // Verify autospawning for free workers
4572+ const std::vector <Widelands::Ware_Index> worker_types_without_cost =
4573+ owner().tribe().worker_types_without_cost();
4574+ BOOST_FOREACH(Ware_Index idx, worker_types_without_cost) {
4575+ if (!owner().is_worker_type_allowed(idx)) {
4576+ continue;
4577+ }
4578+ if (is_worker_spawn_set(idx)) {
4579+ continue;
4580+ }
4581+ add_worker_spawn(idx);
4582+ log
4583+ ("WARNING: player %u is allowed to create worker type %s but his "
4584+ "%s %u at (%i, %i) does not have spawning set for that "
4585+ "worker type; setting it to default values\n",
4586+ owner().player_number(),
4587+ owner().tribe().get_worker_descr(idx)->descname().c_str(),
4588+ m_building.descname().c_str(), m_building.serial(),
4589+ m_building.get_position().x, m_building.get_position().y);
4590+ }
4591+}
4592+
4593+
4594+void StorageHandler::cleanup(Editor_Game_Base&)
4595+{
4596+ while (!m_planned_workers.empty()) {
4597+ m_planned_workers.back().cleanup();
4598+ m_planned_workers.pop_back();
4599+ }
4600+}
4601+
4602+//TODO return a value so the owner can schedule_act
4603+uint32_t StorageHandler::act(Game& game)
4604+{
4605+ uint32_t gametime = static_cast<uint32_t>(game.get_gametime());
4606+ uint32_t spawn_act = update_spawns(game, gametime);
4607+ uint32_t removal_act = update_removals(game, gametime);
4608+ // Update planned workers; this is to update the request amounts and
4609+ // check because whether we suddenly can produce a requested worker. This
4610+ // is mostly previously available wares may become unavailable due to
4611+ // secondary requests.
4612+ update_all_planned_workers(game);
4613+ // Act in 5 sec, or before if timers will run down
4614+ uint32_t min_act = 5000;
4615+ if (spawn_act > 0 && spawn_act < min_act) {
4616+ min_act = spawn_act;
4617+ }
4618+ if (removal_act > 0 && removal_act < min_act) {
4619+ min_act = removal_act;
4620+ }
4621+ return min_act;
4622+}
4623+
4624+void StorageHandler::set_economy(Economy* economy)
4625+{
4626+ Economy * const old = m_building.get_economy();
4627+
4628+ if (old == economy) {
4629+ return;
4630+ }
4631+
4632+ if (old) {
4633+ old->remove_storage(*this);
4634+ }
4635+
4636+ m_supply->set_economy(economy);
4637+
4638+ container_iterate_const(std::vector<PlannedWorkers>, m_planned_workers, pw_it) {
4639+ container_iterate_const(std::vector<Request *>, pw_it.current->requests, req_it) {
4640+ (*req_it.current)->set_economy(economy);
4641+ }
4642+ }
4643+
4644+ if (economy) {
4645+ economy->add_storage(*this);
4646+ }
4647+}
4648+
4649+uint32_t StorageHandler::count_workers(Game& game, Ware_Index idx, const Requirements& req)
4650+{
4651+ uint32_t stock = m_supply->stock_workers(idx);
4652+ if (stock <= 0) {
4653+ return stock;
4654+ }
4655+ uint32_t matching = 0;
4656+ // Get list of those for which we stored the attributes
4657+ // This is similar logic than in launch_worker
4658+ std::vector<const StockedWorkerAtr*> workers_with_atr;
4659+ BOOST_FOREACH(StockedWorkerAtr& atr, m_stocked_workers_atr) {
4660+ if (atr.index == idx) {
4661+ workers_with_atr.push_back(&atr);
4662+ }
4663+ }
4664+ // First check those without atr
4665+ Worker* w;
4666+ bool checkpass = false;
4667+ const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(idx);
4668+ if (stock > workers_with_atr.size()) {
4669+ w = &workerdescr.create(game, owner(), &m_building, m_building.get_position());
4670+ checkpass = req.check(*w);
4671+ if (checkpass) {
4672+ matching += stock - workers_with_atr.size();
4673+ }
4674+ w->remove(game);
4675+ }
4676+ // Check with our atr
4677+ // TODO CGH use smarter way of storing atr, maybe with map
4678+ BOOST_FOREACH(const StockedWorkerAtr* atr, workers_with_atr) {
4679+ w = create_with_atr(game, *atr);
4680+ checkpass = req.check(*w);
4681+ if (checkpass) {
4682+ matching++;
4683+ }
4684+ w->remove(game);
4685+ }
4686+ return matching;
4687+}
4688+
4689+
4690+void StorageHandler::launch_all_workers(Game & game, bool exp_only, const WareList& excluded)
4691+{
4692+ if (!exp_only) {
4693+ for (Ware_Index id = Ware_Index::First(); id < m_supply->get_workers().get_nrwareids(); ++id) {
4694+ if (excluded.stock(id)) {
4695+ continue;
4696+ }
4697+ const uint32_t stock = m_supply->get_workers().stock(id);
4698+ if (stock > 0) {
4699+ for (uint32_t i = 0; i < stock; ++i) {
4700+ launch_worker(game, id).start_task_leavebuilding(game, true);
4701+ }
4702+ }
4703+ }
4704+ return;
4705+ }
4706+ BOOST_FOREACH(StockedWorkerAtr atr, m_stocked_workers_atr) {
4707+ if (excluded.stock(atr.index)) {
4708+ continue;
4709+ }
4710+ if (m_supply->get_workers().stock(atr.index) <= 0) {
4711+ continue;
4712+ }
4713+ Worker* w = create_with_atr(game, atr);
4714+ w->start_task_leavebuilding(game, true);
4715+ m_supply->remove_workers(atr.index, 1);
4716+ }
4717+}
4718+
4719+void StorageHandler::add_ware_spawn
4720+ (const Ware_Index idx, uint32_t interval, uint32_t stock_max, uint32_t counter, bool dont_exceed)
4721+{
4722+ if (m_spawn_wares.count(idx)) {
4723+ remove_ware_spawn(idx);
4724+ }
4725+ if (dont_exceed) {
4726+ std::vector<uint32_t> values = {interval, interval, stock_max};
4727+ m_spawn_wares.insert(std::make_pair(idx, values));
4728+ } else {
4729+ std::vector<uint32_t> values = {interval, interval, stock_max, counter};
4730+ m_spawn_wares.insert(std::make_pair(idx, values));
4731+ }
4732+}
4733+
4734+void StorageHandler::remove_ware_spawn(const Ware_Index idx)
4735+{
4736+ m_spawn_wares.erase(idx);
4737+}
4738+bool StorageHandler::is_ware_spawn_set(Ware_Index idx)
4739+{
4740+ return m_spawn_wares.count(idx);
4741+}
4742+
4743+
4744+void StorageHandler::add_worker_spawn
4745+ (const Ware_Index idx, uint32_t interval, uint32_t stock_max, uint32_t counter, bool dont_exceed)
4746+{
4747+ if (m_spawn_workers.count(idx)) {
4748+ remove_worker_spawn(idx);
4749+ }
4750+ if (dont_exceed) {
4751+ std::vector<uint32_t> values = {interval, interval, stock_max};
4752+ m_spawn_workers.insert(std::make_pair(idx, values));
4753+ } else {
4754+ std::vector<uint32_t> values = {interval, interval, stock_max, counter};
4755+ m_spawn_workers.insert(std::make_pair(idx, values));
4756+ }
4757+}
4758+
4759+void StorageHandler::remove_worker_spawn(const Ware_Index idx)
4760+{
4761+ m_spawn_workers.erase(idx);
4762+}
4763+bool StorageHandler::is_worker_spawn_set(Ware_Index idx)
4764+{
4765+ return m_spawn_workers.count(idx);
4766+}
4767+
4768+//
4769+//
4770+// Storage implementation
4771+//
4772+//
4773+
4774+Player& StorageHandler::owner() const
4775+{
4776+ return m_building.owner();
4777+}
4778+
4779+const WareList& StorageHandler::get_wares() const
4780+{
4781+ return m_supply->get_wares();
4782+}
4783+
4784+const WareList& StorageHandler::get_workers() const
4785+{
4786+ return m_supply->get_workers();
4787+}
4788+
4789+void StorageHandler::insert_wares(Ware_Index idx, uint32_t count)
4790+{
4791+ m_supply->add_wares(idx, count);
4792+}
4793+
4794+void StorageHandler::remove_wares(Ware_Index idx, uint32_t count)
4795+{
4796+ m_supply->remove_wares(idx, count);
4797+}
4798+
4799+void StorageHandler::insert_workers(Ware_Index idx, uint32_t count)
4800+{
4801+ m_supply->add_workers(idx, count);
4802+}
4803+
4804+void StorageHandler::remove_workers(Ware_Index idx, uint32_t count)
4805+{
4806+ m_supply->remove_workers(idx, count);
4807+}
4808+
4809+WareInstance& StorageHandler::launch_ware(Game& game, Ware_Index idx)
4810+{
4811+ WareInstance & item = *new WareInstance(idx, owner().tribe().get_ware_descr(idx));
4812+ item.init(game);
4813+ do_launch_ware(game, item);
4814+
4815+ m_supply->remove_wares(idx, 1);
4816+
4817+ return item;
4818+}
4819+
4820+
4821+void StorageHandler::do_launch_ware(Game& game, WareInstance& ware_inst)
4822+{
4823+ // Create a carrier
4824+ Ware_Index const carrierid = owner().tribe().worker_index("carrier");
4825+ const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(carrierid);
4826+
4827+ Worker & worker = workerdescr.create(game, owner(), &m_building, m_building.get_position());
4828+
4829+ // Yup, this is cheating.
4830+ if (m_supply->stock_workers(carrierid))
4831+ m_supply->remove_workers(carrierid, 1);
4832+
4833+ // Setup the carrier
4834+ worker.start_task_dropoff(game, ware_inst);
4835+}
4836+
4837+
4838+void StorageHandler::incorporate_ware(Editor_Game_Base& egbase, WareInstance& item)
4839+{
4840+ m_supply->add_wares(item.descr_index(), 1);
4841+ return item.destroy(egbase);
4842+}
4843+
4844+Worker& StorageHandler::launch_worker(Game& game, Ware_Index idx, const Requirements& req)
4845+{
4846+ do {
4847+ uint32_t stock = m_supply->stock_workers(idx);
4848+ if (stock > 0) {
4849+ // Get list of those for which we stored the attributes, as pointers to actual objects
4850+ // TODO smarter storage for atrs
4851+ std::vector<const StockedWorkerAtr*> workers_with_atr;
4852+ for
4853+ (std::vector<StockedWorkerAtr>::iterator it = m_stocked_workers_atr.begin();
4854+ it != m_stocked_workers_atr.end(); ++it)
4855+ {
4856+ if (it->index == idx) {
4857+ workers_with_atr.push_back(&(*it));
4858+ }
4859+ }
4860+ // First check if one without atr is enough
4861+ Worker* w;
4862+ if (stock > workers_with_atr.size()) {
4863+ const Worker_Descr & workerdescr = *owner().tribe().get_worker_descr(idx);
4864+ w = &workerdescr.create(game, owner(), &m_building, m_building.get_position());
4865+ if (req.check(*w)) {
4866+ m_supply->remove_workers(idx, 1);
4867+ return *w;
4868+ }
4869+ }
4870+ // Check with our atr
4871+ BOOST_FOREACH(const StockedWorkerAtr* atr, workers_with_atr) {
4872+ w = create_with_atr(game, *atr);
4873+ if (req.check(*w)) {
4874+ // We need to find back our atr in original vector to erase it
4875+ bool removed = false;
4876+ for
4877+ (std::vector<StockedWorkerAtr>::iterator it = m_stocked_workers_atr.begin();
4878+ it != m_stocked_workers_atr.end(); ++it)
4879+ {
4880+ if (&(*it) == atr) {
4881+ m_stocked_workers_atr.erase(it);
4882+ removed = true;
4883+ break;
4884+ }
4885+ }
4886+ assert(removed);
4887+ m_supply->remove_workers(idx, 1);
4888+ return *w;
4889+ }
4890+ }
4891+ }
4892+ // Check if we got the tools to create a new one
4893+ if (can_create_worker(game, idx)) {
4894+ // don't want to use an upgraded worker, so create new one.
4895+ create_worker(game, idx);
4896+ } else {
4897+ idx = owner().tribe().get_worker_descr(idx)->becomes();
4898+ }
4899+ } while (idx != Ware_Index::Null());
4900+
4901+ throw wexception
4902+ ("StorageHandler::launch_worker: worker does not actually exist");
4903+}
4904+
4905+void StorageHandler::incorporate_worker(Editor_Game_Base& egbase, Worker& w)
4906+{
4907+ assert(w.get_owner() == &owner());
4908+ // Rescue carried ware
4909+ if (WareInstance * const item = w.fetch_carried_item(egbase)) {
4910+ incorporate_ware(egbase, *item);
4911+ }
4912+ // Add to supply
4913+ Ware_Index worker_index = owner().tribe().worker_index(w.name().c_str());
4914+ m_supply->add_workers(worker_index, 1);
4915+
4916+ // Store the attributes.
4917+ // FIXME CGH handle soldiers : hp & healing
4918+ StockedWorkerAtr* atr = store_worker_atr(w);
4919+ if (atr != nullptr) {
4920+ m_stocked_workers_atr.push_back(*atr);
4921+ }
4922+ // Destroy the instance
4923+ w.remove(egbase);
4924+}
4925+
4926+Storage::StockPolicy StorageHandler::get_ware_policy(Ware_Index ware) const
4927+{
4928+ assert(ware.value() < m_ware_policy.size());
4929+ return m_ware_policy[ware.value()];
4930+}
4931+
4932+Storage::StockPolicy StorageHandler::get_worker_policy(Ware_Index ware) const
4933+{
4934+ assert(ware.value() < m_worker_policy.size());
4935+ return m_worker_policy[ware.value()];
4936+}
4937+
4938+Storage::StockPolicy StorageHandler::get_stock_policy(WareWorker waretype, Ware_Index wareindex) const
4939+{
4940+ if (waretype == wwWORKER)
4941+ return get_worker_policy(wareindex);
4942+ else
4943+ return get_ware_policy(wareindex);
4944+}
4945+
4946+void StorageHandler::set_ware_policy(Ware_Index ware, Storage::StockPolicy policy)
4947+{
4948+ assert(ware.value() < m_ware_policy.size());
4949+ m_ware_policy[ware.value()] = policy;
4950+}
4951+
4952+void StorageHandler::set_worker_policy(Ware_Index ware, Storage::StockPolicy policy)
4953+{
4954+ assert(ware.value() < m_worker_policy.size());
4955+ m_worker_policy[ware.value()] = policy;
4956+}
4957+
4958+bool StorageHandler::can_create_worker(Game&, Ware_Index worker_idx)
4959+{
4960+ if (not (worker_idx < m_supply->get_workers().get_nrwareids())) {
4961+ throw wexception
4962+ ("worker type %d does not exists (max is %d)",
4963+ worker_idx.value(), m_supply->get_workers().get_nrwareids().value());
4964+ }
4965+
4966+ const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(worker_idx);
4967+ assert(&w_desc);
4968+ if (not w_desc.is_buildable()) {
4969+ return false;
4970+ }
4971+
4972+ // see if we have the resources
4973+ const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
4974+ container_iterate_const(Worker_Descr::Buildcost, buildcost, it) {
4975+ const std::string & input_name = it.current->first;
4976+ if (Ware_Index id_w = owner().tribe().ware_index(input_name)) {
4977+ if (m_supply->stock_wares (id_w) < it.current->second)
4978+ return false;
4979+ } else if ((id_w = owner().tribe().worker_index(input_name))) {
4980+ if (m_supply->stock_workers(id_w) < it.current->second)
4981+ return false;
4982+ } else
4983+ throw wexception
4984+ ("worker type %s needs \"%s\" to be built but that is neither "
4985+ "a ware type nor a worker type defined in the tribe %s",
4986+ w_desc.descname().c_str(), input_name.c_str(),
4987+ owner().tribe().name().c_str());
4988+ }
4989+ return true;
4990+}
4991+
4992+void StorageHandler::create_worker(Game& game, Ware_Index worker_idx)
4993+{
4994+ assert(can_create_worker (game, worker_idx));
4995+
4996+ const Worker_Descr & w_desc = *owner().tribe().get_worker_descr(worker_idx);
4997+ const Worker_Descr::Buildcost & buildcost = w_desc.buildcost();
4998+ container_iterate_const(Worker_Descr::Buildcost, buildcost, i) {
4999+ const std::string & input = i.current->first;
5000+ 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: