From 3f28634d1f617691c672e41a3ee950e6daec8c77 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 15 Mar 2015 14:07:47 +1300 Subject: [PATCH] consolidate random number logic Note, I suspect Rng::rollClosedProbability() is not needed. The only difference between it and rollProbability() is that one time in 37k (on Windows), it will give an output of 1.0. On some versions of Linux, the value of 1.0 will occur about 1 time in 4 billion. --- apps/openmw/engine.cpp | 3 ++ apps/openmw/mwclass/creature.cpp | 9 ++--- apps/openmw/mwclass/npc.cpp | 12 +++---- apps/openmw/mwgui/jailscreen.cpp | 4 ++- apps/openmw/mwgui/loadingscreen.cpp | 4 ++- apps/openmw/mwgui/pickpocketitemmodel.cpp | 6 +++- apps/openmw/mwgui/recharge.cpp | 4 ++- apps/openmw/mwgui/tradewindow.cpp | 4 ++- apps/openmw/mwgui/waitdialog.cpp | 7 ++-- apps/openmw/mwmechanics/activespells.cpp | 5 +-- apps/openmw/mwmechanics/aicombat.cpp | 25 ++++++------- apps/openmw/mwmechanics/aiwander.cpp | 10 +++--- apps/openmw/mwmechanics/alchemy.cpp | 6 ++-- apps/openmw/mwmechanics/character.cpp | 8 +++-- apps/openmw/mwmechanics/combat.cpp | 12 +++---- apps/openmw/mwmechanics/disease.hpp | 6 ++-- apps/openmw/mwmechanics/enchanting.cpp | 5 ++- apps/openmw/mwmechanics/levelledlist.hpp | 7 ++-- .../mwmechanics/mechanicsmanagerimp.cpp | 7 ++-- apps/openmw/mwmechanics/pickpocket.cpp | 4 ++- apps/openmw/mwmechanics/repair.cpp | 4 ++- apps/openmw/mwmechanics/security.cpp | 8 ++--- apps/openmw/mwmechanics/spellcasting.cpp | 20 +++++------ apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 ++- apps/openmw/mwrender/sky.cpp | 6 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 8 +++-- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/store.hpp | 4 ++- apps/openmw/mwworld/weather.cpp | 8 +++-- apps/openmw/mwworld/worldimp.cpp | 6 ++-- components/CMakeLists.txt | 6 +++- components/nifogre/particles.cpp | 4 ++- libs/openengine/CMakeLists.txt | 7 +++- libs/openengine/misc/rng.cpp | 29 +++++++++++++++ libs/openengine/misc/rng.hpp | 36 +++++++++++++++++++ libs/openengine/ogre/selectionbuffer.cpp | 4 ++- 37 files changed, 214 insertions(+), 92 deletions(-) create mode 100644 libs/openengine/misc/rng.cpp create mode 100644 libs/openengine/misc/rng.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 92731ee1a2..a4bb8c5380 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include @@ -191,6 +193,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mExportFonts(false) , mNewGame (false) { + OEngine::Misc::Rng::init(); std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 908de02d89..8404b95234 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,6 +1,8 @@ #include "creature.hpp" +#include + #include #include @@ -249,7 +251,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) + if(OEngine::Misc::Rng::rollProbability() >= hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -375,8 +377,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) + if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -680,7 +681,7 @@ namespace MWClass ++sound; } if(!sounds.empty()) - return sounds[(int)(rand()/(RAND_MAX+1.0)*sounds.size())]->mSound; + return sounds[OEngine::Misc::Rng::rollDice(sounds.size())]->mSound; } if (type == ESM::SoundGenerator::Land) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d5055fcb20..1d58dc87e3 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include #include @@ -513,7 +515,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) + if (OEngine::Misc::Rng::rollProbability() >= hitchance / 100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -643,8 +645,7 @@ namespace MWClass const GMST& gmst = getGmst(); int chance = store.get().find("iVoiceHitOdds")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); } @@ -653,8 +654,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); - roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) + if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -680,7 +680,7 @@ namespace MWClass MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet }; - int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)]; + int hitslot = hitslots[OEngine::Misc::Rng::rollDice(20)]; float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 728c460236..5c0a6ec5f2 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,5 +1,7 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" @@ -83,7 +85,7 @@ namespace MWGui std::set skills; for (int day=0; day(std::rand() / (static_cast (RAND_MAX)+1) * ESM::Skill::Length); + int skill = OEngine::Misc::Rng::rollDice(ESM::Skill::Length); skills.insert(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f920acf1ad..3204c65482 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -146,7 +148,7 @@ namespace MWGui if (!mResources.empty()) { - std::string const & randomSplash = mResources.at (rand() % mResources.size()); + std::string const & randomSplash = mResources.at(OEngine::Misc::Rng::rollDice(mResources.size())); Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index f6882ada61..bc7c5528e8 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,5 +1,7 @@ #include "pickpocketitemmodel.hpp" +#include + #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" @@ -12,11 +14,13 @@ namespace MWGui int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak); mSourceModel->update(); + + // build list of items that player is unable to find when attempts to pickpocket. if (hideItems) { for (size_t i = 0; igetItemCount(); ++i) { - if (std::rand() / static_cast(RAND_MAX) * 100 > chance) + if (chance <= OEngine::Misc::Rng::roll0to99()) mHiddenItems.push_back(mSourceModel->getItem(i)); } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 1af31373c6..a0e5991b46 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -161,7 +163,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) intelligenceTerm = 1; float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (roll < x) { std::string soul = gem.getCellRef().getSoul(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 841e2e1854..e14642fe79 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -365,7 +367,7 @@ namespace MWGui else x += abs(int(npcTerm - pcTerm)); - int roll = std::rand()%100 + 1; + int roll = OEngine::Misc::Rng::rollDice(100) + 1; if(roll > x || (mCurrentMerchantOffer < 0) != (mCurrentBalance < 0)) //trade refused { MWBase::Environment::get().getWindowManager()-> diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index b73ab38f22..f74b068912 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include @@ -152,10 +154,9 @@ namespace MWGui const ESM::Region *region = world->getStore().get().find (regionstr); if (!region->mSleepList.empty()) { + // figure out if player will be woken while sleeping float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - int x = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * hoursToWait); // [0, hoursRested] - float y = fSleepRandMod * hoursToWait; - if (x > y) + if (OEngine::Misc::Rng::rollProbability() > fSleepRandMod) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 5eea08caa8..a6cc9af8ef 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -1,5 +1,7 @@ #include "activespells.hpp" +#include + #include #include @@ -229,8 +231,7 @@ namespace MWMechanics { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) mSpells.erase(it++); else ++it; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index c16baefaab..bac7d7286c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include "../mwworld/class.hpp" @@ -393,7 +395,7 @@ namespace MWMechanics if (!distantCombat) attackType = chooseBestAttack(weapon, movement); else attackType = ESM::Weapon::AT_Chop; // cause it's =0 - strength = static_cast(rand()) / RAND_MAX; + strength = OEngine::Misc::Rng::rollClosedProbability(); // Note: may be 0 for some animations timerAttack = minMaxAttackDuration[attackType][0] + @@ -404,8 +406,7 @@ namespace MWMechanics { const MWWorld::ESMStore &store = world->getStore(); int chance = store.get().find("iVoiceAttackOdds")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } @@ -512,17 +513,17 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * static_cast(rand())/RAND_MAX; + timerCombatMove = 0.1f + 0.1f * OEngine::Misc::Rng::rollClosedProbability(); combatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) { //apply sideway movement (kind of dodging) with some probability - if(static_cast(rand())/RAND_MAX < 0.25) + if (OEngine::Misc::Rng::rollClosedProbability() < 0.25) { - movement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * static_cast(rand())/RAND_MAX; + movement.mPosition[0] = OEngine::Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + timerCombatMove = 0.05f + 0.15f * OEngine::Misc::Rng::rollClosedProbability(); combatMove = true; } } @@ -637,7 +638,7 @@ namespace MWMechanics float s2 = speed2 * t; float t_swing = minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + - (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * static_cast(rand()) / RAND_MAX; + (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * OEngine::Misc::Rng::rollClosedProbability(); if (t + s2/speed1 <= t_swing) { @@ -761,10 +762,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: if (weapon == NULL) { //hand-to-hand deal equal damage for each type - float roll = static_cast(rand())/RAND_MAX; + float roll = OEngine::Misc::Rng::rollClosedProbability(); if(roll <= 0.333f) //side punch { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; + movement.mPosition[0] = OEngine::Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } @@ -788,10 +789,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: float total = static_cast(slash + chop + thrust); - float roll = static_cast(rand())/RAND_MAX; + float roll = OEngine::Misc::Rng::rollClosedProbability(); if(roll <= (slash/total)) { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; + movement.mPosition[0] = (OEngine::Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 842f03edff..b791ff3a9d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -315,7 +317,7 @@ namespace MWMechanics static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; + float roll = OEngine::Misc::Rng::rollProbability() * 10000.0f; // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds // due to the roll being an integer. @@ -490,7 +492,7 @@ namespace MWMechanics if(!storage.mPathFinder.isPathConstructed()) { assert(mAllowedNodes.size()); - unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); + unsigned int randNode = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); @@ -637,7 +639,7 @@ namespace MWMechanics .get().find("fIdleChanceMultiplier")->getFloat(); unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); - unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / fIdleChanceMultiplier)); + unsigned short randSelect = (int)(OEngine::Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { playedIdle = counter+2; @@ -659,7 +661,7 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - int index = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * mAllowedNodes.size()); + int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index a833e28d94..58c42ddb81 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include @@ -294,7 +296,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) newRecord.mName = name; - int index = static_cast (std::rand()/(static_cast (RAND_MAX)+1)*6); + int index = OEngine::Misc::Rng::rollDice(6); assert (index>=0 && index<6); static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; @@ -467,7 +469,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_RandomFailure; } - if (getAlchemyFactor() (RAND_MAX)*100) + if (getAlchemyFactor() < OEngine::Misc::Rng::roll0to99()) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 28028500a0..ffde59aee6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,8 @@ #include "creaturestats.hpp" #include "security.hpp" +#include + #include #include "../mwrender/animation.hpp" @@ -220,7 +222,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) ++numAnims; - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * numAnims) + 1; // [1, numAnims] + int roll = OEngine::Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] if (num) *num = roll; return prefix + Ogre::StringConverter::toString(roll); @@ -829,7 +831,7 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] + int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] if (roll == 0) mCurrentWeapon = "attack1"; else if (roll == 1) @@ -1125,7 +1127,7 @@ bool CharacterController::updateWeaponState() // most creatures don't actually have an attack wind-up animation, so use a uniform random value // (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings) // Note: vanilla MW uses a random value for *all* non-player actors, but we probably don't need to go that far. - attackStrength = std::min(1.f, 0.1f + std::rand() / float(RAND_MAX)); + attackStrength = std::min(1.f, 0.1f + OEngine::Misc::Rng::rollClosedProbability()); } if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index fdb3758464..6a1e08df82 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -107,8 +109,7 @@ namespace MWMechanics int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < x) + if (OEngine::Misc::Rng::roll0to99() < x) { // Reduce shield durability by incoming damage int shieldhealth = shield->getClass().getItemHealth(*shield); @@ -186,7 +187,7 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if((::rand()/(RAND_MAX+1.0)) >= getHitChance(attacker, victim, skillValue)/100.0f) + if (OEngine::Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); @@ -224,7 +225,7 @@ namespace MWMechanics && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); - if ((::rand()/(RAND_MAX+1.0)) < fProjectileThrownStoreChance/100.f) + if (OEngine::Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) victim.getClass().getContainerStore(victim).add(projectile, 1, victim); } @@ -291,8 +292,7 @@ namespace MWMechanics saveTerm *= 1.25f * normalisedFatigue; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - float x = std::max(0.f, saveTerm - roll); + float x = std::max(0.f, saveTerm - OEngine::Misc::Rng::roll0to99()); int element = ESM::MagicEffect::FireDamage; if (i == 1) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 2f7d65dfd2..0153be3dc8 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MECHANICS_DISEASE_H #define OPENMW_MECHANICS_DISEASE_H +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -49,9 +51,7 @@ namespace MWMechanics continue; int x = static_cast(fDiseaseXferChance * 100 * resist); - float roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 10000); // [0, 9999] - - if (roll < x) + if (OEngine::Misc::Rng::rollDice(10000) < x) { // Contracted disease! actor.getClass().getCreatureStats(actor).getSpells().add(it->first); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d99b337d50..bb02fb41d3 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -1,4 +1,7 @@ #include "enchanting.hpp" + +#include + #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -67,7 +70,7 @@ namespace MWMechanics if(mSelfEnchanting) { - if(getEnchantChance() (RAND_MAX)*100) + if(getEnchantChance() <= (OEngine::Misc::Rng::roll0to99())) return false; mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index cd12760382..20b87a3a96 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MECHANICS_LEVELLEDLIST_H #define OPENMW_MECHANICS_LEVELLEDLIST_H +#include + #include "../mwworld/ptr.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" @@ -22,8 +24,7 @@ namespace MWMechanics failChance += levItem->mChanceNone; - int random = static_cast(static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100)); // [0, 99] - if (random < failChance) + if (OEngine::Misc::Rng::roll0to99() < failChance) return std::string(); std::vector candidates; @@ -52,7 +53,7 @@ namespace MWMechanics } if (candidates.empty()) return std::string(); - std::string item = candidates[std::rand()%candidates.size()]; + std::string item = candidates[OEngine::Misc::Rng::rollDice(candidates.size())]; // Vanilla doesn't fail on nonexistent items in levelled lists if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item))) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bf1d3ec197..0d4518f875 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,8 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" +#include + #include #include "../mwworld/esmstore.hpp" @@ -723,7 +725,7 @@ namespace MWMechanics float x = 0; float y = 0; - float roll = static_cast (std::rand()) / RAND_MAX * 100; + float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; if (type == PT_Admire) { @@ -1378,9 +1380,8 @@ namespace MWMechanics y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; float target = x - y; - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - return (roll >= target); + return (OEngine::Misc::Rng::roll0to99() >= target); } void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 12db9d6f5a..561011df38 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -1,5 +1,7 @@ #include "pickpocket.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -39,7 +41,7 @@ namespace MWMechanics int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 486a9183d8..b5058fb88e 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -46,7 +48,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); + int roll = OEngine::Misc::Rng::roll0to99(); if (roll <= x) { int y = static_cast(fRepairAmountMult * toolQuality * roll); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index d987814e5c..3f72f1b669 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -1,5 +1,7 @@ #include "security.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" @@ -48,8 +50,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { lock.getClass().unlock(lock); resultMessage = "#{sLockSuccess}"; @@ -90,8 +91,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 590c8fe832..8a43cc9322 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -4,6 +4,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -280,7 +282,7 @@ namespace MWMechanics if (castChance > 0) x *= 50 / castChance; - float roll = static_cast(std::rand()) / RAND_MAX * 100; + float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) roll -= resistance; @@ -383,8 +385,7 @@ namespace MWMechanics target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); - int roll = static_cast(std::rand()/ (static_cast (RAND_MAX) + 1) * 100); // [0, 99] - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { // Fully resisted, show message if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) @@ -414,8 +415,7 @@ namespace MWMechanics if (spell && caster != target && target.getClass().isActor()) { float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - absorbed = (roll < absorb); + absorbed = (OEngine::Misc::Rng::roll0to99() < absorb); if (absorbed) { const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); @@ -463,8 +463,7 @@ namespace MWMechanics if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - bool isReflected = (roll < reflect); + bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect); if (isReflected) { const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); @@ -492,7 +491,7 @@ namespace MWMechanics if (magnitudeMult > 0 && !absorbed) { - float random = std::rand() / static_cast(RAND_MAX); + float random = OEngine::Misc::Rng::rollClosedProbability(); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; @@ -824,8 +823,7 @@ namespace MWMechanics // Check success float successChance = getSpellSuccessChance(spell, mCaster); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (!fail && roll >= successChance) + if (OEngine::Misc::Rng::roll0to99() >= successChance) { if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); @@ -903,7 +901,7 @@ namespace MWMechanics + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (roll > x) { // "X has no effect on you" diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index dcbd3f09f3..04225b43eb 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -38,7 +38,7 @@ namespace MWMechanics for (unsigned int i=0; imEffects.mList.size();++i) { if (spell->mEffects.mList[i].mMagnMin != spell->mEffects.mList[i].mMagnMax) - random[i] = static_cast (std::rand()) / RAND_MAX; + random[i] = OEngine::Misc::Rng::rollClosedProbability(); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 2847885229..a724644a70 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -12,6 +12,8 @@ #include +#include + #include #include "../mwworld/esmstore.hpp" @@ -101,7 +103,7 @@ void HeadAnimationTime::setEnabled(bool enabled) void HeadAnimationTime::resetBlinkTimer() { - mBlinkTimer = -(2 + (std::rand() / static_cast(RAND_MAX)) * 6); + mBlinkTimer = -(2.0f + OEngine::Misc::Rng::rollDice(6)); } void HeadAnimationTime::update(float dt) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6e9684475c..d591cca2ea 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -19,6 +19,8 @@ #include +#include + #include #include @@ -464,8 +466,8 @@ void SkyManager::updateRain(float dt) // TODO: handle rain settings from Morrowind.ini const float rangeRandom = 100; - float xOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); - float yOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); + float xOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); + float yOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 998cc460ba..06c40dd8e8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" @@ -224,7 +226,7 @@ namespace MWSound if(!filelist.size()) return; - int i = rand()%filelist.size(); + int i = OEngine::Misc::Rng::rollDice(filelist.size()); // Don't play the same music track twice in a row if (filelist[i] == mLastPlayedMusic) @@ -559,7 +561,7 @@ namespace MWSound if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - float a = std::rand() / static_cast(RAND_MAX); + float a = OEngine::Misc::Rng::rollClosedProbability(); // NOTE: We should use the "Minimum Time Between Environmental Sounds" and // "Maximum Time Between Environmental Sounds" fallback settings here. sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a); @@ -588,7 +590,7 @@ namespace MWSound return; } - int r = (int)(rand()/((double)RAND_MAX+1) * total); + int r = OEngine::Misc::Rng::rollDice(total); int pos = 0; soundIter = regn->mSoundList.begin(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index da43df5131..4503e66f58 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -364,7 +364,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Roll some dice, one for each effect params.resize(enchantment.mEffects.mList.size()); for (unsigned int i=0; i (std::rand()) / RAND_MAX; + params[i].mRandom = OEngine::Misc::Rng::rollClosedProbability(); // Try resisting each effect int i=0; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 56f16377b4..d6aeeb51ed 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -178,7 +180,7 @@ namespace MWWorld std::vector results; std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); if(!results.empty()) - return results[int(std::rand()/((double)RAND_MAX+1)*results.size())]; + return results[OEngine::Misc::Rng::rollDice(results.size())]; return NULL; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 69495cdd20..a9ca8e72b5 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -3,6 +3,8 @@ #include "weather.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -526,7 +528,7 @@ void WeatherManager::update(float duration, bool paused) if (mThunderSoundDelay <= 0) { // pick a random sound - int sound = rand() % 4; + int sound = OEngine::Misc::Rng::rollDice(4); std::string* soundName = NULL; if (sound == 0) soundName = &mThunderSoundID0; else if (sound == 1) soundName = &mThunderSoundID1; @@ -542,7 +544,7 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); else { - mThunderChanceNeeded = static_cast(rand() % 100); + mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); mThunderChance = 0; mRendering->getSkyManager()->setLightningStrength( 0.f ); } @@ -624,7 +626,7 @@ std::string WeatherManager::nextWeather(const ESM::Region* region) const * 70% will be greater than 30 (in theory). */ - int chance = (rand() % 100) + 1; // 1..100 + int chance = OEngine::Misc::Rng::rollDice(100) + 1; // 1..100 int sum = 0; unsigned int i = 0; for (; i < probability.size(); ++i) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ce4b10dfc9..013386f8f9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include #include #include @@ -3133,7 +3135,7 @@ namespace MWWorld const ESM::CreatureLevList* list = getStore().get().find(creatureList); int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); - int numCreatures = static_cast(1 + std::rand() / (static_cast (RAND_MAX)+1) * iNumberCreatures); // [1, iNumberCreatures] + int numCreatures = 1 + OEngine::Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] for (int i=0; i(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] + int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9718976194..38fcd88e3e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -160,7 +160,11 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) +target_link_libraries(components + ${Boost_LIBRARIES} + ${OGRE_LIBRARIES} + ${OENGINE_LIBRARY} +) if (GIT_CHECKOUT) add_dependencies (components git-version) diff --git a/components/nifogre/particles.cpp b/components/nifogre/particles.cpp index 4fec2d29eb..936bfb435f 100644 --- a/components/nifogre/particles.cpp +++ b/components/nifogre/particles.cpp @@ -12,6 +12,8 @@ #include #include +#include + /* FIXME: "Nif" isn't really an appropriate emitter name. */ class NifEmitter : public Ogre::ParticleEmitter { @@ -171,7 +173,7 @@ public: Ogre::Real& timeToLive = particle->timeToLive; #endif - Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size())); + Ogre::Node* emitterBone = mEmitterBones.at(OEngine::Misc::Rng::rollDice(mEmitterBones.size())); position = xOff + yOff + zOff + mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition() diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 7a0a791d11..3542becf64 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -23,7 +23,12 @@ set(OENGINE_BULLET bullet/trace.h ) -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) +set(OENGINE_MISC + misc/rng.cpp + misc/rng.hpp +) + +set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) diff --git a/libs/openengine/misc/rng.cpp b/libs/openengine/misc/rng.cpp new file mode 100644 index 0000000000..140aa337eb --- /dev/null +++ b/libs/openengine/misc/rng.cpp @@ -0,0 +1,29 @@ +#include "rng.hpp" +#include +#include + +namespace OEngine { +namespace Misc { + + void Rng::init() + { + std::srand(static_cast(std::time(NULL))); + } + + float Rng::rollProbability() + { + return static_cast(std::rand() / (static_cast(RAND_MAX)+1.0)); + } + + float Rng::rollClosedProbability() + { + return static_cast(std::rand() / static_cast(RAND_MAX)); + } + + int Rng::rollDice(int max) + { + return static_cast((std::rand() / (static_cast(RAND_MAX)+1.0)) * (max)); + } + +} +} \ No newline at end of file diff --git a/libs/openengine/misc/rng.hpp b/libs/openengine/misc/rng.hpp new file mode 100644 index 0000000000..4e1da17e10 --- /dev/null +++ b/libs/openengine/misc/rng.hpp @@ -0,0 +1,36 @@ +#ifndef MISC_RNG_H +#define MISC_RNG_H + +#include + +namespace OEngine { +namespace Misc +{ + +/* + Provides central implementation of the RNG logic +*/ +class Rng +{ +public: + + /// seed the RNG + static void init(); + + /// return value in range [0.0f, 1.0f) <- note open upper range. + static float rollProbability(); + + /// return value in range [0.0f, 1.0f] <- note closed upper range. + static float rollClosedProbability(); + + /// return value in range [0, max) <- note open upper range. + static int rollDice(int max); + + /// return value in range [0, 99] + static int roll0to99() { return rollDice(100); } +}; + +} +} + +#endif diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index 87b85732bd..741b672ff1 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -10,6 +10,8 @@ #include +#include + #include namespace OEngine @@ -145,7 +147,7 @@ namespace Render void SelectionBuffer::getNextColour () { - Ogre::ARGB color = static_cast((float(rand()) / float(RAND_MAX)) * std::numeric_limits::max()); + Ogre::ARGB color = static_cast(OEngine::Misc::Rng::rollClosedProbability() * std::numeric_limits::max()); if (mCurrentColour.getAsARGB () == color) {