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) {