diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index fca3b3073..c028f78e7 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -1588,81 +1588,6 @@ struct statsHLP } return h[best]; } - - //calculates total number of artifacts that belong to given player - static int getNumberOfArts(const PlayerState * ps) - { - int ret = 0; - for(auto h : ps->heroes) - { - ret += (int)h->artifactsInBackpack.size() + (int)h->artifactsWorn.size(); - } - return ret; - } - - // get total strength of player army - static si64 getArmyStrength(const PlayerState * ps) - { - si64 str = 0; - - for(auto h : ps->heroes) - { - if(!h->inTownGarrison) //original h3 behavior - str += h->getArmyStrength(); - } - return str; - } - - // get total gold income - static int getIncome(const PlayerState * ps) - { - int totalIncome = 0; - const CGObjectInstance * heroOrTown = nullptr; - - //Heroes can produce gold as well - skill, specialty or arts - for(const auto & h : ps->heroes) - { - totalIncome += h->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, BonusSubtypeID(GameResID(GameResID::GOLD)))); - - if(!heroOrTown) - heroOrTown = h; - } - - //Add town income of all towns - for(const auto & t : ps->towns) - { - totalIncome += t->dailyIncome()[EGameResID::GOLD]; - - if(!heroOrTown) - heroOrTown = t; - } - - /// FIXME: Dirty dirty hack - /// Stats helper need some access to gamestate. - std::vector ownedObjects; - for(const CGObjectInstance * obj : heroOrTown->cb->gameState()->map->objects) - { - if(obj && obj->tempOwner == ps->color) - ownedObjects.push_back(obj); - } - /// This is code from CPlayerSpecificInfoCallback::getMyObjects - /// I'm really need to find out about callback interface design... - - for(const auto * object : ownedObjects) - { - //Mines - if ( object->ID == Obj::MINE ) - { - const auto * mine = dynamic_cast(object); - assert(mine); - - if (mine->producedResource == EGameResID::GOLD) - totalIncome += mine->producedQuantity; - } - } - - return totalIncome; - } }; void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) @@ -1739,15 +1664,15 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) } if(level >= 4) //artifacts { - FILL_FIELD(artifacts, statsHLP::getNumberOfArts(&g->second)) + FILL_FIELD(artifacts, Statistic::getNumberOfArts(&g->second)) } if(level >= 4) //army strength { - FILL_FIELD(army, statsHLP::getArmyStrength(&g->second)) + FILL_FIELD(army, Statistic::getArmyStrength(&g->second)) } if(level >= 5) //income { - FILL_FIELD(income, statsHLP::getIncome(&g->second)) + FILL_FIELD(income, Statistic::getIncome(&g->second)) } if(level >= 2) //best hero's stats { diff --git a/lib/gameState/GameStatistics.cpp b/lib/gameState/GameStatistics.cpp index 49c489ccc..69c4e01f6 100644 --- a/lib/gameState/GameStatistics.cpp +++ b/lib/gameState/GameStatistics.cpp @@ -12,6 +12,11 @@ #include "../CPlayerState.h" #include "../constants/StringConstants.h" #include "CGameState.h" +#include "../mapObjects/CGHeroInstance.h" +#include "../mapObjects/CGTownInstance.h" +#include "../mapObjects/CGObjectInstance.h" +#include "../mapObjects/MiscObjects.h" +#include "../mapping/CMap.h" VCMI_LIB_NAMESPACE_BEGIN @@ -28,8 +33,11 @@ StatisticDataSetEntry StatisticDataSet::createEntry(const PlayerState * ps, cons data.player = ps->color; data.team = ps->team; data.resources = ps->resources; - data.heroesCount = ps->heroes.size(); - data.townCount = ps->towns.size(); + data.numberHeroes = ps->heroes.size(); + data.numberTowns = ps->towns.size(); + data.numberArtifacts = Statistic::getNumberOfArts(ps); + data.armyStrength = Statistic::getArmyStrength(ps); + data.income = Statistic::getIncome(ps); return data; } @@ -40,14 +48,14 @@ std::string StatisticDataSet::toCsv() auto resources = std::vector{EGameResID::GOLD, EGameResID::WOOD, EGameResID::MERCURY, EGameResID::ORE, EGameResID::SULFUR, EGameResID::CRYSTAL, EGameResID::GEMS}; - ss << "Day" << ";" << "Player" << ";" << "Team" << ";" << "HeroesCount" << ";" << "TownCount"; + ss << "Day" << ";" << "Player" << ";" << "Team" << ";" << "NumberHeroes" << ";" << "NumberTowns" << ";" << "NumberArtifacts" << ";" << "ArmyStrength" << ";" << "Income"; for(auto & resource : resources) ss << ";" << GameConstants::RESOURCE_NAMES[resource]; ss << "\r\n"; for(auto & entry : data) { - ss << entry.day << ";" << GameConstants::PLAYER_COLOR_NAMES[entry.player] << ";" << entry.team.getNum() << ";" << entry.heroesCount << ";" << entry.townCount; + ss << entry.day << ";" << GameConstants::PLAYER_COLOR_NAMES[entry.player] << ";" << entry.team.getNum() << ";" << entry.numberHeroes << ";" << entry.numberTowns << ";" << entry.numberArtifacts << ";" << entry.armyStrength << ";" << entry.income; for(auto & resource : resources) ss << ";" << entry.resources[resource]; ss << "\r\n"; @@ -56,4 +64,79 @@ std::string StatisticDataSet::toCsv() return ss.str(); } +//calculates total number of artifacts that belong to given player +int Statistic::getNumberOfArts(const PlayerState * ps) +{ + int ret = 0; + for(auto h : ps->heroes) + { + ret += (int)h->artifactsInBackpack.size() + (int)h->artifactsWorn.size(); + } + return ret; +} + +// get total strength of player army +si64 Statistic::getArmyStrength(const PlayerState * ps) +{ + si64 str = 0; + + for(auto h : ps->heroes) + { + if(!h->inTownGarrison) //original h3 behavior + str += h->getArmyStrength(); + } + return str; +} + +// get total gold income +int Statistic::getIncome(const PlayerState * ps) +{ + int totalIncome = 0; + const CGObjectInstance * heroOrTown = nullptr; + + //Heroes can produce gold as well - skill, specialty or arts + for(const auto & h : ps->heroes) + { + totalIncome += h->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, BonusSubtypeID(GameResID(GameResID::GOLD)))); + + if(!heroOrTown) + heroOrTown = h; + } + + //Add town income of all towns + for(const auto & t : ps->towns) + { + totalIncome += t->dailyIncome()[EGameResID::GOLD]; + + if(!heroOrTown) + heroOrTown = t; + } + + /// FIXME: Dirty dirty hack + /// Stats helper need some access to gamestate. + std::vector ownedObjects; + for(const CGObjectInstance * obj : heroOrTown->cb->gameState()->map->objects) + { + if(obj && obj->tempOwner == ps->color) + ownedObjects.push_back(obj); + } + /// This is code from CPlayerSpecificInfoCallback::getMyObjects + /// I'm really need to find out about callback interface design... + + for(const auto * object : ownedObjects) + { + //Mines + if ( object->ID == Obj::MINE ) + { + const auto * mine = dynamic_cast(object); + assert(mine); + + if (mine->producedResource == EGameResID::GOLD) + totalIncome += mine->producedQuantity; + } + } + + return totalIncome; +} + VCMI_LIB_NAMESPACE_END diff --git a/lib/gameState/GameStatistics.h b/lib/gameState/GameStatistics.h index 3edf366d8..133e24c57 100644 --- a/lib/gameState/GameStatistics.h +++ b/lib/gameState/GameStatistics.h @@ -23,8 +23,11 @@ struct DLL_LINKAGE StatisticDataSetEntry PlayerColor player; TeamID team; TResources resources; - int heroesCount; - int townCount; + int numberHeroes; + int numberTowns; + int numberArtifacts; + si64 armyStrength; + int income; template void serialize(Handler &h) { @@ -32,8 +35,11 @@ struct DLL_LINKAGE StatisticDataSetEntry h & player; h & team; h & resources; - h & heroesCount; - h & townCount; + h & numberHeroes; + h & numberTowns; + h & numberArtifacts; + h & armyStrength; + h & income; } }; @@ -52,4 +58,12 @@ public: } }; +class DLL_LINKAGE Statistic +{ +public: + static int getNumberOfArts(const PlayerState * ps); + static si64 getArmyStrength(const PlayerState * ps); + static int getIncome(const PlayerState * ps); +}; + VCMI_LIB_NAMESPACE_END