widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #10463
[Merge] lp:~widelands-dev/widelands/00_soldier_control into lp:widelands
SirVer has proposed merging lp:~widelands-dev/widelands/00_soldier_control into lp:widelands.
Commit message:
Refactor SoldierControl to use composition instead of inheritance.
The interface is still weird, but at least this gets rid of some DynamicCasts. It could potentially modify behavior of MilitarySite, Warehouses (+ Headquarters and ports) or Trainingsites, though nothing of this would be intentional.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/00_soldier_control/+merge/325902
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/00_soldier_control into lp:widelands.
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2017-01-28 14:53:28 +0000
+++ src/ai/defaultai.cc 2017-06-19 07:06:15 +0000
@@ -1306,11 +1306,10 @@
const int32_t radius = militarysite->descr().get_conquers() + 4;
if (radius > dist) {
-
- field.area_military_capacity += militarysite->max_soldier_capacity();
- field.area_military_presence += militarysite->stationed_soldiers().size();
-
- if (militarysite->stationed_soldiers().empty()) {
+ field.area_military_capacity += militarysite->soldier_control()->max_soldier_capacity();
+ field.area_military_presence += militarysite->soldier_control()->stationed_soldiers().size();
+
+ if (militarysite->soldier_control()->stationed_soldiers().empty()) {
field.military_unstationed += 1;
} else {
field.military_stationed += 1;
@@ -2811,7 +2810,7 @@
bool occupied_military_ = false;
Building* b = flag.get_building();
if (upcast(MilitarySite, militb, b)) {
- if (militb->stationed_soldiers().size() > 0) {
+ if (militb->soldier_control()->stationed_soldiers().size() > 0) {
occupied_military_ = true;
}
}
=== modified file 'src/ai/defaultai_warfare.cc'
--- src/ai/defaultai_warfare.cc 2017-05-20 22:42:49 +0000
+++ src/ai/defaultai_warfare.cc 2017-06-19 07:06:15 +0000
@@ -225,7 +225,7 @@
if (upcast(MilitarySite, bld, f.field->get_immovable())) {
if (player_->is_hostile(bld->owner())) {
std::vector<Soldier*> defenders;
- defenders = bld->present_soldiers();
+ defenders = bld->soldier_control()->present_soldiers();
defenders_strength = calculate_strength(defenders);
flag = &bld->base_flag();
@@ -239,7 +239,7 @@
if (player_->is_hostile(Wh->owner())) {
std::vector<Soldier*> defenders;
- defenders = Wh->present_soldiers();
+ defenders = Wh->soldier_control()->present_soldiers();
defenders_strength = calculate_strength(defenders);
flag = &Wh->base_flag();
@@ -434,12 +434,13 @@
// counting vacant positions
vacant_mil_positions_ = 0;
for (TrainingSiteObserver tso : trainingsites) {
- vacant_mil_positions_ +=
- 10 * (tso.site->soldier_capacity() - tso.site->stationed_soldiers().size());
+ vacant_mil_positions_ += 10 * (tso.site->soldier_control()->soldier_capacity() -
+ tso.site->soldier_control()->stationed_soldiers().size());
vacant_mil_positions_ += (tso.site->can_start_working()) ? 0 : 10;
}
for (MilitarySiteObserver mso : militarysites) {
- vacant_mil_positions_ += mso.site->soldier_capacity() - mso.site->stationed_soldiers().size();
+ vacant_mil_positions_ += mso.site->soldier_control()->soldier_capacity() -
+ mso.site->soldier_control()->stationed_soldiers().size();
}
}
@@ -470,8 +471,8 @@
}
// changing capacity to 0 - this will happen only once.....
- if (tso.site->soldier_capacity() > 1) {
- game().send_player_change_soldier_capacity(*ts, -tso.site->soldier_capacity());
+ if (tso.site->soldier_control()->soldier_capacity() > 1) {
+ game().send_player_change_soldier_capacity(*ts, -tso.site->soldier_control()->soldier_capacity());
return true;
}
@@ -512,7 +513,7 @@
// if soldier capacity is set to 0, we need to find out if the site is
// supplied enough to incrase the capacity to 1
- if (tso.site->soldier_capacity() == 0) {
+ if (tso.site->soldier_control()->soldier_capacity() == 0) {
// First subsitute wares
int32_t filled = 0;
@@ -610,7 +611,7 @@
// same economy where the thrown out soldiers can go to.
if (ms->economy().warehouses().size()) {
- uint32_t const j = ms->soldier_capacity();
+ uint32_t const j = ms->soldier_control()->soldier_capacity();
if (MilitarySite::kPrefersRookies != ms->get_soldier_preference()) {
game().send_player_militarysite_set_soldier_preference(
@@ -665,8 +666,8 @@
if (other_player_accessible(
vision + 4, &unused1, &unused2, ms->get_position(), WalkSearch::kEnemy)) {
- Quantity const total_capacity = ms->max_soldier_capacity();
- Quantity const target_capacity = ms->soldier_capacity();
+ Quantity const total_capacity = ms->soldier_control()->max_soldier_capacity();
+ Quantity const target_capacity = ms->soldier_control()->soldier_capacity();
game().send_player_change_soldier_capacity(*ms, total_capacity - target_capacity);
changed = true;
@@ -681,7 +682,7 @@
mso.enemies_nearby = true;
enemy_last_seen_ = gametime;
} else { // otherwise decrease soldiers
- uint32_t const j = ms->soldier_capacity();
+ uint32_t const j = ms->soldier_control()->soldier_capacity();
if (MilitarySite::kPrefersRookies != ms->get_soldier_preference()) {
game().send_player_militarysite_set_soldier_preference(
@@ -785,9 +786,9 @@
for (TrainingSiteObserver& trainingsite_obs : trainingsites) {
if (trainingsite_obs.site == &site) {
- if (trainingsite_obs.site->soldier_capacity() > 0) {
+ if (trainingsite_obs.site->soldier_control()->soldier_capacity() > 0) {
game().send_player_change_soldier_capacity(
- *trainingsite_obs.site, -trainingsite_obs.site->soldier_capacity());
+ *trainingsite_obs.site, -trainingsite_obs.site->soldier_control()->soldier_capacity());
}
return;
}
=== modified file 'src/logic/map_objects/tribes/building.cc'
--- src/logic/map_objects/tribes/building.cc 2017-05-25 13:00:12 +0000
+++ src/logic/map_objects/tribes/building.cc 2017-06-19 07:06:15 +0000
@@ -244,7 +244,8 @@
leave_time_(0),
defeating_player_(0),
seeing_(false),
- attack_target_(nullptr) {
+ attack_target_(nullptr),
+ soldier_control_(nullptr) {
}
void Building::load_finish(EditorGameBase& egbase) {
@@ -706,6 +707,11 @@
attack_target_ = new_attack_target;
}
+void Building::set_soldier_control(SoldierControl* new_soldier_control) {
+ assert(soldier_control_ == nullptr);
+ soldier_control_ = new_soldier_control;
+}
+
/**
* Change whether this building sees its vision range based on workers
* inside the building.
=== modified file 'src/logic/map_objects/tribes/building.h'
--- src/logic/map_objects/tribes/building.h 2017-05-25 12:31:33 +0000
+++ src/logic/map_objects/tribes/building.h 2017-06-19 07:06:15 +0000
@@ -32,6 +32,7 @@
#include "logic/map_objects/immovable.h"
#include "logic/map_objects/tribes/attack_target.h"
#include "logic/map_objects/tribes/bill_of_materials.h"
+#include "logic/map_objects/tribes/soldiercontrol.h"
#include "logic/map_objects/tribes/wareworker.h"
#include "logic/map_objects/tribes/workarea_info.h"
#include "logic/message.h"
@@ -293,13 +294,21 @@
void add_worker(Worker&) override;
void remove_worker(Worker&) override;
- // Returns the AttackTarget object associated with this building. If the
- // building can never be attacked (for example productionsites) this will be
- // nullptr.
+ // AttackTarget object associated with this building. If the building can
+ // never be attacked (for example productionsites) this will be nullptr.
const AttackTarget* attack_target() const {
return attack_target_;
}
+ // SoldierControl object associated with this building. If the building can
+ // not house soldiers (for example productionsites) this will be nullptr.
+ const SoldierControl* soldier_control() const {
+ return soldier_control_;
+ }
+ SoldierControl* mutable_soldier_control() {
+ return soldier_control_;
+ }
+
void send_message(Game& game,
const Message::Type msgtype,
const std::string& title,
@@ -332,6 +341,7 @@
void set_seeing(bool see);
void set_attack_target(AttackTarget* new_attack_target);
+ void set_soldier_control(SoldierControl* new_soldier_control);
Coords position_;
Flag* flag_;
@@ -359,6 +369,7 @@
private:
std::string statistics_string_;
AttackTarget* attack_target_; // owned by the base classes, set by 'set_attack_target'.
+ SoldierControl* soldier_control_; // owned by the base classes, set by 'set_soldier_control'.
};
}
=== modified file 'src/logic/map_objects/tribes/militarysite.cc'
--- src/logic/map_objects/tribes/militarysite.cc 2017-06-06 05:26:58 +0000
+++ src/logic/map_objects/tribes/militarysite.cc 2017-06-19 07:06:15 +0000
@@ -43,6 +43,114 @@
namespace Widelands {
+// TODO(sirver): This method should probably return a const reference.
+std::vector<Soldier*> MilitarySite::SoldierControl::present_soldiers() const {
+ std::vector<Soldier*> soldiers;
+
+ for (Worker* worker : military_site_->get_workers()) {
+ if (upcast(Soldier, soldier, worker)) {
+ if (military_site_->is_present(*soldier)) {
+ soldiers.push_back(soldier);
+ }
+ }
+ }
+ return soldiers;
+}
+
+// TODO(sirver): This method should probably return a const reference.
+std::vector<Soldier*> MilitarySite::SoldierControl::stationed_soldiers() const {
+ std::vector<Soldier*> soldiers;
+
+ for (Worker* worker : military_site_->get_workers()) {
+ if (upcast(Soldier, soldier, worker)) {
+ soldiers.push_back(soldier);
+ }
+ }
+ return soldiers;
+}
+
+Quantity MilitarySite::SoldierControl::min_soldier_capacity() const {
+ return 1;
+}
+
+Quantity MilitarySite::SoldierControl::max_soldier_capacity() const {
+ return military_site_->descr().get_max_number_of_soldiers();
+}
+
+Quantity MilitarySite::SoldierControl::soldier_capacity() const {
+ return military_site_->capacity_;
+}
+
+void MilitarySite::SoldierControl::set_soldier_capacity(uint32_t const capacity) {
+ assert(min_soldier_capacity() <= capacity);
+ assert(capacity <= max_soldier_capacity());
+ assert(military_site_->capacity_ != capacity);
+ military_site_->capacity_ = capacity;
+ military_site_->update_soldier_request();
+}
+
+void MilitarySite::SoldierControl::drop_soldier(Soldier& soldier) {
+ Game& game = dynamic_cast<Game&>(military_site_->owner().egbase());
+
+ if (!military_site_->is_present(soldier)) {
+ // This can happen when the "drop soldier" player command is delayed
+ // by network delay or a client has bugs.
+ military_site_->molog("MilitarySite::drop_soldier(%u): not present\n", soldier.serial());
+ return;
+ }
+ if (present_soldiers().size() <= min_soldier_capacity()) {
+ military_site_->molog("cannot drop last soldier(s)\n");
+ return;
+ }
+
+ soldier.reset_tasks(game);
+ soldier.start_task_leavebuilding(game, true);
+
+ military_site_->update_soldier_request();
+}
+
+int MilitarySite::SoldierControl::incorporate_soldier(EditorGameBase& egbase, Soldier& s) {
+ if (s.get_location(egbase) != military_site_) {
+ s.set_location(military_site_);
+ }
+
+ // Soldier upgrade is done once the site is full. In soldier upgrade, we
+ // request one new soldier who is better suited than the existing ones.
+ // Normally, I kick out one existing soldier as soon as a new guy starts walking
+ // towards here. However, since that is done via infrequent polling, a new soldier
+ // can sometimes reach the site before such kick-out happens. In those cases, we
+ // should either drop one of the existing soldiers or reject the new guy, to
+ // avoid overstocking this site.
+
+ if (stationed_soldiers().size() > military_site_->descr().get_max_number_of_soldiers()) {
+ return military_site_->incorporate_upgraded_soldier(egbase, s) ? 0 : -1;
+ }
+
+ if (!military_site_->didconquer_) {
+ military_site_->conquer_area(egbase);
+ // Building is now occupied - idle animation should be played
+ military_site_->start_animation(egbase, military_site_->descr().get_animation("idle"));
+
+ if (upcast(Game, game, &egbase)) {
+ military_site_->send_message(
+ *game, Message::Type::kEconomySiteOccupied, military_site_->descr().descname(),
+ military_site_->descr().icon_filename(), military_site_->descr().descname(),
+ military_site_->descr().occupied_str_, true);
+ }
+ }
+
+ if (upcast(Game, game, &egbase)) {
+ // Bind the worker into this house, hide him on the map
+ s.reset_tasks(*game);
+ s.start_task_buildingwork(*game);
+ }
+
+ // Make sure the request count is reduced or the request is deleted.
+ military_site_->update_soldier_request(true);
+
+ return 0;
+}
+
bool MilitarySite::AttackTarget::can_be_attacked() const {
return military_site_->didconquer_;
}
@@ -63,7 +171,7 @@
// We're dealing with a soldier that we might want to keep busy
// Now would be the time to implement some player-definable
// policy as to how many soldiers are allowed to leave as defenders
- std::vector<Soldier*> present = military_site_->present_soldiers();
+ std::vector<Soldier*> present = military_site_->soldier_control_.present_soldiers();
if (1 < present.size()) {
for (Soldier* temp_soldier : present) {
@@ -87,7 +195,7 @@
AttackTarget::AttackResult MilitarySite::AttackTarget::attack(Soldier* enemy) const {
Game& game = dynamic_cast<Game&>(military_site_->owner().egbase());
- std::vector<Soldier*> present = military_site_->present_soldiers();
+ std::vector<Soldier*> present = military_site_->soldier_control_.present_soldiers();
Soldier* defender = nullptr;
if (!present.empty()) {
@@ -102,7 +210,7 @@
} else {
// If one of our stationed soldiers is currently walking into the
// building, give us another chance.
- std::vector<Soldier*> stationed = military_site_->stationed_soldiers();
+ std::vector<Soldier*> stationed = military_site_->soldier_control_.stationed_soldiers();
for (Soldier* temp_soldier : stationed) {
if (temp_soldier->get_position() == military_site_->get_position()) {
defender = temp_soldier;
@@ -233,6 +341,7 @@
MilitarySite::MilitarySite(const MilitarySiteDescr& ms_descr)
: Building(ms_descr),
attack_target_(this),
+ soldier_control_(this),
didconquer_(false),
capacity_(ms_descr.get_max_number_of_soldiers()),
nexthealtime_(0),
@@ -241,6 +350,7 @@
doing_upgrade_request_(false) {
next_swap_soldiers_time_ = 0;
set_attack_target(&attack_target_);
+ set_soldier_control(&soldier_control_);
}
MilitarySite::~MilitarySite() {
@@ -255,8 +365,8 @@
*/
void MilitarySite::update_statistics_string(std::string* s) {
s->clear();
- Quantity present = present_soldiers().size();
- Quantity stationed = stationed_soldiers().size();
+ Quantity present = soldier_control_.present_soldiers().size();
+ Quantity stationed = soldier_control_.stationed_soldiers().size();
if (present == stationed) {
if (capacity_ > stationed) {
@@ -356,60 +466,12 @@
}
/*
-===============
-Takes one soldier and adds him to ours
-
-returns 0 on succes, -1 if there was no room for this soldier
-===============
-*/
-int MilitarySite::incorporate_soldier(EditorGameBase& egbase, Soldier& s) {
-
- if (s.get_location(egbase) != this) {
- s.set_location(this);
- }
-
- // Soldier upgrade is done once the site is full. In soldier upgrade, we
- // request one new soldier who is better suited than the existing ones.
- // Normally, I kick out one existing soldier as soon as a new guy starts walking
- // towards here. However, since that is done via infrequent polling, a new soldier
- // can sometimes reach the site before such kick-out happens. In those cases, we
- // should either drop one of the existing soldiers or reject the new guy, to
- // avoid overstocking this site.
-
- if (stationed_soldiers().size() > descr().get_max_number_of_soldiers()) {
- return incorporate_upgraded_soldier(egbase, s) ? 0 : -1;
- }
-
- if (!didconquer_) {
- conquer_area(egbase);
- // Building is now occupied - idle animation should be played
- start_animation(egbase, descr().get_animation("idle"));
-
- if (upcast(Game, game, &egbase)) {
- send_message(*game, Message::Type::kEconomySiteOccupied, descr().descname(),
- descr().icon_filename(), descr().descname(), descr().occupied_str_, true);
- }
- }
-
- if (upcast(Game, game, &egbase)) {
- // Bind the worker into this house, hide him on the map
- s.reset_tasks(*game);
- s.start_task_buildingwork(*game);
- }
-
- // Make sure the request count is reduced or the request is deleted.
- update_soldier_request(true);
-
- return 0;
-}
-
-/*
* Returns the least wanted soldier -- If player prefers zero-level guys,
* the most trained soldier is the "weakest guy".
*/
Soldier* MilitarySite::find_least_suited_soldier() {
- const std::vector<Soldier*> present = present_soldiers();
+ const std::vector<Soldier*> present = soldier_control_.present_soldiers();
const int32_t multiplier = kPrefersHeroes == soldier_preference_ ? -1 : 1;
int worst_soldier_level = INT_MIN;
Soldier* worst_soldier = nullptr;
@@ -439,7 +501,7 @@
*/
bool MilitarySite::drop_least_suited_soldier(bool new_soldier_has_arrived, Soldier* newguy) {
- const std::vector<Soldier*> present = present_soldiers();
+ const std::vector<Soldier*> present = soldier_control_.present_soldiers();
// If I have only one soldier, and the new guy is not here yet, I can't release.
if (new_soldier_has_arrived || 1 < present.size()) {
@@ -474,7 +536,7 @@
*/
bool MilitarySite::incorporate_upgraded_soldier(EditorGameBase& egbase, Soldier& s) {
// Call to drop_least routine has side effects: it tries to drop a soldier. Order is important!
- if (stationed_soldiers().size() < capacity_ || drop_least_suited_soldier(true, &s)) {
+ if (soldier_control_.stationed_soldiers().size() < capacity_ || drop_least_suited_soldier(true, &s)) {
Game& game = dynamic_cast<Game&>(egbase);
s.set_location(this);
s.reset_tasks(game);
@@ -494,7 +556,7 @@
MilitarySite& msite = dynamic_cast<MilitarySite&>(target);
Soldier& s = dynamic_cast<Soldier&>(*w);
- msite.incorporate_soldier(game, s);
+ msite.soldier_control_.incorporate_soldier(game, s);
}
/**
@@ -502,8 +564,8 @@
* as appropriate.
*/
void MilitarySite::update_normal_soldier_request() {
- std::vector<Soldier*> present = present_soldiers();
- Quantity const stationed = stationed_soldiers().size();
+ std::vector<Soldier*> present = soldier_control_.present_soldiers();
+ Quantity const stationed = soldier_control_.stationed_soldiers().size();
if (stationed < capacity_) {
if (!normal_soldier_request_) {
@@ -582,8 +644,8 @@
*/
void MilitarySite::update_soldier_request(bool incd) {
- const uint32_t capacity = soldier_capacity();
- const uint32_t stationed = stationed_soldiers().size();
+ const uint32_t capacity = soldier_control_.soldier_capacity();
+ const uint32_t stationed = soldier_control_.stationed_soldiers().size();
if (doing_upgrade_request_) {
if (incd && upgrade_soldier_request_) // update requests always ask for one soldier at time!
@@ -625,7 +687,7 @@
update_normal_soldier_request();
if ((capacity == stationed) && (!normal_soldier_request_)) {
- if (present_soldiers().size() == capacity) {
+ if (soldier_control_.present_soldiers().size() == capacity) {
doing_upgrade_request_ = true;
update_upgrade_soldier_request();
}
@@ -668,7 +730,7 @@
if (nexthealtime_ <= timeofgame) {
uint32_t total_heal = descr().get_heal_per_second();
- std::vector<Soldier*> soldiers = present_soldiers();
+ std::vector<Soldier*> soldiers = soldier_control_.present_soldiers();
uint32_t max_total_level = 0;
float max_health = 0;
Soldier* soldier_to_heal = 0;
@@ -720,7 +782,7 @@
bool MilitarySite::get_building_work(Game& game, Worker& worker, bool) {
if (upcast(Soldier, soldier, &worker)) {
// Evict soldiers that have returned home if the capacity is too low
- if (capacity_ < present_soldiers().size()) {
+ if (capacity_ < soldier_control_.present_soldiers().size()) {
worker.reset_tasks(game);
worker.start_task_leavebuilding(game, true);
return true;
@@ -755,70 +817,6 @@
soldier.get_position() == get_position();
}
-// TODO(sirver): This method should probably return a const reference.
-std::vector<Soldier*> MilitarySite::present_soldiers() const {
- std::vector<Soldier*> soldiers;
-
- for (Worker* worker : get_workers()) {
- if (upcast(Soldier, soldier, worker)) {
- if (is_present(*soldier)) {
- soldiers.push_back(soldier);
- }
- }
- }
- return soldiers;
-}
-
-// TODO(sirver): This method should probably return a const reference.
-std::vector<Soldier*> MilitarySite::stationed_soldiers() const {
- std::vector<Soldier*> soldiers;
-
- for (Worker* worker : get_workers()) {
- if (upcast(Soldier, soldier, worker)) {
- soldiers.push_back(soldier);
- }
- }
- return soldiers;
-}
-
-Quantity MilitarySite::min_soldier_capacity() const {
- return 1;
-}
-Quantity MilitarySite::max_soldier_capacity() const {
- return descr().get_max_number_of_soldiers();
-}
-Quantity MilitarySite::soldier_capacity() const {
- return capacity_;
-}
-
-void MilitarySite::set_soldier_capacity(uint32_t const capacity) {
- assert(min_soldier_capacity() <= capacity);
- assert(capacity <= max_soldier_capacity());
- assert(capacity_ != capacity);
- capacity_ = capacity;
- update_soldier_request();
-}
-
-void MilitarySite::drop_soldier(Soldier& soldier) {
- Game& game = dynamic_cast<Game&>(owner().egbase());
-
- if (!is_present(soldier)) {
- // This can happen when the "drop soldier" player command is delayed
- // by network delay or a client has bugs.
- molog("MilitarySite::drop_soldier(%u): not present\n", soldier.serial());
- return;
- }
- if (present_soldiers().size() <= min_soldier_capacity()) {
- molog("cannot drop last soldier(s)\n");
- return;
- }
-
- soldier.reset_tasks(game);
- soldier.start_task_leavebuilding(game, true);
-
- update_soldier_request();
-}
-
void MilitarySite::conquer_area(EditorGameBase& egbase) {
assert(!didconquer_);
egbase.conquer_area(PlayerArea<Area<FCoords>>(
=== modified file 'src/logic/map_objects/tribes/militarysite.h'
--- src/logic/map_objects/tribes/militarysite.h 2017-05-20 22:42:49 +0000
+++ src/logic/map_objects/tribes/militarysite.h 2017-06-19 07:06:15 +0000
@@ -68,7 +68,7 @@
DISALLOW_COPY_AND_ASSIGN(MilitarySiteDescr);
};
-class MilitarySite : public Building, public SoldierControl {
+class MilitarySite : public Building {
friend class MapBuildingdataPacket;
MO_DESCR(MilitarySiteDescr)
@@ -91,16 +91,6 @@
void set_economy(Economy*) override;
bool get_building_work(Game&, Worker&, bool success) override;
- // Begin implementation of SoldierControl
- std::vector<Soldier*> present_soldiers() const override;
- std::vector<Soldier*> stationed_soldiers() const override;
- Quantity min_soldier_capacity() const override;
- Quantity max_soldier_capacity() const override;
- Quantity soldier_capacity() const override;
- void set_soldier_capacity(Quantity capacity) override;
- void drop_soldier(Soldier&) override;
- int incorporate_soldier(EditorGameBase& game, Soldier& s) override;
-
/// Launch the given soldier on an attack towards the given
/// target building.
void send_attacker(Soldier&, Building&);
@@ -157,7 +147,26 @@
MilitarySite* const military_site_;
};
+ class SoldierControl : public Widelands::SoldierControl {
+ public:
+ explicit SoldierControl(MilitarySite* military_site) : military_site_(military_site) {
+ }
+
+ std::vector<Soldier*> present_soldiers() const override;
+ std::vector<Soldier*> stationed_soldiers() const override;
+ Quantity min_soldier_capacity() const override;
+ Quantity max_soldier_capacity() const override;
+ Quantity soldier_capacity() const override;
+ void set_soldier_capacity(Quantity capacity) override;
+ void drop_soldier(Soldier&) override;
+ int incorporate_soldier(EditorGameBase& game, Soldier& s) override;
+
+ private:
+ MilitarySite* const military_site_;
+ };
+
AttackTarget attack_target_;
+ SoldierControl soldier_control_;
Requirements soldier_requirements_; // This is used to grab a bunch of soldiers: Anything goes
RequireAttribute soldier_upgrade_requirements_; // This is used when exchanging soldiers.
std::unique_ptr<Request> normal_soldier_request_; // filling the site
=== modified file 'src/logic/map_objects/tribes/production_program.cc'
--- src/logic/map_objects/tribes/production_program.cc 2017-06-15 22:00:08 +0000
+++ src/logic/map_objects/tribes/production_program.cc 2017-06-19 07:06:15 +0000
@@ -1276,8 +1276,9 @@
}
void ProductionProgram::ActCheckSoldier::execute(Game& game, ProductionSite& ps) const {
- SoldierControl& ctrl = dynamic_cast<SoldierControl&>(ps);
- const std::vector<Soldier*> soldiers = ctrl.present_soldiers();
+ const SoldierControl* ctrl = ps.soldier_control();
+ assert(ctrl != nullptr);
+ const std::vector<Soldier*> soldiers = ctrl->present_soldiers();
if (soldiers.empty()) {
ps.set_production_result(_("No soldier to train!"));
return ps.program_end(game, Skipped);
@@ -1355,8 +1356,8 @@
}
void ProductionProgram::ActTrain::execute(Game& game, ProductionSite& ps) const {
- SoldierControl& ctrl = dynamic_cast<SoldierControl&>(ps);
- const std::vector<Soldier*> soldiers = ctrl.present_soldiers();
+ const SoldierControl* ctrl = ps.soldier_control();;
+ const std::vector<Soldier*> soldiers = ctrl->present_soldiers();
const std::vector<Soldier*>::const_iterator soldiers_end = soldiers.end();
std::vector<Soldier*>::const_iterator it = soldiers.begin();
=== modified file 'src/logic/map_objects/tribes/soldier.cc'
--- src/logic/map_objects/tribes/soldier.cc 2017-05-21 22:18:02 +0000
+++ src/logic/map_objects/tribes/soldier.cc 2017-06-19 07:06:15 +0000
@@ -832,8 +832,8 @@
// Count remaining defenders
if (enemy) {
- if (upcast(MilitarySite, ms, enemy)) {
- defenders = ms->present_soldiers().size();
+ if (enemy->soldier_control() != nullptr) {
+ defenders = enemy->soldier_control()->present_soldiers().size();
}
if (upcast(Warehouse, wh, enemy)) {
Requirements noreq;
@@ -865,18 +865,18 @@
BaseImmovable* const newimm = game.map()[state.coords].get_immovable();
upcast(MilitarySite, newsite, newimm);
if (newsite && (&newsite->owner() == &owner())) {
- if (upcast(SoldierControl, ctrl, newsite)) {
- state.objvar1 = nullptr;
- // We may also have our location destroyed in between
- if (ctrl->stationed_soldiers().size() < ctrl->soldier_capacity() &&
- (!location ||
- location->base_flag().get_position() != newsite->base_flag().get_position())) {
- molog("[attack] enemy belongs to us now, move in\n");
- pop_task(game);
- set_location(newsite);
- newsite->update_soldier_request();
- return schedule_act(game, 10);
- }
+ const SoldierControl* soldier_control = newsite->soldier_control();
+ state.objvar1 = nullptr;
+ // We may also have our location destroyed in between
+ if (soldier_control->stationed_soldiers().size() <
+ soldier_control->soldier_capacity() &&
+ (!location ||
+ location->base_flag().get_position() != newsite->base_flag().get_position())) {
+ molog("[attack] enemy belongs to us now, move in\n");
+ pop_task(game);
+ set_location(newsite);
+ newsite->update_soldier_request();
+ return schedule_act(game, 10);
}
}
}
=== modified file 'src/logic/map_objects/tribes/soldiercontrol.h'
--- src/logic/map_objects/tribes/soldiercontrol.h 2017-01-25 18:55:59 +0000
+++ src/logic/map_objects/tribes/soldiercontrol.h 2017-06-19 07:06:15 +0000
@@ -41,7 +41,8 @@
* the two concepts are equal. However, they're different for a MilitarySite,
* where soldiers can be outside in combat.
*/
-struct SoldierControl {
+class SoldierControl {
+public:
/**
* \return a list of soldiers that are currently present in the building.
*/
@@ -78,16 +79,6 @@
*/
virtual void set_soldier_capacity(Quantity capacity) = 0;
- void changeSoldierCapacity(int32_t const difference) {
- Widelands::Quantity const old_capacity = soldier_capacity();
- Widelands::Quantity const new_capacity = std::min(
- static_cast<Widelands::Quantity>(std::max(static_cast<int32_t>(old_capacity) + difference,
- static_cast<int32_t>(min_soldier_capacity()))),
- max_soldier_capacity());
- if (old_capacity != new_capacity)
- set_soldier_capacity(new_capacity);
- }
-
/**
* Evict the given soldier from the building immediately,
* without changing the building's capacity.
@@ -108,7 +99,7 @@
* informed by the soldier when it is removed, but WareHouses for example
* will not.
*/
- virtual int outcorporate_soldier(EditorGameBase&, Soldier&) {
+ virtual int outcorporate_soldier(Soldier&) {
return 0;
}
@@ -116,6 +107,7 @@
virtual ~SoldierControl() {
}
};
+
}
#endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_SOLDIERCONTROL_H
=== modified file 'src/logic/map_objects/tribes/trainingsite.cc'
--- src/logic/map_objects/tribes/trainingsite.cc 2017-04-23 12:11:19 +0000
+++ src/logic/map_objects/tribes/trainingsite.cc 2017-06-19 07:06:15 +0000
@@ -178,6 +178,78 @@
}
}
+std::vector<Soldier*> TrainingSite::SoldierControl::present_soldiers() const {
+ return training_site_->soldiers_;
+}
+
+std::vector<Soldier*> TrainingSite::SoldierControl::stationed_soldiers() const {
+ return training_site_->soldiers_;
+}
+
+Quantity TrainingSite::SoldierControl::min_soldier_capacity() const {
+ return 0;
+}
+Quantity TrainingSite::SoldierControl::max_soldier_capacity() const {
+ return training_site_->descr().get_max_number_of_soldiers();
+}
+Quantity TrainingSite::SoldierControl::soldier_capacity() const {
+ return training_site_->capacity_;
+}
+
+void TrainingSite::SoldierControl::set_soldier_capacity(Quantity const capacity) {
+ assert(min_soldier_capacity() <= capacity);
+ assert(capacity <= max_soldier_capacity());
+ assert(training_site_->capacity_ != capacity);
+ training_site_->capacity_ = capacity;
+ training_site_->update_soldier_request();
+}
+
+/**
+ * Drop a given soldier.
+ *
+ * 'Dropping' means releasing the soldier from the site. The soldier then
+ * becomes available to the economy.
+ *
+ * \note This is called from player commands, so we need to verify that the
+ * soldier is actually stationed here, without breaking anything if he isn't.
+ */
+void TrainingSite::SoldierControl::drop_soldier(Soldier& soldier) {
+ Game& game = dynamic_cast<Game&>(training_site_->owner().egbase());
+
+ std::vector<Soldier*>::iterator it = std::find(training_site_->soldiers_.begin(), training_site_->soldiers_.end(), &soldier);
+ if (it == training_site_->soldiers_.end()) {
+ training_site_->molog("TrainingSite::SoldierControl::drop_soldier: soldier not in training site");
+ return;
+ }
+
+ training_site_->soldiers_.erase(it);
+
+ soldier.reset_tasks(game);
+ soldier.start_task_leavebuilding(game, true);
+
+ // Schedule, so that we can call new soldiers on next act()
+ training_site_->schedule_act(game, 100);
+ Notifications::publish(NoteTrainingSiteSoldierTrained(training_site_, training_site_->get_owner()));
+}
+
+int TrainingSite::SoldierControl::incorporate_soldier(EditorGameBase& egbase, Soldier& s) {
+ if (s.get_location(egbase) != training_site_) {
+ if (stationed_soldiers().size() + 1 > training_site_->descr().get_max_number_of_soldiers())
+ return -1;
+
+ s.set_location(training_site_);
+ }
+
+ // Bind the worker into this house, hide him on the map
+ if (upcast(Game, game, &egbase))
+ s.start_task_idle(*game, 0, -1);
+
+ // Make sure the request count is reduced or the request is deleted.
+ training_site_->update_soldier_request();
+
+ return 0;
+}
+
/*
=============================
@@ -188,10 +260,13 @@
TrainingSite::TrainingSite(const TrainingSiteDescr& d)
: ProductionSite(d),
+soldier_control_(this),
soldier_request_(nullptr),
capacity_(descr().get_max_number_of_soldiers()),
build_heroes_(false),
result_(Failed) {
+ set_soldier_control(&soldier_control_);
+
// Initialize this in the constructor so that loading code may
// overwrite priorities.
calc_upgrades();
@@ -329,7 +404,7 @@
soldier_request_ = nullptr;
while (soldiers_.size() > capacity_) {
- drop_soldier(**soldiers_.rbegin());
+ soldier_control_.drop_soldier(**soldiers_.rbegin());
}
}
}
@@ -353,86 +428,7 @@
assert(s.get_location(game) == &tsite);
assert(tsite.soldier_request_ == &rq);
- tsite.incorporate_soldier(game, s);
-}
-
-/*
-===============
-Takes one soldier and adds him to ours
-
-returns 0 on succes, -1 if there was no room for this soldier
-===============
-*/
-int TrainingSite::incorporate_soldier(EditorGameBase& egbase, Soldier& s) {
- if (s.get_location(egbase) != this) {
- if (stationed_soldiers().size() + 1 > descr().get_max_number_of_soldiers())
- return -1;
-
- s.set_location(this);
- }
-
- // Bind the worker into this house, hide him on the map
- if (upcast(Game, game, &egbase))
- s.start_task_idle(*game, 0, -1);
-
- // Make sure the request count is reduced or the request is deleted.
- update_soldier_request();
-
- return 0;
-}
-
-std::vector<Soldier*> TrainingSite::present_soldiers() const {
- return soldiers_;
-}
-
-std::vector<Soldier*> TrainingSite::stationed_soldiers() const {
- return soldiers_;
-}
-
-Quantity TrainingSite::min_soldier_capacity() const {
- return 0;
-}
-Quantity TrainingSite::max_soldier_capacity() const {
- return descr().get_max_number_of_soldiers();
-}
-Quantity TrainingSite::soldier_capacity() const {
- return capacity_;
-}
-
-void TrainingSite::set_soldier_capacity(Quantity const capacity) {
- assert(min_soldier_capacity() <= capacity);
- assert(capacity <= max_soldier_capacity());
- assert(capacity_ != capacity);
- capacity_ = capacity;
- update_soldier_request();
-}
-
-/**
- * Drop a given soldier.
- *
- * 'Dropping' means releasing the soldier from the site. The soldier then
- * becomes available to the economy.
- *
- * \note This is called from player commands, so we need to verify that the
- * soldier is actually stationed here, without breaking anything if he isn't.
- */
-void TrainingSite::drop_soldier(Soldier& soldier) {
- Game& game = dynamic_cast<Game&>(owner().egbase());
-
- std::vector<Soldier*>::iterator it = std::find(soldiers_.begin(), soldiers_.end(), &soldier);
- if (it == soldiers_.end()) {
- molog("TrainingSite::drop_soldier: soldier not in training site");
- return;
- }
-
- soldiers_.erase(it);
-
- soldier.reset_tasks(game);
- soldier.start_task_leavebuilding(game, true);
-
- // Schedule, so that we can call new soldiers on next act()
- schedule_act(game, 100);
- Notifications::publish(NoteTrainingSiteSoldierTrained(this, get_owner()));
+ tsite.soldier_control_.incorporate_soldier(game, s);
}
/**
@@ -456,7 +452,7 @@
// Drop soldiers only now, so that changes in the soldiers array don't
// mess things up
for (Soldier* soldier : droplist) {
- drop_soldier(*soldier);
+ soldier_control_.drop_soldier(*soldier);
}
}
@@ -518,7 +514,7 @@
// Finally drop the soldier.
if (nullptr != soldier_to_drop) {
log("TrainingSite::drop_stalled_soldiers: Kicking somebody out.\n");
- drop_soldier(*soldier_to_drop);
+ soldier_control_.drop_soldier(*soldier_to_drop);
}
}
=== modified file 'src/logic/map_objects/tribes/trainingsite.h'
--- src/logic/map_objects/tribes/trainingsite.h 2017-04-23 12:11:19 +0000
+++ src/logic/map_objects/tribes/trainingsite.h 2017-06-19 07:06:15 +0000
@@ -148,7 +148,7 @@
* surrounding strongholds, the training site will burn even if it
* contains soldiers!
*/
-class TrainingSite : public ProductionSite, public SoldierControl {
+class TrainingSite : public ProductionSite {
friend class MapBuildingdataPacket;
MO_DESCR(TrainingSiteDescr)
friend struct ::TrainingSiteWindow;
@@ -189,17 +189,6 @@
void set_economy(Economy* e) override;
- // Begin implementation of SoldierControl
- std::vector<Soldier*> present_soldiers() const override;
- std::vector<Soldier*> stationed_soldiers() const override;
- Quantity min_soldier_capacity() const override;
- Quantity max_soldier_capacity() const override;
- Quantity soldier_capacity() const override;
- void set_soldier_capacity(Quantity capacity) override;
- void drop_soldier(Soldier&) override;
- int incorporate_soldier(EditorGameBase&, Soldier&) override;
- // End implementation of SoldierControl
-
int32_t get_pri(enum TrainingAttribute atr);
void set_pri(enum TrainingAttribute atr, int32_t prio);
@@ -212,6 +201,24 @@
void program_end(Game&, ProgramResult) override;
private:
+ class SoldierControl : public Widelands::SoldierControl {
+ public:
+ explicit SoldierControl(TrainingSite* training_site) : training_site_(training_site) {
+ }
+
+ std::vector<Soldier*> present_soldiers() const override;
+ std::vector<Soldier*> stationed_soldiers() const override;
+ Quantity min_soldier_capacity() const override;
+ Quantity max_soldier_capacity() const override;
+ Quantity soldier_capacity() const override;
+ void set_soldier_capacity(Quantity capacity) override;
+ void drop_soldier(Soldier&) override;
+ int incorporate_soldier(EditorGameBase& game, Soldier& s) override;
+
+ private:
+ TrainingSite* const training_site_;
+ };
+
void update_soldier_request();
static void
request_soldier_callback(Game&, Request&, DescriptionIndex, Worker*, PlayerImmovable&);
@@ -225,6 +232,7 @@
void drop_stalled_soldiers(Game&);
Upgrade* get_upgrade(TrainingAttribute);
+ SoldierControl soldier_control_;
/// Open requests for soldiers. The soldiers can be under way or unavailable
Request* soldier_request_;
=== modified file 'src/logic/map_objects/tribes/warehouse.cc'
--- src/logic/map_objects/tribes/warehouse.cc 2017-05-20 22:42:49 +0000
+++ src/logic/map_objects/tribes/warehouse.cc 2017-06-19 07:06:15 +0000
@@ -303,21 +303,77 @@
}
}
-/*
-==============================
-IMPLEMENTATION
-==============================
-*/
+std::vector<Soldier*> Warehouse::SoldierControl::present_soldiers() const {
+ std::vector<Soldier*> rv;
+ DescriptionIndex const soldier_index = warehouse_->owner().tribe().soldier();
+ IncorporatedWorkers::const_iterator sidx = warehouse_->incorporated_workers_.find(soldier_index);
+
+ if (sidx != warehouse_->incorporated_workers_.end()) {
+ const WorkerList& soldiers = sidx->second;
+ for (Worker* temp_soldier : soldiers) {
+ rv.push_back(static_cast<Soldier*>(temp_soldier));
+ }
+ }
+ return rv;
+}
+
+std::vector<Soldier*> Warehouse::SoldierControl::stationed_soldiers() const {
+ return present_soldiers();
+}
+
+Quantity Warehouse::SoldierControl::min_soldier_capacity() const {
+ return 0;
+}
+
+Quantity Warehouse::SoldierControl::max_soldier_capacity() const {
+ return 4294967295U;
+}
+
+Quantity Warehouse::SoldierControl::soldier_capacity() const {
+ return max_soldier_capacity();
+}
+
+void Warehouse::SoldierControl::set_soldier_capacity(Quantity /* capacity */) {
+ throw wexception("Not implemented for a Warehouse!");
+}
+
+void Warehouse::SoldierControl::drop_soldier(Soldier&) {
+ throw wexception("Not implemented for a Warehouse!");
+}
+
+int Warehouse::SoldierControl::outcorporate_soldier(Soldier& soldier) {
+ DescriptionIndex const soldier_index = warehouse_->owner().tribe().soldier();
+ if (warehouse_->incorporated_workers_.count(soldier_index)) {
+ WorkerList& soldiers = warehouse_->incorporated_workers_[soldier_index];
+
+ WorkerList::iterator i = std::find(soldiers.begin(), soldiers.end(), &soldier);
+
+ soldiers.erase(i);
+ warehouse_->supply_->remove_workers(soldier_index, 1);
+ }
+#ifndef NDEBUG
+ else
+ throw wexception("outcorporate_soldier: soldier not in this warehouse!");
+#endif
+ return 0;
+}
+
+int Warehouse::SoldierControl::incorporate_soldier(EditorGameBase& egbase, Soldier& soldier) {
+ warehouse_->incorporate_worker(egbase, &soldier);
+ return 0;
+}
Warehouse::Warehouse(const WarehouseDescr& warehouse_descr)
: Building(warehouse_descr),
attack_target_(this),
+ soldier_control_(this),
supply_(new WarehouseSupply(this)),
next_military_act_(0),
portdock_(nullptr) {
next_stock_remove_act_ = 0;
cleanup_in_progress_ = false;
set_attack_target(&attack_target_);
+ set_soldier_control(&soldier_control_);
}
Warehouse::~Warehouse() {
@@ -1287,49 +1343,6 @@
return portdock_->expedition_bootstrap()->inputqueue(index, type);
}
-/*
- * SoldierControl implementations
- */
-std::vector<Soldier*> Warehouse::present_soldiers() const {
- std::vector<Soldier*> rv;
-
- DescriptionIndex const soldier_index = owner().tribe().soldier();
- IncorporatedWorkers::const_iterator sidx = incorporated_workers_.find(soldier_index);
-
- if (sidx != incorporated_workers_.end()) {
- const WorkerList& soldiers = sidx->second;
-
- for (Worker* temp_soldier : soldiers) {
- rv.push_back(static_cast<Soldier*>(temp_soldier));
- }
- }
-
- return rv;
-}
-int Warehouse::incorporate_soldier(EditorGameBase& egbase, Soldier& soldier) {
- incorporate_worker(egbase, &soldier);
- return 0;
-}
-
-int Warehouse::outcorporate_soldier(EditorGameBase& /* egbase */, Soldier& soldier) {
-
- DescriptionIndex const soldier_index = owner().tribe().soldier();
- if (incorporated_workers_.count(soldier_index)) {
- WorkerList& soldiers = incorporated_workers_[soldier_index];
-
- WorkerList::iterator i = std::find(soldiers.begin(), soldiers.end(), &soldier);
-
- soldiers.erase(i);
- supply_->remove_workers(soldier_index, 1);
- }
-#ifndef NDEBUG
- else
- throw wexception("outcorporate_soldier: soldier not in this warehouse!");
-#endif
-
- return 0;
-}
-
void Warehouse::log_general_info(const EditorGameBase& egbase) {
Building::log_general_info(egbase);
=== modified file 'src/logic/map_objects/tribes/warehouse.h'
--- src/logic/map_objects/tribes/warehouse.h 2017-05-20 22:42:49 +0000
+++ src/logic/map_objects/tribes/warehouse.h 2017-06-19 07:06:15 +0000
@@ -70,7 +70,7 @@
DISALLOW_COPY_AND_ASSIGN(WarehouseDescr);
};
-class Warehouse : public Building, public SoldierControl {
+class Warehouse : public Building {
friend class PortDock;
friend class MapBuildingdataPacket;
@@ -172,29 +172,6 @@
void insert_workers(DescriptionIndex, Quantity count);
void remove_workers(DescriptionIndex, Quantity count);
- /* SoldierControl implementation */
- std::vector<Soldier*> present_soldiers() const override;
- std::vector<Soldier*> stationed_soldiers() const override {
- return present_soldiers();
- }
- Quantity min_soldier_capacity() const override {
- return 0;
- }
- Quantity max_soldier_capacity() const override {
- return 4294967295U;
- }
- Quantity soldier_capacity() const override {
- return max_soldier_capacity();
- }
- void set_soldier_capacity(Quantity /* capacity */) override {
- throw wexception("Not implemented for a Warehouse!");
- }
- void drop_soldier(Soldier&) override {
- throw wexception("Not implemented for a Warehouse!");
- }
- int outcorporate_soldier(EditorGameBase&, Soldier&) override;
- int incorporate_soldier(EditorGameBase&, Soldier& soldier) override;
-
bool fetch_from_flag(Game&) override;
Quantity count_workers(const Game&, DescriptionIndex worker, const Requirements&, Match);
@@ -241,6 +218,25 @@
void log_general_info(const EditorGameBase&) override;
private:
+ class SoldierControl : public Widelands::SoldierControl {
+ public:
+ explicit SoldierControl(Warehouse* warehouse) : warehouse_(warehouse) {
+ }
+
+ std::vector<Soldier*> present_soldiers() const override;
+ std::vector<Soldier*> stationed_soldiers() const override;
+ Quantity min_soldier_capacity() const override;
+ Quantity max_soldier_capacity() const override;
+ Quantity soldier_capacity() const override;
+ void set_soldier_capacity(Quantity capacity) override;
+ void drop_soldier(Soldier&) override;
+ int incorporate_soldier(EditorGameBase& game, Soldier& s) override;
+ int outcorporate_soldier(Soldier&) override;
+
+ private:
+ Warehouse* const warehouse_;
+ };
+
// A warehouse that conquers space can also be attacked.
class AttackTarget : public Widelands::AttackTarget {
public:
@@ -286,6 +282,7 @@
void update_all_planned_workers(Game&);
AttackTarget attack_target_;
+ SoldierControl soldier_control_;
WarehouseSupply* supply_;
std::vector<StockPolicy> ware_policy_;
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2017-05-25 12:58:01 +0000
+++ src/logic/player.cc 2017-06-19 07:06:15 +0000
@@ -19,6 +19,7 @@
#include "logic/player.h"
+#include <cassert>
#include <memory>
#include <boost/bind.hpp>
@@ -806,8 +807,12 @@
return;
if (soldier.descr().type() != MapObjectType::SOLDIER)
return;
- if (upcast(SoldierControl, ctrl, &imm))
- ctrl->drop_soldier(soldier);
+ if (upcast(Building, building, &imm)) {
+ SoldierControl* soldier_control = building->mutable_soldier_control();
+ if (soldier_control != nullptr) {
+ soldier_control->drop_soldier(soldier);
+ }
+ }
}
/*
@@ -842,9 +847,10 @@
for (BaseImmovable* temp_flag : flags) {
upcast(Flag, attackerflag, temp_flag);
- upcast(MilitarySite, ms, attackerflag->get_building());
- std::vector<Soldier*> const present = ms->present_soldiers();
- uint32_t const nr_staying = ms->min_soldier_capacity();
+ const SoldierControl* soldier_control = attackerflag->get_building()->soldier_control();
+ assert(soldier_control != nullptr);
+ std::vector<Soldier*> const present = soldier_control->present_soldiers();
+ uint32_t const nr_staying = soldier_control->min_soldier_capacity();
uint32_t const nr_present = present.size();
if (nr_staying < nr_present) {
uint32_t const nr_taken = std::min(nr_wanted, nr_present - nr_staying);
=== modified file 'src/logic/playercommand.cc'
--- src/logic/playercommand.cc 2017-02-12 09:10:57 +0000
+++ src/logic/playercommand.cc 2017-06-19 07:06:15 +0000
@@ -1514,10 +1514,20 @@
}
void CmdChangeSoldierCapacity::execute(Game& game) {
- if (upcast(Building, building, game.objects().get_object(serial)))
- if (&building->owner() == game.get_player(sender()))
- if (upcast(SoldierControl, ctrl, building))
- ctrl->changeSoldierCapacity(val);
+ if (upcast(Building, building, game.objects().get_object(serial))) {
+ if (&building->owner() == game.get_player(sender()) &&
+ building->soldier_control() != nullptr) {
+ SoldierControl* soldier_control = building->mutable_soldier_control();
+ Widelands::Quantity const old_capacity = soldier_control->soldier_capacity();
+ Widelands::Quantity const new_capacity =
+ std::min(static_cast<Widelands::Quantity>(
+ std::max(static_cast<int32_t>(old_capacity) + val,
+ static_cast<int32_t>(soldier_control->min_soldier_capacity()))),
+ soldier_control->max_soldier_capacity());
+ if (old_capacity != new_capacity)
+ soldier_control->set_soldier_capacity(new_capacity);
+ }
+ }
}
void CmdChangeSoldierCapacity::serialize(StreamWrite& ser) {
=== modified file 'src/map_io/map_buildingdata_packet.cc'
--- src/map_io/map_buildingdata_packet.cc 2017-02-12 09:10:57 +0000
+++ src/map_io/map_buildingdata_packet.cc 2017-06-19 07:06:15 +0000
@@ -525,20 +525,20 @@
// Cmd_ChangeSoldierCapacity to the beginning of the game's command
// queue. But that would not work because the command queue is not read
// yet and will be cleared before it is read.
- if (militarysite.capacity_ < militarysite.min_soldier_capacity()) {
+ if (militarysite.capacity_ < militarysite.soldier_control()->min_soldier_capacity()) {
log("WARNING: militarysite %u of player %u at (%i, %i) has capacity "
"set to %u but it must be at least %u. Changing to that value.\n",
militarysite.serial(), militarysite.owner().player_number(),
militarysite.get_position().x, militarysite.get_position().y, militarysite.capacity_,
- militarysite.min_soldier_capacity());
- militarysite.capacity_ = militarysite.min_soldier_capacity();
- } else if (militarysite.max_soldier_capacity() < militarysite.capacity_) {
+ militarysite.soldier_control()->min_soldier_capacity());
+ militarysite.capacity_ = militarysite.soldier_control()->min_soldier_capacity();
+ } else if (militarysite.soldier_control()->max_soldier_capacity() < militarysite.capacity_) {
log("WARNING: militarysite %u of player %u at (%i, %i) has capacity "
"set to %u but it can be at most %u. Changing to that value.\n",
militarysite.serial(), militarysite.owner().player_number(),
militarysite.get_position().x, militarysite.get_position().y, militarysite.capacity_,
- militarysite.max_soldier_capacity());
- militarysite.capacity_ = militarysite.max_soldier_capacity();
+ militarysite.soldier_control()->max_soldier_capacity());
+ militarysite.capacity_ = militarysite.soldier_control()->max_soldier_capacity();
}
} catch (const WException& e) {
throw GameDataError("militarysite: %s", e.what());
@@ -800,20 +800,20 @@
// Cmd_ChangeSoldierCapacity to the beginning of the game's command
// queue. But that would not work because the command queue is not read
// yet and will be cleared before it is read.
- if (trainingsite.capacity_ < trainingsite.min_soldier_capacity()) {
+ if (trainingsite.capacity_ < trainingsite.soldier_control()->min_soldier_capacity()) {
log("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
"set to %u but it must be at least %u. Changing to that value.\n",
trainingsite.serial(), trainingsite.owner().player_number(),
trainingsite.get_position().x, trainingsite.get_position().y, trainingsite.capacity_,
- trainingsite.min_soldier_capacity());
- trainingsite.capacity_ = trainingsite.min_soldier_capacity();
- } else if (trainingsite.max_soldier_capacity() < trainingsite.capacity_) {
+ trainingsite.soldier_control()->min_soldier_capacity());
+ trainingsite.capacity_ = trainingsite.soldier_control()->min_soldier_capacity();
+ } else if (trainingsite.soldier_control()->max_soldier_capacity() < trainingsite.capacity_) {
log("WARNING: trainingsite %u of player %u at (%i, %i) has capacity "
"set to %u but it can be at most %u. Changing to that value.\n",
trainingsite.serial(), trainingsite.owner().player_number(),
trainingsite.get_position().x, trainingsite.get_position().y, trainingsite.capacity_,
- trainingsite.max_soldier_capacity());
- trainingsite.capacity_ = trainingsite.max_soldier_capacity();
+ trainingsite.soldier_control()->max_soldier_capacity());
+ trainingsite.capacity_ = trainingsite.soldier_control()->max_soldier_capacity();
}
} catch (const WException& e) {
throw GameDataError("trainingsite: %s", e.what());
=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc 2017-04-05 14:19:14 +0000
+++ src/scripting/lua_map.cc 2017-06-19 07:06:15 +0000
@@ -573,7 +573,7 @@
s->get_defense_level(), s->get_evade_level());
if (is == sp.first) {
- sc->outcorporate_soldier(egbase, *s);
+ sc->outcorporate_soldier(*s);
s->remove(egbase);
++d;
break;
@@ -4654,13 +4654,13 @@
// documented in parent class
int LuaWarehouse::get_soldiers(lua_State* L) {
Warehouse* wh = get(L, get_egbase(L));
- return do_get_soldiers(L, *wh, wh->owner().tribe());
+ return do_get_soldiers(L, *wh->soldier_control(), wh->owner().tribe());
}
// documented in parent class
int LuaWarehouse::set_soldiers(lua_State* L) {
Warehouse* wh = get(L, get_egbase(L));
- return do_set_soldiers(L, wh->get_position(), wh, wh->get_owner());
+ return do_set_soldiers(L, wh->get_position(), wh->mutable_soldier_control(), wh->get_owner());
}
/* RST
@@ -4923,7 +4923,7 @@
// documented in parent class
int LuaMilitarySite::get_max_soldiers(lua_State* L) {
- lua_pushuint32(L, get(L, get_egbase(L))->soldier_capacity());
+ lua_pushuint32(L, get(L, get_egbase(L))->soldier_control()->soldier_capacity());
return 1;
}
@@ -4936,13 +4936,13 @@
// documented in parent class
int LuaMilitarySite::get_soldiers(lua_State* L) {
MilitarySite* ms = get(L, get_egbase(L));
- return do_get_soldiers(L, *ms, ms->owner().tribe());
+ return do_get_soldiers(L, *ms->soldier_control(), ms->owner().tribe());
}
// documented in parent class
int LuaMilitarySite::set_soldiers(lua_State* L) {
MilitarySite* ms = get(L, get_egbase(L));
- return do_set_soldiers(L, ms->get_position(), ms, ms->get_owner());
+ return do_set_soldiers(L, ms->get_position(), ms->mutable_soldier_control(), ms->get_owner());
}
/*
@@ -4977,7 +4977,7 @@
// documented in parent class
int LuaTrainingSite::get_max_soldiers(lua_State* L) {
- lua_pushuint32(L, get(L, get_egbase(L))->soldier_capacity());
+ lua_pushuint32(L, get(L, get_egbase(L))->soldier_control()->soldier_capacity());
return 1;
}
@@ -4990,13 +4990,13 @@
// documented in parent class
int LuaTrainingSite::get_soldiers(lua_State* L) {
TrainingSite* ts = get(L, get_egbase(L));
- return do_get_soldiers(L, *ts, ts->owner().tribe());
+ return do_get_soldiers(L, *ts->soldier_control(), ts->owner().tribe());
}
// documented in parent class
int LuaTrainingSite::set_soldiers(lua_State* L) {
TrainingSite* ts = get(L, get_egbase(L));
- return do_set_soldiers(L, ts->get_position(), ts, ts->get_owner());
+ return do_set_soldiers(L, ts->get_position(), ts->mutable_soldier_control(), ts->get_owner());
}
/*
=== modified file 'src/wui/building_statistics_menu.cc'
--- src/wui/building_statistics_menu.cc 2017-04-03 17:29:50 +0000
+++ src/wui/building_statistics_menu.cc 2017-06-19 07:06:15 +0000
@@ -422,8 +422,9 @@
if (!stats_vector[last_building_index_].is_constructionsite) {
if (upcast(MilitarySite, militarysite,
map[stats_vector[last_building_index_].pos].get_immovable())) {
- if (militarysite->stationed_soldiers().size() <
- militarysite->soldier_capacity()) {
+ auto* soldier_control = militarysite->soldier_control();
+ if (soldier_control->stationed_soldiers().size() <
+ soldier_control->soldier_capacity()) {
found = true;
break;
}
@@ -442,8 +443,10 @@
if (!stats_vector[last_building_index_].is_constructionsite) {
if (upcast(MilitarySite, militarysite,
map[stats_vector[last_building_index_].pos].get_immovable())) {
- if (militarysite->stationed_soldiers().size() <
- militarysite->soldier_capacity()) {
+ auto* soldier_control = militarysite->soldier_control();
+ assert(soldier_control != nullptr);
+ if (soldier_control->stationed_soldiers().size() <
+ soldier_control->soldier_capacity()) {
found = true;
break;
}
@@ -461,7 +464,9 @@
if (!found) { // Now look at the old
if (upcast(MilitarySite, militarysite,
map[stats_vector[last_building_index_].pos].get_immovable())) {
- if (militarysite->stationed_soldiers().size() < militarysite->soldier_capacity()) {
+ auto* soldier_control = militarysite->soldier_control();
+ assert(soldier_control != nullptr);
+ if (soldier_control->stationed_soldiers().size() < soldier_control->soldier_capacity()) {
found = true;
}
} else if (upcast(ProductionSite, productionsite,
@@ -585,9 +590,10 @@
++nr_unproductive;
}
} else if (building.type() == MapObjectType::MILITARYSITE) {
- MilitarySite& militarysite = dynamic_cast<MilitarySite&>(immovable);
- total_soldier_capacity += militarysite.soldier_capacity();
- total_stationed_soldiers += militarysite.stationed_soldiers().size();
+ const SoldierControl* soldier_control = dynamic_cast<Building&>(immovable).soldier_control();
+ assert(soldier_control != nullptr);
+ total_soldier_capacity += soldier_control->soldier_capacity();
+ total_stationed_soldiers += soldier_control->stationed_soldiers().size();
if (total_stationed_soldiers < total_soldier_capacity) {
++nr_unproductive;
}
=== modified file 'src/wui/soldiercapacitycontrol.cc'
--- src/wui/soldiercapacitycontrol.cc 2017-02-25 13:27:40 +0000
+++ src/wui/soldiercapacitycontrol.cc 2017-06-19 07:06:15 +0000
@@ -97,9 +97,8 @@
}
void SoldierCapacityControl::think() {
-
- SoldierControl* soldiers = dynamic_cast<SoldierControl*>(&building_);
-
+ const SoldierControl* soldiers = building_.soldier_control();
+ assert(soldiers != nullptr);
uint32_t const capacity = soldiers->soldier_capacity();
value_.set_text(boost::lexical_cast<std::string>(capacity));
=== modified file 'src/wui/soldierlist.cc'
--- src/wui/soldierlist.cc 2017-05-18 21:26:29 +0000
+++ src/wui/soldierlist.cc 2017-06-19 07:06:15 +0000
@@ -94,7 +94,7 @@
};
Widelands::EditorGameBase& egbase_;
- SoldierControl& soldiers_;
+ const SoldierControl* soldier_control_;
SoldierFn mouseover_fn_;
SoldierFn click_fn_;
@@ -115,13 +115,14 @@
Widelands::Building& building)
: Panel(&parent, 0, 0, 0, 0),
egbase_(gegbase),
- soldiers_(*dynamic_cast<SoldierControl*>(&building)),
+ soldier_control_(building.soldier_control()),
last_animate_time_(0) {
+ assert(soldier_control_ != nullptr);
Soldier::calc_info_icon_size(building.owner().tribe(), icon_width_, icon_height_);
icon_width_ += 2 * kIconBorder;
icon_height_ += 2 * kIconBorder;
- Widelands::Quantity maxcapacity = soldiers_.max_soldier_capacity();
+ Widelands::Quantity maxcapacity = soldier_control_->max_soldier_capacity();
if (maxcapacity <= kMaxColumns) {
cols_ = maxcapacity;
rows_ = 1;
@@ -137,7 +138,7 @@
// Initialize the icons
uint32_t row = 0;
uint32_t col = 0;
- for (Soldier* soldier : soldiers_.present_soldiers()) {
+ for (Soldier* soldier : soldier_control_->present_soldiers()) {
Icon icon;
icon.soldier = soldier;
icon.row = row;
@@ -168,10 +169,10 @@
void SoldierPanel::think() {
bool changes = false;
- uint32_t capacity = soldiers_.soldier_capacity();
+ uint32_t capacity = soldier_control_->soldier_capacity();
// Update soldier list and target row/col:
- std::vector<Soldier*> soldierlist = soldiers_.present_soldiers();
+ std::vector<Soldier*> soldierlist = soldier_control_->present_soldiers();
std::vector<uint32_t> row_occupancy;
row_occupancy.resize(rows_);
@@ -276,7 +277,7 @@
void SoldierPanel::draw(RenderTarget& dst) {
// Fill a region matching the current site capacity with black
- uint32_t capacity = soldiers_.soldier_capacity();
+ uint32_t capacity = soldier_control_->soldier_capacity();
uint32_t fullrows = capacity / kMaxColumns;
if (fullrows) {
@@ -347,7 +348,7 @@
struct SoldierList : UI::Box {
SoldierList(UI::Panel& parent, InteractiveGameBase& igb, Widelands::Building& building);
- SoldierControl& soldiers() const;
+ const SoldierControl* soldiers() const;
private:
void mouseover(const Soldier* soldier);
@@ -424,8 +425,8 @@
add(buttons, UI::Box::Resizing::kFullSize);
}
-SoldierControl& SoldierList::soldiers() const {
- return *dynamic_cast<SoldierControl*>(&building_);
+const SoldierControl* SoldierList::soldiers() const {
+ return building_.soldier_control();
}
void SoldierList::think() {
@@ -464,9 +465,9 @@
}
void SoldierList::eject(const Soldier* soldier) {
- uint32_t const capacity_min = soldiers().min_soldier_capacity();
+ uint32_t const capacity_min = soldiers()->min_soldier_capacity();
bool can_act = igbase_.can_act(building_.owner().player_number());
- bool over_min = capacity_min < soldiers().present_soldiers().size();
+ bool over_min = capacity_min < soldiers()->present_soldiers().size();
if (can_act && over_min)
igbase_.game().send_player_drop_soldier(building_, soldier->serial());
References