Add the ability to Randomize Music and Sound Effects and Cosmetrics based on Rando File Seed. (#5970)

Add the ability to Randomize All Music and sfx based on file Rando seed.
Add the ability to Randomize All cosmetics based on file rando seed.

Add combobox for selection:
- Disabled: No music or sound effects are randomized.
- On New Scene: Randomizes when you enter a new scene.
- On Rando Gen Only: Randomizes only when you generate a new randomizer
- On File Load: Randomizes on File Load.
- On File Load (Seeded): Randomizes on file load based on the current randomizer seed/file.

Removed checkboxes.
This commit is contained in:
Glought
2026-01-02 07:01:01 -08:00
committed by GitHub
parent 0bd08d626a
commit dd9d63eecb
7 changed files with 162 additions and 44 deletions

View File

@@ -33,8 +33,7 @@ static WidgetInfo leadingMusic;
static WidgetInfo displaySeqName;
static WidgetInfo ovlDuration;
static WidgetInfo voicePitch;
static WidgetInfo randoMusicOnSceneChange;
static WidgetInfo randomAudioOnSeedGen;
static WidgetInfo randomAudioGenModes;
static WidgetInfo lowerOctaves;
namespace SohGui {
@@ -78,6 +77,14 @@ size_t AuthenticCountBySequenceType(SeqType type) {
}
}
static const std::unordered_map<int32_t, const char*> audioRandomizerModes = {
{ RANDOMIZE_OFF, "Manual" },
{ RANDOMIZE_ON_NEW_SCENE, "On New Scene" },
{ RANDOMIZE_ON_RANDO_GEN_ONLY, "On Rando Gen Only" },
{ RANDOMIZE_ON_FILE_LOAD, "On File Load" },
{ RANDOMIZE_ON_FILE_LOAD_SEEDED, "On File Load (Seeded)" },
};
// Grabs the current BGM sequence ID and replays it
// which will lookup the proper override, or reset back to vanilla
void ReplayCurrentBGM() {
@@ -100,9 +107,19 @@ void UpdateCurrentBGM(u16 seqKey, SeqType seqType) {
}
}
void RandomizeGroup(SeqType type) {
void RandomizeGroup(SeqType type, bool manual = true) {
std::vector<u16> values;
if (!manual) {
if (CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0) == RANDOMIZE_ON_FILE_LOAD_SEEDED ||
CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0) == RANDOMIZE_ON_RANDO_GEN_ONLY) {
uint32_t finalSeed = type + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed()
: static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt));
Random_Init(finalSeed);
}
}
// An empty IncludedSequences set means that the AudioEditor window has never been drawn
if (AudioCollection::Instance->GetIncludedSequences().empty()) {
AudioCollection::Instance->InitializeShufflePool();
@@ -478,16 +495,29 @@ void DrawTypeChip(SeqType type, std::string sequenceName) {
void AudioEditorRegisterOnSceneInitHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) {
if (gSaveContext.gameMode != GAMEMODE_END_CREDITS && CVarGetInteger(CVAR_AUDIO("RandomizeAllOnNewScene"), 0)) {
AudioEditor_RandomizeAll();
if (gSaveContext.gameMode != GAMEMODE_END_CREDITS &&
CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0) == RANDOMIZE_ON_NEW_SCENE) {
AudioEditor_AutoRandomizeAll();
}
});
}
void AudioEditorRegisterOnGenerationCompletionHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGenerationCompletion>([]() {
if (CVarGetInteger(CVAR_AUDIO("RandomizeAllOnRandoGen"), 0)) {
AudioEditor_RandomizeAll();
if (CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0) == RANDOMIZE_ON_RANDO_GEN_ONLY) {
AudioEditor_AutoRandomizeAll();
}
});
}
void AudioEditorRegisterOnLoadGameHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>([](int32_t fileNum) {
if (CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0) == RANDOMIZE_ON_FILE_LOAD ||
CVarGetInteger(CVAR_AUDIO("RandomizeAudioGenModes"), 0) == RANDOMIZE_ON_FILE_LOAD_SEEDED) {
AudioEditor_AutoRandomizeAll();
}
});
}
@@ -495,6 +525,7 @@ void AudioEditorRegisterOnGenerationCompletionHook() {
void AudioEditor::InitElement() {
AudioEditorRegisterOnSceneInitHook();
AudioEditorRegisterOnGenerationCompletionHook();
AudioEditorRegisterOnLoadGameHook();
}
void AudioEditor::DrawElement() {
@@ -556,8 +587,7 @@ void AudioEditor::DrawElement() {
UIWidgets::ButtonOptions().Size(ImVec2(80, 36)).Padding(ImVec2(5.0f, 0.0f)))) {
CVarSetFloat(CVAR_AUDIO("LinkVoiceFreqMultiplier"), 1.0f);
}
SohGui::mSohMenu->MenuDrawItem(randoMusicOnSceneChange, ImGui::GetContentRegionAvail().x, THEME_COLOR);
SohGui::mSohMenu->MenuDrawItem(randomAudioOnSeedGen, ImGui::GetContentRegionAvail().x, THEME_COLOR);
SohGui::mSohMenu->MenuDrawItem(randomAudioGenModes, ImGui::GetContentRegionAvail().x, THEME_COLOR);
SohGui::mSohMenu->MenuDrawItem(lowerOctaves, ImGui::GetContentRegionAvail().x, THEME_COLOR);
}
ImGui::EndChild();
@@ -774,6 +804,15 @@ void AudioEditor_RandomizeAll() {
ReplayCurrentBGM();
}
void AudioEditor_AutoRandomizeAll() {
for (auto type : allTypes) {
RandomizeGroup(type, false);
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
ReplayCurrentBGM();
}
void AudioEditor_RandomizeGroup(SeqType group) {
RandomizeGroup(group);
@@ -865,22 +904,22 @@ void RegisterAudioWidgets() {
.Size(ImVec2(300.0f, 0.0f)));
SohGui::mSohMenu->AddSearchWidget({ voicePitch, "Enhancements", "Audio Editor", "Audio Options" });
randoMusicOnSceneChange = { .name = "Randomize All Music and Sound Effects on New Scene",
.type = WidgetType::WIDGET_CVAR_CHECKBOX };
randoMusicOnSceneChange.CVar(CVAR_AUDIO("RandomizeAllOnNewScene"))
.Options(CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Enables randomizing all unlocked music and sound effects when you enter a new scene."));
SohGui::mSohMenu->AddSearchWidget({ randoMusicOnSceneChange, "Enhancements", "Audio Editor", "Audio Options" });
randomAudioOnSeedGen = { .name = "Randomize All Music and Sound Effects on Randomizer Generation",
.type = WidgetType::WIDGET_CVAR_CHECKBOX };
randomAudioOnSeedGen.CVar(CVAR_AUDIO("RandomizeAllOnRandoGen"))
.Options(CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Enables randomizing all unlocked music and sound effects when you generate a new "
"randomizer. Respects locks already in place."));
SohGui::mSohMenu->AddSearchWidget({ randomAudioOnSeedGen, "Enhancements", "Audio Editor", "Audio Options" });
randomAudioGenModes = { .name = "Automatically Randomize All Music and Sound Effects",
.type = WidgetType::WIDGET_CVAR_COMBOBOX };
randomAudioGenModes.CVar(CVAR_AUDIO("RandomizeAudioGenModes"))
.Options(
ComboboxOptions()
.DefaultIndex(RANDOMIZE_OFF)
.ComboMap(audioRandomizerModes)
.Tooltip(
"Set when the music and sound effects is automaticly randomized:\n"
"- Manual: Manually randomize music or sound effects by pressing the 'Randomize all Groups' "
"button\n"
"- On New Scene : Randomizes when you enter a new scene.\n"
"- On Rando Gen Only: Randomizes only when you generate a new randomizer.\n"
"- On File Load: Randomizes on File Load.\n"
"- On File Load (Seeded): Randomizes on file load based on the current randomizer seed/file.\n"));
SohGui::mSohMenu->AddSearchWidget({ randomAudioGenModes, "Enhancements", "Audio Editor", "Audio Options" });
lowerOctaves = { .name = "Lower Octaves of Unplayable High Notes", .type = WidgetType::WIDGET_CVAR_CHECKBOX };
lowerOctaves.CVar(CVAR_AUDIO("ExperimentalOctaveDrop"))

View File

@@ -18,6 +18,7 @@ class AudioEditor final : public Ship::GuiWindow {
};
void AudioEditor_RandomizeAll();
void AudioEditor_AutoRandomizeAll();
void AudioEditor_RandomizeGroup(SeqType group);
void AudioEditor_ResetAll();
void AudioEditor_ResetGroup(SeqType group);

View File

@@ -13,9 +13,11 @@
#include "soh/SohGui/SohGui.hpp"
#include "soh/OTRGlobals.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/Enhancements/enhancementTypes.h"
extern "C" {
#include "z64.h"
#include "z64save.h"
#include "macros.h"
#include "soh/cvar_prefixes.h"
#include "objects/object_link_boy/object_link_boy.h"
@@ -47,6 +49,7 @@ extern "C" {
#include "objects/object_gi_rabit_mask/object_gi_rabit_mask.h"
#include "overlays/ovl_Magic_Wind/ovl_Magic_Wind.h"
extern SaveContext gSaveContext;
extern PlayState* gPlayState;
void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction);
void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const char* patchName, int destinationIndex,
@@ -96,6 +99,14 @@ std::map<CosmeticGroup, const char*> groupLabels = {
{ COSMETICS_GROUP_MESSAGE, "Message" },
};
static const std::unordered_map<int32_t, const char*> cosmeticsRandomizerModes = {
{ RANDOMIZE_OFF, "Manual" },
{ RANDOMIZE_ON_NEW_SCENE, "On New Scene" },
{ RANDOMIZE_ON_RANDO_GEN_ONLY, "On Rando Gen Only" },
{ RANDOMIZE_ON_FILE_LOAD, "On File Load" },
{ RANDOMIZE_ON_FILE_LOAD_SEEDED, "On File Load (Seeded)" },
};
typedef struct {
const char* cvar;
const char* valuesCvar;
@@ -2093,8 +2104,22 @@ void ApplySideEffects(CosmeticOption& cosmeticOption) {
}
}
void RandomizeColor(CosmeticOption& cosmeticOption) {
ImVec4 randomColor = GetRandomValue();
void RandomizeColor(CosmeticOption& cosmeticOption, bool manual = true) {
ImVec4 randomColor;
if (!manual && CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), 0) == RANDOMIZE_ON_FILE_LOAD_SEEDED ||
!manual && CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), 0) == RANDOMIZE_ON_RANDO_GEN_ONLY) {
uint32_t finalSeed = cosmeticOption.defaultColor.r + cosmeticOption.defaultColor.g +
cosmeticOption.defaultColor.b + cosmeticOption.defaultColor.a +
(IS_RANDO ? Rando::Context::GetInstance()->GetSeed()
: static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt));
randomColor = GetRandomValue(finalSeed);
} else {
randomColor = GetRandomValue();
}
Color_RGBA8 newColor;
newColor.r = static_cast<uint8_t>(randomColor.x * 255.0f);
newColor.g = static_cast<uint8_t>(randomColor.y * 255.0f);
@@ -2372,17 +2397,17 @@ void CosmeticsEditorWindow::DrawElement() {
.Step(0.01f)
.Size(ImVec2(300.0f, 0.0f))
.Color(THEME_COLOR));
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::CVarCheckbox("Randomize All on New Scene", CVAR_COSMETIC("RandomizeAllOnNewScene"),
UIWidgets::CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Enables randomizing all unlocked cosmetics when you enter a new scene."));
ImGui::EndDisabled();
UIWidgets::CVarCheckbox(
"Randomize All on Randomizer Generation", CVAR_COSMETIC("RandomizeAllOnRandoGen"),
UIWidgets::CheckboxOptions()
UIWidgets::CVarCombobox(
"Automatically Randomize All Cosmetics", CVAR_COSMETIC("RandomizeCosmeticsGenModes"), cosmeticsRandomizerModes,
UIWidgets::ComboboxOptions()
.DefaultIndex(RANDOMIZE_OFF)
.Color(THEME_COLOR)
.Tooltip("Enables randomizing all unlocked cosmetics when you generate a new randomizer."));
.Tooltip("Set when the cosmetics is automaticly randomized:\n"
"- Manual: Manually randomize cosmetics by pressing the 'Randomize all' button\n"
"- On New Scene : Randomizes when you enter a new scene.\n"
"- On Rando Gen Only: Randomizes only when you generate a new randomizer.\n"
"- On File Load: Randomizes on File Load.\n"
"- On File Load (Seeded): Randomizes on file load based on the current randomizer seed/file.\n"));
UIWidgets::CVarCheckbox(
"Advanced Mode", CVAR_COSMETIC("AdvancedMode"),
UIWidgets::CheckboxOptions()
@@ -2573,6 +2598,10 @@ void CosmeticsEditorWindow::DrawElement() {
UIWidgets::PopStyleTabs();
}
void RegisterOnGameFrameUpdateHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { CosmeticsUpdateTick(); });
}
void CosmeticsEditorWindow::InitElement() {
// Convert the `current color` into the format that the ImGui color picker expects
for (auto& [id, cosmeticOption] : cosmeticOptions) {
@@ -2602,6 +2631,18 @@ void CosmeticsEditor_RandomizeAll() {
ApplyOrResetCustomGfxPatches();
}
void CosmeticsEditor_AutoRandomizeAll() {
for (auto& [id, cosmeticOption] : cosmeticOptions) {
if (!CVarGetInteger(cosmeticOption.lockedCvar, 0) &&
(!cosmeticOption.advancedOption || CVarGetInteger(CVAR_COSMETIC("AdvancedMode"), 0))) {
RandomizeColor(cosmeticOption, false);
}
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
ApplyOrResetCustomGfxPatches();
}
void CosmeticsEditor_RandomizeGroup(CosmeticGroup group) {
for (auto& [id, cosmeticOption] : cosmeticOptions) {
if (!CVarGetInteger(cosmeticOption.lockedCvar, 0) &&
@@ -2638,13 +2679,25 @@ void CosmeticsEditor_ResetGroup(CosmeticGroup group) {
}
void RegisterCosmeticHooks() {
COND_HOOK(OnSceneInit, CVarGetInteger(CVAR_COSMETIC("RandomizeAllOnNewScene"), 0),
[](s16 sceneNum) { CosmeticsEditor_RandomizeAll(); });
COND_HOOK(OnGenerationCompletion,
CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), RANDOMIZE_OFF) == RANDOMIZE_ON_RANDO_GEN_ONLY,
[]() { CosmeticsEditor_AutoRandomizeAll(); });
COND_HOOK(OnGenerationCompletion, CVarGetInteger(CVAR_COSMETIC("RandomizeAllOnRandoGen"), 0),
[]() { CosmeticsEditor_RandomizeAll(); });
COND_HOOK(OnLoadGame, CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), RANDOMIZE_OFF) == RANDOMIZE_OFF,
[](s32 fileNum) { ApplyOrResetCustomGfxPatches(); });
COND_HOOK(OnLoadGame, true, [](int32_t fileNum) { ApplyOrResetCustomGfxPatches(); });
COND_HOOK(OnLoadGame,
CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), RANDOMIZE_OFF) == RANDOMIZE_ON_FILE_LOAD,
[](s32 fileNum) { CosmeticsEditor_AutoRandomizeAll(); });
COND_HOOK(OnLoadGame,
CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), RANDOMIZE_OFF) ==
RANDOMIZE_ON_FILE_LOAD_SEEDED,
[](s32 fileNum) { CosmeticsEditor_AutoRandomizeAll(); });
COND_HOOK(OnSceneInit,
CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), RANDOMIZE_OFF) == RANDOMIZE_ON_NEW_SCENE,
[](s16 sceneNum) { CosmeticsEditor_AutoRandomizeAll(); });
COND_HOOK(OnGameFrameUpdate, true, CosmeticsUpdateTick);
}
@@ -2664,7 +2717,6 @@ void RegisterCosmeticWidgets() {
}
static RegisterShipInitFunc initFunc(RegisterCosmeticHooks, {
CVAR_COSMETIC("RandomizeAllOnNewScene"),
CVAR_COSMETIC("RandomizeAllOnRandoGen"),
CVAR_COSMETIC("RandomizeCosmeticsGenModes"),
});
static RegisterMenuInitFunc menuInitFunc(RegisterCosmeticWidgets);

View File

@@ -55,6 +55,7 @@ static ImGuiTableColumnFlags FlagsCell =
ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoSort;
void CosmeticsEditor_RandomizeAll();
void CosmeticsEditor_AutoRandomizeAll();
void CosmeticsEditor_RandomizeGroup(CosmeticGroup group);
void CosmeticsEditor_ResetAll();
void CosmeticsEditor_ResetGroup(CosmeticGroup group);

View File

@@ -123,4 +123,12 @@ typedef enum {
WATERFALL_NEVER,
} SleepingWaterfallType;
typedef enum {
RANDOMIZE_OFF,
RANDOMIZE_ON_NEW_SCENE,
RANDOMIZE_ON_RANDO_GEN_ONLY,
RANDOMIZE_ON_FILE_LOAD,
RANDOMIZE_ON_FILE_LOAD_SEEDED,
} RandomizeOnMode;
#endif

View File

@@ -1170,6 +1170,21 @@ ImVec4 GetRandomValue() {
return NewColor;
}
ImVec4 GetRandomValue(uint32_t seed) {
#if !defined(__SWITCH__) && !defined(__WIIU__)
std::mt19937 rng(seed);
#else
std::mt19937_64 rng(seed);
#endif
std::uniform_int_distribution<int> dist(0, 255 - 1);
ImVec4 NewColor;
NewColor.x = (float)(dist(rng)) / 255.0f;
NewColor.y = (float)(dist(rng)) / 255.0f;
NewColor.z = (float)(dist(rng)) / 255.0f;
return NewColor;
}
Color_RGBA8 RGBA8FromVec(ImVec4 vec) {
Color_RGBA8 color = { vec.x * 255, vec.y * 255, vec.z * 255, vec.w * 255 };
return color;

View File

@@ -1051,7 +1051,9 @@ void DrawFlagArray8Mask(const std::string& name, uint8_t& flags, Colors color =
void InsertHelpHoverText(const std::string& text);
void InsertHelpHoverText(const char* text);
} // namespace UIWidgets
ImVec4 GetRandomValue();
ImVec4 GetRandomValue(uint32_t seed);
Color_RGBA8 RGBA8FromVec(ImVec4 vec);
ImVec4 VecFromRGBA8(Color_RGBA8 color);