Merge lp:~widelands-dev/widelands/warehouse_refactor into lp:widelands
- warehouse_refactor
- Merge into trunk
Proposed by
SirVer
Status: | Merged |
---|---|
Merged at revision: | 8368 |
Proposed branch: | lp:~widelands-dev/widelands/warehouse_refactor |
Merge into: | lp:widelands |
Diff against target: |
1066 lines (+339/-307) 19 files modified
src/ai/defaultai_warfare.cc (+3/-3) src/economy/route.h (+4/-2) src/logic/CMakeLists.txt (+2/-2) src/logic/cmd_queue.h (+0/-1) src/logic/findimmovable.cc (+5/-3) src/logic/findimmovable.h (+2/-2) src/logic/map_objects/map_object.h (+2/-2) src/logic/map_objects/tribes/attack_target.h (+43/-56) src/logic/map_objects/tribes/building.cc (+7/-1) src/logic/map_objects/tribes/building.h (+10/-0) src/logic/map_objects/tribes/militarysite.cc (+141/-136) src/logic/map_objects/tribes/militarysite.h (+16/-11) src/logic/map_objects/tribes/soldier.cc (+17/-15) src/logic/map_objects/tribes/soldier.h (+1/-1) src/logic/map_objects/tribes/warehouse.cc (+53/-45) src/logic/map_objects/tribes/warehouse.h (+19/-15) src/logic/player.cc (+4/-4) src/wui/attack_box.h (+0/-1) src/wui/fieldaction.cc (+10/-7) |
To merge this branch: | bzr merge lp:~widelands-dev/widelands/warehouse_refactor |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
GunChleoc | Approve | ||
Review via email:
|
Commit message
Refactor Attackable.
- Getting rid of some multiple inheritance in Warehouse and MilitarySite by
composing Attackable as a member into Building.
- Rename Attackable -> AttackTarget and change the interface to be cleaner.
- Mild related cleanups.
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
SirVer (sirver) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
GunChleoc (gunchleoc) wrote : | # |
2 tiny nits, code LGTM otherwise. Not tested yet.
And trading - yay! :)
review:
Approve
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2227. State: passed. Details: https:/
Appveyor build 2062. State: success. Details: https:/
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
GunChleoc (gunchleoc) wrote : | # |
Tested now, so you can merge this any time :)
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
SirVer (sirver) : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
SirVer (sirver) wrote : | # |
@bunnybot merge
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/ai/defaultai_warfare.cc' | |||
2 | --- src/ai/defaultai_warfare.cc 2017-01-28 14:53:28 +0000 | |||
3 | +++ src/ai/defaultai_warfare.cc 2017-05-21 11:20:39 +0000 | |||
4 | @@ -122,7 +122,7 @@ | |||
5 | 122 | // get list of immovable around this our military site | 122 | // get list of immovable around this our military site |
6 | 123 | std::vector<ImmovableFound> immovables; | 123 | std::vector<ImmovableFound> immovables; |
7 | 124 | map.find_immovables(Area<FCoords>(f, (vision + 3 < 13) ? 13 : vision + 3), &immovables, | 124 | map.find_immovables(Area<FCoords>(f, (vision + 3 < 13) ? 13 : vision + 3), &immovables, |
9 | 125 | FindImmovableAttackable()); | 125 | FindImmovableAttackTarget()); |
10 | 126 | 126 | ||
11 | 127 | for (uint32_t j = 0; j < immovables.size(); ++j) { | 127 | for (uint32_t j = 0; j < immovables.size(); ++j) { |
12 | 128 | if (upcast(MilitarySite const, bld, immovables.at(j).object)) { | 128 | if (upcast(MilitarySite const, bld, immovables.at(j).object)) { |
13 | @@ -229,7 +229,7 @@ | |||
14 | 229 | defenders_strength = calculate_strength(defenders); | 229 | defenders_strength = calculate_strength(defenders); |
15 | 230 | 230 | ||
16 | 231 | flag = &bld->base_flag(); | 231 | flag = &bld->base_flag(); |
18 | 232 | if (is_visible && bld->can_attack()) { | 232 | if (is_visible && bld->attack_target()->can_be_attacked()) { |
19 | 233 | is_attackable = true; | 233 | is_attackable = true; |
20 | 234 | } | 234 | } |
21 | 235 | owner_number = bld->owner().player_number(); | 235 | owner_number = bld->owner().player_number(); |
22 | @@ -244,7 +244,7 @@ | |||
23 | 244 | 244 | ||
24 | 245 | flag = &Wh->base_flag(); | 245 | flag = &Wh->base_flag(); |
25 | 246 | is_warehouse = true; | 246 | is_warehouse = true; |
27 | 247 | if (is_visible && Wh->can_attack()) { | 247 | if (is_visible && Wh->attack_target()->can_be_attacked()) { |
28 | 248 | is_attackable = true; | 248 | is_attackable = true; |
29 | 249 | } | 249 | } |
30 | 250 | owner_number = Wh->owner().player_number(); | 250 | owner_number = Wh->owner().player_number(); |
31 | 251 | 251 | ||
32 | === modified file 'src/economy/route.h' | |||
33 | --- src/economy/route.h 2017-01-25 18:55:59 +0000 | |||
34 | +++ src/economy/route.h 2017-05-21 11:20:39 +0000 | |||
35 | @@ -23,14 +23,16 @@ | |||
36 | 23 | #include <vector> | 23 | #include <vector> |
37 | 24 | 24 | ||
38 | 25 | #include "economy/iroute.h" | 25 | #include "economy/iroute.h" |
39 | 26 | #include "io/fileread.h" | ||
40 | 27 | #include "io/filewrite.h" | ||
41 | 26 | #include "logic/map_objects/map_object.h" | 28 | #include "logic/map_objects/map_object.h" |
42 | 27 | 29 | ||
43 | 28 | namespace Widelands { | 30 | namespace Widelands { |
44 | 29 | 31 | ||
45 | 32 | class EditorGameBase; | ||
46 | 33 | class MapObjectLoader; | ||
47 | 30 | struct Flag; | 34 | struct Flag; |
48 | 31 | class EditorGameBase; | ||
49 | 32 | struct MapObjectSaver; | 35 | struct MapObjectSaver; |
50 | 33 | class MapObjectLoader; | ||
51 | 34 | struct RoutingNode; | 36 | struct RoutingNode; |
52 | 35 | 37 | ||
53 | 36 | /** | 38 | /** |
54 | 37 | 39 | ||
55 | === modified file 'src/logic/CMakeLists.txt' | |||
56 | --- src/logic/CMakeLists.txt 2017-05-14 18:17:16 +0000 | |||
57 | +++ src/logic/CMakeLists.txt 2017-05-21 11:20:39 +0000 | |||
58 | @@ -127,14 +127,13 @@ | |||
59 | 127 | save_handler.h | 127 | save_handler.h |
60 | 128 | widelands_geometry_io.cc | 128 | widelands_geometry_io.cc |
61 | 129 | widelands_geometry_io.h | 129 | widelands_geometry_io.h |
62 | 130 | map_objects/draw_text.h | ||
63 | 131 | map_objects/attackable.h | ||
64 | 132 | map_objects/bob.cc | 130 | map_objects/bob.cc |
65 | 133 | map_objects/bob.h | 131 | map_objects/bob.h |
66 | 134 | map_objects/buildcost.cc | 132 | map_objects/buildcost.cc |
67 | 135 | map_objects/buildcost.h | 133 | map_objects/buildcost.h |
68 | 136 | map_objects/checkstep.cc | 134 | map_objects/checkstep.cc |
69 | 137 | map_objects/checkstep.h | 135 | map_objects/checkstep.h |
70 | 136 | map_objects/draw_text.h | ||
71 | 138 | map_objects/immovable.cc | 137 | map_objects/immovable.cc |
72 | 139 | map_objects/immovable.h | 138 | map_objects/immovable.h |
73 | 140 | map_objects/immovable_program.h | 139 | map_objects/immovable_program.h |
74 | @@ -142,6 +141,7 @@ | |||
75 | 142 | map_objects/map_object.h | 141 | map_objects/map_object.h |
76 | 143 | map_objects/terrain_affinity.cc | 142 | map_objects/terrain_affinity.cc |
77 | 144 | map_objects/terrain_affinity.h | 143 | map_objects/terrain_affinity.h |
78 | 144 | map_objects/tribes/attack_target.h | ||
79 | 145 | map_objects/tribes/battle.cc | 145 | map_objects/tribes/battle.cc |
80 | 146 | map_objects/tribes/battle.h | 146 | map_objects/tribes/battle.h |
81 | 147 | map_objects/tribes/bill_of_materials.h | 147 | map_objects/tribes/bill_of_materials.h |
82 | 148 | 148 | ||
83 | === modified file 'src/logic/cmd_queue.h' | |||
84 | --- src/logic/cmd_queue.h 2017-01-25 18:55:59 +0000 | |||
85 | +++ src/logic/cmd_queue.h 2017-05-21 11:20:39 +0000 | |||
86 | @@ -27,7 +27,6 @@ | |||
87 | 27 | #include <stdint.h> | 27 | #include <stdint.h> |
88 | 28 | 28 | ||
89 | 29 | #include "logic/queue_cmd_ids.h" | 29 | #include "logic/queue_cmd_ids.h" |
90 | 30 | #include <stdint.h> | ||
91 | 31 | 30 | ||
92 | 32 | class FileRead; | 31 | class FileRead; |
93 | 33 | class FileWrite; | 32 | class FileWrite; |
94 | 34 | 33 | ||
95 | === modified file 'src/logic/findimmovable.cc' | |||
96 | --- src/logic/findimmovable.cc 2017-01-25 18:55:59 +0000 | |||
97 | +++ src/logic/findimmovable.cc 2017-05-21 11:20:39 +0000 | |||
98 | @@ -21,7 +21,6 @@ | |||
99 | 21 | 21 | ||
100 | 22 | #include "base/macros.h" | 22 | #include "base/macros.h" |
101 | 23 | #include "economy/flag.h" | 23 | #include "economy/flag.h" |
102 | 24 | #include "logic/map_objects/attackable.h" | ||
103 | 25 | #include "logic/map_objects/immovable.h" | 24 | #include "logic/map_objects/immovable.h" |
104 | 26 | #include "logic/map_objects/tribes/militarysite.h" | 25 | #include "logic/map_objects/tribes/militarysite.h" |
105 | 27 | 26 | ||
106 | @@ -61,8 +60,11 @@ | |||
107 | 61 | return false; | 60 | return false; |
108 | 62 | } | 61 | } |
109 | 63 | 62 | ||
112 | 64 | bool FindImmovableAttackable::accept(const BaseImmovable& imm) const { | 63 | bool FindImmovableAttackTarget::accept(const BaseImmovable& imm) const { |
113 | 65 | return dynamic_cast<Attackable const*>(&imm); | 64 | if (upcast(Building const, b, &imm)) { |
114 | 65 | return b->attack_target() != nullptr; | ||
115 | 66 | } | ||
116 | 67 | return false; | ||
117 | 66 | } | 68 | } |
118 | 67 | 69 | ||
119 | 68 | bool FindImmovableByDescr::accept(const BaseImmovable& baseimm) const { | 70 | bool FindImmovableByDescr::accept(const BaseImmovable& baseimm) const { |
120 | 69 | 71 | ||
121 | === modified file 'src/logic/findimmovable.h' | |||
122 | --- src/logic/findimmovable.h 2017-01-25 18:55:59 +0000 | |||
123 | +++ src/logic/findimmovable.h 2017-05-21 11:20:39 +0000 | |||
124 | @@ -132,8 +132,8 @@ | |||
125 | 132 | 132 | ||
126 | 133 | const Player& player; | 133 | const Player& player; |
127 | 134 | }; | 134 | }; |
130 | 135 | struct FindImmovableAttackable { | 135 | struct FindImmovableAttackTarget { |
131 | 136 | FindImmovableAttackable() { | 136 | FindImmovableAttackTarget() { |
132 | 137 | } | 137 | } |
133 | 138 | 138 | ||
134 | 139 | bool accept(const BaseImmovable&) const; | 139 | bool accept(const BaseImmovable&) const; |
135 | 140 | 140 | ||
136 | === modified file 'src/logic/map_objects/map_object.h' | |||
137 | --- src/logic/map_objects/map_object.h 2017-04-23 12:11:19 +0000 | |||
138 | +++ src/logic/map_objects/map_object.h 2017-05-21 11:20:39 +0000 | |||
139 | @@ -491,12 +491,12 @@ | |||
140 | 491 | ObjectPointer() { | 491 | ObjectPointer() { |
141 | 492 | serial_ = 0; | 492 | serial_ = 0; |
142 | 493 | } | 493 | } |
144 | 494 | ObjectPointer(MapObject* const obj) { | 494 | ObjectPointer(const MapObject* const obj) { |
145 | 495 | serial_ = obj ? obj->serial_ : 0; | 495 | serial_ = obj ? obj->serial_ : 0; |
146 | 496 | } | 496 | } |
147 | 497 | // can use standard copy constructor and assignment operator | 497 | // can use standard copy constructor and assignment operator |
148 | 498 | 498 | ||
150 | 499 | ObjectPointer& operator=(MapObject* const obj) { | 499 | ObjectPointer& operator=(const MapObject* const obj) { |
151 | 500 | serial_ = obj ? obj->serial_ : 0; | 500 | serial_ = obj ? obj->serial_ : 0; |
152 | 501 | return *this; | 501 | return *this; |
153 | 502 | } | 502 | } |
154 | 503 | 503 | ||
155 | === renamed file 'src/logic/map_objects/attackable.h' => 'src/logic/map_objects/tribes/attack_target.h' | |||
156 | --- src/logic/map_objects/attackable.h 2017-01-25 18:55:59 +0000 | |||
157 | +++ src/logic/map_objects/tribes/attack_target.h 2017-05-21 11:20:39 +0000 | |||
158 | @@ -17,68 +17,55 @@ | |||
159 | 17 | * | 17 | * |
160 | 18 | */ | 18 | */ |
161 | 19 | 19 | ||
164 | 20 | #ifndef WL_LOGIC_MAP_OBJECTS_ATTACKABLE_H | 20 | #ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_ATTACK_TARGET_H |
165 | 21 | #define WL_LOGIC_MAP_OBJECTS_ATTACKABLE_H | 21 | #define WL_LOGIC_MAP_OBJECTS_TRIBES_ATTACK_TARGET_H |
166 | 22 | |||
167 | 23 | #include "base/macros.h" | ||
168 | 22 | 24 | ||
169 | 23 | namespace Widelands { | 25 | namespace Widelands { |
170 | 24 | 26 | ||
171 | 25 | class Player; | ||
172 | 26 | class Soldier; | 27 | class Soldier; |
173 | 27 | 28 | ||
226 | 28 | enum { | 29 | // This is the maximum radius that a military building can protect in the sense |
227 | 29 | /** | 30 | // that an enemy soldier that enters the player's territory will call \ref |
228 | 30 | * This is the maximum radius that a military building can protect | 31 | // AttackTarget::enemy_soldier_approaches if it is that close. |
229 | 31 | * in the sense that an enemy soldier that enters the player's territory | 32 | constexpr int kMaxProtectionRadius = 25; |
230 | 32 | * will call \ref Attackable::aggressor if it is that close. | 33 | |
231 | 33 | */ | 34 | class AttackTarget { |
232 | 34 | MaxProtectionRadius = 25 | 35 | public: |
233 | 35 | }; | 36 | AttackTarget() = default; |
234 | 36 | 37 | virtual ~AttackTarget() { | |
183 | 37 | /** | ||
184 | 38 | * Buildings can implement this interface to indicate that | ||
185 | 39 | * they can be attacked. | ||
186 | 40 | */ | ||
187 | 41 | struct Attackable { | ||
188 | 42 | /** | ||
189 | 43 | * Return the player that owns this attackable. | ||
190 | 44 | */ | ||
191 | 45 | virtual Player& owner() const = 0; | ||
192 | 46 | |||
193 | 47 | /** | ||
194 | 48 | * Determines whether this building can be attacked right now. | ||
195 | 49 | * | ||
196 | 50 | * This should only return false for military sites that have not | ||
197 | 51 | * been occupied yet. | ||
198 | 52 | */ | ||
199 | 53 | virtual bool can_attack() = 0; | ||
200 | 54 | |||
201 | 55 | /** | ||
202 | 56 | * Called by an enemy soldier that enters a node with distance | ||
203 | 57 | * less than or equal to \ref MaxProtectionRadius from the building. | ||
204 | 58 | * | ||
205 | 59 | * This allows the building to send protective forces to intercept | ||
206 | 60 | * the soldier. | ||
207 | 61 | */ | ||
208 | 62 | virtual void aggressor(Soldier&) = 0; | ||
209 | 63 | |||
210 | 64 | /** | ||
211 | 65 | * Called by a soldier who is standing on the building's flag | ||
212 | 66 | * to attack the building. | ||
213 | 67 | * | ||
214 | 68 | * The building must send a soldier for defense, and return \c true. | ||
215 | 69 | * Otherwise, i.e. if the building cannot defend itself anymore, | ||
216 | 70 | * it must destroy itself or turn over to the attacking player, | ||
217 | 71 | * and return \c false. | ||
218 | 72 | * | ||
219 | 73 | * \return \c true if a soldier was launched in defense of the building, | ||
220 | 74 | * or \c false if the building cannot defend itself any longer. | ||
221 | 75 | */ | ||
222 | 76 | virtual bool attack(Soldier&) = 0; | ||
223 | 77 | |||
224 | 78 | protected: | ||
225 | 79 | virtual ~Attackable() { | ||
235 | 80 | } | 38 | } |
236 | 39 | |||
237 | 40 | // Determines whether this building can be attacked right now. | ||
238 | 41 | virtual bool can_be_attacked() const = 0; | ||
239 | 42 | |||
240 | 43 | // Called by an enemy soldier that enters a node with distance | ||
241 | 44 | // less than or equal to \ref kMaxProtectionRadius from the building. | ||
242 | 45 | // | ||
243 | 46 | // This allows the building to send protective forces to intercept | ||
244 | 47 | // the soldier. | ||
245 | 48 | virtual void enemy_soldier_approaches(const Soldier& enemy) const = 0; | ||
246 | 49 | |||
247 | 50 | // Called by a soldier who is standing on the building's flag | ||
248 | 51 | // to attack the building. | ||
249 | 52 | // | ||
250 | 53 | // The building must send a soldier for defense, and return \c true. | ||
251 | 54 | // Otherwise, i.e. if the building cannot defend itself anymore, | ||
252 | 55 | // it must destroy itself or turn over to the attacking player, | ||
253 | 56 | // and return \c false. | ||
254 | 57 | enum class AttackResult { | ||
255 | 58 | // Returned when a soldier was launched in defense of the building. | ||
256 | 59 | DefenderLaunched, | ||
257 | 60 | |||
258 | 61 | // Returned if the building cannot defend itself any longer. | ||
259 | 62 | Defenseless | ||
260 | 63 | }; | ||
261 | 64 | virtual AttackResult attack(Soldier* attacker) const = 0; | ||
262 | 65 | |||
263 | 66 | private: | ||
264 | 67 | DISALLOW_COPY_AND_ASSIGN(AttackTarget); | ||
265 | 81 | }; | 68 | }; |
266 | 82 | } | 69 | } |
267 | 83 | 70 | ||
269 | 84 | #endif // end of include guard: WL_LOGIC_MAP_OBJECTS_ATTACKABLE_H | 71 | #endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_ATTACK_TARGET_H |
270 | 85 | 72 | ||
271 | === modified file 'src/logic/map_objects/tribes/building.cc' | |||
272 | --- src/logic/map_objects/tribes/building.cc 2017-05-09 09:18:14 +0000 | |||
273 | +++ src/logic/map_objects/tribes/building.cc 2017-05-21 11:20:39 +0000 | |||
274 | @@ -235,7 +235,8 @@ | |||
275 | 235 | animstart_(0), | 235 | animstart_(0), |
276 | 236 | leave_time_(0), | 236 | leave_time_(0), |
277 | 237 | defeating_player_(0), | 237 | defeating_player_(0), |
279 | 238 | seeing_(false) { | 238 | seeing_(false), |
280 | 239 | attack_target_(nullptr) { | ||
281 | 239 | } | 240 | } |
282 | 240 | 241 | ||
283 | 241 | void Building::load_finish(EditorGameBase& egbase) { | 242 | void Building::load_finish(EditorGameBase& egbase) { |
284 | @@ -692,6 +693,11 @@ | |||
285 | 692 | Notifications::publish(NoteBuilding(serial(), NoteBuilding::Action::kWorkersChanged)); | 693 | Notifications::publish(NoteBuilding(serial(), NoteBuilding::Action::kWorkersChanged)); |
286 | 693 | } | 694 | } |
287 | 694 | 695 | ||
288 | 696 | void Building::set_attack_target(AttackTarget* new_attack_target) { | ||
289 | 697 | assert(attack_target_ == nullptr); | ||
290 | 698 | attack_target_ = new_attack_target; | ||
291 | 699 | } | ||
292 | 700 | |||
293 | 695 | /** | 701 | /** |
294 | 696 | * Change whether this building sees its vision range based on workers | 702 | * Change whether this building sees its vision range based on workers |
295 | 697 | * inside the building. | 703 | * inside the building. |
296 | 698 | 704 | ||
297 | === modified file 'src/logic/map_objects/tribes/building.h' | |||
298 | --- src/logic/map_objects/tribes/building.h 2017-05-06 19:21:47 +0000 | |||
299 | +++ src/logic/map_objects/tribes/building.h 2017-05-21 11:20:39 +0000 | |||
300 | @@ -30,6 +30,7 @@ | |||
301 | 30 | #include "base/macros.h" | 30 | #include "base/macros.h" |
302 | 31 | #include "logic/map_objects/buildcost.h" | 31 | #include "logic/map_objects/buildcost.h" |
303 | 32 | #include "logic/map_objects/immovable.h" | 32 | #include "logic/map_objects/immovable.h" |
304 | 33 | #include "logic/map_objects/tribes/attack_target.h" | ||
305 | 33 | #include "logic/map_objects/tribes/bill_of_materials.h" | 34 | #include "logic/map_objects/tribes/bill_of_materials.h" |
306 | 34 | #include "logic/map_objects/tribes/wareworker.h" | 35 | #include "logic/map_objects/tribes/wareworker.h" |
307 | 35 | #include "logic/map_objects/tribes/workarea_info.h" | 36 | #include "logic/map_objects/tribes/workarea_info.h" |
308 | @@ -293,6 +294,13 @@ | |||
309 | 293 | void add_worker(Worker&) override; | 294 | void add_worker(Worker&) override; |
310 | 294 | void remove_worker(Worker&) override; | 295 | void remove_worker(Worker&) override; |
311 | 295 | 296 | ||
312 | 297 | // Returns the AttackTarget object associated with this building. If the | ||
313 | 298 | // building can never be attacked (for example productionsites) this will be | ||
314 | 299 | // nullptr. | ||
315 | 300 | const AttackTarget* attack_target() const { | ||
316 | 301 | return attack_target_; | ||
317 | 302 | } | ||
318 | 303 | |||
319 | 296 | void send_message(Game& game, | 304 | void send_message(Game& game, |
320 | 297 | const Message::Type msgtype, | 305 | const Message::Type msgtype, |
321 | 298 | const std::string& title, | 306 | const std::string& title, |
322 | @@ -324,6 +332,7 @@ | |||
323 | 324 | draw_info(TextToDraw draw_text, const Vector2f& point_on_dst, float scale, RenderTarget* dst); | 332 | draw_info(TextToDraw draw_text, const Vector2f& point_on_dst, float scale, RenderTarget* dst); |
324 | 325 | 333 | ||
325 | 326 | void set_seeing(bool see); | 334 | void set_seeing(bool see); |
326 | 335 | void set_attack_target(AttackTarget* new_attack_target); | ||
327 | 327 | 336 | ||
328 | 328 | Coords position_; | 337 | Coords position_; |
329 | 329 | Flag* flag_; | 338 | Flag* flag_; |
330 | @@ -350,6 +359,7 @@ | |||
331 | 350 | 359 | ||
332 | 351 | private: | 360 | private: |
333 | 352 | std::string statistics_string_; | 361 | std::string statistics_string_; |
334 | 362 | AttackTarget* attack_target_; // owned by the base classes, set by 'set_attack_target'. | ||
335 | 353 | }; | 363 | }; |
336 | 354 | } | 364 | } |
337 | 355 | 365 | ||
338 | 356 | 366 | ||
339 | === modified file 'src/logic/map_objects/tribes/militarysite.cc' | |||
340 | --- src/logic/map_objects/tribes/militarysite.cc 2017-04-23 12:11:19 +0000 | |||
341 | +++ src/logic/map_objects/tribes/militarysite.cc 2017-05-21 11:20:39 +0000 | |||
342 | @@ -43,6 +43,145 @@ | |||
343 | 43 | 43 | ||
344 | 44 | namespace Widelands { | 44 | namespace Widelands { |
345 | 45 | 45 | ||
346 | 46 | bool MilitarySite::AttackTarget::can_be_attacked() const { | ||
347 | 47 | return military_site_->didconquer_; | ||
348 | 48 | } | ||
349 | 49 | |||
350 | 50 | void MilitarySite::AttackTarget::enemy_soldier_approaches(const Soldier& enemy) const { | ||
351 | 51 | auto& owner = military_site_->owner(); | ||
352 | 52 | Game& game = dynamic_cast<Game&>(owner.egbase()); | ||
353 | 53 | Map& map = game.map(); | ||
354 | 54 | if (enemy.get_owner() == &owner || enemy.get_battle() || | ||
355 | 55 | military_site_->descr().get_conquers() <= | ||
356 | 56 | map.calc_distance(enemy.get_position(), military_site_->get_position())) | ||
357 | 57 | return; | ||
358 | 58 | |||
359 | 59 | if (map.find_bobs(Area<FCoords>(map.get_fcoords(military_site_->base_flag().get_position()), 2), | ||
360 | 60 | nullptr, FindBobEnemySoldier(&owner))) | ||
361 | 61 | return; | ||
362 | 62 | |||
363 | 63 | // We're dealing with a soldier that we might want to keep busy | ||
364 | 64 | // Now would be the time to implement some player-definable | ||
365 | 65 | // policy as to how many soldiers are allowed to leave as defenders | ||
366 | 66 | std::vector<Soldier*> present = military_site_->present_soldiers(); | ||
367 | 67 | |||
368 | 68 | if (1 < present.size()) { | ||
369 | 69 | for (Soldier* temp_soldier : present) { | ||
370 | 70 | if (!military_site_->has_soldier_job(*temp_soldier)) { | ||
371 | 71 | SoldierJob sj; | ||
372 | 72 | sj.soldier = temp_soldier; | ||
373 | 73 | sj.enemy = &enemy; | ||
374 | 74 | sj.stayhome = false; | ||
375 | 75 | military_site_->soldierjobs_.push_back(sj); | ||
376 | 76 | temp_soldier->update_task_buildingwork(game); | ||
377 | 77 | return; | ||
378 | 78 | } | ||
379 | 79 | } | ||
380 | 80 | } | ||
381 | 81 | |||
382 | 82 | // Inform the player, that we are under attack by adding a new entry to the | ||
383 | 83 | // message queue - a sound will automatically be played. | ||
384 | 84 | military_site_->notify_player(game, true); | ||
385 | 85 | } | ||
386 | 86 | |||
387 | 87 | AttackTarget::AttackResult MilitarySite::AttackTarget::attack(Soldier* enemy) const { | ||
388 | 88 | Game& game = dynamic_cast<Game&>(military_site_->owner().egbase()); | ||
389 | 89 | |||
390 | 90 | std::vector<Soldier*> present = military_site_->present_soldiers(); | ||
391 | 91 | Soldier* defender = nullptr; | ||
392 | 92 | |||
393 | 93 | if (!present.empty()) { | ||
394 | 94 | // Find soldier with greatest health | ||
395 | 95 | uint32_t current_max = 0; | ||
396 | 96 | for (Soldier* temp_soldier : present) { | ||
397 | 97 | if (temp_soldier->get_current_health() > current_max) { | ||
398 | 98 | defender = temp_soldier; | ||
399 | 99 | current_max = defender->get_current_health(); | ||
400 | 100 | } | ||
401 | 101 | } | ||
402 | 102 | } else { | ||
403 | 103 | // If one of our stationed soldiers is currently walking into the | ||
404 | 104 | // building, give us another chance. | ||
405 | 105 | std::vector<Soldier*> stationed = military_site_->stationed_soldiers(); | ||
406 | 106 | for (Soldier* temp_soldier : stationed) { | ||
407 | 107 | if (temp_soldier->get_position() == military_site_->get_position()) { | ||
408 | 108 | defender = temp_soldier; | ||
409 | 109 | break; | ||
410 | 110 | } | ||
411 | 111 | } | ||
412 | 112 | } | ||
413 | 113 | |||
414 | 114 | if (defender) { | ||
415 | 115 | military_site_->pop_soldier_job(defender); // defense overrides all other jobs | ||
416 | 116 | |||
417 | 117 | SoldierJob sj; | ||
418 | 118 | sj.soldier = defender; | ||
419 | 119 | sj.enemy = enemy; | ||
420 | 120 | sj.stayhome = true; | ||
421 | 121 | military_site_->soldierjobs_.push_back(sj); | ||
422 | 122 | |||
423 | 123 | defender->update_task_buildingwork(game); | ||
424 | 124 | |||
425 | 125 | // Inform the player, that we are under attack by adding a new entry to | ||
426 | 126 | // the message queue - a sound will automatically be played. | ||
427 | 127 | military_site_->notify_player(game); | ||
428 | 128 | |||
429 | 129 | return AttackTarget::AttackResult::DefenderLaunched; | ||
430 | 130 | } | ||
431 | 131 | |||
432 | 132 | // The enemy has defeated our forces, we should inform the player | ||
433 | 133 | const Coords coords = military_site_->get_position(); | ||
434 | 134 | { | ||
435 | 135 | military_site_->send_message(game, Message::Type::kWarfareSiteLost, | ||
436 | 136 | /** TRANSLATORS: Militarysite lost (taken/destroyed by enemy) */ | ||
437 | 137 | pgettext("building", "Lost!"), | ||
438 | 138 | military_site_->descr().icon_filename(), _("Militarysite lost!"), | ||
439 | 139 | military_site_->descr().defeated_enemy_str_, false); | ||
440 | 140 | } | ||
441 | 141 | |||
442 | 142 | // Now let's see whether the enemy conquers our militarysite, or whether | ||
443 | 143 | // we still hold the bigger military presence in that area (e.g. if there | ||
444 | 144 | // is a fortress one or two points away from our sentry, the fortress has | ||
445 | 145 | // a higher presence and thus the enemy can just burn down the sentry. | ||
446 | 146 | if (military_site_->military_presence_kept(game)) { | ||
447 | 147 | // Okay we still got the higher military presence, so the attacked | ||
448 | 148 | // militarysite will be destroyed. | ||
449 | 149 | military_site_->set_defeating_player(enemy->owner().player_number()); | ||
450 | 150 | military_site_->schedule_destroy(game); | ||
451 | 151 | return AttackTarget::AttackResult::Defenseless; | ||
452 | 152 | } | ||
453 | 153 | |||
454 | 154 | // The enemy conquers the building | ||
455 | 155 | // In fact we do not conquer it, but place a new building of same type at | ||
456 | 156 | // the old location. | ||
457 | 157 | |||
458 | 158 | Building::FormerBuildings former_buildings = military_site_->old_buildings_; | ||
459 | 159 | |||
460 | 160 | // The enemy conquers the building | ||
461 | 161 | // In fact we do not conquer it, but place a new building of same type at | ||
462 | 162 | // the old location. | ||
463 | 163 | Player* enemyplayer = enemy->get_owner(); | ||
464 | 164 | |||
465 | 165 | // Now we destroy the old building before we place the new one. | ||
466 | 166 | military_site_->set_defeating_player(enemyplayer->player_number()); | ||
467 | 167 | military_site_->schedule_destroy(game); | ||
468 | 168 | |||
469 | 169 | enemyplayer->force_building(coords, former_buildings); | ||
470 | 170 | BaseImmovable* const newimm = game.map()[coords].get_immovable(); | ||
471 | 171 | upcast(MilitarySite, newsite, newimm); | ||
472 | 172 | newsite->reinit_after_conqueration(game); | ||
473 | 173 | |||
474 | 174 | // Of course we should inform the victorious player as well | ||
475 | 175 | newsite->send_message( | ||
476 | 176 | game, Message::Type::kWarfareSiteDefeated, | ||
477 | 177 | /** TRANSLATORS: Message title. */ | ||
478 | 178 | /** TRANSLATORS: If you run out of space, you can also translate this as "Success!" */ | ||
479 | 179 | _("Enemy Defeated!"), newsite->descr().icon_filename(), _("Enemy at site defeated!"), | ||
480 | 180 | newsite->descr().defeated_you_str_, true); | ||
481 | 181 | |||
482 | 182 | return AttackTarget::AttackResult::Defenseless; | ||
483 | 183 | } | ||
484 | 184 | |||
485 | 46 | /** | 185 | /** |
486 | 47 | * The contents of 'table' are documented in | 186 | * The contents of 'table' are documented in |
487 | 48 | * /data/tribes/buildings/militarysites/atlanteans/castle/init.lua | 187 | * /data/tribes/buildings/militarysites/atlanteans/castle/init.lua |
488 | @@ -91,6 +230,7 @@ | |||
489 | 91 | 230 | ||
490 | 92 | MilitarySite::MilitarySite(const MilitarySiteDescr& ms_descr) | 231 | MilitarySite::MilitarySite(const MilitarySiteDescr& ms_descr) |
491 | 93 | : Building(ms_descr), | 232 | : Building(ms_descr), |
492 | 233 | attack_target_(this), | ||
493 | 94 | didconquer_(false), | 234 | didconquer_(false), |
494 | 95 | capacity_(ms_descr.get_max_number_of_soldiers()), | 235 | capacity_(ms_descr.get_max_number_of_soldiers()), |
495 | 96 | nexthealtime_(0), | 236 | nexthealtime_(0), |
496 | @@ -98,6 +238,7 @@ | |||
497 | 98 | soldier_upgrade_try_(false), | 238 | soldier_upgrade_try_(false), |
498 | 99 | doing_upgrade_request_(false) { | 239 | doing_upgrade_request_(false) { |
499 | 100 | next_swap_soldiers_time_ = 0; | 240 | next_swap_soldiers_time_ = 0; |
500 | 241 | set_attack_target(&attack_target_); | ||
501 | 101 | } | 242 | } |
502 | 102 | 243 | ||
503 | 103 | MilitarySite::~MilitarySite() { | 244 | MilitarySite::~MilitarySite() { |
504 | @@ -684,142 +825,6 @@ | |||
505 | 684 | didconquer_ = true; | 825 | didconquer_ = true; |
506 | 685 | } | 826 | } |
507 | 686 | 827 | ||
508 | 687 | bool MilitarySite::can_attack() { | ||
509 | 688 | return didconquer_; | ||
510 | 689 | } | ||
511 | 690 | |||
512 | 691 | void MilitarySite::aggressor(Soldier& enemy) { | ||
513 | 692 | Game& game = dynamic_cast<Game&>(owner().egbase()); | ||
514 | 693 | Map& map = game.map(); | ||
515 | 694 | if (enemy.get_owner() == &owner() || enemy.get_battle() || | ||
516 | 695 | descr().get_conquers() <= map.calc_distance(enemy.get_position(), get_position())) | ||
517 | 696 | return; | ||
518 | 697 | |||
519 | 698 | if (map.find_bobs(Area<FCoords>(map.get_fcoords(base_flag().get_position()), 2), nullptr, | ||
520 | 699 | FindBobEnemySoldier(&owner()))) | ||
521 | 700 | return; | ||
522 | 701 | |||
523 | 702 | // We're dealing with a soldier that we might want to keep busy | ||
524 | 703 | // Now would be the time to implement some player-definable | ||
525 | 704 | // policy as to how many soldiers are allowed to leave as defenders | ||
526 | 705 | std::vector<Soldier*> present = present_soldiers(); | ||
527 | 706 | |||
528 | 707 | if (1 < present.size()) { | ||
529 | 708 | for (Soldier* temp_soldier : present) { | ||
530 | 709 | if (!has_soldier_job(*temp_soldier)) { | ||
531 | 710 | SoldierJob sj; | ||
532 | 711 | sj.soldier = temp_soldier; | ||
533 | 712 | sj.enemy = &enemy; | ||
534 | 713 | sj.stayhome = false; | ||
535 | 714 | soldierjobs_.push_back(sj); | ||
536 | 715 | temp_soldier->update_task_buildingwork(game); | ||
537 | 716 | return; | ||
538 | 717 | } | ||
539 | 718 | } | ||
540 | 719 | } | ||
541 | 720 | |||
542 | 721 | // Inform the player, that we are under attack by adding a new entry to the | ||
543 | 722 | // message queue - a sound will automatically be played. | ||
544 | 723 | notify_player(game, true); | ||
545 | 724 | } | ||
546 | 725 | |||
547 | 726 | bool MilitarySite::attack(Soldier& enemy) { | ||
548 | 727 | Game& game = dynamic_cast<Game&>(owner().egbase()); | ||
549 | 728 | |||
550 | 729 | std::vector<Soldier*> present = present_soldiers(); | ||
551 | 730 | Soldier* defender = nullptr; | ||
552 | 731 | |||
553 | 732 | if (!present.empty()) { | ||
554 | 733 | // Find soldier with greatest health | ||
555 | 734 | uint32_t current_max = 0; | ||
556 | 735 | for (Soldier* temp_soldier : present) { | ||
557 | 736 | if (temp_soldier->get_current_health() > current_max) { | ||
558 | 737 | defender = temp_soldier; | ||
559 | 738 | current_max = defender->get_current_health(); | ||
560 | 739 | } | ||
561 | 740 | } | ||
562 | 741 | } else { | ||
563 | 742 | // If one of our stationed soldiers is currently walking into the | ||
564 | 743 | // building, give us another chance. | ||
565 | 744 | std::vector<Soldier*> stationed = stationed_soldiers(); | ||
566 | 745 | for (Soldier* temp_soldier : stationed) { | ||
567 | 746 | if (temp_soldier->get_position() == get_position()) { | ||
568 | 747 | defender = temp_soldier; | ||
569 | 748 | break; | ||
570 | 749 | } | ||
571 | 750 | } | ||
572 | 751 | } | ||
573 | 752 | |||
574 | 753 | if (defender) { | ||
575 | 754 | pop_soldier_job(defender); // defense overrides all other jobs | ||
576 | 755 | |||
577 | 756 | SoldierJob sj; | ||
578 | 757 | sj.soldier = defender; | ||
579 | 758 | sj.enemy = &enemy; | ||
580 | 759 | sj.stayhome = true; | ||
581 | 760 | soldierjobs_.push_back(sj); | ||
582 | 761 | |||
583 | 762 | defender->update_task_buildingwork(game); | ||
584 | 763 | |||
585 | 764 | // Inform the player, that we are under attack by adding a new entry to | ||
586 | 765 | // the message queue - a sound will automatically be played. | ||
587 | 766 | notify_player(game); | ||
588 | 767 | |||
589 | 768 | return true; | ||
590 | 769 | } else { | ||
591 | 770 | // The enemy has defeated our forces, we should inform the player | ||
592 | 771 | const Coords coords = get_position(); | ||
593 | 772 | { | ||
594 | 773 | send_message(game, Message::Type::kWarfareSiteLost, | ||
595 | 774 | /** TRANSLATORS: Militarysite lost (taken/destroyed by enemy) */ | ||
596 | 775 | pgettext("building", "Lost!"), descr().icon_filename(), | ||
597 | 776 | _("Militarysite lost!"), descr().defeated_enemy_str_, false); | ||
598 | 777 | } | ||
599 | 778 | |||
600 | 779 | // Now let's see whether the enemy conquers our militarysite, or whether | ||
601 | 780 | // we still hold the bigger military presence in that area (e.g. if there | ||
602 | 781 | // is a fortress one or two points away from our sentry, the fortress has | ||
603 | 782 | // a higher presence and thus the enemy can just burn down the sentry. | ||
604 | 783 | if (military_presence_kept(game)) { | ||
605 | 784 | // Okay we still got the higher military presence, so the attacked | ||
606 | 785 | // militarysite will be destroyed. | ||
607 | 786 | set_defeating_player(enemy.owner().player_number()); | ||
608 | 787 | schedule_destroy(game); | ||
609 | 788 | return false; | ||
610 | 789 | } | ||
611 | 790 | |||
612 | 791 | // The enemy conquers the building | ||
613 | 792 | // In fact we do not conquer it, but place a new building of same type at | ||
614 | 793 | // the old location. | ||
615 | 794 | |||
616 | 795 | Building::FormerBuildings former_buildings = old_buildings_; | ||
617 | 796 | |||
618 | 797 | // The enemy conquers the building | ||
619 | 798 | // In fact we do not conquer it, but place a new building of same type at | ||
620 | 799 | // the old location. | ||
621 | 800 | Player* enemyplayer = enemy.get_owner(); | ||
622 | 801 | |||
623 | 802 | // Now we destroy the old building before we place the new one. | ||
624 | 803 | set_defeating_player(enemyplayer->player_number()); | ||
625 | 804 | schedule_destroy(game); | ||
626 | 805 | |||
627 | 806 | enemyplayer->force_building(coords, former_buildings); | ||
628 | 807 | BaseImmovable* const newimm = game.map()[coords].get_immovable(); | ||
629 | 808 | upcast(MilitarySite, newsite, newimm); | ||
630 | 809 | newsite->reinit_after_conqueration(game); | ||
631 | 810 | |||
632 | 811 | // Of course we should inform the victorious player as well | ||
633 | 812 | newsite->send_message( | ||
634 | 813 | game, Message::Type::kWarfareSiteDefeated, | ||
635 | 814 | /** TRANSLATORS: Message title. */ | ||
636 | 815 | /** TRANSLATORS: If you run out of space, you can also translate this as "Success!" */ | ||
637 | 816 | _("Enemy Defeated!"), newsite->descr().icon_filename(), _("Enemy at site defeated!"), | ||
638 | 817 | newsite->descr().defeated_you_str_, true); | ||
639 | 818 | |||
640 | 819 | return false; | ||
641 | 820 | } | ||
642 | 821 | } | ||
643 | 822 | |||
644 | 823 | /// Initialises the militarysite after it was "conquered" (the old was replaced) | 828 | /// Initialises the militarysite after it was "conquered" (the old was replaced) |
645 | 824 | void MilitarySite::reinit_after_conqueration(Game& game) { | 829 | void MilitarySite::reinit_after_conqueration(Game& game) { |
646 | 825 | clear_requirements(); | 830 | clear_requirements(); |
647 | 826 | 831 | ||
648 | === modified file 'src/logic/map_objects/tribes/militarysite.h' | |||
649 | --- src/logic/map_objects/tribes/militarysite.h 2017-04-23 12:11:19 +0000 | |||
650 | +++ src/logic/map_objects/tribes/militarysite.h 2017-05-21 11:20:39 +0000 | |||
651 | @@ -24,7 +24,6 @@ | |||
652 | 24 | 24 | ||
653 | 25 | #include "base/macros.h" | 25 | #include "base/macros.h" |
654 | 26 | #include "economy/request.h" | 26 | #include "economy/request.h" |
655 | 27 | #include "logic/map_objects/attackable.h" | ||
656 | 28 | #include "logic/map_objects/tribes/building.h" | 27 | #include "logic/map_objects/tribes/building.h" |
657 | 29 | #include "logic/map_objects/tribes/requirements.h" | 28 | #include "logic/map_objects/tribes/requirements.h" |
658 | 30 | #include "logic/map_objects/tribes/soldiercontrol.h" | 29 | #include "logic/map_objects/tribes/soldiercontrol.h" |
659 | @@ -69,7 +68,7 @@ | |||
660 | 69 | DISALLOW_COPY_AND_ASSIGN(MilitarySiteDescr); | 68 | DISALLOW_COPY_AND_ASSIGN(MilitarySiteDescr); |
661 | 70 | }; | 69 | }; |
662 | 71 | 70 | ||
664 | 72 | class MilitarySite : public Building, public SoldierControl, public Attackable { | 71 | class MilitarySite : public Building, public SoldierControl { |
665 | 73 | friend class MapBuildingdataPacket; | 72 | friend class MapBuildingdataPacket; |
666 | 74 | MO_DESCR(MilitarySiteDescr) | 73 | MO_DESCR(MilitarySiteDescr) |
667 | 75 | 74 | ||
668 | @@ -102,15 +101,6 @@ | |||
669 | 102 | void drop_soldier(Soldier&) override; | 101 | void drop_soldier(Soldier&) override; |
670 | 103 | int incorporate_soldier(EditorGameBase& game, Soldier& s) override; | 102 | int incorporate_soldier(EditorGameBase& game, Soldier& s) override; |
671 | 104 | 103 | ||
672 | 105 | // Begin implementation of Attackable | ||
673 | 106 | Player& owner() const override { | ||
674 | 107 | return Building::owner(); | ||
675 | 108 | } | ||
676 | 109 | bool can_attack() override; | ||
677 | 110 | void aggressor(Soldier&) override; | ||
678 | 111 | bool attack(Soldier&) override; | ||
679 | 112 | // End implementation of Attackable | ||
680 | 113 | |||
681 | 114 | /// Launch the given soldier on an attack towards the given | 104 | /// Launch the given soldier on an attack towards the given |
682 | 115 | /// target building. | 105 | /// target building. |
683 | 116 | void send_attacker(Soldier&, Building&); | 106 | void send_attacker(Soldier&, Building&); |
684 | @@ -153,6 +143,21 @@ | |||
685 | 153 | bool drop_least_suited_soldier(bool new_has_arrived, Soldier* s); | 143 | bool drop_least_suited_soldier(bool new_has_arrived, Soldier* s); |
686 | 154 | 144 | ||
687 | 155 | private: | 145 | private: |
688 | 146 | // We can be attacked if we have stationed soldiers. | ||
689 | 147 | class AttackTarget : public Widelands::AttackTarget { | ||
690 | 148 | public: | ||
691 | 149 | explicit AttackTarget(MilitarySite* military_site) : military_site_(military_site) { | ||
692 | 150 | } | ||
693 | 151 | |||
694 | 152 | bool can_be_attacked() const override; | ||
695 | 153 | void enemy_soldier_approaches(const Soldier&) const override; | ||
696 | 154 | Widelands::AttackTarget::AttackResult attack(Soldier*) const override; | ||
697 | 155 | |||
698 | 156 | private: | ||
699 | 157 | MilitarySite* const military_site_; | ||
700 | 158 | }; | ||
701 | 159 | |||
702 | 160 | AttackTarget attack_target_; | ||
703 | 156 | Requirements soldier_requirements_; // This is used to grab a bunch of soldiers: Anything goes | 161 | Requirements soldier_requirements_; // This is used to grab a bunch of soldiers: Anything goes |
704 | 157 | RequireAttribute soldier_upgrade_requirements_; // This is used when exchanging soldiers. | 162 | RequireAttribute soldier_upgrade_requirements_; // This is used when exchanging soldiers. |
705 | 158 | std::unique_ptr<Request> normal_soldier_request_; // filling the site | 163 | std::unique_ptr<Request> normal_soldier_request_; // filling the site |
706 | 159 | 164 | ||
707 | === modified file 'src/logic/map_objects/tribes/soldier.cc' | |||
708 | --- src/logic/map_objects/tribes/soldier.cc 2017-05-13 18:48:26 +0000 | |||
709 | +++ src/logic/map_objects/tribes/soldier.cc 2017-05-21 11:20:39 +0000 | |||
710 | @@ -42,7 +42,6 @@ | |||
711 | 42 | #include "logic/game.h" | 42 | #include "logic/game.h" |
712 | 43 | #include "logic/game_controller.h" | 43 | #include "logic/game_controller.h" |
713 | 44 | #include "logic/game_data_error.h" | 44 | #include "logic/game_data_error.h" |
714 | 45 | #include "logic/map_objects/attackable.h" | ||
715 | 46 | #include "logic/map_objects/checkstep.h" | 45 | #include "logic/map_objects/checkstep.h" |
716 | 47 | #include "logic/map_objects/tribes/battle.h" | 46 | #include "logic/map_objects/tribes/battle.h" |
717 | 48 | #include "logic/map_objects/tribes/building.h" | 47 | #include "logic/map_objects/tribes/building.h" |
718 | @@ -602,7 +601,7 @@ | |||
719 | 602 | return false; | 601 | return false; |
720 | 603 | } | 602 | } |
721 | 604 | 603 | ||
723 | 605 | Battle* Soldier::get_battle() { | 604 | Battle* Soldier::get_battle() const { |
724 | 606 | return battle_; | 605 | return battle_; |
725 | 607 | } | 606 | } |
726 | 608 | 607 | ||
727 | @@ -902,12 +901,14 @@ | |||
728 | 902 | } | 901 | } |
729 | 903 | } | 902 | } |
730 | 904 | 903 | ||
733 | 905 | upcast(Attackable, attackable, enemy); | 904 | assert(enemy->attack_target() != nullptr); |
732 | 906 | assert(attackable); | ||
734 | 907 | 905 | ||
735 | 908 | molog("[attack] attacking target building\n"); | 906 | molog("[attack] attacking target building\n"); |
736 | 909 | // give the enemy soldier some time to act | 907 | // give the enemy soldier some time to act |
738 | 910 | schedule_act(game, attackable->attack(*this) ? 1000 : 10); | 908 | schedule_act( |
739 | 909 | game, enemy->attack_target()->attack(this) == AttackTarget::AttackResult::DefenderLaunched ? | ||
740 | 910 | 1000 : | ||
741 | 911 | 10); | ||
742 | 911 | } | 912 | } |
743 | 912 | 913 | ||
744 | 913 | void Soldier::attack_pop(Game& game, State&) { | 914 | void Soldier::attack_pop(Game& game, State&) { |
745 | @@ -1520,20 +1521,21 @@ | |||
746 | 1520 | PlayerNumber const land_owner = get_position().field->get_owned_by(); | 1521 | PlayerNumber const land_owner = get_position().field->get_owned_by(); |
747 | 1521 | // First check if the soldier is standing on someone else's territory | 1522 | // First check if the soldier is standing on someone else's territory |
748 | 1522 | if (land_owner != owner().player_number()) { | 1523 | if (land_owner != owner().player_number()) { |
751 | 1523 | // Let's collect all reachable attackable sites in vicinity (militarysites mainly) | 1524 | // Let's collect all reachable attack_target sites in vicinity (militarysites mainly) |
752 | 1524 | std::vector<BaseImmovable*> attackables; | 1525 | std::vector<BaseImmovable*> attack_targets; |
753 | 1525 | game.map().find_reachable_immovables_unique( | 1526 | game.map().find_reachable_immovables_unique( |
756 | 1526 | Area<FCoords>(get_position(), MaxProtectionRadius), attackables, | 1527 | Area<FCoords>(get_position(), kMaxProtectionRadius), attack_targets, |
757 | 1527 | CheckStepWalkOn(descr().movecaps(), false), FindImmovableAttackable()); | 1528 | CheckStepWalkOn(descr().movecaps(), false), FindImmovableAttackTarget()); |
758 | 1528 | 1529 | ||
762 | 1529 | for (BaseImmovable* temp_attackable : attackables) { | 1530 | for (BaseImmovable* temp_attack_target : attack_targets) { |
763 | 1530 | const Player* attackable_player = | 1531 | Building* building = dynamic_cast<Building*>(temp_attack_target); |
764 | 1531 | dynamic_cast<const PlayerImmovable&>(*temp_attackable).get_owner(); | 1532 | assert(building != nullptr && building->attack_target() != nullptr); |
765 | 1533 | const Player& attack_target_player = building->owner(); | ||
766 | 1532 | // Let's inform the site that this (=enemy) soldier is nearby and within the site's owner's | 1534 | // Let's inform the site that this (=enemy) soldier is nearby and within the site's owner's |
767 | 1533 | // territory | 1535 | // territory |
771 | 1534 | if (attackable_player->player_number() == land_owner && | 1536 | if (attack_target_player.player_number() == land_owner && |
772 | 1535 | attackable_player->is_hostile(*get_owner())) { | 1537 | attack_target_player.is_hostile(*get_owner())) { |
773 | 1536 | dynamic_cast<Attackable&>(*temp_attackable).aggressor(*this); | 1538 | building->attack_target()->enemy_soldier_approaches(*this); |
774 | 1537 | } | 1539 | } |
775 | 1538 | } | 1540 | } |
776 | 1539 | } | 1541 | } |
777 | 1540 | 1542 | ||
778 | === modified file 'src/logic/map_objects/tribes/soldier.h' | |||
779 | --- src/logic/map_objects/tribes/soldier.h 2017-05-13 13:14:29 +0000 | |||
780 | +++ src/logic/map_objects/tribes/soldier.h 2017-05-21 11:20:39 +0000 | |||
781 | @@ -262,7 +262,7 @@ | |||
782 | 262 | 262 | ||
783 | 263 | bool is_on_battlefield(); | 263 | bool is_on_battlefield(); |
784 | 264 | bool is_attacking_player(Game&, Player&); | 264 | bool is_attacking_player(Game&, Player&); |
786 | 265 | Battle* get_battle(); | 265 | Battle* get_battle() const; |
787 | 266 | bool can_be_challenged(); | 266 | bool can_be_challenged(); |
788 | 267 | bool check_node_blocked(Game&, const FCoords&, bool commit) override; | 267 | bool check_node_blocked(Game&, const FCoords&, bool commit) override; |
789 | 268 | 268 | ||
790 | 269 | 269 | ||
791 | === modified file 'src/logic/map_objects/tribes/warehouse.cc' | |||
792 | --- src/logic/map_objects/tribes/warehouse.cc 2017-05-03 10:34:46 +0000 | |||
793 | +++ src/logic/map_objects/tribes/warehouse.cc 2017-05-21 11:20:39 +0000 | |||
794 | @@ -69,6 +69,57 @@ | |||
795 | 69 | 69 | ||
796 | 70 | } // namespace | 70 | } // namespace |
797 | 71 | 71 | ||
798 | 72 | bool Warehouse::AttackTarget::can_be_attacked() const { | ||
799 | 73 | return warehouse_->descr().get_conquers() > 0; | ||
800 | 74 | } | ||
801 | 75 | |||
802 | 76 | void Warehouse::AttackTarget::enemy_soldier_approaches(const Soldier& enemy) const { | ||
803 | 77 | if (!warehouse_->descr().get_conquers()) | ||
804 | 78 | return; | ||
805 | 79 | |||
806 | 80 | Player& owner = warehouse_->owner(); | ||
807 | 81 | Game& game = dynamic_cast<Game&>(owner.egbase()); | ||
808 | 82 | Map& map = game.map(); | ||
809 | 83 | if (enemy.get_owner() == &owner || enemy.get_battle() || | ||
810 | 84 | warehouse_->descr().get_conquers() <= | ||
811 | 85 | map.calc_distance(enemy.get_position(), warehouse_->get_position())) | ||
812 | 86 | return; | ||
813 | 87 | |||
814 | 88 | if (game.map().find_bobs( | ||
815 | 89 | Area<FCoords>(map.get_fcoords(warehouse_->base_flag().get_position()), 2), nullptr, | ||
816 | 90 | FindBobEnemySoldier(&owner))) | ||
817 | 91 | return; | ||
818 | 92 | |||
819 | 93 | DescriptionIndex const soldier_index = owner.tribe().soldier(); | ||
820 | 94 | Requirements noreq; | ||
821 | 95 | |||
822 | 96 | if (!warehouse_->count_workers(game, soldier_index, noreq, Match::kCompatible)) | ||
823 | 97 | return; | ||
824 | 98 | |||
825 | 99 | Soldier& defender = | ||
826 | 100 | dynamic_cast<Soldier&>(warehouse_->launch_worker(game, soldier_index, noreq)); | ||
827 | 101 | defender.start_task_defense(game, false); | ||
828 | 102 | } | ||
829 | 103 | |||
830 | 104 | AttackTarget::AttackResult Warehouse::AttackTarget::attack(Soldier* enemy) const { | ||
831 | 105 | Player& owner = warehouse_->owner(); | ||
832 | 106 | Game& game = dynamic_cast<Game&>(owner.egbase()); | ||
833 | 107 | DescriptionIndex const soldier_index = owner.tribe().soldier(); | ||
834 | 108 | Requirements noreq; | ||
835 | 109 | |||
836 | 110 | if (warehouse_->count_workers(game, soldier_index, noreq, Match::kCompatible)) { | ||
837 | 111 | Soldier& defender = | ||
838 | 112 | dynamic_cast<Soldier&>(warehouse_->launch_worker(game, soldier_index, noreq)); | ||
839 | 113 | defender.start_task_defense(game, true); | ||
840 | 114 | enemy->send_signal(game, "sleep"); | ||
841 | 115 | return AttackTarget::AttackResult::DefenderLaunched; | ||
842 | 116 | } | ||
843 | 117 | |||
844 | 118 | warehouse_->set_defeating_player(enemy->owner().player_number()); | ||
845 | 119 | warehouse_->schedule_destroy(game); | ||
846 | 120 | return AttackTarget::AttackResult::Defenseless; | ||
847 | 121 | } | ||
848 | 122 | |||
849 | 72 | WarehouseSupply::~WarehouseSupply() { | 123 | WarehouseSupply::~WarehouseSupply() { |
850 | 73 | if (economy_) { | 124 | if (economy_) { |
851 | 74 | log("WarehouseSupply::~WarehouseSupply: Warehouse %u still belongs to " | 125 | log("WarehouseSupply::~WarehouseSupply: Warehouse %u still belongs to " |
852 | @@ -260,11 +311,13 @@ | |||
853 | 260 | 311 | ||
854 | 261 | Warehouse::Warehouse(const WarehouseDescr& warehouse_descr) | 312 | Warehouse::Warehouse(const WarehouseDescr& warehouse_descr) |
855 | 262 | : Building(warehouse_descr), | 313 | : Building(warehouse_descr), |
856 | 314 | attack_target_(this), | ||
857 | 263 | supply_(new WarehouseSupply(this)), | 315 | supply_(new WarehouseSupply(this)), |
858 | 264 | next_military_act_(0), | 316 | next_military_act_(0), |
859 | 265 | portdock_(nullptr) { | 317 | portdock_(nullptr) { |
860 | 266 | next_stock_remove_act_ = 0; | 318 | next_stock_remove_act_ = 0; |
861 | 267 | cleanup_in_progress_ = false; | 319 | cleanup_in_progress_ = false; |
862 | 320 | set_attack_target(&attack_target_); | ||
863 | 268 | } | 321 | } |
864 | 269 | 322 | ||
865 | 270 | Warehouse::~Warehouse() { | 323 | Warehouse::~Warehouse() { |
866 | @@ -1165,51 +1218,6 @@ | |||
867 | 1165 | next_worker_without_cost_spawn_[worker_types_without_cost_index] = never(); | 1218 | next_worker_without_cost_spawn_[worker_types_without_cost_index] = never(); |
868 | 1166 | } | 1219 | } |
869 | 1167 | 1220 | ||
870 | 1168 | bool Warehouse::can_attack() { | ||
871 | 1169 | return descr().get_conquers() > 0; | ||
872 | 1170 | } | ||
873 | 1171 | |||
874 | 1172 | void Warehouse::aggressor(Soldier& enemy) { | ||
875 | 1173 | if (!descr().get_conquers()) | ||
876 | 1174 | return; | ||
877 | 1175 | |||
878 | 1176 | Game& game = dynamic_cast<Game&>(owner().egbase()); | ||
879 | 1177 | Map& map = game.map(); | ||
880 | 1178 | if (enemy.get_owner() == &owner() || enemy.get_battle() || | ||
881 | 1179 | descr().get_conquers() <= map.calc_distance(enemy.get_position(), get_position())) | ||
882 | 1180 | return; | ||
883 | 1181 | |||
884 | 1182 | if (game.map().find_bobs(Area<FCoords>(map.get_fcoords(base_flag().get_position()), 2), nullptr, | ||
885 | 1183 | FindBobEnemySoldier(&owner()))) | ||
886 | 1184 | return; | ||
887 | 1185 | |||
888 | 1186 | DescriptionIndex const soldier_index = owner().tribe().soldier(); | ||
889 | 1187 | Requirements noreq; | ||
890 | 1188 | |||
891 | 1189 | if (!count_workers(game, soldier_index, noreq, Match::kCompatible)) | ||
892 | 1190 | return; | ||
893 | 1191 | |||
894 | 1192 | Soldier& defender = dynamic_cast<Soldier&>(launch_worker(game, soldier_index, noreq)); | ||
895 | 1193 | defender.start_task_defense(game, false); | ||
896 | 1194 | } | ||
897 | 1195 | |||
898 | 1196 | bool Warehouse::attack(Soldier& enemy) { | ||
899 | 1197 | Game& game = dynamic_cast<Game&>(owner().egbase()); | ||
900 | 1198 | DescriptionIndex const soldier_index = owner().tribe().soldier(); | ||
901 | 1199 | Requirements noreq; | ||
902 | 1200 | |||
903 | 1201 | if (count_workers(game, soldier_index, noreq, Match::kCompatible)) { | ||
904 | 1202 | Soldier& defender = dynamic_cast<Soldier&>(launch_worker(game, soldier_index, noreq)); | ||
905 | 1203 | defender.start_task_defense(game, true); | ||
906 | 1204 | enemy.send_signal(game, "sleep"); | ||
907 | 1205 | return true; | ||
908 | 1206 | } | ||
909 | 1207 | |||
910 | 1208 | set_defeating_player(enemy.owner().player_number()); | ||
911 | 1209 | schedule_destroy(game); | ||
912 | 1210 | return false; | ||
913 | 1211 | } | ||
914 | 1212 | |||
915 | 1213 | void Warehouse::PlannedWorkers::cleanup() { | 1221 | void Warehouse::PlannedWorkers::cleanup() { |
916 | 1214 | while (!requests.empty()) { | 1222 | while (!requests.empty()) { |
917 | 1215 | delete requests.back(); | 1223 | delete requests.back(); |
918 | 1216 | 1224 | ||
919 | === modified file 'src/logic/map_objects/tribes/warehouse.h' | |||
920 | --- src/logic/map_objects/tribes/warehouse.h 2017-04-23 12:11:19 +0000 | |||
921 | +++ src/logic/map_objects/tribes/warehouse.h 2017-05-21 11:20:39 +0000 | |||
922 | @@ -24,7 +24,6 @@ | |||
923 | 24 | #include "base/wexception.h" | 24 | #include "base/wexception.h" |
924 | 25 | #include "economy/request.h" | 25 | #include "economy/request.h" |
925 | 26 | #include "economy/wares_queue.h" | 26 | #include "economy/wares_queue.h" |
926 | 27 | #include "logic/map_objects/attackable.h" | ||
927 | 28 | #include "logic/map_objects/tribes/building.h" | 27 | #include "logic/map_objects/tribes/building.h" |
928 | 29 | #include "logic/map_objects/tribes/soldiercontrol.h" | 28 | #include "logic/map_objects/tribes/soldiercontrol.h" |
929 | 30 | #include "logic/map_objects/tribes/wareworker.h" | 29 | #include "logic/map_objects/tribes/wareworker.h" |
930 | @@ -71,7 +70,7 @@ | |||
931 | 71 | DISALLOW_COPY_AND_ASSIGN(WarehouseDescr); | 70 | DISALLOW_COPY_AND_ASSIGN(WarehouseDescr); |
932 | 72 | }; | 71 | }; |
933 | 73 | 72 | ||
935 | 74 | class Warehouse : public Building, public Attackable, public SoldierControl { | 73 | class Warehouse : public Building, public SoldierControl { |
936 | 75 | friend class PortDock; | 74 | friend class PortDock; |
937 | 76 | friend class MapBuildingdataPacket; | 75 | friend class MapBuildingdataPacket; |
938 | 77 | 76 | ||
939 | @@ -221,15 +220,6 @@ | |||
940 | 221 | void enable_spawn(Game&, uint8_t worker_types_without_cost_index); | 220 | void enable_spawn(Game&, uint8_t worker_types_without_cost_index); |
941 | 222 | void disable_spawn(uint8_t worker_types_without_cost_index); | 221 | void disable_spawn(uint8_t worker_types_without_cost_index); |
942 | 223 | 222 | ||
943 | 224 | // Begin Attackable implementation | ||
944 | 225 | Player& owner() const override { | ||
945 | 226 | return Building::owner(); | ||
946 | 227 | } | ||
947 | 228 | bool can_attack() override; | ||
948 | 229 | void aggressor(Soldier&) override; | ||
949 | 230 | bool attack(Soldier&) override; | ||
950 | 231 | // End Attackable implementation | ||
951 | 232 | |||
952 | 233 | void receive_ware(Game&, DescriptionIndex ware) override; | 223 | void receive_ware(Game&, DescriptionIndex ware) override; |
953 | 234 | void receive_worker(Game&, Worker& worker) override; | 224 | void receive_worker(Game&, Worker& worker) override; |
954 | 235 | 225 | ||
955 | @@ -250,13 +240,26 @@ | |||
956 | 250 | 240 | ||
957 | 251 | void log_general_info(const EditorGameBase&) override; | 241 | void log_general_info(const EditorGameBase&) override; |
958 | 252 | 242 | ||
960 | 253 | protected: | 243 | private: |
961 | 244 | // A warehouse that conquers space can also be attacked. | ||
962 | 245 | class AttackTarget : public Widelands::AttackTarget { | ||
963 | 246 | public: | ||
964 | 247 | AttackTarget(Warehouse* warehouse) : warehouse_(warehouse) { | ||
965 | 248 | } | ||
966 | 249 | |||
967 | 250 | bool can_be_attacked() const override; | ||
968 | 251 | void enemy_soldier_approaches(const Soldier&) const override; | ||
969 | 252 | Widelands::AttackTarget::AttackResult attack(Soldier*) const override; | ||
970 | 253 | |||
971 | 254 | private: | ||
972 | 255 | Warehouse* const warehouse_; | ||
973 | 256 | }; | ||
974 | 257 | |||
975 | 258 | void init_portdock(EditorGameBase& egbase); | ||
976 | 259 | |||
977 | 254 | /// Initializes the container sizes for the owner's tribe. | 260 | /// Initializes the container sizes for the owner's tribe. |
978 | 255 | void init_containers(Player& owner); | 261 | void init_containers(Player& owner); |
979 | 256 | 262 | ||
980 | 257 | private: | ||
981 | 258 | void init_portdock(EditorGameBase& egbase); | ||
982 | 259 | |||
983 | 260 | /** | 263 | /** |
984 | 261 | * Plan to produce a certain worker type in this warehouse. This means | 264 | * Plan to produce a certain worker type in this warehouse. This means |
985 | 262 | * requesting all the necessary wares, if multiple different wares types are | 265 | * requesting all the necessary wares, if multiple different wares types are |
986 | @@ -282,6 +285,7 @@ | |||
987 | 282 | void update_planned_workers(Game&, PlannedWorkers& pw); | 285 | void update_planned_workers(Game&, PlannedWorkers& pw); |
988 | 283 | void update_all_planned_workers(Game&); | 286 | void update_all_planned_workers(Game&); |
989 | 284 | 287 | ||
990 | 288 | AttackTarget attack_target_; | ||
991 | 285 | WarehouseSupply* supply_; | 289 | WarehouseSupply* supply_; |
992 | 286 | 290 | ||
993 | 287 | std::vector<StockPolicy> ware_policy_; | 291 | std::vector<StockPolicy> ware_policy_; |
994 | 288 | 292 | ||
995 | === modified file 'src/logic/player.cc' | |||
996 | --- src/logic/player.cc 2017-04-22 05:35:46 +0000 | |||
997 | +++ src/logic/player.cc 2017-05-21 11:20:39 +0000 | |||
998 | @@ -452,8 +452,8 @@ | |||
999 | 452 | log("Clearing for road at (%i, %i)\n", c.x, c.y); | 452 | log("Clearing for road at (%i, %i)\n", c.x, c.y); |
1000 | 453 | 453 | ||
1001 | 454 | // Make sure that the player owns the area around. | 454 | // Make sure that the player owns the area around. |
1004 | 455 | dynamic_cast<Game&>(egbase()) | 455 | dynamic_cast<Game&>(egbase()).conquer_area_no_building( |
1005 | 456 | .conquer_area_no_building(PlayerArea<Area<FCoords>>(player_number(), Area<FCoords>(c, 1))); | 456 | PlayerArea<Area<FCoords>>(player_number(), Area<FCoords>(c, 1))); |
1006 | 457 | 457 | ||
1007 | 458 | if (BaseImmovable* const immovable = c.field->get_immovable()) { | 458 | if (BaseImmovable* const immovable = c.field->get_immovable()) { |
1008 | 459 | assert(immovable != &start); | 459 | assert(immovable != &start); |
1009 | @@ -869,8 +869,8 @@ | |||
1010 | 869 | log("enemyflagaction: count is 0\n"); | 869 | log("enemyflagaction: count is 0\n"); |
1011 | 870 | else if (is_hostile(flag.owner())) { | 870 | else if (is_hostile(flag.owner())) { |
1012 | 871 | if (Building* const building = flag.get_building()) { | 871 | if (Building* const building = flag.get_building()) { |
1015 | 872 | if (upcast(Attackable, attackable, building)) { | 872 | if (const AttackTarget* attack_target = building->attack_target()) { |
1016 | 873 | if (attackable->can_attack()) { | 873 | if (attack_target->can_be_attacked()) { |
1017 | 874 | std::vector<Soldier*> attackers; | 874 | std::vector<Soldier*> attackers; |
1018 | 875 | find_attack_soldiers(flag, &attackers, count); | 875 | find_attack_soldiers(flag, &attackers, count); |
1019 | 876 | assert(attackers.size() <= count); | 876 | assert(attackers.size() <= count); |
1020 | 877 | 877 | ||
1021 | === modified file 'src/wui/attack_box.h' | |||
1022 | --- src/wui/attack_box.h 2017-02-23 17:58:25 +0000 | |||
1023 | +++ src/wui/attack_box.h 2017-05-21 11:20:39 +0000 | |||
1024 | @@ -26,7 +26,6 @@ | |||
1025 | 26 | #include "graphic/font_handler1.h" | 26 | #include "graphic/font_handler1.h" |
1026 | 27 | #include "graphic/text/font_set.h" | 27 | #include "graphic/text/font_set.h" |
1027 | 28 | #include "graphic/text_constants.h" | 28 | #include "graphic/text_constants.h" |
1028 | 29 | #include "logic/map_objects/attackable.h" | ||
1029 | 30 | #include "logic/map_objects/bob.h" | 29 | #include "logic/map_objects/bob.h" |
1030 | 31 | #include "logic/map_objects/tribes/soldier.h" | 30 | #include "logic/map_objects/tribes/soldier.h" |
1031 | 32 | #include "logic/player.h" | 31 | #include "logic/player.h" |
1032 | 33 | 32 | ||
1033 | === modified file 'src/wui/fieldaction.cc' | |||
1034 | --- src/wui/fieldaction.cc 2017-02-27 19:10:24 +0000 | |||
1035 | +++ src/wui/fieldaction.cc 2017-05-21 11:20:39 +0000 | |||
1036 | @@ -26,7 +26,7 @@ | |||
1037 | 26 | #include "economy/road.h" | 26 | #include "economy/road.h" |
1038 | 27 | #include "graphic/graphic.h" | 27 | #include "graphic/graphic.h" |
1039 | 28 | #include "logic/cmd_queue.h" | 28 | #include "logic/cmd_queue.h" |
1041 | 29 | #include "logic/map_objects/attackable.h" | 29 | #include "logic/map_objects/tribes/attack_target.h" |
1042 | 30 | #include "logic/map_objects/tribes/soldier.h" | 30 | #include "logic/map_objects/tribes/soldier.h" |
1043 | 31 | #include "logic/map_objects/tribes/tribe_descr.h" | 31 | #include "logic/map_objects/tribes/tribe_descr.h" |
1044 | 32 | #include "logic/map_objects/tribes/warehouse.h" | 32 | #include "logic/map_objects/tribes/warehouse.h" |
1045 | @@ -380,13 +380,16 @@ | |||
1046 | 380 | void FieldActionWindow::add_buttons_attack() { | 380 | void FieldActionWindow::add_buttons_attack() { |
1047 | 381 | UI::Box& a_box = *new UI::Box(&tabpanel_, 0, 0, UI::Box::Horizontal); | 381 | UI::Box& a_box = *new UI::Box(&tabpanel_, 0, 0, UI::Box::Horizontal); |
1048 | 382 | 382 | ||
1053 | 383 | if (upcast(Widelands::Attackable, attackable, map_->get_immovable(node_))) { | 383 | if (upcast(Widelands::Building, building, map_->get_immovable(node_))) { |
1054 | 384 | if (player_ && player_->is_hostile(attackable->owner()) && attackable->can_attack()) { | 384 | if (const Widelands::AttackTarget* attack_target = building->attack_target()) { |
1055 | 385 | attack_box_ = new AttackBox(&a_box, player_, &node_, 0, 0); | 385 | if (player_ && player_->is_hostile(building->owner()) && |
1056 | 386 | a_box.add(attack_box_); | 386 | attack_target->can_be_attacked()) { |
1057 | 387 | attack_box_ = new AttackBox(&a_box, player_, &node_, 0, 0); | ||
1058 | 388 | a_box.add(attack_box_); | ||
1059 | 387 | 389 | ||
1062 | 388 | set_fastclick_panel(&add_button( | 390 | set_fastclick_panel(&add_button( |
1063 | 389 | &a_box, "attack", pic_attack, &FieldActionWindow::act_attack, _("Start attack"))); | 391 | &a_box, "attack", pic_attack, &FieldActionWindow::act_attack, _("Start attack"))); |
1064 | 392 | } | ||
1065 | 390 | } | 393 | } |
1066 | 391 | } | 394 | } |
1067 | 392 | 395 |
I was looking into how Warehouse works - thinking about trading. And the design of this irked me, so I improved it.