Coe LGTM - added some comments with ideas and small code style fixes. Diff comments:
> > === 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. There is an element being erased in soldierlist.cc, so we can't do that yet. > +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_; > } > > === 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 > @@ -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(); Can this be nullptr? Maybe add an assert here. > + 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/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) { We have the exact same code in Militarysite. Move to Building? > + 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; > +} > + > /* > ============================= > > > === 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; Use std::numeric_limits? > +} > + > +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() { > > === 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) Add {} for code safety > + > soldier_control->set_soldier_capacity(new_capacity); > + } > + } > } > > void CmdChangeSoldierCapacity::serialize(StreamWrite& ser) { > > === 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(); assert(soldier_control != nullptr); > + if > (soldier_control->stationed_soldiers().size() < > + > soldier_control->soldier_capacity()) { > found = true; > break; > } -- 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. _______________________________________________ Mailing list: https://launchpad.net/~widelands-dev Post to : widelands-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~widelands-dev More help : https://help.launchpad.net/ListHelp