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
|
*.layout
|
||||||
*.pro.user
|
*.pro.user
|
||||||
*.pro.user.*
|
*.pro.user.*
|
||||||
|
/CMakeLists.txt.user
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CEmptyAI.h"
|
#include "CEmptyAI.h"
|
||||||
|
|
||||||
|
#include "CRandomGenerator.h"
|
||||||
|
|
||||||
void CEmptyAI::init(shared_ptr<CCallback> CB)
|
void CEmptyAI::init(shared_ptr<CCallback> CB)
|
||||||
{
|
{
|
||||||
cb = 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)
|
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)
|
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)
|
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)
|
if(stack->type->idNumber == CreatureID::CATAPULT)
|
||||||
{
|
{
|
||||||
BattleAction attack;
|
BattleAction attack;
|
||||||
static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
|
static const std::vector<int> wallHexes = boost::assign::list_of(50)(183)(182)(130)(62)(29)(12)(95);
|
||||||
attack.destinationTile = wallHexes[ rand()%ARRAY_COUNT(wallHexes) ];
|
|
||||||
|
attack.destinationTile = *RandomGeneratorUtil::nextItem(wallHexes, CRandomGenerator::getDefault());
|
||||||
attack.actionType = Battle::CATAPULT;
|
attack.actionType = Battle::CATAPULT;
|
||||||
attack.additionalInfo = 0;
|
attack.additionalInfo = 0;
|
||||||
attack.side = side;
|
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>
|
template<typename T>
|
||||||
void advance(T &obj, int change)
|
void advance(T &obj, int change)
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
||||||
#include "../lib/JsonNode.h"
|
#include "../lib/JsonNode.h"
|
||||||
|
#include "../lib/CRandomGenerator.h"
|
||||||
|
|
||||||
#include "CBitmapHandler.h"
|
#include "CBitmapHandler.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
@ -1432,7 +1433,7 @@ void CCreatureAnim::loopPreview(bool warMachine)
|
|||||||
if (anim.size(elem))
|
if (anim.size(elem))
|
||||||
available.push_back(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())
|
if (rnd >= available.size())
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/StringConstants.h"
|
#include "../lib/StringConstants.h"
|
||||||
|
#include "../lib/CRandomGenerator.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CMusicHandler.cpp, part of VCMI engine
|
* 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
|
// Helper. Randomly select a sound from an array and play it
|
||||||
int CSoundHandler::playSoundFromSet(std::vector<soundBase::soundID> &sound_vec)
|
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 )
|
void CSoundHandler::stopSound( int handler )
|
||||||
@ -504,10 +505,7 @@ bool MusicEntry::play()
|
|||||||
if (!setName.empty())
|
if (!setName.empty())
|
||||||
{
|
{
|
||||||
auto set = owner->musicsSet[setName];
|
auto set = owner->musicsSet[setName];
|
||||||
size_t entryID = rand() % set.size();
|
load(RandomGeneratorUtil::nextItem(set, CRandomGenerator::getDefault())->second);
|
||||||
auto iterator = set.begin();
|
|
||||||
std::advance(iterator, entryID);
|
|
||||||
load(iterator->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logGlobal->traceStream()<<"Playing music file "<<currentName;
|
logGlobal->traceStream()<<"Playing music file "<<currentName;
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "gui/CIntObjectClasses.h"
|
#include "gui/CIntObjectClasses.h"
|
||||||
#include "../lib/mapping/CMapService.h"
|
#include "../lib/mapping/CMapService.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
|
#include "../lib/CRandomGenerator.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CPreGame.cpp, part of VCMI engine
|
* CPreGame.cpp, part of VCMI engine
|
||||||
@ -607,7 +608,7 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
|||||||
bordered = true;
|
bordered = true;
|
||||||
//load random background
|
//load random background
|
||||||
const JsonVector & bgNames = CGPreGameConfig::get().getConfig()["game-select"].Vector();
|
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();
|
pos = bg->center();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4136,7 +4137,7 @@ std::string CLoadingScreen::getBackground()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return conf[ rand() % conf.size() ].String();
|
return RandomGeneratorUtil::nextItem(conf, CRandomGenerator::getDefault())->String();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "../CVideoHandler.h"
|
#include "../CVideoHandler.h"
|
||||||
#include "../../lib/CTownHandler.h"
|
#include "../../lib/CTownHandler.h"
|
||||||
#include "../../lib/mapping/CMap.h"
|
#include "../../lib/mapping/CMap.h"
|
||||||
|
#include "../../lib/CRandomGenerator.h"
|
||||||
|
|
||||||
#include "CBattleAnimations.h"
|
#include "CBattleAnimations.h"
|
||||||
#include "CBattleInterfaceClasses.h"
|
#include "CBattleInterfaceClasses.h"
|
||||||
@ -59,7 +60,7 @@ static void onAnimationFinished(const CStack *stack, CCreatureAnimation * anim)
|
|||||||
|
|
||||||
if (anim->framesInGroup(CCreatureAnim::MOUSEON) > 0)
|
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);
|
anim->playOnce(CCreatureAnim::MOUSEON);
|
||||||
else
|
else
|
||||||
anim->setType(CCreatureAnim::HOLDING);
|
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!";
|
logGlobal->errorStream() << bfieldType << " battlefield type does not have any backgrounds!";
|
||||||
else
|
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);
|
background = BitmapHandler::loadBitmap(bgName, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "../lib/CStopWatch.h"
|
#include "../lib/CStopWatch.h"
|
||||||
#include "CMT.h"
|
#include "CMT.h"
|
||||||
|
#include "../lib/CRandomGenerator.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mapHandler.cpp, part of VCMI engine
|
* mapHandler.cpp, part of VCMI engine
|
||||||
@ -129,7 +130,7 @@ void CMapHandler::prepareFOWDefs()
|
|||||||
elem[j].resize(sizes.z);
|
elem[j].resize(sizes.z);
|
||||||
for(int k = 0; k < sizes.z; ++k)
|
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;
|
int terBitmapNum = -1;
|
||||||
|
|
||||||
|
auto & rand = CRandomGenerator::getDefault();
|
||||||
|
|
||||||
if(i==-1 && j==-1)
|
if(i==-1 && j==-1)
|
||||||
terBitmapNum = 16;
|
terBitmapNum = 16;
|
||||||
else if(i==-1 && j==(sizes.y))
|
else if(i==-1 && j==(sizes.y))
|
||||||
@ -208,15 +211,15 @@ void CMapHandler::borderAndTerrainBitmapInit()
|
|||||||
else if(i==(sizes.x) && j==(sizes.y))
|
else if(i==(sizes.x) && j==(sizes.y))
|
||||||
terBitmapNum = 18;
|
terBitmapNum = 18;
|
||||||
else if(j == -1 && i > -1 && i < sizes.y)
|
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)
|
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)
|
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)
|
else if(i == sizes.x && j > -1 && j < sizes.y)
|
||||||
terBitmapNum = 25+rand()%2;
|
terBitmapNum = rand.nextInt(25, 26);
|
||||||
else
|
else
|
||||||
terBitmapNum = rand()%16;
|
terBitmapNum = rand.nextInt(15);
|
||||||
|
|
||||||
if(terBitmapNum != -1)
|
if(terBitmapNum != -1)
|
||||||
{
|
{
|
||||||
@ -1083,7 +1086,7 @@ ui8 CMapHandler::getPhaseShift(const CGObjectInstance *object) const
|
|||||||
auto i = animationPhase.find(object);
|
auto i = animationPhase.find(object);
|
||||||
if(i == animationPhase.end())
|
if(i == animationPhase.end())
|
||||||
{
|
{
|
||||||
ui8 ret = rand() % 255;
|
ui8 ret = CRandomGenerator::getDefault().nextInt(254);
|
||||||
animationPhase[object] = ret;
|
animationPhase[object] = ret;
|
||||||
return 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,
|
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);
|
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);
|
int howManyToAv = std::min<ui32>(10, attacker->count);
|
||||||
for (int g=0; g<howManyToAv; ++g)
|
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;
|
return std::accumulate(valuesToAverage, valuesToAverage + howManyToAv, 0) / howManyToAv;
|
||||||
@ -723,7 +723,9 @@ const CGHeroInstance * BattleInfo::getHero( PlayerColor player ) const
|
|||||||
return nullptr;
|
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;
|
std::vector<ui32> ret;
|
||||||
for(auto & affectedCreature : affectedCreatures)
|
for(auto & affectedCreature : affectedCreatures)
|
||||||
@ -749,8 +751,11 @@ std::vector<ui32> BattleInfo::calculateResistedStacks(const CSpell * sp, const C
|
|||||||
|
|
||||||
if(prob > 100) prob = 100;
|
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);
|
ret.push_back((affectedCreature)->ID);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
|||||||
shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
|
shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
|
||||||
std::set<BattleHex> getStoppers(bool whichSidePerspective) 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 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
|
//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
|
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 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
|
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())
|
if(!possibleSpells.empty())
|
||||||
return possibleSpells[rand() % possibleSpells.size()];
|
{
|
||||||
|
return *RandomGeneratorUtil::nextItem(possibleSpells, gs->getRandomGenerator());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return SpellID::NONE;
|
return SpellID::NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SpellID CBattleInfoCallback::getRandomCastedSpell(const CStack * caster) const
|
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
|
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)
|
for(Bonus * b : *bl)
|
||||||
{
|
{
|
||||||
randomPos -= std::max(b->additionalInfo, 1);
|
randomPos -= std::max(b->additionalInfo, 1);
|
||||||
|
@ -458,7 +458,7 @@ public:
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
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
|
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;
|
int totalProb = 0;
|
||||||
for(auto & possible : possibles)
|
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)
|
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)
|
for(auto & possible : possibles)
|
||||||
{
|
{
|
||||||
ran -= secSkillProbability[possible];
|
ran -= secSkillProbability[possible];
|
||||||
if(ran<0)
|
if(ran < 0)
|
||||||
|
{
|
||||||
return possible;
|
return possible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME: select randomly? How H3 handles such rare situation?
|
// FIXME: select randomly? How H3 handles such rare situation?
|
||||||
|
@ -21,6 +21,7 @@ class CGameInfo;
|
|||||||
class CGHeroInstance;
|
class CGHeroInstance;
|
||||||
struct BattleHex;
|
struct BattleHex;
|
||||||
class JsonNode;
|
class JsonNode;
|
||||||
|
class CRandomGenerator;
|
||||||
|
|
||||||
struct SSpecialtyInfo
|
struct SSpecialtyInfo
|
||||||
{ si32 type;
|
{ si32 type;
|
||||||
@ -132,7 +133,7 @@ public:
|
|||||||
CHeroClass();
|
CHeroClass();
|
||||||
|
|
||||||
bool isMagicHero() const;
|
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)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
|
@ -68,6 +68,7 @@ set(lib_SRCS
|
|||||||
CHeroHandler.cpp
|
CHeroHandler.cpp
|
||||||
CModHandler.cpp
|
CModHandler.cpp
|
||||||
CObstacleInstance.cpp
|
CObstacleInstance.cpp
|
||||||
|
CRandomGenerator.cpp
|
||||||
CSpellHandler.cpp
|
CSpellHandler.cpp
|
||||||
CThreadHelper.cpp
|
CThreadHelper.cpp
|
||||||
CTownHandler.cpp
|
CTownHandler.cpp
|
||||||
@ -91,7 +92,6 @@ set(lib_HEADERS
|
|||||||
CondSh.h
|
CondSh.h
|
||||||
ConstTransitivePtr.h
|
ConstTransitivePtr.h
|
||||||
CBonusTypeHandler.h
|
CBonusTypeHandler.h
|
||||||
CRandomGenerator.h
|
|
||||||
CScriptingModule.h
|
CScriptingModule.h
|
||||||
CStopWatch.h
|
CStopWatch.h
|
||||||
FunctionList.h
|
FunctionList.h
|
||||||
|
@ -767,17 +767,14 @@ void CGHeroInstance::initHero()
|
|||||||
}
|
}
|
||||||
assert(validTypes());
|
assert(validTypes());
|
||||||
|
|
||||||
if (exp == 0xffffffff)
|
level = 1;
|
||||||
|
if(exp == 0xffffffff)
|
||||||
{
|
{
|
||||||
initExp();
|
initExp();
|
||||||
}
|
}
|
||||||
else if (ID != Obj::PRISON)
|
else
|
||||||
{
|
{
|
||||||
level = VLC->heroh->level(exp);
|
levelUpAutomatically();
|
||||||
}
|
|
||||||
else //warp hero at the beginning of next turn
|
|
||||||
{
|
|
||||||
level = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VLC->modh->modules.COMMANDERS && !commander)
|
if (VLC->modh->modules.COMMANDERS && !commander)
|
||||||
@ -953,7 +950,7 @@ void CGHeroInstance::initObj()
|
|||||||
if(!type)
|
if(!type)
|
||||||
initHero(); //TODO: set up everything for prison before specialties are configured
|
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.resetMagicSchoolCounter();
|
||||||
skillsInfo.resetWisdomCounter();
|
skillsInfo.resetWisdomCounter();
|
||||||
|
|
||||||
@ -1552,7 +1549,6 @@ EAlignment::EAlignment CGHeroInstance::getAlignment() const
|
|||||||
void CGHeroInstance::initExp()
|
void CGHeroInstance::initExp()
|
||||||
{
|
{
|
||||||
exp = cb->gameState()->getRandomGenerator().nextInt(40, 89);
|
exp = cb->gameState()->getRandomGenerator().nextInt(40, 89);
|
||||||
level = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CGHeroInstance::nodeName() const
|
std::string CGHeroInstance::nodeName() const
|
||||||
@ -1630,7 +1626,7 @@ ArtBearer::ArtBearer CGHeroInstance::bearerType() const
|
|||||||
return ArtBearer::HERO;
|
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
|
std::vector<SecondarySkill> obligatorySkills; //hero is offered magic school or wisdom if possible
|
||||||
if (!skillsInfo.wisdomCounter)
|
if (!skillsInfo.wisdomCounter)
|
||||||
@ -1643,11 +1639,7 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
|||||||
std::vector<SecondarySkill> ss;
|
std::vector<SecondarySkill> ss;
|
||||||
ss += SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC;
|
ss += SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC;
|
||||||
|
|
||||||
auto rng = [=](ui32 val) mutable -> ui32
|
std::shuffle(ss.begin(), ss.end(), skillsInfo.rand.getStdGenerator());
|
||||||
{
|
|
||||||
return skillsInfo.distribution() % val; //must be determined
|
|
||||||
};
|
|
||||||
std::random_shuffle(ss.begin(), ss.end(), rng);
|
|
||||||
|
|
||||||
for (auto skill : ss)
|
for (auto skill : ss)
|
||||||
{
|
{
|
||||||
@ -1691,12 +1683,12 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
|||||||
}
|
}
|
||||||
else if(none.size() && canLearnSkill()) //hero have free skill slot
|
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());
|
none.erase(skills.back());
|
||||||
}
|
}
|
||||||
else if(!basicAndAdv.empty())
|
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());
|
basicAndAdv.erase(skills.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1706,7 +1698,7 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
|||||||
//3) give any other new skill
|
//3) give any other new skill
|
||||||
if(!basicAndAdv.empty())
|
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);
|
skills.push_back(s);
|
||||||
basicAndAdv.erase(s);
|
basicAndAdv.erase(s);
|
||||||
}
|
}
|
||||||
@ -1716,18 +1708,147 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
|||||||
}
|
}
|
||||||
else if(none.size() && canLearnSkill())
|
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());
|
none.erase(skills.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
return skills;
|
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
|
bool CGHeroInstance::gainsLevel() const
|
||||||
{
|
{
|
||||||
return exp >= VLC->heroh->reqExp(level+1);
|
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()
|
void CGDwelling::initObj()
|
||||||
{
|
{
|
||||||
switch(ID)
|
switch(ID)
|
||||||
@ -2303,13 +2424,15 @@ void CGTownInstance::newTurn() const
|
|||||||
{
|
{
|
||||||
if (cb->getDate(Date::DAY_OF_WEEK) == 1) //reset on new week
|
if (cb->getDate(Date::DAY_OF_WEEK) == 1) //reset on new week
|
||||||
{
|
{
|
||||||
|
auto & rand = cb->gameState()->getRandomGenerator();
|
||||||
|
|
||||||
//give resources for Rampart, Mystic Pond
|
//give resources for Rampart, Mystic Pond
|
||||||
if (hasBuilt(BuildingID::MYSTIC_POND, ETownType::RAMPART)
|
if (hasBuilt(BuildingID::MYSTIC_POND, ETownType::RAMPART)
|
||||||
&& cb->getDate(Date::DAY) != 1 && (tempOwner < PlayerColor::PLAYER_LIMIT))
|
&& 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;
|
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->giveResource(tempOwner, static_cast<Res::ERes>(resID), resVal);
|
||||||
cb->setObjProperty (id, ObjProperty::BONUS_VALUE_FIRST, resID);
|
cb->setObjProperty (id, ObjProperty::BONUS_VALUE_FIRST, resID);
|
||||||
cb->setObjProperty (id, ObjProperty::BONUS_VALUE_SECOND, resVal);
|
cb->setObjProperty (id, ObjProperty::BONUS_VALUE_SECOND, resVal);
|
||||||
@ -2334,11 +2457,11 @@ void CGTownInstance::newTurn() const
|
|||||||
}
|
}
|
||||||
if (nativeCrits.size())
|
if (nativeCrits.size())
|
||||||
{
|
{
|
||||||
SlotID pos = nativeCrits[rand() % nativeCrits.size()];
|
SlotID pos = *RandomGeneratorUtil::nextItem(nativeCrits, rand);
|
||||||
StackLocation sl(this, pos);
|
StackLocation sl(this, pos);
|
||||||
|
|
||||||
const CCreature *c = getCreature(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);
|
cb->changeStackCount(sl, c->growth);
|
||||||
}
|
}
|
||||||
@ -2347,9 +2470,9 @@ void CGTownInstance::newTurn() const
|
|||||||
cb->changeStackType(sl, VLC->creh->creatures[*c->upgrades.begin()]);
|
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())
|
if (!town->creatures[i].empty())
|
||||||
{
|
{
|
||||||
CreatureID c = town->creatures[i][0];
|
CreatureID c = town->creatures[i][0];
|
||||||
@ -3316,7 +3439,7 @@ void CGCreature::initObj()
|
|||||||
amount = 1;
|
amount = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
formation.randomFormation = rand();
|
formation.randomFormation = cb->gameState()->getRandomGenerator().nextInt();
|
||||||
|
|
||||||
temppower = stacks[SlotID(0)]->count * 1000;
|
temppower = stacks[SlotID(0)]->count * 1000;
|
||||||
refusedJoining = false;
|
refusedJoining = false;
|
||||||
@ -3532,10 +3655,10 @@ void CGCreature::fight( const CGHeroInstance *h ) const
|
|||||||
if (formation.randomFormation % 100 < 50) //upgrade
|
if (formation.randomFormation % 100 < 50) //upgrade
|
||||||
{
|
{
|
||||||
SlotID slotId = SlotID(stacks.size() / 2);
|
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
|
auto it = RandomGeneratorUtil::nextItem(upgrades, cb->gameState()->getRandomGenerator());
|
||||||
std::advance (it, rand() % upgradesSize);
|
|
||||||
cb->changeStackType(StackLocation(this, slotId), VLC->creh->creatures[*it]);
|
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;
|
Component::EComponentType type = Component::RESOURCE;
|
||||||
Res::ERes sub=Res::WOOD;
|
Res::ERes sub=Res::WOOD;
|
||||||
int val=0;
|
int val=0;
|
||||||
|
auto & rand = cb->gameState()->getRandomGenerator();
|
||||||
|
|
||||||
switch (ID)
|
switch (ID)
|
||||||
{
|
{
|
||||||
case Obj::MYSTICAL_GARDEN:
|
case Obj::MYSTICAL_GARDEN:
|
||||||
if (rand()%2)
|
if(rand.nextInt(1) == 1)
|
||||||
{
|
{
|
||||||
sub = Res::GEMS;
|
sub = Res::GEMS;
|
||||||
val = 5;
|
val = 5;
|
||||||
@ -3886,8 +4010,8 @@ void CGVisitableOPW::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
break;
|
break;
|
||||||
case Obj::WINDMILL:
|
case Obj::WINDMILL:
|
||||||
mid = 170;
|
mid = 170;
|
||||||
sub = static_cast<Res::ERes>((rand() % 5) + 1);
|
sub = static_cast<Res::ERes>(rand.nextInt(1, 5));
|
||||||
val = (rand() % 4) + 3;
|
val = rand.nextInt(3, 6);
|
||||||
break;
|
break;
|
||||||
case Obj::WATER_WHEEL:
|
case Obj::WATER_WHEEL:
|
||||||
mid = 164;
|
mid = 164;
|
||||||
@ -3923,16 +4047,27 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
switch(ID)
|
switch(ID)
|
||||||
{
|
{
|
||||||
case Obj::MONOLITH1: //one way - find corresponding exit monolith
|
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())
|
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
|
else
|
||||||
|
{
|
||||||
logGlobal->warnStream() << "Cannot find corresponding exit monolith for "<< id;
|
logGlobal->warnStream() << "Cannot find corresponding exit monolith for "<< id;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Obj::MONOLITH3://two way monolith - pick any other one
|
case Obj::MONOLITH3://two way monolith - pick any other one
|
||||||
case Obj::WHIRLPOOL: //Whirlpool
|
case Obj::WHIRLPOOL: //Whirlpool
|
||||||
if(vstd::contains(objs,ID) && vstd::contains(objs[ID],subID) && objs[ID][subID].size()>1)
|
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 (ID == Obj::WHIRLPOOL)
|
||||||
{
|
{
|
||||||
if (!h->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION))
|
if (!h->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION))
|
||||||
@ -3983,9 +4118,8 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
if (ID == Obj::WHIRLPOOL)
|
if (ID == Obj::WHIRLPOOL)
|
||||||
{
|
{
|
||||||
std::set<int3> tiles = cb->getObj(destinationid)->getBlockedPos();
|
std::set<int3> tiles = cb->getObj(destinationid)->getBlockedPos();
|
||||||
auto it = tiles.begin();
|
auto & tile = *RandomGeneratorUtil::nextItem(tiles, cb->gameState()->getRandomGenerator());
|
||||||
std::advance (it, rand() % tiles.size()); //picking random element of set is tiring
|
cb->moveHero(h->id, tile + int3(1,0,0), true);
|
||||||
cb->moveHero (h->id, *it + int3(1,0,0), true);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cb->moveHero (h->id,CGHeroInstance::convertPosition(cb->getObj(destinationid)->pos,true) - getVisitableOffset(), true);
|
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;
|
messageID = 55;
|
||||||
iw.soundID = soundBase::LUCK;
|
iw.soundID = soundBase::LUCK;
|
||||||
gbonus.bonus.type = Bonus::LUCK;
|
gbonus.bonus.type = Bonus::LUCK;
|
||||||
gbonus.bonus.val = rand()%5 - 1;
|
gbonus.bonus.val = cb->gameState()->getRandomGenerator().nextInt(-1, 3);
|
||||||
descr_id = 69;
|
descr_id = 69;
|
||||||
gbonus.bdescr.addReplacement((gbonus.bonus.val<0 ? "-" : "+") + boost::lexical_cast<std::string>(gbonus.bonus.val));
|
gbonus.bdescr.addReplacement((gbonus.bonus.val<0 ? "-" : "+") + boost::lexical_cast<std::string>(gbonus.bonus.val));
|
||||||
break;
|
break;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "int3.h"
|
#include "int3.h"
|
||||||
#include "GameConstants.h"
|
#include "GameConstants.h"
|
||||||
#include "ResourceSet.h"
|
#include "ResourceSet.h"
|
||||||
|
#include "CRandomGenerator.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CObjectHandler.h, part of VCMI engine
|
* CObjectHandler.h, part of VCMI engine
|
||||||
@ -387,8 +388,8 @@ public:
|
|||||||
struct DLL_LINKAGE SecondarySkillsInfo
|
struct DLL_LINKAGE SecondarySkillsInfo
|
||||||
{
|
{
|
||||||
//skills are determined, initialized at map start
|
//skills are determined, initialized at map start
|
||||||
//FIXME: remove mutable?
|
//FIXME remove mutable
|
||||||
mutable std::minstd_rand distribution;
|
mutable CRandomGenerator rand;
|
||||||
ui8 magicSchoolCounter;
|
ui8 magicSchoolCounter;
|
||||||
ui8 wisdomCounter;
|
ui8 wisdomCounter;
|
||||||
|
|
||||||
@ -397,39 +398,10 @@ public:
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & magicSchoolCounter & wisdomCounter;
|
h & magicSchoolCounter & wisdomCounter & rand;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} skillsInfo;
|
} 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
|
int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
|
||||||
int getSightRadious() const; //sight distance (should be used if player-owned structure)
|
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 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
|
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
|
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
|
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 maxMovePoints(bool onLand) const;
|
||||||
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false) const;
|
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false) const;
|
||||||
@ -470,8 +461,6 @@ public:
|
|||||||
CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
|
CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
|
||||||
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
|
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
|
||||||
ECanDig diggingStatus() const; //0 - can dig; 1 - lack of movement; 2 -
|
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;
|
const std::string & getHoverText() const override;
|
||||||
protected:
|
protected:
|
||||||
void setPropertyDer(ui8 what, ui32 val) override;//synchr
|
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
|
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
|
/// 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
|
/// a given range. This is a header only class and mainly a wrapper for
|
||||||
/// convenient usage of the standard random API.
|
/// convenient usage of the standard random API. An instance of this RNG is not thread safe.
|
||||||
class CRandomGenerator : boost::noncopyable
|
class DLL_LINKAGE CRandomGenerator : boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Seeds the generator with the current time by default.
|
/// Seeds the generator by default with the product of the current time in milliseconds and the
|
||||||
CRandomGenerator()
|
/// current thread ID.
|
||||||
{
|
CRandomGenerator();
|
||||||
rand.seed(static_cast<unsigned long>(std::time(nullptr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSeed(int seed)
|
void setSeed(int seed);
|
||||||
{
|
|
||||||
rand.seed(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.
|
/// Generate several integer numbers within the same range.
|
||||||
/// e.g.: auto a = gen.getIntRange(0,10); a(); a(); a();
|
/// e.g.: auto a = gen.getIntRange(0,10); a(); a(); a();
|
||||||
/// requires: lower <= upper
|
/// requires: lower <= upper
|
||||||
TRandI getIntRange(int lower, int upper)
|
TRandI getIntRange(int lower, int upper);
|
||||||
{
|
|
||||||
return boost::bind(TIntDist(lower, upper), boost::ref(rand));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates an integer between 0 and upper.
|
/// Generates an integer between 0 and upper.
|
||||||
/// requires: 0 <= upper
|
/// requires: 0 <= upper
|
||||||
int nextInt(int upper)
|
int nextInt(int upper);
|
||||||
{
|
|
||||||
return getIntRange(0, upper)();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// requires: lower <= upper
|
/// requires: lower <= upper
|
||||||
int nextInt(int lower, int upper)
|
int nextInt(int lower, int upper);
|
||||||
{
|
|
||||||
return getIntRange(lower, upper)();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates an integer between 0 and the maximum value it can hold.
|
/// Generates an integer between 0 and the maximum value it can hold.
|
||||||
int nextInt()
|
int nextInt();
|
||||||
{
|
|
||||||
return TIntDist()(rand);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate several double/real numbers within the same range.
|
/// Generate several double/real numbers within the same range.
|
||||||
/// e.g.: auto a = gen.getDoubleRange(4.5,10.2); a(); a(); a();
|
/// e.g.: auto a = gen.getDoubleRange(4.5,10.2); a(); a(); a();
|
||||||
/// requires: lower <= upper
|
/// requires: lower <= upper
|
||||||
TRand getDoubleRange(double lower, double upper)
|
TRand getDoubleRange(double lower, double upper);
|
||||||
{
|
|
||||||
return boost::bind(TRealDist(lower, upper), boost::ref(rand));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates a double between 0 and upper.
|
/// Generates a double between 0 and upper.
|
||||||
/// requires: 0 <= upper
|
/// requires: 0 <= upper
|
||||||
double nextDouble(double upper)
|
double nextDouble(double upper);
|
||||||
{
|
|
||||||
return getDoubleRange(0, upper)();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// requires: lower <= upper
|
/// requires: lower <= upper
|
||||||
double nextDouble(double lower, double upper)
|
double nextDouble(double lower, double upper);
|
||||||
{
|
|
||||||
return getDoubleRange(lower, upper)();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates a double between 0.0 and 1.0.
|
/// Generates a double between 0.0 and 1.0.
|
||||||
double nextDouble()
|
double nextDouble();
|
||||||
{
|
|
||||||
return TRealDist()(rand);
|
/// 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:
|
private:
|
||||||
TGenerator rand;
|
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
|
namespace RandomGeneratorUtil
|
||||||
|
@ -1068,14 +1068,13 @@ struct HeroLevelUp : public Query//2000
|
|||||||
|
|
||||||
const CGHeroInstance *hero;
|
const CGHeroInstance *hero;
|
||||||
PrimarySkill::PrimarySkill primskill;
|
PrimarySkill::PrimarySkill primskill;
|
||||||
ui8 level;
|
|
||||||
std::vector<SecondarySkill> skills;
|
std::vector<SecondarySkill> skills;
|
||||||
|
|
||||||
HeroLevelUp(){type = 2000;};
|
HeroLevelUp(){type = 2000;};
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
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 )
|
DLL_LINKAGE void SetPrimSkill::applyGs( CGameState *gs )
|
||||||
{
|
{
|
||||||
CGHeroInstance *hero = gs->getHero(id);
|
CGHeroInstance * hero = gs->getHero(id);
|
||||||
assert(hero);
|
assert(hero);
|
||||||
|
hero->setPrimarySkill(which, val, abs);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE void SetSecSkill::applyGs( CGameState *gs )
|
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 )
|
DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
|
||||||
{
|
{
|
||||||
CGHeroInstance* h = gs->getHero(hero->id);
|
CGHeroInstance * h = gs->getHero(hero->id);
|
||||||
h->level = level;
|
h->levelUp(skills);
|
||||||
//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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE void CommanderLevelUp::applyGs (CGameState *gs)
|
DLL_LINKAGE void CommanderLevelUp::applyGs (CGameState *gs)
|
||||||
|
@ -107,6 +107,7 @@
|
|||||||
<Unit filename="CObjectHandler.h" />
|
<Unit filename="CObjectHandler.h" />
|
||||||
<Unit filename="CObstacleInstance.cpp" />
|
<Unit filename="CObstacleInstance.cpp" />
|
||||||
<Unit filename="CObstacleInstance.h" />
|
<Unit filename="CObstacleInstance.h" />
|
||||||
|
<Unit filename="CRandomGenerator.cpp" />
|
||||||
<Unit filename="CRandomGenerator.h" />
|
<Unit filename="CRandomGenerator.h" />
|
||||||
<Unit filename="CScriptingModule.h" />
|
<Unit filename="CScriptingModule.h" />
|
||||||
<Unit filename="CSpellHandler.cpp" />
|
<Unit filename="CSpellHandler.cpp" />
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
<ClCompile Include="CSpellHandler.cpp" />
|
<ClCompile Include="CSpellHandler.cpp" />
|
||||||
<ClCompile Include="CThreadHelper.cpp" />
|
<ClCompile Include="CThreadHelper.cpp" />
|
||||||
<ClCompile Include="CTownHandler.cpp" />
|
<ClCompile Include="CTownHandler.cpp" />
|
||||||
|
<ClCompile Include="CRandomGenerator.cpp" />
|
||||||
<ClCompile Include="filesystem\AdapterLoaders.cpp" />
|
<ClCompile Include="filesystem\AdapterLoaders.cpp" />
|
||||||
<ClCompile Include="filesystem\CArchiveLoader.cpp" />
|
<ClCompile Include="filesystem\CArchiveLoader.cpp" />
|
||||||
<ClCompile Include="filesystem\CBinaryReader.cpp" />
|
<ClCompile Include="filesystem\CBinaryReader.cpp" />
|
||||||
@ -323,4 +324,4 @@
|
|||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
<ClCompile Include="CCreatureSet.cpp" />
|
<ClCompile Include="CCreatureSet.cpp" />
|
||||||
<ClCompile Include="CGameState.cpp" />
|
<ClCompile Include="CGameState.cpp" />
|
||||||
<ClCompile Include="Connection.cpp" />
|
<ClCompile Include="Connection.cpp" />
|
||||||
|
<ClCompile Include="CRandomGenerator.cpp" />
|
||||||
<ClCompile Include="HeroBonus.cpp" />
|
<ClCompile Include="HeroBonus.cpp" />
|
||||||
<ClCompile Include="IGameCallback.cpp" />
|
<ClCompile Include="IGameCallback.cpp" />
|
||||||
<ClCompile Include="NetPacksLib.cpp" />
|
<ClCompile Include="NetPacksLib.cpp" />
|
||||||
@ -393,4 +394,4 @@
|
|||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -183,31 +183,21 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//give prim skill
|
// give primary skill
|
||||||
logGlobal->traceStream() << hero->name <<" got level "<<hero->level;
|
logGlobal->traceStream() << hero->name << " got level "<< hero->level;
|
||||||
int r = rand()%100, pom=0, x=0;
|
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;
|
SetPrimSkill sps;
|
||||||
sps.id = hero->id;
|
sps.id = hero->id;
|
||||||
sps.which = static_cast<PrimarySkill::PrimarySkill>(x);
|
sps.which = primarySkill;
|
||||||
sps.abs = false;
|
sps.abs = false;
|
||||||
sps.val = 1;
|
sps.val = 1;
|
||||||
sendAndApply(&sps);
|
sendAndApply(&sps);
|
||||||
|
|
||||||
HeroLevelUp hlu;
|
HeroLevelUp hlu;
|
||||||
hlu.hero = hero;
|
hlu.hero = hero;
|
||||||
hlu.primskill = static_cast<PrimarySkill::PrimarySkill>(x);
|
hlu.primskill = primarySkill;
|
||||||
hlu.level = hero->level+1;
|
hlu.skills = hero->getLevelUpProposedSecondarySkills();
|
||||||
hlu.skills = hero->levelUpProposedSkills();
|
|
||||||
|
|
||||||
if(hlu.skills.size() == 0)
|
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
|
else if(hlu.skills.size() == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
|
||||||
{
|
{
|
||||||
sendAndApply(&hlu);
|
sendAndApply(&hlu);
|
||||||
auto rng = [&]() mutable -> ui32
|
levelUpHero(hero, *RandomGeneratorUtil::nextItem(hlu.skills, hero->skillsInfo.rand));
|
||||||
{
|
|
||||||
return hero->skillsInfo.distribution(); //must be determined
|
|
||||||
};
|
|
||||||
levelUpHero(hero, vstd::pickRandomElementOf (hlu.skills, rng));
|
|
||||||
}
|
}
|
||||||
else if(hlu.skills.size() > 1)
|
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
|
else if(skillAmount == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
|
||||||
{
|
{
|
||||||
sendAndApply(&clu);
|
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
|
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;
|
int maxLevel = eagleEyeLevel + 1;
|
||||||
double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::EAGLE_EYE);
|
double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::EAGLE_EYE);
|
||||||
for(const CSpell *sp : gs->curB->sides.at(!battleResult.data->winner).usedSpellsHistory)
|
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);
|
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(!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;
|
bat.flags |= BattleAttack::LUCKY;
|
||||||
}
|
}
|
||||||
if (VLC->modh->settings.data["hardcodedFeatures"]["NEGATIVE_LUCK"].Bool()) // negative luck enabled
|
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;
|
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;
|
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};
|
static const int artilleryLvlToChance[] = {0, 50, 75, 100};
|
||||||
const CGHeroInstance * owner = gs->curB->getHero(att->owner);
|
const CGHeroInstance * owner = gs->curB->getHero(att->owner);
|
||||||
int chance = artilleryLvlToChance[owner->getSecSkillLevel(SecondarySkill::ARTILLERY)];
|
int chance = artilleryLvlToChance[owner->getSecSkillLevel(SecondarySkill::ARTILLERY)];
|
||||||
if(chance > rand() % 100)
|
if(chance > gs->getRandomGenerator().nextInt(99))
|
||||||
{
|
{
|
||||||
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
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.flags |= BattleStackAttacked::SECONDARY; //all other targets do not suffer from spells & spell-like abilities
|
||||||
bsa.attackerID = att->ID;
|
bsa.attackerID = att->ID;
|
||||||
bsa.stackAttacked = def->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());
|
bsa.damageAmount = gs->curB->calculateDmg(att, def, gs->curB->battleGetOwner(att), gs->curB->battleGetOwner(def),
|
||||||
def->prepareAttacked(bsa, gameState()->getRandomGenerator()); //calculate casualties
|
bat.shot(), distance, bat.lucky(), bat.unlucky(), bat.deathBlow(), bat.ballistaDoubleDmg(), gs->getRandomGenerator());
|
||||||
|
def->prepareAttacked(bsa, gs->getRandomGenerator()); //calculate casualties
|
||||||
|
|
||||||
//life drain handling
|
//life drain handling
|
||||||
if (att->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
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)
|
void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &c)
|
||||||
{
|
{
|
||||||
setThreadName("CGameHandler::handleConnection");
|
setThreadName("CGameHandler::handleConnection");
|
||||||
srand(time(nullptr));
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1089,6 +1075,9 @@ void CGameHandler::init(StartInfo *si)
|
|||||||
gs->init(si);
|
gs->init(si);
|
||||||
logGlobal->infoStream() << "Gamestate initialized!";
|
logGlobal->infoStream() << "Gamestate initialized!";
|
||||||
|
|
||||||
|
// reset seed, so that clients can't predict any following random values
|
||||||
|
gs->getRandomGenerator().resetSeed();
|
||||||
|
|
||||||
for(auto & elem : gs->players)
|
for(auto & elem : gs->players)
|
||||||
{
|
{
|
||||||
states.addPlayer(elem.first);
|
states.addPlayer(elem.first);
|
||||||
@ -1123,15 +1112,20 @@ void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=fa
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui32 dwellpos = rand()%dwellings.size();//take random dwelling
|
auto dwelling = *RandomGeneratorUtil::nextItem(dwellings, gs->getRandomGenerator());
|
||||||
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];
|
|
||||||
|
|
||||||
if (clear)
|
// for multi-creature dwellings like Golem Factory
|
||||||
ssi.creatures[GameConstants::CREATURES_PER_TOWN].first = std::max((ui32)1, (VLC->creh->creatures.at(creature)->growth)/2);
|
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
|
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);
|
sendAndApply(&ssi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1149,7 +1143,6 @@ void CGameHandler::newTurn()
|
|||||||
bool newMonth = getDate(Date::DAY_OF_MONTH) == 28;
|
bool newMonth = getDate(Date::DAY_OF_MONTH) == 28;
|
||||||
|
|
||||||
std::map<PlayerColor, si32> hadGold;//starting gold - for buildings like dwarven treasury
|
std::map<PlayerColor, si32> hadGold;//starting gold - for buildings like dwarven treasury
|
||||||
srand(time(nullptr));
|
|
||||||
|
|
||||||
if (firstTurn)
|
if (firstTurn)
|
||||||
{
|
{
|
||||||
@ -1182,7 +1175,7 @@ void CGameHandler::newTurn()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int monthType = rand()%100;
|
int monthType = gs->getRandomGenerator().nextInt(99);
|
||||||
if(newMonth) //new month
|
if(newMonth) //new month
|
||||||
{
|
{
|
||||||
if (monthType < 40) //double growth
|
if (monthType < 40) //double growth
|
||||||
@ -1196,7 +1189,7 @@ void CGameHandler::newTurn()
|
|||||||
else if(VLC->creh->doubledCreatures.size())
|
else if(VLC->creh->doubledCreatures.size())
|
||||||
{
|
{
|
||||||
const std::vector<CreatureID> doubledCreatures (VLC->creh->doubledCreatures.begin(), VLC->creh->doubledCreatures.end());
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -1427,12 +1420,12 @@ void CGameHandler::newTurn()
|
|||||||
if (newMonth)
|
if (newMonth)
|
||||||
{
|
{
|
||||||
iw.text.addTxt(MetaString::ARRAY_TXT, (130));
|
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
|
else
|
||||||
{
|
{
|
||||||
iw.text.addTxt(MetaString::ARRAY_TXT, (133));
|
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)
|
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
|
if(currentHP.at(attackedPart) != EWallState::DESTROYED && // this part can be hit
|
||||||
currentHP.at(attackedPart) != EWallState::NONE &&
|
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;
|
hitSuccessfull = true;
|
||||||
}
|
}
|
||||||
@ -3607,7 +3600,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
}
|
}
|
||||||
if (allowedTargets.empty())
|
if (allowedTargets.empty())
|
||||||
break;
|
break;
|
||||||
attackedPart = allowedTargets.at(rand()%allowedTargets.size());
|
attackedPart = *RandomGeneratorUtil::nextItem(allowedTargets, gs->getRandomGenerator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!hitSuccessfull);
|
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 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
|
//accumulating dmgChance
|
||||||
dmgChance[1] += dmgChance[0];
|
dmgChance[1] += dmgChance[0];
|
||||||
dmgChance[2] += dmgChance[1];
|
dmgChance[2] += dmgChance[1];
|
||||||
@ -4071,7 +4064,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
|
|||||||
}
|
}
|
||||||
|
|
||||||
//checking if creatures resist
|
//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
|
//calculating dmg to display
|
||||||
if (spellID == SpellID::DEATH_STARE || spellID == SpellID::ACID_BREATH_DAMAGE)
|
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)
|
for(auto & attackedCre : attackedCres)
|
||||||
{
|
{
|
||||||
int mirrorChance = (attackedCre)->valOfBonuses(Bonus::MAGIC_MIRROR);
|
int mirrorChance = (attackedCre)->valOfBonuses(Bonus::MAGIC_MIRROR);
|
||||||
if(mirrorChance > rand()%100)
|
if(mirrorChance > gs->getRandomGenerator().nextInt(99))
|
||||||
{
|
{
|
||||||
std::vector<CStack *> mirrorTargets;
|
std::vector<CStack *> mirrorTargets;
|
||||||
std::vector<CStack *> & battleStacks = gs->curB->stacks;
|
std::vector<CStack *> & battleStacks = gs->curB->stacks;
|
||||||
@ -4479,7 +4472,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
|
|||||||
}
|
}
|
||||||
if (!mirrorTargets.empty())
|
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));
|
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 (fearsomeCreature)
|
||||||
{
|
{
|
||||||
if (rand() % 100 < 10) //fixed 10%
|
if (gs->getRandomGenerator().nextInt(99) < 10) //fixed 10%
|
||||||
{
|
{
|
||||||
bte.effect = Bonus::FEAR;
|
bte.effect = Bonus::FEAR;
|
||||||
sendAndApply(&bte);
|
sendAndApply(&bte);
|
||||||
@ -4663,18 +4656,18 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
|
|||||||
int side = gs->curB->whatSide(st->owner);
|
int side = gs->curB->whatSide(st->owner);
|
||||||
if (bl.size() && st->casts && !gs->curB->sides.at(side).enchanterCounter)
|
if (bl.size() && st->casts && !gs->curB->sides.at(side).enchanterCounter)
|
||||||
{
|
{
|
||||||
int index = rand() % bl.size();
|
auto bonus = *RandomGeneratorUtil::nextItem(bl, gs->getRandomGenerator());
|
||||||
SpellID spellID = SpellID(bl[index]->subtype);
|
auto spellID = SpellID(bonus->subtype);
|
||||||
if (gs->curB->battleCanCastThisSpell(st->owner, SpellID(spellID).toSpell(), ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK) //TODO: select another available?
|
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));
|
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);
|
handleSpellCasting(spellID, spellLeveL, -1, side, st->owner, nullptr, enemyHero, 0, ECastingMode::ENCHANTER_CASTING, st);
|
||||||
|
|
||||||
BattleSetStackProperty ssp;
|
BattleSetStackProperty ssp;
|
||||||
ssp.which = BattleSetStackProperty::ENCHANTER_COUNTER;
|
ssp.which = BattleSetStackProperty::ENCHANTER_COUNTER;
|
||||||
ssp.absolute = false;
|
ssp.absolute = false;
|
||||||
ssp.val = bl[index]->additionalInfo; //increase cooldown counter
|
ssp.val = bonus->additionalInfo; //increase cooldown counter
|
||||||
ssp.stackID = st->ID;
|
ssp.stackID = st->ID;
|
||||||
sendAndApply(&ssp);
|
sendAndApply(&ssp);
|
||||||
}
|
}
|
||||||
@ -5345,7 +5338,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
//check if spell should be casted (probability handling)
|
//check if spell should be casted (probability handling)
|
||||||
if(rand()%100 >= chance)
|
if(gs->getRandomGenerator().nextInt(99) >= chance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//casting //TODO: check if spell can be blocked or target is immune
|
//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;
|
double chanceToKill = attacker->valOfBonuses(Bonus::DEATH_STARE, 0) / 100.0f;
|
||||||
vstd::amin(chanceToKill, 1); //cap at 100%
|
vstd::amin(chanceToKill, 1); //cap at 100%
|
||||||
|
|
||||||
std::binomial_distribution<> distr(attacker->count, chanceToKill);
|
std::binomial_distribution<> distribution(attacker->count, chanceToKill);
|
||||||
std::mt19937 rng(rand());
|
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
|
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
|
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));
|
TBonusListPtr acidBreath = attacker->getBonuses(Selector::type(Bonus::ACID_BREATH));
|
||||||
for(const Bonus *b : *acidBreath)
|
for(const Bonus *b : *acidBreath)
|
||||||
{
|
{
|
||||||
if (b->additionalInfo > rand()%100)
|
if (b->additionalInfo > gs->getRandomGenerator().nextInt(99))
|
||||||
acidDamage += b->val;
|
acidDamage += b->val;
|
||||||
}
|
}
|
||||||
if (acidDamage)
|
if (acidDamage)
|
||||||
@ -5439,7 +5432,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, SpellID spellID, const int
|
|||||||
case SpellID::SUMMON_BOAT:
|
case SpellID::SUMMON_BOAT:
|
||||||
{
|
{
|
||||||
//check if spell works at all
|
//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;
|
InfoWindow iw;
|
||||||
iw.player = h->tempOwner;
|
iw.player = h->tempOwner;
|
||||||
@ -5501,7 +5494,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, SpellID spellID, const int
|
|||||||
case SpellID::SCUTTLE_BOAT:
|
case SpellID::SCUTTLE_BOAT:
|
||||||
{
|
{
|
||||||
//check if spell works at all
|
//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;
|
InfoWindow iw;
|
||||||
iw.player = h->tempOwner;
|
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)
|
|| 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
|
//unit loses its turn - empty freeze action
|
||||||
BattleAction ba;
|
BattleAction ba;
|
||||||
@ -5983,7 +5976,7 @@ void CGameHandler::runBattle()
|
|||||||
if(!attackableBattleHexes.empty())
|
if(!attackableBattleHexes.empty())
|
||||||
{
|
{
|
||||||
BattleAction attack;
|
BattleAction attack;
|
||||||
attack.destinationTile = attackableBattleHexes[rand() % attackableBattleHexes.size()];
|
attack.destinationTile = *RandomGeneratorUtil::nextItem(attackableBattleHexes, gs->getRandomGenerator());
|
||||||
attack.actionType = Battle::CATAPULT;
|
attack.actionType = Battle::CATAPULT;
|
||||||
attack.additionalInfo = 0;
|
attack.additionalInfo = 0;
|
||||||
attack.side = !next->attackerOwned;
|
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
|
|| 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;
|
BattleTriggerEffect bte;
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
//#include <boost/interprocess/shared_memory_object.hpp>
|
//#include <boost/interprocess/shared_memory_object.hpp>
|
||||||
#include <boost/random/linear_congruential.hpp>
|
#include <boost/random/linear_congruential.hpp>
|
||||||
#include <boost/random/mersenne_twister.hpp>
|
#include <boost/random/mersenne_twister.hpp>
|
||||||
#include <boost/random/poisson_distribution.hpp>
|
|
||||||
#include <boost/random/variate_generator.hpp>
|
#include <boost/random/variate_generator.hpp>
|
||||||
#include <boost/system/system_error.hpp>
|
#include <boost/system/system_error.hpp>
|
||||||
//#include <boost/asio.hpp>
|
//#include <boost/asio.hpp>
|
||||||
|
Loading…
Reference in New Issue
Block a user