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 & heroesPool;
|
||||||
h & pavailable;
|
h & pavailable;
|
||||||
|
h & currentTavern;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -7242,3 +7242,10 @@ void CGameHandler::createObject(const int3 & visitablePosition, Obj type, int32_
|
|||||||
no.targetPos = visitablePosition;
|
no.targetPos = visitablePosition;
|
||||||
sendAndApply(&no);
|
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::shared_ptr<CApplier<CBaseForGHApply>> applier;
|
||||||
std::unique_ptr<boost::thread> battleThread;
|
std::unique_ptr<boost::thread> battleThread;
|
||||||
|
|
||||||
|
void deserializationFix();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<HeroPoolProcessor> heroPool;
|
std::unique_ptr<HeroPoolProcessor> heroPool;
|
||||||
|
|
||||||
@@ -290,6 +292,9 @@ public:
|
|||||||
h & heroPool;
|
h & heroPool;
|
||||||
h & getRandomGenerator();
|
h & getRandomGenerator();
|
||||||
|
|
||||||
|
if (!h.saving)
|
||||||
|
deserializationFix();
|
||||||
|
|
||||||
#if SCRIPTING_ENABLED
|
#if SCRIPTING_ENABLED
|
||||||
JsonNode scriptsState;
|
JsonNode scriptsState;
|
||||||
if(h.saving)
|
if(h.saving)
|
||||||
|
@@ -175,38 +175,43 @@ bool HeroPoolProcessor::hireHero(const CGObjectInstance *obj, const HeroTypeID &
|
|||||||
return true;
|
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;
|
const auto & hpool = gameHandler->gameState()->hpool;
|
||||||
FactionID factionID = gameHandler->getPlayerSettings(player)->castle;
|
FactionID factionID = gameHandler->getPlayerSettings(player)->castle;
|
||||||
|
|
||||||
for(auto & elem : hpool->unusedHeroesFromPool())
|
for(auto & elem : hpool->unusedHeroesFromPool())
|
||||||
{
|
{
|
||||||
|
if (vstd::contains(result, elem.second->type->heroClass))
|
||||||
|
continue;
|
||||||
|
|
||||||
bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player);
|
bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player);
|
||||||
bool heroClassBanned = elem.second->type->heroClass->selectionProbability[factionID] == 0;
|
bool heroClassBanned = elem.second->type->heroClass->selectionProbability[factionID] == 0;
|
||||||
|
|
||||||
if(heroAvailable && !heroClassBanned)
|
if(heroAvailable && !heroClassBanned)
|
||||||
result.insert(elem.second->type->heroClass);
|
result.push_back(elem.second->type->heroClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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;
|
const auto & hpool = gameHandler->gameState()->hpool;
|
||||||
|
|
||||||
for(auto & elem : hpool->unusedHeroesFromPool())
|
for(auto & elem : hpool->unusedHeroesFromPool())
|
||||||
{
|
{
|
||||||
|
assert(!vstd::contains(result, elem.second));
|
||||||
|
|
||||||
bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player);
|
bool heroAvailable = hpool->isHeroAvailableFor(elem.first, player);
|
||||||
bool heroClassMatches = elem.second->type->heroClass == heroClass;
|
bool heroClassMatches = elem.second->type->heroClass == heroClass;
|
||||||
|
|
||||||
if(heroAvailable && heroClassMatches)
|
if(heroAvailable && heroClassMatches)
|
||||||
result.insert(elem.second);
|
result.push_back(elem.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -224,8 +229,8 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
|
|||||||
const auto & hpool = gameHandler->gameState()->hpool;
|
const auto & hpool = gameHandler->gameState()->hpool;
|
||||||
const auto & currentTavern = hpool->getHeroesFor(player);
|
const auto & currentTavern = hpool->getHeroesFor(player);
|
||||||
|
|
||||||
std::set<const CHeroClass *> potentialClasses = findAvailableClassesFor(player);
|
std::vector<const CHeroClass *> potentialClasses = findAvailableClassesFor(player);
|
||||||
std::set<const CHeroClass *> possibleClasses;
|
std::vector<const CHeroClass *> possibleClasses;
|
||||||
|
|
||||||
if(potentialClasses.empty())
|
if(potentialClasses.empty())
|
||||||
{
|
{
|
||||||
@@ -245,7 +250,7 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
|
|||||||
if (hasSameClass)
|
if (hasSameClass)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
possibleClasses.insert(heroClass);
|
possibleClasses.push_back(heroClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (possibleClasses.empty())
|
if (possibleClasses.empty())
|
||||||
@@ -259,6 +264,7 @@ const CHeroClass * HeroPoolProcessor::pickClassFor(bool isNative, const PlayerCo
|
|||||||
totalWeight += heroClass->selectionProbability.at(factionID);
|
totalWeight += heroClass->selectionProbability.at(factionID);
|
||||||
|
|
||||||
int roll = getRandomGenerator(player).nextInt(totalWeight - 1);
|
int roll = getRandomGenerator(player).nextInt(totalWeight - 1);
|
||||||
|
|
||||||
for(const auto & heroClass : possibleClasses)
|
for(const auto & heroClass : possibleClasses)
|
||||||
{
|
{
|
||||||
roll -= heroClass->selectionProbability.at(factionID);
|
roll -= heroClass->selectionProbability.at(factionID);
|
||||||
@@ -276,7 +282,7 @@ CGHeroInstance * HeroPoolProcessor::pickHeroFor(bool isNative, const PlayerColor
|
|||||||
if(!heroClass)
|
if(!heroClass)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::set<CGHeroInstance *> possibleHeroes = findAvailableHeroesFor(player, heroClass);
|
std::vector<CGHeroInstance *> possibleHeroes = findAvailableHeroesFor(player, heroClass);
|
||||||
|
|
||||||
assert(!possibleHeroes.empty());
|
assert(!possibleHeroes.empty());
|
||||||
if(possibleHeroes.empty())
|
if(possibleHeroes.empty())
|
||||||
@@ -288,7 +294,10 @@ CGHeroInstance * HeroPoolProcessor::pickHeroFor(bool isNative, const PlayerColor
|
|||||||
CRandomGenerator & HeroPoolProcessor::getRandomGenerator(const PlayerColor & player)
|
CRandomGenerator & HeroPoolProcessor::getRandomGenerator(const PlayerColor & player)
|
||||||
{
|
{
|
||||||
if (playerSeed.count(player) == 0)
|
if (playerSeed.count(player) == 0)
|
||||||
playerSeed.emplace(player, CRandomGenerator(gameHandler->getRandomGenerator().nextInt()));
|
{
|
||||||
|
int seed = gameHandler->getRandomGenerator().nextInt();
|
||||||
|
playerSeed.emplace(player, std::make_unique<CRandomGenerator>(seed));
|
||||||
|
}
|
||||||
|
|
||||||
return playerSeed.at(player);
|
return *playerSeed.at(player);
|
||||||
}
|
}
|
||||||
|
@@ -26,23 +26,24 @@ class CGameHandler;
|
|||||||
|
|
||||||
class HeroPoolProcessor : boost::noncopyable
|
class HeroPoolProcessor : boost::noncopyable
|
||||||
{
|
{
|
||||||
CGameHandler * gameHandler;
|
|
||||||
|
|
||||||
/// per-player random generators
|
/// 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 clearHeroFromSlot(const PlayerColor & color, TavernHeroSlot slot);
|
||||||
void selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveStartingArmy);
|
void selectNewHeroForSlot(const PlayerColor & color, TavernHeroSlot slot, bool needNativeHero, bool giveStartingArmy);
|
||||||
|
|
||||||
std::set<const CHeroClass *> findAvailableClassesFor(const PlayerColor & player) const;
|
std::vector<const CHeroClass *> findAvailableClassesFor(const PlayerColor & player) const;
|
||||||
std::set<CGHeroInstance *> findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const;
|
std::vector<CGHeroInstance *> findAvailableHeroesFor(const PlayerColor & player, const CHeroClass * heroClass) const;
|
||||||
|
|
||||||
const CHeroClass * pickClassFor(bool isNative, const PlayerColor & player);
|
const CHeroClass * pickClassFor(bool isNative, const PlayerColor & player);
|
||||||
|
|
||||||
CGHeroInstance * pickHeroFor(bool isNative, const PlayerColor & player);
|
CGHeroInstance * pickHeroFor(bool isNative, const PlayerColor & player);
|
||||||
|
|
||||||
CRandomGenerator & getRandomGenerator(const PlayerColor & player);
|
CRandomGenerator & getRandomGenerator(const PlayerColor & player);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
CGameHandler * gameHandler;
|
||||||
|
|
||||||
HeroPoolProcessor();
|
HeroPoolProcessor();
|
||||||
HeroPoolProcessor(CGameHandler * gameHandler);
|
HeroPoolProcessor(CGameHandler * gameHandler);
|
||||||
|
|
||||||
@@ -55,7 +56,6 @@ public:
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & gameHandler;
|
|
||||||
h & playerSeed;
|
h & playerSeed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user