From 461cc0930fd039dc5c2403e4530e0bb3a4246df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= <159546+serprex@users.noreply.github.com> Date: Mon, 20 Apr 2026 17:18:48 +0000 Subject: [PATCH] don't use 3drando/random.hpp outside 3drando (#6537) --- .../ExtraModes/EnemyRandomizer.cpp | 19 ++++----- .../Enhancements/ExtraModes/MirroredWorld.cpp | 19 +++++---- soh/soh/Enhancements/audio/AudioEditor.cpp | 2 +- .../GameInteractor_RawAction.cpp | 4 +- .../randomizer/3drando/random.cpp | 4 -- soh/soh/Enhancements/randomizer/Traps.cpp | 15 +++---- soh/soh/Enhancements/randomizer/settings.cpp | 39 ++++++++++--------- .../Network/Anchor/Packets/GameComplete.cpp | 4 +- 8 files changed, 54 insertions(+), 52 deletions(-) diff --git a/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp b/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp index d2579e127..04514b352 100644 --- a/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp +++ b/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp @@ -1,6 +1,6 @@ #include "functions.h" #include "macros.h" -#include "soh/Enhancements/randomizer/3drando/random.hpp" +#include "soh/ShipUtils.h" #include "soh/Enhancements/randomizer/SeedContext.h" #include "soh/Enhancements/enhancementTypes.h" #include "soh/ObjectExtension/ObjectExtension.h" @@ -304,15 +304,16 @@ EnemyEntry GetRandomizedEnemyEntry(uint32_t seed, PlayState* play) { filteredEnemyList = selectedEnemyList; } if (CVAR_ENEMY_RANDOMIZER_VALUE == ENEMY_RANDOMIZER_RANDOM_SEEDED) { - uint32_t finalSeed = - seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt); - Random_Init(finalSeed); - uint32_t randomNumber = Random(0, filteredEnemyList.size()); - return filteredEnemyList[randomNumber]; - } else { - uint32_t randomSelectedEnemy = Random(0, filteredEnemyList.size()); - return filteredEnemyList[randomSelectedEnemy]; + uint64_t randomState = 0; + + ShipUtils::RandInit( + seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt), + &randomState); + + return ShipUtils::RandomElement(filteredEnemyList, false, &randomState); } + + return ShipUtils::RandomElement(filteredEnemyList, false); } bool IsEnemyFoundToRandomize(int16_t sceneNum, int8_t roomNum, int16_t actorId, int16_t params, float posX) { diff --git a/soh/soh/Enhancements/ExtraModes/MirroredWorld.cpp b/soh/soh/Enhancements/ExtraModes/MirroredWorld.cpp index 98d9c2c0d..304046bb4 100644 --- a/soh/soh/Enhancements/ExtraModes/MirroredWorld.cpp +++ b/soh/soh/Enhancements/ExtraModes/MirroredWorld.cpp @@ -1,6 +1,6 @@ #include "soh/Enhancements/cosmetics/authenticGfxPatches.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/Enhancements/randomizer/3drando/random.hpp" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/ShipUtils.h" #include "soh/Enhancements/randomizer/SeedContext.h" #include "soh/Enhancements/enhancementTypes.h" #include "soh/ResourceManagerHelpers.h" @@ -25,20 +25,22 @@ static bool MirroredWorld_IsInDungeon(int32_t sceneNum) { (sceneNum == SCENE_GANON_BOSS); } -static void MirroredWorld_InitRandomSeed(int32_t sceneNum) { +static void MirroredWorld_InitRandomSeed(int32_t sceneNum, uint64_t* randState) { uint32_t seed = sceneNum + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt); - Random_Init(seed); + ShipUtils::RandInit(seed, randState); } static bool MirroredWorld_ShouldApply(int32_t sceneNum) { + uint64_t randState = 0; switch (CVAR_MIRRORED_WORLD_MODE_VALUE) { case MIRRORED_WORLD_ALWAYS: return true; case MIRRORED_WORLD_RANDOM_SEEDED: - MirroredWorld_InitRandomSeed(sceneNum); + MirroredWorld_InitRandomSeed(sceneNum, &randState); + return ShipUtils::Random(0, 2, &randState) == 0; case MIRRORED_WORLD_RANDOM: - return Random(0, 2) == 1; + return ShipUtils::Random(0, 2) == 0; case MIRRORED_WORLD_DUNGEONS_ALL: return MirroredWorld_IsInDungeon(sceneNum); case MIRRORED_WORLD_DUNGEONS_VANILLA: @@ -46,9 +48,10 @@ static bool MirroredWorld_ShouldApply(int32_t sceneNum) { case MIRRORED_WORLD_DUNGEONS_MQ: return MirroredWorld_IsInDungeon(sceneNum) && ResourceMgr_IsSceneMasterQuest(sceneNum); case MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED: - MirroredWorld_InitRandomSeed(sceneNum); + MirroredWorld_InitRandomSeed(sceneNum, &randState); + return MirroredWorld_IsInDungeon(sceneNum) && ShipUtils::Random(0, 2, &randState) == 0; case MIRRORED_WORLD_DUNGEONS_RANDOM: - return MirroredWorld_IsInDungeon(sceneNum) && (Random(0, 2) == 1); + return MirroredWorld_IsInDungeon(sceneNum) && ShipUtils::Random(0, 2) == 0; default: return false; } diff --git a/soh/soh/Enhancements/audio/AudioEditor.cpp b/soh/soh/Enhancements/audio/AudioEditor.cpp index 6139da7c0..60a20805f 100644 --- a/soh/soh/Enhancements/audio/AudioEditor.cpp +++ b/soh/soh/Enhancements/audio/AudioEditor.cpp @@ -6,7 +6,7 @@ #include #include #include -#include "../randomizer/3drando/random.hpp" +#include "soh/ShipUtils.h" #include "soh/OTRGlobals.h" #include "soh/cvar_prefixes.h" #include diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp index 9ffdb2452..a1fa273cb 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp @@ -1,6 +1,6 @@ #include "GameInteractor.h" #include -#include "soh/Enhancements/randomizer/3drando/random.hpp" +#include "soh/ShipUtils.h" #include #include "soh/Enhancements/debugger/colViewer.h" #include "soh/Enhancements/nametag.h" @@ -498,7 +498,7 @@ GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnEnemyWithOffset } // Generate point in random angle with a radius. - float angle = static_cast(RandomDouble() * 2 * M_PI); + float angle = static_cast(ShipUtils::RandomDouble() * 2 * M_PI); float radius = 150; float posXOffset = radius * cos(angle); float posZOffset = radius * sin(angle); diff --git a/soh/soh/Enhancements/randomizer/3drando/random.cpp b/soh/soh/Enhancements/randomizer/3drando/random.cpp index 73b97f6b6..b0b3f796e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/random.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/random.cpp @@ -9,10 +9,6 @@ void Random_Init(uint64_t seed) { ShipUtils::RandInit(seed, &rando_state); } -uint32_t next32() { - return ShipUtils::next32(&rando_state); -} - // Returns a random integer in range [min, max-1] uint32_t Random(uint32_t min, uint32_t max) { return ShipUtils::Random(min, max, &rando_state); diff --git a/soh/soh/Enhancements/randomizer/Traps.cpp b/soh/soh/Enhancements/randomizer/Traps.cpp index 050913a4a..d6334ba3a 100644 --- a/soh/soh/Enhancements/randomizer/Traps.cpp +++ b/soh/soh/Enhancements/randomizer/Traps.cpp @@ -2,7 +2,7 @@ #include "soh/Enhancements/randomizer/SeedContext.h" #include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/randomizer/static_data.h" -#include "soh/Enhancements/randomizer/3drando/random.hpp" +#include "soh/ShipUtils.h" #include @@ -1431,19 +1431,19 @@ Text Rando::Traps::GetTrapName(uint16_t id) { } // Randomly get the easy, medium, or hard name for the given item id - return RandomElement(trickNameTable[id]); + return ShipUtils::RandomElement(trickNameTable[id]); } RandomizerGet Rando::Traps::GetTrapTrickModel() { auto ctx = Rando::Context::GetInstance(); - RandomizerGet trickModel = RandomElementFromSet(ctx->possibleIceTrapModels); + RandomizerGet trickModel = ShipUtils::RandomElementFromSet(ctx->possibleIceTrapModels); if (trickModel == RG_EMPTY_BOTTLE) { - trickModel = RandomElement(Rando::StaticData::normalBottles); + trickModel = ShipUtils::RandomElement(Rando::StaticData::normalBottles); } else if (trickModel == RG_GUARD_HOUSE_KEY) { - trickModel = RandomElement(Rando::StaticData::overworldKeys); + trickModel = ShipUtils::RandomElement(Rando::StaticData::overworldKeys); } else if (trickModel == RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL) { - trickModel = RandomElement(Rando::StaticData::beanSouls); + trickModel = ShipUtils::RandomElement(Rando::StaticData::beanSouls); } return trickModel; @@ -1456,7 +1456,8 @@ bool Rando::Traps::ShouldJunkItemBeTrap() { return false; } - if (ctx->GetOption(RSK_ICE_TRAP_PERCENT).Is(100) || Random(0, 100) < ctx->GetOption(RSK_ICE_TRAP_PERCENT).Get()) { + if (ctx->GetOption(RSK_ICE_TRAP_PERCENT).Is(100) || + ShipUtils::Random(0, 100) < ctx->GetOption(RSK_ICE_TRAP_PERCENT).Get()) { return true; } diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index ad92fede4..3a058db89 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -2,7 +2,7 @@ #include "soh/Enhancements/randomizer/randomizerTypes.h" #include "trial.h" #include "dungeon.h" -#include "3drando/random.hpp" +#include "soh/ShipUtils.h" #include "soh/OTRGlobals.h" @@ -2600,7 +2600,7 @@ void Context::FinalizeSettings(const std::set& excludedLocation case RO_MQ_SET_RANDOM: // 50% per dungeon, rolled separatly so people can either have a linear distribtuion // or a bell curve for the number of MQ dungeons per seed. - if (Random(0, 2)) { + if (ShipUtils::Random(0, 2)) { dungeon->SetMQ(); mqSet += 1; } @@ -2667,13 +2667,13 @@ void Context::FinalizeSettings(const std::set& excludedLocation if (randMQOption.size() > 0) { // Figure out how many dungeons to select, rolling the random number if needed if (mOptions[RSK_MQ_DUNGEON_RANDOM].Is(RO_MQ_DUNGEONS_RANDOM_NUMBER)) { - mqToSet = Random(0, static_cast(randMQOption.size()) + 1); + mqToSet = ShipUtils::Random(0, static_cast(randMQOption.size()) + 1); } else if (mqCount > mqSet) { mqToSet = std::min(mqCount - mqSet, static_cast(randMQOption.size())); } // we only need to shuffle if we're not using them all if (mqToSet <= static_cast(randMQOption.size()) && mqToSet > 0) { - Shuffle(randMQOption); + ShipUtils::Shuffle(randMQOption); } for (uint8_t i = 0; i < mqToSet; i++) { dungeons[randMQOption[i]]->SetMQ(); @@ -2722,8 +2722,8 @@ void Context::FinalizeSettings(const std::set& excludedLocation if (mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_RANDOM) || mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT)) { const uint32_t keyRingCount = mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT) ? mOptions[RSK_KEYRINGS_RANDOM_COUNT].Get() - : Random(0, static_cast(keyrings.size())); - Shuffle(keyrings); + : ShipUtils::Random(0, static_cast(keyrings.size())); + ShipUtils::Shuffle(keyrings); for (size_t i = 0; i < keyRingCount; i++) { keyrings[i]->Set(RO_KEYRING_FOR_DUNGEON_ON); } @@ -2732,49 +2732,50 @@ void Context::FinalizeSettings(const std::set& excludedLocation } } if (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_ON) || - (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { + (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && + ShipUtils::Random(0, 2) == 0)) { this->GetDungeon(BOTTOM_OF_THE_WELL)->SetKeyRing(); } if (mOptions[RSK_KEYRINGS_FOREST_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || - (mOptions[RSK_KEYRINGS_FOREST_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { + (mOptions[RSK_KEYRINGS_FOREST_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && ShipUtils::Random(0, 2) == 0)) { this->GetDungeon(FOREST_TEMPLE)->SetKeyRing(); } if (mOptions[RSK_KEYRINGS_FIRE_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || - (mOptions[RSK_KEYRINGS_FIRE_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { + (mOptions[RSK_KEYRINGS_FIRE_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && ShipUtils::Random(0, 2) == 0)) { this->GetDungeon(FIRE_TEMPLE)->SetKeyRing(); } if (mOptions[RSK_KEYRINGS_WATER_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || - (mOptions[RSK_KEYRINGS_WATER_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { + (mOptions[RSK_KEYRINGS_WATER_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && ShipUtils::Random(0, 2) == 0)) { this->GetDungeon(WATER_TEMPLE)->SetKeyRing(); } if (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || - (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { + (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && ShipUtils::Random(0, 2) == 0)) { this->GetDungeon(SPIRIT_TEMPLE)->SetKeyRing(); } if (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || - (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { + (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && ShipUtils::Random(0, 2) == 0)) { this->GetDungeon(SHADOW_TEMPLE)->SetKeyRing(); } if (mOptions[RSK_KEYRINGS_GTG].Is(RO_KEYRING_FOR_DUNGEON_ON) || - (mOptions[RSK_KEYRINGS_GTG].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { + (mOptions[RSK_KEYRINGS_GTG].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && ShipUtils::Random(0, 2) == 0)) { this->GetDungeon(GERUDO_TRAINING_GROUND)->SetKeyRing(); } if (mOptions[RSK_KEYRINGS_GANONS_CASTLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || - (mOptions[RSK_KEYRINGS_GANONS_CASTLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { + (mOptions[RSK_KEYRINGS_GANONS_CASTLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && ShipUtils::Random(0, 2) == 0)) { this->GetDungeon(GANONS_CASTLE)->SetKeyRing(); } } auto trials = this->GetTrials()->GetTrialList(); - Shuffle(trials); + ShipUtils::Shuffle(trials); for (const auto trial : trials) { trial->SetAsSkipped(); } if (mOptions[RSK_GANONS_TRIALS].Is(RO_GANONS_TRIALS_SKIP)) { mOptions[RSK_TRIAL_COUNT].Set(0); } else if (mOptions[RSK_GANONS_TRIALS].Is(RO_GANONS_TRIALS_RANDOM_NUMBER)) { - mOptions[RSK_TRIAL_COUNT].Set( - Random(0, static_cast(Rando::Settings::GetInstance()->GetOption(RSK_TRIAL_COUNT).GetOptionCount()))); + mOptions[RSK_TRIAL_COUNT].Set(ShipUtils::Random( + 0, static_cast(Rando::Settings::GetInstance()->GetOption(RSK_TRIAL_COUNT).GetOptionCount()))); } for (uint8_t i = 0; i < mOptions[RSK_TRIAL_COUNT].Get(); i++) { trials[i]->SetAsRequired(); @@ -2816,7 +2817,7 @@ void Context::FinalizeSettings(const std::set& excludedLocation } if (mOptions[RSK_STARTING_AGE].Is(RO_AGE_RANDOM)) { - if (const uint32_t choice = Random(0, 2); choice == 0) { + if (const uint32_t choice = ShipUtils::Random(0, 2); choice == 0) { mOptions[RSK_SELECTED_STARTING_AGE].Set(RO_AGE_CHILD); } else { mOptions[RSK_SELECTED_STARTING_AGE].Set(RO_AGE_ADULT); @@ -2941,7 +2942,7 @@ void Settings::RandomizeAllSettings() { continue; } - uint8_t randomIndex = Random(0, static_cast(option.GetOptionCount())); + uint8_t randomIndex = ShipUtils::Random(0, static_cast(option.GetOptionCount())); option.SetContextIndex(randomIndex); if (!option.GetCVarName().empty()) { diff --git a/soh/soh/Network/Anchor/Packets/GameComplete.cpp b/soh/soh/Network/Anchor/Packets/GameComplete.cpp index e8fdaafc3..7f41ecfeb 100644 --- a/soh/soh/Network/Anchor/Packets/GameComplete.cpp +++ b/soh/soh/Network/Anchor/Packets/GameComplete.cpp @@ -3,7 +3,7 @@ #include #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Notification/Notification.h" -#include "soh/Enhancements/randomizer/3drando/random.hpp" +#include "soh/ShipUtils.h" const std::string gameCompleteMessages[] = { "killed Ganon", "saved Zelda", "proved their Courage", @@ -37,6 +37,6 @@ void Anchor::HandlePacket_GameComplete(nlohmann::json payload) { Notification::Emit({ .prefix = isGlobalRoom ? "Someone" : anchorClient.name, - .message = RandomElement(gameCompleteMessages), + .message = ShipUtils::RandomElement(gameCompleteMessages), }); }