mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
parent
d234f8627b
commit
1d57b75bc5
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@
|
||||
*.layout
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
/CMakeLists.txt.user
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "StdInc.h"
|
||||
#include "CEmptyAI.h"
|
||||
|
||||
#include "CRandomGenerator.h"
|
||||
|
||||
void CEmptyAI::init(shared_ptr<CCallback> CB)
|
||||
{
|
||||
cb = CB;
|
||||
@ -15,12 +17,12 @@ void CEmptyAI::yourTurn()
|
||||
|
||||
void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID)
|
||||
{
|
||||
cb->selectionMade(rand() % skills.size(), queryID);
|
||||
cb->selectionMade(CRandomGenerator::getDefault().nextInt(skills.size() - 1), queryID);
|
||||
}
|
||||
|
||||
void CEmptyAI::commanderGotLevel(const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID)
|
||||
{
|
||||
cb->selectionMade(rand() % skills.size(), queryID);
|
||||
cb->selectionMade(CRandomGenerator::getDefault().nextInt(skills.size() - 1), queryID);
|
||||
}
|
||||
|
||||
void CEmptyAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel)
|
||||
|
@ -104,8 +104,9 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
||||
if(stack->type->idNumber == CreatureID::CATAPULT)
|
||||
{
|
||||
BattleAction attack;
|
||||
static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
|
||||
attack.destinationTile = wallHexes[ rand()%ARRAY_COUNT(wallHexes) ];
|
||||
static const std::vector<int> wallHexes = boost::assign::list_of(50)(183)(182)(130)(62)(29)(12)(95);
|
||||
|
||||
attack.destinationTile = *RandomGeneratorUtil::nextItem(wallHexes, CRandomGenerator::getDefault());
|
||||
attack.actionType = Battle::CATAPULT;
|
||||
attack.additionalInfo = 0;
|
||||
attack.side = side;
|
||||
|
13
Global.h
13
Global.h
@ -553,19 +553,6 @@ namespace vstd
|
||||
});
|
||||
}
|
||||
|
||||
static inline int retreiveRandNum(const std::function<int()> &randGen)
|
||||
{
|
||||
if (randGen)
|
||||
return randGen();
|
||||
else
|
||||
return rand();
|
||||
}
|
||||
|
||||
template <typename T> const T & pickRandomElementOf(const std::vector<T> &v, const std::function<int()> &randGen)
|
||||
{
|
||||
return v.at(retreiveRandNum(randGen) % v.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void advance(T &obj, int change)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
#include "CBitmapHandler.h"
|
||||
#include "Graphics.h"
|
||||
@ -1432,7 +1433,7 @@ void CCreatureAnim::loopPreview(bool warMachine)
|
||||
if (anim.size(elem))
|
||||
available.push_back(elem);
|
||||
|
||||
size_t rnd = rand()%(available.size()*2);
|
||||
size_t rnd = CRandomGenerator::getDefault().nextInt(available.size() * 2 - 1);
|
||||
|
||||
if (rnd >= available.size())
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/StringConstants.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
* CMusicHandler.cpp, part of VCMI engine
|
||||
@ -230,7 +231,7 @@ int CSoundHandler::playSound(std::string sound, int repeats)
|
||||
// Helper. Randomly select a sound from an array and play it
|
||||
int CSoundHandler::playSoundFromSet(std::vector<soundBase::soundID> &sound_vec)
|
||||
{
|
||||
return playSound(sound_vec[rand() % sound_vec.size()]);
|
||||
return playSound(*RandomGeneratorUtil::nextItem(sound_vec, CRandomGenerator::getDefault()));
|
||||
}
|
||||
|
||||
void CSoundHandler::stopSound( int handler )
|
||||
@ -504,10 +505,7 @@ bool MusicEntry::play()
|
||||
if (!setName.empty())
|
||||
{
|
||||
auto set = owner->musicsSet[setName];
|
||||
size_t entryID = rand() % set.size();
|
||||
auto iterator = set.begin();
|
||||
std::advance(iterator, entryID);
|
||||
load(iterator->second);
|
||||
load(RandomGeneratorUtil::nextItem(set, CRandomGenerator::getDefault())->second);
|
||||
}
|
||||
|
||||
logGlobal->traceStream()<<"Playing music file "<<currentName;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "../lib/mapping/CMapService.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
* CPreGame.cpp, part of VCMI engine
|
||||
@ -607,7 +608,7 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
||||
bordered = true;
|
||||
//load random background
|
||||
const JsonVector & bgNames = CGPreGameConfig::get().getConfig()["game-select"].Vector();
|
||||
bg = new CPicture(bgNames[rand() % bgNames.size()].String(), 0, 0);
|
||||
bg = new CPicture(RandomGeneratorUtil::nextItem(bgNames, CRandomGenerator::getDefault())->String(), 0, 0);
|
||||
pos = bg->center();
|
||||
}
|
||||
|
||||
@ -4136,7 +4137,7 @@ std::string CLoadingScreen::getBackground()
|
||||
}
|
||||
else
|
||||
{
|
||||
return conf[ rand() % conf.size() ].String();
|
||||
return RandomGeneratorUtil::nextItem(conf, CRandomGenerator::getDefault())->String();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "../CVideoHandler.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
|
||||
#include "CBattleAnimations.h"
|
||||
#include "CBattleInterfaceClasses.h"
|
||||
@ -59,7 +60,7 @@ static void onAnimationFinished(const CStack *stack, CCreatureAnimation * anim)
|
||||
|
||||
if (anim->framesInGroup(CCreatureAnim::MOUSEON) > 0)
|
||||
{
|
||||
if (float(rand() % 100) < creature->animation.timeBetweenFidgets * 10)
|
||||
if (CRandomGenerator::getDefault().nextDouble(99.0) < creature->animation.timeBetweenFidgets * 10)
|
||||
anim->playOnce(CCreatureAnim::MOUSEON);
|
||||
else
|
||||
anim->setType(CCreatureAnim::HOLDING);
|
||||
@ -194,7 +195,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
logGlobal->errorStream() << bfieldType << " battlefield type does not have any backgrounds!";
|
||||
else
|
||||
{
|
||||
const std::string bgName = vstd::pickRandomElementOf(graphics->battleBacks[bfieldType], rand);
|
||||
const std::string bgName = *RandomGeneratorUtil::nextItem(graphics->battleBacks[bfieldType], CRandomGenerator::getDefault());
|
||||
background = BitmapHandler::loadBitmap(bgName, false);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/CStopWatch.h"
|
||||
#include "CMT.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
* mapHandler.cpp, part of VCMI engine
|
||||
@ -129,7 +130,7 @@ void CMapHandler::prepareFOWDefs()
|
||||
elem[j].resize(sizes.z);
|
||||
for(int k = 0; k < sizes.z; ++k)
|
||||
{
|
||||
elem[j][k] = rand()%graphics->FoWfullHide->ourImages.size();
|
||||
elem[j][k] = CRandomGenerator::getDefault().nextInt(graphics->FoWfullHide->ourImages.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,6 +200,8 @@ void CMapHandler::borderAndTerrainBitmapInit()
|
||||
{
|
||||
int terBitmapNum = -1;
|
||||
|
||||
auto & rand = CRandomGenerator::getDefault();
|
||||
|
||||
if(i==-1 && j==-1)
|
||||
terBitmapNum = 16;
|
||||
else if(i==-1 && j==(sizes.y))
|
||||
@ -208,15 +211,15 @@ void CMapHandler::borderAndTerrainBitmapInit()
|
||||
else if(i==(sizes.x) && j==(sizes.y))
|
||||
terBitmapNum = 18;
|
||||
else if(j == -1 && i > -1 && i < sizes.y)
|
||||
terBitmapNum = 22+rand()%2;
|
||||
terBitmapNum = rand.nextInt(22, 23);
|
||||
else if(i == -1 && j > -1 && j < sizes.y)
|
||||
terBitmapNum = 33+rand()%2;
|
||||
terBitmapNum = rand.nextInt(33, 34);
|
||||
else if(j == sizes.y && i >-1 && i < sizes.x)
|
||||
terBitmapNum = 29+rand()%2;
|
||||
terBitmapNum = rand.nextInt(29, 30);
|
||||
else if(i == sizes.x && j > -1 && j < sizes.y)
|
||||
terBitmapNum = 25+rand()%2;
|
||||
terBitmapNum = rand.nextInt(25, 26);
|
||||
else
|
||||
terBitmapNum = rand()%16;
|
||||
terBitmapNum = rand.nextInt(15);
|
||||
|
||||
if(terBitmapNum != -1)
|
||||
{
|
||||
@ -1083,7 +1086,7 @@ ui8 CMapHandler::getPhaseShift(const CGObjectInstance *object) const
|
||||
auto i = animationPhase.find(object);
|
||||
if(i == animationPhase.end())
|
||||
{
|
||||
ui8 ret = rand() % 255;
|
||||
ui8 ret = CRandomGenerator::getDefault().nextInt(254);
|
||||
animationPhase[object] = ret;
|
||||
return ret;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ std::pair< std::vector<BattleHex>, int > BattleInfo::getPath(BattleHex start, Ba
|
||||
}
|
||||
|
||||
ui32 BattleInfo::calculateDmg( const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero,
|
||||
bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg )
|
||||
bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg, CRandomGenerator & rand )
|
||||
{
|
||||
TDmgRange range = calculateDmgRange(attacker, defender, shooting, charge, lucky, unlucky, deathBlow, ballistaDoubleDmg);
|
||||
|
||||
@ -97,7 +97,7 @@ ui32 BattleInfo::calculateDmg( const CStack* attacker, const CStack* defender, c
|
||||
int howManyToAv = std::min<ui32>(10, attacker->count);
|
||||
for (int g=0; g<howManyToAv; ++g)
|
||||
{
|
||||
valuesToAverage[g] = range.first + rand() % (range.second - range.first + 1);
|
||||
valuesToAverage[g] = rand.nextInt(range.first, range.second);
|
||||
}
|
||||
|
||||
return std::accumulate(valuesToAverage, valuesToAverage + howManyToAv, 0) / howManyToAv;
|
||||
@ -723,7 +723,9 @@ const CGHeroInstance * BattleInfo::getHero( PlayerColor player ) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<ui32> BattleInfo::calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::vector<const CStack*> & affectedCreatures, PlayerColor casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel) const
|
||||
std::vector<ui32> BattleInfo::calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2,
|
||||
const std::vector<const CStack*> & affectedCreatures, PlayerColor casterSideOwner, ECastingMode::ECastingMode mode,
|
||||
int usedSpellPower, int spellLevel, CRandomGenerator & rand) const
|
||||
{
|
||||
std::vector<ui32> ret;
|
||||
for(auto & affectedCreature : affectedCreatures)
|
||||
@ -749,8 +751,11 @@ std::vector<ui32> BattleInfo::calculateResistedStacks(const CSpell * sp, const C
|
||||
|
||||
if(prob > 100) prob = 100;
|
||||
|
||||
if(rand()%100 < prob) //immunity from resistance
|
||||
//immunity from resistance
|
||||
if(rand.nextInt(99) < prob)
|
||||
{
|
||||
ret.push_back((affectedCreature)->ID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
||||
shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
|
||||
std::set<BattleHex> getStoppers(bool whichSidePerspective) const;
|
||||
|
||||
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg, CRandomGenerator & rand); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
||||
|
||||
//void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee
|
||||
@ -144,7 +144,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
||||
|
||||
const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player
|
||||
|
||||
std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::vector<const CStack*> & affectedCreatures, PlayerColor casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel) const;
|
||||
std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::vector<const CStack*> & affectedCreatures, PlayerColor casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel, CRandomGenerator & rand) const;
|
||||
|
||||
const CStack * battleGetStack(BattleHex pos, bool onlyAlive); //returns stack at given tile
|
||||
const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; nullptr if none
|
||||
|
@ -2251,10 +2251,14 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
|
||||
}
|
||||
}
|
||||
|
||||
if (possibleSpells.size())
|
||||
return possibleSpells[rand() % possibleSpells.size()];
|
||||
if(!possibleSpells.empty())
|
||||
{
|
||||
return *RandomGeneratorUtil::nextItem(possibleSpells, gs->getRandomGenerator());
|
||||
}
|
||||
else
|
||||
{
|
||||
return SpellID::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
SpellID CBattleInfoCallback::getRandomCastedSpell(const CStack * caster) const
|
||||
@ -2269,7 +2273,7 @@ SpellID CBattleInfoCallback::getRandomCastedSpell(const CStack * caster) const
|
||||
{
|
||||
totalWeight += std::max(b->additionalInfo, 1); //minimal chance to cast is 1
|
||||
}
|
||||
int randomPos = rand() % totalWeight;
|
||||
int randomPos = gs->getRandomGenerator().nextInt(totalWeight - 1);
|
||||
for(Bonus * b : *bl)
|
||||
{
|
||||
randomPos -= std::max(b->additionalInfo, 1);
|
||||
|
@ -458,7 +458,7 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects;
|
||||
h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects & rand;
|
||||
BONUS_TREE_DESERIALIZATION_FIX
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possibles, std::minstd_rand & distr) const //picks secondary skill out from given possibilities
|
||||
SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possibles, CRandomGenerator & rand) const //picks secondary skill out from given possibilities
|
||||
{
|
||||
int totalProb = 0;
|
||||
for(auto & possible : possibles)
|
||||
@ -32,12 +32,14 @@ SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possi
|
||||
}
|
||||
if (totalProb != 0) // may trigger if set contains only banned skills (0 probability)
|
||||
{
|
||||
int ran = distr()%totalProb;
|
||||
auto ran = rand.nextInt(totalProb - 1);
|
||||
for(auto & possible : possibles)
|
||||
{
|
||||
ran -= secSkillProbability[possible];
|
||||
if(ran<0)
|
||||
if(ran < 0)
|
||||
{
|
||||
return possible;
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME: select randomly? How H3 handles such rare situation?
|
||||
|
@ -21,6 +21,7 @@ class CGameInfo;
|
||||
class CGHeroInstance;
|
||||
struct BattleHex;
|
||||
class JsonNode;
|
||||
class CRandomGenerator;
|
||||
|
||||
struct SSpecialtyInfo
|
||||
{ si32 type;
|
||||
@ -132,7 +133,7 @@ public:
|
||||
CHeroClass();
|
||||
|
||||
bool isMagicHero() const;
|
||||
SecondarySkill chooseSecSkill(const std::set<SecondarySkill> & possibles, std::minstd_rand & distr) const; //picks secondary skill out from given possibilities
|
||||
SecondarySkill chooseSecSkill(const std::set<SecondarySkill> & possibles, CRandomGenerator & rand) const; //picks secondary skill out from given possibilities
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -68,6 +68,7 @@ set(lib_SRCS
|
||||
CHeroHandler.cpp
|
||||
CModHandler.cpp
|
||||
CObstacleInstance.cpp
|
||||
CRandomGenerator.cpp
|
||||
CSpellHandler.cpp
|
||||
CThreadHelper.cpp
|
||||
CTownHandler.cpp
|
||||
@ -91,7 +92,6 @@ set(lib_HEADERS
|
||||
CondSh.h
|
||||
ConstTransitivePtr.h
|
||||
CBonusTypeHandler.h
|
||||
CRandomGenerator.h
|
||||
CScriptingModule.h
|
||||
CStopWatch.h
|
||||
FunctionList.h
|
||||
|
@ -767,17 +767,14 @@ void CGHeroInstance::initHero()
|
||||
}
|
||||
assert(validTypes());
|
||||
|
||||
if (exp == 0xffffffff)
|
||||
level = 1;
|
||||
if(exp == 0xffffffff)
|
||||
{
|
||||
initExp();
|
||||
}
|
||||
else if (ID != Obj::PRISON)
|
||||
else
|
||||
{
|
||||
level = VLC->heroh->level(exp);
|
||||
}
|
||||
else //warp hero at the beginning of next turn
|
||||
{
|
||||
level = 1;
|
||||
levelUpAutomatically();
|
||||
}
|
||||
|
||||
if (VLC->modh->modules.COMMANDERS && !commander)
|
||||
@ -953,7 +950,7 @@ void CGHeroInstance::initObj()
|
||||
if(!type)
|
||||
initHero(); //TODO: set up everything for prison before specialties are configured
|
||||
|
||||
skillsInfo.distribution.seed(rand());
|
||||
skillsInfo.rand.setSeed(cb->gameState()->getRandomGenerator().nextInt());
|
||||
skillsInfo.resetMagicSchoolCounter();
|
||||
skillsInfo.resetWisdomCounter();
|
||||
|
||||
@ -1552,7 +1549,6 @@ EAlignment::EAlignment CGHeroInstance::getAlignment() const
|
||||
void CGHeroInstance::initExp()
|
||||
{
|
||||
exp = cb->gameState()->getRandomGenerator().nextInt(40, 89);
|
||||
level = 1;
|
||||
}
|
||||
|
||||
std::string CGHeroInstance::nodeName() const
|
||||
@ -1630,7 +1626,7 @@ ArtBearer::ArtBearer CGHeroInstance::bearerType() const
|
||||
return ArtBearer::HERO;
|
||||
}
|
||||
|
||||
std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills() const
|
||||
{
|
||||
std::vector<SecondarySkill> obligatorySkills; //hero is offered magic school or wisdom if possible
|
||||
if (!skillsInfo.wisdomCounter)
|
||||
@ -1643,11 +1639,7 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
std::vector<SecondarySkill> ss;
|
||||
ss += SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC;
|
||||
|
||||
auto rng = [=](ui32 val) mutable -> ui32
|
||||
{
|
||||
return skillsInfo.distribution() % val; //must be determined
|
||||
};
|
||||
std::random_shuffle(ss.begin(), ss.end(), rng);
|
||||
std::shuffle(ss.begin(), ss.end(), skillsInfo.rand.getStdGenerator());
|
||||
|
||||
for (auto skill : ss)
|
||||
{
|
||||
@ -1691,12 +1683,12 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
}
|
||||
else if(none.size() && canLearnSkill()) //hero have free skill slot
|
||||
{
|
||||
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.distribution)); //new skill
|
||||
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.rand)); //new skill
|
||||
none.erase(skills.back());
|
||||
}
|
||||
else if(!basicAndAdv.empty())
|
||||
{
|
||||
skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.distribution)); //upgrade existing
|
||||
skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.rand)); //upgrade existing
|
||||
basicAndAdv.erase(skills.back());
|
||||
}
|
||||
|
||||
@ -1706,7 +1698,7 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
//3) give any other new skill
|
||||
if(!basicAndAdv.empty())
|
||||
{
|
||||
SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.distribution);//upgrade existing
|
||||
SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.rand);//upgrade existing
|
||||
skills.push_back(s);
|
||||
basicAndAdv.erase(s);
|
||||
}
|
||||
@ -1716,18 +1708,147 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
}
|
||||
else if(none.size() && canLearnSkill())
|
||||
{
|
||||
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.distribution)); //give new skill
|
||||
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.rand)); //give new skill
|
||||
none.erase(skills.back());
|
||||
}
|
||||
|
||||
return skills;
|
||||
}
|
||||
|
||||
PrimarySkill::PrimarySkill CGHeroInstance::nextPrimarySkill() const
|
||||
{
|
||||
assert(gainsLevel());
|
||||
int randomValue = cb->gameState()->getRandomGenerator().nextInt(99), pom = 0, primarySkill = 0;
|
||||
const auto & skillChances = (level > 9) ? type->heroClass->primarySkillLowLevel : type->heroClass->primarySkillHighLevel;
|
||||
|
||||
for(; primarySkill < GameConstants::PRIMARY_SKILLS; ++primarySkill)
|
||||
{
|
||||
pom += skillChances[primarySkill];
|
||||
if(randomValue < pom)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logGlobal->traceStream() << "The hero gets the primary skill " << primarySkill << " with a probability of " << randomValue << "%.";
|
||||
return static_cast<PrimarySkill::PrimarySkill>(primarySkill);
|
||||
}
|
||||
|
||||
boost::optional<SecondarySkill> CGHeroInstance::nextSecondarySkill() const
|
||||
{
|
||||
assert(gainsLevel());
|
||||
|
||||
boost::optional<SecondarySkill> chosenSecondarySkill;
|
||||
const auto proposedSecondarySkills = getLevelUpProposedSecondarySkills();
|
||||
if(!proposedSecondarySkills.empty())
|
||||
{
|
||||
std::vector<SecondarySkill> learnedSecondarySkills;
|
||||
for(auto secondarySkill : proposedSecondarySkills)
|
||||
{
|
||||
if(getSecSkillLevel(secondarySkill) > 0)
|
||||
{
|
||||
learnedSecondarySkills.push_back(secondarySkill);
|
||||
}
|
||||
}
|
||||
|
||||
auto & rand = cb->gameState()->getRandomGenerator();
|
||||
if(learnedSecondarySkills.empty())
|
||||
{
|
||||
// there are only new skills to learn, so choose anyone of them
|
||||
chosenSecondarySkill = *RandomGeneratorUtil::nextItem(proposedSecondarySkills, rand);
|
||||
}
|
||||
else
|
||||
{
|
||||
// preferably upgrade a already learned secondary skill
|
||||
chosenSecondarySkill = *RandomGeneratorUtil::nextItem(learnedSecondarySkills, rand);
|
||||
}
|
||||
}
|
||||
return chosenSecondarySkill;
|
||||
}
|
||||
|
||||
void CGHeroInstance::setPrimarySkill(PrimarySkill::PrimarySkill primarySkill, si64 value, ui8 abs)
|
||||
{
|
||||
if(primarySkill < PrimarySkill::EXPERIENCE)
|
||||
{
|
||||
Bonus * skill = getBonusLocalFirst(Selector::type(Bonus::PRIMARY_SKILL)
|
||||
.And(Selector::subtype(primarySkill))
|
||||
.And(Selector::sourceType(Bonus::HERO_BASE_SKILL)));
|
||||
assert(skill);
|
||||
|
||||
if(abs)
|
||||
{
|
||||
skill->val = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
skill->val += value;
|
||||
}
|
||||
}
|
||||
else if(primarySkill == PrimarySkill::EXPERIENCE)
|
||||
{
|
||||
if(abs)
|
||||
{
|
||||
exp = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
exp += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CGHeroInstance::gainsLevel() const
|
||||
{
|
||||
return exp >= VLC->heroh->reqExp(level+1);
|
||||
}
|
||||
|
||||
void CGHeroInstance::levelUp(std::vector<SecondarySkill> skills)
|
||||
{
|
||||
++level;
|
||||
|
||||
//deterministic secondary skills
|
||||
skillsInfo.magicSchoolCounter = (skillsInfo.magicSchoolCounter + 1) % maxlevelsToMagicSchool();
|
||||
skillsInfo.wisdomCounter = (skillsInfo.wisdomCounter + 1) % maxlevelsToWisdom();
|
||||
if(vstd::contains(skills, SecondarySkill::WISDOM))
|
||||
{
|
||||
skillsInfo.resetWisdomCounter();
|
||||
}
|
||||
|
||||
SecondarySkill spellSchools[] = {
|
||||
SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC};
|
||||
for(auto skill : spellSchools)
|
||||
{
|
||||
if(vstd::contains(skills, skill))
|
||||
{
|
||||
skillsInfo.resetMagicSchoolCounter();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//specialty
|
||||
Updatespecialty();
|
||||
}
|
||||
|
||||
void CGHeroInstance::levelUpAutomatically()
|
||||
{
|
||||
while(gainsLevel())
|
||||
{
|
||||
const auto primarySkill = nextPrimarySkill();
|
||||
setPrimarySkill(primarySkill, 1, false);
|
||||
|
||||
auto proposedSecondarySkills = getLevelUpProposedSecondarySkills();
|
||||
|
||||
const auto secondarySkill = nextSecondarySkill();
|
||||
if(secondarySkill)
|
||||
{
|
||||
setSecSkillLevel(*secondarySkill, 1, false);
|
||||
}
|
||||
|
||||
//TODO why has the secondary skills to be passed to the method?
|
||||
levelUp(proposedSecondarySkills);
|
||||
}
|
||||
}
|
||||
|
||||
void CGDwelling::initObj()
|
||||
{
|
||||
switch(ID)
|
||||
@ -2303,13 +2424,15 @@ void CGTownInstance::newTurn() 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))
|
||||
{
|
||||
int resID = rand()%4+2;//bonus to random rare resource
|
||||
int resID = rand.nextInt(2, 5); //bonus to random rare resource
|
||||
resID = (resID==2)?1:resID;
|
||||
int resVal = rand()%4+1;//with size 1..4
|
||||
int resVal = rand.nextInt(1, 4);//with size 1..4
|
||||
cb->giveResource(tempOwner, static_cast<Res::ERes>(resID), resVal);
|
||||
cb->setObjProperty (id, ObjProperty::BONUS_VALUE_FIRST, resID);
|
||||
cb->setObjProperty (id, ObjProperty::BONUS_VALUE_SECOND, resVal);
|
||||
@ -2334,11 +2457,11 @@ void CGTownInstance::newTurn() const
|
||||
}
|
||||
if (nativeCrits.size())
|
||||
{
|
||||
SlotID pos = nativeCrits[rand() % nativeCrits.size()];
|
||||
SlotID pos = *RandomGeneratorUtil::nextItem(nativeCrits, rand);
|
||||
StackLocation sl(this, pos);
|
||||
|
||||
const CCreature *c = getCreature(pos);
|
||||
if (rand()%100 < 90 || c->upgrades.empty()) //increase number if no upgrade available
|
||||
if (rand.nextInt(99) < 90 || c->upgrades.empty()) //increase number if no upgrade available
|
||||
{
|
||||
cb->changeStackCount(sl, c->growth);
|
||||
}
|
||||
@ -2347,9 +2470,9 @@ void CGTownInstance::newTurn() const
|
||||
cb->changeStackType(sl, VLC->creh->creatures[*c->upgrades.begin()]);
|
||||
}
|
||||
}
|
||||
if ((stacksCount() < GameConstants::ARMY_SIZE && rand()%100 < 25) || Slots().empty()) //add new stack
|
||||
if ((stacksCount() < GameConstants::ARMY_SIZE && rand.nextInt(99) < 25) || Slots().empty()) //add new stack
|
||||
{
|
||||
int i = rand() % std::min (GameConstants::CREATURES_PER_TOWN, cb->getDate(Date::MONTH)<<1);
|
||||
int i = rand.nextInt(std::min(GameConstants::CREATURES_PER_TOWN, cb->getDate(Date::MONTH) << 1) - 1);
|
||||
if (!town->creatures[i].empty())
|
||||
{
|
||||
CreatureID c = town->creatures[i][0];
|
||||
@ -3316,7 +3439,7 @@ void CGCreature::initObj()
|
||||
amount = 1;
|
||||
}
|
||||
}
|
||||
formation.randomFormation = rand();
|
||||
formation.randomFormation = cb->gameState()->getRandomGenerator().nextInt();
|
||||
|
||||
temppower = stacks[SlotID(0)]->count * 1000;
|
||||
refusedJoining = false;
|
||||
@ -3532,10 +3655,10 @@ void CGCreature::fight( const CGHeroInstance *h ) const
|
||||
if (formation.randomFormation % 100 < 50) //upgrade
|
||||
{
|
||||
SlotID slotId = SlotID(stacks.size() / 2);
|
||||
if(ui32 upgradesSize = getStack(slotId).type->upgrades.size())
|
||||
const auto & upgrades = getStack(slotId).type->upgrades;
|
||||
if(!upgrades.empty())
|
||||
{
|
||||
auto it = getStack(slotId).type->upgrades.cbegin(); //pick random in case there are more
|
||||
std::advance (it, rand() % upgradesSize);
|
||||
auto it = RandomGeneratorUtil::nextItem(upgrades, cb->gameState()->getRandomGenerator());
|
||||
cb->changeStackType(StackLocation(this, slotId), VLC->creh->creatures[*it]);
|
||||
}
|
||||
}
|
||||
@ -3869,11 +3992,12 @@ void CGVisitableOPW::onHeroVisit( const CGHeroInstance * h ) const
|
||||
Component::EComponentType type = Component::RESOURCE;
|
||||
Res::ERes sub=Res::WOOD;
|
||||
int val=0;
|
||||
auto & rand = cb->gameState()->getRandomGenerator();
|
||||
|
||||
switch (ID)
|
||||
{
|
||||
case Obj::MYSTICAL_GARDEN:
|
||||
if (rand()%2)
|
||||
if(rand.nextInt(1) == 1)
|
||||
{
|
||||
sub = Res::GEMS;
|
||||
val = 5;
|
||||
@ -3886,8 +4010,8 @@ void CGVisitableOPW::onHeroVisit( const CGHeroInstance * h ) const
|
||||
break;
|
||||
case Obj::WINDMILL:
|
||||
mid = 170;
|
||||
sub = static_cast<Res::ERes>((rand() % 5) + 1);
|
||||
val = (rand() % 4) + 3;
|
||||
sub = static_cast<Res::ERes>(rand.nextInt(1, 5));
|
||||
val = rand.nextInt(3, 6);
|
||||
break;
|
||||
case Obj::WATER_WHEEL:
|
||||
mid = 164;
|
||||
@ -3923,16 +4047,27 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
|
||||
switch(ID)
|
||||
{
|
||||
case Obj::MONOLITH1: //one way - find corresponding exit monolith
|
||||
{
|
||||
if(vstd::contains(objs,Obj::MONOLITH2) && vstd::contains(objs[Obj::MONOLITH2],subID) && objs[Obj::MONOLITH2][subID].size())
|
||||
destinationid = objs[Obj::MONOLITH2][subID][rand()%objs[Obj::MONOLITH2][subID].size()];
|
||||
{
|
||||
destinationid = *RandomGeneratorUtil::nextItem(objs[Obj::MONOLITH2][subID], cb->gameState()->getRandomGenerator());
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->warnStream() << "Cannot find corresponding exit monolith for "<< id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Obj::MONOLITH3://two way monolith - pick any other one
|
||||
case Obj::WHIRLPOOL: //Whirlpool
|
||||
if(vstd::contains(objs,ID) && vstd::contains(objs[ID],subID) && objs[ID][subID].size()>1)
|
||||
{
|
||||
while ((destinationid = objs[ID][subID][rand()%objs[ID][subID].size()]) == id); //choose another exit
|
||||
//choose another exit
|
||||
do
|
||||
{
|
||||
destinationid = *RandomGeneratorUtil::nextItem(objs[ID][subID], cb->gameState()->getRandomGenerator());
|
||||
} while(destinationid == id);
|
||||
|
||||
if (ID == Obj::WHIRLPOOL)
|
||||
{
|
||||
if (!h->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION))
|
||||
@ -3983,9 +4118,8 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
|
||||
if (ID == Obj::WHIRLPOOL)
|
||||
{
|
||||
std::set<int3> tiles = cb->getObj(destinationid)->getBlockedPos();
|
||||
auto it = tiles.begin();
|
||||
std::advance (it, rand() % tiles.size()); //picking random element of set is tiring
|
||||
cb->moveHero (h->id, *it + int3(1,0,0), true);
|
||||
auto & tile = *RandomGeneratorUtil::nextItem(tiles, cb->gameState()->getRandomGenerator());
|
||||
cb->moveHero(h->id, tile + int3(1,0,0), true);
|
||||
}
|
||||
else
|
||||
cb->moveHero (h->id,CGHeroInstance::convertPosition(cb->getObj(destinationid)->pos,true) - getVisitableOffset(), true);
|
||||
@ -5156,7 +5290,7 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
|
||||
messageID = 55;
|
||||
iw.soundID = soundBase::LUCK;
|
||||
gbonus.bonus.type = Bonus::LUCK;
|
||||
gbonus.bonus.val = rand()%5 - 1;
|
||||
gbonus.bonus.val = cb->gameState()->getRandomGenerator().nextInt(-1, 3);
|
||||
descr_id = 69;
|
||||
gbonus.bdescr.addReplacement((gbonus.bonus.val<0 ? "-" : "+") + boost::lexical_cast<std::string>(gbonus.bonus.val));
|
||||
break;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "int3.h"
|
||||
#include "GameConstants.h"
|
||||
#include "ResourceSet.h"
|
||||
#include "CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
* CObjectHandler.h, part of VCMI engine
|
||||
@ -387,8 +388,8 @@ public:
|
||||
struct DLL_LINKAGE SecondarySkillsInfo
|
||||
{
|
||||
//skills are determined, initialized at map start
|
||||
//FIXME: remove mutable?
|
||||
mutable std::minstd_rand distribution;
|
||||
//FIXME remove mutable
|
||||
mutable CRandomGenerator rand;
|
||||
ui8 magicSchoolCounter;
|
||||
ui8 wisdomCounter;
|
||||
|
||||
@ -397,39 +398,10 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & magicSchoolCounter & wisdomCounter;
|
||||
if (h.saving)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << distribution;
|
||||
std::string str = stream.str();
|
||||
h & str;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string str;
|
||||
h & str;
|
||||
std::istringstream stream(str);
|
||||
stream >> distribution;
|
||||
}
|
||||
h & magicSchoolCounter & wisdomCounter & rand;
|
||||
}
|
||||
} skillsInfo;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CArmedInstance&>(*this);
|
||||
h & static_cast<CArtifactSet&>(*this);
|
||||
h & exp & level & name & biography & portrait & mana & secSkills & movement
|
||||
& sex & inTownGarrison & spells & patrol & moveDir & skillsInfo;
|
||||
h & visitedTown & boat;
|
||||
h & type & specialty & commander;
|
||||
BONUS_TREE_DESERIALIZATION_FIX
|
||||
//visitied town pointer will be restored by map serialization method
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
|
||||
int getSightRadious() const; //sight distance (should be used if player-owned structure)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -451,9 +423,28 @@ public:
|
||||
int getCurrentLuck(int stack=-1, bool town=false) const;
|
||||
int getSpellCost(const CSpell *sp) const; //do not use during battles -> bonuses from army would be ignored
|
||||
|
||||
// ----- primary and secondary skill, experience, level handling -----
|
||||
|
||||
/// Returns true if hero has lower level than should upon his experience.
|
||||
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;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Gets 0, 1 or 2 secondary skills which are proposed on hero level up.
|
||||
std::vector<SecondarySkill> getLevelUpProposedSecondarySkills() const;
|
||||
|
||||
ui8 getSecSkillLevel(SecondarySkill skill) const; //0 - no skill
|
||||
|
||||
/// Returns true if hero has free secondary skill slot.
|
||||
bool canLearnSkill() const;
|
||||
|
||||
void setPrimarySkill(PrimarySkill::PrimarySkill primarySkill, si64 value, ui8 abs);
|
||||
void setSecSkillLevel(SecondarySkill which, int val, bool abs);// abs == 0 - changes by value; 1 - sets to value
|
||||
bool canLearnSkill() const; ///true if hero has free secondary skill slot
|
||||
void levelUp(std::vector<SecondarySkill> skills);
|
||||
|
||||
int maxMovePoints(bool onLand) const;
|
||||
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false) const;
|
||||
@ -470,8 +461,6 @@ public:
|
||||
CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
|
||||
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
|
||||
ECanDig diggingStatus() const; //0 - can dig; 1 - lack of movement; 2 -
|
||||
std::vector<SecondarySkill> levelUpProposedSkills() const;
|
||||
bool gainsLevel() const; //true if hero has lower level than should upon his experience
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -506,6 +495,22 @@ public:
|
||||
const std::string & getHoverText() const override;
|
||||
protected:
|
||||
void setPropertyDer(ui8 what, ui32 val) override;//synchr
|
||||
|
||||
private:
|
||||
void levelUpAutomatically();
|
||||
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CArmedInstance&>(*this);
|
||||
h & static_cast<CArtifactSet&>(*this);
|
||||
h & exp & level & name & biography & portrait & mana & secSkills & movement
|
||||
& sex & inTownGarrison & spells & patrol & moveDir & skillsInfo;
|
||||
h & visitedTown & boat;
|
||||
h & type & specialty & commander;
|
||||
BONUS_TREE_DESERIALIZATION_FIX
|
||||
//visitied town pointer will be restored by map serialization method
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CSpecObjInfo
|
||||
|
86
lib/CRandomGenerator.cpp
Normal file
86
lib/CRandomGenerator.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
/*
|
||||
* CRandomGenerator.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 "CRandomGenerator.h"
|
||||
|
||||
boost::thread_specific_ptr<CRandomGenerator> CRandomGenerator::defaultRand;
|
||||
|
||||
CRandomGenerator::CRandomGenerator()
|
||||
{
|
||||
resetSeed();
|
||||
}
|
||||
|
||||
void CRandomGenerator::setSeed(int seed)
|
||||
{
|
||||
rand.seed(seed);
|
||||
}
|
||||
|
||||
void CRandomGenerator::resetSeed()
|
||||
{
|
||||
boost::hash<std::string> stringHash;
|
||||
auto threadIdHash = stringHash(boost::lexical_cast<std::string>(boost::this_thread::get_id()));
|
||||
setSeed(threadIdHash * std::time(nullptr));
|
||||
}
|
||||
|
||||
TRandI CRandomGenerator::getIntRange(int lower, int upper)
|
||||
{
|
||||
return boost::bind(TIntDist(lower, upper), boost::ref(rand));
|
||||
}
|
||||
|
||||
int CRandomGenerator::nextInt(int upper)
|
||||
{
|
||||
return getIntRange(0, upper)();
|
||||
}
|
||||
|
||||
int CRandomGenerator::nextInt(int lower, int upper)
|
||||
{
|
||||
return getIntRange(lower, upper)();
|
||||
}
|
||||
|
||||
int CRandomGenerator::nextInt()
|
||||
{
|
||||
return TIntDist()(rand);
|
||||
}
|
||||
|
||||
TRand CRandomGenerator::getDoubleRange(double lower, double upper)
|
||||
{
|
||||
return boost::bind(TRealDist(lower, upper), boost::ref(rand));
|
||||
}
|
||||
|
||||
double CRandomGenerator::nextDouble(double upper)
|
||||
{
|
||||
return getDoubleRange(0, upper)();
|
||||
}
|
||||
|
||||
double CRandomGenerator::nextDouble(double lower, double upper)
|
||||
{
|
||||
return getDoubleRange(lower, upper)();
|
||||
}
|
||||
|
||||
double CRandomGenerator::nextDouble()
|
||||
{
|
||||
return TRealDist()(rand);
|
||||
}
|
||||
|
||||
CRandomGenerator & CRandomGenerator::getDefault()
|
||||
{
|
||||
if(!defaultRand.get())
|
||||
{
|
||||
defaultRand.reset(new CRandomGenerator());
|
||||
}
|
||||
return *defaultRand.get();
|
||||
}
|
||||
|
||||
TGenerator & CRandomGenerator::getStdGenerator()
|
||||
{
|
||||
return rand;
|
||||
}
|
@ -19,77 +19,80 @@ 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 : boost::noncopyable
|
||||
/// convenient usage of the standard random API. An instance of this RNG is not thread safe.
|
||||
class DLL_LINKAGE CRandomGenerator : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/// Seeds the generator with the current time by default.
|
||||
CRandomGenerator()
|
||||
{
|
||||
rand.seed(static_cast<unsigned long>(std::time(nullptr)));
|
||||
}
|
||||
/// Seeds the generator by default with the product of the current time in milliseconds and the
|
||||
/// current thread ID.
|
||||
CRandomGenerator();
|
||||
|
||||
void setSeed(int seed)
|
||||
{
|
||||
rand.seed(seed);
|
||||
}
|
||||
void setSeed(int seed);
|
||||
|
||||
/// Resets the seed to the product of the current time in milliseconds and the
|
||||
/// current thread ID.
|
||||
void resetSeed();
|
||||
|
||||
/// Generate several integer numbers within the same range.
|
||||
/// 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(rand));
|
||||
}
|
||||
TRandI getIntRange(int lower, int upper);
|
||||
|
||||
/// Generates an integer between 0 and upper.
|
||||
/// requires: 0 <= upper
|
||||
int nextInt(int upper)
|
||||
{
|
||||
return getIntRange(0, upper)();
|
||||
}
|
||||
int nextInt(int upper);
|
||||
|
||||
/// requires: lower <= upper
|
||||
int nextInt(int lower, int upper)
|
||||
{
|
||||
return getIntRange(lower, upper)();
|
||||
}
|
||||
int nextInt(int lower, int upper);
|
||||
|
||||
/// Generates an integer between 0 and the maximum value it can hold.
|
||||
int nextInt()
|
||||
{
|
||||
return TIntDist()(rand);
|
||||
}
|
||||
int nextInt();
|
||||
|
||||
/// Generate several double/real numbers within the same range.
|
||||
/// 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(rand));
|
||||
}
|
||||
TRand getDoubleRange(double lower, double upper);
|
||||
|
||||
/// Generates a double between 0 and upper.
|
||||
/// requires: 0 <= upper
|
||||
double nextDouble(double upper)
|
||||
{
|
||||
return getDoubleRange(0, upper)();
|
||||
}
|
||||
double nextDouble(double upper);
|
||||
|
||||
/// requires: lower <= upper
|
||||
double nextDouble(double lower, double upper)
|
||||
{
|
||||
return getDoubleRange(lower, upper)();
|
||||
}
|
||||
double nextDouble(double lower, double upper);
|
||||
|
||||
/// Generates a double between 0.0 and 1.0.
|
||||
double nextDouble()
|
||||
{
|
||||
return TRealDist()(rand);
|
||||
}
|
||||
double nextDouble();
|
||||
|
||||
/// Gets a globally accessible RNG which will be constructed once per thread. For the
|
||||
/// seed a combination of the thread ID and current time in milliseconds will be used.
|
||||
static CRandomGenerator & getDefault();
|
||||
|
||||
/// Provide method so that this RNG can be used with legacy std:: API
|
||||
TGenerator & getStdGenerator();
|
||||
|
||||
private:
|
||||
TGenerator rand;
|
||||
static boost::thread_specific_ptr<CRandomGenerator> defaultRand;
|
||||
|
||||
public:
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
if(h.saving)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << rand;
|
||||
std::string str = stream.str();
|
||||
h & str;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string str;
|
||||
h & str;
|
||||
std::istringstream stream(str);
|
||||
stream >> rand;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace RandomGeneratorUtil
|
||||
|
@ -1068,14 +1068,13 @@ struct HeroLevelUp : public Query//2000
|
||||
|
||||
const CGHeroInstance *hero;
|
||||
PrimarySkill::PrimarySkill primskill;
|
||||
ui8 level;
|
||||
std::vector<SecondarySkill> skills;
|
||||
|
||||
HeroLevelUp(){type = 2000;};
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & queryID & hero & primskill & level & skills;
|
||||
h & queryID & hero & primskill & skills;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -49,28 +49,9 @@ DLL_LINKAGE void SetResources::applyGs( CGameState *gs )
|
||||
|
||||
DLL_LINKAGE void SetPrimSkill::applyGs( CGameState *gs )
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(id);
|
||||
CGHeroInstance * hero = gs->getHero(id);
|
||||
assert(hero);
|
||||
|
||||
if(which < PrimarySkill::EXPERIENCE)
|
||||
{
|
||||
Bonus *skill = hero->getBonusLocalFirst(Selector::type(Bonus::PRIMARY_SKILL)
|
||||
.And(Selector::subtype(which))
|
||||
.And(Selector::sourceType(Bonus::HERO_BASE_SKILL)));
|
||||
assert(skill);
|
||||
|
||||
if(abs)
|
||||
skill->val = val;
|
||||
else
|
||||
skill->val += val;
|
||||
}
|
||||
else if(which == PrimarySkill::EXPERIENCE)
|
||||
{
|
||||
if(abs)
|
||||
hero->exp = val;
|
||||
else
|
||||
hero->exp += val;
|
||||
}
|
||||
hero->setPrimarySkill(which, val, abs);
|
||||
}
|
||||
|
||||
DLL_LINKAGE void SetSecSkill::applyGs( CGameState *gs )
|
||||
@ -1020,25 +1001,8 @@ DLL_LINKAGE void SetHoverName::applyGs( CGameState *gs )
|
||||
|
||||
DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
|
||||
{
|
||||
CGHeroInstance* h = gs->getHero(hero->id);
|
||||
h->level = level;
|
||||
//deterministic secondary skills
|
||||
h->skillsInfo.magicSchoolCounter = (h->skillsInfo.magicSchoolCounter + 1) % h->maxlevelsToMagicSchool();
|
||||
h->skillsInfo.wisdomCounter = (h->skillsInfo.wisdomCounter + 1) % h->maxlevelsToWisdom();
|
||||
if (vstd::contains(skills, SecondarySkill::WISDOM))
|
||||
h->skillsInfo.resetWisdomCounter();
|
||||
SecondarySkill spellSchools[] = {
|
||||
SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC};
|
||||
for (auto skill : spellSchools)
|
||||
{
|
||||
if (vstd::contains(skills, skill))
|
||||
{
|
||||
h->skillsInfo.resetMagicSchoolCounter();
|
||||
break;
|
||||
}
|
||||
}
|
||||
//specialty
|
||||
h->Updatespecialty();
|
||||
CGHeroInstance * h = gs->getHero(hero->id);
|
||||
h->levelUp(skills);
|
||||
}
|
||||
|
||||
DLL_LINKAGE void CommanderLevelUp::applyGs (CGameState *gs)
|
||||
|
@ -107,6 +107,7 @@
|
||||
<Unit filename="CObjectHandler.h" />
|
||||
<Unit filename="CObstacleInstance.cpp" />
|
||||
<Unit filename="CObstacleInstance.h" />
|
||||
<Unit filename="CRandomGenerator.cpp" />
|
||||
<Unit filename="CRandomGenerator.h" />
|
||||
<Unit filename="CScriptingModule.h" />
|
||||
<Unit filename="CSpellHandler.cpp" />
|
||||
|
@ -185,6 +185,7 @@
|
||||
<ClCompile Include="CSpellHandler.cpp" />
|
||||
<ClCompile Include="CThreadHelper.cpp" />
|
||||
<ClCompile Include="CTownHandler.cpp" />
|
||||
<ClCompile Include="CRandomGenerator.cpp" />
|
||||
<ClCompile Include="filesystem\AdapterLoaders.cpp" />
|
||||
<ClCompile Include="filesystem\CArchiveLoader.cpp" />
|
||||
<ClCompile Include="filesystem\CBinaryReader.cpp" />
|
||||
@ -323,4 +324,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -39,6 +39,7 @@
|
||||
<ClCompile Include="CCreatureSet.cpp" />
|
||||
<ClCompile Include="CGameState.cpp" />
|
||||
<ClCompile Include="Connection.cpp" />
|
||||
<ClCompile Include="CRandomGenerator.cpp" />
|
||||
<ClCompile Include="HeroBonus.cpp" />
|
||||
<ClCompile Include="IGameCallback.cpp" />
|
||||
<ClCompile Include="NetPacksLib.cpp" />
|
||||
@ -393,4 +394,4 @@
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -183,31 +183,21 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
|
||||
return;
|
||||
}
|
||||
|
||||
//give prim skill
|
||||
logGlobal->traceStream() << hero->name <<" got level "<<hero->level;
|
||||
int r = rand()%100, pom=0, x=0;
|
||||
// give primary skill
|
||||
logGlobal->traceStream() << hero->name << " got level "<< hero->level;
|
||||
auto primarySkill = hero->nextPrimarySkill();
|
||||
|
||||
auto & skillChances = (hero->level>9) ? hero->type->heroClass->primarySkillLowLevel : hero->type->heroClass->primarySkillHighLevel;
|
||||
|
||||
for(;x<GameConstants::PRIMARY_SKILLS;x++)
|
||||
{
|
||||
pom += skillChances[x];
|
||||
if(r<pom)
|
||||
break;
|
||||
}
|
||||
logGlobal->traceStream() << "The hero gets the primary skill with the no. " << x << " with a probability of " << r << "%.";
|
||||
SetPrimSkill sps;
|
||||
sps.id = hero->id;
|
||||
sps.which = static_cast<PrimarySkill::PrimarySkill>(x);
|
||||
sps.which = primarySkill;
|
||||
sps.abs = false;
|
||||
sps.val = 1;
|
||||
sendAndApply(&sps);
|
||||
|
||||
HeroLevelUp hlu;
|
||||
hlu.hero = hero;
|
||||
hlu.primskill = static_cast<PrimarySkill::PrimarySkill>(x);
|
||||
hlu.level = hero->level+1;
|
||||
hlu.skills = hero->levelUpProposedSkills();
|
||||
hlu.primskill = primarySkill;
|
||||
hlu.skills = hero->getLevelUpProposedSecondarySkills();
|
||||
|
||||
if(hlu.skills.size() == 0)
|
||||
{
|
||||
@ -217,11 +207,7 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
|
||||
else if(hlu.skills.size() == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
|
||||
{
|
||||
sendAndApply(&hlu);
|
||||
auto rng = [&]() mutable -> ui32
|
||||
{
|
||||
return hero->skillsInfo.distribution(); //must be determined
|
||||
};
|
||||
levelUpHero(hero, vstd::pickRandomElementOf (hlu.skills, rng));
|
||||
levelUpHero(hero, *RandomGeneratorUtil::nextItem(hlu.skills, hero->skillsInfo.rand));
|
||||
}
|
||||
else if(hlu.skills.size() > 1)
|
||||
{
|
||||
@ -359,7 +345,7 @@ void CGameHandler::levelUpCommander(const CCommanderInstance * c)
|
||||
else if(skillAmount == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
|
||||
{
|
||||
sendAndApply(&clu);
|
||||
levelUpCommander(c, vstd::pickRandomElementOf (clu.skills, rand));
|
||||
levelUpCommander(c, *RandomGeneratorUtil::nextItem(clu.skills, gs->getRandomGenerator()));
|
||||
}
|
||||
else if(skillAmount > 1) //apply and ask for secondary skill
|
||||
{
|
||||
@ -520,7 +506,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) && rand() % 100 < eagleEyeChance)
|
||||
if(sp->level <= maxLevel && !vstd::contains(finishingBattle->winnerHero->spells, sp->id) && gs->getRandomGenerator().nextInt(99) < eagleEyeChance)
|
||||
cs.spells.insert(sp->id);
|
||||
}
|
||||
}
|
||||
@ -754,20 +740,20 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
|
||||
|
||||
if(!vstd::contains_if(gs->curB->sides, sideHeroBlocksLuck))
|
||||
{
|
||||
if(attackerLuck > 0 && rand()%24 < attackerLuck)
|
||||
if(attackerLuck > 0 && gs->getRandomGenerator().nextInt(23) < attackerLuck)
|
||||
{
|
||||
bat.flags |= BattleAttack::LUCKY;
|
||||
}
|
||||
if (VLC->modh->settings.data["hardcodedFeatures"]["NEGATIVE_LUCK"].Bool()) // negative luck enabled
|
||||
{
|
||||
if (attackerLuck < 0 && rand()%24 < abs(attackerLuck))
|
||||
if (attackerLuck < 0 && gs->getRandomGenerator().nextInt(23) < abs(attackerLuck))
|
||||
{
|
||||
bat.flags |= BattleAttack::UNLUCKY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rand()%100 < att->valOfBonuses(Bonus::DOUBLE_DAMAGE_CHANCE))
|
||||
if(gs->getRandomGenerator().nextInt(99) < att->valOfBonuses(Bonus::DOUBLE_DAMAGE_CHANCE))
|
||||
{
|
||||
bat.flags |= BattleAttack::DEATH_BLOW;
|
||||
}
|
||||
@ -777,7 +763,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 > rand() % 100)
|
||||
if(chance > gs->getRandomGenerator().nextInt(99))
|
||||
{
|
||||
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
||||
}
|
||||
@ -823,8 +809,9 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
|
||||
bsa.flags |= BattleStackAttacked::SECONDARY; //all other targets do not suffer from spells & spell-like abilities
|
||||
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, gameState()->getRandomGenerator()); //calculate casualties
|
||||
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
|
||||
|
||||
//life drain handling
|
||||
if (att->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
||||
@ -865,7 +852,6 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
|
||||
void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &c)
|
||||
{
|
||||
setThreadName("CGameHandler::handleConnection");
|
||||
srand(time(nullptr));
|
||||
|
||||
try
|
||||
{
|
||||
@ -1089,6 +1075,9 @@ void CGameHandler::init(StartInfo *si)
|
||||
gs->init(si);
|
||||
logGlobal->infoStream() << "Gamestate initialized!";
|
||||
|
||||
// reset seed, so that clients can't predict any following random values
|
||||
gs->getRandomGenerator().resetSeed();
|
||||
|
||||
for(auto & elem : gs->players)
|
||||
{
|
||||
states.addPlayer(elem.first);
|
||||
@ -1123,15 +1112,20 @@ void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=fa
|
||||
return;
|
||||
}
|
||||
|
||||
ui32 dwellpos = rand()%dwellings.size();//take random dwelling
|
||||
ui32 creapos = rand()%dwellings.at(dwellpos)->creatures.size();//for multi-creature dwellings like Golem Factory
|
||||
CreatureID creature = dwellings.at(dwellpos)->creatures.at(creapos).second[0];
|
||||
auto dwelling = *RandomGeneratorUtil::nextItem(dwellings, gs->getRandomGenerator());
|
||||
|
||||
if (clear)
|
||||
ssi.creatures[GameConstants::CREATURES_PER_TOWN].first = std::max((ui32)1, (VLC->creh->creatures.at(creature)->growth)/2);
|
||||
// for multi-creature dwellings like Golem Factory
|
||||
auto creatureId = RandomGeneratorUtil::nextItem(dwelling->creatures, gs->getRandomGenerator())->second[0];
|
||||
|
||||
if(clear)
|
||||
{
|
||||
ssi.creatures[GameConstants::CREATURES_PER_TOWN].first = std::max((ui32)1, (VLC->creh->creatures.at(creatureId)->growth)/2);
|
||||
}
|
||||
else
|
||||
ssi.creatures[GameConstants::CREATURES_PER_TOWN].first = VLC->creh->creatures.at(creature)->growth;
|
||||
ssi.creatures[GameConstants::CREATURES_PER_TOWN].second.push_back(creature);
|
||||
{
|
||||
ssi.creatures[GameConstants::CREATURES_PER_TOWN].first = VLC->creh->creatures.at(creatureId)->growth;
|
||||
}
|
||||
ssi.creatures[GameConstants::CREATURES_PER_TOWN].second.push_back(creatureId);
|
||||
sendAndApply(&ssi);
|
||||
}
|
||||
}
|
||||
@ -1149,7 +1143,6 @@ void CGameHandler::newTurn()
|
||||
bool newMonth = getDate(Date::DAY_OF_MONTH) == 28;
|
||||
|
||||
std::map<PlayerColor, si32> hadGold;//starting gold - for buildings like dwarven treasury
|
||||
srand(time(nullptr));
|
||||
|
||||
if (firstTurn)
|
||||
{
|
||||
@ -1182,7 +1175,7 @@ void CGameHandler::newTurn()
|
||||
}
|
||||
else
|
||||
{
|
||||
int monthType = rand()%100;
|
||||
int monthType = gs->getRandomGenerator().nextInt(99);
|
||||
if(newMonth) //new month
|
||||
{
|
||||
if (monthType < 40) //double growth
|
||||
@ -1196,7 +1189,7 @@ void CGameHandler::newTurn()
|
||||
else if(VLC->creh->doubledCreatures.size())
|
||||
{
|
||||
const std::vector<CreatureID> doubledCreatures (VLC->creh->doubledCreatures.begin(), VLC->creh->doubledCreatures.end());
|
||||
n.creatureid = vstd::pickRandomElementOf(doubledCreatures, []{ return rand(); });
|
||||
n.creatureid = *RandomGeneratorUtil::nextItem(doubledCreatures, gs->getRandomGenerator());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1427,12 +1420,12 @@ void CGameHandler::newTurn()
|
||||
if (newMonth)
|
||||
{
|
||||
iw.text.addTxt(MetaString::ARRAY_TXT, (130));
|
||||
iw.text.addReplacement(MetaString::ARRAY_TXT, 32 + rand()%10);
|
||||
iw.text.addReplacement(MetaString::ARRAY_TXT, gs->getRandomGenerator().nextInt(32, 41));
|
||||
}
|
||||
else
|
||||
{
|
||||
iw.text.addTxt(MetaString::ARRAY_TXT, (133));
|
||||
iw.text.addReplacement(MetaString::ARRAY_TXT, 43 + rand()%15);
|
||||
iw.text.addReplacement(MetaString::ARRAY_TXT, gs->getRandomGenerator().nextInt(43, 57));
|
||||
}
|
||||
}
|
||||
for (auto & elem : gs->players)
|
||||
@ -3592,7 +3585,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
{
|
||||
if(currentHP.at(attackedPart) != EWallState::DESTROYED && // this part can be hit
|
||||
currentHP.at(attackedPart) != EWallState::NONE &&
|
||||
rand()%100 < getCatapultHitChance(attackedPart, sbi))//hit is successful
|
||||
gs->getRandomGenerator().nextInt(99) < getCatapultHitChance(attackedPart, sbi))//hit is successful
|
||||
{
|
||||
hitSuccessfull = true;
|
||||
}
|
||||
@ -3607,7 +3600,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
}
|
||||
if (allowedTargets.empty())
|
||||
break;
|
||||
attackedPart = allowedTargets.at(rand()%allowedTargets.size());
|
||||
attackedPart = *RandomGeneratorUtil::nextItem(allowedTargets, gs->getRandomGenerator());
|
||||
}
|
||||
}
|
||||
while (!hitSuccessfull);
|
||||
@ -3623,7 +3616,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 = rand()%100;
|
||||
int dmgRand = gs->getRandomGenerator().nextInt(99);
|
||||
//accumulating dmgChance
|
||||
dmgChance[1] += dmgChance[0];
|
||||
dmgChance[2] += dmgChance[1];
|
||||
@ -4071,7 +4064,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
|
||||
}
|
||||
|
||||
//checking if creatures resist
|
||||
sc.resisted = gs->curB->calculateResistedStacks(spell, caster, secHero, attackedCres, casterColor, mode, usedSpellPower, spellLvl);
|
||||
sc.resisted = gs->curB->calculateResistedStacks(spell, caster, secHero, attackedCres, casterColor, mode, usedSpellPower, spellLvl, gs->getRandomGenerator());
|
||||
|
||||
//calculating dmg to display
|
||||
if (spellID == SpellID::DEATH_STARE || spellID == SpellID::ACID_BREATH_DAMAGE)
|
||||
@ -4465,7 +4458,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
|
||||
for(auto & attackedCre : attackedCres)
|
||||
{
|
||||
int mirrorChance = (attackedCre)->valOfBonuses(Bonus::MAGIC_MIRROR);
|
||||
if(mirrorChance > rand()%100)
|
||||
if(mirrorChance > gs->getRandomGenerator().nextInt(99))
|
||||
{
|
||||
std::vector<CStack *> mirrorTargets;
|
||||
std::vector<CStack *> & battleStacks = gs->curB->stacks;
|
||||
@ -4479,7 +4472,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
|
||||
}
|
||||
if (!mirrorTargets.empty())
|
||||
{
|
||||
int targetHex = mirrorTargets.at(rand() % mirrorTargets.size())->position;
|
||||
int targetHex = (*RandomGeneratorUtil::nextItem(mirrorTargets, gs->getRandomGenerator()))->position;
|
||||
handleSpellCasting(spellID, 0, targetHex, 1 - casterSide, (attackedCre)->owner, nullptr, (caster ? caster : nullptr), usedSpellPower, ECastingMode::MAGIC_MIRROR, (attackedCre));
|
||||
}
|
||||
}
|
||||
@ -4652,7 +4645,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
|
||||
}
|
||||
if (fearsomeCreature)
|
||||
{
|
||||
if (rand() % 100 < 10) //fixed 10%
|
||||
if (gs->getRandomGenerator().nextInt(99) < 10) //fixed 10%
|
||||
{
|
||||
bte.effect = Bonus::FEAR;
|
||||
sendAndApply(&bte);
|
||||
@ -4663,18 +4656,18 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
|
||||
int side = gs->curB->whatSide(st->owner);
|
||||
if (bl.size() && st->casts && !gs->curB->sides.at(side).enchanterCounter)
|
||||
{
|
||||
int index = rand() % bl.size();
|
||||
SpellID spellID = SpellID(bl[index]->subtype);
|
||||
auto bonus = *RandomGeneratorUtil::nextItem(bl, gs->getRandomGenerator());
|
||||
auto spellID = SpellID(bonus->subtype);
|
||||
if (gs->curB->battleCanCastThisSpell(st->owner, SpellID(spellID).toSpell(), ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK) //TODO: select another available?
|
||||
{
|
||||
int spellLeveL = bl[index]->val; //spell level
|
||||
int spellLeveL = bonus->val; //spell level
|
||||
const CGHeroInstance * enemyHero = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
|
||||
handleSpellCasting(spellID, spellLeveL, -1, side, st->owner, nullptr, enemyHero, 0, ECastingMode::ENCHANTER_CASTING, st);
|
||||
|
||||
BattleSetStackProperty ssp;
|
||||
ssp.which = BattleSetStackProperty::ENCHANTER_COUNTER;
|
||||
ssp.absolute = false;
|
||||
ssp.val = bl[index]->additionalInfo; //increase cooldown counter
|
||||
ssp.val = bonus->additionalInfo; //increase cooldown counter
|
||||
ssp.stackID = st->ID;
|
||||
sendAndApply(&ssp);
|
||||
}
|
||||
@ -5345,7 +5338,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
|
||||
continue;
|
||||
|
||||
//check if spell should be casted (probability handling)
|
||||
if(rand()%100 >= chance)
|
||||
if(gs->getRandomGenerator().nextInt(99) >= chance)
|
||||
continue;
|
||||
|
||||
//casting //TODO: check if spell can be blocked or target is immune
|
||||
@ -5383,10 +5376,10 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
double chanceToKill = attacker->valOfBonuses(Bonus::DEATH_STARE, 0) / 100.0f;
|
||||
vstd::amin(chanceToKill, 1); //cap at 100%
|
||||
|
||||
std::binomial_distribution<> distr(attacker->count, chanceToKill);
|
||||
std::mt19937 rng(rand());
|
||||
std::binomial_distribution<> distribution(attacker->count, chanceToKill);
|
||||
std::mt19937 rng(std::time(nullptr));
|
||||
|
||||
int staredCreatures = distr(rng);
|
||||
int staredCreatures = distribution(rng);
|
||||
|
||||
double cap = 1 / std::max(chanceToKill, (double)(0.01));//don't divide by 0
|
||||
int maxToKill = (attacker->count + cap - 1) / cap; //not much more than chance * count
|
||||
@ -5405,7 +5398,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
TBonusListPtr acidBreath = attacker->getBonuses(Selector::type(Bonus::ACID_BREATH));
|
||||
for(const Bonus *b : *acidBreath)
|
||||
{
|
||||
if (b->additionalInfo > rand()%100)
|
||||
if (b->additionalInfo > gs->getRandomGenerator().nextInt(99))
|
||||
acidDamage += b->val;
|
||||
}
|
||||
if (acidDamage)
|
||||
@ -5439,7 +5432,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, SpellID spellID, const int
|
||||
case SpellID::SUMMON_BOAT:
|
||||
{
|
||||
//check if spell works at all
|
||||
if(rand() % 100 >= s->getPower(schoolLevel)) //power is % chance of success
|
||||
if(gs->getRandomGenerator().nextInt(99) >= s->getPower(schoolLevel)) //power is % chance of success
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = h->tempOwner;
|
||||
@ -5501,7 +5494,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, SpellID spellID, const int
|
||||
case SpellID::SCUTTLE_BOAT:
|
||||
{
|
||||
//check if spell works at all
|
||||
if(rand() % 100 >= s->getPower(schoolLevel)) //power is % chance of success
|
||||
if(gs->getRandomGenerator().nextInt(99) >= s->getPower(schoolLevel)) //power is % chance of success
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = h->tempOwner;
|
||||
@ -5918,7 +5911,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( rand()%24 < -2 * nextStackMorale)
|
||||
if(gs->getRandomGenerator().nextInt(23) < -2 * nextStackMorale)
|
||||
{
|
||||
//unit loses its turn - empty freeze action
|
||||
BattleAction ba;
|
||||
@ -5983,7 +5976,7 @@ void CGameHandler::runBattle()
|
||||
if(!attackableBattleHexes.empty())
|
||||
{
|
||||
BattleAction attack;
|
||||
attack.destinationTile = attackableBattleHexes[rand() % attackableBattleHexes.size()];
|
||||
attack.destinationTile = *RandomGeneratorUtil::nextItem(attackableBattleHexes, gs->getRandomGenerator());
|
||||
attack.actionType = Battle::CATAPULT;
|
||||
attack.additionalInfo = 0;
|
||||
attack.side = !next->attackerOwned;
|
||||
@ -6077,7 +6070,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(rand()%24 < nextStackMorale) //this stack hasn't got morale this turn
|
||||
if(gs->getRandomGenerator().nextInt(23) < nextStackMorale) //this stack hasn't got morale this turn
|
||||
|
||||
{
|
||||
BattleTriggerEffect bte;
|
||||
|
@ -8,7 +8,6 @@
|
||||
//#include <boost/interprocess/shared_memory_object.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <boost/random/poisson_distribution.hpp>
|
||||
#include <boost/random/variate_generator.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
//#include <boost/asio.hpp>
|
||||
|
Loading…
Reference in New Issue
Block a user