diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index a60c44265c..0b4edf4e1a 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -120,7 +120,8 @@ namespace MWClass if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Sound *sound = store.get().searchRandom("WolfActivator"); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const ESM::Sound *sound = store.get().searchRandom("WolfActivator", prng); std::shared_ptr action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); if(sound) action->setSound(sound->mId); @@ -156,6 +157,7 @@ namespace MWClass int type = getSndGenTypeFromName(name); std::vector fallbacksounds; + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); if (!creatureId.empty()) { std::vector sounds; @@ -168,9 +170,9 @@ namespace MWClass } if (!sounds.empty()) - return sounds[Misc::Rng::rollDice(sounds.size())]->mSound; + return sounds[Misc::Rng::rollDice(sounds.size(), prng)]->mSound; if (!fallbacksounds.empty()) - return fallbacksounds[Misc::Rng::rollDice(fallbacksounds.size())]->mSound; + return fallbacksounds[Misc::Rng::rollDice(fallbacksounds.size(), prng)]->mSound; } else { @@ -180,7 +182,7 @@ namespace MWClass fallbacksounds.push_back(&*sound); if (!fallbacksounds.empty()) - return fallbacksounds[Misc::Rng::rollDice(fallbacksounds.size())]->mSound; + return fallbacksounds[Misc::Rng::rollDice(fallbacksounds.size(), prng)]->mSound; } return std::string(); diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 3fcd7368d6..f9350222f1 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -56,7 +56,8 @@ namespace MWClass if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Sound *sound = store.get().searchRandom("WolfItem"); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const ESM::Sound *sound = store.get().searchRandom("WolfItem", prng); std::shared_ptr action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); if(sound) action->setSound(sound->mId); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 09d33af414..e319cdf410 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -32,7 +32,8 @@ namespace MWClass { ContainerCustomData::ContainerCustomData(const ESM::Container& container, MWWorld::CellStore* cell) { - unsigned int seed = Misc::Rng::rollDice(std::numeric_limits::max()); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + unsigned int seed = Misc::Rng::rollDice(std::numeric_limits::max(), prng); // setting ownership not needed, since taking items from a container inherits the // container's owner automatically mStore.fillNonRandom(container.mInventory, "", seed); @@ -139,7 +140,8 @@ namespace MWClass if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Sound *sound = store.get().searchRandom("WolfContainer"); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const ESM::Sound *sound = store.get().searchRandom("WolfContainer", prng); std::shared_ptr action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); if(sound) action->setSound(sound->mId); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 49b3627952..6a633bc668 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -159,7 +159,8 @@ namespace MWClass resetter.mPtr = {}; - getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId()); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId(), prng); if (hasInventory) getInventoryStore(ptr).autoEquip(ptr); @@ -264,8 +265,8 @@ namespace MWClass osg::Vec3f hitPosition (result.second); float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - - if(Misc::Rng::roll0to99() >= hitchance) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if(Misc::Rng::roll0to99(prng) >= hitchance) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, osg::Vec3f(), false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -392,7 +393,8 @@ namespace MWClass float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->mValue.getFloat(); float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * getGmst().iKnockDownOddsMult->mValue.getInteger() * 0.01f + getGmst().iKnockDownOddsBase->mValue.getInteger(); - if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99(prng)) stats.setKnockedDown(true); else stats.setHitRecovery(true); // Is this supposed to always occur? @@ -429,7 +431,8 @@ namespace MWClass if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Sound *sound = store.get().searchRandom("WolfCreature"); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const ESM::Sound *sound = store.get().searchRandom("WolfCreature", prng); std::shared_ptr action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); if(sound) action->setSound(sound->mId); @@ -642,10 +645,11 @@ namespace MWClass } } + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); if (!sounds.empty()) - return sounds[Misc::Rng::rollDice(sounds.size())]->mSound; + return sounds[Misc::Rng::rollDice(sounds.size(), prng)]->mSound; if (!fallbacksounds.empty()) - return fallbacksounds[Misc::Rng::rollDice(fallbacksounds.size())]->mSound; + return fallbacksounds[Misc::Rng::rollDice(fallbacksounds.size(), prng)]->mSound; return std::string(); } diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 66e35e5bf8..de40030a80 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -127,7 +127,8 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - std::string id = MWMechanics::getLevelledItem(ref->mBase, true); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + std::string id = MWMechanics::getLevelledItem(ref->mBase, true, prng); if (!id.empty()) { diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bfae090545..94027e5039 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -394,7 +394,8 @@ namespace MWClass // inventory // setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items - getInventoryStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId()); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + getInventoryStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId(), prng); getInventoryStore(ptr).autoEquip(ptr); } @@ -584,7 +585,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, getSkill(ptr, weapskill)); - if (Misc::Rng::roll0to99() >= hitchance) + if (Misc::Rng::roll0to99(world->getPrng()) >= hitchance) { othercls.onHit(victim, 0.0f, false, weapon, ptr, osg::Vec3f(), false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -726,15 +727,16 @@ namespace MWClass const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const GMST& gmst = getGmst(); - int chance = store.get().find("iVoiceHitOdds")->mValue.getInteger(); - if (Misc::Rng::roll0to99() < chance) + int chance = store.get().find("iVoiceHitOdds")->mValue.getInteger(); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (Misc::Rng::roll0to99(prng) < chance) MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); // Check for knockdown float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->mValue.getFloat(); float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * gmst.iKnockDownOddsMult->mValue.getInteger() * 0.01f + gmst.iKnockDownOddsBase->mValue.getInteger(); - if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) + if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99(prng)) stats.setKnockedDown(true); else stats.setHitRecovery(true); // Is this supposed to always occur? @@ -757,7 +759,7 @@ namespace MWClass MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet }; - int hitslot = hitslots[Misc::Rng::rollDice(20)]; + int hitslot = hitslots[Misc::Rng::rollDice(20, prng)]; float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); @@ -773,7 +775,7 @@ namespace MWClass // If there's no item in the carried left slot or if it is not a shield redistribute the hit. if (!hasArmor && hitslot == MWWorld::InventoryStore::Slot_CarriedLeft) { - if (Misc::Rng::rollDice(2) == 0) + if (Misc::Rng::rollDice(2, prng) == 0) hitslot = MWWorld::InventoryStore::Slot_Cuirass; else hitslot = MWWorld::InventoryStore::Slot_LeftPauldron; @@ -865,7 +867,8 @@ namespace MWClass if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Sound *sound = store.get().searchRandom("WolfNPC"); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const ESM::Sound *sound = store.get().searchRandom("WolfNPC", prng); std::shared_ptr action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); if(sound) action->setSound(sound->mId); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 53219a29d6..92c0fc9edc 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -87,7 +87,8 @@ namespace MWGui std::set skills; for (int day=0; daygetPrng(); + int skill = Misc::Rng::rollDice(ESM::Skill::Length, prng); skills.insert(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 5ba1b4aafa..2b4d474059 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -24,13 +24,13 @@ namespace MWGui float chance = player.getClass().getSkill(player, ESM::Skill::Sneak); mSourceModel->update(); - // build list of items that player is unable to find when attempts to pickpocket. if (hideItems) { + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); for (size_t i = 0; igetItemCount(); ++i) { - if (Misc::Rng::roll0to99() > chance) + if (Misc::Rng::roll0to99(prng) > chance) mHiddenItems.push_back(mSourceModel->getItem(i)); } } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 42a70dcfa7..754777c507 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -191,7 +191,7 @@ namespace MWGui if (!region->mSleepList.empty()) { // figure out if player will be woken while sleeping - int x = Misc::Rng::rollDice(hoursToWait); + int x = Misc::Rng::rollDice(hoursToWait, world->getPrng()); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->mValue.getFloat(); if (x < fSleepRandMod * hoursToWait) { diff --git a/apps/openmw/mwmechanics/actor.cpp b/apps/openmw/mwmechanics/actor.cpp index 5801ea751d..d1d37eeb56 100644 --- a/apps/openmw/mwmechanics/actor.cpp +++ b/apps/openmw/mwmechanics/actor.cpp @@ -60,6 +60,11 @@ namespace MWMechanics mIsTurningToPlayer = turning; } + Misc::TimerStatus Actor::updateEngageCombatTimer(float duration) + { + return mEngageCombat.update(duration, MWBase::Environment::get().getWorld()->getPrng()); + } + void Actor::setPositionAdjusted(bool adjusted) { mPositionAdjusted = adjusted; diff --git a/apps/openmw/mwmechanics/actor.hpp b/apps/openmw/mwmechanics/actor.hpp index c25fc1cb73..231c756810 100644 --- a/apps/openmw/mwmechanics/actor.hpp +++ b/apps/openmw/mwmechanics/actor.hpp @@ -43,10 +43,7 @@ namespace MWMechanics bool isTurningToPlayer() const; void setTurningToPlayer(bool turning); - Misc::TimerStatus updateEngageCombatTimer(float duration) - { - return mEngageCombat.update(duration); - } + Misc::TimerStatus updateEngageCombatTimer(float duration); void setPositionAdjusted(bool adjusted); bool getPositionAdjusted() const; @@ -57,7 +54,7 @@ namespace MWMechanics float mTargetAngleRadians{0.f}; GreetingState mGreetingState{Greet_None}; bool mIsTurningToPlayer{false}; - Misc::DeviatingPeriodicTimer mEngageCombat{1.0f, 0.25f, Misc::Rng::deviate(0, 0.25f)}; + Misc::DeviatingPeriodicTimer mEngageCombat{1.0f, 0.25f, Misc::Rng::deviate(0, 0.25f, MWBase::Environment::get().getWorld()->getPrng())}; bool mPositionAdjusted; }; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f13afb02d6..b7b83ed562 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -305,7 +305,7 @@ namespace MWMechanics // We chose to use the chance MW would have when run at 60 FPS with the default value of the GMST. const float delta = MWBase::Environment::get().getFrameDuration() * 6.f; static const float fVoiceIdleOdds = world->getStore().get().find("fVoiceIdleOdds")->mValue.getFloat(); - if (Misc::Rng::rollProbability() * 10000.f < fVoiceIdleOdds * delta && world->getLOS(getPlayer(), actor)) + if (Misc::Rng::rollProbability(world->getPrng()) * 10000.f < fVoiceIdleOdds * delta && world->getLOS(getPlayer(), actor)) MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); } diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 6a59ae2bfb..e8cb71add0 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -80,7 +80,8 @@ bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const void MWMechanics::AiAvoidDoor::adjustDirection() { - mDirection = Misc::Rng::rollDice(MAX_DIRECTIONS); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + mDirection = Misc::Rng::rollDice(MAX_DIRECTIONS, prng); } float MWMechanics::AiAvoidDoor::getAdjustedAngle() const diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 9776bb8891..12671d50dd 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -370,7 +370,8 @@ namespace MWMechanics if (!points.empty()) { - ESM::Pathgrid::Point dest = points[Misc::Rng::rollDice(points.size())]; + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + ESM::Pathgrid::Point dest = points[Misc::Rng::rollDice(points.size(), prng)]; coords.toWorld(dest); state = AiCombatStorage::FleeState_RunToDestination; @@ -464,8 +465,38 @@ namespace MWMechanics sequence.mPackages.push_back(std::move(package)); } + + AiCombatStorage::AiCombatStorage() : + mAttackCooldown(0.0f), + mReaction(MWBase::Environment::get().getWorld()->getPrng()), + mTimerCombatMove(0.0f), + mReadyToAttack(false), + mAttack(false), + mAttackRange(0.0f), + mCombatMove(false), + mRotateMove(false), + mLastTargetPos(0, 0, 0), + mCell(nullptr), + mCurrentAction(), + mActionCooldown(0.0f), + mStrength(), + mForceNoShortcut(false), + mShortcutFailPos(), + mMovement(), + mFleeState(FleeState_None), + mLOS(false), + mUpdateLOSTimer(0.0f), + mFleeBlindRunTimer(0.0f), + mUseCustomDestination(false), + mCustomDestination() + { + + } + void AiCombatStorage::startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target) { + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + // get the range of the target's weapon MWWorld::Ptr targetWeapon = MWWorld::Ptr(); const MWWorld::Class& targetClass = target.getClass(); @@ -483,7 +514,7 @@ namespace MWMechanics if (mMovement.mPosition[0] || mMovement.mPosition[1]) { - mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(prng); mCombatMove = true; } else if (isDistantCombat) @@ -537,11 +568,11 @@ namespace MWMechanics // if actor is within range of target's weapon. if (std::abs(angleToTarget) > osg::PI / 4) moveDuration = 0.2f; - else if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25) - moveDuration = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + else if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability(prng) < 0.25) + moveDuration = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(prng); if (moveDuration > 0) { - mMovement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; // to the left/right + mMovement.mPosition[0] = Misc::Rng::rollProbability(prng) < 0.5 ? 1.0f : -1.0f; // to the left/right mTimerCombatMove = moveDuration; mCombatMove = true; } @@ -580,7 +611,8 @@ namespace MWMechanics if (!distantCombat) characterController.setAIAttackType(chooseBestAttack(weapon)); - mStrength = Misc::Rng::rollClosedProbability(); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + mStrength = Misc::Rng::rollClosedProbability(prng); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -592,11 +624,11 @@ namespace MWMechanics // Say a provoking combat phrase const int iVoiceAttackOdds = store.get().find("iVoiceAttackOdds")->mValue.getInteger(); - if (Misc::Rng::roll0to99() < iVoiceAttackOdds) + if (Misc::Rng::roll0to99(prng) < iVoiceAttackOdds) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } - mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); + mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(prng), baseDelay + 0.9); } else mAttackCooldown -= AI_REACTION_TIME; @@ -657,7 +689,8 @@ std::string chooseBestAttack(const ESM::Weapon* weapon) int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; - float roll = Misc::Rng::rollClosedProbability() * (slash + chop + thrust); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + float roll = Misc::Rng::rollClosedProbability(prng) * (slash + chop + thrust); if(roll <= slash) attackType = "slash"; else if(roll <= (slash + thrust)) diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index c783994b97..566ec354d6 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -59,29 +59,7 @@ namespace MWMechanics bool mUseCustomDestination; osg::Vec3f mCustomDestination; - AiCombatStorage(): - mAttackCooldown(0.0f), - mTimerCombatMove(0.0f), - mReadyToAttack(false), - mAttack(false), - mAttackRange(0.0f), - mCombatMove(false), - mRotateMove(false), - mLastTargetPos(0,0,0), - mCell(nullptr), - mCurrentAction(), - mActionCooldown(0.0f), - mStrength(), - mForceNoShortcut(false), - mShortcutFailPos(), - mMovement(), - mFleeState(FleeState_None), - mLOS(false), - mUpdateLOSTimer(0.0f), - mFleeBlindRunTimer(0.0f), - mUseCustomDestination(false), - mCustomDestination() - {} + AiCombatStorage(); void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target); void updateCombatMove(float duration); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index e8e03daad6..1a674d444a 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -43,6 +43,7 @@ namespace MWMechanics::AiPackage::AiPackage(AiPackageTypeId typeId, const Options& options) : mTypeId(typeId), + mReaction(MWBase::Environment::get().getWorld()->getPrng()), mOptions(options), mTargetActorRefId(""), mTargetActorId(-1), diff --git a/apps/openmw/mwmechanics/aitimer.hpp b/apps/openmw/mwmechanics/aitimer.hpp index 804cda1bd2..e4bc07e52d 100644 --- a/apps/openmw/mwmechanics/aitimer.hpp +++ b/apps/openmw/mwmechanics/aitimer.hpp @@ -13,13 +13,20 @@ namespace MWMechanics public: static constexpr float sDeviation = 0.1f; - Misc::TimerStatus update(float duration) { return mImpl.update(duration); } + AiReactionTimer(Misc::Rng::Generator& prng) + : mPrng{ prng } + , mImpl{ AI_REACTION_TIME, sDeviation, Misc::Rng::deviate(0, sDeviation, prng) } + { + } - void reset() { mImpl.reset(Misc::Rng::deviate(0, sDeviation)); } + Misc::TimerStatus update(float duration) { return mImpl.update(duration, mPrng); } + + void reset() { mImpl.reset(Misc::Rng::deviate(0, sDeviation, mPrng)); } private: - Misc::DeviatingPeriodicTimer mImpl {AI_REACTION_TIME, sDeviation, - Misc::Rng::deviate(0, sDeviation)}; + Misc::Rng::Generator& mPrng; + Misc::DeviatingPeriodicTimer mImpl; + }; } diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 4a2df475f4..919685e93d 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -36,11 +36,13 @@ namespace MWMechanics { AiTravel::AiTravel(float x, float y, float z, bool repeat, AiTravel*) : TypedAiPackage(repeat), mX(x), mY(y), mZ(z), mHidden(false) + , mDestinationCheck(MWBase::Environment::get().getWorld()->getPrng()) { } AiTravel::AiTravel(float x, float y, float z, AiInternalTravel* derived) : TypedAiPackage(derived), mX(x), mY(y), mZ(z), mHidden(true) + , mDestinationCheck(MWBase::Environment::get().getWorld()->getPrng()) { } @@ -51,6 +53,7 @@ namespace MWMechanics AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel) : TypedAiPackage(travel->mRepeat), mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(false) + , mDestinationCheck(MWBase::Environment::get().getWorld()->getPrng()) { // Hidden ESM::AiSequence::AiTravel package should be converted into MWMechanics::AiInternalTravel type assert(!travel->mHidden); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index c63a4c0270..ebaff54f20 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -59,7 +59,8 @@ namespace MWMechanics osg::Vec3f getRandomPointAround(const osg::Vec3f& position, const float distance) { - const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * osg::PI; + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const float randomDirection = Misc::Rng::rollClosedProbability(prng) * 2.0f * osg::PI; osg::Matrixf rotation; rotation.makeRotate(randomDirection, osg::Vec3f(0.0, 0.0, 1.0)); return position + osg::Vec3f(distance, 0.0, 0.0) * rotation; @@ -102,6 +103,22 @@ namespace MWMechanics { return std::vector(std::begin(idle), std::end(idle)); } + + } + + AiWanderStorage::AiWanderStorage() : + mState(Wander_ChooseAction), + mIsWanderingManually(false), + mCanWanderAlongPathGrid(true), + mIdleAnimation(0), + mBadIdles(), + mPopulateAvailableNodes(true), + mAllowedNodes(), + mTrimCurrentNode(false), + mCheckIdlePositionTimer(0), + mStuckCount(0), + mReaction(MWBase::Environment::get().getWorld()->getPrng()) + { } AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): @@ -250,9 +267,10 @@ namespace MWMechanics getAllowedNodes(actor, actor.getCell()->getCell(), storage); } + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); if (canActorMoveByZAxis(actor) && mDistance > 0) { // Typically want to idle for a short time before the next wander - if (Misc::Rng::rollDice(100) >= 92 && storage.mState != AiWanderStorage::Wander_Walking) { + if (Misc::Rng::rollDice(100, prng) >= 92 && storage.mState != AiWanderStorage::Wander_Walking) { wanderNearStart(actor, storage, mDistance); } @@ -262,7 +280,7 @@ namespace MWMechanics // randomly idle or wander near spawn point else if(storage.mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) { // Typically want to idle for a short time before the next wander - if (Misc::Rng::rollDice(100) >= 96) { + if (Misc::Rng::rollDice(100, prng) >= 96) { wanderNearStart(actor, storage, mDistance); } else { storage.setState(AiWanderStorage::Wander_IdleNow); @@ -330,10 +348,12 @@ namespace MWMechanics const auto navigator = world->getNavigator(); const auto navigatorFlags = getNavigatorFlags(actor); const auto areaCosts = getAreaCosts(actor); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); do { + // Determine a random location within radius of original position - const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance; + const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability(prng) * 0.8f) * wanderDistance; if (!isWaterCreature && !isFlyingCreature) { // findRandomPointAroundCircle uses wanderDistance as limit for random and not as exact distance @@ -544,7 +564,8 @@ namespace MWMechanics void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) { - unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size()); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng); ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]); ToWorldCoordinates(dest, actor.getCell()->getCell()); @@ -650,11 +671,11 @@ namespace MWMechanics for(unsigned int counter = 0; counter < mIdle.size(); counter++) { - static float fIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore() - .get().find("fIdleChanceMultiplier")->mValue.getFloat(); + MWBase::World* world = MWBase::Environment::get().getWorld(); + static float fIdleChanceMultiplier = world->getStore().get().find("fIdleChanceMultiplier")->mValue.getFloat(); unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); - unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); + unsigned short randSelect = (int)(Misc::Rng::rollProbability(world->getPrng()) * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { selectedAnimation = counter + GroupIndex_MinIdle; @@ -678,7 +699,8 @@ namespace MWMechanics if (storage.mAllowedNodes.empty()) return; - int index = Misc::Rng::rollDice(storage.mAllowedNodes.size()); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int index = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng); ESM::Pathgrid::Point dest = storage.mAllowedNodes[index]; ESM::Pathgrid::Point worldDest = dest; ToWorldCoordinates(worldDest, actor.getCell()->getCell()); @@ -700,7 +722,7 @@ namespace MWMechanics // AI will try to move the NPC towards every neighboring node until suitable place will be found for (int i = 0; i < initialSize; i++) { - int randomIndex = Misc::Rng::rollDice(points.size()); + int randomIndex = Misc::Rng::rollDice(points.size(), prng); ESM::Pathgrid::Point connDest = points[randomIndex]; // add an offset towards random neighboring node diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index f8506ff594..02a1054363 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -55,18 +55,7 @@ namespace MWMechanics float mCheckIdlePositionTimer; int mStuckCount; - AiWanderStorage(): - mState(Wander_ChooseAction), - mIsWanderingManually(false), - mCanWanderAlongPathGrid(true), - mIdleAnimation(0), - mBadIdles(), - mPopulateAvailableNodes(true), - mAllowedNodes(), - mTrimCurrentNode(false), - mCheckIdlePositionTimer(0), - mStuckCount(0) - {}; + AiWanderStorage(); void setState(const WanderState wanderState, const bool isManualWander = false) { diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index f513554c12..d60eac15de 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -289,7 +289,8 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) newRecord.mName = name; - int index = Misc::Rng::rollDice(6); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int index = Misc::Rng::rollDice(6, prng); assert (index>=0 && index<6); static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; @@ -527,8 +528,8 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::createSingle () removeIngredients(); return Result_RandomFailure; } - - if (getAlchemyFactor() < Misc::Rng::roll0to99()) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (getAlchemyFactor() < Misc::Rng::roll0to99(prng)) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 25a5ac6aa0..1c0a4f2c85 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -193,11 +193,13 @@ public: std::string CharacterController::chooseRandomGroup (const std::string& prefix, int* num) const { + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int numAnims=0; while (mAnimation->hasAnimation(prefix + std::to_string(numAnims+1))) ++numAnims; - int roll = Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] + int roll = Misc::Rng::rollDice(numAnims, prng) + 1; // [1, numAnims] if (num) *num = roll; return prefix + std::to_string(roll); @@ -209,12 +211,13 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle) bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); if(mHitState == CharState_None) { if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0)) { - mTimeUntilWake = Misc::Rng::rollClosedProbability() * 2 + 1; // Wake up after 1 to 3 seconds + mTimeUntilWake = Misc::Rng::rollClosedProbability(prng) * 2 + 1; // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; @@ -678,7 +681,8 @@ void CharacterController::refreshIdleAnims(const std::string& weapShortGroup, Ch // play until the Loop Stop key 2 to 5 times, then play until the Stop key // this replicates original engine behavior for the "Idle1h" 1st-person animation - numLoops = 1 + Misc::Rng::rollDice(4); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + numLoops = 1 + Misc::Rng::rollDice(4, prng); } } @@ -1131,6 +1135,8 @@ bool CharacterController::updateCarriedLeftVisible(const int weaptype) const bool CharacterController::updateState(CharacterState idle) { + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const MWWorld::Class &cls = mPtr.getClass(); CreatureStats &stats = cls.getCreatureStats(mPtr); int weaptype = ESM::Weapon::None; @@ -1288,7 +1294,7 @@ bool CharacterController::updateState(CharacterState idle) if(isWerewolf) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Sound *sound = store.get().searchRandom("WolfEquip"); + const ESM::Sound *sound = store.get().searchRandom("WolfEquip", prng); if(sound) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -1563,7 +1569,7 @@ bool CharacterController::updateState(CharacterState idle) mUpperBodyState = UpperCharState_StartToMinAttack; if (isRandomAttackAnimation(mCurrentWeapon)) { - mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); + mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability(prng)); playSwishSound(0.0f); } } @@ -1596,7 +1602,7 @@ bool CharacterController::updateState(CharacterState idle) // 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 + Misc::Rng::rollClosedProbability()); + attackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability(prng)); } if(weapclass != ESM::WeaponType::Ranged && weapclass != ESM::WeaponType::Thrown) @@ -1606,7 +1612,7 @@ bool CharacterController::updateState(CharacterState idle) if(isWerewolf) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Sound *sound = store.get().searchRandom("WolfSwing"); + const ESM::Sound *sound = store.get().searchRandom("WolfSwing", prng); if(sound) sndMgr->playSound3D(mPtr, sound->mId, 1.0f, 1.0f); } @@ -2771,7 +2777,8 @@ void CharacterController::setAIAttackType(const std::string& attackType) void CharacterController::setAttackTypeRandomly(std::string& attackType) { - float random = Misc::Rng::rollProbability(); + MWBase::World* world = MWBase::Environment::get().getWorld(); + float random = Misc::Rng::rollProbability(world->getPrng()); if (random >= 2/3.f) attackType = "thrust"; else if (random >= 1/3.f) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 0eccd6688c..27582840df 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -117,7 +117,8 @@ namespace MWMechanics const int iBlockMinChance = gmst.find("iBlockMinChance")->mValue.getInteger(); int x = std::clamp(blockerTerm - attackerTerm, iBlockMinChance, iBlockMaxChance); - if (Misc::Rng::roll0to99() < x) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (Misc::Rng::roll0to99(prng) < x) { // Reduce shield durability by incoming damage int shieldhealth = shield->getClass().getItemHealth(*shield); @@ -212,7 +213,7 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weaponSkill); - if (Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue)) + if (Misc::Rng::roll0to99(world->getPrng()) >= getHitChance(attacker, victim, skillValue)) { victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false); MWMechanics::reduceWeaponCondition(damage, false, weapon, attacker); @@ -262,7 +263,7 @@ namespace MWMechanics if (victim != getPlayer() && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->mValue.getFloat(); - if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) + if (Misc::Rng::rollProbability(world->getPrng()) < fProjectileThrownStoreChance / 100.f) victim.getClass().getContainerStore(victim).add(projectile, 1, victim); } @@ -315,6 +316,7 @@ namespace MWMechanics bool godmode = attacker == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); if (godmode) return; + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); for (int i=0; i<3; ++i) { float magnitude = victim.getClass().getCreatureStats(victim).getMagicEffects().get(ESM::MagicEffect::FireShield+i).getMagnitude(); @@ -334,7 +336,7 @@ namespace MWMechanics saveTerm *= 1.25f * normalisedFatigue; - float x = std::max(0.f, saveTerm - Misc::Rng::roll0to99()); + float x = std::max(0.f, saveTerm - Misc::Rng::roll0to99(prng)); int element = ESM::MagicEffect::FireDamage; if (i == 1) @@ -444,7 +446,8 @@ namespace MWMechanics MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(isWerewolf) { - const ESM::Sound *sound = store.get().searchRandom("WolfHit"); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const ESM::Sound *sound = store.get().searchRandom("WolfHit", prng); if(sound) sndMgr->playSound3D(victim, sound->mId, 1.0f, 1.0f); } diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 426a66ecf2..82c5236ca4 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -52,7 +52,8 @@ namespace MWMechanics continue; int x = static_cast(fDiseaseXferChance * 100 * resist); - if (Misc::Rng::rollDice(10000) < x) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (Misc::Rng::rollDice(10000, prng) < x) { // Contracted disease! actor.getClass().getCreatureStats(actor).getSpells().add(spell); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index a1870cbdb0..7ed58f0d25 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -76,7 +76,8 @@ namespace MWMechanics if(mSelfEnchanting) { - if(getEnchantChance() <= (Misc::Rng::roll0to99())) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if(getEnchantChance() <= (Misc::Rng::roll0to99(prng))) 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 a1eb958ed1..be5c5962bb 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -19,7 +19,7 @@ namespace MWMechanics { /// @return ID of resulting item, or empty if none - inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, Misc::Rng::Generator& prng = Misc::Rng::getGenerator()) + inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, Misc::Rng::Generator& prng) { const std::vector& items = levItem->mList; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 658c5c85c6..8cf6126cba 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -651,7 +651,8 @@ namespace MWMechanics float x = 0; float y = 0; - int roll = Misc::Rng::roll0to99(); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int roll = Misc::Rng::roll0to99(prng); if (type == PT_Admire) { @@ -1570,8 +1571,8 @@ namespace MWMechanics } float target = x - y; - - return (Misc::Rng::roll0to99() >= target); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + return (Misc::Rng::roll0to99(prng) >= 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 038753f7d1..1b638eadd2 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -41,7 +41,8 @@ namespace MWMechanics int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->mValue.getInteger(); - int roll = Misc::Rng::roll0to99(); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int roll = Misc::Rng::roll0to99(prng); if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); diff --git a/apps/openmw/mwmechanics/recharge.cpp b/apps/openmw/mwmechanics/recharge.cpp index 51c78e1e3b..1f92466e04 100644 --- a/apps/openmw/mwmechanics/recharge.cpp +++ b/apps/openmw/mwmechanics/recharge.cpp @@ -49,7 +49,8 @@ bool rechargeItem(const MWWorld::Ptr &item, const MWWorld::Ptr &gem) intelligenceTerm = 1; float x = (player.getClass().getSkill(player, ESM::Skill::Enchant) + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = Misc::Rng::roll0to99(); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int roll = Misc::Rng::roll0to99(prng); if (roll < x) { std::string soul = gem.getCellRef().getSoul(); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 81886ed9b0..ac6cc5b414 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -44,7 +44,8 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = Misc::Rng::roll0to99(); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int roll = Misc::Rng::roll0to99(prng); 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 e642a7bb4b..bfb48dd754 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -54,7 +54,8 @@ namespace MWMechanics resultMessage = "#{sLockImpossible}"; else { - if (Misc::Rng::roll0to99() <= x) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (Misc::Rng::roll0to99(prng) <= x) { lock.getCellRef().unlock(); resultMessage = "#{sLockSuccess}"; @@ -98,7 +99,8 @@ namespace MWMechanics resultMessage = "#{sTrapImpossible}"; else { - if (Misc::Rng::roll0to99() <= x) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (Misc::Rng::roll0to99(prng) <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index c99eee43d5..b92cbc74fb 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -87,7 +87,8 @@ namespace MWMechanics : ESM::MagicEffect::ResistBlightDisease; float x = target.getClass().getCreatureStats(target).getMagicEffects().get(requiredResistance).getMagnitude(); - if (Misc::Rng::roll0to99() <= x) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (Misc::Rng::roll0to99(prng) <= x) { // Fully resisted, show message if (target == getPlayer()) @@ -339,7 +340,8 @@ namespace MWMechanics // Check success float successChance = getSpellSuccessChance(spell, mCaster, nullptr, true, false); - if (Misc::Rng::roll0to99() >= successChance) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + if (Misc::Rng::roll0to99(prng) >= successChance) { if (mCaster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); @@ -403,7 +405,8 @@ namespace MWMechanics + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = Misc::Rng::roll0to99(); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int roll = Misc::Rng::roll0to99(prng); if (roll > x) { // "X has no effect on you" diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index befe182cb5..ae18c6ae0c 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -35,7 +35,8 @@ namespace { if(effect.mMinMagnitude == effect.mMaxMagnitude) return effect.mMinMagnitude; - return effect.mMinMagnitude + Misc::Rng::rollDice(effect.mMaxMagnitude - effect.mMinMagnitude + 1); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + return effect.mMinMagnitude + Misc::Rng::rollDice(effect.mMaxMagnitude - effect.mMinMagnitude + 1, prng); } void modifyAiSetting(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, ESM::MagicEffect::Effects creatureEffect, MWMechanics::CreatureStats::AiSetting setting, float magnitude, bool& invalid) @@ -305,6 +306,7 @@ namespace bool canAbsorb = !(effect.mFlags & ESM::ActiveEffect::Flag_Ignore_SpellAbsorption) && magnitudes.get(ESM::MagicEffect::SpellAbsorption).getMagnitude() > 0.f; if(canReflect || canAbsorb) { + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); for(const auto& activeParam : stats.getActiveSpells()) { for(const auto& activeEffect : activeParam.getEffects()) @@ -313,14 +315,14 @@ namespace continue; if(activeEffect.mEffectId == ESM::MagicEffect::Reflect) { - if(canReflect && Misc::Rng::roll0to99() < activeEffect.mMagnitude) + if(canReflect && Misc::Rng::roll0to99(prng) < activeEffect.mMagnitude) { return MWMechanics::MagicApplicationResult::REFLECTED; } } else if(activeEffect.mEffectId == ESM::MagicEffect::SpellAbsorption) { - if(canAbsorb && Misc::Rng::roll0to99() < activeEffect.mMagnitude) + if(canAbsorb && Misc::Rng::roll0to99(prng) < activeEffect.mMagnitude) { absorbSpell(spellParams.getId(), caster, target); return MWMechanics::MagicApplicationResult::REMOVED; @@ -405,8 +407,11 @@ void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, co if(params.getType() == ESM::ActiveSpells::Type_Temporary) { const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(params.getId()); - if(spell && spell->mData.mType == ESM::Spell::ST_Spell) - return Misc::Rng::roll0to99() < magnitude; + if (spell && spell->mData.mType == ESM::Spell::ST_Spell) + { + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + return Misc::Rng::roll0to99(prng) < magnitude; + } } return false; }, target); diff --git a/apps/openmw/mwmechanics/spellresistance.cpp b/apps/openmw/mwmechanics/spellresistance.cpp index 1edf140915..bb39255b43 100644 --- a/apps/openmw/mwmechanics/spellresistance.cpp +++ b/apps/openmw/mwmechanics/spellresistance.cpp @@ -51,7 +51,8 @@ namespace MWMechanics if (castChance > 0) x *= 50 / castChance; - float roll = Misc::Rng::rollClosedProbability() * 100; + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + float roll = Misc::Rng::rollClosedProbability(prng) * 100; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) roll -= resistance; diff --git a/apps/openmw/mwmechanics/trading.cpp b/apps/openmw/mwmechanics/trading.cpp index d9ec66bab2..a40b745d21 100644 --- a/apps/openmw/mwmechanics/trading.cpp +++ b/apps/openmw/mwmechanics/trading.cpp @@ -57,7 +57,8 @@ namespace MWMechanics + gmst.find("fBargainOfferBase")->mValue.getFloat() + int(pcTerm - npcTerm); - int roll = Misc::Rng::rollDice(100) + 1; + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + int roll = Misc::Rng::rollDice(100, prng) + 1; // reject if roll fails // (or if player tries to buy things and get money) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 01f59fd69c..40ad3b7835 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -61,7 +61,8 @@ namespace } else { - std::string itemId = MWMechanics::getLevelledItem(itemPtr.get()->mBase, false); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + std::string itemId = MWMechanics::getLevelledItem(itemPtr.get()->mBase, false, prng); if (itemId.empty()) return; MWWorld::ManualRef manualRef(MWBase::Environment::get().getWorld()->getStore(), itemId, 1); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 0c5a47e029..38da34201b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -111,7 +111,8 @@ namespace MWScript throw std::runtime_error ( "random: argument out of range (Don't be so negative!)"); - runtime.push (static_cast(::Misc::Rng::rollDice(limit))); // [o, limit) + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + runtime.push (static_cast(::Misc::Rng::rollDice(limit, prng))); // [o, limit) } }; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index c8cd53a331..50a3a48ad8 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -466,6 +466,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str case ESM::REC_LEVI: case ESM::REC_CREA: case ESM::REC_CONT: + case ESM::REC_RAND: MWBase::Environment::get().getWorld()->readRecord(reader, n.toInt(), contentFileMap); break; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index ac78114932..34a2b49c7b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -333,7 +333,8 @@ namespace MWWorld if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Sound *sound = store.get().searchRandom("WolfItem"); + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + const ESM::Sound *sound = store.get().searchRandom("WolfItem", prng); std::shared_ptr action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); if(sound) action->setSound(sound->mId); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 1951f0708e..92c28bbcb5 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -221,7 +221,7 @@ namespace MWWorld virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; ///< @return true if the two specified objects can stack with each other - void fill (const ESM::InventoryList& items, const std::string& owner, Misc::Rng::Generator& seed = Misc::Rng::getGenerator()); + void fill (const ESM::InventoryList& items, const std::string& owner, Misc::Rng::Generator& seed); ///< Insert items into *this. void fillNonRandom (const ESM::InventoryList& items, const std::string& owner, unsigned int seed); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index d35746dfff..095c40697e 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -125,7 +125,7 @@ namespace MWWorld return (dit != mDynamic.end()); } template - const T *Store::searchRandom(const std::string &id) const + const T *Store::searchRandom(const std::string &id, Misc::Rng::Generator& prng) const { std::vector results; std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results), @@ -134,7 +134,7 @@ namespace MWWorld return Misc::StringUtils::ciCompareLen(id, item->mId, id.size()) == 0; }); if(!results.empty()) - return results[Misc::Rng::rollDice(results.size())]; + return results[Misc::Rng::rollDice(results.size(), prng)]; return nullptr; } template diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 1ec51ad5fd..bcd744c23c 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -10,6 +10,7 @@ #include #include +#include #include "../mwdialogue/keywordsearch.hpp" @@ -181,7 +182,7 @@ namespace MWWorld bool isDynamic(const std::string &id) const; /** Returns a random record that starts with the named ID, or nullptr if not found. */ - const T *searchRandom(const std::string &id) const; + const T *searchRandom(const std::string &id, Misc::Rng::Generator& prng) const; const T *find(const std::string &id) const; diff --git a/components/misc/timer.hpp b/components/misc/timer.hpp index 81a2ca073c..910d45bc03 100644 --- a/components/misc/timer.hpp +++ b/components/misc/timer.hpp @@ -18,7 +18,7 @@ namespace Misc : mPeriod(period), mDeviation(deviation), mTimeLeft(timeLeft) {} - TimerStatus update(float duration) + TimerStatus update(float duration, Rng::Generator& prng) { if (mTimeLeft > 0) { @@ -26,7 +26,7 @@ namespace Misc return TimerStatus::Waiting; } - mTimeLeft = Rng::deviate(mPeriod, mDeviation); + mTimeLeft = Rng::deviate(mPeriod, mDeviation, prng); return TimerStatus::Elapsed; }