1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge remote-tracking branch 'remotes/origin/develop' into SpellsRefactoring8

# Conflicts:
#	client/battle/CBattleInterface.cpp
#	lib/spells/BattleSpellMechanics.cpp
This commit is contained in:
AlexVinS 2016-09-12 10:13:40 +03:00
commit 505e53c17d
34 changed files with 366 additions and 311 deletions

View File

@ -701,7 +701,7 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo &AttackInfo
for(int i = 0; i < totalAttacks; i++)
{
std::pair<ui32, ui32> retaliation(0,0);
auto attackDmg = cbc->battleEstimateDamage(curBai, &retaliation);
auto attackDmg = cbc->battleEstimateDamage(CRandomGenerator::getDefault(), curBai, &retaliation);
ap.damageDealt = (attackDmg.first + attackDmg.second) / 2;
ap.damageReceived = (retaliation.first + retaliation.second) / 2;
@ -785,7 +785,7 @@ int PotentialTargets::bestActionValue() const
void EnemyInfo::calcDmg(const CStack * ourStack)
{
TDmgRange retal, dmg = cbc->battleEstimateDamage(ourStack, s, &retal);
TDmgRange retal, dmg = cbc->battleEstimateDamage(CRandomGenerator::getDefault(), ourStack, s, &retal);
adi = (dmg.first + dmg.second) / 2;
adr = (retal.first + retal.second) / 2;
}

View File

@ -44,7 +44,7 @@ struct EnemyInfo
{}
void calcDmg(const CStack * ourStack)
{
TDmgRange retal, dmg = cbc->battleEstimateDamage(ourStack, s, &retal);
TDmgRange retal, dmg = cbc->battleEstimateDamage(CRandomGenerator::getDefault(), ourStack, s, &retal);
adi = (dmg.first + dmg.second) / 2;
adr = (retal.first + retal.second) / 2;
}

View File

@ -1587,7 +1587,7 @@ void CBattleInterface::activateStack()
if(randomSpellcaster)
creatureSpellToCast = -1; //spell will be set later on cast
else
creatureSpellToCast = curInt->cb->battleGetRandomStackSpell(s, CBattleInfoCallback::RANDOM_AIMED); //faerie dragon can cast only one spell until their next move
creatureSpellToCast = curInt->cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), s, CBattleInfoCallback::RANDOM_AIMED); //faerie dragon can cast only one spell until their next move
//TODO: what if creature can cast BOTH random genie spell and aimed spell?
//TODO: faerie dragon type spell should be selected by server
}
@ -2059,7 +2059,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
{
if (shere && ourStack && shere != sactive) //only positive spells for other allied creatures
{
int spellID = curInt->cb->battleGetRandomStackSpell(shere, CBattleInfoCallback::RANDOM_GENIE);
int spellID = curInt->cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), shere, CBattleInfoCallback::RANDOM_GENIE);
if (spellID > -1)
{
legalAction = true;
@ -2203,7 +2203,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
}
};
std::string estDmgText = formatDmgRange(curInt->cb->battleEstimateDamage(sactive, shere)); //calculating estimated dmg
std::string estDmgText = formatDmgRange(curInt->cb->battleEstimateDamage(CRandomGenerator::getDefault(), sactive, shere)); //calculating estimated dmg
consoleMsg = (boost::format(CGI->generaltexth->allTexts[36]) % shere->getName() % estDmgText).str(); //Attack %s (%s damage)
}
break;
@ -2215,7 +2215,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
cursorFrame = ECursor::COMBAT_SHOOT;
realizeAction = [=] {giveCommand(Battle::SHOOT, myNumber, activeStack->ID);};
std::string estDmgText = formatDmgRange(curInt->cb->battleEstimateDamage(sactive, shere)); //calculating estimated dmg
std::string estDmgText = formatDmgRange(curInt->cb->battleEstimateDamage(CRandomGenerator::getDefault(), sactive, shere)); //calculating estimated dmg
//printing - Shoot %s (%d shots left, %s damage)
consoleMsg = (boost::format(CGI->generaltexth->allTexts[296]) % shere->getName() % sactive->shots % estDmgText).str();
}
@ -2359,7 +2359,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
}
else //unknown random spell
{
giveCommand(Battle::MONSTER_SPELL, myNumber, sactive->ID, curInt->cb->battleGetRandomStackSpell(shere, CBattleInfoCallback::RANDOM_GENIE));
giveCommand(Battle::MONSTER_SPELL, myNumber, sactive->ID, curInt->cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), shere, CBattleInfoCallback::RANDOM_GENIE));
}
}
else

View File

@ -521,15 +521,15 @@ std::set<BattleHex> CBattleInfoCallback::battleGetAttackedHexes(const CStack* at
return attackedHexes;
}
SpellID CBattleInfoCallback::battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode) const
SpellID CBattleInfoCallback::battleGetRandomStackSpell(CRandomGenerator & rand, const CStack * stack, ERandomSpell mode) const
{
switch (mode)
{
case RANDOM_GENIE:
return getRandomBeneficialSpell(stack); //target
return getRandomBeneficialSpell(rand, stack); //target
break;
case RANDOM_AIMED:
return getRandomCastedSpell(stack); //caster
return getRandomCastedSpell(rand, stack); //caster
break;
default:
logGlobal->errorStream() << "Incorrect mode of battleGetRandomSpell (" << mode <<")";
@ -1076,15 +1076,15 @@ TDmgRange CBattleInfoCallback::calculateDmgRange( const CStack* attacker, const
return calculateDmgRange(bai);
}
TDmgRange CBattleInfoCallback::battleEstimateDamage(const CStack * attacker, const CStack * defender, TDmgRange * retaliationDmg) const
TDmgRange CBattleInfoCallback::battleEstimateDamage(CRandomGenerator & rand, const CStack * attacker, const CStack * defender, TDmgRange * retaliationDmg) const
{
RETURN_IF_NOT_BATTLE(std::make_pair(0, 0));
const bool shooting = battleCanShoot(attacker, defender->position);
const BattleAttackInfo bai(attacker, defender, shooting);
return battleEstimateDamage(bai, retaliationDmg);
return battleEstimateDamage(rand, bai, retaliationDmg);
}
std::pair<ui32, ui32> CBattleInfoCallback::battleEstimateDamage(const BattleAttackInfo &bai, std::pair<ui32, ui32> * retaliationDmg /*= nullptr*/) const
std::pair<ui32, ui32> CBattleInfoCallback::battleEstimateDamage(CRandomGenerator & rand, const BattleAttackInfo &bai, std::pair<ui32, ui32> * retaliationDmg /*= nullptr*/) const
{
RETURN_IF_NOT_BATTLE(std::make_pair(0, 0));
@ -1106,7 +1106,7 @@ std::pair<ui32, ui32> CBattleInfoCallback::battleEstimateDamage(const BattleAtta
{
BattleStackAttacked bsa;
bsa.damageAmount = ret.*pairElems[i];
bai.defender->prepareAttacked(bsa, gs->getRandomGenerator(), bai.defenderCount);
bai.defender->prepareAttacked(bsa, rand, bai.defenderCount);
auto retaliationAttack = bai.reverse();
retaliationAttack.attackerCount = bsa.newAmount;
@ -1753,7 +1753,7 @@ std::set<const CStack*> CBattleInfoCallback:: batteAdjacentCreatures(const CStac
return stacks;
}
SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) const
SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, const CStack * subject) const
{
RETURN_IF_NOT_BATTLE(SpellID::NONE);
//This is complete list. No spells from mods.
@ -1875,7 +1875,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
if(!beneficialSpells.empty())
{
return *RandomGeneratorUtil::nextItem(beneficialSpells, gs->getRandomGenerator());
return *RandomGeneratorUtil::nextItem(beneficialSpells, rand);
}
else
{
@ -1883,7 +1883,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
}
}
SpellID CBattleInfoCallback::getRandomCastedSpell(const CStack * caster) const
SpellID CBattleInfoCallback::getRandomCastedSpell(CRandomGenerator & rand,const CStack * caster) const
{
RETURN_IF_NOT_BATTLE(SpellID::NONE);
@ -1895,7 +1895,7 @@ SpellID CBattleInfoCallback::getRandomCastedSpell(const CStack * caster) const
{
totalWeight += std::max(b->additionalInfo, 1); //minimal chance to cast is 1
}
int randomPos = gs->getRandomGenerator().nextInt(totalWeight - 1);
int randomPos = rand.nextInt(totalWeight - 1);
for(Bonus * b : *bl)
{
randomPos -= std::max(b->additionalInfo, 1);

View File

@ -22,6 +22,7 @@ struct CObstacleInstance;
class IBonusBearer;
struct InfoAboutHero;
class CArmedInstance;
class CRandomGenerator;
namespace boost
{class shared_mutex;}
@ -266,8 +267,8 @@ public:
TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
//hextowallpart //int battleGetWallUnderHex(BattleHex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
std::pair<ui32, ui32> battleEstimateDamage(const BattleAttackInfo &bai, std::pair<ui32, ui32> * retaliationDmg = nullptr) const; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
std::pair<ui32, ui32> battleEstimateDamage(const CStack * attacker, const CStack * defender, std::pair<ui32, ui32> * retaliationDmg = nullptr) const; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
std::pair<ui32, ui32> battleEstimateDamage(CRandomGenerator & rand, const BattleAttackInfo &bai, std::pair<ui32, ui32> * retaliationDmg = nullptr) const; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
std::pair<ui32, ui32> battleEstimateDamage(CRandomGenerator & rand, const CStack * attacker, const CStack * defender, std::pair<ui32, ui32> * retaliationDmg = nullptr) const; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
si8 battleHasDistancePenalty( const CStack * stack, BattleHex destHex ) const;
si8 battleHasDistancePenalty(const IBonusBearer *bonusBearer, BattleHex shooterPosition, BattleHex destHex ) const;
si8 battleHasWallPenalty(const CStack * stack, BattleHex destHex) const; //checks if given stack has wall penalty
@ -285,9 +286,9 @@ public:
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode) const; //checks if given player can cast given spell
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpellHere(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const; //checks if given player can cast given spell at given tile in given mode
SpellID battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode) const;
SpellID getRandomBeneficialSpell(const CStack * subject) const;
SpellID getRandomCastedSpell(const CStack * caster) const; //called at the beginning of turn for Faerie Dragon
SpellID battleGetRandomStackSpell(CRandomGenerator & rand, const CStack * stack, ERandomSpell mode) const;
SpellID getRandomBeneficialSpell(CRandomGenerator & rand, const CStack * subject) const;
SpellID getRandomCastedSpell(CRandomGenerator & rand, const CStack * caster) const; //called at the beginning of turn for Faerie Dragon
const CStack * getStackIf(std::function<bool(const CStack*)> pred) const;

View File

@ -476,13 +476,13 @@ int CGameState::pickUnusedHeroTypeRandomly(PlayerColor owner)
// select random hero native to "our" faction
if(!factionHeroes.empty())
{
return RandomGeneratorUtil::nextItem(factionHeroes, rand)->getNum();
return RandomGeneratorUtil::nextItem(factionHeroes, getRandomGenerator())->getNum();
}
logGlobal->warnStream() << "Cannot find free hero of appropriate faction for player " << owner << " - trying to get first available...";
if(!otherHeroes.empty())
{
return RandomGeneratorUtil::nextItem(otherHeroes, rand)->getNum();
return RandomGeneratorUtil::nextItem(otherHeroes, getRandomGenerator())->getNum();
}
logGlobal->error("No free allowed heroes!");
@ -500,29 +500,29 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
switch(obj->ID)
{
case Obj::RANDOM_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(getRandomGenerator(), CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC));
case Obj::RANDOM_TREASURE_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(getRandomGenerator(), CArtifact::ART_TREASURE));
case Obj::RANDOM_MINOR_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MINOR));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(getRandomGenerator(), CArtifact::ART_MINOR));
case Obj::RANDOM_MAJOR_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MAJOR));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(getRandomGenerator(), CArtifact::ART_MAJOR));
case Obj::RANDOM_RELIC_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, CArtifact::ART_RELIC));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(getRandomGenerator(), CArtifact::ART_RELIC));
case Obj::RANDOM_HERO:
return std::make_pair(Obj::HERO, pickNextHeroType(obj->tempOwner));
case Obj::RANDOM_MONSTER:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(getRandomGenerator()));
case Obj::RANDOM_MONSTER_L1:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 1));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(getRandomGenerator(), 1));
case Obj::RANDOM_MONSTER_L2:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 2));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(getRandomGenerator(), 2));
case Obj::RANDOM_MONSTER_L3:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 3));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(getRandomGenerator(), 3));
case Obj::RANDOM_MONSTER_L4:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 4));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(getRandomGenerator(), 4));
case Obj::RANDOM_RESOURCE:
return std::make_pair(Obj::RESOURCE,rand.nextInt(6)); //now it's OH3 style, use %8 for mithril
return std::make_pair(Obj::RESOURCE,getRandomGenerator().nextInt(6)); //now it's OH3 style, use %8 for mithril
case Obj::RANDOM_TOWN:
{
PlayerColor align = PlayerColor((static_cast<CGTownInstance*>(obj))->alignment);
@ -542,18 +542,18 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
{
do
{
f = rand.nextInt(VLC->townh->factions.size() - 1);
f = getRandomGenerator().nextInt(VLC->townh->factions.size() - 1);
}
while (VLC->townh->factions[f]->town == nullptr); // find playable faction
}
return std::make_pair(Obj::TOWN,f);
}
case Obj::RANDOM_MONSTER_L5:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 5));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(getRandomGenerator(), 5));
case Obj::RANDOM_MONSTER_L6:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 6));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(getRandomGenerator(), 6));
case Obj::RANDOM_MONSTER_L7:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 7));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(getRandomGenerator(), 7));
case Obj::RANDOM_DWELLING:
case Obj::RANDOM_DWELLING_LVL:
case Obj::RANDOM_DWELLING_FACTION:
@ -564,7 +564,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
//if castle alignment available
if (auto info = dynamic_cast<CCreGenAsCastleInfo*>(dwl->info))
{
faction = rand.nextInt(VLC->townh->factions.size() - 1);
faction = getRandomGenerator().nextInt(VLC->townh->factions.size() - 1);
if (info->asCastle)
{
for(auto & elem : map->objects)
@ -593,7 +593,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
{
if((faction>7) && (info->castles[1]&(1<<(faction-8))))
break;
faction = rand.nextInt(GameConstants::F_NUMBER - 1);
faction = getRandomGenerator().nextInt(GameConstants::F_NUMBER - 1);
}
}
}
@ -605,7 +605,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
//if level set to range
if (auto info = dynamic_cast<CCreGenLeveledInfo*>(dwl->info))
{
level = rand.nextInt(info->minLevel, info->maxLevel);
level = getRandomGenerator().nextInt(info->minLevel, info->maxLevel);
}
else // fixed level
{
@ -639,7 +639,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
if (result.first == Obj::NO_OBJ)
{
logGlobal->errorStream() << "Error: failed to find dwelling for "<< VLC->townh->factions[faction]->name << " of level " << int(level);
result = std::make_pair(Obj::CREATURE_GENERATOR1, *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::CREATURE_GENERATOR1), rand));
result = std::make_pair(Obj::CREATURE_GENERATOR1, *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::CREATURE_GENERATOR1), getRandomGenerator()));
}
return result;
@ -727,23 +727,10 @@ CGameState::~CGameState()
ptr.second.dellNull();
}
BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town)
{
const TerrainTile &t = map->getTile(tile);
ETerrainType terrain = t.terType;
if(map->isCoastalTile(tile)) //coastal tile is always ground
terrain = ETerrainType::SAND;
BFieldType terType = battleGetBattlefieldType(tile);
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)
terType = BFieldType::SHIP_TO_SHIP;
return BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
}
void CGameState::init(StartInfo * si)
{
logGlobal->infoStream() << "\tUsing random seed: "<< si->seedToBeUsed;
rand.setSeed(si->seedToBeUsed);
getRandomGenerator().setSeed(si->seedToBeUsed);
scenarioOps = CMemorySerializer::deepCopy(*si).release();
initialOpts = CMemorySerializer::deepCopy(*si).release();
si = nullptr;
@ -800,7 +787,7 @@ void CGameState::init(StartInfo * si)
logGlobal->debug("\tChecking objectives");
map->checkForObjectives(); //needs to be run when all objects are properly placed
auto seedAfterInit = rand.nextInt();
auto seedAfterInit = getRandomGenerator().nextInt();
logGlobal->infoStream() << "Seed after init is " << seedAfterInit << " (before was " << scenarioOps->seedToBeUsed << ")";
if(scenarioOps->seedPostInit > 0)
{
@ -925,8 +912,8 @@ void CGameState::initDuel()
for(TSecSKill secSkill : ss.heroSecSkills)
h->setSecSkillLevel(SecondarySkill(secSkill.first), secSkill.second, 1);
h->initHero(HeroTypeID(h->subID));
obj->initObj();
h->initHero(getRandomGenerator(), HeroTypeID(h->subID));
obj->initObj(getRandomGenerator());
}
else
{
@ -1026,7 +1013,7 @@ void CGameState::initGrailPosition()
if(!allowedPos.empty())
{
map->grailPos = *RandomGeneratorUtil::nextItem(allowedPos, rand);
map->grailPos = *RandomGeneratorUtil::nextItem(allowedPos, getRandomGenerator());
}
else
{
@ -1042,7 +1029,7 @@ void CGameState::initRandomFactionsForPlayers()
{
if(elem.second.castle==-1)
{
auto randomID = rand.nextInt(map->players[elem.first.getNum()].allowedFactions.size() - 1);
auto randomID = getRandomGenerator().nextInt(map->players[elem.first.getNum()].allowedFactions.size() - 1);
auto iter = map->players[elem.first.getNum()].allowedFactions.begin();
std::advance(iter, randomID);
@ -1171,7 +1158,7 @@ void CGameState::placeCampaignHeroes()
auto unusedHeroTypeIds = getUnusedAllowedHeroes();
if(!unusedHeroTypeIds.empty())
{
heroTypeId = (*RandomGeneratorUtil::nextItem(unusedHeroTypeIds, rand)).getNum();
heroTypeId = (*RandomGeneratorUtil::nextItem(unusedHeroTypeIds, getRandomGenerator())).getNum();
}
else
{
@ -1252,7 +1239,7 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar
return crossoverHeroes;
}
void CGameState::prepareCrossoverHeroes(std::vector<CGameState::CampaignHeroReplacement> & campaignHeroReplacements, const CScenarioTravel & travelOptions) const
void CGameState::prepareCrossoverHeroes(std::vector<CGameState::CampaignHeroReplacement> & campaignHeroReplacements, const CScenarioTravel & travelOptions)
{
// create heroes list for convenience iterating
std::vector<CGHeroInstance *> crossoverHeroes;
@ -1268,7 +1255,7 @@ void CGameState::prepareCrossoverHeroes(std::vector<CGameState::CampaignHeroRepl
//trimming experience
for(CGHeroInstance * cgh : crossoverHeroes)
{
cgh->initExp();
cgh->initExp(getRandomGenerator());
}
}
@ -1475,7 +1462,7 @@ void CGameState::initHeroes()
continue;
}
hero->initHero();
hero->initHero(getRandomGenerator());
getPlayer(hero->getOwner())->heroes.push_back(hero);
map->allHeroes[hero->type->ID.getNum()] = hero;
}
@ -1491,7 +1478,7 @@ void CGameState::initHeroes()
{
if(!vstd::contains(heroesToCreate, HeroTypeID(ph->subID)))
continue;
ph->initHero();
ph->initHero(getRandomGenerator());
hpool.heroesPool[ph->subID] = ph;
hpool.pavailable[ph->subID] = 0xff;
heroesToCreate.erase(ph->type->ID);
@ -1502,7 +1489,7 @@ void CGameState::initHeroes()
for(HeroTypeID htype : heroesToCreate) //all not used allowed heroes go with default state into the pool
{
auto vhi = new CGHeroInstance();
vhi->initHero(htype);
vhi->initHero(getRandomGenerator(), htype);
int typeID = htype.getNum();
map->allHeroes[typeID] = vhi;
@ -1660,24 +1647,24 @@ void CGameState::initStartingBonus()
{
//starting bonus
if(scenarioOps->playerInfos[elem.first].bonus==PlayerSettings::RANDOM)
scenarioOps->playerInfos[elem.first].bonus = static_cast<PlayerSettings::Ebonus>(rand.nextInt(2));
scenarioOps->playerInfos[elem.first].bonus = static_cast<PlayerSettings::Ebonus>(getRandomGenerator().nextInt(2));
switch(scenarioOps->playerInfos[elem.first].bonus)
{
case PlayerSettings::GOLD:
elem.second.resources[Res::GOLD] += rand.nextInt(5, 10) * 100;
elem.second.resources[Res::GOLD] += getRandomGenerator().nextInt(5, 10) * 100;
break;
case PlayerSettings::RESOURCE:
{
int res = VLC->townh->factions[scenarioOps->playerInfos[elem.first].castle]->town->primaryRes;
if(res == Res::WOOD_AND_ORE)
{
int amount = rand.nextInt(5, 10);
int amount = getRandomGenerator().nextInt(5, 10);
elem.second.resources[Res::WOOD] += amount;
elem.second.resources[Res::ORE] += amount;
}
else
{
elem.second.resources[res] += rand.nextInt(3, 6);
elem.second.resources[res] += getRandomGenerator().nextInt(3, 6);
}
break;
}
@ -1689,7 +1676,7 @@ void CGameState::initStartingBonus()
break;
}
CArtifact *toGive;
toGive = VLC->arth->artifacts[VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE)];
toGive = VLC->arth->artifacts[VLC->arth->pickRandomArtifact(getRandomGenerator(), CArtifact::ART_TREASURE)];
CGHeroInstance *hero = elem.second.heroes[0];
giveHeroArtifact(hero, toGive->id);
@ -1742,7 +1729,7 @@ void CGameState::initTowns()
}
if(vti->name.empty())
{
vti->name = *RandomGeneratorUtil::nextItem(vti->town->names, rand);
vti->name = *RandomGeneratorUtil::nextItem(vti->town->names, getRandomGenerator());
}
//init buildings
@ -1754,7 +1741,7 @@ void CGameState::initTowns()
vti->builtBuildings.insert(BuildingID::TAVERN);
vti->builtBuildings.insert(BuildingID::DWELL_FIRST);
if(rand.nextInt(1) == 1)
if(getRandomGenerator().nextInt(1) == 1)
{
vti->builtBuildings.insert(BuildingID::DWELL_LVL_2);
}
@ -1826,7 +1813,7 @@ void CGameState::initTowns()
if (total == 0) // remaining spells have 0 probability
break;
auto r = rand.nextInt(total - 1);
auto r = getRandomGenerator().nextInt(total - 1);
for(ui32 ps=0; ps<vti->possibleSpells.size();ps++)
{
r -= vti->possibleSpells[ps].toSpell()->getProbability(vti->subID);
@ -1859,7 +1846,7 @@ void CGameState::initMapObjects()
if(obj)
{
logGlobal->traceStream() << boost::format ("Calling Init for object %d, %s, %s") % obj->id.getNum() % obj->typeName % obj->subTypeName;
obj->initObj();
obj->initObj(getRandomGenerator());
}
}
for(CGObjectInstance *obj : map->objects)
@ -1919,7 +1906,7 @@ void CGameState::initVisitingAndGarrisonedHeroes()
}
}
BFieldType CGameState::battleGetBattlefieldType(int3 tile)
BFieldType CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & rand)
{
if(tile==int3() && curB)
tile = curB->tile;
@ -3263,9 +3250,12 @@ TeamState::TeamState(TeamState && other):
std::swap(fogOfWarMap, other.fogOfWarMap);
}
CRandomGenerator & CGameState::getRandomGenerator()
{
//if(scenarioOps && scenarioOps->seedPostInit)
//{
// logGlobal->trace("CGameState::getRandomGenerator used after initialization!");
//}
//logGlobal->traceStream() << "Fetching CGameState::rand with seed " << rand.nextInt();
return rand;
}

View File

@ -218,7 +218,7 @@ public:
void giveHeroArtifact(CGHeroInstance *h, ArtifactID aid);
void apply(CPack *pack);
BFieldType battleGetBattlefieldType(int3 tile);
BFieldType battleGetBattlefieldType(int3 tile, CRandomGenerator & rand);
UpgradeInfo getUpgradeInfo(const CStackInstance &stack);
PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2);
bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
@ -236,7 +236,6 @@ public:
void obtainPlayersStats(SThievesGuildInfo & tgi, int level); //fills tgi with info about other players that is available at given level of thieves' guild
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > unusedHeroesFromPool(); //heroes pool without heroes that are available in taverns
BattleInfo * setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town);
bool isVisible(int3 pos, PlayerColor player);
bool isVisible(const CGObjectInstance *obj, boost::optional<PlayerColor> player);
@ -244,6 +243,14 @@ public:
int getDate(Date::EDateType mode=Date::DAY) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
// ----- getters, setters -----
/// This RNG should only be used inside GS or CPackForClient-derived applyGs
/// If this doesn't work for your code that mean you need a new netpack
///
/// Client-side must use CRandomGenerator::getDefault which is not serialized
///
/// CGameHandler have it's own getter for CRandomGenerator::getDefault
/// Any server-side code outside of GH must use CRandomGenerator::getDefault
CRandomGenerator & getRandomGenerator();
template <typename Handler> void serialize(Handler &h, const int version)
@ -292,7 +299,7 @@ private:
std::vector<CampaignHeroReplacement> generateCampaignHeroesToReplace(CrossoverHeroesList & crossoverHeroes);
/// gets prepared and copied hero instances with crossover heroes from prev. scenario and travel options from current scenario
void prepareCrossoverHeroes(std::vector<CampaignHeroReplacement> & campaignHeroReplacements, const CScenarioTravel & travelOptions) const;
void prepareCrossoverHeroes(std::vector<CampaignHeroReplacement> & campaignHeroReplacements, const CScenarioTravel & travelOptions);
void replaceHeroesPlaceholders(const std::vector<CampaignHeroReplacement> & campaignHeroReplacements);
void placeStartingHeroes();

View File

@ -27,7 +27,7 @@
#include "mapping/CCampaignHandler.h" //for CCampaignState
#include "rmg/CMapGenerator.h" // for CMapGenOptions
const ui32 version = 760;
const ui32 version = 761;
const ui32 minSupportedVersion = 753;
class CISer;

View File

@ -119,14 +119,14 @@ void CPrivilagedInfoCallback::getAllTiles (std::unordered_set<int3, ShashInt3> &
}
}
void CPrivilagedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact*> &out)
void CPrivilagedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact*> &out, CRandomGenerator & rand)
{
for (int j = 0; j < 3 ; j++)
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_TREASURE)]);
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE)]);
for (int j = 0; j < 3 ; j++)
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_MINOR)]);
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MINOR)]);
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_MAJOR)]);
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MAJOR)]);
}
void CPrivilagedInfoCallback::getAllowedSpells(std::vector<SpellID> &out, ui16 level)

View File

@ -1,6 +1,7 @@
#pragma once
#include "CGameInfoCallback.h" // for CGameInfoCallback
#include "CRandomGenerator.h"
/*
* IGameCallback.h, part of VCMI engine
@ -32,7 +33,7 @@ public:
void getFreeTiles (std::vector<int3> &tiles) const; //used for random spawns
void getTilesInRange(std::unordered_set<int3, ShashInt3> &tiles, int3 pos, int radious, boost::optional<PlayerColor> player = boost::optional<PlayerColor>(), int mode = 0, bool patrolDistance = false) const; //mode 1 - only unrevealed tiles; mode 0 - all, mode -1 - only unrevealed
void getAllTiles (std::unordered_set<int3, ShashInt3> &tiles, boost::optional<PlayerColor> player = boost::optional<PlayerColor>(), int level=-1, int surface=0) const; //returns all tiles on given level (-1 - both levels, otherwise number of level); surface: 0 - land and water, 1 - only land, 2 - only water
void pickAllowedArtsSet(std::vector<const CArtifact*> &out); //gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant
void pickAllowedArtsSet(std::vector<const CArtifact*> &out, CRandomGenerator & rand); //gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant
void getAllowedSpells(std::vector<SpellID> &out, ui16 level);
template<typename Saver>

View File

@ -1093,6 +1093,23 @@ struct ChangeObjectVisitors : public CPackForClient // 1003
}
};
struct PrepareHeroLevelUp : public CPackForClient//1999
{
DLL_LINKAGE void applyGs(CGameState *gs);
const CGHeroInstance *hero;
/// Do not serialize, used by server only
std::vector<SecondarySkill> skills;
PrepareHeroLevelUp(){type = 1999;};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & hero;
}
};
struct HeroLevelUp : public Query//2000
{
void applyCl(CClient *cl);

View File

@ -624,7 +624,7 @@ DLL_LINKAGE void HeroRecruited::applyGs( CGameState *gs )
h->attachTo(p);
if(fresh)
{
h->initObj();
h->initObj(gs->getRandomGenerator());
}
gs->map->addBlockVisTiles(h);
@ -689,7 +689,7 @@ DLL_LINKAGE void NewObject::applyGs( CGameState *gs )
gs->map->objects.push_back(o);
gs->map->addBlockVisTiles(o);
o->initObj();
o->initObj(gs->getRandomGenerator());
gs->map->calculateGuardingGreaturePositions();
logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getObjectName();
@ -1162,6 +1162,21 @@ DLL_LINKAGE void SetObjectProperty::applyGs( CGameState *gs )
}
}
DLL_LINKAGE void PrepareHeroLevelUp::applyGs(CGameState *gs)
{
CGHeroInstance * h = gs->getHero(hero->id);
auto proposedSkills = h->getLevelUpProposedSecondarySkills();
if(skills.size() == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
{
skills.push_back(*RandomGeneratorUtil::nextItem(proposedSkills, h->skillsInfo.rand));
}
else
{
skills = proposedSkills;
}
}
DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
{
CGHeroInstance * h = gs->getHero(hero->id);

View File

@ -34,11 +34,11 @@ CBank::~CBank()
{
}
void CBank::initObj()
void CBank::initObj(CRandomGenerator & rand)
{
daycounter = 0;
resetDuration = 0;
VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, cb->gameState()->getRandomGenerator());
VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
}
std::string CBank::getHoverText(PlayerColor player) const
@ -64,7 +64,8 @@ void CBank::setPropertyDer (ui8 what, ui32 val)
daycounter+=val;
break;
case ObjProperty::BANK_RESET:
initObj();
// FIXME: Object reset must be done by separate netpack from server
initObj(cb->gameState()->getRandomGenerator());
daycounter = 1; //yes, 1 since "today" daycounter won't be incremented
break;
case ObjProperty::BANK_CLEAR:
@ -73,7 +74,7 @@ void CBank::setPropertyDer (ui8 what, ui32 val)
}
}
void CBank::newTurn() const
void CBank::newTurn(CRandomGenerator & rand) const
{
if (bc == nullptr)
{

View File

@ -31,9 +31,9 @@ public:
void setConfig(const BankConfig & bc);
void initObj() override;
void initObj(CRandomGenerator & rand) override;
std::string getHoverText(PlayerColor player) const override;
void newTurn() const override;
void newTurn(CRandomGenerator & rand) const override;
bool wasVisited (PlayerColor player) const override;
void onHeroVisit(const CGHeroInstance * h) const override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;

View File

@ -244,10 +244,10 @@ CGHeroInstance::CGHeroInstance()
secSkills.push_back(std::make_pair(SecondarySkill::DEFAULT, -1));
}
void CGHeroInstance::initHero(HeroTypeID SUBID)
void CGHeroInstance::initHero(CRandomGenerator & rand, HeroTypeID SUBID)
{
subID = SUBID.getNum();
initHero();
initHero(rand);
}
void CGHeroInstance::setType(si32 ID, si32 subID)
@ -259,7 +259,7 @@ void CGHeroInstance::setType(si32 ID, si32 subID)
randomizeArmy(type->heroClass->faction);
}
void CGHeroInstance::initHero()
void CGHeroInstance::initHero(CRandomGenerator & rand)
{
assert(validTypes(true));
if(!type)
@ -302,17 +302,17 @@ void CGHeroInstance::initHero()
setFormation(false);
if (!stacksCount()) //standard army//initial army
{
initArmy();
initArmy(rand);
}
assert(validTypes());
if(exp == 0xffffffff)
{
initExp();
initExp(rand);
}
else
{
levelUpAutomatically();
levelUpAutomatically(rand);
}
if (VLC->modh->modules.COMMANDERS && !commander)
@ -326,13 +326,13 @@ void CGHeroInstance::initHero()
mana = manaLimit();
}
void CGHeroInstance::initArmy(IArmyDescriptor *dst /*= nullptr*/)
void CGHeroInstance::initArmy(CRandomGenerator & rand, IArmyDescriptor *dst /*= nullptr*/)
{
if(!dst)
dst = this;
int howManyStacks = 0; //how many stacks will hero receives <1 - 3>
int pom = cb->gameState()->getRandomGenerator().nextInt(99);
int pom = rand.nextInt(99);
int warMachinesGiven = 0;
if(pom < 9)
@ -348,7 +348,7 @@ void CGHeroInstance::initArmy(IArmyDescriptor *dst /*= nullptr*/)
{
auto & stack = type->initialArmy[stackNo];
int count = cb->gameState()->getRandomGenerator().nextInt(stack.minAmount, stack.maxAmount);
int count = rand.nextInt(stack.minAmount, stack.maxAmount);
if(stack.creature >= CreatureID::CATAPULT &&
stack.creature <= CreatureID::ARROW_TOWERS) //war machine
@ -483,7 +483,7 @@ void CGHeroInstance::SecondarySkillsInfo::resetWisdomCounter()
wisdomCounter = 1;
}
void CGHeroInstance::initObj()
void CGHeroInstance::initObj(CRandomGenerator & rand)
{
blockVisit = true;
auto hs = new HeroSpecial();
@ -491,9 +491,9 @@ void CGHeroInstance::initObj()
attachTo(hs); //do we ever need to detach it?
if(!type)
initHero(); //TODO: set up everything for prison before specialties are configured
initHero(rand); //TODO: set up everything for prison before specialties are configured
skillsInfo.rand.setSeed(cb->gameState()->getRandomGenerator().nextInt());
skillsInfo.rand.setSeed(rand.nextInt());
skillsInfo.resetMagicSchoolCounter();
skillsInfo.resetWisdomCounter();
@ -1063,10 +1063,10 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
* @param raisedStack Pair where the first element represents ID of the raised creature
* and the second element the amount.
*/
void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const
void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedStack, CRandomGenerator & rand) const
{
InfoWindow iw;
iw.soundID = soundBase::pickup01 + cb->gameState()->getRandomGenerator().nextInt(6);
iw.soundID = soundBase::pickup01 + rand.nextInt(6);
iw.player = tempOwner;
iw.components.push_back(Component(raisedStack));
@ -1169,9 +1169,9 @@ EAlignment::EAlignment CGHeroInstance::getAlignment() const
return type->heroClass->getAlignment();
}
void CGHeroInstance::initExp()
void CGHeroInstance::initExp(CRandomGenerator & rand)
{
exp = cb->gameState()->getRandomGenerator().nextInt(40, 89);
exp = rand.nextInt(40, 89);
}
std::string CGHeroInstance::nodeName() const
@ -1344,10 +1344,10 @@ std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills()
return skills;
}
PrimarySkill::PrimarySkill CGHeroInstance::nextPrimarySkill() const
PrimarySkill::PrimarySkill CGHeroInstance::nextPrimarySkill(CRandomGenerator & rand) const
{
assert(gainsLevel());
int randomValue = cb->gameState()->getRandomGenerator().nextInt(99), pom = 0, primarySkill = 0;
int randomValue = rand.nextInt(99), pom = 0, primarySkill = 0;
const auto & skillChances = (level > 9) ? type->heroClass->primarySkillLowLevel : type->heroClass->primarySkillHighLevel;
for(; primarySkill < GameConstants::PRIMARY_SKILLS; ++primarySkill)
@ -1363,7 +1363,7 @@ PrimarySkill::PrimarySkill CGHeroInstance::nextPrimarySkill() const
return static_cast<PrimarySkill::PrimarySkill>(primarySkill);
}
boost::optional<SecondarySkill> CGHeroInstance::nextSecondarySkill() const
boost::optional<SecondarySkill> CGHeroInstance::nextSecondarySkill(CRandomGenerator & rand) const
{
assert(gainsLevel());
@ -1380,7 +1380,6 @@ boost::optional<SecondarySkill> CGHeroInstance::nextSecondarySkill() const
}
}
auto & rand = cb->gameState()->getRandomGenerator();
if(learnedSecondarySkills.empty())
{
// there are only new skills to learn, so choose anyone of them
@ -1459,16 +1458,16 @@ void CGHeroInstance::levelUp(std::vector<SecondarySkill> skills)
Updatespecialty();
}
void CGHeroInstance::levelUpAutomatically()
void CGHeroInstance::levelUpAutomatically(CRandomGenerator & rand)
{
while(gainsLevel())
{
const auto primarySkill = nextPrimarySkill();
const auto primarySkill = nextPrimarySkill(rand);
setPrimarySkill(primarySkill, 1, false);
auto proposedSecondarySkills = getLevelUpProposedSecondarySkills();
const auto secondarySkill = nextSecondarySkill();
const auto secondarySkill = nextSecondarySkill(rand);
if(secondarySkill)
{
setSecSkillLevel(*secondarySkill, 1, false);

View File

@ -163,10 +163,10 @@ public:
bool gainsLevel() const;
/// Returns the next primary skill on level up. Can only be called if hero can gain a level up.
PrimarySkill::PrimarySkill nextPrimarySkill() const;
PrimarySkill::PrimarySkill nextPrimarySkill(CRandomGenerator & rand) const;
/// Returns the next secondary skill randomly on level up. Can only be called if hero can gain a level up.
boost::optional<SecondarySkill> nextSecondarySkill() const;
boost::optional<SecondarySkill> nextSecondarySkill(CRandomGenerator & rand) const;
/// Gets 0, 1 or 2 secondary skills which are proposed on hero level up.
std::vector<SecondarySkill> getLevelUpProposedSecondarySkills() const;
@ -192,20 +192,20 @@ public:
bool canCastThisSpell(const CSpell * spell) const; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack, CRandomGenerator & rand) const;
EDiggingStatus diggingStatus() const;
//////////////////////////////////////////////////////////////////////////
void setType(si32 ID, si32 subID) override;
void initHero();
void initHero(HeroTypeID SUBID);
void initHero(CRandomGenerator & rand);
void initHero(CRandomGenerator & rand, HeroTypeID SUBID);
void putArtifact(ArtifactPosition pos, CArtifactInstance *art);
void putInBackpack(CArtifactInstance *art);
void initExp();
void initArmy(IArmyDescriptor *dst = nullptr);
void initExp(CRandomGenerator & rand);
void initArmy(CRandomGenerator & rand, IArmyDescriptor *dst = nullptr);
//void giveArtifact (ui32 aid);
void pushPrimSkill(PrimarySkill::PrimarySkill which, int val);
ui8 maxlevelsToMagicSchool() const;
@ -250,7 +250,7 @@ public:
void deserializationFix();
void initObj() override;
void initObj(CRandomGenerator & rand) override;
void onHeroVisit(const CGHeroInstance * h) const override;
std::string getObjectName() const override;
protected:
@ -258,7 +258,7 @@ protected:
void serializeJsonOptions(JsonSerializeFormat & handler) override;
private:
void levelUpAutomatically();
void levelUpAutomatically(CRandomGenerator & rand);
public:
template <typename Handler> void serialize(Handler &h, const int version)

View File

@ -282,18 +282,18 @@ std::vector<int> CGBlackMarket::availableItemsIds(EMarketMode::EMarketMode mode)
}
}
void CGBlackMarket::newTurn() const
void CGBlackMarket::newTurn(CRandomGenerator & rand) const
{
if(cb->getDate(Date::DAY_OF_MONTH) != 1) //new month
return;
SetAvailableArtifacts saa;
saa.id = id.getNum();
cb->pickAllowedArtsSet(saa.arts);
cb->pickAllowedArtsSet(saa.arts, rand);
cb->sendAndApply(&saa);
}
void CGUniversity::initObj()
void CGUniversity::initObj(CRandomGenerator & rand)
{
std::vector<int> toChoose;
for(int i = 0; i < GameConstants::SKILL_QUANTITY; ++i)
@ -313,7 +313,7 @@ void CGUniversity::initObj()
for(int i = 0; i < 4; ++i)
{
// move randomly one skill to selected and remove from list
auto it = RandomGeneratorUtil::nextItem(toChoose, cb->gameState()->getRandomGenerator());
auto it = RandomGeneratorUtil::nextItem(toChoose, rand);
skills.push_back(*it);
toChoose.erase(it);
}

View File

@ -61,7 +61,7 @@ class DLL_LINKAGE CGBlackMarket : public CGMarket
public:
std::vector<const CArtifact *> artifacts; //available artifacts
void newTurn() const override; //reset artifacts for black market every month
void newTurn(CRandomGenerator & rand) const override; //reset artifacts for black market every month
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override;
template <typename Handler> void serialize(Handler &h, const int version)
@ -77,7 +77,7 @@ public:
std::vector<int> skills; //available skills
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override;
void initObj() override;//set skills for trade
void initObj(CRandomGenerator & rand) override;//set skills for trade
void onHeroVisit(const CGHeroInstance * h) const override; //open window
template <typename Handler> void serialize(Handler &h, const int version)

View File

@ -34,7 +34,7 @@ static void showInfoDialog(const CGHeroInstance* h, const ui32 txtID, const ui16
showInfoDialog(playerID,txtID,soundID);
}
void CGPandoraBox::initObj()
void CGPandoraBox::initObj(CRandomGenerator & rand)
{
blockVisit = (ID==Obj::PANDORAS_BOX); //block only if it's really pandora's box (events also derive from that class)
hasGuardians = stacks.size();

View File

@ -36,7 +36,7 @@ public:
CCreatureSet creatures; //gained creatures
CGPandoraBox() : gainedExp(0), manaDiff(0), moraleDiff(0), luckDiff(0){};
void initObj() override;
void initObj(CRandomGenerator & rand) override;
void onHeroVisit(const CGHeroInstance * h) const override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;

View File

@ -25,14 +25,14 @@
std::vector<const CArtifact *> CGTownInstance::merchantArtifacts;
std::vector<int> CGTownInstance::universitySkills;
void CGDwelling::initObj()
void CGDwelling::initObj(CRandomGenerator & rand)
{
switch(ID)
{
case Obj::CREATURE_GENERATOR1:
case Obj::CREATURE_GENERATOR4:
{
VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, cb->gameState()->getRandomGenerator());
VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
if (getOwner() != PlayerColor::NEUTRAL)
cb->gameState()->players[getOwner()].dwellings.push_back (this);
@ -141,7 +141,7 @@ void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
cb->showBlockingDialog(&bd);
}
void CGDwelling::newTurn() const
void CGDwelling::newTurn(CRandomGenerator & rand) const
{
if(cb->getDate(Date::DAY_OF_WEEK) != 1) //not first day of week
return;
@ -152,7 +152,7 @@ void CGDwelling::newTurn() const
if(ID == Obj::REFUGEE_CAMP) //if it's a refugee camp, we need to pick an available creature
{
cb->setObjProperty(id, ObjProperty::AVAILABLE_CREATURE, VLC->creh->pickRandomMonster(cb->gameState()->getRandomGenerator()));
cb->setObjProperty(id, ObjProperty::AVAILABLE_CREATURE, VLC->creh->pickRandomMonster(rand));
}
bool change = false;
@ -595,7 +595,7 @@ std::string CGTownInstance::getObjectName() const
return name + ", " + town->faction->name;
}
void CGTownInstance::initObj()
void CGTownInstance::initObj(CRandomGenerator & rand)
///initialize town structures
{
blockVisit = true;
@ -637,12 +637,10 @@ void CGTownInstance::initObj()
updateAppearance();
}
void CGTownInstance::newTurn() const
void CGTownInstance::newTurn(CRandomGenerator & rand) const
{
if (cb->getDate(Date::DAY_OF_WEEK) == 1) //reset on new week
{
auto & rand = cb->gameState()->getRandomGenerator();
//give resources for Rampart, Mystic Pond
if (hasBuilt(BuildingID::MYSTIC_POND, ETownType::RAMPART)
&& cb->getDate(Date::DAY) != 1 && (tempOwner < PlayerColor::PLAYER_LIMIT))

View File

@ -56,9 +56,9 @@ protected:
void serializeJsonOptions(JsonSerializeFormat & handler) override;
private:
void initObj() override;
void initObj(CRandomGenerator & rand) override;
void onHeroVisit(const CGHeroInstance * h) const override;
void newTurn() const override;
void newTurn(CRandomGenerator & rand) const override;
void setPropertyDer(ui8 what, ui32 val) override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
@ -249,10 +249,10 @@ public:
virtual ~CGTownInstance();
///IObjectInterface overrides
void newTurn() const override;
void newTurn(CRandomGenerator & rand) const override;
void onHeroVisit(const CGHeroInstance * h) const override;
void onHeroLeave(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
std::string getObjectName() const override;
protected:

View File

@ -66,7 +66,7 @@ void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const
void IObjectInterface::onHeroLeave(const CGHeroInstance * h) const
{}
void IObjectInterface::newTurn () const
void IObjectInterface::newTurn(CRandomGenerator & rand) const
{}
IObjectInterface::~IObjectInterface()
@ -75,7 +75,7 @@ IObjectInterface::~IObjectInterface()
IObjectInterface::IObjectInterface()
{}
void IObjectInterface::initObj()
void IObjectInterface::initObj(CRandomGenerator & rand)
{}
void IObjectInterface::setProperty( ui8 what, ui32 val )
@ -207,7 +207,7 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
cb->gameState()->map->addBlockVisTiles(this);
}
void CGObjectInstance::initObj()
void CGObjectInstance::initObj(CRandomGenerator & rand)
{
switch(ID)
{

View File

@ -22,6 +22,7 @@ class CGObjectInstance;
struct MetaString;
struct BattleResult;
class JsonSerializeFormat;
class CRandomGenerator;
// This one teleport-specific, but has to be available everywhere in callbacks and netpacks
// For now it's will be there till teleports code refactored and moved into own file
@ -37,8 +38,8 @@ public:
virtual void onHeroVisit(const CGHeroInstance * h) const;
virtual void onHeroLeave(const CGHeroInstance * h) const;
virtual void newTurn() const;
virtual void initObj(); //synchr
virtual void newTurn(CRandomGenerator & rand) const;
virtual void initObj(CRandomGenerator & rand); //synchr
virtual void setProperty(ui8 what, ui32 val);//synchr
//Called when queries created DURING HERO VISIT are resolved
@ -166,7 +167,7 @@ public:
/** OVERRIDES OF IObjectInterface **/
void initObj() override;
void initObj(CRandomGenerator & rand) override;
void onHeroVisit(const CGHeroInstance * h) const override;
/// method for synchronous update. Note: For new properties classes should override setPropertyDer instead
void setProperty(ui8 what, ui32 val) override final;

View File

@ -420,16 +420,16 @@ void CGSeerHut::setObjToKill()
}
}
void CGSeerHut::init()
void CGSeerHut::init(CRandomGenerator & rand)
{
seerName = *RandomGeneratorUtil::nextItem(VLC->generaltexth->seerNames, cb->gameState()->getRandomGenerator());
quest->textOption = cb->gameState()->getRandomGenerator().nextInt(2);
quest->completedOption = cb->gameState()->getRandomGenerator().nextInt(1, 3);
seerName = *RandomGeneratorUtil::nextItem(VLC->generaltexth->seerNames, rand);
quest->textOption = rand.nextInt(2);
quest->completedOption = rand.nextInt(1, 3);
}
void CGSeerHut::initObj()
void CGSeerHut::initObj(CRandomGenerator & rand)
{
init();
init(rand);
quest->progress = CQuest::NOT_ACTIVE;
if(quest->missionType)
@ -549,7 +549,7 @@ void CGSeerHut::setPropertyDer (ui8 what, ui32 val)
}
}
void CGSeerHut::newTurn() const
void CGSeerHut::newTurn(CRandomGenerator & rand) const
{
if(quest->lastDay >= 0 && quest->lastDay <= cb->getDate() - 1) //time is up
{
@ -761,11 +761,11 @@ void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer)
finishQuest(hero, answer);
}
void CGQuestGuard::init()
void CGQuestGuard::init(CRandomGenerator & rand)
{
blockVisit = true;
quest->textOption = cb->gameState()->getRandomGenerator().nextInt(3, 5);
quest->completedOption = cb->gameState()->getRandomGenerator().nextInt(4, 5);
quest->textOption = rand.nextInt(3, 5);
quest->completedOption = rand.nextInt(4, 5);
}
void CGQuestGuard::completeQuest(const CGHeroInstance *h) const
@ -825,7 +825,7 @@ void CGKeymasterTent::onHeroVisit( const CGHeroInstance * h ) const
showInfoDialog(h,txt_id,soundBase::CAVEHEAD);
}
void CGBorderGuard::initObj()
void CGBorderGuard::initObj(CRandomGenerator & rand)
{
//ui32 m13489val = subID; //store color as quest info
blockVisit = true;

View File

@ -108,13 +108,13 @@ public:
std::string seerName;
CGSeerHut();
void initObj() override;
void initObj(CRandomGenerator & rand) override;
std::string getHoverText(PlayerColor player) const override;
void newTurn() const override;
void newTurn(CRandomGenerator & rand) const override;
void onHeroVisit(const CGHeroInstance * h) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
virtual void init();
virtual void init(CRandomGenerator & rand);
int checkDirection() const; //calculates the region of map where monster is placed
void setObjToKill(); //remember creatures / heroes to kill after they are initialized
const CGHeroInstance *getHeroToKill(bool allowNull = false) const;
@ -139,7 +139,7 @@ class DLL_LINKAGE CGQuestGuard : public CGSeerHut
{
public:
CGQuestGuard() : CGSeerHut(){};
void init() override;
void init(CRandomGenerator & rand) override;
void completeQuest (const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
@ -185,7 +185,7 @@ class DLL_LINKAGE CGBorderGuard : public CGKeys, public IQuestObject
{
public:
CGBorderGuard() : IQuestObject(){};
void initObj() override;
void initObj(CRandomGenerator & rand) override;
void onHeroVisit(const CGHeroInstance * h) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;

View File

@ -158,7 +158,7 @@ void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const
grantRewardWithMessage(rewards[0]);
break;
case SELECT_RANDOM: // select one randomly //TODO: use weights
grantRewardWithMessage(rewards[cb->gameState()->getRandomGenerator().nextInt(rewards.size()-1)]);
grantRewardWithMessage(rewards[CRandomGenerator::getDefault().nextInt(rewards.size()-1)]);
break;
}
return;
@ -431,7 +431,7 @@ void CRewardableObject::setPropertyDer(ui8 what, ui32 val)
}
}
void CRewardableObject::newTurn() const
void CRewardableObject::newTurn(CRandomGenerator & rand) const
{
if (resetDuration != 0 && cb->getDate(Date::DAY) > 1 && (cb->getDate(Date::DAY) % resetDuration) == 1)
cb->setObjProperty(id, ObjProperty::REWARD_RESET, 0);
@ -450,11 +450,11 @@ CRewardableObject::CRewardableObject():
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper, selects random art class based on weights
static int selectRandomArtClass(int treasure, int minor, int major, int relic)
static int selectRandomArtClass(CRandomGenerator & rand, int treasure, int minor, int major, int relic)
{
int total = treasure + minor + major + relic;
assert(total != 0);
int hlp = IObjectInterface::cb->gameState()->getRandomGenerator().nextInt(total - 1);
int hlp = rand.nextInt(total - 1);
if(hlp < treasure)
return CArtifact::ART_TREASURE;
@ -466,10 +466,10 @@ static int selectRandomArtClass(int treasure, int minor, int major, int relic)
}
/// Helper, adds random artifact to reward selecting class based on weights
static void loadRandomArtifact(CVisitInfo & info, int treasure, int minor, int major, int relic)
static void loadRandomArtifact(CRandomGenerator & rand, CVisitInfo & info, int treasure, int minor, int major, int relic)
{
int artClass = selectRandomArtClass(treasure, minor, major, relic);
ArtifactID artID = VLC->arth->pickRandomArtifact(IObjectInterface::cb->gameState()->getRandomGenerator(), artClass);
int artClass = selectRandomArtClass(rand, treasure, minor, major, relic);
ArtifactID artID = VLC->arth->pickRandomArtifact(rand, artClass);
info.reward.artifacts.push_back(artID);
}
@ -479,7 +479,7 @@ CGPickable::CGPickable()
selectMode = SELECT_PLAYER;
}
void CGPickable::initObj()
void CGPickable::initObj(CRandomGenerator & rand)
{
blockVisit = true;
switch(ID)
@ -487,8 +487,8 @@ void CGPickable::initObj()
case Obj::CAMPFIRE:
{
soundID = soundBase::experience;
int givenRes = cb->gameState()->getRandomGenerator().nextInt(5);
int givenAmm = cb->gameState()->getRandomGenerator().nextInt(4, 6);
int givenRes = rand.nextInt(5);
int givenAmm = rand.nextInt(4, 6);
info.resize(1);
info[0].reward.resources[givenRes] = givenAmm;
@ -499,7 +499,7 @@ void CGPickable::initObj()
}
case Obj::FLOTSAM:
{
int type = cb->gameState()->getRandomGenerator().nextInt(3);
int type = rand.nextInt(3);
soundID = soundBase::GENIE;
switch(type)
{
@ -540,7 +540,7 @@ void CGPickable::initObj()
case Obj::SEA_CHEST:
{
soundID = soundBase::chest;
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
int hlp = rand.nextInt(99);
if(hlp < 20)
{
info.resize(1);
@ -557,7 +557,7 @@ void CGPickable::initObj()
else
{
info.resize(1);
loadRandomArtifact(info[0], 100, 0, 0, 0);
loadRandomArtifact(rand, info[0], 100, 0, 0, 0);
info[0].reward.resources[Res::GOLD] = 1000;
info[0].message.addTxt(MetaString::ADVOB_TXT, 117);
info[0].message.addReplacement(MetaString::ART_NAMES, info[0].reward.artifacts.back());
@ -569,7 +569,7 @@ void CGPickable::initObj()
{
soundID = soundBase::experience;
info.resize(1);
loadRandomArtifact(info[0], 55, 20, 20, 5);
loadRandomArtifact(rand, info[0], 55, 20, 20, 5);
info[0].message.addTxt(MetaString::ADVOB_TXT, 125);
info[0].message.addReplacement(MetaString::ART_NAMES, info[0].reward.artifacts.back());
info[0].reward.removeObject = true;
@ -577,12 +577,12 @@ void CGPickable::initObj()
break;
case Obj::TREASURE_CHEST:
{
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
int hlp = rand.nextInt(99);
if(hlp >= 95)
{
soundID = soundBase::treasure;
info.resize(1);
loadRandomArtifact(info[0], 100, 0, 0, 0);
loadRandomArtifact(rand, info[0], 100, 0, 0, 0);
info[0].message.addTxt(MetaString::ADVOB_TXT,145);
info[0].message.addReplacement(MetaString::ART_NAMES, info[0].reward.artifacts.back());
info[0].reward.removeObject = true;
@ -631,7 +631,7 @@ CGBonusingObject::CGBonusingObject()
selectMode = SELECT_FIRST;
}
void CGBonusingObject::initObj()
void CGBonusingObject::initObj(CRandomGenerator & rand)
{
auto configureBonusDuration = [&](CVisitInfo & visit, Bonus::BonusDuration duration, Bonus::BonusType type, si32 value, si32 descrID)
{
@ -817,7 +817,7 @@ CGOnceVisitable::CGOnceVisitable()
selectMode = SELECT_FIRST;
}
void CGOnceVisitable::initObj()
void CGOnceVisitable::initObj(CRandomGenerator & rand)
{
switch(ID)
{
@ -826,10 +826,10 @@ void CGOnceVisitable::initObj()
onEmpty.addTxt(MetaString::ADVOB_TXT, 38);
soundID = soundBase::MYSTERY;
blockVisit = true;
if(cb->gameState()->getRandomGenerator().nextInt(99) < 20)
if(rand.nextInt(99) < 20)
{
info.resize(1);
loadRandomArtifact(info[0], 10, 10, 10, 0);
loadRandomArtifact(rand, info[0], 10, 10, 10, 0);
info[0].message.addTxt(MetaString::ADVOB_TXT, 37);
}
}
@ -839,8 +839,8 @@ void CGOnceVisitable::initObj()
soundID = soundBase::GENIE;
onEmpty.addTxt(MetaString::ADVOB_TXT, 65);
info.resize(1);
int type = cb->gameState()->getRandomGenerator().nextInt(5); //any basic resource without gold
int value = cb->gameState()->getRandomGenerator().nextInt(1, 4);
int type = rand.nextInt(5); //any basic resource without gold
int value = rand.nextInt(1, 4);
info[0].reward.resources[type] = value;
info[0].message.addTxt(MetaString::ADVOB_TXT, 64);
}
@ -851,7 +851,7 @@ void CGOnceVisitable::initObj()
onSelect.addTxt(MetaString::ADVOB_TXT, 161);
info.resize(2);
loadRandomArtifact(info[0], 30, 50, 25, 5);
loadRandomArtifact(rand, info[0], 30, 50, 25, 5);
Bonus bonus(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::OBJECT, -3, ID);
info[0].reward.bonuses.push_back(bonus);
@ -866,19 +866,19 @@ void CGOnceVisitable::initObj()
soundID = soundBase::GENIE;
onVisited.addTxt(MetaString::ADVOB_TXT, 156);
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
int hlp = rand.nextInt(99);
if(hlp < 40) //minor or treasure art
{
info.resize(1);
loadRandomArtifact(info[0], 10, 10, 0, 0);
loadRandomArtifact(rand, info[0], 10, 10, 0, 0);
info[0].message.addTxt(MetaString::ADVOB_TXT, 155);
}
else if(hlp < 90) //2 - 5 of non-gold resource
{
info.resize(1);
int type = cb->gameState()->getRandomGenerator().nextInt(5);
int value = cb->gameState()->getRandomGenerator().nextInt(2, 5);
int type = rand.nextInt(5);
int value = rand.nextInt(2, 5);
info[0].reward.resources[type] = value;
info[0].message.addTxt(MetaString::ADVOB_TXT, 154);
}
@ -896,7 +896,7 @@ CGVisitableOPH::CGVisitableOPH()
selectMode = SELECT_PLAYER;
}
void CGVisitableOPH::initObj()
void CGVisitableOPH::initObj(CRandomGenerator & rand)
{
switch(ID)
{
@ -951,7 +951,7 @@ void CGVisitableOPH::initObj()
info[0].reward.gainedLevels = 1;
onVisited.addTxt(MetaString::ADVOB_TXT, 147);
info.resize(1);
switch (cb->gameState()->getRandomGenerator().nextInt(2))
switch (rand.nextInt(2))
{
case 0: // free
onSelect.addTxt(MetaString::ADVOB_TXT, 148);
@ -1029,7 +1029,7 @@ CGVisitableOPW::CGVisitableOPW()
resetDuration = 7;
}
void CGVisitableOPW::initObj()
void CGVisitableOPW::initObj(CRandomGenerator & rand)
{
switch (ID)
{
@ -1087,7 +1087,7 @@ void CGVisitableOPW::setPropertyDer(ui8 what, ui32 val)
///////////////////////////////////////////////////////////////////////////////////////////////////
void CGMagicSpring::initObj()
void CGMagicSpring::initObj(CRandomGenerator & rand)
{
CVisitInfo visit; // TODO: "player above max mana" limiter. Use logical expressions for limiters?
visit.reward.manaPercentage = 200;

View File

@ -227,7 +227,7 @@ public:
void onHeroVisit(const CGHeroInstance *h) const override;
///possibly resets object state
void newTurn() const override;
void newTurn(CRandomGenerator & rand) const override;
/// gives second part of reward after hero level-ups for proper granting of spells/mana
void heroLevelUpDone(const CGHeroInstance *hero) const override;
@ -255,7 +255,7 @@ public:
class DLL_LINKAGE CGPickable : public CRewardableObject //campfire, treasure chest, Flotsam, Shipwreck Survivor, Sea Chest
{
public:
void initObj() override;
void initObj(CRandomGenerator & rand) override;
CGPickable();
@ -273,7 +273,7 @@ protected:
void grantReward(ui32 rewardID, const CGHeroInstance * hero) const override;
public:
void initObj() override;
void initObj(CRandomGenerator & rand) override;
CGBonusingObject();
@ -290,7 +290,7 @@ public:
class DLL_LINKAGE CGOnceVisitable : public CRewardableObject // wagon, corpse, lean to, warriors tomb
{
public:
void initObj() override;
void initObj(CRandomGenerator & rand) override;
CGOnceVisitable();
@ -303,7 +303,7 @@ public:
class DLL_LINKAGE CGVisitableOPH : public CRewardableObject //objects visitable only once per hero
{
public:
void initObj() override;
void initObj(CRandomGenerator & rand) override;
CGVisitableOPH();
@ -316,7 +316,7 @@ public:
class DLL_LINKAGE CGVisitableOPW : public CRewardableObject //objects visitable once per week
{
public:
void initObj() override;
void initObj(CRandomGenerator & rand) override;
CGVisitableOPW();
@ -335,7 +335,7 @@ protected:
std::vector<ui32> getAvailableRewards(const CGHeroInstance * hero) const override;
public:
void initObj() override;
void initObj(CRandomGenerator & rand) override;
std::vector<int3> getVisitableOffsets() const;
int3 getVisitableOffset() const override;

View File

@ -201,7 +201,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
}
void CGCreature::initObj()
void CGCreature::initObj(CRandomGenerator & rand)
{
blockVisit = true;
switch(character)
@ -210,13 +210,13 @@ void CGCreature::initObj()
character = -4;
break;
case 1:
character = cb->gameState()->getRandomGenerator().nextInt(1, 7);
character = rand.nextInt(1, 7);
break;
case 2:
character = cb->gameState()->getRandomGenerator().nextInt(1, 10);
character = rand.nextInt(1, 10);
break;
case 3:
character = cb->gameState()->getRandomGenerator().nextInt(4, 10);
character = rand.nextInt(4, 10);
break;
case 4:
character = 10;
@ -228,7 +228,7 @@ void CGCreature::initObj()
CCreature &c = *VLC->creh->creatures[subID];
if(amount == 0)
{
amount = cb->gameState()->getRandomGenerator().nextInt(c.ammMin, c.ammMax);
amount = rand.nextInt(c.ammMin, c.ammMax);
if(amount == 0) //armies with 0 creatures are illegal
{
@ -241,7 +241,7 @@ void CGCreature::initObj()
refusedJoining = false;
}
void CGCreature::newTurn() const
void CGCreature::newTurn(CRandomGenerator & rand) const
{//Works only for stacks of single type of size up to 2 millions
if (!notGrowingTeam)
{
@ -434,7 +434,7 @@ void CGCreature::fight( const CGHeroInstance *h ) const
const auto & upgrades = getStack(slotID).type->upgrades;
if(!upgrades.empty())
{
auto it = RandomGeneratorUtil::nextItem(upgrades, cb->gameState()->getRandomGenerator());
auto it = RandomGeneratorUtil::nextItem(upgrades, CRandomGenerator::getDefault());
cb->changeStackType(StackLocation(this, slotID), VLC->creh->creatures[*it]);
}
}
@ -676,7 +676,7 @@ void CGMine::onHeroVisit( const CGHeroInstance * h ) const
}
void CGMine::newTurn() const
void CGMine::newTurn(CRandomGenerator & rand) const
{
if(cb->getDate() == 1)
return;
@ -687,12 +687,12 @@ void CGMine::newTurn() const
cb->giveResource(tempOwner, producedResource, producedQuantity);
}
void CGMine::initObj()
void CGMine::initObj(CRandomGenerator & rand)
{
if(isAbandoned())
{
//set guardians
int howManyTroglodytes = cb->gameState()->getRandomGenerator().nextInt(100, 199);
int howManyTroglodytes = rand.nextInt(100, 199);
auto troglodytes = new CStackInstance(CreatureID::TROGLODYTES, howManyTroglodytes);
putStack(SlotID(0), troglodytes);
@ -703,7 +703,7 @@ void CGMine::initObj()
possibleResources.push_back(static_cast<Res::ERes>(i));
assert(!possibleResources.empty());
producedResource = *RandomGeneratorUtil::nextItem(possibleResources, cb->gameState()->getRandomGenerator());
producedResource = *RandomGeneratorUtil::nextItem(possibleResources, rand);
tempOwner = PlayerColor::NEUTRAL;
}
else
@ -859,7 +859,7 @@ CGResource::CGResource()
amount = 0;
}
void CGResource::initObj()
void CGResource::initObj(CRandomGenerator & rand)
{
blockVisit = true;
@ -868,13 +868,13 @@ void CGResource::initObj()
switch(subID)
{
case 6:
amount = cb->gameState()->getRandomGenerator().nextInt(500, 1000);
amount = rand.nextInt(500, 1000);
break;
case 0: case 2:
amount = cb->gameState()->getRandomGenerator().nextInt(6, 10);
amount = rand.nextInt(6, 10);
break;
default:
amount = cb->gameState()->getRandomGenerator().nextInt(3, 5);
amount = rand.nextInt(3, 5);
break;
}
}
@ -987,7 +987,7 @@ ObjectInstanceID CGTeleport::getRandomExit(const CGHeroInstance * h) const
{
auto passableExits = getPassableExits(cb->gameState(), h, getAllExits(true));
if(passableExits.size())
return *RandomGeneratorUtil::nextItem(passableExits, cb->gameState()->getRandomGenerator());
return *RandomGeneratorUtil::nextItem(passableExits, CRandomGenerator::getDefault());
return ObjectInstanceID();
}
@ -1119,7 +1119,7 @@ void CGMonolith::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer,
cb->moveHero(hero->id, dPos, true);
}
void CGMonolith::initObj()
void CGMonolith::initObj(CRandomGenerator & rand)
{
std::vector<Obj> IDs;
IDs.push_back(ID);
@ -1164,7 +1164,7 @@ void CGSubterraneanGate::onHeroVisit( const CGHeroInstance * h ) const
cb->showTeleportDialog(&td);
}
void CGSubterraneanGate::initObj()
void CGSubterraneanGate::initObj(CRandomGenerator & rand)
{
type = BOTH;
}
@ -1283,7 +1283,7 @@ void CGWhirlpool::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer
{
auto obj = cb->getObj(getRandomExit(hero));
std::set<int3> tiles = obj->getBlockedPos();
dPos = CGHeroInstance::convertPosition(*RandomGeneratorUtil::nextItem(tiles, cb->gameState()->getRandomGenerator()), true);
dPos = CGHeroInstance::convertPosition(*RandomGeneratorUtil::nextItem(tiles, CRandomGenerator::getDefault()), true);
}
cb->moveHero(hero->id, dPos, true);
@ -1299,7 +1299,7 @@ bool CGWhirlpool::isProtected(const CGHeroInstance * h)
return false;
}
void CGArtifact::initObj()
void CGArtifact::initObj(CRandomGenerator & rand)
{
blockVisit = true;
if(ID == Obj::ARTIFACT)
@ -1441,14 +1441,14 @@ void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler)
}
}
void CGWitchHut::initObj()
void CGWitchHut::initObj(CRandomGenerator & rand)
{
if (allowedAbilities.empty()) //this can happen for RMG. regular maps load abilities from map file
{
for (int i = 0; i < GameConstants::SKILL_QUANTITY; i++)
allowedAbilities.push_back(i);
}
ability = *RandomGeneratorUtil::nextItem(allowedAbilities, cb->gameState()->getRandomGenerator());
ability = *RandomGeneratorUtil::nextItem(allowedAbilities, rand);
}
void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
@ -1627,7 +1627,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
cb->showInfoDialog(&iw);
}
void CGShrine::initObj()
void CGShrine::initObj(CRandomGenerator & rand)
{
if(spell == SpellID::NONE) //spell not set
{
@ -1641,7 +1641,7 @@ void CGShrine::initObj()
return;
}
spell = *RandomGeneratorUtil::nextItem(possibilities, cb->gameState()->getRandomGenerator());
spell = *RandomGeneratorUtil::nextItem(possibilities, rand);
}
}
@ -1669,12 +1669,12 @@ void CGShrine::serializeJsonOptions(JsonSerializeFormat& handler)
handler.serializeId("spell", &CSpellHandler::decodeSpell, &CSpellHandler::encodeSpell, SpellID(SpellID::NONE), spell);
}
void CGSignBottle::initObj()
void CGSignBottle::initObj(CRandomGenerator & rand)
{
//if no text is set than we pick random from the predefined ones
if(message.empty())
{
message = *RandomGeneratorUtil::nextItem(VLC->generaltexth->randsign, cb->gameState()->getRandomGenerator());
message = *RandomGeneratorUtil::nextItem(VLC->generaltexth->randsign, rand);
}
if(ID == Obj::OCEAN_BOTTLE)
@ -1714,7 +1714,7 @@ void CGScholar::onHeroVisit( const CGHeroInstance * h ) const
))) //hero doesn't have a spellbook or already knows the spell or doesn't have Wisdom
{
type = PRIM_SKILL;
bid = cb->gameState()->getRandomGenerator().nextInt(GameConstants::PRIMARY_SKILLS - 1);
bid = CRandomGenerator::getDefault().nextInt(GameConstants::PRIMARY_SKILLS - 1);
}
InfoWindow iw;
@ -1749,25 +1749,25 @@ void CGScholar::onHeroVisit( const CGHeroInstance * h ) const
cb->removeObject(this);
}
void CGScholar::initObj()
void CGScholar::initObj(CRandomGenerator & rand)
{
blockVisit = true;
if(bonusType == RANDOM)
{
bonusType = static_cast<EBonusType>(cb->gameState()->getRandomGenerator().nextInt(2));
bonusType = static_cast<EBonusType>(rand.nextInt(2));
switch(bonusType)
{
case PRIM_SKILL:
bonusID = cb->gameState()->getRandomGenerator().nextInt(GameConstants::PRIMARY_SKILLS -1);
bonusID = rand.nextInt(GameConstants::PRIMARY_SKILLS -1);
break;
case SECONDARY_SKILL:
bonusID = cb->gameState()->getRandomGenerator().nextInt(GameConstants::SKILL_QUANTITY -1);
bonusID = rand.nextInt(GameConstants::SKILL_QUANTITY -1);
break;
case SPELL:
std::vector<SpellID> possibilities;
for (int i = 1; i < 6; ++i)
cb->getAllowedSpells (possibilities, i);
bonusID = *RandomGeneratorUtil::nextItem(possibilities, cb->gameState()->getRandomGenerator());
bonusID = *RandomGeneratorUtil::nextItem(possibilities, rand);
break;
}
}
@ -1874,7 +1874,7 @@ void CGMagi::reset()
eyelist.clear();
}
void CGMagi::initObj()
void CGMagi::initObj(CRandomGenerator & rand)
{
if (ID == Obj::EYE_OF_MAGI)
{
@ -1920,12 +1920,12 @@ void CGMagi::onHeroVisit(const CGHeroInstance * h) const
}
}
void CGBoat::initObj()
void CGBoat::initObj(CRandomGenerator & rand)
{
hero = nullptr;
}
void CGSirens::initObj()
void CGSirens::initObj(CRandomGenerator & rand)
{
blockVisit = true;
}
@ -2111,7 +2111,7 @@ void CGObelisk::onHeroVisit( const CGHeroInstance * h ) const
}
void CGObelisk::initObj()
void CGObelisk::initObj(CRandomGenerator & rand)
{
obeliskCount++;
}
@ -2172,7 +2172,7 @@ void CGLighthouse::onHeroVisit( const CGHeroInstance * h ) const
}
}
void CGLighthouse::initObj()
void CGLighthouse::initObj(CRandomGenerator & rand)
{
if(tempOwner < PlayerColor::PLAYER_LIMIT)
{

View File

@ -59,8 +59,8 @@ public:
void onHeroVisit(const CGHeroInstance * h) const override;
std::string getHoverText(PlayerColor player) const override;
std::string getHoverText(const CGHeroInstance * hero) const override;
void initObj() override;
void newTurn() const override;
void initObj(CRandomGenerator & rand) override;
void newTurn(CRandomGenerator & rand) const override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
@ -105,7 +105,7 @@ public:
std::string message;
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -125,7 +125,7 @@ public:
std::string getHoverText(PlayerColor player) const override;
std::string getHoverText(const CGHeroInstance * hero) const override;
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CPlayersVisited&>(*this);
@ -144,7 +144,7 @@ public:
CGScholar() : bonusType(EBonusType::RANDOM){};
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
@ -187,7 +187,7 @@ public:
std::string getObjectName() const override;
void pick( const CGHeroInstance * h ) const;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -206,7 +206,7 @@ public:
CGResource();
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
std::string getHoverText(PlayerColor player) const override;
@ -227,7 +227,7 @@ class DLL_LINKAGE CGShrine : public CPlayersVisited
public:
SpellID spell; //id of spell or NONE if random
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
std::string getHoverText(PlayerColor player) const override;
std::string getHoverText(const CGHeroInstance * hero) const override;
@ -252,8 +252,8 @@ private:
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
void flagMine(PlayerColor player) const;
void newTurn() const override;
void initObj() override;
void newTurn(CRandomGenerator & rand) const override;
void initObj(CRandomGenerator & rand) override;
std::string getObjectName() const override;
std::string getHoverText(PlayerColor player) const override;
@ -329,7 +329,7 @@ class DLL_LINKAGE CGMonolith : public CGTeleport
protected:
void onHeroVisit(const CGHeroInstance * h) const override;
void teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer, TTeleportExitsList exits) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
public:
template <typename Handler> void serialize(Handler &h, const int version)
@ -341,7 +341,7 @@ public:
class DLL_LINKAGE CGSubterraneanGate : public CGMonolith
{
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
public:
static void postInit();
@ -382,7 +382,7 @@ class DLL_LINKAGE CGSirens : public CGObjectInstance
public:
void onHeroVisit(const CGHeroInstance * h) const override;
std::string getHoverText(const CGHeroInstance * hero) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -407,7 +407,7 @@ public:
ui8 direction;
const CGHeroInstance *hero; //hero on board
void initObj() override;
void initObj(CRandomGenerator & rand) override;
CGBoat()
{
@ -443,7 +443,7 @@ public:
static void reset();
void initObj() override;
void initObj(CRandomGenerator & rand) override;
void onHeroVisit(const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
@ -478,7 +478,7 @@ public:
static std::map<TeamID, ui8> visited; //map: team_id => how many obelisks has been visited
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
std::string getHoverText(PlayerColor player) const override;
static void reset();
@ -494,7 +494,7 @@ class DLL_LINKAGE CGLighthouse : public CGObjectInstance
{
public:
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void initObj(CRandomGenerator & rand) override;
std::string getHoverText(PlayerColor player) const override;
template <typename Handler> void serialize(Handler &h, const int version)

View File

@ -253,6 +253,7 @@ void registerTypesClientPacks1(Serializer &s)
s.template registerType<CPackForClient, SetCommanderProperty>();
s.template registerType<CPackForClient, ChangeObjectVisitors>();
s.template registerType<CPackForClient, ShowWorldViewEx>();
s.template registerType<CPackForClient, PrepareHeroLevelUp>();
}
template<typename Serializer>

View File

@ -449,8 +449,7 @@ void PatchObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env
if(hex.getX() > 0 && hex.getX() < 16 && !(parameters.cb->battleGetStackByPos(hex, false)) && !(parameters.cb->battleGetObstacleOnPos(hex, false)))
availableTiles.push_back(hex);
}
boost::range::random_shuffle(availableTiles);
RandomGeneratorUtil::randomShuffle(availableTiles, env->getRandomGenerator());
const int patchesForSkill[] = {4, 4, 6, 8};
const int patchesToPut = std::min<int>(patchesForSkill[parameters.spellLvl], availableTiles.size());

View File

@ -204,7 +204,7 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
// give primary skill
logGlobal->trace("%s got level %d", hero->name, hero->level);
auto primarySkill = hero->nextPrimarySkill();
auto primarySkill = hero->nextPrimarySkill(getRandomGenerator());
SetPrimSkill sps;
sps.id = hero->id;
@ -213,20 +213,24 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
sps.val = 1;
sendAndApply(&sps);
PrepareHeroLevelUp pre;
pre.hero = hero;
sendAndApply(&pre);
HeroLevelUp hlu;
hlu.hero = hero;
hlu.primskill = primarySkill;
hlu.skills = hero->getLevelUpProposedSecondarySkills();
hlu.skills = pre.skills;
if(hlu.skills.size() == 0)
{
sendAndApply(&hlu);
levelUpHero(hero);
}
else if(hlu.skills.size() == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
else if(hlu.skills.size() == 1)
{
sendAndApply(&hlu);
levelUpHero(hero, *RandomGeneratorUtil::nextItem(hlu.skills, hero->skillsInfo.rand));
levelUpHero(hero, pre.skills.front());
}
else if(hlu.skills.size() > 1)
{
@ -364,7 +368,7 @@ void CGameHandler::levelUpCommander(const CCommanderInstance * c)
else if(skillAmount == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
{
sendAndApply(&clu);
levelUpCommander(c, *RandomGeneratorUtil::nextItem(clu.skills, gs->getRandomGenerator()));
levelUpCommander(c, *RandomGeneratorUtil::nextItem(clu.skills, getRandomGenerator()));
}
else if(skillAmount > 1) //apply and ask for secondary skill
{
@ -525,7 +529,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
int maxLevel = eagleEyeLevel + 1;
double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::EAGLE_EYE);
for(const CSpell *sp : gs->curB->sides.at(!battleResult.data->winner).usedSpellsHistory)
if(sp->level <= maxLevel && !vstd::contains(finishingBattle->winnerHero->spells, sp->id) && gs->getRandomGenerator().nextInt(99) < eagleEyeChance)
if(sp->level <= maxLevel && !vstd::contains(finishingBattle->winnerHero->spells, sp->id) && getRandomGenerator().nextInt(99) < eagleEyeChance)
cs.spells.insert(sp->id);
}
}
@ -716,7 +720,7 @@ void CGameHandler::battleAfterLevelUp( const BattleResult &result )
if (necroSlot != SlotID())
{
finishingBattle->winnerHero->showNecromancyDialog(raisedStack);
finishingBattle->winnerHero->showNecromancyDialog(raisedStack, getRandomGenerator());
addToSlot(StackLocation(finishingBattle->winnerHero, necroSlot), raisedStack.type, raisedStack.count);
}
@ -789,20 +793,20 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
if(!vstd::contains_if(gs->curB->sides, sideHeroBlocksLuck))
{
if(attackerLuck > 0 && gs->getRandomGenerator().nextInt(23) < attackerLuck)
if(attackerLuck > 0 && getRandomGenerator().nextInt(23) < attackerLuck)
{
bat.flags |= BattleAttack::LUCKY;
}
if (VLC->modh->settings.data["hardcodedFeatures"]["NEGATIVE_LUCK"].Bool()) // negative luck enabled
{
if (attackerLuck < 0 && gs->getRandomGenerator().nextInt(23) < abs(attackerLuck))
if (attackerLuck < 0 && getRandomGenerator().nextInt(23) < abs(attackerLuck))
{
bat.flags |= BattleAttack::UNLUCKY;
}
}
}
if(gs->getRandomGenerator().nextInt(99) < att->valOfBonuses(Bonus::DOUBLE_DAMAGE_CHANCE))
if(getRandomGenerator().nextInt(99) < att->valOfBonuses(Bonus::DOUBLE_DAMAGE_CHANCE))
{
bat.flags |= BattleAttack::DEATH_BLOW;
}
@ -812,7 +816,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
static const int artilleryLvlToChance[] = {0, 50, 75, 100};
const CGHeroInstance * owner = gs->curB->getHero(att->owner);
int chance = artilleryLvlToChance[owner->getSecSkillLevel(SecondarySkill::ARTILLERY)];
if(chance > gs->getRandomGenerator().nextInt(99))
if(chance > getRandomGenerator().nextInt(99))
{
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
}
@ -875,8 +879,8 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
bsa.attackerID = att->ID;
bsa.stackAttacked = def->ID;
bsa.damageAmount = gs->curB->calculateDmg(att, def, gs->curB->battleGetOwner(att), gs->curB->battleGetOwner(def),
bat.shot(), distance, bat.lucky(), bat.unlucky(), bat.deathBlow(), bat.ballistaDoubleDmg(), gs->getRandomGenerator());
def->prepareAttacked(bsa, gs->getRandomGenerator()); //calculate casualties
bat.shot(), distance, bat.lucky(), bat.unlucky(), bat.deathBlow(), bat.ballistaDoubleDmg(), getRandomGenerator());
def->prepareAttacked(bsa, getRandomGenerator()); //calculate casualties
//life drain handling
if (att->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
@ -913,7 +917,7 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
bsa2.effect = 11;
bsa2.damageAmount = (std::min(def->totalHelth(), bsa.damageAmount) * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100; //TODO: scale with attack/defense
att->prepareAttacked(bsa2, gameState()->getRandomGenerator());
att->prepareAttacked(bsa2, getRandomGenerator());
bat.bsa.push_back(bsa2);
}
}
@ -1337,7 +1341,7 @@ void CGameHandler::init(StartInfo *si)
logGlobal->info("Gamestate initialized!");
// reset seed, so that clients can't predict any following random values
gs->getRandomGenerator().resetSeed();
getRandomGenerator().resetSeed();
for(auto & elem : gs->players)
{
@ -1373,10 +1377,10 @@ void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=fa
return;
}
auto dwelling = *RandomGeneratorUtil::nextItem(dwellings, gs->getRandomGenerator());
auto dwelling = *RandomGeneratorUtil::nextItem(dwellings, getRandomGenerator());
// for multi-creature dwellings like Golem Factory
auto creatureId = RandomGeneratorUtil::nextItem(dwelling->creatures, gs->getRandomGenerator())->second[0];
auto creatureId = RandomGeneratorUtil::nextItem(dwelling->creatures, getRandomGenerator())->second[0];
if(clear)
{
@ -1436,7 +1440,7 @@ void CGameHandler::newTurn()
}
else
{
int monthType = gs->getRandomGenerator().nextInt(99);
int monthType = getRandomGenerator().nextInt(99);
if(newMonth) //new month
{
if (monthType < 40) //double growth
@ -1444,13 +1448,13 @@ void CGameHandler::newTurn()
n.specialWeek = NewTurn::DOUBLE_GROWTH;
if (VLC->modh->settings.ALL_CREATURES_GET_DOUBLE_MONTHS)
{
std::pair<int, CreatureID> newMonster(54, VLC->creh->pickRandomMonster(gs->getRandomGenerator()));
std::pair<int, CreatureID> newMonster(54, VLC->creh->pickRandomMonster(getRandomGenerator()));
n.creatureid = newMonster.second;
}
else if(VLC->creh->doubledCreatures.size())
{
const std::vector<CreatureID> doubledCreatures (VLC->creh->doubledCreatures.begin(), VLC->creh->doubledCreatures.end());
n.creatureid = *RandomGeneratorUtil::nextItem(doubledCreatures, gs->getRandomGenerator());
n.creatureid = *RandomGeneratorUtil::nextItem(doubledCreatures, getRandomGenerator());
}
else
{
@ -1466,7 +1470,7 @@ void CGameHandler::newTurn()
if (monthType < 25)
{
n.specialWeek = NewTurn::BONUS_GROWTH; //+5
std::pair<int, CreatureID> newMonster(54, VLC->creh->pickRandomMonster(gs->getRandomGenerator()));
std::pair<int, CreatureID> newMonster(54, VLC->creh->pickRandomMonster(getRandomGenerator()));
//TODO do not pick neutrals
n.creatureid = newMonster.second;
}
@ -1515,10 +1519,10 @@ void CGameHandler::newTurn()
for (int j = 0; j < GameConstants::AVAILABLE_HEROES_PER_PLAYER; j++)
{
//first hero - native if possible, second hero -> any other class
if(CGHeroInstance *h = gs->hpool.pickHeroFor(j == 0, elem.first, getNativeTown(elem.first), pool, gs->getRandomGenerator(), banned))
if(CGHeroInstance *h = gs->hpool.pickHeroFor(j == 0, elem.first, getNativeTown(elem.first), pool, getRandomGenerator(), banned))
{
sah.hid[j] = h->subID;
h->initArmy(&sah.army[j]);
h->initArmy(getRandomGenerator(), &sah.army[j]);
banned = h->type->heroClass;
}
else
@ -1647,7 +1651,7 @@ void CGameHandler::newTurn()
{
SetAvailableArtifacts saa;
saa.id = -1;
pickAllowedArtsSet(saa.arts);
pickAllowedArtsSet(saa.arts, getRandomGenerator());
sendAndApply(&saa);
}
sendAndApply(&n);
@ -1691,12 +1695,12 @@ void CGameHandler::newTurn()
if (newMonth)
{
iw.text.addTxt(MetaString::ARRAY_TXT, (130));
iw.text.addReplacement(MetaString::ARRAY_TXT, gs->getRandomGenerator().nextInt(32, 41));
iw.text.addReplacement(MetaString::ARRAY_TXT, getRandomGenerator().nextInt(32, 41));
}
else
{
iw.text.addTxt(MetaString::ARRAY_TXT, (133));
iw.text.addReplacement(MetaString::ARRAY_TXT, gs->getRandomGenerator().nextInt(43, 57));
iw.text.addReplacement(MetaString::ARRAY_TXT, getRandomGenerator().nextInt(43, 57));
}
}
for (auto & elem : gs->players)
@ -1713,7 +1717,7 @@ void CGameHandler::newTurn()
for(auto & elem : gs->map->objects)
{
if(elem)
elem->newTurn();
elem->newTurn(getRandomGenerator());
}
synchronizeArtifactHandlerLists(); //new day events may have changed them. TODO better of managing that
@ -1859,9 +1863,18 @@ void CGameHandler::setupBattle( int3 tile, const CArmedInstance *armies[2], cons
{
battleResult.set(nullptr);
const auto t = gs->getTile(tile);
ETerrainType terrain = t->terType;
if(gs->map->isCoastalTile(tile)) //coastal tile is always ground
terrain = ETerrainType::SAND;
BFieldType terType = gs->battleGetBattlefieldType(tile, getRandomGenerator());
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)
terType = BFieldType::SHIP_TO_SHIP;
//send info about battles
BattleStart bs;
bs.info = gs->setupBattle(tile, armies, heroes, creatureBank, town);
bs.info = BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
sendAndApply(&bs);
}
@ -3569,7 +3582,7 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
const CGHeroInstance *newHero = nullptr;
if (theOtherHero) //on XXL maps all heroes can be imprisoned :(
{
newHero = gs->hpool.pickHeroFor(false, player, getNativeTown(player), pool, gs->getRandomGenerator(), theOtherHero->type->heroClass);
newHero = gs->hpool.pickHeroFor(false, player, getNativeTown(player), pool, getRandomGenerator(), theOtherHero->type->heroClass);
}
SetAvailableHeroes sah;
@ -3978,7 +3991,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
{
if(currentHP.at(attackedPart) != EWallState::DESTROYED && // this part can be hit
currentHP.at(attackedPart) != EWallState::NONE &&
gs->getRandomGenerator().nextInt(99) < getCatapultHitChance(attackedPart, sbi))//hit is successful
getRandomGenerator().nextInt(99) < getCatapultHitChance(attackedPart, sbi))//hit is successful
{
hitSuccessfull = true;
}
@ -3993,7 +4006,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
}
if (allowedTargets.empty())
break;
attackedPart = *RandomGeneratorUtil::nextItem(allowedTargets, gs->getRandomGenerator());
attackedPart = *RandomGeneratorUtil::nextItem(allowedTargets, getRandomGenerator());
}
}
while (!hitSuccessfull);
@ -4009,7 +4022,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
int dmgChance[] = { sbi.noDmg, sbi.oneDmg, sbi.twoDmg }; //dmgChance[i] - chance for doing i dmg when hit is successful
int dmgRand = gs->getRandomGenerator().nextInt(99);
int dmgRand = getRandomGenerator().nextInt(99);
//accumulating dmgChance
dmgChance[1] += dmgChance[0];
dmgChance[2] += dmgChance[1];
@ -4164,8 +4177,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
const Bonus * spellcaster = stack->getBonusLocalFirst(Selector::typeSubtype(Bonus::SPELLCASTER, spellID));
//TODO special bonus for genies ability
if(randSpellcaster && battleGetRandomStackSpell(stack, CBattleInfoCallback::RANDOM_AIMED) < 0)
spellID = battleGetRandomStackSpell(stack, CBattleInfoCallback::RANDOM_GENIE);
if(randSpellcaster && battleGetRandomStackSpell(getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) < 0)
spellID = battleGetRandomStackSpell(getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_GENIE);
if(spellID < 0)
complain("That stack can't cast spells!");
@ -4507,7 +4520,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
}
if (fearsomeCreature)
{
if (gs->getRandomGenerator().nextInt(99) < 10) //fixed 10%
if (getRandomGenerator().nextInt(99) < 10) //fixed 10%
{
bte.effect = Bonus::FEAR;
sendAndApply(&bte);
@ -4521,7 +4534,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
bool cast = false;
while (!bl.empty() && !cast)
{
auto bonus = *RandomGeneratorUtil::nextItem(bl, gs->getRandomGenerator());
auto bonus = *RandomGeneratorUtil::nextItem(bl, getRandomGenerator());
auto spellID = SpellID(bonus->subtype);
const CSpell * spell = SpellID(spellID).toSpell();
bl.remove_if([&bonus](Bonus * b){return b==bonus;});
@ -4635,7 +4648,7 @@ void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, c
bsa.damageAmount = damage;
bsa.stackAttacked = curStack->ID;
bsa.attackerID = -1;
curStack->prepareAttacked(bsa, gameState()->getRandomGenerator());
curStack->prepareAttacked(bsa, getRandomGenerator());
StacksInjured si;
si.stacks.push_back(bsa);
@ -5232,7 +5245,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
continue;
//check if spell should be cast (probability handling)
if(gs->getRandomGenerator().nextInt(99) >= chance)
if(getRandomGenerator().nextInt(99) >= chance)
continue;
//casting
@ -5314,7 +5327,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
TBonusListPtr acidBreath = attacker->getBonuses(Selector::type(Bonus::ACID_BREATH));
for(const Bonus *b : *acidBreath)
{
if (b->additionalInfo > gs->getRandomGenerator().nextInt(99))
if (b->additionalInfo > getRandomGenerator().nextInt(99))
acidDamage += b->val;
}
if (acidDamage)
@ -5625,7 +5638,7 @@ void CGameHandler::runBattle()
|| NBonus::hasOfType(gs->curB->battleGetFightingHero(1), Bonus::BLOCK_MORALE)) //checking if gs->curB->heroes have (or don't have) morale blocking bonuses)
)
{
if(gs->getRandomGenerator().nextInt(23) < -2 * nextStackMorale)
if(getRandomGenerator().nextInt(23) < -2 * nextStackMorale)
{
//unit loses its turn - empty freeze action
BattleAction ba;
@ -5697,7 +5710,7 @@ void CGameHandler::runBattle()
{
BattleAction attack;
attack.destinationTile = *RandomGeneratorUtil::nextItem(attackableBattleHexes,
gs->getRandomGenerator());
getRandomGenerator());
attack.actionType = Battle::CATAPULT;
attack.additionalInfo = 0;
attack.side = !next->attackerOwned;
@ -5723,7 +5736,7 @@ void CGameHandler::runBattle()
if(!curOwner || curOwner->getSecSkillLevel(SecondarySkill::FIRST_AID) == 0) //no hero or hero has no first aid
{
range::random_shuffle(possibleStacks);
RandomGeneratorUtil::randomShuffle(possibleStacks, getRandomGenerator());
const CStack * toBeHealed = possibleStacks.front();
BattleAction heal;
@ -5802,7 +5815,7 @@ void CGameHandler::runBattle()
|| NBonus::hasOfType(gs->curB->battleGetFightingHero(1), Bonus::BLOCK_MORALE)) //checking if gs->curB->heroes have (or don't have) morale blocking bonuses
)
{
if(gs->getRandomGenerator().nextInt(23) < nextStackMorale) //this stack hasn't got morale this turn
if(getRandomGenerator().nextInt(23) < nextStackMorale) //this stack hasn't got morale this turn
{
BattleTriggerEffect bte;
@ -5926,7 +5939,8 @@ void CGameHandler::spawnWanderingMonsters(CreatureID creatureID)
std::vector<int3> tiles;
getFreeTiles(tiles);
ui32 amount = tiles.size() / 200; //Chance is 0.5% for each tile
std::random_shuffle(tiles.begin(), tiles.end());
RandomGeneratorUtil::randomShuffle(tiles, getRandomGenerator());
logGlobal->trace("Spawning wandering monsters. Found %d free tiles. Creature type: %d", tiles.size(), creatureID.num);
const CCreature *cre = VLC->creh->creatures.at(creatureID);
for (int i = 0; i < amount; ++i)
@ -6230,6 +6244,11 @@ CGameHandler::FinishingBattleHelper::FinishingBattleHelper()
winnerHero = loserHero = nullptr;
}
CRandomGenerator & CGameHandler::getRandomGenerator()
{
return CRandomGenerator::getDefault();
}
///ServerSpellCastEnvironment
ServerSpellCastEnvironment::ServerSpellCastEnvironment(CGameHandler * gh): gh(gh)
{
@ -6243,7 +6262,7 @@ void ServerSpellCastEnvironment::sendAndApply(CPackForClient * info) const
CRandomGenerator & ServerSpellCastEnvironment::getRandomGenerator() const
{
return gh->gameState()->getRandomGenerator();
return gh->getRandomGenerator();
}
void ServerSpellCastEnvironment::complain(const std::string& problem) const

View File

@ -247,6 +247,10 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & QID & states & finishingBattle;
if(version >= 761)
{
h & getRandomGenerator();
}
}
void sendMessageToAll(const std::string &message);
@ -290,6 +294,8 @@ public:
void spawnWanderingMonsters(CreatureID creatureID);
friend class CVCMIServer;
CRandomGenerator & getRandomGenerator();
private:
ServerSpellCastEnvironment * spellEnv;