From a3ab0e2bdf17c1c5d29d3bf46bfc4eb72793f225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= <159546+serprex@users.noreply.github.com> Date: Fri, 29 May 2026 21:50:19 +0000 Subject: [PATCH] Eradicate `rand` (#6553) Random seed: always generate 10 digits Reduce max seed size, this is getting hashed so it's not valuable to have so many characters --- .../ExtraModes/EnemyRandomizer.cpp | 2 +- .../ExtraModes/RandomizedEnemySizes.cpp | 17 +++++---------- soh/soh/Enhancements/audio/AudioEditor.cpp | 3 ++- .../GameInteractor_RawAction.cpp | 11 ++++------ .../Enhancements/randomizer/3drando/menu.cpp | 14 ++++++------- .../randomizer/3drando/playthrough.cpp | 7 ++++++- soh/soh/Enhancements/randomizer/randomizer.h | 4 ---- soh/soh/Network/Sail/Sail.cpp | 21 ++++++++++--------- soh/soh/SohGui/SohMenuRandomizer.cpp | 10 ++++++--- soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c | 7 +++---- 10 files changed, 46 insertions(+), 50 deletions(-) diff --git a/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp b/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp index 04514b3520..6938b7cd7e 100644 --- a/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp +++ b/soh/soh/Enhancements/ExtraModes/EnemyRandomizer.cpp @@ -763,7 +763,7 @@ void RegisterEnemyRandomizer() { // Offset small jellyfish with Enemy Randomizer, otherwise it gets // stuck in a loop spawning more big jellyfish with seeded spawns. if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0)) { - rotY += rand() % 50; + rotY += ShipUtils::Random(0, 50); } if (!GetRandomizedEnemy(play, &actorId, &posX, &posY, &posZ, &rotX, &rotY, &rotZ, ¶ms)) { diff --git a/soh/soh/Enhancements/ExtraModes/RandomizedEnemySizes.cpp b/soh/soh/Enhancements/ExtraModes/RandomizedEnemySizes.cpp index acb4b94d3b..671a7e6b93 100644 --- a/soh/soh/Enhancements/ExtraModes/RandomizedEnemySizes.cpp +++ b/soh/soh/Enhancements/ExtraModes/RandomizedEnemySizes.cpp @@ -1,6 +1,7 @@ #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/ObjectExtension/ActorMaximumHealth.h" #include "soh/ShipInit.hpp" +#include "soh/ShipUtils.h" extern "C" { #include "functions.h" @@ -30,25 +31,17 @@ static void RandomizedEnemySizes(void* refActor) { return; } - float randomNumber; - float randomScale; - // Dodongo, Volvagia and Dead Hand are always smaller because they're impossible when bigger. bool smallOnlyEnemy = actor->id == ACTOR_BOSS_DODONGO || actor->id == ACTOR_BOSS_FD || actor->id == ACTOR_BOSS_FD2 || actor->id == ACTOR_EN_DH; - bool bigActor = !smallOnlyEnemy && (rand() % 2); + bool bigActor = !smallOnlyEnemy && ShipUtils::Random(0, 2) == 0; - // Big actor + float randomScale; if (bigActor) { - randomNumber = rand() % 200; - // Between 100% and 300% size. - randomScale = 1.0f + (randomNumber / 100); + randomScale = 1.0f + ShipUtils::RandomDouble() * 2.0f; } else { - // Small actor - randomNumber = rand() % 90; - // Between 10% and 100% size. - randomScale = 0.1f + (randomNumber / 100); + randomScale = 0.1f + ShipUtils::RandomDouble() * 0.9f; } Actor_SetScale(actor, actor->scale.z * randomScale); diff --git a/soh/soh/Enhancements/audio/AudioEditor.cpp b/soh/soh/Enhancements/audio/AudioEditor.cpp index 6e50e7007a..3f56ed07dc 100644 --- a/soh/soh/Enhancements/audio/AudioEditor.cpp +++ b/soh/soh/Enhancements/audio/AudioEditor.cpp @@ -14,6 +14,7 @@ #include "soh/SohGui/SohGui.hpp" #include "AudioCollection.h" #include "soh/Enhancements/enhancementTypes.h" +#include "soh/ShipUtils.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/SeedContext.h" @@ -406,7 +407,7 @@ void Draw_SfxTab(const std::string& tabId, SeqType type, const std::string& tabN if (validSequences.size()) { auto it = validSequences.begin(); - const auto& seqData = *std::next(it, rand() % validSequences.size()); + const auto& seqData = *std::next(it, ShipUtils::Random(0, validSequences.size())); CVarSetInteger(cvarKey.c_str(), seqData->sequenceId); if (locked) { CVarClear(cvarLockKey.c_str()); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp index a1fa273cb4..9267724456 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp @@ -4,6 +4,7 @@ #include #include "soh/Enhancements/debugger/colViewer.h" #include "soh/Enhancements/nametag.h" +#include "soh/ShipUtils.h" extern "C" { #include "variables.h" @@ -410,15 +411,11 @@ void GameInteractor::RawAction::EmulateButtonPress(int32_t button) { } void GameInteractor::RawAction::EmulateRandomButtonPress(uint32_t chancePercentage) { - uint32_t emulatedButton; - uint32_t randomNumber = rand(); + uint32_t randomNumber = ShipUtils::Random(0, 1400); uint32_t possibleButtons[14] = { BTN_CRIGHT, BTN_CLEFT, BTN_CDOWN, BTN_CUP, BTN_R, BTN_L, BTN_DRIGHT, BTN_DLEFT, BTN_DDOWN, BTN_DUP, BTN_START, BTN_Z, BTN_B, BTN_A }; - - emulatedButton = possibleButtons[randomNumber % 14]; - if (randomNumber % 100 < chancePercentage) { - GameInteractor::State::EmulatedButtons |= emulatedButton; + GameInteractor::State::EmulatedButtons |= possibleButtons[randomNumber / 100]; } } @@ -431,7 +428,7 @@ void GameInteractor::RawAction::SetRandomWind(bool active) { if (active) { GameInteractor::State::RandomWindActive = 1; if (GameInteractor::State::RandomWindSecondsSinceLastDirectionChange == 0) { - player->pushedYaw = (rand() % 49152) - 32767; + player->pushedYaw = ShipUtils::Random(0, 0xc000) - 0x8000; GameInteractor::State::RandomWindSecondsSinceLastDirectionChange = 5; } else { GameInteractor::State::RandomWindSecondsSinceLastDirectionChange--; diff --git a/soh/soh/Enhancements/randomizer/3drando/menu.cpp b/soh/soh/Enhancements/randomizer/3drando/menu.cpp index 0402b10968..820c5066d0 100644 --- a/soh/soh/Enhancements/randomizer/3drando/menu.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/menu.cpp @@ -1,11 +1,7 @@ -#include -#include -#include -#include - #include "menu.hpp" #include "playthrough.hpp" #include "soh/Enhancements/debugger/performanceTimer.h" +#include "soh/ShipUtils.h" #include #include "../../randomizer/randomizerTypes.h" @@ -22,10 +18,14 @@ bool GenerateRandomizer(std::set excludedLocations, std::set(time(NULL))); // if a blank seed was entered, make a random one if (seedInput.empty()) { - seedInput = std::to_string(rand()); + char seedString[12]; + for (size_t i = 0; i < 10; i++) { + seedString[i] = '0' + ShipUtils::Random(0, 10); + } + seedString[11] = '\0'; + seedInput = std::string(seedString); } else if (seedInput.rfind("seed_testing_count", 0) == 0 && seedInput.length() > 18) { int count; try { diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp index b6a3aeed9e..4ee635323c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -94,7 +94,12 @@ int Playthrough_Repeat(std::set excludedLocations, std::setSetSeedString(std::to_string(rand())); + char seedString[12]; + for (size_t i = 0; i < 10; i++) { + seedString[i] = '0' + ShipUtils::Random(0, 10); + } + seedString[11] = '\0'; + ctx->SetSeedString(std::string(seedString)); repeatedSeed = SohUtils::Hash(ctx->GetSeedString()); ctx->SetSeed(repeatedSeed); SPDLOG_DEBUG("testing seed: %d", repeatedSeed); diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 1bc6dcadd1..c577f39e4b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -1,12 +1,9 @@ #pragma once #include -#include #include -#include #include #include "z64item.h" -#include #include "SeedContext.h" #include #include "soh/Enhancements/randomizer/randomizer_check_objects.h" @@ -15,7 +12,6 @@ #include #include "soh/Enhancements/item-tables/ItemTableTypes.h" #include "../custom-message/CustomMessageTypes.h" -#include "soh/Enhancements/randomizer/fishsanity.h" #define MAX_SEED_STRING_SIZE 1024 diff --git a/soh/soh/Network/Sail/Sail.cpp b/soh/soh/Network/Sail/Sail.cpp index ddaf059c58..ded3201106 100644 --- a/soh/soh/Network/Sail/Sail.cpp +++ b/soh/soh/Network/Sail/Sail.cpp @@ -4,6 +4,7 @@ #include #include "soh/OTRGlobals.h" #include "soh/util.h" +#include "soh/ShipUtils.h" template bool IsType(const SrcType* src) { return dynamic_cast(src) != nullptr; @@ -339,7 +340,7 @@ void Sail::RegisterHooks() { return; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnTransitionEnd"; payload["hook"]["sceneNum"] = sceneNum; @@ -352,7 +353,7 @@ void Sail::RegisterHooks() { return; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnLoadGame"; payload["hook"]["fileNum"] = fileNum; @@ -365,7 +366,7 @@ void Sail::RegisterHooks() { return; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnExitGame"; payload["hook"]["fileNum"] = fileNum; @@ -377,7 +378,7 @@ void Sail::RegisterHooks() { if (!isConnected || !GameInteractor::IsSaveLoaded()) return; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnItemReceive"; payload["hook"]["tableId"] = itemEntry.tableId; @@ -392,7 +393,7 @@ void Sail::RegisterHooks() { Actor* actor = (Actor*)refActor; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnEnemyDefeat"; payload["hook"]["actorId"] = actor->id; @@ -407,7 +408,7 @@ void Sail::RegisterHooks() { Actor* actor = (Actor*)refActor; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnActorInit"; payload["hook"]["actorId"] = actor->id; @@ -420,7 +421,7 @@ void Sail::RegisterHooks() { if (!isConnected || !GameInteractor::IsSaveLoaded()) return; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnFlagSet"; payload["hook"]["flagType"] = flagType; @@ -433,7 +434,7 @@ void Sail::RegisterHooks() { if (!isConnected || !GameInteractor::IsSaveLoaded()) return; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnFlagUnset"; payload["hook"]["flagType"] = flagType; @@ -446,7 +447,7 @@ void Sail::RegisterHooks() { if (!isConnected || !GameInteractor::IsSaveLoaded()) return; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnSceneFlagSet"; payload["hook"]["flagType"] = flagType; @@ -460,7 +461,7 @@ void Sail::RegisterHooks() { if (!isConnected || !GameInteractor::IsSaveLoaded()) return; nlohmann::json payload; - payload["id"] = std::rand(); + payload["id"] = ShipUtils::Random(0, UINT32_MAX); payload["type"] = "hook"; payload["hook"]["type"] = "OnSceneFlagUnset"; payload["hook"]["flagType"] = flagType; diff --git a/soh/soh/SohGui/SohMenuRandomizer.cpp b/soh/soh/SohGui/SohMenuRandomizer.cpp index d231c8a5a8..d53fdf6c51 100644 --- a/soh/soh/SohGui/SohMenuRandomizer.cpp +++ b/soh/soh/SohGui/SohMenuRandomizer.cpp @@ -4,6 +4,7 @@ #include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/randomizer/settings.h" #include "soh/OTRGlobals.h" +#include "soh/ShipUtils.h" #include "soh/SohGui/SohGui.hpp" extern "C" { @@ -559,16 +560,19 @@ void SohMenu::AddMenuRandomizer() { .Color(THEME_COLOR) .Padding(ImVec2(10.f, 6.f)) .Tooltip("Creates a new random seed value to be used when generating a randomizer"))) { - SohUtils::CopyStringToCharArray(seedString, std::to_string(rand() & 0xFFFFFFFF), MAX_SEED_STRING_SIZE); + for (size_t i = 0; i < 10; i++) { + seedString[i] = '0' + ShipUtils::Random(0, 10); + } + seedString[11] = '\0'; } ImGui::SameLine(); if (UIWidgets::Button(ICON_FA_ERASER, UIWidgets::ButtonOptions() .Size(UIWidgets::Sizes::Inline) .Color(THEME_COLOR) .Padding(ImVec2(10.f, 6.f)))) { - memset(seedString, 0, MAX_SEED_STRING_SIZE); + seedString[0] = 0; } - if (strnlen(seedString, MAX_SEED_STRING_SIZE) == 0) { + if (seedString[0] == 0) { ImGui::SameLine(17.0f); ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "Leave blank for random seed"); } diff --git a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c index 9fe450695e..900a869025 100644 --- a/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c +++ b/soh/src/overlays/actors/ovl_En_Bom/z_en_bom.c @@ -8,7 +8,7 @@ #include "overlays/effects/ovl_Effect_Ss_Dead_Sound/z_eff_ss_dead_sound.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include +#include "soh/ShipUtils.h" #define FLAGS (ACTOR_FLAG_UPDATE_CULLING_DISABLED | ACTOR_FLAG_DRAW_CULLING_DISABLED) @@ -104,14 +104,13 @@ void EnBom_Init(Actor* thisx, PlayState* play) { } else { // Set random fuse timer with a minimum of 10. Do the sound and scale immediately, // otherwise the bomb is invisible until the timer hits the "normal" amount. - uint32_t randomTimer = (rand() % 150) + 10; - this->timer = randomTimer; + this->timer = 10 + (s16)(Rand_ZeroOne() * 150.0f); Audio_PlayActorSound2(thisx, NA_SE_PL_TAKE_OUT_SHIELD); Actor_SetScale(thisx, 0.01f); } if (CVarGetFloat(CVAR_CHEAT("BombTimerMultiplier"), 1.0f) != 1.0f) { - this->timer = (s32)(70 * CVarGetFloat(CVAR_CHEAT("BombTimerMultiplier"), 1.0f)); + this->timer *= CVarGetFloat(CVAR_CHEAT("BombTimerMultiplier"), 1.0f); // Do the sound and scale immediately if GameInteractor hasn't already. if (!GameInteractor_GetRandomBombFuseTimerActive()) { Audio_PlayActorSound2(thisx, NA_SE_PL_TAKE_OUT_SHIELD);