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

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
Reviewer Review Type Date Requested Status
GunChleoc Approve
Review via email: mp+324367@code.launchpad.net

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.

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

I was looking into how Warehouse works - thinking about trading. And the design of this irked me, so I improved it.

Revision history for this message
GunChleoc (gunchleoc) wrote :

2 tiny nits, code LGTM otherwise. Not tested yet.

And trading - yay! :)

review: Approve
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2227. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/234476861.
Appveyor build 2062. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_warehouse_refactor-2062.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Tested now, so you can merge this any time :)

Revision history for this message
SirVer (sirver) :
Revision history for this message
SirVer (sirver) wrote :

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/ai/defaultai_warfare.cc'
--- src/ai/defaultai_warfare.cc 2017-01-28 14:53:28 +0000
+++ src/ai/defaultai_warfare.cc 2017-05-21 11:20:39 +0000
@@ -122,7 +122,7 @@
122 // get list of immovable around this our military site122 // get list of immovable around this our military site
123 std::vector<ImmovableFound> immovables;123 std::vector<ImmovableFound> immovables;
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,
125 FindImmovableAttackable());125 FindImmovableAttackTarget());
126126
127 for (uint32_t j = 0; j < immovables.size(); ++j) {127 for (uint32_t j = 0; j < immovables.size(); ++j) {
128 if (upcast(MilitarySite const, bld, immovables.at(j).object)) {128 if (upcast(MilitarySite const, bld, immovables.at(j).object)) {
@@ -229,7 +229,7 @@
229 defenders_strength = calculate_strength(defenders);229 defenders_strength = calculate_strength(defenders);
230230
231 flag = &bld->base_flag();231 flag = &bld->base_flag();
232 if (is_visible && bld->can_attack()) {232 if (is_visible && bld->attack_target()->can_be_attacked()) {
233 is_attackable = true;233 is_attackable = true;
234 }234 }
235 owner_number = bld->owner().player_number();235 owner_number = bld->owner().player_number();
@@ -244,7 +244,7 @@
244244
245 flag = &Wh->base_flag();245 flag = &Wh->base_flag();
246 is_warehouse = true;246 is_warehouse = true;
247 if (is_visible && Wh->can_attack()) {247 if (is_visible && Wh->attack_target()->can_be_attacked()) {
248 is_attackable = true;248 is_attackable = true;
249 }249 }
250 owner_number = Wh->owner().player_number();250 owner_number = Wh->owner().player_number();
251251
=== modified file 'src/economy/route.h'
--- src/economy/route.h 2017-01-25 18:55:59 +0000
+++ src/economy/route.h 2017-05-21 11:20:39 +0000
@@ -23,14 +23,16 @@
23#include <vector>23#include <vector>
2424
25#include "economy/iroute.h"25#include "economy/iroute.h"
26#include "io/fileread.h"
27#include "io/filewrite.h"
26#include "logic/map_objects/map_object.h"28#include "logic/map_objects/map_object.h"
2729
28namespace Widelands {30namespace Widelands {
2931
32class EditorGameBase;
33class MapObjectLoader;
30struct Flag;34struct Flag;
31class EditorGameBase;
32struct MapObjectSaver;35struct MapObjectSaver;
33class MapObjectLoader;
34struct RoutingNode;36struct RoutingNode;
3537
36/**38/**
3739
=== modified file 'src/logic/CMakeLists.txt'
--- src/logic/CMakeLists.txt 2017-05-14 18:17:16 +0000
+++ src/logic/CMakeLists.txt 2017-05-21 11:20:39 +0000
@@ -127,14 +127,13 @@
127 save_handler.h127 save_handler.h
128 widelands_geometry_io.cc128 widelands_geometry_io.cc
129 widelands_geometry_io.h129 widelands_geometry_io.h
130 map_objects/draw_text.h
131 map_objects/attackable.h
132 map_objects/bob.cc130 map_objects/bob.cc
133 map_objects/bob.h131 map_objects/bob.h
134 map_objects/buildcost.cc132 map_objects/buildcost.cc
135 map_objects/buildcost.h133 map_objects/buildcost.h
136 map_objects/checkstep.cc134 map_objects/checkstep.cc
137 map_objects/checkstep.h135 map_objects/checkstep.h
136 map_objects/draw_text.h
138 map_objects/immovable.cc137 map_objects/immovable.cc
139 map_objects/immovable.h138 map_objects/immovable.h
140 map_objects/immovable_program.h139 map_objects/immovable_program.h
@@ -142,6 +141,7 @@
142 map_objects/map_object.h141 map_objects/map_object.h
143 map_objects/terrain_affinity.cc142 map_objects/terrain_affinity.cc
144 map_objects/terrain_affinity.h143 map_objects/terrain_affinity.h
144 map_objects/tribes/attack_target.h
145 map_objects/tribes/battle.cc145 map_objects/tribes/battle.cc
146 map_objects/tribes/battle.h146 map_objects/tribes/battle.h
147 map_objects/tribes/bill_of_materials.h147 map_objects/tribes/bill_of_materials.h
148148
=== modified file 'src/logic/cmd_queue.h'
--- src/logic/cmd_queue.h 2017-01-25 18:55:59 +0000
+++ src/logic/cmd_queue.h 2017-05-21 11:20:39 +0000
@@ -27,7 +27,6 @@
27#include <stdint.h>27#include <stdint.h>
2828
29#include "logic/queue_cmd_ids.h"29#include "logic/queue_cmd_ids.h"
30#include <stdint.h>
3130
32class FileRead;31class FileRead;
33class FileWrite;32class FileWrite;
3433
=== modified file 'src/logic/findimmovable.cc'
--- src/logic/findimmovable.cc 2017-01-25 18:55:59 +0000
+++ src/logic/findimmovable.cc 2017-05-21 11:20:39 +0000
@@ -21,7 +21,6 @@
2121
22#include "base/macros.h"22#include "base/macros.h"
23#include "economy/flag.h"23#include "economy/flag.h"
24#include "logic/map_objects/attackable.h"
25#include "logic/map_objects/immovable.h"24#include "logic/map_objects/immovable.h"
26#include "logic/map_objects/tribes/militarysite.h"25#include "logic/map_objects/tribes/militarysite.h"
2726
@@ -61,8 +60,11 @@
61 return false;60 return false;
62}61}
6362
64bool FindImmovableAttackable::accept(const BaseImmovable& imm) const {63bool FindImmovableAttackTarget::accept(const BaseImmovable& imm) const {
65 return dynamic_cast<Attackable const*>(&imm);64 if (upcast(Building const, b, &imm)) {
65 return b->attack_target() != nullptr;
66 }
67 return false;
66}68}
6769
68bool FindImmovableByDescr::accept(const BaseImmovable& baseimm) const {70bool FindImmovableByDescr::accept(const BaseImmovable& baseimm) const {
6971
=== modified file 'src/logic/findimmovable.h'
--- src/logic/findimmovable.h 2017-01-25 18:55:59 +0000
+++ src/logic/findimmovable.h 2017-05-21 11:20:39 +0000
@@ -132,8 +132,8 @@
132132
133 const Player& player;133 const Player& player;
134};134};
135struct FindImmovableAttackable {135struct FindImmovableAttackTarget {
136 FindImmovableAttackable() {136 FindImmovableAttackTarget() {
137 }137 }
138138
139 bool accept(const BaseImmovable&) const;139 bool accept(const BaseImmovable&) const;
140140
=== modified file 'src/logic/map_objects/map_object.h'
--- src/logic/map_objects/map_object.h 2017-04-23 12:11:19 +0000
+++ src/logic/map_objects/map_object.h 2017-05-21 11:20:39 +0000
@@ -491,12 +491,12 @@
491 ObjectPointer() {491 ObjectPointer() {
492 serial_ = 0;492 serial_ = 0;
493 }493 }
494 ObjectPointer(MapObject* const obj) {494 ObjectPointer(const MapObject* const obj) {
495 serial_ = obj ? obj->serial_ : 0;495 serial_ = obj ? obj->serial_ : 0;
496 }496 }
497 // can use standard copy constructor and assignment operator497 // can use standard copy constructor and assignment operator
498498
499 ObjectPointer& operator=(MapObject* const obj) {499 ObjectPointer& operator=(const MapObject* const obj) {
500 serial_ = obj ? obj->serial_ : 0;500 serial_ = obj ? obj->serial_ : 0;
501 return *this;501 return *this;
502 }502 }
503503
=== renamed file 'src/logic/map_objects/attackable.h' => 'src/logic/map_objects/tribes/attack_target.h'
--- src/logic/map_objects/attackable.h 2017-01-25 18:55:59 +0000
+++ src/logic/map_objects/tribes/attack_target.h 2017-05-21 11:20:39 +0000
@@ -17,68 +17,55 @@
17 *17 *
18 */18 */
1919
20#ifndef WL_LOGIC_MAP_OBJECTS_ATTACKABLE_H20#ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_ATTACK_TARGET_H
21#define WL_LOGIC_MAP_OBJECTS_ATTACKABLE_H21#define WL_LOGIC_MAP_OBJECTS_TRIBES_ATTACK_TARGET_H
22
23#include "base/macros.h"
2224
23namespace Widelands {25namespace Widelands {
2426
25class Player;
26class Soldier;27class Soldier;
2728
28enum {29// This is the maximum radius that a military building can protect in the sense
29 /**30// that an enemy soldier that enters the player's territory will call \ref
30 * This is the maximum radius that a military building can protect31// AttackTarget::enemy_soldier_approaches if it is that close.
31 * in the sense that an enemy soldier that enters the player's territory32constexpr int kMaxProtectionRadius = 25;
32 * will call \ref Attackable::aggressor if it is that close.33
33 */34class AttackTarget {
34 MaxProtectionRadius = 2535public:
35};36 AttackTarget() = default;
3637 virtual ~AttackTarget() {
37/**
38 * Buildings can implement this interface to indicate that
39 * they can be attacked.
40 */
41struct Attackable {
42 /**
43 * Return the player that owns this attackable.
44 */
45 virtual Player& owner() const = 0;
46
47 /**
48 * Determines whether this building can be attacked right now.
49 *
50 * This should only return false for military sites that have not
51 * been occupied yet.
52 */
53 virtual bool can_attack() = 0;
54
55 /**
56 * Called by an enemy soldier that enters a node with distance
57 * less than or equal to \ref MaxProtectionRadius from the building.
58 *
59 * This allows the building to send protective forces to intercept
60 * the soldier.
61 */
62 virtual void aggressor(Soldier&) = 0;
63
64 /**
65 * Called by a soldier who is standing on the building's flag
66 * to attack the building.
67 *
68 * The building must send a soldier for defense, and return \c true.
69 * Otherwise, i.e. if the building cannot defend itself anymore,
70 * it must destroy itself or turn over to the attacking player,
71 * and return \c false.
72 *
73 * \return \c true if a soldier was launched in defense of the building,
74 * or \c false if the building cannot defend itself any longer.
75 */
76 virtual bool attack(Soldier&) = 0;
77
78protected:
79 virtual ~Attackable() {
80 }38 }
39
40 // Determines whether this building can be attacked right now.
41 virtual bool can_be_attacked() const = 0;
42
43 // Called by an enemy soldier that enters a node with distance
44 // less than or equal to \ref kMaxProtectionRadius from the building.
45 //
46 // This allows the building to send protective forces to intercept
47 // the soldier.
48 virtual void enemy_soldier_approaches(const Soldier& enemy) const = 0;
49
50 // Called by a soldier who is standing on the building's flag
51 // to attack the building.
52 //
53 // The building must send a soldier for defense, and return \c true.
54 // Otherwise, i.e. if the building cannot defend itself anymore,
55 // it must destroy itself or turn over to the attacking player,
56 // and return \c false.
57 enum class AttackResult {
58 // Returned when a soldier was launched in defense of the building.
59 DefenderLaunched,
60
61 // Returned if the building cannot defend itself any longer.
62 Defenseless
63 };
64 virtual AttackResult attack(Soldier* attacker) const = 0;
65
66private:
67 DISALLOW_COPY_AND_ASSIGN(AttackTarget);
81};68};
82}69}
8370
84#endif // end of include guard: WL_LOGIC_MAP_OBJECTS_ATTACKABLE_H71#endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_ATTACK_TARGET_H
8572
=== modified file 'src/logic/map_objects/tribes/building.cc'
--- src/logic/map_objects/tribes/building.cc 2017-05-09 09:18:14 +0000
+++ src/logic/map_objects/tribes/building.cc 2017-05-21 11:20:39 +0000
@@ -235,7 +235,8 @@
235 animstart_(0),235 animstart_(0),
236 leave_time_(0),236 leave_time_(0),
237 defeating_player_(0),237 defeating_player_(0),
238 seeing_(false) {238 seeing_(false),
239 attack_target_(nullptr) {
239}240}
240241
241void Building::load_finish(EditorGameBase& egbase) {242void Building::load_finish(EditorGameBase& egbase) {
@@ -692,6 +693,11 @@
692 Notifications::publish(NoteBuilding(serial(), NoteBuilding::Action::kWorkersChanged));693 Notifications::publish(NoteBuilding(serial(), NoteBuilding::Action::kWorkersChanged));
693}694}
694695
696void Building::set_attack_target(AttackTarget* new_attack_target) {
697 assert(attack_target_ == nullptr);
698 attack_target_ = new_attack_target;
699}
700
695/**701/**
696 * Change whether this building sees its vision range based on workers702 * Change whether this building sees its vision range based on workers
697 * inside the building.703 * inside the building.
698704
=== modified file 'src/logic/map_objects/tribes/building.h'
--- src/logic/map_objects/tribes/building.h 2017-05-06 19:21:47 +0000
+++ src/logic/map_objects/tribes/building.h 2017-05-21 11:20:39 +0000
@@ -30,6 +30,7 @@
30#include "base/macros.h"30#include "base/macros.h"
31#include "logic/map_objects/buildcost.h"31#include "logic/map_objects/buildcost.h"
32#include "logic/map_objects/immovable.h"32#include "logic/map_objects/immovable.h"
33#include "logic/map_objects/tribes/attack_target.h"
33#include "logic/map_objects/tribes/bill_of_materials.h"34#include "logic/map_objects/tribes/bill_of_materials.h"
34#include "logic/map_objects/tribes/wareworker.h"35#include "logic/map_objects/tribes/wareworker.h"
35#include "logic/map_objects/tribes/workarea_info.h"36#include "logic/map_objects/tribes/workarea_info.h"
@@ -293,6 +294,13 @@
293 void add_worker(Worker&) override;294 void add_worker(Worker&) override;
294 void remove_worker(Worker&) override;295 void remove_worker(Worker&) override;
295296
297 // Returns the AttackTarget object associated with this building. If the
298 // building can never be attacked (for example productionsites) this will be
299 // nullptr.
300 const AttackTarget* attack_target() const {
301 return attack_target_;
302 }
303
296 void send_message(Game& game,304 void send_message(Game& game,
297 const Message::Type msgtype,305 const Message::Type msgtype,
298 const std::string& title,306 const std::string& title,
@@ -324,6 +332,7 @@
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);
325333
326 void set_seeing(bool see);334 void set_seeing(bool see);
335 void set_attack_target(AttackTarget* new_attack_target);
327336
328 Coords position_;337 Coords position_;
329 Flag* flag_;338 Flag* flag_;
@@ -350,6 +359,7 @@
350359
351private:360private:
352 std::string statistics_string_;361 std::string statistics_string_;
362 AttackTarget* attack_target_; // owned by the base classes, set by 'set_attack_target'.
353};363};
354}364}
355365
356366
=== modified file 'src/logic/map_objects/tribes/militarysite.cc'
--- src/logic/map_objects/tribes/militarysite.cc 2017-04-23 12:11:19 +0000
+++ src/logic/map_objects/tribes/militarysite.cc 2017-05-21 11:20:39 +0000
@@ -43,6 +43,145 @@
4343
44namespace Widelands {44namespace Widelands {
4545
46bool MilitarySite::AttackTarget::can_be_attacked() const {
47 return military_site_->didconquer_;
48}
49
50void MilitarySite::AttackTarget::enemy_soldier_approaches(const Soldier& enemy) const {
51 auto& owner = military_site_->owner();
52 Game& game = dynamic_cast<Game&>(owner.egbase());
53 Map& map = game.map();
54 if (enemy.get_owner() == &owner || enemy.get_battle() ||
55 military_site_->descr().get_conquers() <=
56 map.calc_distance(enemy.get_position(), military_site_->get_position()))
57 return;
58
59 if (map.find_bobs(Area<FCoords>(map.get_fcoords(military_site_->base_flag().get_position()), 2),
60 nullptr, FindBobEnemySoldier(&owner)))
61 return;
62
63 // We're dealing with a soldier that we might want to keep busy
64 // Now would be the time to implement some player-definable
65 // policy as to how many soldiers are allowed to leave as defenders
66 std::vector<Soldier*> present = military_site_->present_soldiers();
67
68 if (1 < present.size()) {
69 for (Soldier* temp_soldier : present) {
70 if (!military_site_->has_soldier_job(*temp_soldier)) {
71 SoldierJob sj;
72 sj.soldier = temp_soldier;
73 sj.enemy = &enemy;
74 sj.stayhome = false;
75 military_site_->soldierjobs_.push_back(sj);
76 temp_soldier->update_task_buildingwork(game);
77 return;
78 }
79 }
80 }
81
82 // Inform the player, that we are under attack by adding a new entry to the
83 // message queue - a sound will automatically be played.
84 military_site_->notify_player(game, true);
85}
86
87AttackTarget::AttackResult MilitarySite::AttackTarget::attack(Soldier* enemy) const {
88 Game& game = dynamic_cast<Game&>(military_site_->owner().egbase());
89
90 std::vector<Soldier*> present = military_site_->present_soldiers();
91 Soldier* defender = nullptr;
92
93 if (!present.empty()) {
94 // Find soldier with greatest health
95 uint32_t current_max = 0;
96 for (Soldier* temp_soldier : present) {
97 if (temp_soldier->get_current_health() > current_max) {
98 defender = temp_soldier;
99 current_max = defender->get_current_health();
100 }
101 }
102 } else {
103 // If one of our stationed soldiers is currently walking into the
104 // building, give us another chance.
105 std::vector<Soldier*> stationed = military_site_->stationed_soldiers();
106 for (Soldier* temp_soldier : stationed) {
107 if (temp_soldier->get_position() == military_site_->get_position()) {
108 defender = temp_soldier;
109 break;
110 }
111 }
112 }
113
114 if (defender) {
115 military_site_->pop_soldier_job(defender); // defense overrides all other jobs
116
117 SoldierJob sj;
118 sj.soldier = defender;
119 sj.enemy = enemy;
120 sj.stayhome = true;
121 military_site_->soldierjobs_.push_back(sj);
122
123 defender->update_task_buildingwork(game);
124
125 // Inform the player, that we are under attack by adding a new entry to
126 // the message queue - a sound will automatically be played.
127 military_site_->notify_player(game);
128
129 return AttackTarget::AttackResult::DefenderLaunched;
130 }
131
132 // The enemy has defeated our forces, we should inform the player
133 const Coords coords = military_site_->get_position();
134 {
135 military_site_->send_message(game, Message::Type::kWarfareSiteLost,
136 /** TRANSLATORS: Militarysite lost (taken/destroyed by enemy) */
137 pgettext("building", "Lost!"),
138 military_site_->descr().icon_filename(), _("Militarysite lost!"),
139 military_site_->descr().defeated_enemy_str_, false);
140 }
141
142 // Now let's see whether the enemy conquers our militarysite, or whether
143 // we still hold the bigger military presence in that area (e.g. if there
144 // is a fortress one or two points away from our sentry, the fortress has
145 // a higher presence and thus the enemy can just burn down the sentry.
146 if (military_site_->military_presence_kept(game)) {
147 // Okay we still got the higher military presence, so the attacked
148 // militarysite will be destroyed.
149 military_site_->set_defeating_player(enemy->owner().player_number());
150 military_site_->schedule_destroy(game);
151 return AttackTarget::AttackResult::Defenseless;
152 }
153
154 // The enemy conquers the building
155 // In fact we do not conquer it, but place a new building of same type at
156 // the old location.
157
158 Building::FormerBuildings former_buildings = military_site_->old_buildings_;
159
160 // The enemy conquers the building
161 // In fact we do not conquer it, but place a new building of same type at
162 // the old location.
163 Player* enemyplayer = enemy->get_owner();
164
165 // Now we destroy the old building before we place the new one.
166 military_site_->set_defeating_player(enemyplayer->player_number());
167 military_site_->schedule_destroy(game);
168
169 enemyplayer->force_building(coords, former_buildings);
170 BaseImmovable* const newimm = game.map()[coords].get_immovable();
171 upcast(MilitarySite, newsite, newimm);
172 newsite->reinit_after_conqueration(game);
173
174 // Of course we should inform the victorious player as well
175 newsite->send_message(
176 game, Message::Type::kWarfareSiteDefeated,
177 /** TRANSLATORS: Message title. */
178 /** TRANSLATORS: If you run out of space, you can also translate this as "Success!" */
179 _("Enemy Defeated!"), newsite->descr().icon_filename(), _("Enemy at site defeated!"),
180 newsite->descr().defeated_you_str_, true);
181
182 return AttackTarget::AttackResult::Defenseless;
183}
184
46/**185/**
47 * The contents of 'table' are documented in186 * The contents of 'table' are documented in
48 * /data/tribes/buildings/militarysites/atlanteans/castle/init.lua187 * /data/tribes/buildings/militarysites/atlanteans/castle/init.lua
@@ -91,6 +230,7 @@
91230
92MilitarySite::MilitarySite(const MilitarySiteDescr& ms_descr)231MilitarySite::MilitarySite(const MilitarySiteDescr& ms_descr)
93 : Building(ms_descr),232 : Building(ms_descr),
233 attack_target_(this),
94 didconquer_(false),234 didconquer_(false),
95 capacity_(ms_descr.get_max_number_of_soldiers()),235 capacity_(ms_descr.get_max_number_of_soldiers()),
96 nexthealtime_(0),236 nexthealtime_(0),
@@ -98,6 +238,7 @@
98 soldier_upgrade_try_(false),238 soldier_upgrade_try_(false),
99 doing_upgrade_request_(false) {239 doing_upgrade_request_(false) {
100 next_swap_soldiers_time_ = 0;240 next_swap_soldiers_time_ = 0;
241 set_attack_target(&attack_target_);
101}242}
102243
103MilitarySite::~MilitarySite() {244MilitarySite::~MilitarySite() {
@@ -684,142 +825,6 @@
684 didconquer_ = true;825 didconquer_ = true;
685}826}
686827
687bool MilitarySite::can_attack() {
688 return didconquer_;
689}
690
691void MilitarySite::aggressor(Soldier& enemy) {
692 Game& game = dynamic_cast<Game&>(owner().egbase());
693 Map& map = game.map();
694 if (enemy.get_owner() == &owner() || enemy.get_battle() ||
695 descr().get_conquers() <= map.calc_distance(enemy.get_position(), get_position()))
696 return;
697
698 if (map.find_bobs(Area<FCoords>(map.get_fcoords(base_flag().get_position()), 2), nullptr,
699 FindBobEnemySoldier(&owner())))
700 return;
701
702 // We're dealing with a soldier that we might want to keep busy
703 // Now would be the time to implement some player-definable
704 // policy as to how many soldiers are allowed to leave as defenders
705 std::vector<Soldier*> present = present_soldiers();
706
707 if (1 < present.size()) {
708 for (Soldier* temp_soldier : present) {
709 if (!has_soldier_job(*temp_soldier)) {
710 SoldierJob sj;
711 sj.soldier = temp_soldier;
712 sj.enemy = &enemy;
713 sj.stayhome = false;
714 soldierjobs_.push_back(sj);
715 temp_soldier->update_task_buildingwork(game);
716 return;
717 }
718 }
719 }
720
721 // Inform the player, that we are under attack by adding a new entry to the
722 // message queue - a sound will automatically be played.
723 notify_player(game, true);
724}
725
726bool MilitarySite::attack(Soldier& enemy) {
727 Game& game = dynamic_cast<Game&>(owner().egbase());
728
729 std::vector<Soldier*> present = present_soldiers();
730 Soldier* defender = nullptr;
731
732 if (!present.empty()) {
733 // Find soldier with greatest health
734 uint32_t current_max = 0;
735 for (Soldier* temp_soldier : present) {
736 if (temp_soldier->get_current_health() > current_max) {
737 defender = temp_soldier;
738 current_max = defender->get_current_health();
739 }
740 }
741 } else {
742 // If one of our stationed soldiers is currently walking into the
743 // building, give us another chance.
744 std::vector<Soldier*> stationed = stationed_soldiers();
745 for (Soldier* temp_soldier : stationed) {
746 if (temp_soldier->get_position() == get_position()) {
747 defender = temp_soldier;
748 break;
749 }
750 }
751 }
752
753 if (defender) {
754 pop_soldier_job(defender); // defense overrides all other jobs
755
756 SoldierJob sj;
757 sj.soldier = defender;
758 sj.enemy = &enemy;
759 sj.stayhome = true;
760 soldierjobs_.push_back(sj);
761
762 defender->update_task_buildingwork(game);
763
764 // Inform the player, that we are under attack by adding a new entry to
765 // the message queue - a sound will automatically be played.
766 notify_player(game);
767
768 return true;
769 } else {
770 // The enemy has defeated our forces, we should inform the player
771 const Coords coords = get_position();
772 {
773 send_message(game, Message::Type::kWarfareSiteLost,
774 /** TRANSLATORS: Militarysite lost (taken/destroyed by enemy) */
775 pgettext("building", "Lost!"), descr().icon_filename(),
776 _("Militarysite lost!"), descr().defeated_enemy_str_, false);
777 }
778
779 // Now let's see whether the enemy conquers our militarysite, or whether
780 // we still hold the bigger military presence in that area (e.g. if there
781 // is a fortress one or two points away from our sentry, the fortress has
782 // a higher presence and thus the enemy can just burn down the sentry.
783 if (military_presence_kept(game)) {
784 // Okay we still got the higher military presence, so the attacked
785 // militarysite will be destroyed.
786 set_defeating_player(enemy.owner().player_number());
787 schedule_destroy(game);
788 return false;
789 }
790
791 // The enemy conquers the building
792 // In fact we do not conquer it, but place a new building of same type at
793 // the old location.
794
795 Building::FormerBuildings former_buildings = old_buildings_;
796
797 // The enemy conquers the building
798 // In fact we do not conquer it, but place a new building of same type at
799 // the old location.
800 Player* enemyplayer = enemy.get_owner();
801
802 // Now we destroy the old building before we place the new one.
803 set_defeating_player(enemyplayer->player_number());
804 schedule_destroy(game);
805
806 enemyplayer->force_building(coords, former_buildings);
807 BaseImmovable* const newimm = game.map()[coords].get_immovable();
808 upcast(MilitarySite, newsite, newimm);
809 newsite->reinit_after_conqueration(game);
810
811 // Of course we should inform the victorious player as well
812 newsite->send_message(
813 game, Message::Type::kWarfareSiteDefeated,
814 /** TRANSLATORS: Message title. */
815 /** TRANSLATORS: If you run out of space, you can also translate this as "Success!" */
816 _("Enemy Defeated!"), newsite->descr().icon_filename(), _("Enemy at site defeated!"),
817 newsite->descr().defeated_you_str_, true);
818
819 return false;
820 }
821}
822
823/// Initialises the militarysite after it was "conquered" (the old was replaced)828/// Initialises the militarysite after it was "conquered" (the old was replaced)
824void MilitarySite::reinit_after_conqueration(Game& game) {829void MilitarySite::reinit_after_conqueration(Game& game) {
825 clear_requirements();830 clear_requirements();
826831
=== modified file 'src/logic/map_objects/tribes/militarysite.h'
--- src/logic/map_objects/tribes/militarysite.h 2017-04-23 12:11:19 +0000
+++ src/logic/map_objects/tribes/militarysite.h 2017-05-21 11:20:39 +0000
@@ -24,7 +24,6 @@
2424
25#include "base/macros.h"25#include "base/macros.h"
26#include "economy/request.h"26#include "economy/request.h"
27#include "logic/map_objects/attackable.h"
28#include "logic/map_objects/tribes/building.h"27#include "logic/map_objects/tribes/building.h"
29#include "logic/map_objects/tribes/requirements.h"28#include "logic/map_objects/tribes/requirements.h"
30#include "logic/map_objects/tribes/soldiercontrol.h"29#include "logic/map_objects/tribes/soldiercontrol.h"
@@ -69,7 +68,7 @@
69 DISALLOW_COPY_AND_ASSIGN(MilitarySiteDescr);68 DISALLOW_COPY_AND_ASSIGN(MilitarySiteDescr);
70};69};
7170
72class MilitarySite : public Building, public SoldierControl, public Attackable {71class MilitarySite : public Building, public SoldierControl {
73 friend class MapBuildingdataPacket;72 friend class MapBuildingdataPacket;
74 MO_DESCR(MilitarySiteDescr)73 MO_DESCR(MilitarySiteDescr)
7574
@@ -102,15 +101,6 @@
102 void drop_soldier(Soldier&) override;101 void drop_soldier(Soldier&) override;
103 int incorporate_soldier(EditorGameBase& game, Soldier& s) override;102 int incorporate_soldier(EditorGameBase& game, Soldier& s) override;
104103
105 // Begin implementation of Attackable
106 Player& owner() const override {
107 return Building::owner();
108 }
109 bool can_attack() override;
110 void aggressor(Soldier&) override;
111 bool attack(Soldier&) override;
112 // End implementation of Attackable
113
114 /// Launch the given soldier on an attack towards the given104 /// Launch the given soldier on an attack towards the given
115 /// target building.105 /// target building.
116 void send_attacker(Soldier&, Building&);106 void send_attacker(Soldier&, Building&);
@@ -153,6 +143,21 @@
153 bool drop_least_suited_soldier(bool new_has_arrived, Soldier* s);143 bool drop_least_suited_soldier(bool new_has_arrived, Soldier* s);
154144
155private:145private:
146 // We can be attacked if we have stationed soldiers.
147 class AttackTarget : public Widelands::AttackTarget {
148 public:
149 explicit AttackTarget(MilitarySite* military_site) : military_site_(military_site) {
150 }
151
152 bool can_be_attacked() const override;
153 void enemy_soldier_approaches(const Soldier&) const override;
154 Widelands::AttackTarget::AttackResult attack(Soldier*) const override;
155
156 private:
157 MilitarySite* const military_site_;
158 };
159
160 AttackTarget attack_target_;
156 Requirements soldier_requirements_; // This is used to grab a bunch of soldiers: Anything goes161 Requirements soldier_requirements_; // This is used to grab a bunch of soldiers: Anything goes
157 RequireAttribute soldier_upgrade_requirements_; // This is used when exchanging soldiers.162 RequireAttribute soldier_upgrade_requirements_; // This is used when exchanging soldiers.
158 std::unique_ptr<Request> normal_soldier_request_; // filling the site163 std::unique_ptr<Request> normal_soldier_request_; // filling the site
159164
=== modified file 'src/logic/map_objects/tribes/soldier.cc'
--- src/logic/map_objects/tribes/soldier.cc 2017-05-13 18:48:26 +0000
+++ src/logic/map_objects/tribes/soldier.cc 2017-05-21 11:20:39 +0000
@@ -42,7 +42,6 @@
42#include "logic/game.h"42#include "logic/game.h"
43#include "logic/game_controller.h"43#include "logic/game_controller.h"
44#include "logic/game_data_error.h"44#include "logic/game_data_error.h"
45#include "logic/map_objects/attackable.h"
46#include "logic/map_objects/checkstep.h"45#include "logic/map_objects/checkstep.h"
47#include "logic/map_objects/tribes/battle.h"46#include "logic/map_objects/tribes/battle.h"
48#include "logic/map_objects/tribes/building.h"47#include "logic/map_objects/tribes/building.h"
@@ -602,7 +601,7 @@
602 return false;601 return false;
603}602}
604603
605Battle* Soldier::get_battle() {604Battle* Soldier::get_battle() const {
606 return battle_;605 return battle_;
607}606}
608607
@@ -902,12 +901,14 @@
902 }901 }
903 }902 }
904903
905 upcast(Attackable, attackable, enemy);904 assert(enemy->attack_target() != nullptr);
906 assert(attackable);
907905
908 molog("[attack] attacking target building\n");906 molog("[attack] attacking target building\n");
909 // give the enemy soldier some time to act907 // give the enemy soldier some time to act
910 schedule_act(game, attackable->attack(*this) ? 1000 : 10);908 schedule_act(
909 game, enemy->attack_target()->attack(this) == AttackTarget::AttackResult::DefenderLaunched ?
910 1000 :
911 10);
911}912}
912913
913void Soldier::attack_pop(Game& game, State&) {914void Soldier::attack_pop(Game& game, State&) {
@@ -1520,20 +1521,21 @@
1520 PlayerNumber const land_owner = get_position().field->get_owned_by();1521 PlayerNumber const land_owner = get_position().field->get_owned_by();
1521 // First check if the soldier is standing on someone else's territory1522 // First check if the soldier is standing on someone else's territory
1522 if (land_owner != owner().player_number()) {1523 if (land_owner != owner().player_number()) {
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)
1524 std::vector<BaseImmovable*> attackables;1525 std::vector<BaseImmovable*> attack_targets;
1525 game.map().find_reachable_immovables_unique(1526 game.map().find_reachable_immovables_unique(
1526 Area<FCoords>(get_position(), MaxProtectionRadius), attackables,1527 Area<FCoords>(get_position(), kMaxProtectionRadius), attack_targets,
1527 CheckStepWalkOn(descr().movecaps(), false), FindImmovableAttackable());1528 CheckStepWalkOn(descr().movecaps(), false), FindImmovableAttackTarget());
15281529
1529 for (BaseImmovable* temp_attackable : attackables) {1530 for (BaseImmovable* temp_attack_target : attack_targets) {
1530 const Player* attackable_player =1531 Building* building = dynamic_cast<Building*>(temp_attack_target);
1531 dynamic_cast<const PlayerImmovable&>(*temp_attackable).get_owner();1532 assert(building != nullptr && building->attack_target() != nullptr);
1533 const Player& attack_target_player = building->owner();
1532 // Let's inform the site that this (=enemy) soldier is nearby and within the site's owner's1534 // Let's inform the site that this (=enemy) soldier is nearby and within the site's owner's
1533 // territory1535 // territory
1534 if (attackable_player->player_number() == land_owner &&1536 if (attack_target_player.player_number() == land_owner &&
1535 attackable_player->is_hostile(*get_owner())) {1537 attack_target_player.is_hostile(*get_owner())) {
1536 dynamic_cast<Attackable&>(*temp_attackable).aggressor(*this);1538 building->attack_target()->enemy_soldier_approaches(*this);
1537 }1539 }
1538 }1540 }
1539 }1541 }
15401542
=== modified file 'src/logic/map_objects/tribes/soldier.h'
--- src/logic/map_objects/tribes/soldier.h 2017-05-13 13:14:29 +0000
+++ src/logic/map_objects/tribes/soldier.h 2017-05-21 11:20:39 +0000
@@ -262,7 +262,7 @@
262262
263 bool is_on_battlefield();263 bool is_on_battlefield();
264 bool is_attacking_player(Game&, Player&);264 bool is_attacking_player(Game&, Player&);
265 Battle* get_battle();265 Battle* get_battle() const;
266 bool can_be_challenged();266 bool can_be_challenged();
267 bool check_node_blocked(Game&, const FCoords&, bool commit) override;267 bool check_node_blocked(Game&, const FCoords&, bool commit) override;
268268
269269
=== modified file 'src/logic/map_objects/tribes/warehouse.cc'
--- src/logic/map_objects/tribes/warehouse.cc 2017-05-03 10:34:46 +0000
+++ src/logic/map_objects/tribes/warehouse.cc 2017-05-21 11:20:39 +0000
@@ -69,6 +69,57 @@
6969
70} // namespace70} // namespace
7171
72bool Warehouse::AttackTarget::can_be_attacked() const {
73 return warehouse_->descr().get_conquers() > 0;
74}
75
76void Warehouse::AttackTarget::enemy_soldier_approaches(const Soldier& enemy) const {
77 if (!warehouse_->descr().get_conquers())
78 return;
79
80 Player& owner = warehouse_->owner();
81 Game& game = dynamic_cast<Game&>(owner.egbase());
82 Map& map = game.map();
83 if (enemy.get_owner() == &owner || enemy.get_battle() ||
84 warehouse_->descr().get_conquers() <=
85 map.calc_distance(enemy.get_position(), warehouse_->get_position()))
86 return;
87
88 if (game.map().find_bobs(
89 Area<FCoords>(map.get_fcoords(warehouse_->base_flag().get_position()), 2), nullptr,
90 FindBobEnemySoldier(&owner)))
91 return;
92
93 DescriptionIndex const soldier_index = owner.tribe().soldier();
94 Requirements noreq;
95
96 if (!warehouse_->count_workers(game, soldier_index, noreq, Match::kCompatible))
97 return;
98
99 Soldier& defender =
100 dynamic_cast<Soldier&>(warehouse_->launch_worker(game, soldier_index, noreq));
101 defender.start_task_defense(game, false);
102}
103
104AttackTarget::AttackResult Warehouse::AttackTarget::attack(Soldier* enemy) const {
105 Player& owner = warehouse_->owner();
106 Game& game = dynamic_cast<Game&>(owner.egbase());
107 DescriptionIndex const soldier_index = owner.tribe().soldier();
108 Requirements noreq;
109
110 if (warehouse_->count_workers(game, soldier_index, noreq, Match::kCompatible)) {
111 Soldier& defender =
112 dynamic_cast<Soldier&>(warehouse_->launch_worker(game, soldier_index, noreq));
113 defender.start_task_defense(game, true);
114 enemy->send_signal(game, "sleep");
115 return AttackTarget::AttackResult::DefenderLaunched;
116 }
117
118 warehouse_->set_defeating_player(enemy->owner().player_number());
119 warehouse_->schedule_destroy(game);
120 return AttackTarget::AttackResult::Defenseless;
121}
122
72WarehouseSupply::~WarehouseSupply() {123WarehouseSupply::~WarehouseSupply() {
73 if (economy_) {124 if (economy_) {
74 log("WarehouseSupply::~WarehouseSupply: Warehouse %u still belongs to "125 log("WarehouseSupply::~WarehouseSupply: Warehouse %u still belongs to "
@@ -260,11 +311,13 @@
260311
261Warehouse::Warehouse(const WarehouseDescr& warehouse_descr)312Warehouse::Warehouse(const WarehouseDescr& warehouse_descr)
262 : Building(warehouse_descr),313 : Building(warehouse_descr),
314 attack_target_(this),
263 supply_(new WarehouseSupply(this)),315 supply_(new WarehouseSupply(this)),
264 next_military_act_(0),316 next_military_act_(0),
265 portdock_(nullptr) {317 portdock_(nullptr) {
266 next_stock_remove_act_ = 0;318 next_stock_remove_act_ = 0;
267 cleanup_in_progress_ = false;319 cleanup_in_progress_ = false;
320 set_attack_target(&attack_target_);
268}321}
269322
270Warehouse::~Warehouse() {323Warehouse::~Warehouse() {
@@ -1165,51 +1218,6 @@
1165 next_worker_without_cost_spawn_[worker_types_without_cost_index] = never();1218 next_worker_without_cost_spawn_[worker_types_without_cost_index] = never();
1166}1219}
11671220
1168bool Warehouse::can_attack() {
1169 return descr().get_conquers() > 0;
1170}
1171
1172void Warehouse::aggressor(Soldier& enemy) {
1173 if (!descr().get_conquers())
1174 return;
1175
1176 Game& game = dynamic_cast<Game&>(owner().egbase());
1177 Map& map = game.map();
1178 if (enemy.get_owner() == &owner() || enemy.get_battle() ||
1179 descr().get_conquers() <= map.calc_distance(enemy.get_position(), get_position()))
1180 return;
1181
1182 if (game.map().find_bobs(Area<FCoords>(map.get_fcoords(base_flag().get_position()), 2), nullptr,
1183 FindBobEnemySoldier(&owner())))
1184 return;
1185
1186 DescriptionIndex const soldier_index = owner().tribe().soldier();
1187 Requirements noreq;
1188
1189 if (!count_workers(game, soldier_index, noreq, Match::kCompatible))
1190 return;
1191
1192 Soldier& defender = dynamic_cast<Soldier&>(launch_worker(game, soldier_index, noreq));
1193 defender.start_task_defense(game, false);
1194}
1195
1196bool Warehouse::attack(Soldier& enemy) {
1197 Game& game = dynamic_cast<Game&>(owner().egbase());
1198 DescriptionIndex const soldier_index = owner().tribe().soldier();
1199 Requirements noreq;
1200
1201 if (count_workers(game, soldier_index, noreq, Match::kCompatible)) {
1202 Soldier& defender = dynamic_cast<Soldier&>(launch_worker(game, soldier_index, noreq));
1203 defender.start_task_defense(game, true);
1204 enemy.send_signal(game, "sleep");
1205 return true;
1206 }
1207
1208 set_defeating_player(enemy.owner().player_number());
1209 schedule_destroy(game);
1210 return false;
1211}
1212
1213void Warehouse::PlannedWorkers::cleanup() {1221void Warehouse::PlannedWorkers::cleanup() {
1214 while (!requests.empty()) {1222 while (!requests.empty()) {
1215 delete requests.back();1223 delete requests.back();
12161224
=== modified file 'src/logic/map_objects/tribes/warehouse.h'
--- src/logic/map_objects/tribes/warehouse.h 2017-04-23 12:11:19 +0000
+++ src/logic/map_objects/tribes/warehouse.h 2017-05-21 11:20:39 +0000
@@ -24,7 +24,6 @@
24#include "base/wexception.h"24#include "base/wexception.h"
25#include "economy/request.h"25#include "economy/request.h"
26#include "economy/wares_queue.h"26#include "economy/wares_queue.h"
27#include "logic/map_objects/attackable.h"
28#include "logic/map_objects/tribes/building.h"27#include "logic/map_objects/tribes/building.h"
29#include "logic/map_objects/tribes/soldiercontrol.h"28#include "logic/map_objects/tribes/soldiercontrol.h"
30#include "logic/map_objects/tribes/wareworker.h"29#include "logic/map_objects/tribes/wareworker.h"
@@ -71,7 +70,7 @@
71 DISALLOW_COPY_AND_ASSIGN(WarehouseDescr);70 DISALLOW_COPY_AND_ASSIGN(WarehouseDescr);
72};71};
7372
74class Warehouse : public Building, public Attackable, public SoldierControl {73class Warehouse : public Building, public SoldierControl {
75 friend class PortDock;74 friend class PortDock;
76 friend class MapBuildingdataPacket;75 friend class MapBuildingdataPacket;
7776
@@ -221,15 +220,6 @@
221 void enable_spawn(Game&, uint8_t worker_types_without_cost_index);220 void enable_spawn(Game&, uint8_t worker_types_without_cost_index);
222 void disable_spawn(uint8_t worker_types_without_cost_index);221 void disable_spawn(uint8_t worker_types_without_cost_index);
223222
224 // Begin Attackable implementation
225 Player& owner() const override {
226 return Building::owner();
227 }
228 bool can_attack() override;
229 void aggressor(Soldier&) override;
230 bool attack(Soldier&) override;
231 // End Attackable implementation
232
233 void receive_ware(Game&, DescriptionIndex ware) override;223 void receive_ware(Game&, DescriptionIndex ware) override;
234 void receive_worker(Game&, Worker& worker) override;224 void receive_worker(Game&, Worker& worker) override;
235225
@@ -250,13 +240,26 @@
250240
251 void log_general_info(const EditorGameBase&) override;241 void log_general_info(const EditorGameBase&) override;
252242
253protected:243private:
244 // A warehouse that conquers space can also be attacked.
245 class AttackTarget : public Widelands::AttackTarget {
246 public:
247 AttackTarget(Warehouse* warehouse) : warehouse_(warehouse) {
248 }
249
250 bool can_be_attacked() const override;
251 void enemy_soldier_approaches(const Soldier&) const override;
252 Widelands::AttackTarget::AttackResult attack(Soldier*) const override;
253
254 private:
255 Warehouse* const warehouse_;
256 };
257
258 void init_portdock(EditorGameBase& egbase);
259
254 /// Initializes the container sizes for the owner's tribe.260 /// Initializes the container sizes for the owner's tribe.
255 void init_containers(Player& owner);261 void init_containers(Player& owner);
256262
257private:
258 void init_portdock(EditorGameBase& egbase);
259
260 /**263 /**
261 * Plan to produce a certain worker type in this warehouse. This means264 * Plan to produce a certain worker type in this warehouse. This means
262 * requesting all the necessary wares, if multiple different wares types are265 * requesting all the necessary wares, if multiple different wares types are
@@ -282,6 +285,7 @@
282 void update_planned_workers(Game&, PlannedWorkers& pw);285 void update_planned_workers(Game&, PlannedWorkers& pw);
283 void update_all_planned_workers(Game&);286 void update_all_planned_workers(Game&);
284287
288 AttackTarget attack_target_;
285 WarehouseSupply* supply_;289 WarehouseSupply* supply_;
286290
287 std::vector<StockPolicy> ware_policy_;291 std::vector<StockPolicy> ware_policy_;
288292
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2017-04-22 05:35:46 +0000
+++ src/logic/player.cc 2017-05-21 11:20:39 +0000
@@ -452,8 +452,8 @@
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);
453453
454 // Make sure that the player owns the area around.454 // Make sure that the player owns the area around.
455 dynamic_cast<Game&>(egbase())455 dynamic_cast<Game&>(egbase()).conquer_area_no_building(
456 .conquer_area_no_building(PlayerArea<Area<FCoords>>(player_number(), Area<FCoords>(c, 1)));456 PlayerArea<Area<FCoords>>(player_number(), Area<FCoords>(c, 1)));
457457
458 if (BaseImmovable* const immovable = c.field->get_immovable()) {458 if (BaseImmovable* const immovable = c.field->get_immovable()) {
459 assert(immovable != &start);459 assert(immovable != &start);
@@ -869,8 +869,8 @@
869 log("enemyflagaction: count is 0\n");869 log("enemyflagaction: count is 0\n");
870 else if (is_hostile(flag.owner())) {870 else if (is_hostile(flag.owner())) {
871 if (Building* const building = flag.get_building()) {871 if (Building* const building = flag.get_building()) {
872 if (upcast(Attackable, attackable, building)) {872 if (const AttackTarget* attack_target = building->attack_target()) {
873 if (attackable->can_attack()) {873 if (attack_target->can_be_attacked()) {
874 std::vector<Soldier*> attackers;874 std::vector<Soldier*> attackers;
875 find_attack_soldiers(flag, &attackers, count);875 find_attack_soldiers(flag, &attackers, count);
876 assert(attackers.size() <= count);876 assert(attackers.size() <= count);
877877
=== modified file 'src/wui/attack_box.h'
--- src/wui/attack_box.h 2017-02-23 17:58:25 +0000
+++ src/wui/attack_box.h 2017-05-21 11:20:39 +0000
@@ -26,7 +26,6 @@
26#include "graphic/font_handler1.h"26#include "graphic/font_handler1.h"
27#include "graphic/text/font_set.h"27#include "graphic/text/font_set.h"
28#include "graphic/text_constants.h"28#include "graphic/text_constants.h"
29#include "logic/map_objects/attackable.h"
30#include "logic/map_objects/bob.h"29#include "logic/map_objects/bob.h"
31#include "logic/map_objects/tribes/soldier.h"30#include "logic/map_objects/tribes/soldier.h"
32#include "logic/player.h"31#include "logic/player.h"
3332
=== modified file 'src/wui/fieldaction.cc'
--- src/wui/fieldaction.cc 2017-02-27 19:10:24 +0000
+++ src/wui/fieldaction.cc 2017-05-21 11:20:39 +0000
@@ -26,7 +26,7 @@
26#include "economy/road.h"26#include "economy/road.h"
27#include "graphic/graphic.h"27#include "graphic/graphic.h"
28#include "logic/cmd_queue.h"28#include "logic/cmd_queue.h"
29#include "logic/map_objects/attackable.h"29#include "logic/map_objects/tribes/attack_target.h"
30#include "logic/map_objects/tribes/soldier.h"30#include "logic/map_objects/tribes/soldier.h"
31#include "logic/map_objects/tribes/tribe_descr.h"31#include "logic/map_objects/tribes/tribe_descr.h"
32#include "logic/map_objects/tribes/warehouse.h"32#include "logic/map_objects/tribes/warehouse.h"
@@ -380,13 +380,16 @@
380void FieldActionWindow::add_buttons_attack() {380void FieldActionWindow::add_buttons_attack() {
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);
382382
383 if (upcast(Widelands::Attackable, attackable, map_->get_immovable(node_))) {383 if (upcast(Widelands::Building, building, map_->get_immovable(node_))) {
384 if (player_ && player_->is_hostile(attackable->owner()) && attackable->can_attack()) {384 if (const Widelands::AttackTarget* attack_target = building->attack_target()) {
385 attack_box_ = new AttackBox(&a_box, player_, &node_, 0, 0);385 if (player_ && player_->is_hostile(building->owner()) &&
386 a_box.add(attack_box_);386 attack_target->can_be_attacked()) {
387 attack_box_ = new AttackBox(&a_box, player_, &node_, 0, 0);
388 a_box.add(attack_box_);
387389
388 set_fastclick_panel(&add_button(390 set_fastclick_panel(&add_button(
389 &a_box, "attack", pic_attack, &FieldActionWindow::act_attack, _("Start attack")));391 &a_box, "attack", pic_attack, &FieldActionWindow::act_attack, _("Start attack")));
392 }
390 }393 }
391 }394 }
392395

Subscribers

People subscribed via source and target branches

to status/vote changes: