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

Some preparation towards mantis #1743:

- refactored CRandomGenerator (added util methods, improved method names)
- usages of std::minstd_ran are replaced by CRandomGenerator (not in entire code base, C rand() usages are still not replaced)
- refactored getArtSync method of CArtHandler -> now named pickRandomArtifact
- fixed some compiler warnings
- updated source code URL in VCMI spec
This commit is contained in:
beegee1 2014-03-17 19:51:07 +00:00
parent 1aff899f5b
commit fe1b16a7ec
22 changed files with 6774 additions and 6695 deletions

View File

@ -1873,8 +1873,6 @@ std::vector<HeroPtr> VCAI::getUnblockedHeroes() const
bool VCAI::canAct (HeroPtr h) const
{
bool digsTile = false;
auto mission = lockedHeroes.find(h);
if (mission != lockedHeroes.end())
{

View File

@ -5963,7 +5963,7 @@ void MoraleLuckBox::set(const IBonusBearer *node)
else
{
//it's a creature window
if (morale && node->hasBonusOfType (Bonus::UNDEAD) ||
if ((morale && node->hasBonusOfType(Bonus::UNDEAD)) ||
node->hasBonusOfType(Bonus::BLOCK_MORALE) || node->hasBonusOfType(Bonus::NON_LIVING))
{
text += CGI->generaltexth->arraytxt[113]; //unaffected by morale

View File

@ -1,4 +1,14 @@
#include "StdInc.h"
/*
* BattleState.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BattleState.h"
#include <numeric>
@ -11,18 +21,7 @@
#include "NetPacks.h"
#include "JsonNode.h"
#include "filesystem/Filesystem.h"
/*
* BattleState.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
extern std::minstd_rand ran;
#include "CRandomGenerator.h"
const CStack * BattleInfo::getNextStack() const
{
@ -1133,7 +1132,7 @@ std::pair<int,int> CStack::countKilledByAttack(int damageReceived) const
return std::make_pair(killedCount, newRemainingHP);
}
void CStack::prepareAttacked(BattleStackAttacked &bsa, boost::optional<int> customCount /*= boost::none*/) const
void CStack::prepareAttacked(BattleStackAttacked &bsa, CRandomGenerator & rand, boost::optional<int> customCount /*= boost::none*/) const
{
auto afterAttack = countKilledByAttack(bsa.damageAmount);
@ -1158,17 +1157,25 @@ void CStack::prepareAttacked(BattleStackAttacked &bsa, boost::optional<int> cust
int resurrectFactor = valOfBonuses(Bonus::REBIRTH);
if(resurrectFactor > 0 && casts) //there must be casts left
{
int resurrectedCount = base->count * resurrectFactor / 100;
if (resurrectedCount)
resurrectedCount += ((base->count * resurrectFactor / 100.0 - resurrectedCount) > ran()%100 / 100.0) ? 1 : 0; //last stack has proportional chance to rebirth
else //only one unit
resurrectedCount += ((base->count * resurrectFactor / 100.0) > ran()%100 / 100.0) ? 1 : 0;
int resurrectedStackCount = base->count * resurrectFactor / 100;
// last stack has proportional chance to rebirth
auto diff = base->count * resurrectFactor / 100.0 - resurrectedStackCount;
if (diff > rand.nextDouble(0, 0.99))
{
resurrectedStackCount += 1;
}
if(hasBonusOfType(Bonus::REBIRTH, 1))
vstd::amax (resurrectedCount, 1); //resurrect at least one Sacred Phoenix
if (resurrectedCount)
{
// resurrect at least one Sacred Phoenix
vstd::amax(resurrectedStackCount, 1);
}
if(resurrectedStackCount > 0)
{
bsa.flags |= BattleStackAttacked::REBIRTH;
bsa.newAmount = resurrectedCount; //risky?
bsa.newAmount = resurrectedStackCount; //risky?
bsa.newHP = MaxHealth(); //resore full health
}
}

View File

@ -27,7 +27,7 @@ class CArmedInstance;
class CGTownInstance;
class CStackInstance;
struct BattleStackAttacked;
class CRandomGenerator;
//only for use in BattleInfo
@ -222,7 +222,7 @@ public:
std::vector<BattleHex> getSurroundingHexes(BattleHex attackerPos = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
std::pair<int,int> countKilledByAttack(int damageReceived) const; //returns pair<killed count, new left HP>
void prepareAttacked(BattleStackAttacked &bsa, boost::optional<int> customCount = boost::none) const; //requires bsa.damageAmout filled
void prepareAttacked(BattleStackAttacked &bsa, CRandomGenerator & rand, boost::optional<int> customCount = boost::none) const; //requires bsa.damageAmout filled
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -1,3 +1,13 @@
/*
* CArtHandler.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "CArtHandler.h"
@ -9,20 +19,10 @@
#include "CObjectHandler.h"
#include "NetPacksBase.h"
#include "GameConstants.h"
#include "CRandomGenerator.h"
using namespace boost::assign;
/*
* CArtHandler.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
extern std::minstd_rand ran;
// Note: list must match entries in ArtTraits.txt
#define ART_POS_LIST \
ART_POS(SPELLBOOK) \
@ -422,11 +422,7 @@ CreatureID CArtHandler::machineIDToCreature(ArtifactID id)
return CreatureID::NONE; //this artifact is not a creature
}
ArtifactID CArtHandler::getRandomArt(int flags)
{
return getArtSync(ran(), flags, true);
}
ArtifactID CArtHandler::getArtSync (ui32 rand, int flags, bool erasePicked)
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags)
{
auto getAllowedArts = [&](std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, CArtifact::EartClass flag)
{
@ -466,8 +462,7 @@ ArtifactID CArtHandler::getArtSync (ui32 rand, int flags, bool erasePicked)
std::vector<ConstTransitivePtr<CArtifact> > out;
getAllowed(out);
ArtifactID artID = out[rand % out.size()]->id;
if(erasePicked)
ArtifactID artID = (*RandomGeneratorUtil::nextItem(out, rand))->id;
erasePickedArt(artID);
return artID;
}

View File

@ -24,6 +24,7 @@ class CGHeroInstance;
struct ArtifactLocation;
class CArtifactSet;
class CArtifactInstance;
class CRandomGenerator;
#define ART_BEARER_LIST \
ART_BEARER(HERO)\
@ -188,18 +189,6 @@ public:
class DLL_LINKAGE CArtHandler : public IHandlerBase //handles artifacts
{
CArtifact * loadFromJson(const JsonNode & node);
void addSlot(CArtifact * art, const std::string & slotID);
void loadSlots(CArtifact * art, const JsonNode & node);
void loadClass(CArtifact * art, const JsonNode & node);
void loadType(CArtifact * art, const JsonNode & node);
void loadComponents(CArtifact * art, const JsonNode & node);
void loadGrowingArt(CGrowingArtifact * art, const JsonNode & node);
void giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype = -1, Bonus::ValueType valType = Bonus::BASE_NUMBER, shared_ptr<ILimiter> limiter = shared_ptr<ILimiter>(), int additionalinfo = 0);
void giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator, int additionalinfo = 0);
void giveArtBonus(ArtifactID aid, Bonus *bonus);
public:
std::vector<CArtifact*> treasures, minors, majors, relics; //tmp vectors!!! do not touch if you don't know what you are doing!!!
@ -213,9 +202,9 @@ public:
void fillList(std::vector<CArtifact*> &listToBeFilled, CArtifact::EartClass artifactClass); //fills given empty list with allowed artifacts of gibven class. No side effects
boost::optional<std::vector<CArtifact*>&> listFromClass(CArtifact::EartClass artifactClass);
void erasePickedArt(ArtifactID id);
ArtifactID getRandomArt (int flags);
ArtifactID getArtSync (ui32 rand, int flags, bool erasePicked = false);
/// Gets a artifact ID randomly and removes the selected artifact from this handler.
ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags);
bool legalArtifact(ArtifactID id);
void getAllowedArts(std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, int flag);
void getAllowed(std::vector<ConstTransitivePtr<CArtifact> > &out, int flags);
@ -245,6 +234,22 @@ public:
& growingArtifacts;
//if(!h.saving) sortArts();
}
private:
CArtifact * loadFromJson(const JsonNode & node);
void addSlot(CArtifact * art, const std::string & slotID);
void loadSlots(CArtifact * art, const JsonNode & node);
void loadClass(CArtifact * art, const JsonNode & node);
void loadType(CArtifact * art, const JsonNode & node);
void loadComponents(CArtifact * art, const JsonNode & node);
void loadGrowingArt(CGrowingArtifact * art, const JsonNode & node);
void giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype = -1, Bonus::ValueType valType = Bonus::BASE_NUMBER, shared_ptr<ILimiter> limiter = shared_ptr<ILimiter>(), int additionalinfo = 0);
void giveArtBonus(ArtifactID aid, Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator, int additionalinfo = 0);
void giveArtBonus(ArtifactID aid, Bonus *bonus);
void erasePickedArt(ArtifactID id);
};
struct DLL_LINKAGE ArtSlotInfo

View File

@ -1052,7 +1052,7 @@ std::pair<ui32, ui32> CBattleInfoCallback::battleEstimateDamage(const BattleAtta
{
BattleStackAttacked bsa;
bsa.damageAmount = ret.*pairElems[i];
bai.defender->prepareAttacked(bsa, bai.defenderCount);
bai.defender->prepareAttacked(bsa, gs->getRandomGenerator(), bai.defenderCount);
auto retaliationAttack = bai.reverse();
retaliationAttack.attackerCount = bsa.newAmount;

View File

@ -1054,14 +1054,14 @@ CCreatureHandler::~CCreatureHandler()
creature.dellNull();
}
CreatureID CCreatureHandler::pickRandomMonster(const std::function<int()> &randGen, int tier) const
CreatureID CCreatureHandler::pickRandomMonster(CRandomGenerator & rand, int tier) const
{
int r = 0;
if(tier == -1) //pick any allowed creature
{
do
{
r = vstd::pickRandomElementOf(creatures, randGen)->idNumber;
r = (*RandomGeneratorUtil::nextItem(creatures, rand))->idNumber;
} while (VLC->creh->creatures[r] && VLC->creh->creatures[r]->special); // find first "not special" creature
}
else
@ -1082,7 +1082,7 @@ CreatureID CCreatureHandler::pickRandomMonster(const std::function<int()> &randG
return CreatureID::NONE;
}
return vstd::pickRandomElementOf(allowed, randGen);
return *RandomGeneratorUtil::nextItem(allowed, rand);
}
assert (r >= 0); //should always be, but it crashed
return CreatureID(r);

View File

@ -7,6 +7,7 @@
#include "GameConstants.h"
#include "JsonNode.h"
#include "IHandlerBase.h"
#include "CRandomGenerator.h"
/*
* CCreatureHandler.h, part of VCMI engine
@ -186,7 +187,7 @@ public:
std::vector <std::pair <Bonus*, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it
void deserializationFix();
CreatureID pickRandomMonster(const std::function<int()> &randGen = nullptr, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any
CreatureID pickRandomMonster(CRandomGenerator & rand, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any
void addBonusForTier(int tier, Bonus *b); //tier must be <1-7>
void addBonusForAllCreatures(Bonus *b);

View File

@ -28,7 +28,6 @@
#include "CStopWatch.h"
#include "mapping/CMapEditManager.h"
DLL_LINKAGE std::minstd_rand ran;
class CGObjectInstance;
#ifdef min
@ -363,7 +362,8 @@ static CGObjectInstance * createObject(Obj id, int subid, int3 pos, PlayerColor
return nobj;
}
CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor player, const CTown *town, std::map<ui32, ConstTransitivePtr<CGHeroInstance> > &available, const CHeroClass *bannedClass /*= nullptr*/) const
CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor player, const CTown *town,
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > &available, CRandomGenerator & rand, const CHeroClass * bannedClass /*= nullptr*/) const
{
CGHeroInstance *ret = nullptr;
@ -388,11 +388,11 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
if(!pool.size())
{
logGlobal->errorStream() << "Cannot pick native hero for " << player << ". Picking any...";
return pickHeroFor(false, player, town, available);
return pickHeroFor(false, player, town, available, rand);
}
else
{
ret = pool[rand()%pool.size()];
ret = *RandomGeneratorUtil::nextItem(pool, rand);
}
}
else
@ -414,7 +414,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
return nullptr;
}
r = rand()%sum;
r = rand.nextInt(sum - 1);
for (auto & elem : pool)
{
r -= elem->type->heroClass->selectionProbability[town->faction->index];
@ -449,7 +449,7 @@ CGameState::CampaignHeroReplacement::CampaignHeroReplacement(CGHeroInstance * he
}
int CGameState::pickNextHeroType(PlayerColor owner) const
int CGameState::pickNextHeroType(PlayerColor owner)
{
const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner);
if(ps.hero >= 0 && !isUsedHero(HeroTypeID(ps.hero))) //we haven't used selected hero
@ -460,7 +460,7 @@ int CGameState::pickNextHeroType(PlayerColor owner) const
return pickUnusedHeroTypeRandomly(owner);
}
int CGameState::pickUnusedHeroTypeRandomly(PlayerColor owner) const
int CGameState::pickUnusedHeroTypeRandomly(PlayerColor owner)
{
//list of available heroes for this faction and others
std::vector<HeroTypeID> factionHeroes, otherHeroes;
@ -476,11 +476,15 @@ int CGameState::pickUnusedHeroTypeRandomly(PlayerColor owner) const
// select random hero native to "our" faction
if(!factionHeroes.empty())
return factionHeroes.at(ran() % factionHeroes.size()).getNum();
{
return RandomGeneratorUtil::nextItem(factionHeroes, rand)->getNum();
}
logGlobal->warnStream() << "Cannot find free hero of appropriate faction for player " << owner << " - trying to get first available...";
if(!otherHeroes.empty())
return otherHeroes.at(ran() % otherHeroes.size()).getNum();
{
return RandomGeneratorUtil::nextItem(otherHeroes, rand)->getNum();
}
logGlobal->errorStream() << "No free allowed heroes!";
auto notAllowedHeroesButStillBetterThanCrash = getUnusedAllowedHeroes(true);
@ -497,29 +501,29 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
switch(obj->ID)
{
case Obj::RANDOM_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, 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->getRandomArt (CArtifact::ART_TREASURE));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE));
case Obj::RANDOM_MINOR_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_MINOR));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MINOR));
case Obj::RANDOM_MAJOR_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_MAJOR));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MAJOR));
case Obj::RANDOM_RELIC_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_RELIC));
return std::make_pair(Obj::ARTIFACT, VLC->arth->pickRandomArtifact(rand, 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(std::ref(ran)));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand));
case Obj::RANDOM_MONSTER_L1:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran), 1));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 1));
case Obj::RANDOM_MONSTER_L2:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran), 2));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 2));
case Obj::RANDOM_MONSTER_L3:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran), 3));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 3));
case Obj::RANDOM_MONSTER_L4:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran), 4));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 4));
case Obj::RANDOM_RESOURCE:
return std::make_pair(Obj::RESOURCE,ran()%7); //now it's OH3 style, use %8 for mithril
return std::make_pair(Obj::RESOURCE,rand.nextInt(6)); //now it's OH3 style, use %8 for mithril
case Obj::RANDOM_TOWN:
{
PlayerColor align = PlayerColor((static_cast<CGTownInstance*>(obj))->alignment);
@ -539,18 +543,18 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
{
do
{
f = ran()%VLC->townh->factions.size();
f = rand.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(std::ref(ran), 5));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 5));
case Obj::RANDOM_MONSTER_L6:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran), 6));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 6));
case Obj::RANDOM_MONSTER_L7:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran), 7));
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(rand, 7));
case Obj::RANDOM_DWELLING:
case Obj::RANDOM_DWELLING_LVL:
case Obj::RANDOM_DWELLING_FACTION:
@ -561,7 +565,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
//if castle alignment available
if (auto info = dynamic_cast<CCreGenAsCastleInfo*>(dwl->info))
{
faction = ran() % VLC->townh->factions.size();
faction = rand.nextInt(VLC->townh->factions.size() - 1);
if (info->asCastle)
{
for(auto & elem : map->objects)
@ -586,11 +590,11 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
}
else
{
while((!(info->castles[0]&(1<<faction))))
while(!(info->castles[0]&(1<<faction)))
{
if((faction>7) && (info->castles[1]&(1<<(faction-8))))
break;
faction = ran()%GameConstants::F_NUMBER;
faction = rand.nextInt(GameConstants::F_NUMBER - 1);
}
}
}
@ -601,9 +605,13 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
//if level set to range
if (auto info = dynamic_cast<CCreGenLeveledInfo*>(dwl->info))
level = ((info->maxLevel-info->minLevel) ? (ran()%(info->maxLevel-info->minLevel)+info->minLevel) : (info->minLevel));
{
level = rand.nextInt(info->minLevel, info->maxLevel);
}
else // fixed level
{
level = obj->subID;
}
delete dwl->info;
dwl->info = nullptr;
@ -627,9 +635,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
if (result.first == Obj::NO_OBJ)
{
logGlobal->errorStream() << "Error: failed to find creature for dwelling of "<< int(faction) << " of level " << int(level);
auto iter = VLC->objh->cregens.begin();
std::advance(iter, ran() % VLC->objh->cregens.size() );
result = std::make_pair(Obj::CREATURE_GENERATOR1, iter->first);
result = std::make_pair(Obj::CREATURE_GENERATOR1, RandomGeneratorUtil::nextItem(VLC->objh->cregens, rand)->first);
}
return result;
@ -763,7 +769,7 @@ BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2],
void CGameState::init(StartInfo * si)
{
logGlobal->infoStream() << "\tUsing random seed: "<< si->seedToBeUsed;
ran.seed((boost::int32_t)si->seedToBeUsed);
rand.setSeed(si->seedToBeUsed);
scenarioOps = CMemorySerializer::deepCopy(*si).release();
initialOpts = CMemorySerializer::deepCopy(*si).release();
si = nullptr;
@ -810,7 +816,7 @@ void CGameState::init(StartInfo * si)
logGlobal->debugStream() << "\tChecking objectives";
map->checkForObjectives(); //needs to be run when all objects are properly placed
int seedAfterInit = ran();
auto seedAfterInit = rand.nextInt();
logGlobal->infoStream() << "Seed after init is " << seedAfterInit << " (before was " << scenarioOps->seedToBeUsed << ")";
if(scenarioOps->seedPostInit > 0)
{
@ -1034,12 +1040,16 @@ void CGameState::initGrailPosition()
if(elem && elem->ID == Obj::HOLE)
allowedPos -= elem->pos;
if(allowedPos.size())
map->grailPos = allowedPos[ran() % allowedPos.size()];
if(!allowedPos.empty())
{
map->grailPos = *RandomGeneratorUtil::nextItem(allowedPos, rand);
}
else
{
logGlobal->warnStream() << "Warning: Grail cannot be placed, no appropriate tile found!";
}
}
}
void CGameState::initRandomFactionsForPlayers()
{
@ -1048,7 +1058,7 @@ void CGameState::initRandomFactionsForPlayers()
{
if(elem.second.castle==-1)
{
int randomID = ran() % map->players[elem.first.getNum()].allowedFactions.size();
auto randomID = rand.nextInt(map->players[elem.first.getNum()].allowedFactions.size() - 1);
auto iter = map->players[elem.first.getNum()].allowedFactions.begin();
std::advance(iter, randomID);
@ -1177,7 +1187,7 @@ void CGameState::placeCampaignHeroes()
auto unusedHeroTypeIds = getUnusedAllowedHeroes();
if(!unusedHeroTypeIds.empty())
{
heroTypeId = std::next(unusedHeroTypeIds.begin(), ran() % unusedHeroTypeIds.size())->getNum();
heroTypeId = (*RandomGeneratorUtil::nextItem(unusedHeroTypeIds, rand)).getNum();
}
else
{
@ -1680,23 +1690,23 @@ void CGameState::initStartingBonus()
{
//starting bonus
if(scenarioOps->playerInfos[elem.first].bonus==PlayerSettings::RANDOM)
scenarioOps->playerInfos[elem.first].bonus = static_cast<PlayerSettings::Ebonus>(ran()%3);
scenarioOps->playerInfos[elem.first].bonus = static_cast<PlayerSettings::Ebonus>(rand.nextInt(2));
switch(scenarioOps->playerInfos[elem.first].bonus)
{
case PlayerSettings::GOLD:
elem.second.resources[Res::GOLD] += 500 + (ran()%6)*100;
elem.second.resources[Res::GOLD] += rand.nextInt(500, 1000);
break;
case PlayerSettings::RESOURCE:
{
int res = VLC->townh->factions[scenarioOps->playerInfos[elem.first].castle]->town->primaryRes;
if(res == Res::WOOD_AND_ORE)
{
elem.second.resources[Res::WOOD] += 5 + ran()%6;
elem.second.resources[Res::ORE] += 5 + ran()%6;
elem.second.resources[Res::WOOD] += rand.nextInt(5, 10);
elem.second.resources[Res::ORE] += rand.nextInt(5, 10);
}
else
{
elem.second.resources[res] += 3 + ran()%4;
elem.second.resources[res] += rand.nextInt(3, 6);
}
break;
}
@ -1708,7 +1718,7 @@ void CGameState::initStartingBonus()
break;
}
CArtifact *toGive;
toGive = VLC->arth->artifacts[VLC->arth->getRandomArt (CArtifact::ART_TREASURE)];
toGive = VLC->arth->artifacts[VLC->arth->pickRandomArtifact(rand, CArtifact::ART_TREASURE)];
CGHeroInstance *hero = elem.second.heroes[0];
giveHeroArtifact(hero, toGive->id);
@ -1756,9 +1766,13 @@ void CGameState::initTowns()
{
CGTownInstance * vti =(elem);
if(!vti->town)
{
vti->town = VLC->townh->factions[vti->subID]->town;
if (vti->name.length()==0) // if town hasn't name we draw it
vti->name = vti->town->names[ran()%vti->town->names.size()];
}
if(vti->name.empty())
{
vti->name = *RandomGeneratorUtil::nextItem(vti->town->names, rand);
}
//init buildings
if(vstd::contains(vti->builtBuildings, BuildingID::DEFAULT)) //give standard set of buildings
@ -1767,9 +1781,11 @@ void CGameState::initTowns()
vti->builtBuildings.insert(BuildingID::VILLAGE_HALL);
vti->builtBuildings.insert(BuildingID::TAVERN);
vti->builtBuildings.insert(BuildingID::DWELL_FIRST);
if(ran()%2)
if(rand.nextInt(1) == 1)
{
vti->builtBuildings.insert(BuildingID::DWELL_LVL_2);
}
}
//#1444 - remove entries that don't have buildings defined (like some unused extra town hall buildings)
vstd::erase_if(vti->builtBuildings, [vti](BuildingID bid){
@ -1839,7 +1855,7 @@ void CGameState::initTowns()
if (total == 0) // remaining spells have 0 probability
break;
int r = ran()%total;
auto r = rand.nextInt(total - 1);
for(ui32 ps=0; ps<vti->possibleSpells.size();ps++)
{
r -= vti->possibleSpells[ps].toSpell()->getProbability(vti->subID);
@ -1921,7 +1937,7 @@ void CGameState::initVisitingAndGarrisonedHeroes()
}
}
BFieldType CGameState::battleGetBattlefieldType(int3 tile) const
BFieldType CGameState::battleGetBattlefieldType(int3 tile)
{
if(tile==int3() && curB)
tile = curB->tile;
@ -1971,13 +1987,13 @@ BFieldType CGameState::battleGetBattlefieldType(int3 tile) const
switch(t.terType)
{
case ETerrainType::DIRT:
return BFieldType(rand()%3+3);
return BFieldType(rand.nextInt(3, 5));
case ETerrainType::SAND:
return BFieldType::SAND_MESAS; //TODO: coast support
case ETerrainType::GRASS:
return BFieldType(rand()%2+6);
return BFieldType(rand.nextInt(6, 7));
case ETerrainType::SNOW:
return BFieldType(rand()%2+10);
return BFieldType(rand.nextInt(10, 11));
case ETerrainType::SWAMP:
return BFieldType::SWAMP_TREES;
case ETerrainType::ROUGH:
@ -3630,3 +3646,8 @@ std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & vic
os << victoryLossCheckResult.messageToSelf;
return os;
}
CRandomGenerator & CGameState::getRandomGenerator()
{
return rand;
}

View File

@ -16,7 +16,7 @@
#include "int3.h"
#include "CObjectHandler.h"
#include "IGameCallback.h"
#include "CRandomGenerator.h"
/*
* CGameState.h, part of VCMI engine
@ -399,7 +399,8 @@ public:
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > heroesPool; //[subID] - heroes available to buy; nullptr if not available
std::map<ui32,ui8> pavailable; // [subid] -> which players can recruit hero (binary flags)
CGHeroInstance * pickHeroFor(bool native, PlayerColor player, const CTown *town, std::map<ui32, ConstTransitivePtr<CGHeroInstance> > &available, const CHeroClass *bannedClass = nullptr) const;
CGHeroInstance * pickHeroFor(bool native, PlayerColor player, const CTown *town,
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > &available, CRandomGenerator & rand, const CHeroClass *bannedClass = nullptr) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -426,7 +427,7 @@ public:
void giveHeroArtifact(CGHeroInstance *h, ArtifactID aid);
void apply(CPack *pack);
BFieldType battleGetBattlefieldType(int3 tile) const;
BFieldType battleGetBattlefieldType(int3 tile);
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
@ -453,6 +454,9 @@ public:
int getMovementCost(const CGHeroInstance *h, const int3 &src, const int3 &dest, int remainingMovePoints=-1, bool checkLast=true);
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 -----
CRandomGenerator & getRandomGenerator();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects;
@ -519,8 +523,11 @@ private:
bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons
std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const;
std::pair<Obj,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>
int pickUnusedHeroTypeRandomly(PlayerColor owner) const; // picks a unused hero type randomly
int pickNextHeroType(PlayerColor owner) const; // picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly
int pickUnusedHeroTypeRandomly(PlayerColor owner); // picks a unused hero type randomly
int pickNextHeroType(PlayerColor owner); // picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly
// ---- data -----
CRandomGenerator rand;
friend class CCallback;
friend class CClient;

View File

@ -36,7 +36,6 @@ using namespace boost::assign;
std::map<Obj, std::map<int, std::vector<ObjectInstanceID> > > CGTeleport::objs;
std::vector<std::pair<ObjectInstanceID, ObjectInstanceID> > CGTeleport::gates;
IGameCallback * IObjectInterface::cb = nullptr;
extern std::minstd_rand ran;
std::map <PlayerColor, std::set <ui8> > CGKeys::playerKeyMap;
std::map <si32, std::vector<ObjectInstanceID> > CGMagi::eyelist;
ui8 CGObelisk::obeliskCount; //how many obelisks are on map
@ -798,7 +797,7 @@ void CGHeroInstance::initArmy(IArmyDescriptor *dst /*= nullptr*/)
dst = this;
int howManyStacks = 0; //how many stacks will hero receives <1 - 3>
int pom = ran()%100;
int pom = cb->gameState()->getRandomGenerator().nextInt(99);
int warMachinesGiven = 0;
if(pom < 9)
@ -814,8 +813,7 @@ void CGHeroInstance::initArmy(IArmyDescriptor *dst /*= nullptr*/)
{
auto & stack = type->initialArmy[stackNo];
int range = stack.maxAmount - stack.minAmount;
int count = ran()%(range+1) + stack.minAmount;
int count = cb->gameState()->getRandomGenerator().nextInt(stack.minAmount, stack.maxAmount);
if(stack.creature >= CreatureID::CATAPULT &&
stack.creature <= CreatureID::ARROW_TOWERS) //war machine
@ -1465,7 +1463,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const
{
InfoWindow iw;
iw.soundID = soundBase::pickup01 + ran() % 7;
iw.soundID = soundBase::pickup01 + cb->gameState()->getRandomGenerator().nextInt(6);
iw.player = tempOwner;
iw.components.push_back(Component(raisedStack));
@ -1553,7 +1551,7 @@ EAlignment::EAlignment CGHeroInstance::getAlignment() const
void CGHeroInstance::initExp()
{
exp=40+ (ran()) % 50;
exp = cb->gameState()->getRandomGenerator().nextInt(40, 89);
level = 1;
}
@ -1894,7 +1892,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->setObjProperty(id, ObjProperty::AVAILABLE_CREATURE, VLC->creh->pickRandomMonster(cb->gameState()->getRandomGenerator()));
}
bool change = false;
@ -2774,7 +2772,7 @@ void CGVisitableOPH::initObj()
{
if(ID==Obj::TREE_OF_KNOWLEDGE)
{
switch (ran() % 3)
switch (cb->gameState()->getRandomGenerator().nextInt(2))
{
case 1:
treePrice[Res::GOLD] = 2000;
@ -3292,13 +3290,13 @@ void CGCreature::initObj()
character = -4;
break;
case 1:
character = 1 + ran()%7;
character = cb->gameState()->getRandomGenerator().nextInt(1, 7);
break;
case 2:
character = 1 + ran()%10;
character = cb->gameState()->getRandomGenerator().nextInt(1, 10);
break;
case 3:
character = 4 + ran()%7;
character = cb->gameState()->getRandomGenerator().nextInt(4, 10);
break;
case 4:
character = 10;
@ -3308,14 +3306,11 @@ void CGCreature::initObj()
stacks[SlotID(0)]->setType(CreatureID(subID));
TQuantity &amount = stacks[SlotID(0)]->count;
CCreature &c = *VLC->creh->creatures[subID];
if(!amount)
if(amount == 0)
{
if(c.ammMax == c.ammMin)
amount = c.ammMax;
else
amount = c.ammMin + (ran() % (c.ammMax - c.ammMin));
amount = cb->gameState()->getRandomGenerator().nextInt(c.ammMin, c.ammMax);
if(!amount) //armies with 0 creatures are illegal
if(amount == 0) //armies with 0 creatures are illegal
{
logGlobal->warnStream() << "Problem: stack " << nodeName() << " cannot have 0 creatures. Check properties of " << c.nodeName();
amount = 1;
@ -3666,7 +3661,7 @@ void CGMine::initObj()
if(subID >= 7) //Abandoned Mine
{
//set guardians
int howManyTroglodytes = 100 + ran()%100;
int howManyTroglodytes = cb->gameState()->getRandomGenerator().nextInt(100, 199);
auto troglodytes = new CStackInstance(CreatureID::TROGLODYTES, howManyTroglodytes);
putStack(SlotID(0), troglodytes);
@ -3676,8 +3671,8 @@ void CGMine::initObj()
if(tempOwner.getNum() & 1<<i) //NOTE: reuse of tempOwner
possibleResources.push_back(static_cast<Res::ERes>(i));
assert(possibleResources.size());
producedResource = possibleResources[ran()%possibleResources.size()];
assert(!possibleResources.empty());
producedResource = *RandomGeneratorUtil::nextItem(possibleResources, cb->gameState()->getRandomGenerator());
tempOwner = PlayerColor::NEUTRAL;
hoverName = VLC->generaltexth->mines[7].first + "\n" + VLC->generaltexth->allTexts[202] + " " + troglodytes->getQuantityTXT(false) + " " + troglodytes->type->namePl;
}
@ -3761,13 +3756,13 @@ void CGResource::initObj()
switch(subID)
{
case 6:
amount = 500 + (ran()%6)*100;
amount = cb->gameState()->getRandomGenerator().nextInt(500, 1000);
break;
case 0: case 2:
amount = 6 + (ran()%5);
amount = cb->gameState()->getRandomGenerator().nextInt(6, 10);
break;
default:
amount = 3 + (ran()%3);
amount = cb->gameState()->getRandomGenerator().nextInt(3, 5);
break;
}
}
@ -4171,12 +4166,12 @@ void CGPickable::initObj()
switch(ID)
{
case Obj::CAMPFIRE:
val2 = (ran()%3) + 4; //4 - 6
val2 = cb->gameState()->getRandomGenerator().nextInt(4, 6);
val1 = val2 * 100;
type = ran()%6; //given resource
type = cb->gameState()->getRandomGenerator().nextInt(5); // given resource
break;
case Obj::FLOTSAM:
switch(type = ran()%4)
switch(type = cb->gameState()->getRandomGenerator().nextInt(3))
{
case 0:
val1 = val2 = 0;
@ -4197,7 +4192,7 @@ void CGPickable::initObj()
break;
case Obj::SEA_CHEST:
{
int hlp = ran()%100;
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
if(hlp < 20)
{
val1 = 0;
@ -4211,31 +4206,31 @@ void CGPickable::initObj()
else
{
val1 = 1000;
val2 = cb->getRandomArt (CArtifact::ART_TREASURE);
val2 = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_TREASURE);
type = 1;
}
}
break;
case Obj::SHIPWRECK_SURVIVOR:
{
int hlp = ran()%100;
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
if(hlp < 55)
val1 = cb->getRandomArt (CArtifact::ART_TREASURE);
val1 = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_TREASURE);
else if(hlp < 75)
val1 = cb->getRandomArt (CArtifact::ART_MINOR);
val1 = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_MINOR);
else if(hlp < 95)
val1 = cb->getRandomArt (CArtifact::ART_MAJOR);
val1 = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_MAJOR);
else
val1 = cb->getRandomArt (CArtifact::ART_RELIC);
val1 = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_RELIC);
}
break;
case Obj::TREASURE_CHEST:
{
int hlp = ran()%100;
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
if(hlp >= 95)
{
type = 1;
val1 = cb->getRandomArt (CArtifact::ART_TREASURE);
val1 = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_TREASURE);
return;
}
else if (hlp >= 65)
@ -4733,8 +4728,8 @@ void CGSeerHut::setObjToKill()
void CGSeerHut::init()
{
seerName = VLC->generaltexth->seerNames[ran()%VLC->generaltexth->seerNames.size()];
quest->textOption = ran() % 3;
seerName = *RandomGeneratorUtil::nextItem(VLC->generaltexth->seerNames, cb->gameState()->getRandomGenerator());
quest->textOption = cb->gameState()->getRandomGenerator().nextInt(2);
}
void CGSeerHut::initObj()
@ -5058,7 +5053,7 @@ void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer)
void CGQuestGuard::init()
{
blockVisit = true;
quest->textOption = (ran() % 3) + 3; //3-5
quest->textOption = cb->gameState()->getRandomGenerator().nextInt(3, 5);
}
void CGQuestGuard::completeQuest(const CGHeroInstance *h) const
{
@ -5066,7 +5061,7 @@ void CGQuestGuard::completeQuest(const CGHeroInstance *h) const
}
void CGWitchHut::initObj()
{
ability = allowedAbilities[ran()%allowedAbilities.size()];
ability = *RandomGeneratorUtil::nextItem(allowedAbilities, cb->gameState()->getRandomGenerator());
}
void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
@ -5862,13 +5857,13 @@ void CGShrine::initObj()
std::vector<SpellID> possibilities;
cb->getAllowedSpells (possibilities, level);
if(!possibilities.size())
if(possibilities.empty())
{
logGlobal->errorStream() << "Error: cannot init shrine, no allowed spells!";
return;
}
spell = possibilities[ran() % possibilities.size()];
spell = *RandomGeneratorUtil::nextItem(possibilities, cb->gameState()->getRandomGenerator());
}
}
@ -5889,8 +5884,10 @@ const std::string & CGShrine::getHoverText() const
void CGSignBottle::initObj()
{
//if no text is set than we pick random from the predefined ones
if(!message.size())
message = VLC->generaltexth->randsign[ran()%VLC->generaltexth->randsign.size()];
if(message.empty())
{
message = *RandomGeneratorUtil::nextItem(VLC->generaltexth->randsign, cb->gameState()->getRandomGenerator());
}
if(ID == Obj::OCEAN_BOTTLE)
{
@ -5930,10 +5927,9 @@ 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 = ran() % GameConstants::PRIMARY_SKILLS;
bid = cb->gameState()->getRandomGenerator().nextInt(GameConstants::PRIMARY_SKILLS - 1);
}
InfoWindow iw;
iw.soundID = soundBase::gazebo;
iw.player = h->getOwner();
@ -5971,20 +5967,20 @@ void CGScholar::initObj()
blockVisit = true;
if(bonusType == RANDOM)
{
bonusType = static_cast<EBonusType>(ran()%3);
bonusType = static_cast<EBonusType>(cb->gameState()->getRandomGenerator().nextInt(2));
switch(bonusType)
{
case PRIM_SKILL:
bonusID = ran() % GameConstants::PRIMARY_SKILLS;
bonusID = cb->gameState()->getRandomGenerator().nextInt(GameConstants::PRIMARY_SKILLS -1);
break;
case SECONDARY_SKILL:
bonusID = ran() % GameConstants::SKILL_QUANTITY;
bonusID = cb->gameState()->getRandomGenerator().nextInt(GameConstants::SKILL_QUANTITY -1);
break;
case SPELL:
std::vector<SpellID> possibilities;
for (int i = 1; i < 6; ++i)
cb->getAllowedSpells (possibilities, i);
bonusID = possibilities[ran() % possibilities.size()];
bonusID = *RandomGeneratorUtil::nextItem(possibilities, cb->gameState()->getRandomGenerator());
break;
}
}
@ -6124,11 +6120,11 @@ void CGOnceVisitable::initObj()
case Obj::CORPSE:
{
blockVisit = true;
int hlp = ran()%100;
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
if(hlp < 20)
{
artOrRes = 1;
bonusType = cb->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR);
bonusType = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR);
}
else
{
@ -6140,8 +6136,8 @@ void CGOnceVisitable::initObj()
case Obj::LEAN_TO:
{
artOrRes = 2;
bonusType = ran()%6; //any basic resource without gold
bonusVal = ran()%4 + 1;
bonusType = cb->gameState()->getRandomGenerator().nextInt(5); //any basic resource without gold
bonusVal = cb->gameState()->getRandomGenerator().nextInt(1, 4);
}
break;
@ -6149,21 +6145,21 @@ void CGOnceVisitable::initObj()
{
artOrRes = 1;
int hlp = ran()%100;
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
if(hlp < 30)
bonusType = cb->getRandomArt (CArtifact::ART_TREASURE);
bonusType = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_TREASURE);
else if(hlp < 80)
bonusType = cb->getRandomArt (CArtifact::ART_MINOR);
bonusType = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_MINOR);
else if(hlp < 95)
bonusType = cb->getRandomArt (CArtifact::ART_MAJOR);
bonusType = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_MAJOR);
else
bonusType = cb->getRandomArt (CArtifact::ART_RELIC);
bonusType = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_RELIC);
}
break;
case Obj::WAGON:
{
int hlp = ran()%100;
int hlp = cb->gameState()->getRandomGenerator().nextInt(99);
if(hlp < 10)
{
@ -6172,13 +6168,13 @@ void CGOnceVisitable::initObj()
else if(hlp < 50) //minor or treasure art
{
artOrRes = 1;
bonusType = cb->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR);
bonusType = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), CArtifact::ART_TREASURE | CArtifact::ART_MINOR);
}
else //2 - 5 of non-gold resource
{
artOrRes = 2;
bonusType = ran()%6;
bonusVal = ran()%4 + 2;
bonusType = cb->gameState()->getRandomGenerator().nextInt(5);
bonusVal = cb->gameState()->getRandomGenerator().nextInt(2, 5);
}
}
break;
@ -6250,7 +6246,7 @@ void CBank::reset(ui16 var1) //prevents desync
void CBank::initialize() const
{
cb->setObjProperty (id, ObjProperty::BANK_RESET, ran()); //synchronous reset
cb->setObjProperty(id, ObjProperty::BANK_RESET, cb->gameState()->getRandomGenerator().nextInt()); //synchronous reset
for (ui8 i = 0; i <= 3; i++)
{
@ -6266,12 +6262,12 @@ void CBank::initialize() const
default: assert(0); continue;
}
int artID = cb->getArtSync(ran(), artClass, true);
int artID = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), artClass);
cb->setObjProperty(id, ObjProperty::BANK_ADD_ARTIFACT, artID);
}
}
cb->setObjProperty (id, ObjProperty::BANK_INIT_ARMY, ran()); //get army
cb->setObjProperty(id, ObjProperty::BANK_INIT_ARMY, cb->gameState()->getRandomGenerator().nextInt()); //get army
}
void CBank::setPropertyDer (ui8 what, ui32 val)
/// random values are passed as arguments and processed identically on all clients
@ -6578,13 +6574,13 @@ void CGPyramid::initObj()
if (available.size())
{
bc = VLC->objh->banksInfo[21].front(); //TODO: remove hardcoded value?
spell = (available[ran()%available.size()]);
spell = *RandomGeneratorUtil::nextItem(available, cb->gameState()->getRandomGenerator());
}
else
{
logGlobal->errorStream() <<"No spells available for Pyramid! Object set to empty.";
}
setPropertyDer (ObjProperty::BANK_INIT_ARMY,ran()); //set guards at game start
setPropertyDer(ObjProperty::BANK_INIT_ARMY, cb->gameState()->getRandomGenerator().nextInt()); //set guards at game start
}
const std::string & CGPyramid::getHoverText() const
{
@ -7557,20 +7553,26 @@ void CGBlackMarket::newTurn() const
void CGUniversity::initObj()
{
std::vector<int> toChoose;
for (int i=0; i<GameConstants::SKILL_QUANTITY; i++)
for(int i = 0; i < GameConstants::SKILL_QUANTITY; ++i)
{
if(cb->isAllowed(2, i))
{
toChoose.push_back(i);
}
}
if(toChoose.size() < 4)
{
logGlobal->warnStream()<<"Warning: less then 4 available skills was found by University initializer!";
return;
}
for (int i=0; i<4; i++)//get 4 skills
// get 4 skills
for(int i = 0; i < 4; ++i)
{
int skillPos = ran()%toChoose.size();
skills.push_back(toChoose[skillPos]);//move it to selected
toChoose.erase(toChoose.begin()+skillPos);//remove from list
// move randomly one skill to selected and remove from list
auto it = RandomGeneratorUtil::nextItem(toChoose, cb->gameState()->getRandomGenerator());
skills.push_back(*it);
toChoose.erase(it);
}
}

View File

@ -20,44 +20,92 @@ typedef std::function<double()> TRand;
/// The random generator randomly generates integers and real numbers("doubles") between
/// a given range. This is a header only class and mainly a wrapper for
/// convenient usage of the standard random API.
class CRandomGenerator
class CRandomGenerator : boost::noncopyable
{
public:
/// Seeds the generator with the current time by default.
CRandomGenerator()
{
gen.seed((unsigned long)std::time(nullptr));
rand.seed(static_cast<unsigned long>(std::time(nullptr)));
}
void seed(int value)
void setSeed(int seed)
{
gen.seed(value);
rand.seed(seed);
}
/// Generate several integer numbers within the same range.
/// e.g.: auto a = gen.getRangeI(0,10); a(); a(); a();
TRandI getRangeI(int lower, int upper)
/// e.g.: auto a = gen.getIntRange(0,10); a(); a(); a();
/// requires: lower <= upper
TRandI getIntRange(int lower, int upper)
{
return boost::bind(TIntDist(lower, upper), boost::ref(gen));
return boost::bind(TIntDist(lower, upper), boost::ref(rand));
}
int getInteger(int lower, int upper)
/// Generates an integer between 0 and upper.
/// requires: 0 <= upper
int nextInt(int upper)
{
return getRangeI(lower, upper)();
return getIntRange(0, upper)();
}
/// requires: lower <= upper
int nextInt(int lower, int upper)
{
return getIntRange(lower, upper)();
}
/// Generates an integer between 0 and the maximum value it can hold.
int nextInt()
{
return TIntDist()(rand);
}
/// Generate several double/real numbers within the same range.
/// e.g.: auto a = gen.getRangeI(0,10); a(); a(); a();
TRand getRange(double lower, double upper)
/// e.g.: auto a = gen.getDoubleRange(4.5,10.2); a(); a(); a();
/// requires: lower <= upper
TRand getDoubleRange(double lower, double upper)
{
return boost::bind(TRealDist(lower, upper), boost::ref(gen));
return boost::bind(TRealDist(lower, upper), boost::ref(rand));
}
double getDouble(double lower, double upper)
/// Generates a double between 0 and upper.
/// requires: 0 <= upper
double nextDouble(double upper)
{
return getRange(lower, upper)();
return getDoubleRange(0, upper)();
}
/// requires: lower <= upper
double nextDouble(double lower, double upper)
{
return getDoubleRange(lower, upper)();
}
/// Generates a double between 0.0 and 1.0.
double nextDouble()
{
return TRealDist()(rand);
}
private:
TGenerator gen;
TGenerator rand;
};
namespace RandomGeneratorUtil
{
/// Gets an iterator to an element of a nonempty container randomly. Undefined behaviour if container is empty.
template<typename Container>
auto nextItem(const Container & container, CRandomGenerator & rand) -> decltype(std::begin(container))
{
assert(!container.empty());
return std::next(container.begin(), rand.nextInt(container.size() - 1));
}
template<typename Container>
auto nextItem(Container & container, CRandomGenerator & rand) -> decltype(std::begin(container))
{
assert(!container.empty());
return std::next(container.begin(), rand.nextInt(container.size() - 1));
}
}

View File

@ -1,3 +1,13 @@
/*
* IGameCallback.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "IGameCallback.h"
@ -20,24 +30,12 @@
#include "Connection.h"
/*
* IGameCallback.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
//TODO make clean
#define ERROR_SILENT_RET_VAL_IF(cond, txt, retVal) do {if(cond){return retVal;}} while(0)
#define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0)
#define ERROR_RET_IF(cond, txt) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return;}} while(0)
#define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0)
extern std::minstd_rand ran;
CGameState * CPrivilagedInfoCallback::gameState ()
{
return gs;
@ -182,21 +180,11 @@ bool CGameInfoCallback::isAllowed( int type, int id )
void CPrivilagedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact*> &out)
{
for (int j = 0; j < 3 ; j++)
out.push_back(VLC->arth->artifacts[getRandomArt(CArtifact::ART_TREASURE)]);
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_TREASURE)]);
for (int j = 0; j < 3 ; j++)
out.push_back(VLC->arth->artifacts[getRandomArt(CArtifact::ART_MINOR)]);
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_MINOR)]);
out.push_back(VLC->arth->artifacts[getRandomArt(CArtifact::ART_MAJOR)]);
}
ArtifactID CPrivilagedInfoCallback::getRandomArt (int flags)
{
return VLC->arth->getRandomArt(flags);
}
ArtifactID CPrivilagedInfoCallback::getArtSync (ui32 rand, int flags, bool erasePicked)
{
return VLC->arth->getArtSync (rand, flags, erasePicked);
out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_MAJOR)]);
}
void CPrivilagedInfoCallback::getAllowedSpells(std::vector<SpellID> &out, ui16 level)

View File

@ -171,8 +171,6 @@ 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) 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
ArtifactID getRandomArt (int flags);
ArtifactID getArtSync (ui32 rand, int flags, bool erasePicked); //synchronous
void pickAllowedArtsSet(std::vector<const CArtifact*> &out); //gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant
void getAllowedSpells(std::vector<SpellID> &out, ui16 level);

View File

@ -598,7 +598,7 @@ void CDrawTerrainOperation::updateTerrainViews()
auto & tile = map->getTile(pos);
if(!pattern.diffImages)
{
tile.terView = gen->getInteger(mapping.first, mapping.second);
tile.terView = gen->nextInt(mapping.first, mapping.second);
tile.extTileFlags = valRslt.flip;
}
else
@ -606,7 +606,7 @@ void CDrawTerrainOperation::updateTerrainViews()
const int framesPerRot = (mapping.second - mapping.first + 1) / pattern.rotationTypesCount;
int flip = (pattern.rotationTypesCount == 2 && valRslt.flip == 2) ? 1 : valRslt.flip;
int firstFrame = mapping.first + flip * framesPerRot;
tile.terView = gen->getInteger(firstFrame, firstFrame + framesPerRot - 1);
tile.terView = gen->nextInt(firstFrame, firstFrame + framesPerRot - 1);
tile.extTileFlags = 0;
}
}

View File

@ -177,15 +177,15 @@ const std::map<std::string, CRmgTemplate *> & CMapGenOptions::getAvailableTempla
void CMapGenOptions::finalize()
{
CRandomGenerator gen;
finalize(gen);
CRandomGenerator rand;
finalize(rand);
}
void CMapGenOptions::finalize(CRandomGenerator & gen)
void CMapGenOptions::finalize(CRandomGenerator & rand)
{
if(!mapTemplate)
{
mapTemplate = getPossibleTemplate(gen);
mapTemplate = getPossibleTemplate(rand);
assert(mapTemplate);
}
@ -194,22 +194,22 @@ void CMapGenOptions::finalize(CRandomGenerator & gen)
auto possiblePlayers = mapTemplate->getPlayers().getNumbers();
possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers()));
assert(!possiblePlayers.empty());
playerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1));
playerCount = *RandomGeneratorUtil::nextItem(possiblePlayers, rand);
updatePlayers();
}
if(teamCount == RANDOM_SIZE)
{
teamCount = gen.getInteger(0, playerCount - 1);
teamCount = rand.nextInt(playerCount - 1);
}
if(compOnlyPlayerCount == RANDOM_SIZE)
{
auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers();
compOnlyPlayerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1));
compOnlyPlayerCount = *RandomGeneratorUtil::nextItem(possiblePlayers, rand);
updateCompOnlyPlayers();
}
if(compOnlyTeamCount == RANDOM_SIZE)
{
compOnlyTeamCount = gen.getInteger(0, std::max(compOnlyPlayerCount - 1, 0));
compOnlyTeamCount = rand.nextInt(std::max(compOnlyPlayerCount - 1, 0));
}
// 1 team isn't allowed
@ -220,11 +220,11 @@ void CMapGenOptions::finalize(CRandomGenerator & gen)
if(waterContent == EWaterContent::RANDOM)
{
waterContent = static_cast<EWaterContent::EWaterContent>(gen.getInteger(0, 2));
waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(2));
}
if(monsterStrength == EMonsterStrength::RANDOM)
{
monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(gen.getInteger(0, 2));
monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(rand.nextInt(2));
}
}
@ -313,7 +313,7 @@ bool CMapGenOptions::checkOptions() const
}
}
const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & gen) const
const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & rand) const
{
// Find potential templates
const auto & tpls = getAvailableTemplates();
@ -363,7 +363,7 @@ const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & gen)
}
else
{
return *std::next(potentialTpls.begin(), gen.getInteger(0, potentialTpls.size() - 1));
return *RandomGeneratorUtil::nextItem(potentialTpls, rand);
}
}

View File

@ -143,7 +143,7 @@ public:
/// a random number generator by keeping the options in a valid state. Check options should return true, otherwise
/// this function fails.
void finalize();
void finalize(CRandomGenerator & gen);
void finalize(CRandomGenerator & rand);
/// Returns false if there is no template available which fits to the currently selected options.
bool checkOptions() const;
@ -156,7 +156,7 @@ private:
PlayerColor getNextPlayerColor() const;
void updateCompOnlyPlayers();
void updatePlayers();
const CRmgTemplate * getPossibleTemplate(CRandomGenerator & gen) const;
const CRmgTemplate * getPossibleTemplate(CRandomGenerator & rand) const;
si32 width, height;
bool hasTwoLevels;

View File

@ -35,9 +35,9 @@ CMapGenerator::~CMapGenerator()
std::unique_ptr<CMap> CMapGenerator::generate(CMapGenOptions * mapGenOptions, int randomSeed /*= std::time(nullptr)*/)
{
this->randomSeed = randomSeed;
gen.seed(this->randomSeed);
rand.setSeed(this->randomSeed);
this->mapGenOptions = mapGenOptions;
this->mapGenOptions->finalize(gen);
this->mapGenOptions->finalize(rand);
map = make_unique<CMap>();
editManager = map->getEditManager();
@ -125,7 +125,8 @@ void CMapGenerator::addPlayerInfo()
{
player.canHumanPlay = true;
}
auto itTeam = std::next(teamNumbers[j].begin(), gen.getInteger(0, teamNumbers[j].size() - 1));
auto itTeam = RandomGeneratorUtil::nextItem(teamNumbers[j], rand);
player.team = TeamID(*itTeam);
teamNumbers[j].erase(itTeam);
map->players[pSettings.getColor().getNum()] = player;
@ -138,9 +139,9 @@ void CMapGenerator::addPlayerInfo()
void CMapGenerator::genTerrain()
{
map->initTerrain();
editManager->clearTerrain(&gen);
editManager->clearTerrain(&rand);
editManager->getTerrainSelection().selectRange(MapRect(int3(4, 4, 0), 24, 30));
editManager->drawTerrain(ETerrainType::GRASS, &gen);
editManager->drawTerrain(ETerrainType::GRASS, &rand);
}
void CMapGenerator::genTowns()
@ -158,7 +159,11 @@ void CMapGenerator::genTowns()
auto town = new CGTownInstance();
town->ID = Obj::TOWN;
int townId = mapGenOptions->getPlayersSettings().find(PlayerColor(i))->second.getStartingTown();
if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) townId = gen.getInteger(0, 8); // Default towns
if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN)
{
// select default towns
townId = rand.nextInt(8);
}
town->subID = townId;
town->tempOwner = owner;
town->appearance = VLC->dobjinfo->pickCandidates(town->ID, town->subID, map->getTile(townPos[side]).terType).front();

View File

@ -36,7 +36,7 @@ private:
CMapGenOptions * mapGenOptions;
std::unique_ptr<CMap> map;
CRandomGenerator gen;
CRandomGenerator rand;
int randomSeed;
CMapEditManager * editManager;
};

View File

@ -7,7 +7,7 @@ Group: Amusements/Games
# The source for this package was pulled from upstream's vcs. Use the
# following commands to generate the tarball:
# svn export -r HEAD https://vcmi.svn.sourceforge.net/svnroot/vcmi/tags/0.95 vcmi-0.9.5-1
# svn export -r HEAD https://svn.code.sf.net/p/vcmi/code/tags/0.95 vcmi-0.9.5-1
# tar -cJf vcmi-0.9.5-1.tar.xz vcmi-0.9.5-1
Source: vcmi-0.9.5-1.tar.xz

View File

@ -824,7 +824,7 @@ 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());
def->prepareAttacked(bsa); //calculate casualties
def->prepareAttacked(bsa, gameState()->getRandomGenerator()); //calculate casualties
//life drain handling
if (att->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
@ -858,7 +858,7 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
bsa2.effect = 11;
bsa2.damageAmount = (bsa.damageAmount * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100; //TODO: scale with attack/defense
att->prepareAttacked(bsa2);
att->prepareAttacked(bsa2, gameState()->getRandomGenerator());
bat.bsa.push_back(bsa2);
}
}
@ -1079,9 +1079,10 @@ CGameHandler::~CGameHandler(void)
void CGameHandler::init(StartInfo *si)
{
//extern DLL_LINKAGE std::minstd_rand ran;
if(!si->seedToBeUsed)
if(si->seedToBeUsed == 0)
{
si->seedToBeUsed = std::time(nullptr);
}
gs = new CGameState();
logGlobal->infoStream() << "Gamestate created!";
@ -1089,8 +1090,10 @@ void CGameHandler::init(StartInfo *si)
logGlobal->infoStream() << "Gamestate initialized!";
for(auto & elem : gs->players)
{
states.addPlayer(elem.first);
}
}
static bool evntCmp(const CMapEvent &a, const CMapEvent &b)
{
@ -1187,7 +1190,7 @@ 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([]{ return rand(); }));
std::pair<int, CreatureID> newMonster(54, VLC->creh->pickRandomMonster(gs->getRandomGenerator()));
n.creatureid = newMonster.second;
}
else if(VLC->creh->doubledCreatures.size())
@ -1209,7 +1212,7 @@ void CGameHandler::newTurn()
if (monthType < 25)
{
n.specialWeek = NewTurn::BONUS_GROWTH; //+5
std::pair<int, CreatureID> newMonster(54, VLC->creh->pickRandomMonster([]{ return rand(); }));
std::pair<int, CreatureID> newMonster(54, VLC->creh->pickRandomMonster(gs->getRandomGenerator()));
//TODO do not pick neutrals
n.creatureid = newMonster.second;
}
@ -1238,7 +1241,8 @@ void CGameHandler::newTurn()
CHeroClass *banned = nullptr;
for (int j = 0; j < GameConstants::AVAILABLE_HEROES_PER_PLAYER; j++)
{
if(CGHeroInstance *h = gs->hpool.pickHeroFor(j == 0, elem.first, getNativeTown(elem.first), pool, banned)) //first hero - native if possible, second hero -> any other class
//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))
{
sah.hid[j] = h->subID;
h->initArmy(&sah.army[j]);
@ -3213,7 +3217,7 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
const CGHeroInstance *theOtherHero = p->availableHeroes.at(!hid);
const CGHeroInstance *newHero = nullptr;
if (theOtherHero) //on XXL maps all heroes can be imprisoned :(
newHero = gs->hpool.pickHeroFor(false, player, getNativeTown(player), pool, theOtherHero->type->heroClass);
newHero = gs->hpool.pickHeroFor(false, player, getNativeTown(player), pool, gs->getRandomGenerator(), theOtherHero->type->heroClass);
SetAvailableHeroes sah;
sah.player = player;
@ -4120,7 +4124,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
bsa.attackerID = stack->ID;
else
bsa.attackerID = -1;
(attackedCre)->prepareAttacked(bsa);
(attackedCre)->prepareAttacked(bsa, gs->getRandomGenerator());
si.stacks.push_back(bsa);
if (spellID == SpellID::CHAIN_LIGHTNING)
@ -4419,7 +4423,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
bsa.damageAmount = usedSpellPower * (attackedCre)->valOfBonuses(Bonus::STACK_HEALTH);
bsa.stackAttacked = (attackedCre)->ID;
bsa.attackerID = -1;
(attackedCre)->prepareAttacked(bsa);
(attackedCre)->prepareAttacked(bsa, gameState()->getRandomGenerator());
si.stacks.push_back(bsa);
}
}
@ -4434,7 +4438,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
bsa.damageAmount = usedSpellPower; //damage times the number of attackers
bsa.stackAttacked = (attackedCre)->ID;
bsa.attackerID = -1;
(attackedCre)->prepareAttacked(bsa);
(attackedCre)->prepareAttacked(bsa, gameState()->getRandomGenerator());
si.stacks.push_back(bsa);
}
}
@ -4751,7 +4755,7 @@ void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, c
bsa.damageAmount = damage;
bsa.stackAttacked = curStack->ID;
bsa.attackerID = -1;
curStack->prepareAttacked(bsa);
curStack->prepareAttacked(bsa, gameState()->getRandomGenerator());
StacksInjured si;
si.stacks.push_back(bsa);