mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Fix hero pool persistency between saves
This commit is contained in:
@@ -64,6 +64,7 @@ public:
|
||||
{
|
||||
h & heroesPool;
|
||||
h & pavailable;
|
||||
h & currentTavern;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -7242,3 +7242,10 @@ void CGameHandler::createObject(const int3 & visitablePosition, Obj type, int32_
|
||||
no.targetPos = visitablePosition;
|
||||
sendAndApply(&no);
|
||||
}
|
||||
|
||||
void CGameHandler::deserializationFix()
|
||||
{
|
||||
//FIXME: pointer to GameHandler itself can't be deserialized at the moment since GameHandler is top-level entity in serialization
|
||||
// restore any places that requires such pointer manually
|
||||
heroPool->gameHandler = this;
|
||||
}
|
||||
|
@@ -99,6 +99,8 @@ class CGameHandler : public IGameCallback, public CBattleInfoCallback, public En
|
||||
std::shared_ptr<CApplier<CBaseForGHApply>> applier;
|
||||
std::unique_ptr<boost::thread> battleThread;
|
||||
|
||||
void deserializationFix();
|
||||
|
||||
public:
|
||||
std::unique_ptr<HeroPoolProcessor> heroPool;
|
||||
|
||||
@@ -290,6 +292,9 @@ public:
|
||||
h & heroPool;
|
||||
h & getRandomGenerator();
|
||||
|
||||
if (!h.saving)
|
||||
deserializationFix();
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
JsonNode scriptsState;
|
||||
if(h.saving)
|
||||
|
@@ -175,38 +175,43 @@ bool HeroPoolProcessor::hireHero(const CGObjectInstance *obj, const HeroTypeID &
|
||||
return true;
|
||||
}
|
||||
|
||||
std::set<const CHeroClass *> HeroPoolProcessor::findAvailableClassesFor(const PlayerColor & player) const
|
||||
std::vector<const CHeroClass *> HeroPoolProcessor::findAvailableClassesFor(const PlayerColor & player) const
|
||||
{
|
||||
std::set<const CHeroClass *> result;
|
||||
std::vector<const CHeroClass *> result;
|
||||
|
||||
const auto & hpool = gameHandler->gameState()->hpool;
|
||||
FactionID factionID = gameHandler->getPlayerSettings(player)->castle;
|
||||
|
||||
for(auto & elem : hpool->unusedHeroesFromPool())
|
||||
{
|
||||
if (vstd::contains(result, elem.second->type->heroClass))
|
||||
continue;
|
||||
|
||||
bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player);
|
||||
bool heroClassBanned = elem.second->type->heroClass->selectionProbability[factionID] == 0;
|
||||
|
||||
if(heroAvailable && !heroClassBanned)
|
||||
result.insert(elem.second->type->heroClass);
|
||||
result.push_back(elem.second->type->heroClass);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<CGHeroInstance *> HeroPoolProcessor::findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const
|
||||
std::vector<CGHeroInstance *> HeroPoolProcessor::findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const
|
||||
{
|
||||
std::set<CGHeroInstance *> result;
|
||||
std::vector<CGHeroInstance *> result;
|
||||
|
||||
const auto & hpool = gameHandler->gameState()->hpool;
|
||||
|
||||
for(auto & elem : hpool->unusedHeroesFromPool())
|
||||
{
|
||||
assert(!vstd::contains(result, elem.second));
|
||||
|
||||
bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player);
|
||||
bool heroClassMatches = elem.second->type->heroClass == heroClass;
|
||||
|
||||
if(heroAvailable && heroClassMatches)
|
||||
result.insert(elem.second);
|
||||
result.push_back(elem.second);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -224,8 +229,8 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
|
||||
const auto & hpool = gameHandler->gameState()->hpool;
|
||||
const auto & currentTavern = hpool->getHeroesFor(player);
|
||||
|
||||
std::set<const CHeroClass *> potentialClasses = findAvailableClassesFor(player);
|
||||
std::set<const CHeroClass *> possibleClasses;
|
||||
std::vector<const CHeroClass *> potentialClasses = findAvailableClassesFor(player);
|
||||
std::vector<const CHeroClass *> possibleClasses;
|
||||
|
||||
if(potentialClasses.empty())
|
||||
{
|
||||
@@ -245,7 +250,7 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
|
||||
if (hasSameClass)
|
||||
continue;
|
||||
|
||||
possibleClasses.insert(heroClass);
|
||||
possibleClasses.push_back(heroClass);
|
||||
}
|
||||
|
||||
if (possibleClasses.empty())
|
||||
@@ -259,6 +264,7 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
|
||||
totalWeight += heroClass->selectionProbability.at(factionID);
|
||||
|
||||
int roll = getRandomGenerator(player).nextInt(totalWeight - 1);
|
||||
|
||||
for(const auto & heroClass : possibleClasses)
|
||||
{
|
||||
roll -= heroClass->selectionProbability.at(factionID);
|
||||
@@ -276,7 +282,7 @@ CGHeroInstance * HeroPoolProcessor::pickHeroFor(bool isNative, const PlayerColor
|
||||
if(!heroClass)
|
||||
return nullptr;
|
||||
|
||||
std::set<CGHeroInstance *> possibleHeroes = findAvailableHeroesFor(player, heroClass);
|
||||
std::vector<CGHeroInstance *> possibleHeroes = findAvailableHeroesFor(player, heroClass);
|
||||
|
||||
assert(!possibleHeroes.empty());
|
||||
if(possibleHeroes.empty())
|
||||
@@ -288,7 +294,10 @@ CGHeroInstance * HeroPoolProcessor::pickHeroFor(bool isNative, const PlayerColor
|
||||
CRandomGenerator & HeroPoolProcessor::getRandomGenerator(const PlayerColor & player)
|
||||
{
|
||||
if (playerSeed.count(player) == 0)
|
||||
playerSeed.emplace(player, CRandomGenerator(gameHandler->getRandomGenerator().nextInt()));
|
||||
|
||||
return playerSeed.at(player);
|
||||
{
|
||||
int seed = gameHandler->getRandomGenerator().nextInt();
|
||||
playerSeed.emplace(player, std::make_unique<CRandomGenerator>(seed));
|
||||
}
|
||||
|
||||
return *playerSeed.at(player);
|
||||
}
|
||||
|
@@ -26,23 +26,24 @@ class CGameHandler;
|
||||
|
||||
class HeroPoolProcessor : boost::noncopyable
|
||||
{
|
||||
CGameHandler * gameHandler;
|
||||
|
||||
/// per-player random generators
|
||||
std::map<PlayerColor, CRandomGenerator> playerSeed;
|
||||
std::map<PlayerColor, std::unique_ptr<CRandomGenerator>> playerSeed;
|
||||
|
||||
void clearHeroFromSlot(const PlayerColor & color, TavernHeroSlot slot);
|
||||
void selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveStartingArmy);
|
||||
|
||||
std::set<const CHeroClass *> findAvailableClassesFor(const PlayerColor & player) const;
|
||||
std::set<CGHeroInstance *> findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const;
|
||||
std::vector<const CHeroClass *> findAvailableClassesFor(const PlayerColor & player) const;
|
||||
std::vector<CGHeroInstance *> findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const;
|
||||
|
||||
const CHeroClass * pickClassFor(bool isNative, const PlayerColor & player);
|
||||
|
||||
CGHeroInstance * pickHeroFor(bool isNative, const PlayerColor & player);
|
||||
|
||||
CRandomGenerator & getRandomGenerator(const PlayerColor & player);
|
||||
|
||||
public:
|
||||
CGameHandler * gameHandler;
|
||||
|
||||
HeroPoolProcessor();
|
||||
HeroPoolProcessor(CGameHandler * gameHandler);
|
||||
|
||||
@@ -55,7 +56,6 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & gameHandler;
|
||||
h & playerSeed;
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user