Merge lp:~widelands-dev/widelands/storages_garrisons into lp:widelands
- storages_garrisons
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
SirVer | Needs Fixing | ||
Review via email: mp+178704@code.launchpad.net |
Commit message
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/
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.
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)
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/
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://
[2] http://
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?
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:/
> You proposed lp:~widelands-dev/widelands/storages_garrisons for merging.
>
SirVer (sirver) wrote : | # |
Cool. I am working on getting rid of the old font renderer too in https:/
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:/
> Maybe we can join forces.
>
> --
>
> https:/
> You proposed lp:~widelands-dev/widelands/storages_garrisons for merging.
>
Preview Diff
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 = ⌖ |
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)) { |
that is a lot of code. I will review after I am done with the log_messages one.