From a481f07daf85c435cdd46347b9e982508cbd159a Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 24 Aug 2024 22:21:26 +0000 Subject: [PATCH] PlayerState now stores all objects owned by player --- lib/CGameInfoCallback.cpp | 28 ++++----- lib/CGameInfoCallback.h | 2 +- lib/CPlayerState.cpp | 65 ++++++++++++++++++++ lib/CPlayerState.h | 32 +++++++--- lib/gameState/CGameState.cpp | 31 +++++----- lib/gameState/CGameStateCampaign.cpp | 2 +- lib/gameState/GameStatistics.cpp | 18 +++--- lib/gameState/GameStatistics.h | 2 +- lib/gameState/HighScore.cpp | 4 +- lib/mapObjects/CGDwelling.cpp | 17 ----- lib/mapObjects/CGTownInstance.cpp | 10 +-- lib/mapObjects/CGTownInstance.h | 2 +- lib/networkPacks/NetPacksLib.cpp | 26 +++++--- lib/pathfinder/CPathfinder.cpp | 3 +- lib/spells/AdventureSpellMechanics.cpp | 4 +- server/CGameHandler.cpp | 20 +++--- server/CGameHandler.h | 2 +- server/battles/BattleResultProcessor.cpp | 2 +- server/processors/NewTurnProcessor.cpp | 19 +++--- server/processors/PlayerMessageProcessor.cpp | 4 +- server/processors/TurnOrderProcessor.cpp | 4 +- 21 files changed, 184 insertions(+), 113 deletions(-) diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index 76a7f6f29..3a6b002bd 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -237,7 +237,7 @@ void CGameInfoCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObj if(obj->ID == Obj::TOWN || obj->ID == Obj::TAVERN) { int taverns = 0; - for(auto town : gs->players[*getPlayerID()].towns) + for(auto town : gs->players[*getPlayerID()].getTowns()) { if(town->hasBuilt(BuildingID::TAVERN)) taverns++; @@ -256,7 +256,7 @@ void CGameInfoCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObj int CGameInfoCallback::howManyTowns(PlayerColor Player) const { ERROR_RET_VAL_IF(!hasAccess(Player), "Access forbidden!", -1); - return static_cast(gs->players[Player].towns.size()); + return static_cast(gs->players[Player].getTowns().size()); } bool CGameInfoCallback::getTownInfo(const CGObjectInstance * town, InfoAboutTown & dest, const CGObjectInstance * selectedObject) const @@ -609,7 +609,7 @@ EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, Bu const PlayerState *ps = getPlayerState(t->tempOwner, false); if(ps) { - for(const CGTownInstance *town : ps->towns) + for(const CGTownInstance *town : ps->getTowns()) { if(town->hasBuilt(BuildingID::CAPITOL)) { @@ -711,9 +711,9 @@ int CGameInfoCallback::getHeroCount( PlayerColor player, bool includeGarrisoned ERROR_RET_VAL_IF(!p, "No such player!", -1); if(includeGarrisoned) - return static_cast(p->heroes.size()); + return static_cast(p->getHeroes().size()); else - for(const auto & elem : p->heroes) + for(const auto & elem : p->getHeroes()) if(!elem->inTownGarrison) ret++; return ret; @@ -757,7 +757,7 @@ std::vector < const CGTownInstance *> CPlayerSpecificInfoCallback::getTownsInfo( auto ret = std::vector < const CGTownInstance *>(); for(const auto & i : gs->players) { - for(const auto & town : i.second.towns) + for(const auto & town : i.second.getTowns()) { if(i.first == getPlayerID() || (!onlyOur && isVisible(town, getPlayerID()))) { @@ -789,7 +789,7 @@ int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool return -1; size_t index = 0; - auto & heroes = gs->players[*getPlayerID()].heroes; + const auto & heroes = gs->players[*getPlayerID()].getHeroes(); for (auto & possibleHero : heroes) { @@ -835,7 +835,7 @@ std::vector < const CGDwelling * > CPlayerSpecificInfoCallback::getMyDwellings() { ASSERT_IF_CALLED_WITH_PLAYER std::vector < const CGDwelling * > ret; - for(CGDwelling * dw : gs->getPlayerState(*getPlayerID())->dwellings) + for(const CGDwelling * dw : gs->getPlayerState(*getPlayerID())->getDwellings()) { ret.push_back(dw); } @@ -867,12 +867,12 @@ const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId, if (!includeGarrisoned) { - for(ui32 i = 0; i < p->heroes.size() && static_cast(i) <= serialId; i++) - if(p->heroes[i]->inTownGarrison) + for(ui32 i = 0; i < p->getHeroes().size() && static_cast(i) <= serialId; i++) + if(p->getHeroes()[i]->inTownGarrison) serialId++; } - ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->heroes.size(), "No player info", nullptr); - return p->heroes[serialId]; + ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->getHeroes().size(), "No player info", nullptr); + return p->getHeroes()[serialId]; } const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId) const @@ -880,8 +880,8 @@ const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId) ASSERT_IF_CALLED_WITH_PLAYER const PlayerState *p = getPlayerState(*getPlayerID()); ERROR_RET_VAL_IF(!p, "No player info", nullptr); - ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->towns.size(), "No player info", nullptr); - return p->towns[serialId]; + ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->getTowns().size(), "No player info", nullptr); + return p->getTowns()[serialId]; } int CPlayerSpecificInfoCallback::getResourceAmount(GameResID type) const diff --git a/lib/CGameInfoCallback.h b/lib/CGameInfoCallback.h index ff9867249..c4d0799fa 100644 --- a/lib/CGameInfoCallback.h +++ b/lib/CGameInfoCallback.h @@ -23,7 +23,7 @@ struct InfoWindow; struct PlayerSettings; struct CPackForClient; struct TerrainTile; -struct PlayerState; +class PlayerState; class CTown; struct StartInfo; struct CPathsInfo; diff --git a/lib/CPlayerState.cpp b/lib/CPlayerState.cpp index 0ba55afc8..3480ce332 100644 --- a/lib/CPlayerState.cpp +++ b/lib/CPlayerState.cpp @@ -10,6 +10,9 @@ #include "StdInc.h" #include "CPlayerState.h" +#include "mapObjects/CGDwelling.h" +#include "mapObjects/CGTownInstance.h" +#include "mapObjects/CGHeroInstance.h" #include "gameState/QuestInfo.h" #include "texts/CGeneralTextHandler.h" #include "VCMI_Lib.h" @@ -90,4 +93,66 @@ int PlayerState::getResourceAmount(int type) const return vstd::atOrDefault(resources, static_cast(type), 0); } +std::vector PlayerState::getDwellings() const +{ + std::vector result; + for (auto const & object : ownedObjects) + { + auto dwelling = dynamic_cast(object); + auto town = dynamic_cast(object); + if (dwelling && !town) + result.push_back(dwelling); + } + return result; +} + +template +std::vector PlayerState::getObjectsOfType() const +{ + std::vector result; + for (auto const & object : ownedObjects) + { + auto casted = dynamic_cast(object); + if (casted) + result.push_back(casted); + } + return result; +} + +std::vector PlayerState::getHeroes() const +{ + return getObjectsOfType(); +} + +std::vector PlayerState::getTowns() const +{ + return getObjectsOfType(); +} + +std::vector PlayerState::getHeroes() +{ + return getObjectsOfType(); +} + +std::vector PlayerState::getTowns() +{ + return getObjectsOfType(); +} + +std::vector PlayerState::getOwnedObjects() const +{ + return {ownedObjects.begin(), ownedObjects.end()}; +} + +void PlayerState::addOwnedObject(CGObjectInstance * object) +{ + ownedObjects.push_back(object); +} + +void PlayerState::removeOwnedObject(CGObjectInstance * object) +{ + vstd::erase(ownedObjects, object); +} + + VCMI_LIB_NAMESPACE_END diff --git a/lib/CPlayerState.h b/lib/CPlayerState.h index 3bf0dc2b9..ef602a69f 100644 --- a/lib/CPlayerState.h +++ b/lib/CPlayerState.h @@ -20,12 +20,13 @@ VCMI_LIB_NAMESPACE_BEGIN +class CGObjectInstance; class CGHeroInstance; class CGTownInstance; class CGDwelling; struct QuestInfo; -struct DLL_LINKAGE PlayerState : public CBonusSystemNode, public Player +class DLL_LINKAGE PlayerState : public CBonusSystemNode, public Player { struct VisitedObjectGlobal { @@ -47,6 +48,11 @@ struct DLL_LINKAGE PlayerState : public CBonusSystemNode, public Player } }; + std::vector ownedObjects; + + template + std::vector getObjectsOfType() const; + public: PlayerColor color; bool human; //true if human controlled player, false for AI @@ -55,12 +61,8 @@ public: /// list of objects that were "destroyed" by player, either via simple pick-up (e.g. resources) or defeated heroes or wandering monsters std::set destroyedObjects; - std::set visitedObjects; // as a std::set, since most accesses here will be from visited status checks std::set visitedObjectsGlobal; - std::vector > heroes; - std::vector > towns; - std::vector > dwellings; //used for town growth std::vector quests; //store info about all received quests std::vector battleBonuses; //additional bonuses to be added during battle with neutrals std::map> costumesArtifacts; @@ -90,9 +92,20 @@ public: std::string getNameTextID() const override; void registerIcons(const IconRegistar & cb) const override; + std::vector getHeroes() const; + std::vector getTowns() const; + std::vector getHeroes(); + std::vector getTowns(); + + std::vector getDwellings() const; + std::vector getOwnedObjects() const; + + void addOwnedObject(CGObjectInstance * object); + void removeOwnedObject(CGObjectInstance * object); + bool checkVanquished() const { - return heroes.empty() && towns.empty(); + return ownedObjects.empty(); } template void serialize(Handler &h) @@ -103,9 +116,10 @@ public: h & resources; h & status; h & turnTimer; - h & heroes; - h & towns; - h & dwellings; + h & ownedObjects; + //h & heroes; + //h & towns; + //h & dwellings; h & quests; h & visitedObjects; h & visitedObjectsGlobal; diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 70258f8e0..318135637 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -574,7 +574,6 @@ void CGameState::initHeroes() } hero->initHero(getRandomGenerator()); - getPlayerState(hero->getOwner())->heroes.push_back(hero); map->allHeroes[hero->getHeroType().getNum()] = hero; } @@ -699,14 +698,14 @@ void CGameState::initStartingBonus() } case PlayerStartingBonus::ARTIFACT: { - if(elem.second.heroes.empty()) + if(elem.second.getHeroes().empty()) { logGlobal->error("Cannot give starting artifact - no heroes!"); break; } const Artifact * toGive = pickRandomArtifact(getRandomGenerator(), CArtifact::ART_TREASURE).toEntity(VLC); - CGHeroInstance *hero = elem.second.heroes[0]; + CGHeroInstance *hero = elem.second.getHeroes()[0]; if(!giveHeroArtifact(hero, toGive->getId())) logGlobal->error("Cannot give starting artifact - no free slots!"); } @@ -893,8 +892,6 @@ void CGameState::initTowns() vti->possibleSpells -= s->id; } vti->possibleSpells.clear(); - if(vti->getOwner() != PlayerColor::NEUTRAL) - getPlayerState(vti->getOwner())->towns.emplace_back(vti); } } @@ -902,6 +899,12 @@ void CGameState::initMapObjects() { logGlobal->debug("\tObject initialization"); + for(CGObjectInstance *obj : map->objects) + { + if (obj && obj->getOwner().isValidPlayer()) + getPlayerState(obj->getOwner())->addOwnedObject(obj); + } + // objCaller->preInit(); for(CGObjectInstance *obj : map->objects) { @@ -937,9 +940,9 @@ void CGameState::placeHeroesInTowns() if(player.first == PlayerColor::NEUTRAL) continue; - for(CGHeroInstance * h : player.second.heroes) + for(CGHeroInstance * h : player.second.getHeroes()) { - for(CGTownInstance * t : player.second.towns) + for(CGTownInstance * t : player.second.getTowns()) { if(h->visitablePos().z != t->visitablePos().z) continue; @@ -971,9 +974,9 @@ void CGameState::initVisitingAndGarrisonedHeroes() continue; //init visiting and garrisoned heroes - for(CGHeroInstance * h : player.second.heroes) + for(CGHeroInstance * h : player.second.getHeroes()) { - for(CGTownInstance * t : player.second.towns) + for(CGTownInstance * t : player.second.getTowns()) { if(h->visitablePos().z != t->visitablePos().z) continue; @@ -1371,7 +1374,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio } case EventCondition::HAVE_ARTIFACT: //check if any hero has winning artifact { - for(const auto & elem : p->heroes) + for(const auto & elem : p->getHeroes()) if(elem->hasArt(condition.objectType.as())) return true; return false; @@ -1405,7 +1408,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio } else // any town { - for (const CGTownInstance * t : p->towns) + for (const CGTownInstance * t : p->getTowns()) { if (t->hasBuilt(condition.objectType.as())) return true; @@ -1550,9 +1553,9 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) if(level >= 0) //num of towns & num of heroes { //num of towns - FILL_FIELD(numOfTowns, g->second.towns.size()) + FILL_FIELD(numOfTowns, g->second.getTowns().size()) //num of heroes - FILL_FIELD(numOfHeroes, g->second.heroes.size()) + FILL_FIELD(numOfHeroes, g->second.getHeroes().size()) } if(level >= 1) //best hero's portrait { @@ -1624,7 +1627,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) if(playerInactive(player.second.color)) //do nothing for neutral player continue; CreatureID bestCre; //best creature's ID - for(const auto & elem : player.second.heroes) + for(const auto & elem : player.second.getHeroes()) { for(const auto & it : elem->Slots()) { diff --git a/lib/gameState/CGameStateCampaign.cpp b/lib/gameState/CGameStateCampaign.cpp index 4f66f525f..7772139fc 100644 --- a/lib/gameState/CGameStateCampaign.cpp +++ b/lib/gameState/CGameStateCampaign.cpp @@ -536,7 +536,7 @@ void CGameStateCampaign::initHeroes() } assert(humanPlayer != PlayerColor::NEUTRAL); - std::vector > & heroes = gameState->players[humanPlayer].heroes; + const auto & heroes = gameState->players[humanPlayer].getHeroes(); if (chosenBonus->info1 == 0xFFFD) //most powerful { diff --git a/lib/gameState/GameStatistics.cpp b/lib/gameState/GameStatistics.cpp index 594dc38bb..d458f8aa4 100644 --- a/lib/gameState/GameStatistics.cpp +++ b/lib/gameState/GameStatistics.cpp @@ -50,10 +50,10 @@ StatisticDataSetEntry StatisticDataSet::createEntry(const PlayerState * ps, cons data.isHuman = ps->isHuman(); data.status = ps->status; data.resources = ps->resources; - data.numberHeroes = ps->heroes.size(); + data.numberHeroes = ps->getHeroes().size(); data.numberTowns = gs->howManyTowns(ps->color); data.numberArtifacts = Statistic::getNumberOfArts(ps); - data.numberDwellings = gs->getPlayerState(ps->color)->dwellings.size(); + data.numberDwellings = gs->getPlayerState(ps->color)->getDwellings().size(); data.armyStrength = Statistic::getArmyStrength(ps, true); data.totalExperience = Statistic::getTotalExperience(ps); data.income = Statistic::getIncome(gs, ps); @@ -221,7 +221,7 @@ std::vector Statistic::getMines(const CGameState * gs, const Pla int Statistic::getNumberOfArts(const PlayerState * ps) { int ret = 0; - for(auto h : ps->heroes) + for(auto h : ps->getHeroes()) { ret += h->artifactsInBackpack.size() + h->artifactsWorn.size(); } @@ -233,7 +233,7 @@ si64 Statistic::getArmyStrength(const PlayerState * ps, bool withTownGarrison) { si64 str = 0; - for(auto h : ps->heroes) + for(auto h : ps->getHeroes()) { if(!h->inTownGarrison || withTownGarrison) //original h3 behavior str += h->getArmyStrength(); @@ -246,7 +246,7 @@ si64 Statistic::getTotalExperience(const PlayerState * ps) { si64 tmp = 0; - for(auto h : ps->heroes) + for(auto h : ps->getHeroes()) tmp += h->exp; return tmp; @@ -258,11 +258,11 @@ int Statistic::getIncome(const CGameState * gs, const PlayerState * ps) int totalIncome = 0; //Heroes can produce gold as well - skill, specialty or arts - for(const auto & h : ps->heroes) + for(const auto & h : ps->getHeroes()) totalIncome += h->dailyIncome()[EGameResID::GOLD]; //Add town income of all towns - for(const auto & t : ps->towns) + for(const auto & t : ps->getTowns()) totalIncome += t->dailyIncome()[EGameResID::GOLD]; for(const CGMine * mine : getMines(gs, ps)) @@ -295,7 +295,7 @@ float Statistic::getMapExploredRatio(const CGameState * gs, PlayerColor player) const CGHeroInstance * Statistic::findBestHero(const CGameState * gs, const PlayerColor & color) { - auto &h = gs->players.at(color).heroes; + const auto &h = gs->players.at(color).getHeroes(); if(h.empty()) return nullptr; //best hero will be that with highest exp @@ -368,7 +368,7 @@ float Statistic::getTownBuiltRatio(const PlayerState * ps) float built = 0.0; float total = 0.0; - for(const auto & t : ps->towns) + for(const auto & t : ps->getTowns()) { built += t->getBuildings().size(); for(const auto & b : t->town->buildings) diff --git a/lib/gameState/GameStatistics.h b/lib/gameState/GameStatistics.h index fafddeaa5..450230e63 100644 --- a/lib/gameState/GameStatistics.h +++ b/lib/gameState/GameStatistics.h @@ -14,7 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN -struct PlayerState; +class PlayerState; class CGameState; class CGHeroInstance; class CGMine; diff --git a/lib/gameState/HighScore.cpp b/lib/gameState/HighScore.cpp index 55f615445..9507946b5 100644 --- a/lib/gameState/HighScore.cpp +++ b/lib/gameState/HighScore.cpp @@ -29,10 +29,10 @@ HighScoreParameter HighScore::prepareHighScores(const CGameState * gs, PlayerCol param.townAmount = gs->howManyTowns(player); param.usedCheat = gs->getPlayerState(player)->cheated; param.hasGrail = false; - for(const CGHeroInstance * h : playerState->heroes) + for(const CGHeroInstance * h : playerState->getHeroes()) if(h->hasArt(ArtifactID::GRAIL)) param.hasGrail = true; - for(const CGTownInstance * t : playerState->towns) + for(const CGTownInstance * t : playerState->getTowns()) if(t->hasBuilt(BuildingID::GRAIL)) param.hasGrail = true; param.allEnemiesDefeated = true; diff --git a/lib/mapObjects/CGDwelling.cpp b/lib/mapObjects/CGDwelling.cpp index c810f1307..8d1619b02 100644 --- a/lib/mapObjects/CGDwelling.cpp +++ b/lib/mapObjects/CGDwelling.cpp @@ -182,10 +182,6 @@ void CGDwelling::initObj(vstd::RNG & rand) case Obj::CREATURE_GENERATOR4: { getObjectHandler()->configureObject(this, rand); - - if (getOwner() != PlayerColor::NEUTRAL) - cb->gameState()->players[getOwner()].dwellings.emplace_back(this); - assert(!creatures.empty()); assert(!creatures[0].second.empty()); break; @@ -211,19 +207,6 @@ void CGDwelling::setPropertyDer(ObjProperty what, ObjPropertyID identifier) { switch (what) { - case ObjProperty::OWNER: //change owner - if (ID == Obj::CREATURE_GENERATOR1 || ID == Obj::CREATURE_GENERATOR2 - || ID == Obj::CREATURE_GENERATOR3 || ID == Obj::CREATURE_GENERATOR4) - { - if (tempOwner != PlayerColor::NEUTRAL) - { - std::vector >* dwellings = &cb->gameState()->players[tempOwner].dwellings; - dwellings->erase (std::find(dwellings->begin(), dwellings->end(), this)); - } - if (identifier.as().isValidPlayer()) - cb->gameState()->players[identifier.as()].dwellings.emplace_back(this); - } - break; case ObjProperty::AVAILABLE_CREATURE: creatures.resize(1); creatures[0].second.resize(1); diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 2204f5661..96142e591 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -181,7 +181,7 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const int dwellingBonus = 0; if(const PlayerState *p = cb->getPlayerState(tempOwner, false)) { - dwellingBonus = getDwellingBonus(creatures[level].second, p->dwellings); + dwellingBonus = getDwellingBonus(creatures[level].second, p->getDwellings()); } if(dwellingBonus) ret.entries.emplace_back(VLC->generaltexth->allTexts[591], dwellingBonus); // \nExternal dwellings %+d @@ -192,7 +192,7 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const return ret; } -int CGTownInstance::getDwellingBonus(const std::vector& creatureIds, const std::vector >& dwellings) const +int CGTownInstance::getDwellingBonus(const std::vector& creatureIds, const std::vector& dwellings) const { int totalBonus = 0; for (const auto& dwelling : dwellings) @@ -635,9 +635,9 @@ void CGTownInstance::removeCapitols(const PlayerColor & owner) const if (hasCapitol()) // search if there's an older capitol { PlayerState* state = cb->gameState()->getPlayerState(owner); //get all towns owned by player - for (auto i = state->towns.cbegin(); i < state->towns.cend(); ++i) + for (const auto & town : state->getTowns()) { - if (*i != this && (*i)->hasCapitol()) + if (town != this && town->hasCapitol()) { RazeStructures rs; rs.tid = id; @@ -672,7 +672,7 @@ int CGTownInstance::getMarketEfficiency() const assert(p); int marketCount = 0; - for(const CGTownInstance *t : p->towns) + for(const CGTownInstance *t : p->getTowns()) if(t->hasBuiltSomeTradeBuilding()) marketCount++; diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index 6fcef9f49..1c25c5856 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -239,7 +239,7 @@ private: FactionID randomizeFaction(vstd::RNG & rand); void setOwner(const PlayerColor & owner) const; void onTownCaptured(const PlayerColor & winner) const; - int getDwellingBonus(const std::vector& creatureIds, const std::vector >& dwellings) const; + int getDwellingBonus(const std::vector& creatureIds, const std::vector& dwellings) const; bool townEnvisagesBuilding(BuildingSubID::EBuildingSubID bid) const; void initializeConfigurableBuildings(vstd::RNG & rand); }; diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 2bb20610b..fb70d0a9b 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -1171,7 +1171,7 @@ void RemoveObject::applyGs(CGameState *gs) assert(beatenHero); PlayerState * p = gs->getPlayerState(beatenHero->tempOwner); gs->map->heroesOnMap -= beatenHero; - p->heroes -= beatenHero; + p->removeOwnedObject(beatenHero); auto * siegeNode = beatenHero->whereShouldBeAttachedOnSiege(gs); @@ -1417,7 +1417,7 @@ void HeroRecruited::applyGs(CGameState *gs) gs->map->objects[h->id.getNum()] = h; gs->map->heroesOnMap.emplace_back(h); - p->heroes.emplace_back(h); + p->addOwnedObject(h); h->attachTo(*p); gs->map->addBlockVisTiles(h); @@ -1452,7 +1452,7 @@ void GiveHero::applyGs(CGameState *gs) h->setMovementPoints(h->movementPointsLimit(true)); h->pos = h->convertFromVisitablePos(oldVisitablePos); gs->map->heroesOnMap.emplace_back(h); - gs->getPlayerState(h->getOwner())->heroes.emplace_back(h); + gs->getPlayerState(h->getOwner())->addOwnedObject(h); gs->map->addBlockVisTiles(h); h->inTownGarrison = false; @@ -1942,6 +1942,18 @@ void SetObjectProperty::applyGs(CGameState *gs) } auto * cai = dynamic_cast(obj); + + if(what == ObjProperty::OWNER) + { + PlayerColor oldOwner = obj->getOwner(); + PlayerColor newOwner = identifier.as(); + if(oldOwner.isValidPlayer()) + gs->getPlayerState(oldOwner)->removeOwnedObject(obj);; + + if(newOwner.isValidPlayer()) + gs->getPlayerState(newOwner)->addOwnedObject(obj);; + } + if(what == ObjProperty::OWNER && cai) { if(obj->ID == Obj::TOWN) @@ -1953,17 +1965,13 @@ void SetObjectProperty::applyGs(CGameState *gs) if(oldOwner.isValidPlayer()) { auto * state = gs->getPlayerState(oldOwner); - state->towns -= t; - - if(state->towns.empty()) + if(state->getTowns().empty()) state->daysWithoutCastle = 0; } if(identifier.as().isValidPlayer()) { - PlayerState * p = gs->getPlayerState(identifier.as()); - p->towns.emplace_back(t); - //reset counter before NewTurn to avoid no town message if game loaded at turn when one already captured + PlayerState * p = gs->getPlayerState(identifier.as()); if(p->daysWithoutCastle) p->daysWithoutCastle = std::nullopt; } diff --git a/lib/pathfinder/CPathfinder.cpp b/lib/pathfinder/CPathfinder.cpp index ef92af1df..41b7e7ee5 100644 --- a/lib/pathfinder/CPathfinder.cpp +++ b/lib/pathfinder/CPathfinder.cpp @@ -264,8 +264,7 @@ TeleporterTilesVector CPathfinderHelper::getCastleGates(const PathNodeInfo & sou { TeleporterTilesVector allowedExits; - auto towns = getPlayerState(hero->tempOwner)->towns; - for(const auto & town : towns) + for(const auto & town : getPlayerState(hero->tempOwner)->getTowns()) { if(town->id != source.nodeObject->id && town->visitingHero == nullptr && town->hasBuilt(BuildingID::CASTLE_GATE, ETownType::INFERNO)) diff --git a/lib/spells/AdventureSpellMechanics.cpp b/lib/spells/AdventureSpellMechanics.cpp index 1d559f0d9..a16008d75 100644 --- a/lib/spells/AdventureSpellMechanics.cpp +++ b/lib/spells/AdventureSpellMechanics.cpp @@ -692,9 +692,9 @@ std::vector TownPortalMechanics::getPossibleTowns(SpellC for(const auto & color : team->players) { - for(auto currTown : env->getCb()->getPlayerState(color)->towns) + for(auto currTown : env->getCb()->getPlayerState(color)->getTowns()) { - ret.push_back(currTown.get()); + ret.push_back(currTown); } } return ret; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 9504aafe6..b95c23def 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -555,7 +555,7 @@ void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=fa ssi.creatures = town->creatures; ssi.creatures[town->town->creatures.size()].second.clear();//remove old one - const std::vector > &dwellings = p->dwellings; + const auto &dwellings = p->getDwellings(); if (dwellings.empty())//no dwellings - just remove { sendAndApply(&ssi); @@ -639,7 +639,7 @@ void CGameHandler::onNewTurn() if (player.second.status != EPlayerStatus::INGAME) continue; - if (player.second.heroes.empty() && player.second.towns.empty()) + if (player.second.getHeroes().empty() && player.second.getTowns().empty()) throw std::runtime_error("Invalid player in player state! Player " + std::to_string(player.first.getNum()) + ", map name: " + gs->map->name.toString() + ", map description: " + gs->map->description.toString()); } @@ -724,7 +724,7 @@ void CGameHandler::onNewTurn() if (firstTurn) heroPool->onNewWeek(elem.first); - for (CGHeroInstance *h : (elem).second.heroes) + for (CGHeroInstance *h : (elem).second.getHeroes()) { if (h->visitedTown) giveSpells(h->visitedTown, h); @@ -1286,9 +1286,9 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, const PlayerColor owne const PlayerState * p = getPlayerState(owner); - if ((obj->ID == Obj::CREATURE_GENERATOR1 || obj->ID == Obj::CREATURE_GENERATOR4) && p && p->dwellings.size()==1)//first dwelling captured + if ((obj->ID == Obj::CREATURE_GENERATOR1 || obj->ID == Obj::CREATURE_GENERATOR4) && p && p->getDwellings().size()==1)//first dwelling captured { - for (const CGTownInstance * t : getPlayerState(owner)->towns) + for (const CGTownInstance * t : getPlayerState(owner)->getTowns()) { if (t->hasBuilt(BuildingSubID::PORTAL_OF_SUMMONING)) setPortalDwelling(t);//set initial creatures for all portals of summoning @@ -3297,7 +3297,7 @@ void CGameHandler::handleTimeEvents(PlayerColor color) } } -void CGameHandler::handleTownEvents(CGTownInstance * town) +void CGameHandler::handleTownEvents(const CGTownInstance * town) { for (auto const & event : town->events) { @@ -3631,10 +3631,10 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player) else { //copy heroes vector to avoid iterator invalidation as removal change PlayerState - auto hlp = p->heroes; + auto hlp = p->getHeroes(); for (auto h : hlp) //eliminate heroes { - if (h.get()) + if (h) removeObject(h, player); } @@ -4159,11 +4159,11 @@ void CGameHandler::changeFogOfWar(int3 center, ui32 radius, PlayerColor player, std::unordered_set observedTiles; //do not hide tiles observed by heroes. May lead to disastrous AI problems auto p = getPlayerState(player); - for (auto h : p->heroes) + for (auto h : p->getHeroes()) { getTilesInRange(observedTiles, h->getSightCenter(), h->getSightRadius(), ETileVisibility::REVEALED, h->tempOwner); } - for (auto t : p->towns) + for (auto t : p->getTowns()) { getTilesInRange(observedTiles, t->getSightCenter(), t->getSightRadius(), ETileVisibility::REVEALED, t->tempOwner); } diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 2716e20af..2a4ac68c1 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -230,7 +230,7 @@ public: void addStatistics(StatisticDataSet &stat) const; void handleTimeEvents(PlayerColor player); - void handleTownEvents(CGTownInstance *town); + void handleTownEvents(const CGTownInstance *town); bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h ); void objectVisitEnded(const CObjectVisitQuery &query); diff --git a/server/battles/BattleResultProcessor.cpp b/server/battles/BattleResultProcessor.cpp index b0b476e48..45e08c59b 100644 --- a/server/battles/BattleResultProcessor.cpp +++ b/server/battles/BattleResultProcessor.cpp @@ -484,7 +484,7 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle) if(!finishingBattle->isDraw()) { ConstTransitivePtr strongestHero = nullptr; - for(auto & hero : gameHandler->gameState()->getPlayerState(finishingBattle->loser)->heroes) + for(auto & hero : gameHandler->gameState()->getPlayerState(finishingBattle->loser)->getHeroes()) if(!strongestHero || hero->exp > strongestHero->exp) strongestHero = hero; if(strongestHero->id == finishingBattle->loserHero->id && strongestHero->level > 5) diff --git a/server/processors/NewTurnProcessor.cpp b/server/processors/NewTurnProcessor.cpp index 9318003d9..8629bd4b6 100644 --- a/server/processors/NewTurnProcessor.cpp +++ b/server/processors/NewTurnProcessor.cpp @@ -40,10 +40,10 @@ void NewTurnProcessor::onPlayerTurnStarted(PlayerColor which) const auto * playerState = gameHandler->gameState()->getPlayerState(which); gameHandler->handleTimeEvents(which); - for (auto t : playerState->towns) + for (const auto * t : playerState->getTowns()) gameHandler->handleTownEvents(t); - for (auto t : playerState->towns) + for (const auto * t : playerState->getTowns()) { //garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order if (t->garrisonHero != nullptr) @@ -59,7 +59,7 @@ void NewTurnProcessor::onPlayerTurnEnded(PlayerColor which) const auto * playerState = gameHandler->gameState()->getPlayerState(which); assert(playerState->status == EPlayerStatus::INGAME); - if (playerState->towns.empty()) + if (playerState->getTowns().empty()) { DaysWithoutTown pack; pack.player = which; @@ -92,7 +92,7 @@ ResourceSet NewTurnProcessor::generatePlayerIncome(PlayerColor playerID, bool ne const PlayerState & state = gameHandler->gameState()->players.at(playerID); ResourceSet income; - for (const auto & town : state.towns) + for (const auto & town : state.getTowns()) { if (newWeek && town->hasBuilt(BuildingSubID::TREASURY)) { @@ -123,18 +123,18 @@ ResourceSet NewTurnProcessor::generatePlayerIncome(PlayerColor playerID, bool ne for (GameResID k = GameResID::WOOD; k < GameResID::COUNT; k++) { income += state.valOfBonuses(BonusType::RESOURCES_CONSTANT_BOOST, BonusSubtypeID(k)); - income += state.valOfBonuses(BonusType::RESOURCES_TOWN_MULTIPLYING_BOOST, BonusSubtypeID(k)) * state.towns.size(); + income += state.valOfBonuses(BonusType::RESOURCES_TOWN_MULTIPLYING_BOOST, BonusSubtypeID(k)) * state.getTowns().size(); } if(newWeek) //weekly crystal generation if 1 or more crystal dragons in any hero army or town garrison { bool hasCrystalGenCreature = false; - for (const auto & hero : state.heroes) + for (const auto & hero : state.getHeroes()) for(auto stack : hero->stacks) if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION)) hasCrystalGenCreature = true; - for(const auto & town : state.towns) + for(const auto & town : state.getTowns()) for(auto stack : town->stacks) if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION)) hasCrystalGenCreature = true; @@ -146,10 +146,9 @@ ResourceSet NewTurnProcessor::generatePlayerIncome(PlayerColor playerID, bool ne TResources incomeHandicapped = income; incomeHandicapped.applyHandicap(playerSettings->handicap.percentIncome); - // FIXME: store pre-filtered, all owned objects in PlayerState - for (auto obj : gameHandler->gameState()->map->objects) + for (auto obj : state.getOwnedObjects()) { - if (obj && obj->asOwnable() && obj->getOwner() == playerID) + if (obj->asOwnable()) incomeHandicapped += obj->asOwnable()->dailyIncome(); } diff --git a/server/processors/PlayerMessageProcessor.cpp b/server/processors/PlayerMessageProcessor.cpp index e0198744c..521469cdb 100644 --- a/server/processors/PlayerMessageProcessor.cpp +++ b/server/processors/PlayerMessageProcessor.cpp @@ -710,11 +710,11 @@ bool PlayerMessageProcessor::handleCheatCode(const std::string & cheat, PlayerCo executeCheatCode(cheatName, i.first, ObjectInstanceID::NONE, parameters); if (vstd::contains(townTargetedCheats, cheatName)) - for (const auto & t : i.second.towns) + for (const auto & t : i.second.getTowns()) executeCheatCode(cheatName, i.first, t->id, parameters); if (vstd::contains(heroTargetedCheats, cheatName)) - for (const auto & h : i.second.heroes) + for (const auto & h : i.second.getHeroes()) executeCheatCode(cheatName, i.first, h->id, parameters); } diff --git a/server/processors/TurnOrderProcessor.cpp b/server/processors/TurnOrderProcessor.cpp index ff6bb3d98..b50f56324 100644 --- a/server/processors/TurnOrderProcessor.cpp +++ b/server/processors/TurnOrderProcessor.cpp @@ -121,7 +121,7 @@ bool TurnOrderProcessor::playersInContact(PlayerColor left, PlayerColor right) c } } - for(const auto & hero : leftInfo->heroes) + for(const auto & hero : leftInfo->getHeroes()) { CPathsInfo out(mapSize, hero); auto config = std::make_shared(out, gameHandler->gameState(), hero); @@ -137,7 +137,7 @@ bool TurnOrderProcessor::playersInContact(PlayerColor left, PlayerColor right) c leftReachability[z][x][y] = true; } - for(const auto & hero : rightInfo->heroes) + for(const auto & hero : rightInfo->getHeroes()) { CPathsInfo out(mapSize, hero); auto config = std::make_shared(out, gameHandler->gameState(), hero);