bool nobBaseWarehouse::OrderJob(const Job job, noRoadNode* const goal, const bool allow_recruiting) { RTTR_Assert(goal); // Maybe we have to recruit one if(!inventory[job]) { if(!allow_recruiting) return false; TryRecruitJob(job); } noFigure* fig = JobFactory::CreateJob(job, pos, player, goal); // Wenn Figur nicht sofort von abgeleiteter Klasse verwenet wird, fügen wir die zur Leave-Liste hinzu if(!UseFigureAtOnce(fig, *goal)) AddLeavingFigure(fig); // Ziel Bescheid sagen, dass dortin ein neuer Arbeiter kommt (bei Flaggen als das anders machen) if(goal->GetType() != NOP_FLAG) { RTTR_Assert(dynamic_cast<noBaseBuilding*>(goal)); static_cast<noBaseBuilding*>(goal)->GotWorker(job, fig); } inventory.real.Remove(job); // Evtl. kein Gehilfe mehr da, sodass das Rekrutieren gestoppt werden muss TryStopRecruiting(); return true; }
bool nobBaseMilitary::CallDefender(nofAttacker* attacker) { // Ist noch ein Verteidiger draußen (der z.B. grad wieder reingeht? if(defender_) { // Dann nehmen wir den, müssen ihm nur den neuen Angreifer mitteilen defender_->NewAttacker(attacker); // Leute, die aus diesem Gebäude zum Angriff/aggressiver Verteidigung rauskommen wollen, // blocken CancelJobs(); return true; } // ansonsten einen neuen aus dem Gebäude holen else if((defender_ = ProvideDefender(attacker))) { // Leute, die aus diesem Gebäude zum Angriff/aggressiver Verteidigung rauskommen wollen, // blocken CancelJobs(); // Soldat muss noch rauskommen AddLeavingFigure(defender_); return true; } else { // Gebäude ist leer, dann kann es erobert werden return false; } }
void nobBaseWarehouse::FetchWare() { if(!fetch_double_protection) AddLeavingFigure(new nofWarehouseWorker(pos, player, 0, true)); fetch_double_protection = false; }
/// Starts a trade caravane from this warehouse void nobBaseWarehouse::StartTradeCaravane(const GoodType gt, Job job, const unsigned count, const TradeRoute& tr, nobBaseWarehouse* goal) { nofTradeLeader* tl = new nofTradeLeader(pos, player, tr, this->GetPos(), goal->GetPos()); AddLeavingFigure(tl); // Create the donkeys or other people nofTradeDonkey* last = NULL; for(unsigned i = 0; i < count; ++i) { nofTradeDonkey* next = new nofTradeDonkey(pos, player, gt, job); if(last) last->SetSuccessor(next); else tl->SetSuccessor(next); last = next; AddLeavingFigure(next); } GameClientPlayer& owner = gwg->GetPlayer(player); // Remove leader inventory.real.Remove(JOB_HELPER); owner.DecreaseInventoryJob(JOB_HELPER, 1); // Also diminish the count of donkeys if(job == JOB_NOTHING) { // Diminish the goods in the warehouse RTTR_Assert(gt != GD_NOTHING); inventory.real.Remove(gt, count); owner.DecreaseInventoryWare(gt, count); //now that we have removed the goods lets remove the donkeys inventory.real.Remove(JOB_PACKDONKEY, count); owner.DecreaseInventoryJob(JOB_PACKDONKEY, count); } else { RTTR_Assert(gt == GD_NOTHING); //remove the jobs & the helpers inventory.real.Remove(job, count); owner.DecreaseInventoryJob(job, count); inventory.real.Remove(JOB_HELPER, count); owner.DecreaseInventoryJob(JOB_HELPER, count); } }
nofCarrier* nobBaseWarehouse::OrderDonkey(RoadSegment* road, noRoadNode* const goal_flag) { // Überhaupt ein Esel vorhanden? if(!inventory[JOB_PACKDONKEY]) return NULL; nofCarrier* donkey = new nofCarrier(nofCarrier::CT_DONKEY, pos, player, road, goal_flag); AddLeavingFigure(donkey); inventory.real.Remove(JOB_PACKDONKEY); return donkey; }
/// Erhält die Waren von einem Schiff und nimmt diese in den Warenbestand auf void nobHarborBuilding::ReceiveGoodsFromShip(std::list<noFigure*>& figures, std::list<Ware*>& wares) { // Menschen zur Ausgehliste hinzufügen for(std::list<noFigure*>::const_iterator it = figures.begin(); it != figures.end(); ++it) { (*it)->ArrivedByShip(pos); // Wenn es kein Ziel mehr hat, sprich keinen weiteren Weg, kann es direkt hier gelagert werden if((*it)->GetGoal() == this) (*it)->SetGoalToNULL(); else if(!(*it)->HasNoGoal()) { unsigned char nextDir; MapPoint next_harbor = (*it)->ExamineRouteBeforeShipping(nextDir); if (nextDir == 4) { // Increase visual count if((*it)->GetJobType() == JOB_BOATCARRIER) { inventory.visual.Add(JOB_HELPER); inventory.visual.Add(GD_BOAT); } else inventory.visual.Add((*it)->GetJobType()); AddLeavingFigure(*it); (*it)->ShipJourneyEnded(); } else if (nextDir == SHIP_DIR) { AddFigureForShip(*it, next_harbor); }else { // No or invalid path -> Store here RTTR_Assert(nextDir == 0xFF); (*it)->SetGoalToNULL(); AddDependentFigure(*it); } }else AddDependentFigure(*it); // No goal? We take it if ((*it)->HasNoGoal()) AddFigure(*it, true); } figures.clear(); // Waren zur Warteliste hinzufügen for(std::list<Ware*>::iterator it = wares.begin(); it != wares.end(); ++it) { (*it)->ShipJorneyEnded(this); AddWare(*it); } wares.clear(); }
void nobBaseWarehouse::OrderTroops(nobMilitary* goal, unsigned count,bool ignoresettingsendweakfirst) { // Soldaten durchgehen und count rausschicken // Ränge durchgehen, absteigend, starke zuerst if (gwg->GetPlayer(player).militarySettings_[1] >= MILITARY_SETTINGS_SCALE[1] / 2 && !ignoresettingsendweakfirst) { for(unsigned i = SOLDIER_JOBS.size(); i && count; --i) { const Job curRank = SOLDIER_JOBS[i-1]; // Vertreter der Ränge ggf rausschicken while(inventory[curRank] && count) { nofSoldier* soldier = new nofPassiveSoldier(pos, player, goal, goal, i - 1); inventory.real.Remove(curRank); AddLeavingFigure(soldier); goal->GotWorker(curRank, soldier); --count; } } } // Ränge durchgehen, aufsteigend, schwache zuerst else { for(unsigned i = 1; i <= SOLDIER_JOBS.size() && count; ++i) { const Job curRank = SOLDIER_JOBS[i - 1]; // Vertreter der Ränge ggf rausschicken while(inventory[curRank] && count) { nofSoldier* soldier = new nofPassiveSoldier(pos, player, goal, goal, i - 1); inventory.real.Remove(curRank); AddLeavingFigure(soldier); goal->GotWorker(curRank, soldier); --count; } } } }
nofAggressiveDefender* nobMilitary::SendDefender(nofAttacker* attacker) { // Sind noch Soldaten da? if(troops.size() > 1) { // Verteidiger auswählen nofPassiveSoldier* soldier = ChooseSoldier(); // neuen aggressiven Verteidiger daraus erzeugen nofAggressiveDefender* defender = new nofAggressiveDefender(soldier, attacker); // soll rausgehen AddLeavingFigure(defender); SoldierOnMission(soldier, defender); // alten passiven Soldaten vernichten soldier->Destroy(); delete soldier; return defender; } else return NULL; }
void nobMilitary::SendSoldiersHome() { int diff = 1 - static_cast<int>(GetTotalSoldiers()); if(diff < 0) //poc: this should only be >0 if we are being captured. capturing should be true until its the last soldier and this last one would count twice here and result in a returning soldier that shouldnt return. { // Nur rausschicken, wenn es einen Weg zu einem Lagerhaus gibt! if(!gwg->GetPlayer(player).FindWarehouse(*this, FW::NoCondition(), true, false)) return; int mrank=-1; for(SortedTroops::reverse_iterator it = troops.rbegin(); diff && troops.size() > 1; ++diff) { if(mrank<0) //set mrank = highest rank mrank=(*it)->GetRank(); else if (mrank>(*it)->GetRank()) //if the current soldier is of lower rank than what we started with -> send no more troops out return; (*it)->LeaveBuilding(); AddLeavingFigure(*it); it = helpers::erase(troops, it); } } }
nofAggressiveDefender* nobBaseWarehouse::SendDefender(nofAttacker* attacker) { // Sind noch Soldaten da? unsigned char rank; for(rank = SOLDIER_JOBS.size(); rank > 0; --rank) { if(inventory[SOLDIER_JOBS[rank - 1]]) break; } // Wenn kein Soldat mehr da ist --> 0 zurückgeben if(!rank) return NULL; // Dann den Stärksten rausschicken nofAggressiveDefender* soldier = new nofAggressiveDefender(pos, player, this, rank - 1, attacker); inventory.real.Remove(SOLDIER_JOBS[rank - 1]); AddLeavingFigure(soldier); troops_on_mission.push_back(soldier); return soldier; }
void nobBaseWarehouse::OrderCarrier(noRoadNode& goal, RoadSegment& workplace) { RTTR_Assert(workplace.getCarrier(0) == NULL); const bool isBoatRequired = workplace.GetRoadType() == RoadSegment::RT_BOAT; // We assume, that the caller already checked, if this is possible RTTR_Assert(inventory[JOB_HELPER]); if(isBoatRequired) RTTR_Assert(inventory[GD_BOAT]); nofCarrier* carrier = new nofCarrier(isBoatRequired ? nofCarrier::CT_BOAT : nofCarrier::CT_NORMAL, pos, player, &workplace, &goal); workplace.setCarrier(0, carrier); if(!UseFigureAtOnce(carrier, goal)) AddLeavingFigure(carrier); inventory.real.Remove(JOB_HELPER); if(isBoatRequired) inventory.real.Remove(GD_BOAT); // Evtl. kein Gehilfe mehr, sodass das Rekrutieren gestoppt werden muss TryStopRecruiting(); }
/// Erhält die Waren von einem Schiff und nimmt diese in den Warenbestand auf void nobHarborBuilding::ReceiveGoodsFromShip(const std::list<noFigure*> figures, const std::list<Ware*> wares) { // Menschen zur Ausgehliste hinzufügen for(std::list<noFigure*>::const_iterator it = figures.begin();it!=figures.end();++it) { if((*it)->GetJobType() == JOB_BOATCARRIER) { ++goods.people[JOB_HELPER]; ++goods.goods[GD_BOAT]; } else ++goods.people[(*it)->GetJobType()]; // Wenn es kein Ziel mehr hat, sprich keinen weiteren Weg, kann es direkt hier gelagert // werden if ((*it)->HasNoGoal() || ((*it)->GetGoal() == this)) { AddFigure(*it, false); } else { Point<MapCoord> next_harbor = (*it)->ExamineRouteBeforeShipping(); unsigned char next_dir = (*it)->GetDir(); if (next_dir == 4) { AddLeavingFigure(*it); (*it)->ShipJourneyEnded(); } else if (next_dir == SHIP_DIR) { AddFigureForShip(*it, next_harbor); } else { AddFigure(*it, false); } } } // Waren zur Warteliste hinzufügen for(std::list<Ware*>::const_iterator it = wares.begin();it!=wares.end();++it) { // Optische Warenwerte entsprechend erhöhen ++goods.goods[ConvertShields((*it)->type)]; if((*it)->ShipJorneyEnded(this)) { // Ware will die weitere Reise antreten, also muss sie zur Liste der rausgetragenen Waren // hinzugefügt werden waiting_wares.push_back(*it); } else { // Ansonsten fügen wir die Ware einfach zu unserem Inventar dazu RemoveDependentWare(*it); ++real_goods.goods[ConvertShields((*it)->type)]; players->getElement(player)->RemoveWare(*it); delete *it; } } // Ggf. neues Rausgeh-Event anmelden, was notwendig ist, wenn z.B. nur Waren zur Liste hinzugefügt wurden AddLeavingEvent(); }
void nobBaseWarehouse::HandleSendoutEvent() { // Fight or something in front of the house? Try again later! if(!gwg->IsRoadNodeForFigures(gwg->GetNeighbour(pos, 4), 4)) { empty_event = em->AddEvent(this, empty_INTERVAL, 3); return; } std::vector<unsigned> possibleIds; // Waren und Figuren zum Auslagern zusammensuchen // Wenn keine Platz an Flagge, dann keine Waren raus if(GetFlag()->IsSpaceForWare()) { for(unsigned i = 0; i < WARE_TYPES_COUNT; ++i) { if(GetInventorySetting(GoodType(i)).IsSet(EInventorySetting::SEND) && inventory[GoodType(i)]) possibleIds.push_back(i); } } for(unsigned i = 0; i < JOB_TYPES_COUNT; ++i) { // Figuren, die noch nicht implementiert sind, nicht nehmen! if(GetInventorySetting(Job(i)).IsSet(EInventorySetting::SEND) && inventory[Job(i)]) possibleIds.push_back(WARE_TYPES_COUNT + i); } // Gibts überhaupt welche? if(possibleIds.empty()) // ansonsten gleich tschüss return; // Eine ID zufällig auswählen unsigned selectedId = possibleIds[RANDOM.Rand(__FILE__, __LINE__, GetObjId(), possibleIds.size())]; if(selectedId < WARE_TYPES_COUNT) { // Ware Ware* ware = new Ware(GoodType(selectedId), NULL, this); noBaseBuilding* wareGoal = gwg->GetPlayer(player).FindClientForWare(ware); if(wareGoal != this) { ware->SetGoal(wareGoal); // Ware zur Liste hinzufügen, damit sie dann rausgetragen wird waiting_wares.push_back(ware); AddLeavingEvent(); // Ware aus Inventar entfernen inventory.real.Remove(GoodType(selectedId)); // Evtl. kein Schwert/Schild/Bier mehr da, sodass das Rekrutieren gestoppt werden muss TryStopRecruiting(); } else { gwg->GetPlayer(player).RemoveWare(ware); ware->Destroy(); deletePtr(ware); } } else { // Figur selectedId -= WARE_TYPES_COUNT; nobBaseWarehouse* wh = gwg->GetPlayer(player).FindWarehouse(*this, FW::AcceptsFigureButNoSend(Job(selectedId)), true, false); if(wh != this) { nofPassiveWorker* fig = new nofPassiveWorker(Job(selectedId), pos, player, NULL); if(wh) fig->GoHome(wh); else fig->StartWandering(); AddLeavingFigure(fig); // Person aus Inventar entfernen inventory.real.Remove(Job(selectedId)); // Evtl. kein Gehilfe mehr da, sodass das Rekrutieren gestoppt werden muss TryStopRecruiting(); } } // Weitere Waren/Figuren zum Auslagern? if(AreWaresToEmpty()) // --> Nächstes Event empty_event = em->AddEvent(this, empty_INTERVAL, 3); }
void nobMilitary::RegulateTrainTroops() { if(!gwg->GetPlayer(player).FindWarehouse(*this, FW::NoCondition(), true, false)) { is_regulating_troops = false; return; } is_regulating_troops = true; boost::array< unsigned char, 5 > RankCounts{ { 0, 0, 0, 0, 0 } }; for( auto& Soldier : troops ) ++RankCounts[ Soldier->GetRank() ]; for( auto& Soldier : ordered_troops ) ++RankCounts[ Soldier->GetRank() ]; for( auto& Soldier : troops_on_mission ) ++RankCounts[ Soldier->GetRank() ]; for( auto& Soldier : far_away_capturers ) ++RankCounts[ Soldier->GetRank() ]; SortedTroops::reverse_iterator it = troops.rbegin(); auto GetSoldierRank = []( const Job& Job ) { return unsigned char( Job - JOB_PRIVATE ); }; for( auto SoldierRankIt = SOLDIER_JOBS.crbegin(); SoldierRankIt != SOLDIER_JOBS.crend(); ++SoldierRankIt ) { auto CurrentRank = GetSoldierRank( *SoldierRankIt ); if( CurrentRank >= GetSoldierRank( JOB_GENERAL )) { while( it != troops.rend() && ( *it )->GetRank() == CurrentRank && troops.size() > 1 ) { (*it)->LeaveBuilding(); AddLeavingFigure(*it); it = helpers::erase(troops, it); } } else if( CurrentRank > GetSoldierRank( JOB_PRIVATE ) && CurrentRank < GetSoldierRank( JOB_GENERAL ) ) { if( !RankCounts[CurrentRank] ) { gwg->GetPlayer(player).OrderTroops(this, std::min( TROOPS_COUNT[nation][size] - static_cast<int>(GetTotalSoldiers()), 1 ) ,true, SOLDIER_JOBS[ CurrentRank ]); } else if( RankCounts[CurrentRank] > 1 ) { unsigned SendOut = RankCounts[CurrentRank] - 1; while( it != troops.rend() && ( *it )->GetRank() == CurrentRank && troops.size() > 1 ) { if( SendOut > 0 ) { (*it)->LeaveBuilding(); AddLeavingFigure(*it); it = helpers::erase(troops, it); --SendOut; } else ++it; } } } else { // PRIVATES gwg->GetPlayer(player).OrderTroops(this, TROOPS_COUNT[nation][size] - static_cast<int>(GetTotalSoldiers()) ,true, SOLDIER_JOBS[ CurrentRank ]); } } is_regulating_troops = false; }
void nobMilitary::RegulateTroops() { RTTR_Assert(helpers::contains(gwg->GetPlayer(player).GetMilitaryBuildings(), this)); // If this fails, the building is beeing destroyed! // Wenn das Gebäude eingenommen wird, erstmal keine neuen Truppen und warten, wieviele noch reinkommen if(IsCaptured()) return; // Already regulate its troops => Don't call this method again if(is_regulating_troops) return; is_regulating_troops = true; if( mAutoTrain ) { RegulateTrainTroops(); is_regulating_troops = false; return; } // Zu viele oder zu wenig Truppen? int diff = CalcTroopsCount() - static_cast<int>(GetTotalSoldiers()); if(diff < 0) //poc: this should only be >0 if we are being captured. capturing should be true until its the last soldier and this last one would count twice here and result in a returning soldier that shouldnt return. { // Zu viel --> überflüssige Truppen nach Hause schicken // Zuerst die bestellten Soldaten wegschicken // Weak ones first std::vector<nofPassiveSoldier*> notNeededSoldiers; GameClientPlayer& owner = gwg->GetPlayer(player); if (owner.militarySettings_[1] > MILITARY_SETTINGS_SCALE[1] / 2) { for(SortedTroops::iterator it = ordered_troops.begin(); diff && !ordered_troops.empty(); ++diff) { notNeededSoldiers.push_back(*it); it = helpers::erase(ordered_troops, it); } } // Strong ones first else { for(SortedTroops::reverse_iterator it = ordered_troops.rbegin(); diff && !ordered_troops.empty(); ++diff) { notNeededSoldiers.push_back(*it); it = helpers::erase(ordered_troops, it); } } // send the not-needed-soldiers away for (std::vector<nofPassiveSoldier*>::iterator it = notNeededSoldiers.begin(); it != notNeededSoldiers.end(); ++it) { (*it)->NotNeeded(); } // Nur rausschicken, wenn es einen Weg zu einem Lagerhaus gibt! if(owner.FindWarehouse(*this, FW::NoCondition(), true, false)) { // Dann den Rest (einer muss immer noch drinbleiben!) // erst die schwachen Soldaten raus if (owner.militarySettings_[1] > MILITARY_SETTINGS_SCALE[1] / 2) { for(SortedTroops::iterator it = troops.begin(); diff && troops.size() > 1; ++diff) { (*it)->LeaveBuilding(); AddLeavingFigure(*it); it = helpers::erase(troops, it); } } // erst die starken Soldaten raus else { for(SortedTroops::reverse_iterator it = troops.rbegin(); diff && troops.size() > 1; ++diff) { (*it)->LeaveBuilding(); AddLeavingFigure(*it); it = helpers::erase(troops, it); } } } } else if(diff > 0) { // Zu wenig Truppen // Gebäude wird angegriffen und // Addon aktiv, nur soviele Leute zum Nachbesetzen schicken wie Verteidiger eingestellt if (IsUnderAttack() && gwg->GetGGS().getSelection(AddonId::DEFENDER_BEHAVIOR) == 2) { diff = (gwg->GetPlayer(player).militarySettings_[2] * diff) / MILITARY_SETTINGS_SCALE[2]; } //only order new troops if there is a chance that there is a path - pathfinding from each warehouse with soldiers to this mil building will start at the warehouse and cost time bool mightHaveRoad=false; for(unsigned i=2; i<7; i++) //every direction but 1 because 1 is the building connection so it doesnt count for this check { if(GetFlag()->routes[i%6]) { mightHaveRoad=true; break; } } if(mightHaveRoad) gwg->GetPlayer(player).OrderTroops(this, diff); } is_regulating_troops = false; }