diff --git a/soh/assets/custom/objects/object_keyring/Hilite_new.rgba16 b/soh/assets/custom/objects/object_keyring/Hilite_new.rgba16 new file mode 100644 index 000000000..5438695fa Binary files /dev/null and b/soh/assets/custom/objects/object_keyring/Hilite_new.rgba16 differ diff --git a/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL b/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL index 3552eef1b..7cb17d889 100644 --- a/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL +++ b/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL @@ -1,11 +1,10 @@ + + + + - - - - - diff --git a/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_tri_0 b/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_tri_0 index 791defa81..c7b29e9c7 100644 --- a/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_tri_0 +++ b/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_tri_0 @@ -1,213 +1,110 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_vtx_0 b/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_vtx_0 index 1dd0cbb61..5ab0f76ec 100644 --- a/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_vtx_0 +++ b/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_vtx_0 @@ -1,233 +1,210 @@ - + - - - - - - - + + + + + + + - + - + - - - + - - - + + + - - - + + + - - - + - - - + + + + + - - - - + + + + - - - + - - - + - - - + + + - - + + - - - - + + - - - - - - + + + + + + + + - - - + + + + - - - - - - - + + + + + - - - - + + + + - - - + + + - - - + - + - - - + + + + + - + + - - - - + + - - - - + + + - - - - - - - + + + + - + - + - - - + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + - - - - - - + + + - - - + - + - + + - - - - - - + + + + - - - - + + + + + - - - - - - - - - - + + - + - + - + - + - + + + - + - + - + - - + + - + diff --git a/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_vtx_cull b/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_vtx_cull new file mode 100644 index 000000000..6ef0139b8 --- /dev/null +++ b/soh/assets/custom/objects/object_keyring/gKeyringIconGerudoFortressDL_vtx_cull @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_keyring/mat_gKeyringIconGerudoFortressDL_f3dlite_IconMetal_GerudoFortress b/soh/assets/custom/objects/object_keyring/mat_gKeyringIconGerudoFortressDL_f3dlite_IconMetal_GerudoFortress index b5755b4a8..f926de784 100644 --- a/soh/assets/custom/objects/object_keyring/mat_gKeyringIconGerudoFortressDL_f3dlite_IconMetal_GerudoFortress +++ b/soh/assets/custom/objects/object_keyring/mat_gKeyringIconGerudoFortressDL_f3dlite_IconMetal_GerudoFortress @@ -1,21 +1,15 @@ + - - - + - - - - - + + - - diff --git a/soh/assets/custom/objects/object_keyring/model.xml b/soh/assets/custom/objects/object_keyring/model.xml new file mode 100644 index 000000000..6ef0139b8 --- /dev/null +++ b/soh/assets/custom/objects/object_keyring/model.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/soh/soh/Enhancements/RemoveSpinAttackDarkness.cpp b/soh/soh/Enhancements/RemoveSpinAttackDarkness.cpp index 20beb193a..37fed1b7d 100644 --- a/soh/soh/Enhancements/RemoveSpinAttackDarkness.cpp +++ b/soh/soh/Enhancements/RemoveSpinAttackDarkness.cpp @@ -10,6 +10,12 @@ void Custom_EnMThunder_Update(Actor* thisx, PlayState* play) { f32 blueRadius; s32 redGreen; + // If thunder effect doesn't exist (aka player doesn't have magic), + // don't do anything. + if (enMThunder->actionFunc == nullptr) { + return; + } + enMThunder->actionFunc(enMThunder, play); // don't call this part, it's what makes the spin attack darkness happen // func_80A9F314(play, this->unk_1BC); diff --git a/soh/soh/Enhancements/audio/AudioEditor.cpp b/soh/soh/Enhancements/audio/AudioEditor.cpp index 0149aa148..efbcd5c28 100644 --- a/soh/soh/Enhancements/audio/AudioEditor.cpp +++ b/soh/soh/Enhancements/audio/AudioEditor.cpp @@ -488,6 +488,85 @@ void AudioEditor::DrawElement() { UIWidgets::PushStyleTabs(THEME_COLOR); if (ImGui::BeginTabBar("SfxContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { + + static ImVec2 cellPadding(8.0f, 8.0f); + if (ImGui::BeginTabItem("Audio Options")) { + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding); + ImGui::BeginTable("Audio Options", 1, ImGuiTableFlags_SizingStretchSame); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::BeginChild("SfxOptions", ImVec2(0, -8))) { + UIWidgets::CVarCheckbox( + "Mute Low HP Alarm", CVAR_AUDIO("LowHPAlarm"), + UIWidgets::CheckboxOptions().Color(THEME_COLOR).Tooltip("Disable the low HP beeping sound.")); + UIWidgets::CVarCheckbox("Disable Navi Call Audio", CVAR_AUDIO("DisableNaviCallAudio"), + UIWidgets::CheckboxOptions() + .Color(THEME_COLOR) + .Tooltip("Disables the voice audio when Navi calls you.")); + UIWidgets::CVarCheckbox( + "Disable Enemy Proximity Music", CVAR_AUDIO("EnemyBGMDisable"), + UIWidgets::CheckboxOptions() + .Color(THEME_COLOR) + .Tooltip("Disables the music change when getting close to enemies. Useful for hearing " + "your custom music for each scene more often.")); + UIWidgets::CVarCheckbox( + "Disable Leading Music in Lost Woods", CVAR_AUDIO("LostWoodsConsistentVolume"), + UIWidgets::CheckboxOptions() + .Color(THEME_COLOR) + .Tooltip("Disables the volume shifting in the Lost Woods. Useful for hearing " + "your custom music in the Lost Woods if you don't need the navigation assitance " + "the volume changing provides. If toggling this while in the Lost Woods, reload " + "the area for the effect to kick in.")); + UIWidgets::CVarCheckbox( + "Display Sequence Name on Overlay", CVAR_AUDIO("SeqNameOverlay"), + UIWidgets::CheckboxOptions() + .Color(THEME_COLOR) + .Tooltip("Displays the name of the current sequence in the corner of the screen whenever a new " + "sequence " + "is loaded to the main sequence player (does not apply to fanfares or enemy BGM).")); + UIWidgets::CVarSliderInt("Overlay Duration: %d seconds", CVAR_AUDIO("SeqNameOverlayDuration"), + UIWidgets::IntSliderOptions() + .Min(1) + .Max(10) + .DefaultValue(5) + .Size(ImVec2(300.0f, 0.0f)) + .Color(THEME_COLOR)); + UIWidgets::CVarSliderFloat("Link's voice pitch multiplier", CVAR_AUDIO("LinkVoiceFreqMultiplier"), + UIWidgets::FloatSliderOptions() + .IsPercentage() + .Min(0.4f) + .Max(2.5f) + .DefaultValue(1.0f) + .Size(ImVec2(300.0f, 0.0f)) + .Color(THEME_COLOR)); + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPos().y + 40.f); + if (UIWidgets::Button("Reset##linkVoiceFreqMultiplier", + UIWidgets::ButtonOptions().Size(ImVec2(80, 36)).Padding(ImVec2(5.0f, 0.0f)))) { + CVarSetFloat(CVAR_AUDIO("LinkVoiceFreqMultiplier"), 1.0f); + } + UIWidgets::CVarCheckbox( + "Randomize All Music and Sound Effects on New Scene", CVAR_AUDIO("RandomizeAllOnNewScene"), + UIWidgets::CheckboxOptions() + .Color(THEME_COLOR) + .Tooltip( + "Enables randomizing all unlocked music and sound effects when you enter a new scene.")); + UIWidgets::CVarCheckbox( + "Lower Octaves of Unplayable High Notes", CVAR_AUDIO("ExperimentalOctaveDrop"), + UIWidgets::CheckboxOptions() + .Color(THEME_COLOR) + .Tooltip("Some custom sequences may have notes that are too high for the game's audio " + "engine to play. Enabling this checkbox will cause these notes to drop a " + "couple of octaves so they can still harmonize with the other notes of the " + "sequence.")); + } + ImGui::EndChild(); + ImGui::EndTable(); + ImGui::PopStyleVar(1); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Background Music")) { Draw_SfxTab("backgroundMusic", SEQ_BGM_WORLD, "Background Music"); ImGui::EndTabItem(); @@ -518,78 +597,6 @@ void AudioEditor::DrawElement() { ImGui::EndTabItem(); } - static ImVec2 cellPadding(8.0f, 8.0f); - if (ImGui::BeginTabItem("Options")) { - ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding); - ImGui::BeginTable("Options", 1, ImGuiTableFlags_SizingStretchSame); - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - if (ImGui::BeginChild("SfxOptions", ImVec2(0, -8))) { - UIWidgets::CVarCheckbox( - "Disable Enemy Proximity Music", CVAR_AUDIO("EnemyBGMDisable"), - UIWidgets::CheckboxOptions() - .Color(THEME_COLOR) - .Tooltip("Disables the music change when getting close to enemies. Useful for hearing " - "your custom music for each scene more often.")); - UIWidgets::CVarCheckbox( - "Disable Leading Music in Lost Woods", CVAR_AUDIO("LostWoodsConsistentVolume"), - UIWidgets::CheckboxOptions() - .Color(THEME_COLOR) - .Tooltip("Disables the volume shifting in the Lost Woods. Useful for hearing " - "your custom music in the Lost Woods if you don't need the navigation assitance " - "the volume changing provides. If toggling this while in the Lost Woods, reload " - "the area for the effect to kick in.")); - UIWidgets::CVarCheckbox( - "Display Sequence Name on Overlay", CVAR_AUDIO("SeqNameOverlay"), - UIWidgets::CheckboxOptions() - .Color(THEME_COLOR) - .Tooltip("Displays the name of the current sequence in the corner of the screen whenever a new " - "sequence " - "is loaded to the main sequence player (does not apply to fanfares or enemy BGM).")); - UIWidgets::CVarSliderInt("Overlay Duration: %d seconds", CVAR_AUDIO("SeqNameOverlayDuration"), - UIWidgets::IntSliderOptions() - .Min(1) - .Max(10) - .DefaultValue(5) - .Size(ImVec2(300.0f, 0.0f)) - .Color(THEME_COLOR)); - UIWidgets::CVarSliderFloat("Link's voice pitch multiplier", - CVAR_AUDIO("LinkVoiceFreqMultiplier"), - UIWidgets::FloatSliderOptions() - .IsPercentage() - .Min(0.4f) - .Max(2.5f) - .DefaultValue(1.0f) - .Size(ImVec2(300.0f, 0.0f)) - .Color(THEME_COLOR)); - ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetCursorPos().y + 40.f); - if (UIWidgets::Button("Reset##linkVoiceFreqMultiplier", - UIWidgets::ButtonOptions().Size(ImVec2(80, 36)).Padding(ImVec2(5.0f, 0.0f)))) { - CVarSetFloat(CVAR_AUDIO("LinkVoiceFreqMultiplier"), 1.0f); - } - UIWidgets::CVarCheckbox( - "Randomize All Music and Sound Effects on New Scene", CVAR_AUDIO("RandomizeAllOnNewScene"), - UIWidgets::CheckboxOptions() - .Color(THEME_COLOR) - .Tooltip( - "Enables randomizing all unlocked music and sound effects when you enter a new scene.")); - UIWidgets::CVarCheckbox( - "Lower Octaves of Unplayable High Notes", CVAR_AUDIO("ExperimentalOctaveDrop"), - UIWidgets::CheckboxOptions() - .Color(THEME_COLOR) - .Tooltip("Some custom sequences may have notes that are too high for the game's audio " - "engine to play. Enabling this checkbox will cause these notes to drop a " - "couple of octaves so they can still harmonize with the other notes of the " - "sequence.")); - } - ImGui::EndChild(); - ImGui::EndTable(); - ImGui::PopStyleVar(1); - ImGui::EndTabItem(); - } - static bool excludeTabOpen = false; if (ImGui::BeginTabItem("Audio Shuffle Pool Management")) { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding); diff --git a/soh/soh/Enhancements/controls/InputViewer.cpp b/soh/soh/Enhancements/controls/InputViewer.cpp index 3eb18c0e2..d26de6719 100644 --- a/soh/soh/Enhancements/controls/InputViewer.cpp +++ b/soh/soh/Enhancements/controls/InputViewer.cpp @@ -428,7 +428,6 @@ InputViewerSettingsWindow::~InputViewerSettingsWindow() { } void InputViewerSettingsWindow::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger); // gInputViewer.Scale CVarSliderFloat("Input Viewer Scale: %.2f", CVAR_INPUT_VIEWER("Scale"), FloatSliderOptions().Color(THEME_COLOR).DefaultValue(1.0f).Min(0.1f).Max(5.0f).ShowButtons(true).Tooltip("Sets the on screen size of the input viewer")); @@ -565,7 +564,7 @@ void InputViewerSettingsWindow::DrawElement() { ImGui::Unindent(); } - UIWidgets:PaddedSeparator(true, true); + UIWidgets::PaddedSeparator(true, true); } if (ImGui::CollapsingHeader("Analog Stick")) { @@ -640,5 +639,4 @@ void InputViewerSettingsWindow::DrawElement() { } } PopStyleHeader(); - ImGui::PopFont(); } diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index 93c866eb3..ddd36fa56 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -283,13 +283,13 @@ static std::map cosmeticOptions = { COSMETIC_OPTION("Key.GanonsBossGem", "Ganons Boss Key Gem", COSMETICS_GROUP_BOSS_KEYS, ColorRGBA8(255, 0, 0, 255), false, true, false), COSMETIC_OPTION("Key.WellSmallBody", "Well Small Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Key.WellSmallEmblem", "Well Small Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(227, 110, 255, 255), false, true, true), + COSMETIC_OPTION("Key.WellSmallEmblem", "Well Small Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(227, 110, 255, 255), false, true, false), COSMETIC_OPTION("Key.FortSmallBody", "Fortress Small Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Key.FortSmallEmblem", "Fortress Small Key Emblem",COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Key.FortSmallEmblem", "Fortress Small Key Emblem",COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false), COSMETIC_OPTION("Key.GTGSmallBody", "GTG Small Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Key.GTGSmallEmblem", "GTG Small Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(221, 212, 60, 255), false, true, true), + COSMETIC_OPTION("Key.GTGSmallEmblem", "GTG Small Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(221, 212, 60, 255), false, true, false), //COSMETIC_OPTION("Key.ChestGameSmallBody", "Chest Game Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false), - //COSMETIC_OPTION("Key.ChestGameEmblem", "Chest Game Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 0, 0, 255), false, true, true), + //COSMETIC_OPTION("Key.ChestGameEmblem", "Chest Game Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 0, 0, 255), false, true, false), COSMETIC_OPTION("Key.Skeleton", "Skeleton Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 170, 255), false, true, false), COSMETIC_OPTION("HUD.AButton", "A Button", COSMETICS_GROUP_HUD, ColorRGBA8( 90, 90, 255, 255), false, true, false), @@ -1523,7 +1523,7 @@ void Draw_Placements(){ CVarSetInteger(CVAR_COSMETIC("HUD.EnemyHealthBar.Width.Changed"), 1); } ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 24); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (ImGui::CalcTextSize("g").y * 2)); if (UIWidgets::Button("Reset##EnemyHealthBarWidth", UIWidgets::ButtonOptions().Size(ImVec2(80, 36)).Padding(ImVec2(5.0f, 0.0f)))) { CVarClear(CVAR_COSMETIC("HUD.EnemyHealthBar.Width.Value")); @@ -1537,7 +1537,7 @@ void Draw_Placements(){ void Reset_Option_Single(const char* Button_Title, const char* name) { ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 24); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (ImGui::CalcTextSize("g").y * 2)); if (UIWidgets::Button(Button_Title, UIWidgets::ButtonOptions().Size(ImVec2(80, 36)).Padding(ImVec2(5.0f, 0.0f)))) { CVarClear(name); @@ -1546,7 +1546,7 @@ void Reset_Option_Single(const char* Button_Title, const char* name) { void Reset_Option_Double(const char* Button_Title, const char* name) { ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 24); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (ImGui::CalcTextSize("g").y * 2)); if (UIWidgets::Button(Button_Title, UIWidgets::ButtonOptions().Size(ImVec2(80, 36)).Padding(ImVec2(5.0f, 0.0f)))) { CVarClear((std::string(name) + ".Value").c_str()); @@ -1578,7 +1578,7 @@ void DrawSillyTab() { CVarSetInteger(CVAR_COSMETIC("Link.BodySize.Changed"), 1); } ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 24); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (ImGui::CalcTextSize("g").y * 2)); if (UIWidgets::Button("Reset##Link_BodySize", UIWidgets::ButtonOptions().Size(ImVec2(80, 36)).Padding(ImVec2(5.0f, 0.0f)))) { CVarClear(CVAR_COSMETIC("Link.BodySize.Value")); @@ -2045,8 +2045,8 @@ void CosmeticsEditorWindow::DrawElement() { UIWidgets::ComboboxOptions() .DefaultIndex(COLORSCHEME_N64) .Color(THEME_COLOR) - .LabelPosition(UIWidgets::LabelPosition::Near) - .ComponentAlignment(UIWidgets::ComponentAlignment::Right)); + .LabelPosition(UIWidgets::LabelPositions::Near) + .ComponentAlignment(UIWidgets::ComponentAlignments::Right)); UIWidgets::CVarCheckbox("Sync Rainbow colors", CVAR_COSMETIC("RainbowSync"), UIWidgets::CheckboxOptions() .Color(THEME_COLOR)); @@ -2194,7 +2194,7 @@ void CosmeticsEditorWindow::DrawElement() { CVarSetInteger(CVAR_COSMETIC("Trails.Duration.Changed"), 1); } ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 24); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (ImGui::CalcTextSize("g").y * 2)); if (UIWidgets::Button("Reset##Trails_Duration", UIWidgets::ButtonOptions() .Size(ImVec2(80, 36)) .Padding(ImVec2(5.0f, 0.0f)))) { diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index 96bee1ffd..dac3b2de9 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -79,6 +79,7 @@ static bool ActorSpawnHandler(std::shared_ptr Console, const std: if (args[8][0] != ',') { spawnPoint.rot.z = std::stoi(args[8]); } + [[fallthrough]]; case 6: if (args[3][0] != ',') { spawnPoint.pos.x = std::stoi(args[3]); diff --git a/soh/soh/Enhancements/debugger/MessageViewer.cpp b/soh/soh/Enhancements/debugger/MessageViewer.cpp index 49764374f..aabe9ad61 100644 --- a/soh/soh/Enhancements/debugger/MessageViewer.cpp +++ b/soh/soh/Enhancements/debugger/MessageViewer.cpp @@ -26,7 +26,6 @@ void MessageViewer::InitElement() { } void MessageViewer::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontMonoLargest); ImGui::Text("Table ID"); ImGui::SameLine(); PushStyleInput(THEME_COLOR); @@ -86,7 +85,6 @@ void MessageViewer::DrawElement() { mDisplayCustomMessageClicked = true; } PopStyleButton(); - ImGui::PopFont(); } void MessageViewer::UpdateElement() { diff --git a/soh/soh/Enhancements/debugger/actorViewer.cpp b/soh/soh/Enhancements/debugger/actorViewer.cpp index a154df65b..767ff2723 100644 --- a/soh/soh/Enhancements/debugger/actorViewer.cpp +++ b/soh/soh/Enhancements/debugger/actorViewer.cpp @@ -934,8 +934,6 @@ void ActorViewerWindow::DrawElement() { static s16 currentSelectedInDropdown; static std::vector actors; - ImGui::PushFont(OTRGlobals::Instance->fontMonoLargest); - if (gPlayState != nullptr) { needs_reset = lastSceneId != gPlayState->sceneNum; if (needs_reset) { @@ -1234,7 +1232,6 @@ void ActorViewerWindow::DrawElement() { actors.clear(); } } - ImGui::PopFont(); } void ActorViewerWindow::InitElement() { diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index dfc4d9681..0e9bbc79a 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -1550,7 +1550,7 @@ void ResetBaseOptions() { intSliderOptionsBase.Color(THEME_COLOR).Size({320.0f, 0.0f}).Tooltip(""); buttonOptionsBase.Color(THEME_COLOR).Size(Sizes::Inline).Tooltip(""); checkboxOptionsBase.Color(THEME_COLOR).Tooltip(""); - comboboxOptionsBase.Color(THEME_COLOR).ComponentAlignment(ComponentAlignment::Left).LabelPosition(LabelPosition::Near).Tooltip(""); + comboboxOptionsBase.Color(THEME_COLOR).ComponentAlignment(ComponentAlignments::Left).LabelPosition(LabelPositions::Near).Tooltip(""); } void SaveEditorWindow::DrawElement() { diff --git a/soh/soh/Enhancements/debugger/dlViewer.cpp b/soh/soh/Enhancements/debugger/dlViewer.cpp index 1459d2809..a591cf948 100644 --- a/soh/soh/Enhancements/debugger/dlViewer.cpp +++ b/soh/soh/Enhancements/debugger/dlViewer.cpp @@ -91,7 +91,6 @@ void PerformDisplayListSearch() { } void DLViewerWindow::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger); // Debounce the search field as listing otr files is expensive UIWidgets::PushStyleInput(THEME_COLOR); if (ImGui::InputText("Search Display Lists", searchString, ARRAY_COUNT(searchString))) { @@ -122,7 +121,6 @@ void DLViewerWindow::DrawElement() { UIWidgets::PopStyleCombobox(); if (activeDisplayList == "") { - ImGui::PopFont(); return; } @@ -131,7 +129,6 @@ void DLViewerWindow::DrawElement() { if (res->GetInitData()->Type != static_cast(Fast::ResourceType::DisplayList)) { ImGui::Text("Resource type is not a Display List. Please choose another."); - ImGui::PopFont(); return; } @@ -329,10 +326,8 @@ void DLViewerWindow::DrawElement() { } } catch (const std::exception& e) { ImGui::Text("Error displaying DL instructions."); - ImGui::PopFont(); return; } - ImGui::PopFont(); } void DLViewerWindow::InitElement() { diff --git a/soh/soh/Enhancements/debugger/hookDebugger.cpp b/soh/soh/Enhancements/debugger/hookDebugger.cpp index 782cf4f7a..a9d6ca891 100644 --- a/soh/soh/Enhancements/debugger/hookDebugger.cpp +++ b/soh/soh/Enhancements/debugger/hookDebugger.cpp @@ -4,28 +4,29 @@ #include #include -static std::unordered_map*> hookData; +static std::map*> hookData; const ImVec4 grey = ImVec4(0.75, 0.75, 0.75, 1); const ImVec4 yellow = ImVec4(1, 1, 0, 1); const ImVec4 red = ImVec4(1, 0, 0, 1); void DrawHookRegisteringInfos(const char* hookName) { - if ((*hookData[hookName]).size() == 0) { + size_t numHooks = (*hookData[hookName]).size(); + + if (numHooks == 0) { ImGui::TextColored(grey, "No hooks found"); return; } - if (ImGui::BeginTable( - ("Table##" + std::string(hookName)).c_str(), - 4, - ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit - )) { - ImGui::TableSetupColumn("Id"); - ImGui::TableSetupColumn("Type"); - ImGui::TableSetupColumn("Registration Info"); - //ImGui::TableSetupColumn("Stub"); - ImGui::TableSetupColumn("Number of Calls"); + ImGui::Text("Total Registered: %d", numHooks); + + if (ImGui::BeginTable(("Table##" + std::string(hookName)).c_str(), 4, + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | + ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) { + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Registration Info", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("# Calls", ImGuiTableColumnFlags_WidthFixed); ImGui::TableHeadersRow(); for (auto& [id, hookInfo] : (*hookData[hookName])) { ImGui::TableNextRow(); @@ -39,7 +40,7 @@ void DrawHookRegisteringInfos(const char* hookName) { ImGui::Text("Normal"); break; case HOOK_TYPE_ID: - ImGui::Text("Id"); + ImGui::Text("ID"); break; case HOOK_TYPE_PTR: ImGui::Text("Ptr"); @@ -54,27 +55,19 @@ void DrawHookRegisteringInfos(const char* hookName) { ImGui::TableNextColumn(); if (hookInfo.registering.valid) { - ImGui::Text("%s(%d:%d) %s", hookInfo.registering.file, hookInfo.registering.line, hookInfo.registering.column, hookInfo.registering.function); + // Replace the space after the return type of the parent function with a non-breaking space + std::string parentFunction = std::string(hookInfo.registering.function); + size_t pos = parentFunction.find_first_of(" "); + if (pos != std::string::npos) { + parentFunction.replace(pos, 1, "\u00A0"); + } + // Non breaking space to keep the arrow with the parent function + ImGui::TextWrapped("%s(%d:%d) <-\u00A0%s", hookInfo.registering.file, hookInfo.registering.line, + hookInfo.registering.column, parentFunction.c_str()); } else { - ImGui::TextColored(yellow, "[Unavaliable]"); + ImGui::TextColored(yellow, "[Unavailable]"); } - //TODO: not currently possible - /* - ImGui::TableNextColumn(); - - ImGui::BeginDisabled(); - - bool stubButtonPressed = ImGui::Button(("Stub##" + std::to_string(id)).c_str()); - UIWidgets::SetLastItemHoverText("Stub this hook.\nThis is not possible to automatically undo."); - - if (stubButtonPressed) { - //stub - } - - ImGui::EndDisabled(); - */ - ImGui::TableNextColumn(); ImGui::Text("%d", hookInfo.calls); } @@ -84,12 +77,9 @@ void DrawHookRegisteringInfos(const char* hookName) { void HookDebuggerWindow::DrawElement() { #ifndef __cpp_lib_source_location - ImGui::TextColored( - yellow, - "Some features of the Hook Debugger are unavaliable because SoH was compiled " - "without \"\" support " - "(\"__cpp_lib_source_location\" not defined in \"\")." - ); + ImGui::TextColored(yellow, "Some features of the Hook Debugger are unavailable because SoH was compiled " + "without \"\" support " + "(\"__cpp_lib_source_location\" not defined in \"\")."); #endif for (auto& [hookName, _] : hookData) { @@ -101,9 +91,9 @@ void HookDebuggerWindow::DrawElement() { } void HookDebuggerWindow::InitElement() { - #define DEFINE_HOOK(name, _) hookData.insert({#name, GameInteractor::Instance->GetHookData()}); +#define DEFINE_HOOK(name, _) hookData.insert({ #name, GameInteractor::Instance->GetHookData() }); - #include "../game-interactor/GameInteractor_HookTable.h" +#include "../game-interactor/GameInteractor_HookTable.h" - #undef DEFINE_HOOK +#undef DEFINE_HOOK } diff --git a/soh/soh/Enhancements/debugger/valueViewer.cpp b/soh/soh/Enhancements/debugger/valueViewer.cpp index 40ec77f71..23ce4e26c 100644 --- a/soh/soh/Enhancements/debugger/valueViewer.cpp +++ b/soh/soh/Enhancements/debugger/valueViewer.cpp @@ -143,7 +143,6 @@ void RegisterValueViewerHooks() { RegisterShipInitFunc initFunc(RegisterValueViewerHooks, { CVAR_NAME }); void ValueViewerWindow::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontMonoLargest); UIWidgets::CVarCheckbox("Enable Printing", CVAR_NAME, UIWidgets::CheckboxOptions().Color(THEME_COLOR)); ImGui::BeginGroup(); @@ -264,7 +263,6 @@ void ValueViewerWindow::DrawElement() { } ImGui::EndGroup(); } - ImGui::PopFont(); } void ValueViewerWindow::InitElement() { diff --git a/soh/soh/Enhancements/enemyrandomizer.cpp b/soh/soh/Enhancements/enemyrandomizer.cpp index a2b72ca07..e638d04ad 100644 --- a/soh/soh/Enhancements/enemyrandomizer.cpp +++ b/soh/soh/Enhancements/enemyrandomizer.cpp @@ -286,7 +286,7 @@ void GetSelectedEnemies() { for (int i = 0; i < 49; i++) { if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0)) { selectedEnemyList.push_back(randomizedEnemySpawnTable[i]); - } else if (CVarGetInteger(enemyCVarList[i], 0)) { + } else if (CVarGetInteger(enemyCVarList[i], 1)) { selectedEnemyList.push_back(randomizedEnemySpawnTable[i]); } } diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 8c6be086f..db68ad86a 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -4,8 +4,8 @@ #define GameInteractor_h #include "libultraship/libultraship.h" -#include "GameInteractionEffect.h" #include "vanilla-behavior/GIVanillaBehavior.h" +#include "GameInteractionEffect.h" #include "soh/Enhancements/item-tables/ItemTableTypes.h" #include @@ -92,19 +92,20 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state); } #endif - #ifdef __cplusplus #include #include +#include #include #include #include #include + #include #ifdef __cpp_lib_source_location #include #else -#pragma message("Compiling without support, the Hook Debugger will not be avaliable") +#pragma message("Compiling without support, the Hook Debugger will not be available") #endif typedef uint32_t HOOK_ID; @@ -124,24 +125,31 @@ struct HookRegisteringInfo { const char* function; HookType type; - HookRegisteringInfo() : valid(false), file("unknown file"), line(0), column(0), function("unknown function"), type(HOOK_TYPE_NORMAL) {} + HookRegisteringInfo() + : valid(false), file("unknown file"), line(0), column(0), function("unknown function"), type(HOOK_TYPE_NORMAL) { + } - HookRegisteringInfo(const char* _file, std::uint_least32_t _line, std::uint_least32_t _column, const char* _function, HookType _type) : - valid(true), file(_file), line(_line), column(_column), function(_function), type(_type) {} + HookRegisteringInfo(const char* _file, std::uint_least32_t _line, std::uint_least32_t _column, + const char* _function, HookType _type) + : valid(true), file(_file), line(_line), column(_column), function(_function), type(_type) { + // Trim off user parent directories + const char* trimmed = strstr(_file, "soh/soh/"); + if (trimmed != nullptr) { + file = trimmed; + } + } }; struct HookInfo { uint32_t calls; HookRegisteringInfo registering; - - HookInfo() : calls(0), registering(HookRegisteringInfo{}) {} - HookInfo(HookRegisteringInfo _registering) : calls(0), registering(_registering) {} }; #ifdef __cpp_lib_source_location -#define GET_CURRENT_REGISTERING_INFO(type) HookRegisteringInfo{location.file_name(), location.line(), location.column(), location.function_name(), type} +#define GET_CURRENT_REGISTERING_INFO(type) \ + (HookRegisteringInfo{ location.file_name(), location.line(), location.column(), location.function_name(), type }) #else -#define GET_CURRENT_REGISTERING_INFO(type) HookRegisteringInfo{} +#define GET_CURRENT_REGISTERING_INFO(type) (HookRegisteringInfo{}) #endif #define REGISTER_VB_SHOULD(flag, body) \ @@ -171,23 +179,23 @@ struct HookInfo { hookId = GameInteractor::Instance->RegisterGameHookForID(id, body); \ } \ } -#define COND_VB_SHOULD(id, condition, body) \ - { \ - static HOOK_ID hookId = 0; \ +#define COND_VB_SHOULD(id, condition, body) \ + { \ + static HOOK_ID hookId = 0; \ GameInteractor::Instance->UnregisterGameHookForID(hookId); \ - hookId = 0; \ - if (condition) { \ - hookId = REGISTER_VB_SHOULD(id, body); \ - } \ + hookId = 0; \ + if (condition) { \ + hookId = REGISTER_VB_SHOULD(id, body); \ + } \ } class GameInteractor { -public: + public: static GameInteractor* Instance; // Game State class State { - public: + public: static bool NoUIActive; static GILinkSize LinkSize; static bool InvisibleLinkActive; @@ -219,14 +227,15 @@ public: // Game Hooks HOOK_ID nextHookId = 1; + template struct RegisteredGameHooks { inline static std::unordered_map functions; inline static std::unordered_map> functionsForID; inline static std::unordered_map> functionsForPtr; inline static std::unordered_map> functionsForFilter; - //Used for the hook debugger - inline static std::unordered_map hookData; + // Used for the hook debugger + inline static std::map hookData; }; template struct HooksToUnregister { @@ -236,39 +245,43 @@ public: inline static std::vector hooksForFilter; }; - template std::unordered_map* GetHookData() { + template std::map* GetHookData() { return &RegisteredGameHooks::hookData; } // General Hooks - template HOOK_ID RegisterGameHook( - typename H::fn h + template #ifdef __cpp_lib_source_location - , const std::source_location location = std::source_location::current() + HOOK_ID RegisterGameHook(typename H::fn h, const std::source_location location = std::source_location::current()) { +#else + HOOK_ID RegisterGameHook(typename H::fn h) { #endif - ) { - // Ensure hook id is unique and not 0, which is reserved for invalid hooks - if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1; + if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) + this->nextHookId = 1; while (RegisteredGameHooks::functions.find(this->nextHookId) != RegisteredGameHooks::functions.end()) { this->nextHookId++; } RegisteredGameHooks::functions[this->nextHookId] = h; - RegisteredGameHooks::hookData[this->nextHookId] = HookInfo{GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_NORMAL)}; + RegisteredGameHooks::hookData[this->nextHookId] = + HookInfo{ 0, GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_NORMAL) }; return this->nextHookId++; } template void UnregisterGameHook(HOOK_ID hookId) { - if (hookId == 0) return; + if (hookId == 0) + return; HooksToUnregister::hooks.push_back(hookId); } template void ExecuteHooks(Args&&... args) { + // Remove pending hooks for this type for (auto& hookId : HooksToUnregister::hooks) { RegisteredGameHooks::functions.erase(hookId); RegisteredGameHooks::hookData.erase(hookId); } HooksToUnregister::hooks.clear(); + // Execute hooks for (auto& hook : RegisteredGameHooks::functions) { hook.second(std::forward(args)...); RegisteredGameHooks::hookData[hook.first].calls += 1; @@ -276,39 +289,60 @@ public: } // ID based Hooks - template HOOK_ID RegisterGameHookForID( - int32_t id, typename H::fn h + template #ifdef __cpp_lib_source_location - , const std::source_location location = std::source_location::current() + HOOK_ID RegisterGameHookForID(int32_t id, typename H::fn h, + std::source_location location = std::source_location::current()) { +#else + HOOK_ID RegisterGameHookForID(int32_t id, typename H::fn h) { #endif - ) { - if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1; - while (RegisteredGameHooks::functionsForID[id].find(this->nextHookId) != RegisteredGameHooks::functionsForID[id].end()) { + if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) + this->nextHookId = 1; + while (RegisteredGameHooks::functionsForID[id].find(this->nextHookId) != + RegisteredGameHooks::functionsForID[id].end()) { this->nextHookId++; } RegisteredGameHooks::functionsForID[id][this->nextHookId] = h; - RegisteredGameHooks::hookData[this->nextHookId] = HookInfo{GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_ID)}; + RegisteredGameHooks::hookData[this->nextHookId] = HookInfo{ 0, GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_ID) }; return this->nextHookId++; } template void UnregisterGameHookForID(HOOK_ID hookId) { - if (hookId == 0) return; + if (hookId == 0) + return; HooksToUnregister::hooksForID.push_back(hookId); } template void ExecuteHooksForID(int32_t id, Args&&... args) { - for (auto& hookId : HooksToUnregister::hooksForID) { - for (auto it = RegisteredGameHooks::functionsForID[id].begin(); it != RegisteredGameHooks::functionsForID[id].end(); ) { - if (it->first == hookId) { + // Remove pending hooks for this type + for (auto hookIdIt = HooksToUnregister::hooksForID.begin(); + hookIdIt != HooksToUnregister::hooksForID.end();) { + bool remove = false; + + if (RegisteredGameHooks::functionsForID[id].size() == 0) { + break; + } + + for (auto it = RegisteredGameHooks::functionsForID[id].begin(); + it != RegisteredGameHooks::functionsForID[id].end();) { + if (it->first == *hookIdIt) { it = RegisteredGameHooks::functionsForID[id].erase(it); - HooksToUnregister::hooksForID.erase(std::remove(HooksToUnregister::hooksForID.begin(), HooksToUnregister::hooksForID.end(), hookId), HooksToUnregister::hooksForID.end()); - RegisteredGameHooks::hookData.erase(hookId); + RegisteredGameHooks::hookData.erase(*hookIdIt); + remove = true; + break; } else { ++it; } } + + if (remove) { + hookIdIt = HooksToUnregister::hooksForID.erase(hookIdIt); + } else { + ++hookIdIt; + } } + // Execute hooks for (auto& hook : RegisteredGameHooks::functionsForID[id]) { hook.second(std::forward(args)...); RegisteredGameHooks::hookData[hook.first].calls += 1; @@ -316,39 +350,60 @@ public: } // PTR based Hooks - template HOOK_ID RegisterGameHookForPtr( - uintptr_t ptr, typename H::fn h + template #ifdef __cpp_lib_source_location - , const std::source_location location = std::source_location::current() + HOOK_ID RegisterGameHookForPtr(uintptr_t ptr, typename H::fn h, + const std::source_location location = std::source_location::current()) { +#else + HOOK_ID RegisterGameHookForPtr(uintptr_t ptr, typename H::fn h) { #endif - ) { - if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1; - while (RegisteredGameHooks::functionsForPtr[ptr].find(this->nextHookId) != RegisteredGameHooks::functionsForPtr[ptr].end()) { + if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) + this->nextHookId = 1; + while (RegisteredGameHooks::functionsForPtr[ptr].find(this->nextHookId) != + RegisteredGameHooks::functionsForPtr[ptr].end()) { this->nextHookId++; } RegisteredGameHooks::functionsForPtr[ptr][this->nextHookId] = h; - RegisteredGameHooks::hookData[this->nextHookId] = HookInfo{GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_PTR)}; + RegisteredGameHooks::hookData[this->nextHookId] = HookInfo{ 0, GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_PTR) }; return this->nextHookId++; } template void UnregisterGameHookForPtr(HOOK_ID hookId) { - if (hookId == 0) return; + if (hookId == 0) + return; HooksToUnregister::hooksForPtr.push_back(hookId); } template void ExecuteHooksForPtr(uintptr_t ptr, Args&&... args) { - for (auto& hookId : HooksToUnregister::hooksForPtr) { - for (auto it = RegisteredGameHooks::functionsForPtr[ptr].begin(); it != RegisteredGameHooks::functionsForPtr[ptr].end(); ) { - if (it->first == hookId) { + // Remove pending hooks for this type + for (auto hookIdIt = HooksToUnregister::hooksForPtr.begin(); + hookIdIt != HooksToUnregister::hooksForPtr.end();) { + bool remove = false; + + if (RegisteredGameHooks::functionsForPtr[ptr].size() == 0) { + break; + } + + for (auto it = RegisteredGameHooks::functionsForPtr[ptr].begin(); + it != RegisteredGameHooks::functionsForPtr[ptr].end();) { + if (it->first == *hookIdIt) { it = RegisteredGameHooks::functionsForPtr[ptr].erase(it); - HooksToUnregister::hooksForPtr.erase(std::remove(HooksToUnregister::hooksForPtr.begin(), HooksToUnregister::hooksForPtr.end(), hookId), HooksToUnregister::hooksForPtr.end()); - RegisteredGameHooks::hookData.erase(hookId); + RegisteredGameHooks::hookData.erase(*hookIdIt); + remove = true; + break; } else { ++it; } } + + if (remove) { + hookIdIt = HooksToUnregister::hooksForPtr.erase(hookIdIt); + } else { + ++hookIdIt; + } } + // Execute hooks for (auto& hook : RegisteredGameHooks::functionsForPtr[ptr]) { hook.second(std::forward(args)...); RegisteredGameHooks::hookData[hook.first].calls += 1; @@ -356,33 +411,40 @@ public: } // Filter based Hooks - template HOOK_ID RegisterGameHookForFilter( - typename H::filter f, typename H::fn h + template #ifdef __cpp_lib_source_location - , const std::source_location location = std::source_location::current() + HOOK_ID RegisterGameHookForFilter(typename H::filter f, typename H::fn h, + const std::source_location location = std::source_location::current()) { +#else + HOOK_ID RegisterGameHookForFilter(typename H::filter f, typename H::fn h) { #endif - ) { - if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1; - while (RegisteredGameHooks::functionsForFilter.find(this->nextHookId) != RegisteredGameHooks::functionsForFilter.end()) { + if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) + this->nextHookId = 1; + while (RegisteredGameHooks::functionsForFilter.find(this->nextHookId) != + RegisteredGameHooks::functionsForFilter.end()) { this->nextHookId++; } RegisteredGameHooks::functionsForFilter[this->nextHookId] = std::make_pair(f, h); - RegisteredGameHooks::hookData[this->nextHookId] = HookInfo{GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_FILTER)}; + RegisteredGameHooks::hookData[this->nextHookId] = + HookInfo{ 0, GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_FILTER) }; return this->nextHookId++; } template void UnregisterGameHookForFilter(HOOK_ID hookId) { - if (hookId == 0) return; + if (hookId == 0) + return; HooksToUnregister::hooksForFilter.push_back(hookId); } template void ExecuteHooksForFilter(Args&&... args) { + // Remove pending hooks for this type for (auto& hookId : HooksToUnregister::hooksForFilter) { RegisteredGameHooks::functionsForFilter.erase(hookId); RegisteredGameHooks::hookData.erase(hookId); } HooksToUnregister::hooksForFilter.clear(); + // Execute hooks for (auto& hook : RegisteredGameHooks::functionsForFilter) { if (hook.second.first(std::forward(args)...)) { hook.second.second(std::forward(args)...); @@ -391,8 +453,62 @@ public: } } + template void ProcessUnregisteredHooks() { + // Normal + for (auto& hookId : HooksToUnregister::hooks) { + RegisteredGameHooks::functions.erase(hookId); + RegisteredGameHooks::hookData.erase(hookId); + } + HooksToUnregister::hooks.clear(); + + // ID + for (auto& hookId : HooksToUnregister::hooksForID) { + for (auto& idGroup : RegisteredGameHooks::functionsForID) { + for (auto it = idGroup.second.begin(); it != idGroup.second.end();) { + if (it->first == hookId) { + it = idGroup.second.erase(it); + RegisteredGameHooks::hookData.erase(hookId); + } else { + ++it; + } + } + } + } + HooksToUnregister::hooksForID.clear(); + + // Ptr + for (auto& hookId : HooksToUnregister::hooksForPtr) { + for (auto& ptrGroup : RegisteredGameHooks::functionsForPtr) { + for (auto it = ptrGroup.second.begin(); it != ptrGroup.second.end();) { + if (it->first == hookId) { + it = ptrGroup.second.erase(it); + RegisteredGameHooks::hookData.erase(hookId); + } else { + ++it; + } + } + } + } + HooksToUnregister::hooksForPtr.clear(); + + // Filter + for (auto& hookId : HooksToUnregister::hooksForFilter) { + RegisteredGameHooks::functionsForFilter.erase(hookId); + RegisteredGameHooks::hookData.erase(hookId); + } + HooksToUnregister::hooksForFilter.clear(); + } + + void RemoveAllQueuedHooks() { +#define DEFINE_HOOK(name, _) ProcessUnregisteredHooks(); + +#include "GameInteractor_HookTable.h" + +#undef DEFINE_HOOK + } + class HookFilter { - public: + public: static auto ActorNotPlayer(Actor* actor) { return actor->id != ACTOR_PLAYER; } @@ -401,15 +517,11 @@ public: return actor->id != ACTOR_PLAYER; } static auto ActorMatchIdAndParams(int16_t id, int16_t params) { - return [id, params](Actor* actor) { - return actor->id == id && actor->params == params; - }; + return [id, params](Actor* actor) { return actor->id == id && actor->params == params; }; } // For use with Should hooks static auto SActorMatchIdAndParams(int16_t id, int16_t params) { - return [id, params](Actor* actor, bool* result) { - return actor->id == id && actor->params == params; - }; + return [id, params](Actor* actor, bool* result) { return actor->id == id && actor->params == params; }; } }; @@ -430,7 +542,7 @@ public: static bool CanAddOrTakeAmmo(int16_t amount, int16_t item); class RawAction { - public: + public: static void SetSceneFlag(int16_t sceneNum, int16_t flagType, int16_t flag); static void UnsetSceneFlag(int16_t sceneNum, int16_t flagType, int16_t flag); static bool CheckFlag(int16_t flagType, int16_t flag); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index b41030cfa..9c861062b 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -19,6 +19,9 @@ void GameInteractor_ExecuteOnExitGame(int32_t fileNum) { } void GameInteractor_ExecuteOnGameStateMainStart() { + // Cleanup all hooks at the start of each frame + GameInteractor::Instance->RemoveAllQueuedHooks(); + GameInteractor::Instance->ExecuteHooks(); } diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index f1b918cef..d20864012 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -1,5 +1,6 @@ #pragma once +#include "vanilla-behavior/GIVanillaBehavior.h" #include "GameInteractor.h" #include diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp index aa8c72d00..d0b32018a 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp @@ -564,7 +564,7 @@ void GameInteractor::RawAction::SetRandomWind(bool active) { void GameInteractor::RawAction::SetPlayerInvincibility(bool active) { Player* player = GET_PLAYER(gPlayState); if (active) { - player->invincibilityTimer = 1000; + player->invincibilityTimer = -20; } else { player->invincibilityTimer = 0; } diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index a95dabb00..c8a0f747c 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -1,3 +1,8 @@ +#pragma once + +#ifndef GI_VANILLA_BEHAVIOR_H +#define GI_VANILLA_BEHAVIOR_H + typedef enum { // #### `result` // ```c @@ -95,10 +100,10 @@ typedef enum { // #### `args` // - `*BgDyYoseizo` VB_BE_ELIGIBLE_FOR_GREAT_FAIRY_REWARD, - + // #### `result` // ```c - // CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) && + // CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) && // CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW) && // LINK_IS_ADULT && // !Flags_GetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS) && @@ -118,11 +123,11 @@ typedef enum { // #### `result` // ```c - // (gSaveContext.entranceIndex == ENTR_KAKARIKO_VILLAGE_FRONT_GATE) && + // (gSaveContext.entranceIndex == ENTR_KAKARIKO_VILLAGE_FRONT_GATE) && // LINK_IS_ADULT && - // Flags_GetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP) && + // Flags_GetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP) && // Flags_GetEventChkInf(EVENTCHKINF_USED_FIRE_TEMPLE_BLUE_WARP) && - // Flags_GetEventChkInf(EVENTCHKINF_USED_WATER_TEMPLE_BLUE_WARP) && + // Flags_GetEventChkInf(EVENTCHKINF_USED_WATER_TEMPLE_BLUE_WARP) && // !Flags_GetEventChkInf(EVENTCHKINF_BONGO_BONGO_ESCAPED_FROM_WELL) // ``` // #### `args` @@ -473,7 +478,7 @@ typedef enum { // and // ```c // EnGe2_CheckCarpentersFreed() - // ``` + // ``` // #### `args` // - None VB_GERUDOS_BE_FRIENDLY, @@ -1265,10 +1270,18 @@ typedef enum { // - None VB_PLAY_BOLERO_OF_FIRE_CS, + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - `*EnDaiku` + VB_PLAY_CARPENTER_FREE_CS, + // #### `result` // Close enough & various cutscene checks // ```c - // (func_80AEC5FC(this, play)) && (!Play_InCsMode(play)) && + // (func_80AEC5FC(this, play)) && (!Play_InCsMode(play)) && // (!(player->stateFlags1 & (PLAYER_STATE1_HANGING_OFF_LEDGE | PLAYER_STATE1_CLIMBING_LEDGE | PLAYER_STATE1_CLIMBING_LADDER))) && // (player->actor.bgCheckFlags & 1) // ``` @@ -1697,25 +1710,25 @@ typedef enum { // #### `args` // ##### In `z_boss_dodongo.c`: // - `*BossDodongo` - // + // // ##### In `z_boss_fd2.c` // - `*BossFd2` - // + // // ##### In `z_boss_ganondrof.c`: // - `*BossGanondrof` - // + // // ##### In `z_boss_goma.c`: // - `*BossGoma` - // + // // ##### In `z_boss_mo.c`: // - `*BossMo` - // + // // ##### In `z_boss_sst.c`: // - `*BossSst` - // + // // ##### In `z_boss_tw.c`: // - `*BossTw` - // + // // ##### In `z_boss_va.c`: // - `*BossVa` VB_SPAWN_BLUE_WARP, @@ -1860,7 +1873,7 @@ typedef enum { // #### `args` // - `*EnMk` VB_USE_EYEDROP_DIALOGUE, - + // #### `result` // ```c // true @@ -1869,3 +1882,5 @@ typedef enum { // - `*EnWonderTalk2` VB_WONDER_TALK, } GIVanillaBehavior; + +#endif diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index cfcb98fa2..38de50575 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -16,7 +16,6 @@ #include "soh/Enhancements/timesaver_hook_handlers.h" #include "soh/Enhancements/TimeSavers/TimeSavers.h" #include "soh/Enhancements/randomizer/hook_handlers.h" -#include "objects/object_gi_compass/object_gi_compass.h" #include "src/overlays/actors/ovl_En_Bb/z_en_bb.h" #include "src/overlays/actors/ovl_En_Dekubaba/z_en_dekubaba.h" @@ -810,8 +809,10 @@ void RegisterRandomizedEnemySizes() { Actor* actor = static_cast(refActor); // Exclude wobbly platforms in Jabu because they need to act like platforms. + // Exclude demo effect for Zora sapphire being re-categorized as a "boss". // Exclude Dead Hand hands and Bongo Bongo main body because they make the fights (near) impossible. - uint8_t excludedEnemy = actor->id == ACTOR_EN_BROB || actor->id == ACTOR_EN_DHA || (actor->id == ACTOR_BOSS_SST && actor->params == -1); + uint8_t excludedEnemy = actor->id == ACTOR_EN_BROB || actor->id == ACTOR_EN_DHA || + actor->id == ACTOR_DEMO_EFFECT || (actor->id == ACTOR_BOSS_SST && actor->params == -1); // Dodongo, Volvagia and Dead Hand are always smaller because they're impossible when bigger. uint8_t smallOnlyEnemy = actor->id == ACTOR_BOSS_DODONGO || actor->id == ACTOR_BOSS_FD || @@ -998,26 +999,6 @@ void RegisterPauseMenuHooks() { }); } -extern "C" u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); - -void PatchCompasses() { - s8 compassesCanBeOutsideDungeon = IS_RANDO && DUNGEON_ITEMS_CAN_BE_OUTSIDE_DUNGEON(RSK_SHUFFLE_MAPANDCOMPASS); - s8 isColoredCompassesEnabled = compassesCanBeOutsideDungeon && CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MatchCompassColors"), 1); - if (isColoredCompassesEnabled) { - ResourceMgr_PatchGfxByName(gGiCompassDL, "Compass_PrimColor", 5, gsDPNoOp()); - ResourceMgr_PatchGfxByName(gGiCompassDL, "Compass_EnvColor", 6, gsDPNoOp()); - } else { - ResourceMgr_UnpatchGfxByName(gGiCompassDL, "Compass_PrimColor"); - ResourceMgr_UnpatchGfxByName(gGiCompassDL, "Compass_EnvColor"); - } -} - -void RegisterRandomizerCompasses() { - GameInteractor::Instance->RegisterGameHook([](int32_t _unused) { - PatchCompasses(); - }); -} - void RegisterCustomSkeletons() { static int8_t previousTunic = -1; @@ -1065,7 +1046,6 @@ void InitMods() { RegisterRandomizedEnemySizes(); RegisterOpenAllHours(); RegisterToTMedallions(); - RegisterRandomizerCompasses(); NameTag_RegisterHooks(); RegisterFloorSwitchesHook(); RegisterPatchHandHandler(); diff --git a/soh/soh/Enhancements/mods.h b/soh/soh/Enhancements/mods.h index 930522250..8ada99f1e 100644 --- a/soh/soh/Enhancements/mods.h +++ b/soh/soh/Enhancements/mods.h @@ -11,12 +11,11 @@ void UpdateDirtPathFixState(int32_t sceneNum); void UpdateMirrorModeState(int32_t sceneNum); void UpdateHurtContainerModeState(bool newState); void PatchToTMedallions(); -void PatchCompasses(); void UpdatePermanentHeartLossState(); void UpdateHyperEnemiesState(); void UpdateHyperBossesState(); void InitMods(); -void UpdatePatchHand(); +void UpdatePatchHand(); void SwitchAge(); #ifdef __cplusplus diff --git a/soh/soh/Enhancements/presets.cpp b/soh/soh/Enhancements/presets.cpp index 240d0fa81..c8760caca 100644 --- a/soh/soh/Enhancements/presets.cpp +++ b/soh/soh/Enhancements/presets.cpp @@ -50,7 +50,7 @@ void DrawPresetSelector(PresetType presetTypeId) { comboboxTooltip += std::string(iter->second.label) + " - " + std::string(iter->second.description); } - ImGui::Text("Presets", false, true); + ImGui::Text("Presets"); UIWidgets::PushStyleCombobox(THEME_COLOR); if (ImGui::BeginCombo("##PresetsComboBox", selectedPresetDef.label)) { for ( auto iter = presetTypeDef.presets.begin(); iter != presetTypeDef.presets.end(); ++iter ) { diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 2922ec589..a7bca4e66 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -242,7 +242,7 @@ const std::vector enhancedPresetEntries = { PRESET_ENTRY_S32(CVAR_ENHANCEMENT("SeparateArrows"), 1), // Disable Navi Call Audio - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DisableNaviCallAudio"), 1), + PRESET_ENTRY_S32(CVAR_AUDIO("DisableNaviCallAudio"), 1), // Equipment Toggle PRESET_ENTRY_S32(CVAR_ENHANCEMENT("EquipmentCanBeRemoved"), 1), @@ -373,7 +373,7 @@ const std::vector randomizerPresetEntries = { PRESET_ENTRY_S32(CVAR_ENHANCEMENT("SeparateArrows"), 1), // Disable Navi Call Audio - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DisableNaviCallAudio"), 1), + PRESET_ENTRY_S32(CVAR_AUDIO("DisableNaviCallAudio"), 1), // Equipment Toggle PRESET_ENTRY_S32(CVAR_ENHANCEMENT("EquipmentCanBeRemoved"), 1), @@ -436,7 +436,7 @@ const std::vector spockRacePresetEntries = { PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FasterBlockPush"), 5), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FasterHeavyBlockLift"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("NoForcedNavi"), 1), - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DisableNaviCallAudio"), 1), + PRESET_ENTRY_S32(CVAR_AUDIO("DisableNaviCallAudio"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FastChests"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FastDrops"), 1), PRESET_ENTRY_S32(CVAR_SETTING("DpadInText"), 1), @@ -531,7 +531,7 @@ const std::vector spockRaceNoLogicPresetEntries = { PRESET_ENTRY_S32(CVAR_ENHANCEMENT("CustomizeFishing"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DampeAllNight"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DayGravePull"), 1), - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DisableNaviCallAudio"), 1), + PRESET_ENTRY_S32(CVAR_AUDIO("DisableNaviCallAudio"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DpadNoDropOcarinaInput"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("EquipmentCanBeRemoved"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FastBoomerang"), 1), diff --git a/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp b/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp index 179987dcc..fcab083b4 100644 --- a/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp @@ -2,258 +2,9 @@ #include "../../custom-message/CustomMessageManager.h" #include "z64item.h" -#include -#include -#include - namespace CustomMessages { - using namespace std::literals::string_literals; -class MessageEntryComp { -public: - bool operator()(const MessageEntry& lhs, const MessageEntry& rhs) const { - return lhs.id < rhs.id; - } -}; - -constexpr std::array EnglishDungeonNames = { - "Deku Tree", - "Dodongo's Cavern", - "Jabu Jabu's Belly", - "Forest Temple", - "Fire Temple", - "Water Temple", - "Spirit Temple", - "Shadow Temple", - "Bottom of the Well", - "Ice Cavern", - "Ganon's Tower", - "Gerudo Training Ground", - "Gerudo Fortress", - "Ganon's Castle", -}; - -constexpr std::array FrenchDungeonNames = { - "Vénérable Arbre Mojo", - "Caverne Dodongo", - "Ventre de Jabu-Jabu", - "Temple de la Forêt", - "Temple du Feu", - "Temple de l'Eau", - "Temple de l'Esprit", - "Temple de l'Ombre", - "Puits", - "Caverne Polaire", - "Tour de Ganon", - "Gymnase Gerudo", - "Repaire des Voleurs", - "Château de Ganon", -}; - -constexpr std::array FrenchDungeonArticles = { - "du ", - "de la ", - "du ", - "du ", - "du ", - "du ", - "du ", - "du ", - "du ", - "de la ", - "", - "du ", - "de la ", - "du ", -}; - -constexpr std::array SpanishDungeonNames = { - "Gran Árbol Deku", - "Cueva de los Dodongos", - "Tripa de Jabu-Jabu", - "Templo del Bosque", - "Templo del Fuego", - "Templo del Agua", - "Templo del Espíritu", - "Templo de las Sombras", - "Fondo del pozo", - "Caverna de hielo", - "Torre de Ganon", - "Centro de Instrucción Gerudo", - "Fortaleza Gerudo", - "Castillo de Ganon", -}; - -constexpr std::array SpanishDungeonArticles = { - "del", - "de la", - "de la", - "del", - "del", - "del", - "del", - "del", - "del", - "de la", - "de la", - "del", - "de la", - "del", -}; - -constexpr std::array DungeonColors = { - QM_GREEN, - QM_RED, - QM_BLUE, - QM_GREEN, - QM_RED, - QM_BLUE, - QM_YELLOW, - QM_PINK, - QM_PINK, - QM_LBLUE, - QM_BLACK, - QM_YELLOW, - QM_YELLOW, - QM_RED, -}; - - std::set messageEntries; - std::stringstream messageData; - - //textBoxType and textBoxPosition are defined here: https://wiki.cloudmodding.com/oot/Text_Format#Message_Id - void CreateMessage(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, - std::string englishText, std::string frenchText, std::string spanishText) { - MessageEntry newEntry = { textId, unk_04, textBoxType, textBoxPosition, { 0 } }; - - while ((englishText.size() % 4) != 0) { - englishText += "\0"s; - } - messageData.seekg(0, messageData.end); - newEntry.info[ENGLISH_U].offset = (char*)((int)messageData.tellg()); - newEntry.info[ENGLISH_U].length = englishText.size(); - messageData << englishText; - - while ((frenchText.size() % 4) != 0) { - frenchText += "\0"s; - } - messageData.seekg(0, messageData.end); - newEntry.info[FRENCH_U].offset = (char*)((int)messageData.tellg()); - newEntry.info[FRENCH_U].length = frenchText.size(); - messageData << frenchText; - - while ((spanishText.size() % 4) != 0) { - spanishText += "\0"s; - } - messageData.seekg(0, messageData.end); - newEntry.info[SPANISH_U].offset = (char*)((int)messageData.tellg()); - newEntry.info[SPANISH_U].length = spanishText.size(); - messageData << spanishText; - - messageEntries.insert(newEntry); - } - - void CreateMessageFromTextObject(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, const Text& text) { - CreateMessage(textId, unk_04, textBoxType, textBoxPosition, text.GetEnglish(), text.GetFrench(), text.GetSpanish()); - } - - Text AddColorsAndFormat(Text text, const std::vector& colors /*= {}*/) { - - //for each language - for (std::string* textStr : {&text.english, &text.french, &text.spanish}) { - - //insert playername - size_t atSymbol = textStr->find('@'); - while (atSymbol != std::string::npos) { - textStr->replace(atSymbol, 1, PLAYER_NAME()); - atSymbol = textStr->find('@'); - } - //insert newlines either manually or when encountering a '&' - constexpr size_t lineLength = 44; - size_t lastNewline = 0; - while (lastNewline + lineLength < textStr->length()) { - size_t carrot = textStr->find('^', lastNewline); - size_t ampersand = textStr->find('&', lastNewline); - size_t lastSpace = textStr->rfind(' ', lastNewline + lineLength); - size_t lastPeriod = textStr->rfind('.', lastNewline + lineLength); - //replace '&' first if it's within the newline range - if (ampersand < lastNewline + lineLength) { - textStr->replace(ampersand, 1, NEWLINE()); - lastNewline = ampersand + NEWLINE().length(); - //or move the lastNewline cursor to the next line if a '^' is encountered - } else if (carrot < lastNewline + lineLength) { - lastNewline = carrot + 1; - //some lines need to be split but don't have spaces, look for periods instead - } else if (lastSpace == std::string::npos) { - textStr->replace(lastPeriod, 1, "."+NEWLINE()); - lastNewline = lastPeriod + NEWLINE().length() + 1; - } else { - textStr->replace(lastSpace, 1, NEWLINE()); - lastNewline = lastSpace + NEWLINE().length(); - } - } - //clean up any remaining '&' characters - size_t ampersand = textStr->find('&'); - while (ampersand != std::string::npos) { - textStr->replace(ampersand, 1, NEWLINE()); - ampersand = textStr->find('&'); - } - - //insert box break - size_t carrotSymbol = textStr->find('^'); - while (carrotSymbol != std::string::npos) { - textStr->replace(carrotSymbol, 1, INSTANT_TEXT_OFF()+WAIT_FOR_INPUT()+INSTANT_TEXT_ON()); - carrotSymbol = textStr->find('^'); - } - - //If there's a two-way choice and only 1 newline before it in the same text box, add another one - size_t choice = textStr->find(TWO_WAY_CHOICE()); - if (choice != std::string::npos) { - size_t newLinesCount = 0; - size_t lastBoxBreak = textStr->rfind(WAIT_FOR_INPUT(), choice); - lastNewline = choice; - - if (lastBoxBreak == std::string::npos) { - lastBoxBreak = 0; - } - - while ((lastNewline != std::string::npos)) { - lastNewline = textStr->rfind(NEWLINE(), lastNewline - 1); - if (lastNewline != std::string::npos && lastNewline > lastBoxBreak) { - newLinesCount++; - } else { - break; - } - } - - if (newLinesCount <= 1) { - textStr->replace(choice, TWO_WAY_CHOICE().length(), NEWLINE()+TWO_WAY_CHOICE()); - } - } - - //add colors - for (auto color : colors) { - size_t firstHashtag = textStr->find('#'); - if (firstHashtag != std::string::npos) { - textStr->replace(firstHashtag, 1, COLOR(color)); - size_t secondHashtag = textStr->find('#'); - if (secondHashtag == std::string::npos) { - //CitraPrint("ERROR: Couldn't find second '#' in " + (*textStr)); - } else { - textStr->replace(secondHashtag, 1, COLOR(QM_WHITE)); - } - } - } - } - return Text{"","",""}+UNSKIPPABLE()+INSTANT_TEXT_ON()+text+INSTANT_TEXT_OFF()+MESSAGE_END(); - } - - void ClearMessages() { - messageEntries.clear(); - messageData.str(""); - } - std::string MESSAGE_END() { return "\x7F\x00"s; } std::string WAIT_FOR_INPUT() { return "\x7F\x01"s; } std::string HORIZONTAL_SPACE(uint8_t x) { @@ -280,7 +31,7 @@ constexpr std::array DungeonColors = { std::string SET_SPEED(uint8_t x) { return "\x7F\x10"s + char(x); } - std::string SKULLTULAS_DESTROYED() { return "\x7F\x15"s; } //RANDOTODO just refernce the versions in CustomMessage + std::string SKULLTULAS_DESTROYED() { return "\x7F\x15"s; } std::string CURRENT_TIME() { return "\x7F\x17"s; } std::string UNSKIPPABLE() { return "\x7F\x19"s; } std::string TWO_WAY_CHOICE() { return "\x1B"s; } diff --git a/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp b/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp index b9d2a08c6..4daacf51a 100644 --- a/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp @@ -1,50 +1,11 @@ #pragma once #include -#include -#include #include #include "text.hpp" namespace CustomMessages { -typedef struct { - // In the true file format, offset is the offset into the QM file. - // In randomizer, offset will be a pointer to the text in the game's address space. - // Since these pointers will be much larger as u32 than the original script's offsets, - // We will be able to distinguish between original and custom text using their numerical value. - const char* offset; - uint32_t length; -} MessageLanguageInfo; - -typedef enum { - /* 0x00 */ JAPANESE_J, - /* 0x01 */ ENGLISH_U, - /* 0x02 */ ENGLISH_E, - /* 0x03 */ GERMAN_E, - /* 0x04 */ FRENCH_E, - /* 0x05 */ FRENCH_U, - /* 0x06 */ SPANISH_E, - /* 0x07 */ SPANISH_U, - /* 0x08 */ ITALIAN_E, - /* 0x09 */ DUTCH_E, -} MessageLanguage; - -typedef struct { - uint32_t id; - uint32_t unk_04; - uint32_t unk_08; - uint32_t unk_0C; - MessageLanguageInfo info[10]; -} MessageEntry; // size = 0x60 - - void CreateMessage(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, - std::string englishText, std::string frenchText, std::string spanishText); - void CreateMessageFromTextObject(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, const Text& text); - - Text AddColorsAndFormat(Text text, const std::vector& colors = {}); - void ClearMessages(); - std::string MESSAGE_END(); std::string WAIT_FOR_INPUT(); std::string HORIZONTAL_SPACE(uint8_t x); diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index a7609cc93..cd224ff8f 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -1,6 +1,5 @@ #include "fill.hpp" -#include "custom_messages.hpp" #include "../dungeon.h" #include "../context.h" #include "item_pool.hpp" @@ -19,7 +18,6 @@ #include #include -using namespace CustomMessages; using namespace Rando; diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp index 867da2b2c..c786dd8de 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -2070,23 +2070,23 @@ void StaticData::HintTable_Init_Item() { CustomMessage("a rightward tone", /*german*/"ein rechtsseitiger Ton", /*french*/"une tonalité vers la droite")}); // /*spanish*/un tono hacia la derecha - hintTextTable[RHT_FISHING_POLE] = HintText(CustomMessage("a fishing pole", /*german*/"eine Angelrute", /*french*/"canne à pêche"), + hintTextTable[RHT_FISHING_POLE] = HintText(CustomMessage("a fishing pole", /*german*/"eine Angelrute", /*french*/"une canne à pêche"), // /*spanish*/caña de pescar { - CustomMessage("the pond owner's property", /*german*/"der Besitz des Teicheigners", /*french*/"(canne à pêche)") + CustomMessage("the pond owner's property", /*german*/"der Besitz des Teicheigners", /*french*/"(un truc qui appartient au propriétaire de l'étang)") // /*spanish*/(caña de pescar) }, { - CustomMessage("a fish-puller", /*german*/"ein Fischzieher", /*french*/"(canne à pêche)")}); + CustomMessage("a fish-puller", /*german*/"ein Fischzieher", /*french*/"(un aimant à poisson)")}); // /*spanish*/(caña de pescar) - hintTextTable[RHT_BOMBCHU_BAG] = HintText(CustomMessage("Bombchu Bag", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_BOMBCHU_BAG] = HintText(CustomMessage("Bombchu Bag", /*german*/"!!!", /*french*/"un Sac de Missiles Teigneux"), { CustomMessage("explosives", /*german*/"ein Explosivpaket", /*french*/"un paquet d'explosifs"), // /*spanish*/un montón de explosivos CustomMessage("something that can remove boulders", /*german*/"etwas, das Geröll entfernen kann", /*french*/"une chose qui enlève les rochers") // /*spanish*/algo que pueda quitar rocas }, { - CustomMessage("sack of mice", /*german*/"!!!", /*french*/"!!!")}); + CustomMessage("sack of mice", /*german*/"!!!", /*french*/"un Sac rempli de souris")}); hintTextTable[RHT_SKELETON_KEY] = HintText(CustomMessage("a Skeleton Key", /*german*/ "ein Universalschlüssel", /*french*/ "une Clé Squelette"), // /*spanish*/una Llave Maestra @@ -2096,49 +2096,49 @@ void StaticData::HintTable_Init_Item() { }, { CustomMessage("a master unlocker", /*german*/ "ein Meisterentsperrer", /*french*/ "un Kit de Déverrouillage") }); // /*spanish*/un desbloqueador maestro - hintTextTable[RHT_QUIVER_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_QUIVER_INF] = HintText(CustomMessage("an infinite Quiver", /*german*/"!!!", /*french*/"un Carquois Infini"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), }, { CustomMessage("", /*german*/"!!!", /*french*/"!!!")}); - hintTextTable[RHT_BOMB_BAG_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_BOMB_BAG_INF] = HintText(CustomMessage("an infinite Bomb Bag", /*german*/"!!!", /*french*/"un Sac de Bombe sans fond"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), }, { CustomMessage("", /*german*/"!!!", /*french*/"!!!")}); - hintTextTable[RHT_BULLET_BAG_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_BULLET_BAG_INF] = HintText(CustomMessage("an infinite Bullet Bag", /*german*/"!!!", /*french*/"un Sac de Graine sans fond"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), }, { CustomMessage("", /*german*/"!!!", /*french*/"!!!")}); - hintTextTable[RHT_STICK_UPGRADE_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_STICK_UPGRADE_INF] = HintText(CustomMessage("infinite Deku Sticks", /*german*/"!!!", /*french*/" des Bâtons Mojo illimités"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), }, { CustomMessage("", /*german*/"!!!", /*french*/"!!!")}); - hintTextTable[RHT_NUT_UPGRADE_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_NUT_UPGRADE_INF] = HintText(CustomMessage("infinite Deku Nut", /*german*/"!!!", /*french*/"des Noix Mojo illimitées"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), }, { CustomMessage("", /*german*/"!!!", /*french*/"!!!")}); - hintTextTable[RHT_MAGIC_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_MAGIC_INF] = HintText(CustomMessage("unlimited Magic", /*german*/"!!!", /*french*/"de la Magie infinie"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), }, { CustomMessage("", /*german*/"!!!", /*french*/"!!!")}); - hintTextTable[RHT_BOMBCHU_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_BOMBCHU_INF] = HintText(CustomMessage("infinite Bombchus", /*german*/"!!!", /*french*/"des Missiles Teigneux illimités"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), }, { CustomMessage("", /*german*/"!!!", /*french*/"!!!")}); - hintTextTable[RHT_WALLET_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), + hintTextTable[RHT_WALLET_INF] = HintText(CustomMessage("an infinite Wallet", /*german*/"!!!", /*french*/"une Bourse sans fond"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), }, { diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 45e6221ce..5cbfb9a9e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -1297,7 +1297,7 @@ void GenerateItemPool() { if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) { ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, RG_GANONS_CASTLE_BOSS_KEY); - } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Get() >= RO_GANON_BOSS_KEY_LACS_VANILLA && ctx->GetOption(RSK_GANONS_BOSS_KEY).IsNot(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) { + } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Get() >= RO_GANON_BOSS_KEY_LACS_VANILLA) { ctx->PlaceItemInLocation(RC_TOT_LIGHT_ARROWS_CUTSCENE, RG_GANONS_CASTLE_BOSS_KEY); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA)) { ctx->PlaceItemInLocation(RC_GANONS_TOWER_BOSS_KEY_CHEST, RG_GANONS_CASTLE_BOSS_KEY); diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp index 144dee80a..d8fd302c1 100644 --- a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -2,7 +2,6 @@ #include #include -#include "custom_messages.hpp" #include "fill.hpp" #include "../location_access.h" #include "random.hpp" @@ -23,7 +22,6 @@ int Playthrough_Init(uint32_t seed, std::set excludedLocations, auto ctx = Rando::Context::GetInstance(); ctx->overrides.clear(); - CustomMessages::ClearMessages(); ctx->ItemReset(); ctx->HintReset(); ctx->GetLogic()->Reset(); diff --git a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp index c72b5f285..04a7e3040 100644 --- a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp @@ -57,7 +57,7 @@ void GenerateStartingInventory() { // Add Ganon's Boss key with Triforce Hunt so the game thinks it's obtainable from the start. // During save init, the boss key isn't actually given and it's instead given when completing the triforce. if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH) || - ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) { + ctx->GetOption(RSK_TRIFORCE_HUNT)) { AddItemToInventory(RG_GANONS_CASTLE_BOSS_KEY); } diff --git a/soh/soh/Enhancements/randomizer/ColoredMapsAndCompasses.cpp b/soh/soh/Enhancements/randomizer/ColoredMapsAndCompasses.cpp new file mode 100644 index 000000000..fcfa13d97 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/ColoredMapsAndCompasses.cpp @@ -0,0 +1,43 @@ +#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/ResourceManagerHelpers.h" +#include "soh/ShipInit.hpp" +#include "z64save.h" +#include "objects/object_gi_compass/object_gi_compass.h" +#include "objects/object_gi_map/object_gi_map.h" + +extern "C" { + extern SaveContext gSaveContext; + #include "variables.h" + #include "macros.h" + u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); +} + +#define CVAR_COLORED_MAPS_AND_COMPASSES_NAME CVAR_RANDOMIZER_ENHANCEMENT("ColoredMapsAndCompasses") +#define CVAR_COLORED_MAPS_AND_COMPASSES_DEFAULT 1 +#define CVAR_COLORED_MAPS_AND_COMPASSES_VALUE CVarGetInteger(CVAR_COLORED_MAPS_AND_COMPASSES_NAME, CVAR_COLORED_MAPS_AND_COMPASSES_DEFAULT) + +void OnLoadFileColoredMapsAndCompasses(int32_t _) { + s8 mapsAndCompassesCanBeOutsideDungeon = IS_RANDO && DUNGEON_ITEMS_CAN_BE_OUTSIDE_DUNGEON(RSK_SHUFFLE_MAPANDCOMPASS); + s8 isColoredMapsAndCompassesEnabled = mapsAndCompassesCanBeOutsideDungeon && CVAR_COLORED_MAPS_AND_COMPASSES_VALUE; + if (isColoredMapsAndCompassesEnabled) { + ResourceMgr_PatchGfxByName(gGiDungeonMapDL, "Map_PrimColor", 5, gsDPNoOp()); + ResourceMgr_PatchGfxByName(gGiDungeonMapDL, "Map_EnvColor", 6, gsDPNoOp()); + ResourceMgr_PatchGfxByName(gGiCompassDL, "Compass_PrimColor", 5, gsDPNoOp()); + ResourceMgr_PatchGfxByName(gGiCompassDL, "Compass_EnvColor", 6, gsDPNoOp()); + } else { + ResourceMgr_UnpatchGfxByName(gGiDungeonMapDL, "Map_PrimColor"); + ResourceMgr_UnpatchGfxByName(gGiDungeonMapDL, "Map_EnvColor"); + ResourceMgr_UnpatchGfxByName(gGiCompassDL, "Compass_PrimColor"); + ResourceMgr_UnpatchGfxByName(gGiCompassDL, "Compass_EnvColor"); + } +} + +void RegisterColoredMapsAndCompasses() { + COND_HOOK(OnLoadFile, CVAR_COLORED_MAPS_AND_COMPASSES_VALUE, OnLoadFileColoredMapsAndCompasses) + + //Also need to call it directly to patch/unpatch on cvar change + OnLoadFileColoredMapsAndCompasses(0); +} + +static RegisterShipInitFunc initFunc(RegisterColoredMapsAndCompasses, { CVAR_COLORED_MAPS_AND_COMPASSES_NAME }); diff --git a/soh/soh/Enhancements/randomizer/Plandomizer.cpp b/soh/soh/Enhancements/randomizer/Plandomizer.cpp index 4741d9d0c..39b20d876 100644 --- a/soh/soh/Enhancements/randomizer/Plandomizer.cpp +++ b/soh/soh/Enhancements/randomizer/Plandomizer.cpp @@ -838,8 +838,8 @@ void PlandomizerDrawItemSlots(uint32_t index) { void PlandomizerDrawShopSlider(uint32_t index) { ImGui::PushID(index); UIWidgets::SliderInt("Price:", &plandoLogData[index].shopPrice, UIWidgets::IntSliderOptions() - .Color(THEME_COLOR).Format("%d Rupees").Min(0).Max(999).LabelPosition(UIWidgets::LabelPosition::Near) - .ComponentAlignment(UIWidgets::ComponentAlignment::Right).Size(UIWidgets::Sizes::Inline)); + .Color(THEME_COLOR).Format("%d Rupees").Min(0).Max(999).LabelPosition(UIWidgets::LabelPositions::Near) + .ComponentAlignment(UIWidgets::ComponentAlignments::Right).Size(UIWidgets::Sizes::Inline)); ImGui::PopID(); } @@ -878,7 +878,7 @@ void PlandomizerDrawIceTrapSetup(uint32_t index) { } ImGui::SameLine(); } - if (UIWidgets::InputString("##TrapName", &trapTextInput, UIWidgets::InputOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::None))) { + if (UIWidgets::InputString("##TrapName", &trapTextInput, UIWidgets::InputOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPositions::None))) { plandoLogData[index].iceTrapName = trapTextInput.c_str(); } @@ -933,7 +933,7 @@ void PlandomizerDrawOptions() { PlandomizerPopulateSeedList(); static size_t selectedList = 0; if (existingSeedList.size() != 0) { - UIWidgets::Combobox("##JsonFiles", &selectedList, existingSeedList, UIWidgets::ComboboxOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::None)); + UIWidgets::Combobox("##JsonFiles", &selectedList, existingSeedList, UIWidgets::ComboboxOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPositions::None)); } else { ImGui::Text("No Spoiler Logs found."); @@ -1024,7 +1024,7 @@ void PlandomizerDrawOptions() { } if (getTabID == TAB_LOCATIONS) { if (plandoLogData.size() > 0) { - UIWidgets::Combobox("Filter by Area:##AreaFilter", &selectedArea, rcAreaNameMap, UIWidgets::ComboboxOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::Near).ComponentAlignment(UIWidgets::ComponentAlignment::Right)); + UIWidgets::Combobox("Filter by Area:##AreaFilter", &selectedArea, rcAreaNameMap, UIWidgets::ComboboxOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPositions::Near).ComponentAlignment(UIWidgets::ComponentAlignments::Right)); ImGui::SameLine(); if (UIWidgets::Button("Empty All Rewards", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline).Padding(ImVec2(10.f, 6.f)))) { PlandomizerRemoveAllItems(); @@ -1061,7 +1061,7 @@ void PlandomizerDrawHintsWindow() { } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 10); - if (UIWidgets::InputString("##HintMessage", &hintInputText, UIWidgets::InputOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::None).Tooltip(plandomizerHintsTooltip().c_str()))) { + if (UIWidgets::InputString("##HintMessage", &hintInputText, UIWidgets::InputOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPositions::None).Tooltip(plandomizerHintsTooltip().c_str()))) { plandoHintData[index].hintText = hintInputText.c_str(); } index++; diff --git a/soh/soh/Enhancements/randomizer/ShufflePots.cpp b/soh/soh/Enhancements/randomizer/ShufflePots.cpp index be12d086b..cbc96cd1d 100644 --- a/soh/soh/Enhancements/randomizer/ShufflePots.cpp +++ b/soh/soh/Enhancements/randomizer/ShufflePots.cpp @@ -54,9 +54,6 @@ void ObjTsubo_RandomizerSpawnCollectible(ObjTsubo* potActor, PlayState* play) { void ObjTsubo_RandomizerInit(void* actorRef) { Actor* actor = static_cast(actorRef); - // Check for Lake Hylia specifically because the game spawns 2 pots out of bounds there for some reason. - if (actor->id != ACTOR_OBJ_TSUBO || gPlayState->sceneNum == SCENE_LAKE_HYLIA || gPlayState->sceneNum == SCENE_HYRULE_CASTLE) return; - ObjTsubo* potActor = static_cast(actorRef); potActor->potIdentity = OTRGlobals::Instance->gRandomizer->IdentifyPot(gPlayState->sceneNum, (s16)actor->world.pos.x, (s16)actor->world.pos.z); diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp index 0a89e4dae..73b4142de 100644 --- a/soh/soh/Enhancements/randomizer/draw.cpp +++ b/soh/soh/Enhancements/randomizer/draw.cpp @@ -11,6 +11,7 @@ #include "objects/object_gi_key/object_gi_key.h" #include "objects/object_gi_bosskey/object_gi_bosskey.h" #include "objects/object_gi_compass/object_gi_compass.h" +#include "objects/object_gi_map/object_gi_map.h" #include "objects/object_gi_hearts/object_gi_hearts.h" #include "objects/object_gi_scale/object_gi_scale.h" #include "objects/object_gi_fire/object_gi_fire.h" @@ -80,7 +81,7 @@ Color_RGB8 SmallEmblemDefaultValue[10] = { extern "C" u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); extern "C" void Randomizer_DrawSmallKey(PlayState* play, GetItemEntry* getItemEntry) { - s8 isCustomKeysEnabled = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("CustomKeyModels"), 0); + s8 isCustomKeysEnabled = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("CustomKeyModels"), 1); int slot = getItemEntry->drawItemId - RG_FOREST_TEMPLE_SMALL_KEY; Gfx* customIconDLs[] = { @@ -131,15 +132,35 @@ extern "C" void Randomizer_DrawSmallKey(PlayState* play, GetItemEntry* getItemEn CLOSE_DISPS(play->state.gfxCtx); } -extern "C" { - void GetItem_DrawCompass(PlayState* play, s16 drawId); - void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction); - void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName); +extern "C" void Randomizer_DrawMap(PlayState* play, GetItemEntry* getItemEntry) { + s16 color_slot = getItemEntry->drawItemId - RG_DEKU_TREE_MAP; + s16 colors[12][3] = { + { 4, 100, 46 }, // Deku Tree + { 140, 30, 30 }, // Dodongo's Cavern + { 30, 60, 255 }, // Jabu Jabu's Belly + { 4, 195, 46 }, // Forest Temple + { 237, 95, 95 }, // Fire Temple + { 85, 180, 223 }, // Water Temple + { 222, 158, 47 }, // Spirit Temple + { 126, 16, 177 }, // Shadow Temple + { 227, 110, 255 }, // Bottom of the Well + { 0, 255, 255 }, // Ice Cavern + }; + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL_25Opa(play->state.gfxCtx); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, colors[color_slot][0], colors[color_slot][1], colors[color_slot][2], 255); + + gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gGiDungeonMapDL); + + CLOSE_DISPS(play->state.gfxCtx); } extern "C" void Randomizer_DrawCompass(PlayState* play, GetItemEntry* getItemEntry) { - - s16 color_slot = getItemEntry->getItemId - RG_DEKU_TREE_COMPASS; + s16 color_slot = getItemEntry->drawItemId - RG_DEKU_TREE_COMPASS; s16 colors[12][3] = { { 4, 100, 46 }, // Deku Tree { 140, 30, 30 }, // Dodongo's Cavern @@ -158,8 +179,7 @@ extern "C" void Randomizer_DrawCompass(PlayState* play, GetItemEntry* getItemEnt OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL_25Opa(play->state.gfxCtx); - gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), - G_MTX_MODELVIEW | G_MTX_LOAD); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD); gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, colors[color_slot][0], colors[color_slot][1], colors[color_slot][2], 255); gDPSetEnvColor(POLY_OPA_DISP++, colors[color_slot][0] / 2, colors[color_slot][1] / 2, colors[color_slot][2] / 2, 255); @@ -167,8 +187,7 @@ extern "C" void Randomizer_DrawCompass(PlayState* play, GetItemEntry* getItemEnt gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gGiCompassDL); POLY_XLU_DISP = Gfx_SetupDL(POLY_XLU_DISP, 5); - gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), - G_MTX_MODELVIEW | G_MTX_LOAD); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD); gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gGiCompassGlassDL); CLOSE_DISPS(play->state.gfxCtx); @@ -247,7 +266,7 @@ extern "C" void Randomizer_DrawBossKey(PlayState* play, GetItemEntry* getItemEnt } extern "C" void Randomizer_DrawKeyRing(PlayState* play, GetItemEntry* getItemEntry) { - s8 isCustomKeysEnabled = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("CustomKeyModels"), 0); + s8 isCustomKeysEnabled = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("CustomKeyModels"), 1); int slot = getItemEntry->drawItemId - RG_FOREST_TEMPLE_KEY_RING; Gfx* CustomIconDLs[] = { diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h index 3fc5c86b4..aaac71e06 100644 --- a/soh/soh/Enhancements/randomizer/draw.h +++ b/soh/soh/Enhancements/randomizer/draw.h @@ -10,6 +10,7 @@ typedef struct PlayState PlayState; extern "C" { #endif void Randomizer_DrawSmallKey(PlayState* play, GetItemEntry* getItemEntry); +void Randomizer_DrawMap(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawCompass(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawKeyRing(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawBossKey(PlayState* play, GetItemEntry* getItemEntry); diff --git a/soh/soh/Enhancements/randomizer/hint.cpp b/soh/soh/Enhancements/randomizer/hint.cpp index 29a9a969f..2648c4623 100644 --- a/soh/soh/Enhancements/randomizer/hint.cpp +++ b/soh/soh/Enhancements/randomizer/hint.cpp @@ -587,6 +587,10 @@ CustomMessage Hint::GetGanonBossKeyText() { auto ctx = Rando::Context::GetInstance(); CustomMessage ganonBossKeyMessage; + if (ctx->GetOption(RSK_TRIFORCE_HUNT)) { + return StaticData::hintTextTable[RHT_GANON_BK_TRIFORCE_HINT].GetHintMessage(); + } + if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH)) { return StaticData::hintTextTable[RHT_GANON_BK_START_WITH_HINT].GetHintMessage(); } @@ -631,9 +635,6 @@ CustomMessage Hint::GetGanonBossKeyText() { ganonBossKeyMessage = StaticData::hintTextTable[RHT_LACS_TOKENS_HINT].GetHintMessage(); ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_TOKEN_COUNT).Get()); } - else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) { - return StaticData::hintTextTable[RHT_GANON_BK_TRIFORCE_HINT].GetHintMessage(); - } return ganonBossKeyMessage; } diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index d1f50571d..15e695960 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -297,14 +297,19 @@ void RandomizerOnPlayerUpdateForRCQueueHandler() { rc != RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE && // Always show ItemGet animation for ice traps !(getItemEntry.modIndex == MOD_RANDOMIZER && getItemEntry.getItemId == RG_ICE_TRAP) && + // Always show ItemGet animation outside of randomizer to keep behaviour consistent in vanilla + IS_RANDO && ( CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("TimeSavers.SkipGetItemAnimation"), SGIA_DISABLED) == SGIA_ALL || ( CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("TimeSavers.SkipGetItemAnimation"), SGIA_DISABLED) == SGIA_JUNK && ( + //crude fix to ensure map hints are readable. Ideally replace with better hint tracking. + !(getItemEntry.getItemId >= RG_DEKU_TREE_MAP && getItemEntry.getItemId <= RG_ICE_CAVERN_MAP) && ( getItemEntry.getItemCategory == ITEM_CATEGORY_JUNK || getItemEntry.getItemCategory == ITEM_CATEGORY_SKULLTULA_TOKEN || - getItemEntry.getItemCategory == ITEM_CATEGORY_LESSER + getItemEntry.getItemCategory == ITEM_CATEGORY_LESSER + ) ) ) ) @@ -2031,11 +2036,13 @@ void RandomizerOnActorInitHandler(void* actorRef) { break; } - //Deletes all actors in the boss category if the soul isn't found. - //Some actors, like Dark Link, Arwings, and Zora's Sapphire...?, are in this category despite not being actual bosses, - //so ignore any "boss" if `currentBossSoulRandInf` doesn't change from RAND_INF_MAX. + // Deletes all actors in the boss category if the soul isn't found. + // Some actors, like Dark Link, Arwings, and Zora's Sapphire...?, are in this category despite not being actual bosses, + // so ignore any "boss" if `currentBossSoulRandInf` doesn't change from RAND_INF_MAX. + // Iron Knuckle (Nabooru) in Twinrova's room is a special exception, so exclude knuckles too. if (currentBossSoulRandInf != RAND_INF_MAX) { - if (!Flags_GetRandomizerInf(currentBossSoulRandInf) && actor->category == ACTORCAT_BOSS) { + if (!Flags_GetRandomizerInf(currentBossSoulRandInf) && actor->category == ACTORCAT_BOSS && + actor->id != ACTOR_EN_IK) { Actor_Delete(&gPlayState->actorCtx, actor, gPlayState); } //Special case for Phantom Ganon's horse (and fake), as they're considered "background actors", diff --git a/soh/soh/Enhancements/randomizer/item.cpp b/soh/soh/Enhancements/randomizer/item.cpp index 6f0309223..1c315b47f 100644 --- a/soh/soh/Enhancements/randomizer/item.cpp +++ b/soh/soh/Enhancements/randomizer/item.cpp @@ -94,6 +94,7 @@ std::shared_ptr Item::GetGIEntry() const { // NOLINT(*-no-recursio actual = RG_DEKU_STICK_BAG; break; } + [[fallthrough]]; case 1: if (infiniteUpgrades == RO_INF_UPGRADES_CONDENSED_PROGRESSIVE) { actual = RG_STICK_UPGRADE_INF; @@ -123,6 +124,7 @@ std::shared_ptr Item::GetGIEntry() const { // NOLINT(*-no-recursio actual = RG_DEKU_NUT_BAG; break; } + [[fallthrough]]; case 1: if (infiniteUpgrades == RO_INF_UPGRADES_CONDENSED_PROGRESSIVE) { actual = RG_NUT_UPGRADE_INF; diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index 0b94aab39..45516ef18 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -98,15 +98,25 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_PRELUDE_OF_LIGHT] = Item(RG_PRELUDE_OF_LIGHT, Text{ "Prelude of Light", "Prélude de la Lumière", "Kantate des Lichts" }, ITEMTYPE_SONG, 0xC0, true, LOGIC_PRELUDE_OF_LIGHT, RHT_PRELUDE_OF_LIGHT, ITEM_SONG_PRELUDE, OBJECT_GI_MELODY, GID_SONG_PRELUDE, 0x78, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE); // Maps and Compasses itemTable[RG_DEKU_TREE_MAP] = Item(RG_DEKU_TREE_MAP, Text{ "Great Deku Tree Map", "Carte de l'Arbre Mojo", "Karte des Deku-Baums" }, ITEMTYPE_MAP, 0xA5, false, LOGIC_MAP_DEKU_TREE, RHT_DEKU_TREE_MAP, RG_DEKU_TREE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_DEKU_TREE_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_DODONGOS_CAVERN_MAP] = Item(RG_DODONGOS_CAVERN_MAP, Text{ "Dodongo's Cavern Map", "Carte de la Caverne Dodongo", "Karte der Dodongo-Höhle" }, ITEMTYPE_MAP, 0xA6, false, LOGIC_MAP_DODONGOS_CAVERN, RHT_DODONGOS_CAVERN_MAP, RG_DODONGOS_CAVERN_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_DODONGOS_CAVERN_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_JABU_JABUS_BELLY_MAP] = Item(RG_JABU_JABUS_BELLY_MAP, Text{ "Jabu-Jabu's Belly Map", "Carte du Ventre de Jabu-Jabu", "Karte des Jabu-Jabu-Bauchs" }, ITEMTYPE_MAP, 0xA7, false, LOGIC_MAP_JABU_JABUS_BELLY, RHT_JABU_JABUS_BELLY_MAP, RG_JABU_JABUS_BELLY_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_JABU_JABUS_BELLY_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_FOREST_TEMPLE_MAP] = Item(RG_FOREST_TEMPLE_MAP, Text{ "Forest Temple Map", "Carte du Temple de la Forêt", "Karte des Waldtempels" }, ITEMTYPE_MAP, 0xA8, false, LOGIC_MAP_FOREST_TEMPLE, RHT_FOREST_TEMPLE_MAP, RG_FOREST_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_FOREST_TEMPLE_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_FIRE_TEMPLE_MAP] = Item(RG_FIRE_TEMPLE_MAP, Text{ "Fire Temple Map", "Carte due Temple de Feu", "Karte des Feuertempels" }, ITEMTYPE_MAP, 0xA9, false, LOGIC_MAP_FIRE_TEMPLE, RHT_FIRE_TEMPLE_MAP, RG_FIRE_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_FIRE_TEMPLE_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_WATER_TEMPLE_MAP] = Item(RG_WATER_TEMPLE_MAP, Text{ "Water Temple Map", "Carte du Temple de l'Eau", "Karte des Wassertempels" }, ITEMTYPE_MAP, 0xAA, false, LOGIC_MAP_WATER_TEMPLE, RHT_WATER_TEMPLE_MAP, RG_WATER_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_WATER_TEMPLE_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_SPIRIT_TEMPLE_MAP] = Item(RG_SPIRIT_TEMPLE_MAP, Text{ "Spirit Temple Map", "Carte due Temple de l'Esprit", "Karte des Geistertempels" }, ITEMTYPE_MAP, 0xAB, false, LOGIC_MAP_SPIRIT_TEMPLE, RHT_SPIRIT_TEMPLE_MAP, RG_SPIRIT_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_SPIRIT_TEMPLE_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_SHADOW_TEMPLE_MAP] = Item(RG_SHADOW_TEMPLE_MAP, Text{ "Shadow Temple Map", "Carte du Temple de l'Ombre", "Karte des Schattentempels" }, ITEMTYPE_MAP, 0xAC, false, LOGIC_MAP_SHADOW_TEMPLE, RHT_SHADOW_TEMPLE_MAP, RG_SHADOW_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_SHADOW_TEMPLE_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_BOTTOM_OF_THE_WELL_MAP] = Item(RG_BOTTOM_OF_THE_WELL_MAP, Text{ "Bottom of the Well Map", "Carte du Puits", "Karte des Grund des Brunnens" }, ITEMTYPE_MAP, 0xAD, false, LOGIC_MAP_BOTTOM_OF_THE_WELL, RHT_BOTTOM_OF_THE_WELL_MAP, RG_BOTTOM_OF_THE_WELL_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_BOTTOM_OF_THE_WELL_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_ICE_CAVERN_MAP] = Item(RG_ICE_CAVERN_MAP, Text{ "Ice Cavern Map", "Carte de la Caverne Polaire", "Karte der Eishöhle" }, ITEMTYPE_MAP, 0xAE, false, LOGIC_MAP_ICE_CAVERN, RHT_ICE_CAVERN_MAP, RG_ICE_CAVERN_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); + itemTable[RG_ICE_CAVERN_MAP].SetCustomDrawFunc(Randomizer_DrawMap); itemTable[RG_DEKU_TREE_COMPASS] = Item(RG_DEKU_TREE_COMPASS, Text{ "Great Deku Tree Compass", "Boussole de l'Arbre Mojo", "Kompaß des Deku-Baums" }, ITEMTYPE_COMPASS, 0x9B, false, LOGIC_COMPASS_DEKU_TREE, RHT_DEKU_TREE_COMPASS, RG_DEKU_TREE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); itemTable[RG_DEKU_TREE_COMPASS].SetCustomDrawFunc(Randomizer_DrawCompass); itemTable[RG_DODONGOS_CAVERN_COMPASS] = Item(RG_DODONGOS_CAVERN_COMPASS, Text{ "Dodongo's Cavern Compass", "Boussole de la Caverne Dodongo", "Kompaß der Dodongo-Höhle" }, ITEMTYPE_COMPASS, 0x9C, false, LOGIC_COMPASS_DODONGOS_CAVERN, RHT_DODONGOS_CAVERN_COMPASS, RG_DODONGOS_CAVERN_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); @@ -339,7 +349,7 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_BRONZE_SCALE] = Item(RG_BRONZE_SCALE, Text{ "Bronze Scale", "Écaille de Bronze", "Bronzene Schuppe" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, LOGIC_PROGRESSIVE_WALLET, RHT_BRONZE_SCALE, RG_BRONZE_SCALE, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_BRONZE_SCALE].SetCustomDrawFunc(Randomizer_DrawBronzeScale); - itemTable[RG_BOMBCHU_BAG] = Item(RG_BOMBCHU_BAG, Text{ "Bombchu Bag", "!!!", "!!!" }, ITEMTYPE_ITEM, RG_BOMBCHU_BAG, true, LOGIC_BOMBCHUS, RHT_BOMBCHU_BAG, RG_BOMBCHU_BAG, OBJECT_GI_BOMB_2, GID_BOMBCHU, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_BOMBCHU_BAG] = Item(RG_BOMBCHU_BAG, Text{ "Bombchu Bag", "!!!", "Sac de Missiles Teigneux" }, ITEMTYPE_ITEM, RG_BOMBCHU_BAG, true, LOGIC_BOMBCHUS, RHT_BOMBCHU_BAG, RG_BOMBCHU_BAG, OBJECT_GI_BOMB_2, GID_BOMBCHU, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_BOMBCHU_BAG].SetCustomDrawFunc(Randomizer_DrawBombchuBag); itemTable[RG_QUIVER_INF] = Item(RG_QUIVER_INF, Text{ "Infinite Quiver", "Carquois Infini", "Unendlicher Köcher" }, ITEMTYPE_ITEM, RG_QUIVER_INF, true, LOGIC_PROGRESSIVE_BOW, RHT_QUIVER_INF, RG_QUIVER_INF, OBJECT_GI_ARROWCASE, GID_QUIVER_50, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/deku_tree.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/deku_tree.cpp index 2500e4996..4740a7541 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/deku_tree.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/deku_tree.cpp @@ -71,8 +71,8 @@ void RegionTable_Init_DekuTree() { }, { //Locations LOCATION(RC_DEKU_TREE_BASEMENT_CHEST, true), - LOCATION(RC_DEKU_TREE_GS_BASEMENT_GATE, logic->CanJumpslashExceptHammer() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE)), - LOCATION(RC_DEKU_TREE_GS_BASEMENT_VINES, logic->CanUseProjectile() || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS) && logic->CanJumpslashExceptHammer())), + LOCATION(RC_DEKU_TREE_GS_BASEMENT_GATE, logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH)), + LOCATION(RC_DEKU_TREE_GS_BASEMENT_VINES, logic->CanKillEnemy(RE_GOLD_SKULLTULA, ctx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS) ? ED_SHORT_JUMPSLASH : ED_BOMB_THROW)), }, { //Exits Entrance(RR_DEKU_TREE_LOBBY, []{return true;}), @@ -84,7 +84,7 @@ void RegionTable_Init_DekuTree() { areaTable[RR_DEKU_TREE_BASEMENT_SCRUB_ROOM] = Region("Deku Tree Basement Scrub Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits Entrance(RR_DEKU_TREE_BASEMENT_LOWER, []{return true;}), - Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, []{return Here(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW);});}), + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, []{return Here(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return logic->CanHitEyeTargets();});}), }); areaTable[RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT] = Region("Deku Tree Basement Water Room Front", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp index bb5e1754f..4ae2e1e70 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp @@ -154,6 +154,7 @@ void RegionTable_Init_DodongosCavern() { LOCATION(RC_DODONGOS_CAVERN_BLADE_ROOM_HEART, true), }, { //Exits + Entrance(RR_DODONGOS_CAVERN_ARMOS_ROOM, []{return true;}), Entrance(RR_DODONGOS_CAVERN_2F_SIDE_ROOM, []{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return logic->CanBreakMudWalls() || (ctx->GetTrickOption(RT_DC_SCRUB_ROOM) && logic->HasItem(RG_GORONS_BRACELET));});}), Entrance(RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, []{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);});}), Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, []{return (logic->IsAdult && ctx->GetTrickOption(RT_DC_JUMP)) || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}), @@ -304,6 +305,7 @@ void RegionTable_Init_DodongosCavern() { LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_4, logic->CanBreakPots()), }, { //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return true;}), //This is possible with sticks and shield, igniting a first flower by "touch" then very quickly crouch stabbing in a way that cuts the corner to light the 3rd bomb on the other side, but that's a trick Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, []{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->HasExplosives() || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));});}), Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_MUD_WALL, []{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->CanBreakMudWalls();});}), @@ -460,9 +462,9 @@ void RegionTable_Init_DodongosCavern() { LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_4, logic->CanBreakPots()), }, { //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, []{return Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}), - Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, []{return true;}), - Entrance(RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM, []{return Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}), + Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}), + Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM, []{return Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}), }); areaTable[RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM] = Region("Dodongos Cavern Mad Scrub Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/forest_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/forest_temple.cpp index c9f4ebc23..04efd4994 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/forest_temple.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/forest_temple.cpp @@ -28,7 +28,7 @@ void RegionTable_Init_ForestTemple() { areaTable[RR_FOREST_TEMPLE_SOUTH_CORRIDOR] = Region("Forest Temple South Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits Entrance(RR_FOREST_TEMPLE_FIRST_ROOM, []{return true;}), - Entrance(RR_FOREST_TEMPLE_LOBBY, []{return logic->CanAttack() || logic->CanUse(RG_NUTS);}), + Entrance(RR_FOREST_TEMPLE_LOBBY, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}), }); areaTable[RR_FOREST_TEMPLE_LOBBY] = Region("Forest Temple Lobby", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp index 982ac16fc..c1a846564 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp @@ -61,7 +61,7 @@ void RegionTable_Init_GanonsCastle() { EventAccess(&logic->ForestTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS) && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE));}), }, { //Locations - LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_CHEST, logic->CanDamage()), + LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_CHEST, logic->CanKillEnemy(RE_WOLFOS)), LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_POT_1, logic->CanBreakPots() && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE))), LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_POT_2, logic->CanBreakPots() && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE))), }, {}); @@ -78,7 +78,7 @@ void RegionTable_Init_GanonsCastle() { areaTable[RR_GANONS_CASTLE_WATER_TRIAL] = Region("Ganon's Castle Water Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { //Events - EventAccess(&logic->BlueFireAccess, []{return logic->BlueFireAccess || logic->HasBottle();}), + EventAccess(&logic->BlueFireAccess, []{return true;}), EventAccess(&logic->FairyPot, []{return logic->FairyPot || (logic->BlueFire() && logic->CanKillEnemy(RE_FREEZARD));}), EventAccess(&logic->WaterTrialClear, []{return logic->BlueFire() && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_LIGHT_ARROWS);}), }, { @@ -112,7 +112,7 @@ void RegionTable_Init_GanonsCastle() { EventAccess(&logic->SpiritTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS) && (logic->CanUse(RG_MIRROR_SHIELD) || ctx->GetOption(RSK_SUNLIGHT_ARROWS)) && logic->CanUse(RG_BOMBCHU_5) && ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT));}), }, { //Locations - LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, (ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || logic->CanUse(RG_HOOKSHOT)) && logic->CanJumpslashExceptHammer()), + LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, (ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || logic->CanUse(RG_HOOKSHOT)) && (logic->CanJumpslashExceptHammer() || logic->CanUse(RG_BOMBCHU_5))), LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))), LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_POT_1, ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)))), LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_POT_2, ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)))), diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp index f0b9de5c3..0c45d755c 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp @@ -17,8 +17,8 @@ void RegionTable_Init_GerudoTrainingGround() { areaTable[RR_GERUDO_TRAINING_GROUND_LOBBY] = Region("Gerudo Training Ground Lobby", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)), - LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST, logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)), + LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, logic->CanHitEyeTargets()), + LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST, logic->CanHitEyeTargets()), LOCATION(RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true)), LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST, logic->CanKillEnemy(RE_BEAMOS) && logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true)), LOCATION(RC_GERUDO_TRAINING_GROUND_ENTRANCE_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp index ff9b171c8..879ac1dce 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp @@ -21,18 +21,18 @@ void RegionTable_Init_IceCavern() { }, { //Exits Entrance(RR_ICE_CAVERN_ENTRYWAY, []{return true;}), - Entrance(RR_ICE_CAVERN_MAIN, []{return Here(RR_ICE_CAVERN_BEGINNING, []{return (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives() || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE);});}), + Entrance(RR_ICE_CAVERN_MAIN, []{return Here(RR_ICE_CAVERN_BEGINNING, []{return logic->CanKillEnemy(RE_FREEZARD, ED_CLOSE, true, 4);});}), }); areaTable[RR_ICE_CAVERN_MAIN] = Region("Ice Cavern", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { //Events - EventAccess(&logic->BlueFireAccess, []{return logic->BlueFireAccess || (logic->IsAdult && logic->HasBottle());}), + EventAccess(&logic->BlueFireAccess, []{return logic->IsAdult;}), }, { //Locations LOCATION(RC_ICE_CAVERN_MAP_CHEST, logic->BlueFire() && logic->IsAdult), LOCATION(RC_ICE_CAVERN_COMPASS_CHEST, logic->BlueFire()), - LOCATION(RC_ICE_CAVERN_IRON_BOOTS_CHEST, logic->BlueFire() && (logic->CanJumpslash() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE))), - LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->BlueFire() && (logic->CanJumpslash() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE)) && logic->IsAdult), + LOCATION(RC_ICE_CAVERN_IRON_BOOTS_CHEST, logic->BlueFire() && logic->CanKillEnemy(RE_WOLFOS)), + LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->BlueFire() && logic->CanKillEnemy(RE_WOLFOS) && logic->IsAdult), LOCATION(RC_ICE_CAVERN_FREESTANDING_POH, logic->BlueFire()), LOCATION(RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, logic->HookshotOrBoomerang()), LOCATION(RC_ICE_CAVERN_GS_HEART_PIECE_ROOM, logic->BlueFire() && logic->HookshotOrBoomerang()), @@ -125,8 +125,8 @@ void RegionTable_Init_IceCavern() { LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->CanKillEnemy(RE_STALFOS)), }, { //Exits - Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, []{return logic->BlueFire() && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}), - Entrance(RR_ICE_CAVERN_MQ_BEGINNING, []{return logic->CanUse(RG_IRON_BOOTS) && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}), + Entrance(RR_ICE_CAVERN_MQ_WEST_CORRIDOR, []{return Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}), + Entrance(RR_ICE_CAVERN_MQ_BEGINNING, []{return logic->CanUse(RG_IRON_BOOTS) && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}), }); areaTable[RR_ICE_CAVERN_MQ_COMPASS_ROOM] = Region("Ice Cavern MQ Compass Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp index fa9c7b085..7bfb98a87 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp @@ -24,7 +24,6 @@ void RegionTable_Init_JabuJabusBelly() { //Combines Lift room middle and lower, 1F holes room, the forked corridor, and it's side rooms areaTable[RR_JABU_JABUS_BELLY_MAIN] = Region("Jabu Jabus Belly Main", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { //Events - EventAccess(&logic->JabuRutoInB1, []{return true;}), EventAccess(&logic->JabuWestTentacle, []{return logic->JabuRutoIn1F && logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}), }, { //Locations @@ -263,7 +262,7 @@ void RegionTable_Init_JabuJabusBelly() { areaTable[RR_JABU_JABUS_BELLY_MQ_WEST_FORKED_ROOMS] = Region("Jabu Jabus Belly MQ West Forked Rooms", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { //Events - EventAccess(&logic->JabuWestTentacle, []{return logic->CanUse(RG_BOOMERANG);}), + EventAccess(&logic->JabuWestTentacle, []{return logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}), }, { //Locations LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, Here(RR_JABU_JABUS_BELLY_MQ_WEST_FORKED_ROOMS, []{return logic->HasExplosives();}) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp index bdcf8a4fa..8cf70fc3f 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp @@ -79,8 +79,8 @@ void RegionTable_Init_ShadowTemple() { areaTable[RR_SHADOW_TEMPLE_WIND_TUNNEL] = Region("Shadow Temple Wind Tunnel", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations LOCATION(RC_SHADOW_TEMPLE_WIND_HINT_CHEST, true), - LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, true), + LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, logic->CanKillEnemy(RE_GIBDO, ED_CLOSE, true, 2)), + LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, logic->HasExplosives()), LOCATION(RC_SHADOW_TEMPLE_GS_NEAR_SHIP, logic->CanUse(RG_LONGSHOT) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5)), LOCATION(RC_SHADOW_TEMPLE_WIND_HINT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_POT_1, logic->CanBreakPots()), @@ -96,7 +96,7 @@ void RegionTable_Init_ShadowTemple() { //Locations LOCATION(RC_SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, logic->CanUse(RG_DINS_FIRE)), LOCATION(RC_SHADOW_TEMPLE_BOSS_KEY_CHEST, logic->CanUse(RG_DINS_FIRE)), - LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, logic->CanKillEnemy(RE_FLOORMASTER)), //RANDOTODO check if child can reach the token LOCATION(RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, logic->IsAdult && logic->CanAttack()), LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_1, logic->CanBreakPots()), @@ -181,7 +181,7 @@ void RegionTable_Init_ShadowTemple() { //Room exists for if it's ever possible to go backwards or void warp into the middle of shadow areaTable[RR_SHADOW_TEMPLE_MQ_B2_TO_B3_CORRIDOR] = Region("Shadow Temple MQ B2 to B3 Corridor", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, []{return logic->HasExplosives() && logic->SmallKeys(RR_SHADOW_TEMPLE, 2);}), + Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, []{return logic->SmallKeys(RR_SHADOW_TEMPLE, 2);}), Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, []{return true;}), //bunnyhovers + lens lets you go from the very top of upper pit to the stationary invisible platform below quite easily }); diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp index 87a2e3b48..28d272711 100644 --- a/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp @@ -50,7 +50,7 @@ void RegionTable_Init_Graveyard() { LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_8, true), }, { //Exits - Entrance(RR_THE_GRAVEYARD, []{return true;}), + Entrance(RR_GRAVEYARD_SHIELD_GRAVE, []{return true;}), }); areaTable[RR_GRAVEYARD_HEART_PIECE_GRAVE] = Region("Graveyard Heart Piece Grave", "Graveyard Heart Piece Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp index d828bad47..116b7d709 100644 --- a/soh/soh/Enhancements/randomizer/location_list.cpp +++ b/soh/soh/Enhancements/randomizer/location_list.cpp @@ -992,7 +992,7 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_HF_OPEN_GROTTO_GOSSIP_STONE] = Location::HintStone(RC_HF_OPEN_GROTTO_GOSSIP_STONE, RCQUEST_BOTH, RCAREA_HYRULE_FIELD, SCENE_GROTTOS, -22947, "Open Grotto Gossip Stone"); locationTable[RC_KAK_OPEN_GROTTO_GOSSIP_STONE] = Location::HintStone(RC_KAK_OPEN_GROTTO_GOSSIP_STONE, RCQUEST_BOTH, RCAREA_KAKARIKO_VILLAGE, SCENE_GROTTOS, -22984, "Open Grotto Gossip Stone"); locationTable[RC_ZR_OPEN_GROTTO_GOSSIP_STONE] = Location::HintStone(RC_ZR_OPEN_GROTTO_GOSSIP_STONE, RCQUEST_BOTH, RCAREA_ZORAS_RIVER, SCENE_GROTTOS, -22985, "Open Grotto Gossip Stone"); - locationTable[RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE] = Location::HintStone(RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, RCQUEST_BOTH, RCAREA_LOST_WOODS, SCENE_GROTTOS, -22964, "Near Shortcuts Gossip Stone"); + locationTable[RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE] = Location::HintStone(RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, RCQUEST_BOTH, RCAREA_LOST_WOODS, SCENE_GROTTOS, -22964, "Near Shortcuts Grotto Gossip Stone"); locationTable[RC_DMT_STORMS_GROTTO_GOSSIP_STONE] = Location::HintStone(RC_DMT_STORMS_GROTTO_GOSSIP_STONE, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_TRAIL, SCENE_GROTTOS, -23255, "Storms Grotto Gossip Stone"); locationTable[RC_DMC_UPPER_GROTTO_GOSSIP_STONE] = Location::HintStone(RC_DMC_UPPER_GROTTO_GOSSIP_STONE, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_CRATER, SCENE_GROTTOS, -23802, "Upper Grotto Gossip Stone"); diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 64af9bbef..d1c46d740 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -677,7 +677,7 @@ namespace Rando { } return killed; case RE_BIG_OCTO: - //If chasing octo is annoying but with rolls you can catch him, and you need rang to get into this room without shenanigains anyway. Bunny makes it free + //If chasing octo is annoying but with rolls you can catch him, and you need rang to get into this room without shenanigans anyway. Bunny makes it free return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_STICKS) || CanUse(RG_MASTER_SWORD); case RE_GOHMA: return HasBossSoul(RG_GOHMA_SOUL) && CanJumpslash() && @@ -1793,7 +1793,7 @@ namespace Rando { case ITEMTYPE_EQUIP: { RandomizerGet itemRG = item.GetRandomizerGet(); - if (itemRG == RG_GIANTS_KNIFE) { + if (itemRG == RG_GIANTS_KNIFE || itemRG == RG_DEKU_SHIELD || itemRG == RG_HYLIAN_SHIELD) { return; } uint32_t equipId = RandoGetToEquipFlag.find(itemRG)->second; @@ -2442,7 +2442,6 @@ namespace Rando { MQSpiritMapRoomEnemies = false; MQSpirit3SunsEnemies = false; Spirit1FSilverRupees = false; - JabuRutoInB1 = false; JabuRutoIn1F = false; StopPerformanceTimer(PT_LOGIC_RESET); diff --git a/soh/soh/Enhancements/randomizer/logic.h b/soh/soh/Enhancements/randomizer/logic.h index 4286cc5c3..d8fa9864b 100644 --- a/soh/soh/Enhancements/randomizer/logic.h +++ b/soh/soh/Enhancements/randomizer/logic.h @@ -175,7 +175,6 @@ class Logic { bool MQSpiritTimeTravelChest = false; bool MQSpirit3SunsEnemies = false; bool Spirit1FSilverRupees = false; - bool JabuRutoInB1 = false; bool JabuRutoIn1F = false; /* --- END OF HELPERS AND LOCATION ACCESS --- */ diff --git a/soh/soh/Enhancements/randomizer/option.cpp b/soh/soh/Enhancements/randomizer/option.cpp index 2c478e34c..64ca107c5 100644 --- a/soh/soh/Enhancements/randomizer/option.cpp +++ b/soh/soh/Enhancements/randomizer/option.cpp @@ -232,7 +232,7 @@ bool Option::RenderCombobox() { } UIWidgets::ComboboxOptions widgetOptions = UIWidgets::ComboboxOptions().Color(THEME_COLOR).Tooltip(description.c_str()); if (this->GetKey() == RSK_LOGIC_RULES) { - widgetOptions = widgetOptions.LabelPosition(UIWidgets::LabelPosition::None).ComponentAlignment(UIWidgets::ComponentAlignment::Right); + widgetOptions = widgetOptions.LabelPosition(UIWidgets::LabelPositions::None).ComponentAlignment(UIWidgets::ComponentAlignments::Right); } widgetOptions.disabled = disabled; if(UIWidgets::Combobox(name.c_str(), &selected, options, widgetOptions)) { diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 85ddc6c50..244afb9c4 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1807,7 +1807,6 @@ PotIdentity Randomizer::IdentifyPot(s32 sceneNum, s32 posX, s32 posZ) { if (location->GetRandomizerCheck() == RC_UNKNOWN_CHECK) { LUSLOG_WARN("IdentifyPot did not receive a valid RC value (%d).", location->GetRandomizerCheck()); - assert(false); } else { potIdentity.randomizerInf = rcToRandomizerInf[location->GetRandomizerCheck()]; potIdentity.randomizerCheck = location->GetRandomizerCheck(); @@ -2749,10 +2748,10 @@ CustomMessage Randomizer::GetMapGetItemMessageWithHint(GetItemEntry itemEntry) { } template -void CreateGetItemMessages(const std::array* messageEntries) { +void CreateGetItemMessages(const std::array& messageEntries) { CustomMessageManager* customMessageManager = CustomMessageManager::Instance; customMessageManager->AddCustomMessageTable(Randomizer::getItemMessageTableID); - for (const GetItemMessage& messageEntry : *messageEntries) { + for (const GetItemMessage& messageEntry : messageEntries) { customMessageManager->CreateGetItemMessage( Randomizer::getItemMessageTableID, messageEntry.giid, messageEntry.iid, CustomMessage(messageEntry.english, messageEntry.german, messageEntry.french, TEXTBOX_TYPE_BLUE, @@ -3469,251 +3468,247 @@ void Randomizer::CreateCustomMessages() { GIMESSAGE(RG_GUARD_HOUSE_KEY, ITEM_KEY_SMALL, "You found the key to the&%gGuard House%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gHaus der Wachen%w!", - "Vous obtenez une %rPetite Clé %w&de la %gMaison des Gardes%w!"), + "Vous obtenez la %rClé %wde la&%gMaison des Gardes%w!"), GIMESSAGE(RG_MARKET_BAZAAR_KEY, ITEM_KEY_SMALL, "You found the key to the&%gMarket Bazaar%w!", "Du erhältst einen %rkleinen&Schlüssel%w für den %gBasar des Marktes%w!", - "Vous obtenez une %rPetite Clé %w&du %gMarché%w!"), + "Vous obtenez la %rClé %wdu %gBazar&de la Place du Marché%w!"), GIMESSAGE(RG_MARKET_POTION_SHOP_KEY, ITEM_KEY_SMALL, "You found the key to the&%gMarket Potion Shop%w!", "Du erhältst einen %rkleinen&Schlüssel%w für den %gMagie-Laden des Marktes%w!", - "Vous obtenez une %rPetite Clé %w&du %gMarché%w!"), + "Vous obtenez la %rClé %wde la&%gPlace du Marché%w!"), GIMESSAGE(RG_MASK_SHOP_KEY, ITEM_KEY_SMALL, "You found the key to the&%gMask Shop%w!", "Du erhältst einen %rkleinen&Schlüssel%w für den %gMaskenladen%w!", - "Vous obtenez une %rPetite Clé %w&du %gMagasin de Masques%w!"), + "Vous obtenez la %rClé %wde la&%gFoire aux Masques%w!"), GIMESSAGE(RG_MARKET_SHOOTING_GALLERY_KEY, ITEM_KEY_SMALL, "You found the key to the&%gMarket Shooting Gallery%w!", "Du erhältst einen %rkleinen&Schlüssel%w für die %gSchießbude des Marktes%w!", - "Vous obtenez une %rPetite Clé %w&du %gStand de Tir%w!"), + "Vous obtenez la %rClé %wdu %gStand de&Tir de la Place du Marché%w!"), GIMESSAGE(RG_BOMBCHU_BOWLING_KEY, ITEM_KEY_SMALL, "You found the key to the&%gBombchu Bowling Alley%w!", "Du erhältst einen %rkleinen&Schlüssel%w für die %gMinenbowlingbahn%w!", - "Vous obtenez une %rPetite Clé %w&du %gBowling Bombchu%w!"), + "Vous obtenez la %rClé %wdu %gBowling&Teigneux%w!"), GIMESSAGE(RG_TREASURE_CHEST_GAME_BUILDING_KEY, ITEM_KEY_SMALL, "You found the key to the&%gTreasure Chest Game Building%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gHaus des Schatzkisten-Pokers%w!", - "Vous obtenez une %rPetite Clé %w&du %gJeu de la Chasse au Trésor%w!"), + "Vous obtenez la %rClé %wdu %gJeu de la&Chasse au Trésor%w!"), GIMESSAGE(RG_BOMBCHU_SHOP_KEY, ITEM_KEY_SMALL, "You found the key to the&%gBombchu Shop%w!", "Du erhältst einen %rkleinen&Schlüssel%w für den %gKrabbelminenladen%w!", - "Vous obtenez une %rPetite Clé %w&du %gMagasin de Bombchu%w!"), + "Vous obtenez la %rClé %wdu %gMagasin&de Missiles%w!"), GIMESSAGE(RG_RICHARDS_HOUSE_KEY, ITEM_KEY_SMALL, "You found the key to&%gRichard's House%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gHaus von Richard%w!", - "Vous obtenez une %rPetite Clé %w&de la %gMaison de Richard%w!"), - GIMESSAGE(RG_RICHARDS_HOUSE_KEY, ITEM_KEY_SMALL, - "You found the key to&%gRichard's House%w!", - "Du erhältst einen %rkleinen&Schlüssel%w für das %gHaus von Richard%w!", - "Vous obtenez une %rPetite Clé %w&de la %gMaison de Richard%w!"), + "Vous obtenez la %rClé %wde la %gMaison&de Kiki%w!"), GIMESSAGE(RG_ALLEY_HOUSE_KEY, ITEM_KEY_SMALL, "You found the key to&the %gAlley House%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gHaus in der Gasse%w!", - "Vous obtenez une %rPetite Clé %w&de la %gMaison de la Ruelle%w!"), + "Vous obtenez la %rClé %wde la %gMaison&de la Ruelle%w!"), GIMESSAGE(RG_KAK_BAZAAR_KEY, ITEM_KEY_SMALL, "You found the key to the&%gKakariko Bazaar%w!", "Du erhältst einen %rkleinen&Schlüssel%w für den %gBasar von Kakariko%w!", - "Vous obtenez une %rPetite Clé %w&du %gMarché de Cocorico%w!"), + "Vous obtenez la %rClé %wdu %gBazar&de Cocorico%w!"), GIMESSAGE(RG_KAK_POTION_SHOP_KEY, ITEM_KEY_SMALL, "You found the key to the&%gKakariko Potion Shop%w!", "Du erhältst einen %rkleinen&Schlüssel%w für den %gMagie-Laden von Kakariko%w!", - "Vous obtenez une %rPetite Clé %w&du %gMagasin de Potions de Cocorico%w!"), + "Vous obtenez la %rClé %wdu %gMagasin de&Potions de Cocorico%w!"), GIMESSAGE(RG_BOSS_HOUSE_KEY, ITEM_KEY_SMALL, "You found the key to the&%gBoss's House%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gHaus des Chefs%w!", - "Vous obtenez une %rPetite Clé %w&de la %gMaison du Boss%w!"), + "Vous obtenez la %rClé %wde la %gMaison&du chef des ouvriers%w!"), GIMESSAGE(RG_GRANNYS_POTION_SHOP_KEY, ITEM_KEY_SMALL, "You found the key to&%gGranny's Potion Shop%w!", "Du erhältst einen %rkleinen&Schlüssel%w für %gAsas Hexenladen%w!", - "Vous obtenez une %rPetite Clé %w&du %gMagasin de Potions de Grand-mère%w!"), + "Vous obtenez la %rClé %wde&l'%gApothicaire%w!"), GIMESSAGE(RG_SKULLTULA_HOUSE_KEY, ITEM_KEY_SMALL, "You found the key to the&%gSkulltula House%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gSkulltula-Haus%w!", - "Vous obtenez une %rPetite Clé %w&de la %gMaison des Skulltulas%w!"), + "Vous obtenez la %rClé %wde la %gMaison&des Araignées%w!"), GIMESSAGE(RG_IMPAS_HOUSE_KEY, ITEM_KEY_SMALL, "You found the key to&%gImpa's House%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gHaus von Impa%w!", - "Vous obtenez une %rPetite Clé %w&de la %gMaison d'Impa%w!"), + "Vous obtenez la %rClé %wde la %gMaison&d'Impa%w!"), GIMESSAGE(RG_WINDMILL_KEY, ITEM_KEY_SMALL, "You found the key to the&%gWindmill%w!", "Du erhältst einen %rkleinen&Schlüssel%w für die %gWindmühle%w!", - "Vous obtenez une %rPetite Clé %w&du %gMoulin à Vent%w!"), + "Vous obtenez la %rClé %w du %gMoulin%w!"), GIMESSAGE(RG_KAK_SHOOTING_GALLERY_KEY, ITEM_KEY_SMALL, "You found the key to the&%gKakariko Shooting Gallery%w!", "Du erhältst einen %rkleinen&Schlüssel%w für die %gSchießbude von Kakariko%w!", - "Vous obtenez une %rPetite Clé %w&du %gStand de Tir de Cocorico%w!"), + "Vous obtenez la %rClé %w du %gStand de&Tir de Cocorico%w!"), GIMESSAGE(RG_DAMPES_HUT_KEY, ITEM_KEY_SMALL, "You found the key to&%gDampe's Hut%w!", "Du erhältst einen %rkleinen&Schlüssel%w für die %gHütte von Boris%w!", - "Vous obtenez une %rPetite Clé %w&du %gChalet de Dampe%w!"), + "Vous obtenez la %rClé %wde la %gCabane&d'Igor%w!"), GIMESSAGE(RG_TALONS_HOUSE_KEY, ITEM_KEY_SMALL, "You found the key to&%gTalon's House%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gHaus von Talon%w!", - "Vous obtenez une %rPetite Clé %w&de la %gMaison de Talon%w!"), + "Vous obtenez la %rClé %wde la %gMaison&de Talon%w!"), GIMESSAGE(RG_STABLES_KEY, ITEM_KEY_SMALL, "You found the key to the&%gStables%w!", "Du erhältst einen %rkleinen&Schlüssel%w für die %gStälle%w!", - "Vous obtenez une %rPetite Clé %w&des %gÉcuries%w!"), + "Vous obtenez la %rClé %wdes %gÉcuries%w!"), GIMESSAGE(RG_BACK_TOWER_KEY, ITEM_KEY_SMALL, "You found the key to the&%gBack Tower%w!", "Du erhältst einen %rkleinen&Schlüssel%w für den %ghinteren Turm%w!", - "Vous obtenez une %rPetite Clé %w&du %gTour Arrière%w!"), + "Vous obtenez la %rClé %wdu %gSilo%w!"), GIMESSAGE(RG_HYLIA_LAB_KEY, ITEM_KEY_SMALL, "You found the key to the&%gHylia Laboratory%w!", "Du erhältst einen %rkleinen&Schlüssel%w für das %gHylia-Labor%w!", - "Vous obtenez une %rPetite Clé %w&du %gLaboratoire d'Hylia%w!"), + "Vous obtenez la %rClé %wdu %gLaboratoire&du Lac Hylia%w!"), GIMESSAGE(RG_FISHING_HOLE_KEY, ITEM_KEY_SMALL, - "You found the key to the&%gFishing Hole%w!", + "You found the key to the&%gPond%w!", "Du erhältst einen %rkleinen&Schlüssel%w für den %gFischweiher%w!", - "Vous obtenez une %rPetite Clé %w&du %gTrou de Pêche%w!"), + "Vous obtenez la %rClé %wde l'%gÉtang%w!"), GIMESSAGE(RG_GERUDO_FORTRESS_KEY_RING, ITEM_KEY_SMALL, - "You found a %yThieves Hideout &%wKeyring!", + "You found a %yThieves Hideout&%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für das %yDiebesversteck%w!", - "Vous obtenez un trousseau de&clés du %yRepaire des Voleurs%w!"), + "Vous obtenez le trousseau de&clés du %yRepaire des Voleurs%w!"), GIMESSAGE(RG_FOREST_TEMPLE_KEY_RING, ITEM_KEY_SMALL, - "You found a %gForest Temple &%wKeyring!", + "You found a %gForest Temple&%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für den %gWaldtempel%w!", - "Vous obtenez un trousseau de&clés du %gTemple de la Forêt%w!"), + "Vous obtenez le trousseau de&clés du %gTemple de la Forêt%w!"), GIMESSAGE(RG_FIRE_TEMPLE_KEY_RING, ITEM_KEY_SMALL, - "You found a %rFire Temple &%wKeyring!", + "You found a %rFire Temple&%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für den %rFeuertempel%w!", - "Vous obtenez un trousseau de&clés du %rTemple du Feu%w!"), + "Vous obtenez le trousseau de&clés du %rTemple du Feu%w!"), GIMESSAGE(RG_WATER_TEMPLE_KEY_RING, ITEM_KEY_SMALL, - "You found a %bWater Temple &%wKeyring!", + "You found a %bWater Temple&%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für den %bWassertempel%w!", - "Vous obtenez un trousseau de&clés du %bTemple de l'Eau%w!"), + "Vous obtenez le trousseau de&clés du %bTemple de l'Eau%w!"), GIMESSAGE(RG_SPIRIT_TEMPLE_KEY_RING, ITEM_KEY_SMALL, - "You found a %ySpirit Temple &%wKeyring!", + "You found a %ySpirit Temple&%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für den %yGeistertempel%w!", - "Vous obtenez un trousseau de&clés du %yTemple de l'Esprit%w!"), + "Vous obtenez le trousseau de&clés du %yTemple de l'Esprit%w!"), GIMESSAGE(RG_SHADOW_TEMPLE_KEY_RING, ITEM_KEY_SMALL, - "You found a %pShadow Temple &%wKeyring!", + "You found a %pShadow Temple&%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für den %pSchattentempel%w!", - "Vous obtenez un trousseau de&clés du %pTemple de l'Ombre%w!"), + "Vous obtenez le trousseau de&clés du %pTemple de l'Ombre%w!"), GIMESSAGE(RG_BOTTOM_OF_THE_WELL_KEY_RING, ITEM_KEY_SMALL, - "You found a %pBottom of the &Well %wKeyring!", + "You found a %pBottom of the&Well %wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für den %pGrund des Brunnens%w!", - "Vous obtenez un trousseau de&clés du %pPuits%w!"), + "Vous obtenez le trousseau de&clés du %pPuits%w!"), GIMESSAGE(RG_GERUDO_TRAINING_GROUND_KEY_RING, ITEM_KEY_SMALL, - "You found a %yGerudo Training &Grounds %wKeyring!", + "You found a %yGerudo Training&Grounds %wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für die %yGerudo-Trainingsarena%w!", - "Vous obtenez un trousseau de&clés du %yGymnase Gerudo%w!"), + "Vous obtenez le trousseau de&clés du %yGymnase Gerudo%w!"), GIMESSAGE(RG_GANONS_CASTLE_KEY_RING, ITEM_KEY_SMALL, - "You found a %rGanon's Castle &%wKeyring!", + "You found a %rGanon's Castle&%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für %rGanons Schloß%w!", - "Vous obtenez un trousseau de&clés du %rChâteau de Ganon%w!"), + "Vous obtenez le trousseau de&clés du %rChâteau de Ganon%w!"), GIMESSAGE(RG_TREASURE_GAME_KEY_RING, ITEM_KEY_SMALL, - "You found a %rTreasure Chest Game &%wKeyring!", + "You found a %rTreasure Chest Game&%wKeyring!", "!!!", - "!!!"), + "Vous obtenez le trousseau de&clés du %rJeu de la Chasse au Trésor%w!"), GIMESSAGE(RG_FOREST_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, - "You found the %gForest Temple &%wBoss Key!", + "You found the %gForest Temple&%wBoss Key!", "Du erhältst den %rMaster-Schlüssel%w&für den %gWaldtempel%w!", "Vous obtenez la %rClé d'or %wdu&%gTemple de la Forêt%w!"), GIMESSAGE(RG_FIRE_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, - "You found the %rFire Temple &%wBoss Key!", + "You found the %rFire Temple&%wBoss Key!", "Du erhältst den %rMaster-Schlüssel%w&für den %rFeuertempel%w!", "Vous obtenez la %rClé d'or %wdu&%rTemple du Feu%w!"), GIMESSAGE(RG_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, - "You found the %bWater Temple &%wBoss Key!", + "You found the %bWater Temple&%wBoss Key!", "Du erhältst den %rMaster-Schlüssel%w&für den %bWassertempel%w!", "Vous obtenez la %rClé d'or %wdu&%bTemple de l'Eau%w!"), GIMESSAGE(RG_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, - "You found the %ySpirit Temple &%wBoss Key!", + "You found the %ySpirit Temple&%wBoss Key!", "Du erhältst den %rMaster-Schlüssel%w&für den %yGeistertempel%w!", "Vous obtenez la %rClé d'or %wdu&%yTemple de l'Esprit%w!"), GIMESSAGE(RG_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, - "You found the %pShadow Temple &%wBoss Key!", + "You found the %pShadow Temple&%wBoss Key!", "Du erhältst den %rMaster-Schlüssel%w&für den %pSchattentempel%w!", "Vous obtenez la %rClé d'or %wdu&%pTemple de l'Ombre%w!"), GIMESSAGE(RG_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, - "You found the %rGanon's Castle &%wBoss Key!", + "You found the %rGanon's Castle&%wBoss Key!", "Du erhältst den %rMaster-Schlüssel%w&für %rGanons Schloß%w!", "Vous obtenez la %rClé d'or %wdu&%rChâteau de Ganon%w!"), GIMESSAGE(RG_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, - "You found the %gDeku Tree &%wMap![[typeHint]]", + "You found the %gDeku Tree&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für den&%gDeku-Baum%w![[typeHint]]", "Vous obtenez la %rCarte %wde&l'%gArbre Mojo%w![[typeHint]]"), GIMESSAGE(RG_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, - "You found the %rDodongo's Cavern &%wMap![[typeHint]]", + "You found the %rDodongo's Cavern&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für&%rDodongos Höhle%w![[typeHint]]", "Vous obtenez la %rCarte %wde la&%rCaverne Dodongo%w![[typeHint]]"), GIMESSAGE(RG_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, - "You found the %bJabu Jabu's Belly &%wMap![[typeHint]]", + "You found the %bJabu Jabu's Belly&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für&%bJabu-Jabus Bauch%w![[typeHint]]", - "Vous obtenez la %rCarte %wdu &%bVentre de Jabu-Jabu%w![[typeHint]]"), + "Vous obtenez la %rCarte %wdu&%bVentre de Jabu-Jabu%w![[typeHint]]"), GIMESSAGE(RG_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, - "You found the %gForest Temple &%wMap![[typeHint]]", + "You found the %gForest Temple&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für den&%gWaldtempel%w![[typeHint]]", - "Vous obtenez la %rCarte %wdu &%gTemple de la Forêt%w![[typeHint]]"), + "Vous obtenez la %rCarte %wdu&%gTemple de la Forêt%w![[typeHint]]"), GIMESSAGE(RG_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, - "You found the %rFire Temple &%wMap![[typeHint]]", + "You found the %rFire Temple&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für den&%rFeuertempel%w![[typeHint]]", - "Vous obtenez la %rCarte %wdu &%rTemple du Feu%w![[typeHint]]"), + "Vous obtenez la %rCarte %wdu&%rTemple du Feu%w![[typeHint]]"), GIMESSAGE(RG_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, - "You found the %bWater Temple &%wMap![[typeHint]]", + "You found the %bWater Temple&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für den&%bWassertempel%w![[typeHint]]", - "Vous obtenez la %rCarte %wdu &%bTemple de l'Eau%w![[typeHint]]"), + "Vous obtenez la %rCarte %wdu&%bTemple de l'Eau%w![[typeHint]]"), GIMESSAGE(RG_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, - "You found the %ySpirit Temple &%wMap![[typeHint]]", + "You found the %ySpirit Temple&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für den&%yGeistertempel%w![[typeHint]]", - "Vous obtenez la %rCarte %wdu &%yTemple de l'Esprit%w![[typeHint]]"), + "Vous obtenez la %rCarte %wdu&%yTemple de l'Esprit%w![[typeHint]]"), GIMESSAGE(RG_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, - "You found the %pShadow Temple &%wMap![[typeHint]]", + "You found the %pShadow Temple&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für den&%pSchattentempel%w![[typeHint]]", - "Vous obtenez la %rCarte %wdu &%pTemple de l'Ombre%w![[typeHint]]"), + "Vous obtenez la %rCarte %wdu&%pTemple de l'Ombre%w![[typeHint]]"), GIMESSAGE(RG_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, - "You found the %pBottom of the &Well %wMap![[typeHint]]", + "You found the %pBottom of the&Well %wMap![[typeHint]]", "Du erhältst die %rKarte%w für den&%pGrund des Brunnens%w![[typeHint]]", - "Vous obtenez la %rCarte %wdu &%pPuits%w![[typeHint]]"), + "Vous obtenez la %rCarte %wdu&%pPuits%w![[typeHint]]"), GIMESSAGE(RG_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, - "You found the %cIce Cavern &%wMap![[typeHint]]", + "You found the %cIce Cavern&%wMap![[typeHint]]", "Du erhältst die %rKarte%w für die&%cEishöhle%w![[typeHint]]", - "Vous obtenez la %rCarte %wde &la %cCaverne Polaire%w![[typeHint]]"), + "Vous obtenez la %rCarte %wde&la %cCaverne Polaire%w![[typeHint]]"), GIMESSAGE(RG_DEKU_TREE_COMPASS, ITEM_COMPASS, - "You found the %gDeku Tree &%wCompass!", + "You found the %gDeku Tree&%wCompass!", "Du erhältst den %rKompaß%w für den&%gDeku-Baum%w!", "Vous obtenez la %rBoussole %wde&l'%gArbre Mojo%w!"), GIMESSAGE(RG_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, - "You found the %rDodongo's Cavern &%wCompass!", + "You found the %rDodongo's Cavern&%wCompass!", "Du erhältst den %rKompaß%w für&%rDodongos Höhle%w!", "Vous obtenez la %rBoussole %wde la&%rCaverne Dodongo%w!"), GIMESSAGE(RG_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, - "You found the %bJabu Jabu's Belly &%wCompass!", + "You found the %bJabu Jabu's Belly&%wCompass!", "Du erhältst den %rKompaß%w für den&%bJabu-Jabus Bauch%w!", - "Vous obtenez la %rBoussole %wdu &%bVentre de Jabu-Jabu%w!"), + "Vous obtenez la %rBoussole %wdu&%bVentre de Jabu-Jabu%w!"), GIMESSAGE(RG_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, - "You found the %gForest Temple &%wCompass!", + "You found the %gForest Temple&%wCompass!", "Du erhältst den %rKompaß%w für den&%gWaldtempel%w!", - "Vous obtenez la %rBoussole %wdu &%gTemple de la Forêt%w!"), + "Vous obtenez la %rBoussole %wdu&%gTemple de la Forêt%w!"), GIMESSAGE(RG_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, - "You found the %rFire Temple &%wCompass!", + "You found the %rFire Temple&%wCompass!", "Du erhältst den %rKompaß%w für den&%rFeuertempel%w!", - "Vous obtenez la %rBoussole %wdu &%rTemple du Feu%w!"), + "Vous obtenez la %rBoussole %wdu&%rTemple du Feu%w!"), GIMESSAGE(RG_WATER_TEMPLE_COMPASS, ITEM_COMPASS, - "You found the %bWater Temple &%wCompass!", + "You found the %bWater Temple&%wCompass!", "Du erhältst den %rKompaß%w für den&%bWassertempel%w!", - "Vous obtenez la %rBoussole %wdu &%bTemple de l'Eau%w!"), + "Vous obtenez la %rBoussole %wdu&%bTemple de l'Eau%w!"), GIMESSAGE(RG_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, - "You found the %ySpirit Temple &%wCompass!", + "You found the %ySpirit Temple&%wCompass!", "Du erhältst den %rKompaß%w für den&%yGeistertempel%w!", - "Vous obtenez la %rBoussole %wdu &%yTemple de l'Esprit%w!"), + "Vous obtenez la %rBoussole %wdu&%yTemple de l'Esprit%w!"), GIMESSAGE(RG_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, - "You found the %pShadow Temple &%wCompass!", + "You found the %pShadow Temple&%wCompass!", "Du erhältst den %rKompaß%w für den&%pSchattentempel%w!", - "Vous obtenez la %rBoussole %wdu &%pTemple de l'Ombre%w!"), + "Vous obtenez la %rBoussole %wdu&%pTemple de l'Ombre%w!"), GIMESSAGE(RG_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS, - "You found the %pBottom of the &Well %wCompass!", + "You found the %pBottom of the&Well %wCompass!", "Du erhältst den %rKompaß%w für den&%pGrund des Brunnens%w!", - "Vous obtenez la %rBoussole %wdu &%pPuits%w!"), + "Vous obtenez la %rBoussole %wdu&%pPuits%w!"), GIMESSAGE(RG_ICE_CAVERN_COMPASS, ITEM_COMPASS, - "You found the %cIce Cavern &%wCompass!", + "You found the %cIce Cavern&%wCompass!", "Du erhältst den %rKompaß%w für die&%cEishöhle%w!", - "Vous obtenez la %rBoussole %wde &la %cCaverne Polaire%w!"), + "Vous obtenez la %rBoussole %wde&la %cCaverne Polaire%w!"), GIMESSAGE(RG_MAGIC_BEAN_PACK, ITEM_BEAN, "You got a %rPack of Magic Beans%w!&Find a suitable spot for a garden&and plant them. Then, wait for&something fun to happen!", @@ -3739,7 +3734,7 @@ void Randomizer::CreateCustomMessages() { "Vous obtenez l'âme de %bBarinade%w!"), GIMESSAGE_NO_GERMAN(RG_PHANTOM_GANON_SOUL, ITEM_BIG_POE, "You found the soul for %gPhantom&Ganon%w!", - "Vous obtenez l'âme de %gGanon Spectral%w!"), + "Vous obtenez l'âme de %gGanon&Spectral%w!"), GIMESSAGE_NO_GERMAN(RG_VOLVAGIA_SOUL, ITEM_BIG_POE, "You found the soul for %rVolvagia%w!", "Vous obtenez l'âme de %rVulcania%w!"), @@ -3748,10 +3743,10 @@ void Randomizer::CreateCustomMessages() { "Vous obtenez l'âme de %bMorpha%w!"), GIMESSAGE_NO_GERMAN(RG_BONGO_BONGO_SOUL, ITEM_BIG_POE, "You found the soul for %pBongo&Bongo%w!", - "Vous obtenez l'âme de %pBongo Bongo%w!"), + "Vous obtenez l'âme de %pBongo&Bongo%w!"), GIMESSAGE_NO_GERMAN(RG_TWINROVA_SOUL, ITEM_BIG_POE, "You found the soul for %yTwinrova%w!", - "Vous obtenez l'âme du %yDuo Maléfique%w!"), + "Vous obtenez l'âme du %yDuo&Maléfique%w!"), GIMESSAGE_NO_GERMAN(RG_GANON_SOUL, ITEM_BIG_POE, "You found the soul for %cGanon%w!", "Vous obtenez l'âme de %cGanon%w!"), @@ -3759,68 +3754,68 @@ void Randomizer::CreateCustomMessages() { GIMESSAGE(RG_OCARINA_A_BUTTON, ITEM_OCARINA_TIME, "You got the %b\x9f%r button for the&Ocarina%w! You can now use it&while playing songs!", "Der %b\x9f%r Knopf%w!&Du kannst ihn nun zum Spielen&von Liedern auf der %rOkarina%w&verwenden!", - "Vous trouvez la %rtouche %b\x9f%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), + "Vous obtenez la %rtouche %b\x9f%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), GIMESSAGE(RG_OCARINA_C_LEFT_BUTTON, ITEM_OCARINA_TIME, "You got the %y\xa7%r button for the&Ocarina%w! You can now use it&while playing songs!", "Der %y\xa7%r Knopf%w!&Du kannst ihn nun zum Spielen&von Liedern auf der %rOkarina%w&verwenden!", - "Vous trouvez la %rtouche %y\xa7%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), + "Vous obtenez la %rtouche %y\xa7%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), GIMESSAGE(RG_OCARINA_C_RIGHT_BUTTON, ITEM_OCARINA_TIME, "You got the %y\xa8%r button for the&Ocarina%w! You can now use it&while playing songs!", "Der %y\xa8%r Knopf%w!&Du kannst ihn nun zum Spielen&von Liedern auf der %rOkarina%w&verwenden!", - "Vous trouvez la %rtouche %y\xa8%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), + "Vous obtenez la %rtouche %y\xa8%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), GIMESSAGE(RG_OCARINA_C_UP_BUTTON, ITEM_OCARINA_TIME, "You got the %y\xa5%r button for the&Ocarina%w! You can now use it&while playing songs!", "Der %y\xa5%r Knopf%w!&Du kannst ihn nun zum Spielen&von Liedern auf der %rOkarina%w&verwenden!", - "Vous trouvez la %rtouche %y\xa5%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), + "Vous obtenez la %rtouche %y\xa5%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), GIMESSAGE(RG_OCARINA_C_DOWN_BUTTON, ITEM_OCARINA_TIME, "You got the %y\xa6%r button for the&Ocarina%w! You can now use it&while playing songs!", "Der %y\xa6%r Knopf%w!&Du kannst ihn nun zum Spielen&von Liedern auf der %rOkarina%w&verwenden!", - "Vous trouvez la %rtouche %y\xa6%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), + "Vous obtenez la %rtouche %y\xa6%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), GIMESSAGE_NO_GERMAN(RG_BRONZE_SCALE, ITEM_SCALE_SILVER, "You got the %rBronze Scale%w!&The power of buoyancy is yours!", - "Vous avez obtenu l'%rÉcaille de Bronze%w!&Le pouvoir de la flottabilité est à vous!"), + "Vous obtenez l'%rÉcaille de Bronze%w!&Le pouvoir de la flottabilité est&à vous!"), GIMESSAGE_NO_GERMAN(RG_FISHING_POLE, ITEM_FISHING_POLE, "You found a lost %rFishing Pole%w!&Time to hit the pond!", - "Vous avez trouvé une %rCanne à pêche%w perdue!&Il est temps d'aller à l'étang!"), + "Vous obtenez une %rCanne à pêche%w&perdue!&Il est temps d'aller à %gl'étang%w!"), GIMESSAGE_NO_GERMAN(RG_BOMBCHU_BAG, ITEM_BOMBCHU, "You found the %rBombchu Bag%w!", - "!!!"), + "Vous obtenez un %rSac de Missiles&Teigneux%w!"), GIMESSAGE_NO_GERMAN(RG_BOMB_BAG_INF, ITEM_BOMB_BAG_40, "You got an %rInfinite Bomb Bag%w!&Now you have %yinfinite bombs%w!", - "Vous avez obtenu un %rSac à bombes à l'infini%w!&Vous avez maintenant des %ybombes à l'infini%w!"), + "Vous obtenez un %rSac de Bombes&sans fond%w!&Vous avez maintenant des %ybombes&en quantité illimitée%w!"), GIMESSAGE_NO_GERMAN(RG_QUIVER_INF, ITEM_QUIVER_50, "You got an %rInfinite Quiver%w!&Now you have %yinfinite arrows%w!", - "Vous avez obtenu un %rCarquois à l'infini%w!&Vous avez maintenant des %yflèches à l'infini%w!"), + "Vous obtenez un %rCarquois Infini%w!&Vous avez maintenant des %yflèches&de manière illimitée%w!"), GIMESSAGE_NO_GERMAN(RG_BULLET_BAG_INF, ITEM_BULLET_BAG_50, "You got an %rInfinite Bullet Bag%w!&Now you have %yinfinite&slingshot seeds%w!", - "Vous avez obtenu un %rSac de Graine à l'infini%w!&Vous avez maintenant des %ygraines de lance-pierres à l'infini%w!"), + "Vous obtenez un %rSac de Graines&sans fond%w!&Vous avez maintenant des %ygraines&de lance-pierres à l'infini%w!"), GIMESSAGE_NO_GERMAN(RG_STICK_UPGRADE_INF, ITEM_STICK, "You now have %yinfinite%w %rDeku Sticks%w!", - "Vous avez maintenant des %yBâtons Mojo à l'infini%w!"), + "Vous avez maintenant des %yBâtons&Mojo de manière illimitée%w!"), GIMESSAGE_NO_GERMAN(RG_NUT_UPGRADE_INF, ITEM_NUT, "You now have %yinfinite%w %rDeku Nuts%w!", - "Vous avez maintenant des %yNoix Mojo à l'infini%w!"), + "Vous avez maintenant des %yNoix&Mojo de manière illimitée%w!"), GIMESSAGE_NO_GERMAN(RG_MAGIC_INF, ITEM_MAGIC_LARGE, "You now have %yinfinite%w %rMagic%w!", - "Vous avez maintenant de la %ymagie à l'infini%w!"), + "Vous avez maintenant une quantité&de %ymagie illimitée%w!"), GIMESSAGE_NO_GERMAN(RG_BOMBCHU_INF, ITEM_BOMBCHU, "You now have %yinfinite%w %rBombchus%w!", - "Vous avez maintenant des %Missiles Teigneux à l'infini%w!"), + "Vous avez maintenant des %yMissiles&Teigneux en quantité illimités%w!"), GIMESSAGE_NO_GERMAN(RG_WALLET_INF, ITEM_WALLET_GIANT, "You now have %yinfinite%w %rmoney%w!", - "Vous avez maintenant de l'%yargent à l'infini%w!"), + "Vous avez maintenant des %yRubis en& quantité illimitée%w!"), GIMESSAGE_NO_GERMAN(RG_SKELETON_KEY, ITEM_KEY_SMALL, "You found the %rSkeleton Key%w!", "Vous avez trouvé la %rClé Squelette%w!"), GIMESSAGE_NO_GERMAN(RG_DEKU_STICK_BAG, ITEM_STICK, "You found the %rDeku Stick Bag%w!&You can now hold deku sticks!", - "Vous avez trouvé le %rSac de Bâtons Mojo%w!&Vous pouvez maintenant porter des Bâtons Mojo!"), + "Vous avez trouvé le %rSac de Bâtons&Mojo%w!&Vous pouvez maintenant porter des&Bâtons Mojo!"), GIMESSAGE_NO_GERMAN(RG_DEKU_NUT_BAG, ITEM_NUT, "You found the %rDeku Nut Bag%w!&You can now hold deku nuts!", - "Vous avez trouvé le %rSac de Noix Mojo%w!&Vous pouvez maintenant porter des Noix Mojo!"), + "Vous avez trouvé le %rSac de Noix& Mojo%w!&Vous pouvez maintenant porter des&Noix Mojo!"), }}; - CreateGetItemMessages(&getItemMessages); + CreateGetItemMessages(getItemMessages); CreateRupeeMessages(); CreateTriforcePieceMessages(); CreateNaviRandoMessages(); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index a418627ef..e2581a634 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -5425,7 +5425,6 @@ typedef enum { RO_GANON_BOSS_KEY_LACS_DUNGEONS, RO_GANON_BOSS_KEY_LACS_TOKENS, RO_GANON_BOSS_KEY_KAK_TOKENS, - RO_GANON_BOSS_KEY_TRIFORCE_HUNT, } RandoOptionGanonsBossKey; typedef enum { diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 4cdb4737b..014610152 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -1164,14 +1164,12 @@ void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flag Color_Background.b / 255.0f, Color_Background.a / 255.0f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); - ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger); ImGui::Begin(UniqueName.c_str(), &open, windowFlags); } void EndFloatWindows() { ImGui::PopStyleVar(); ImGui::PopStyleColor(); ImGui::PopStyleColor(); - ImGui::PopFont(); ImGui::End(); } @@ -1846,7 +1844,6 @@ static std::unordered_map buttonStrings = { { TRACKER_COMBO_BUTTON_D_LEFT, "D-Left" }, { TRACKER_COMBO_BUTTON_D_RIGHT, "D-Right" }}; void CheckTrackerSettingsWindow::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger); ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f }); if (ImGui::BeginTable("CheckTrackerSettingsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) { ImGui::TableSetupColumn("General settings", ImGuiTableColumnFlags_WidthStretch, 200.0f); @@ -1860,21 +1857,21 @@ void CheckTrackerSettingsWindow::DrawElement() { ImGui::PopItemWidth(); UIWidgets::CVarCombobox("Window Type", CVAR_TRACKER_CHECK("WindowType"), windowType, - UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPosition::Far).ComponentAlignment(UIWidgets::ComponentAlignment::Right) + UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPositions::Far).ComponentAlignment(UIWidgets::ComponentAlignments::Right) .Color(THEME_COLOR).DefaultIndex(TRACKER_WINDOW_WINDOW)); if (CVarGetInteger(CVAR_TRACKER_CHECK("WindowType"), TRACKER_WINDOW_WINDOW) == TRACKER_WINDOW_FLOATING) { UIWidgets::CVarCheckbox("Enable Dragging", CVAR_TRACKER_CHECK("Draggable"), UIWidgets::CheckboxOptions().Color(THEME_COLOR)); UIWidgets::CVarCheckbox("Only enable while paused", CVAR_TRACKER_CHECK("ShowOnlyPaused"), UIWidgets::CheckboxOptions().Color(THEME_COLOR)); UIWidgets::CVarCombobox("Display Mode", CVAR_TRACKER_CHECK("DisplayType"), displayType, - UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPosition::Far).ComponentAlignment(UIWidgets::ComponentAlignment::Right) + UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPositions::Far).ComponentAlignment(UIWidgets::ComponentAlignments::Right) .Color(THEME_COLOR).DefaultIndex(0)); if (CVarGetInteger(CVAR_TRACKER_CHECK("DisplayType"), TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_COMBO_BUTTON) { UIWidgets::CVarCombobox("Combo Button 1", CVAR_TRACKER_CHECK("ComboButton1"), buttonStrings, - UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPosition::Far).ComponentAlignment(UIWidgets::ComponentAlignment::Right) + UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPositions::Far).ComponentAlignment(UIWidgets::ComponentAlignments::Right) .Color(THEME_COLOR).DefaultIndex(TRACKER_COMBO_BUTTON_L)); UIWidgets::CVarCombobox("Combo Button 2", CVAR_TRACKER_CHECK("ComboButton2"), buttonStrings, - UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPosition::Far).ComponentAlignment(UIWidgets::ComponentAlignment::Right) + UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPositions::Far).ComponentAlignment(UIWidgets::ComponentAlignments::Right) .Color(THEME_COLOR).DefaultIndex(TRACKER_COMBO_BUTTON_L)); } } @@ -1913,7 +1910,6 @@ void CheckTrackerSettingsWindow::DrawElement() { ImGui::PopStyleVar(1); } ImGui::EndTable(); - ImGui::PopFont(); } void CheckTrackerWindow::InitElement() { diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 3ad26b1f6..26592b0ce 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -201,12 +201,12 @@ void Entrance_Init(void) { } // Overwrite grotto related indices - if (originalIndex >= ENTRANCE_GROTTO_EXIT_START) { + if (originalIndex >= ENTRANCE_GROTTO_EXIT_START && originalIndex < ENTRANCE_GROTTO_EXIT_START + NUM_GROTTOS) { Grotto_SetExitOverride(originalIndex, overrideIndex); continue; } - if (originalIndex >= ENTRANCE_GROTTO_LOAD_START && originalIndex < ENTRANCE_GROTTO_EXIT_START) { + if (originalIndex >= ENTRANCE_GROTTO_LOAD_START && originalIndex < ENTRANCE_GROTTO_LOAD_START + NUM_GROTTOS) { Grotto_SetLoadOverride(originalIndex, overrideIndex); continue; } diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp index 49755ff06..fab17acf1 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp @@ -660,7 +660,6 @@ void InitEntranceTrackingData() { void EntranceTrackerSettingsWindow::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger); ImGui::TextWrapped("The entrance tracker will only track shuffled entrances"); UIWidgets::Spacer(0); @@ -675,8 +674,7 @@ void EntranceTrackerSettingsWindow::DrawElement() { ImGui::Text("Sort By"); UIWidgets::CVarRadioButton("To", CVAR_TRACKER_ENTRANCE("SortBy"), 0, UIWidgets::RadioButtonsOptions() - .Color(THEME_COLOR) - .Tooltip("Sort entrances by the original source entrance")); + .Color(THEME_COLOR).Tooltip("Sort entrances by the original source entrance")); UIWidgets::CVarRadioButton("From", CVAR_TRACKER_ENTRANCE("SortBy"), 1, UIWidgets::RadioButtonsOptions() .Color(THEME_COLOR).Tooltip("Sort entrances by the overrided destination")); @@ -722,7 +720,6 @@ void EntranceTrackerSettingsWindow::DrawElement() { ImGui::TextColored(ImColor(COLOR_GRAY), "Undiscovered Entrances"); ImGui::TreePop(); } - ImGui::PopFont(); } void EntranceTrackerWindow::Draw() { @@ -735,12 +732,10 @@ void EntranceTrackerWindow::Draw() { } void EntranceTrackerWindow::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger); ImGui::SetNextWindowSize(ImVec2(600, 375), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Entrance Tracker", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { ImGui::End(); - ImGui::PopFont(); return; } @@ -938,7 +933,6 @@ void EntranceTrackerWindow::DrawElement() { } ImGui::EndChild(); ImGui::End(); - ImGui::PopFont(); } void EntranceTrackerWindow::InitElement() { diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index 9bb562b31..92c7491fc 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -952,14 +952,12 @@ void BeginFloatingWindows(std::string UniqueName, ImGuiWindowFlags flags = 0) { ImGui::PushStyleColor(ImGuiCol_WindowBg, VecFromRGBA8(CVarGetColor(CVAR_TRACKER_ITEM("BgColor.Value"), {0, 0, 0, 0}))); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); - ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger); ImGui::Begin(UniqueName.c_str(), nullptr, windowFlags); } void EndFloatingWindows() { ImGui::PopStyleVar(); ImGui::PopStyleColor(); ImGui::PopStyleColor(); - ImGui::PopFont(); ImGui::End(); } @@ -1218,9 +1216,11 @@ void ItemTrackerWindow::Draw() { if (!IsVisible()) { return; } + ImGui::PushFont(OTRGlobals::Instance->fontMono); DrawElement(); // Sync up the IsVisible flag if it was changed by ImGui SyncVisibilityConsoleVariable(); + ImGui::PopFont(); } void ItemTrackerWindow::DrawElement() { @@ -1375,7 +1375,6 @@ static std::unordered_map extendedDisplayTypes = {{ SECTIO static std::unordered_map minimalDisplayTypes = {{ SECTION_DISPLAY_MINIMAL_HIDDEN, "Hidden" }, { SECTION_DISPLAY_MINIMAL_SEPARATE, "Separate" }}; void ItemTrackerSettingsWindow::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger); ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f }); ImGui::BeginTable("itemTrackerSettingsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV); ImGui::TableSetupColumn("General settings", ImGuiTableColumnFlags_WidthStretch, 200.0f); @@ -1389,8 +1388,8 @@ void ItemTrackerSettingsWindow::DrawElement() { ImGui::PopItemWidth(); if (CVarCombobox("Window Type", CVAR_TRACKER_ITEM("WindowType"), windowTypes, ComboboxOptions() - .DefaultIndex(TRACKER_WINDOW_FLOATING).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(TRACKER_WINDOW_FLOATING).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } @@ -1402,19 +1401,19 @@ void ItemTrackerSettingsWindow::DrawElement() { shouldUpdateVectors = true; } if (CVarCombobox("Display Mode", CVAR_TRACKER_ITEM("DisplayType.Main"), displayModes, ComboboxOptions() - .DefaultIndex(TRACKER_DISPLAY_ALWAYS).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(TRACKER_DISPLAY_ALWAYS).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_COMBO_BUTTON) { if (CVarCombobox("Combo Button 1", CVAR_TRACKER_ITEM("ComboButton1"), buttons, ComboboxOptions() - .DefaultIndex(TRACKER_COMBO_BUTTON_L).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(TRACKER_COMBO_BUTTON_L).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Combo Button 2", CVAR_TRACKER_ITEM("ComboButton2"), buttons, ComboboxOptions() - .DefaultIndex(TRACKER_COMBO_BUTTON_R).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(TRACKER_COMBO_BUTTON_R).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } } @@ -1426,8 +1425,8 @@ void ItemTrackerSettingsWindow::DrawElement() { ImGui::NewLine(); CVarCombobox("Ammo/Capacity Tracking", CVAR_TRACKER_ITEM("ItemCountType"), itemTrackerCapacityTrackOptions, ComboboxOptions() - .DefaultIndex(ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY).ComponentAlignment(ComponentAlignment::Left) - .LabelPosition(LabelPosition::Above).Color(THEME_COLOR) + .DefaultIndex(ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY).ComponentAlignment(ComponentAlignments::Left) + .LabelPosition(LabelPositions::Above).Color(THEME_COLOR) .Tooltip("Customize what the numbers under each item are tracking." "\n\nNote: items without capacity upgrades will track ammo even in capacity mode")); if (CVarGetInteger(CVAR_TRACKER_ITEM("ItemCountType"), ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY) == ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY || CVarGetInteger(CVAR_TRACKER_ITEM("ItemCountType"), ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY) == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY) { @@ -1437,35 +1436,35 @@ void ItemTrackerSettingsWindow::DrawElement() { } CVarCombobox("Key Count Tracking", CVAR_TRACKER_ITEM("KeyCounts"), itemTrackerKeyTrackOptions, ComboboxOptions() - .DefaultIndex(KEYS_COLLECTED_MAX).ComponentAlignment(ComponentAlignment::Left) - .LabelPosition(LabelPosition::Above).Color(THEME_COLOR) + .DefaultIndex(KEYS_COLLECTED_MAX).ComponentAlignment(ComponentAlignments::Left) + .LabelPosition(LabelPositions::Above).Color(THEME_COLOR) .Tooltip("Customize what numbers are shown for key tracking.")); CVarCombobox("Triforce Piece Count Tracking", CVAR_TRACKER_ITEM("TriforcePieceCounts"), itemTrackerTriforcePieceTrackOptions, ComboboxOptions() - .DefaultIndex(TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX).ComponentAlignment(ComponentAlignment::Left) - .LabelPosition(LabelPosition::Above).Color(THEME_COLOR) + .DefaultIndex(TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX).ComponentAlignment(ComponentAlignments::Left) + .LabelPosition(LabelPositions::Above).Color(THEME_COLOR) .Tooltip("Customize what numbers are shown for triforce piece tracking.")); ImGui::TableNextColumn(); if (CVarCombobox("Inventory", CVAR_TRACKER_ITEM("DisplayType.Inventory"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Equipment", CVAR_TRACKER_ITEM("DisplayType.Equipment"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Misc", CVAR_TRACKER_ITEM("DisplayType.Misc"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Dungeon Rewards", CVAR_TRACKER_ITEM("DisplayType.DungeonRewards"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.DungeonRewards"), SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) { @@ -1474,13 +1473,13 @@ void ItemTrackerSettingsWindow::DrawElement() { } } if (CVarCombobox("Songs", CVAR_TRACKER_ITEM("DisplayType.Songs"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Dungeon Items", CVAR_TRACKER_ITEM("DisplayType.DungeonItems"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.DungeonItems"), SECTION_DISPLAY_HIDDEN) != SECTION_DISPLAY_HIDDEN) { @@ -1494,45 +1493,45 @@ void ItemTrackerSettingsWindow::DrawElement() { } } if (CVarCombobox("Greg", CVAR_TRACKER_ITEM("DisplayType.Greg"), extendedDisplayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_EXTENDED_HIDDEN).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_EXTENDED_HIDDEN).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Triforce Pieces", CVAR_TRACKER_ITEM("DisplayType.TriforcePieces"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Boss Souls", CVAR_TRACKER_ITEM("DisplayType.BossSouls"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Ocarina Buttons", CVAR_TRACKER_ITEM("DisplayType.OcarinaButtons"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Fishing Pole", CVAR_TRACKER_ITEM("DisplayType.FishingPole"), extendedDisplayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_EXTENDED_HIDDEN).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_EXTENDED_HIDDEN).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarCombobox("Total Checks", "gTrackers.ItemTracker.TotalChecks.DisplayType", minimalDisplayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_MINIMAL_HIDDEN).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_MINIMAL_HIDDEN).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) { if (CVarCombobox("Personal notes", CVAR_TRACKER_ITEM("DisplayType.Notes"), displayTypes, ComboboxOptions() - .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right) - .LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) { + .DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignments::Right) + .LabelPosition(LabelPositions::Far).Color(THEME_COLOR))) { shouldUpdateVectors = true; } } @@ -1541,7 +1540,6 @@ void ItemTrackerSettingsWindow::DrawElement() { ImGui::PopStyleVar(1); ImGui::EndTable(); - ImGui::PopFont(); } void ItemTrackerWindow::InitElement() { diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 447da07f9..a2bf3660d 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -237,7 +237,7 @@ void Settings::CreateOptions() { OPT_U8(RSK_KEYSANITY, "Small Key Shuffle", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Keysanity"), mOptionDescriptions[RSK_KEYSANITY], WidgetType::Combobox, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); OPT_U8(RSK_GERUDO_KEYS, "Gerudo Fortress Keys", {"Vanilla", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GerudoKeys"), mOptionDescriptions[RSK_GERUDO_KEYS], WidgetType::Combobox, RO_GERUDO_KEYS_VANILLA); OPT_U8(RSK_BOSS_KEYSANITY, "Boss Key Shuffle", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BossKeysanity"), mOptionDescriptions[RSK_BOSS_KEYSANITY], WidgetType::Combobox, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); - OPT_U8(RSK_GANONS_BOSS_KEY, "Ganon's Boss Key", {"Vanilla", "Own Dungeon", "Start With", "Any Dungeon", "Overworld", "Anywhere", "LACS-Vanilla", "LACS-Stones", "LACS-Medallions", "LACS-Rewards", "LACS-Dungeons", "LACS-Tokens", "100 GS Reward", "Triforce Hunt"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), mOptionDescriptions[RSK_GANONS_BOSS_KEY], WidgetType::Combobox, RO_GANON_BOSS_KEY_VANILLA); + OPT_U8(RSK_GANONS_BOSS_KEY, "Ganon's Boss Key", {"Vanilla", "Own Dungeon", "Start With", "Any Dungeon", "Overworld", "Anywhere", "LACS-Vanilla", "LACS-Stones", "LACS-Medallions", "LACS-Rewards", "LACS-Dungeons", "LACS-Tokens", "100 GS Reward"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), mOptionDescriptions[RSK_GANONS_BOSS_KEY], WidgetType::Combobox, RO_GANON_BOSS_KEY_VANILLA); OPT_U8(RSK_LACS_STONE_COUNT, "GCBK Stone Count", {NumOpts(0, 4)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsStoneCount"), "", WidgetType::Slider, 3, true); OPT_U8(RSK_LACS_MEDALLION_COUNT, "GCBK Medallion Count", {NumOpts(0, 7)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsMedallionCount"), "", WidgetType::Slider, 6, true); OPT_U8(RSK_LACS_REWARD_COUNT, "GCBK Reward Count", {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardCount"), "", WidgetType::Slider, 9, true); @@ -1856,10 +1856,6 @@ void Context::FinalizeSettings(const std::set& excludedLocation mOptions[RSK_STARTING_AGE].Set(RO_AGE_CHILD); } - if (mOptions[RSK_TRIFORCE_HUNT]) { - mOptions[RSK_GANONS_BOSS_KEY].Set(RO_GANON_BOSS_KEY_TRIFORCE_HUNT); - } - // Force 100 GS Shuffle if that's where Ganon's Boss Key is if (mOptions[RSK_GANONS_BOSS_KEY].Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) { mOptions[RSK_SHUFFLE_100_GS_REWARD].Set(1); diff --git a/soh/soh/Enhancements/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/timesaver_hook_handlers.cpp index eee2a0e9b..a46ebb814 100644 --- a/soh/soh/Enhancements/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/timesaver_hook_handlers.cpp @@ -23,6 +23,7 @@ extern "C" { #include "src/overlays/actors/ovl_Bg_Ddan_Kd/z_bg_ddan_kd.h" #include "src/overlays/actors/ovl_En_Tk/z_en_tk.h" #include "src/overlays/actors/ovl_En_Fu/z_en_fu.h" +#include "src/overlays/actors/ovl_En_Daiku/z_en_daiku.h" #include "src/overlays/actors/ovl_Bg_Spot02_Objects/z_bg_spot02_objects.h" #include "src/overlays/actors/ovl_Bg_Spot03_Taki/z_bg_spot03_taki.h" #include "src/overlays/actors/ovl_Bg_Hidan_Kousi/z_bg_hidan_kousi.h" @@ -42,6 +43,8 @@ extern void BgSpot03Taki_ApplyOpeningAlpha(BgSpot03Taki* bgSpot03Taki, s32 buffe extern void EnGo2_CurledUp(EnGo2* enGo2, PlayState* play); extern void EnRu2_SetEncounterSwitchFlag(EnRu2* enRu2, PlayState* play); + +extern void EnDaiku_EscapeSuccess(EnDaiku* enDaiku, PlayState* play); } #define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).Get() @@ -354,6 +357,18 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li !(gPlayState->sceneNum == SCENE_ZORAS_RIVER && IS_RANDO && RAND_GET_OPTION(RSK_FROGS_HINT))) { *should = false; } + + // If it's near a jailed carpenter, skip it along with introduction of Gerudo mini-boss + if (gPlayState->sceneNum == SCENE_THIEVES_HIDEOUT && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.BossIntro"), IS_RANDO)) { + EnWonderTalk2* enWonderTalk = va_arg(args, EnWonderTalk2*); + EnDaiku* enDaiku = + (EnDaiku*)Actor_FindNearby(gPlayState, &enWonderTalk->actor, ACTOR_EN_DAIKU, ACTORCAT_NPC, 999.0f); + if (enDaiku != NULL) { + Flags_SetSwitch(gPlayState, enDaiku->startFightSwitchFlag); + *should = false; + } + } break; } case VB_NAVI_TALK: { @@ -551,6 +566,17 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li } break; } + case VB_PLAY_CARPENTER_FREE_CS: { + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO)) { + EnDaiku* enDaiku = va_arg(args, EnDaiku*); + if (enDaiku->subCamActive) { + enDaiku->subCamActive = false; + EnDaiku_EscapeSuccess(enDaiku, gPlayState); + } + *should = false; + } + break; + } case VB_PLAY_GORON_FREE_CS: { if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { *should = false; @@ -1106,12 +1132,18 @@ void TimeSaverOnFlagSetHandler(int16_t flagType, int16_t flag) { break; case FLAG_ITEM_GET_INF: switch (flag) { - case ITEMGETINF_OBTAINED_STICK_UPGRADE_FROM_STAGE: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_DEKU_STICK_CAPACITY_30).GetGIEntry_Copy(); + case ITEMGETINF_OBTAINED_STICK_UPGRADE_FROM_STAGE: { + RandomizerGet stickUpgrade = + CUR_UPG_VALUE(UPG_STICKS) == 2 ? RG_DEKU_STICK_CAPACITY_30 : RG_DEKU_STICK_CAPACITY_20; + vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(stickUpgrade).GetGIEntry_Copy(); break; - case ITEMGETINF_OBTAINED_NUT_UPGRADE_FROM_STAGE: - vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_DEKU_NUT_CAPACITY_40).GetGIEntry_Copy(); + } + case ITEMGETINF_OBTAINED_NUT_UPGRADE_FROM_STAGE: { + RandomizerGet nutUpgrade = + CUR_UPG_VALUE(UPG_NUTS) == 2 ? RG_DEKU_NUT_CAPACITY_40 : RG_DEKU_NUT_CAPACITY_30; + vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(nutUpgrade).GetGIEntry_Copy(); break; + } } break; } diff --git a/soh/soh/Enhancements/timesplits/TimeSplits.cpp b/soh/soh/Enhancements/timesplits/TimeSplits.cpp index 4340be330..046536f45 100644 --- a/soh/soh/Enhancements/timesplits/TimeSplits.cpp +++ b/soh/soh/Enhancements/timesplits/TimeSplits.cpp @@ -809,7 +809,7 @@ void TimeSplitsDrawOptionsMenu() { static uint32_t selectedItem = 0; ImGui::Text("Select List to Load: "); ImGui::PushItemWidth(150.0f); - Combobox("", &selectedItem, keys, ComboboxOptions().Color(THEME_COLOR).LabelPosition(LabelPosition::Near)); + Combobox("", &selectedItem, keys, ComboboxOptions().Color(THEME_COLOR).LabelPosition(LabelPositions::Near)); ImGui::PopItemWidth(); ImGui::SameLine(); if (Button("Load List", ButtonOptions().Color(THEME_COLOR).Size(Sizes::Inline))) { @@ -941,7 +941,6 @@ static bool initialized = false; void TimeSplitWindow::DrawElement() { ImGui::SetWindowFontScale(timeSplitsWindowSize); - ImGui::PushFont(OTRGlobals::Instance->fontMonoLargest); PushStyleTabs(THEME_COLOR); if (ImGui::BeginTabBar("Split Tabs")) { @@ -960,7 +959,6 @@ void TimeSplitWindow::DrawElement() { ImGui::EndTabBar(); } PopStyleTabs(); - ImGui::PopFont(); } void TimeSplitWindow::InitElement() { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 0b8d0030a..5d2310e1b 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -407,7 +407,7 @@ OTRGlobals::OTRGlobals() { fontStandard = CreateFontWithSize(16.0f, "fonts/Montserrat-Regular.ttf"); fontStandardLarger = CreateFontWithSize(20.0f, "fonts/Montserrat-Regular.ttf"); fontStandardLargest = CreateFontWithSize(24.0f, "fonts/Montserrat-Regular.ttf"); - ImGui::GetIO().FontDefault = fontMono; + ImGui::GetIO().FontDefault = fontStandardLarger; ScaleImGui(); // Move the camera strings from read only memory onto the heap (writable memory) @@ -499,15 +499,12 @@ bool OTRGlobals::HasOriginal() { } uint32_t OTRGlobals::GetInterpolationFPS() { - if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) { - return CVarGetInteger(CVAR_SETTING("InterpolationFPS"), 20); - } - if (CVarGetInteger(CVAR_SETTING("MatchRefreshRate"), 0)) { return Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); + } else if (CVarGetInteger(CVAR_VSYNC_ENABLED, 1) || !Ship::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) { + return std::min(Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(), CVarGetInteger(CVAR_SETTING("InterpolationFPS"), 20)); } - - return std::min(Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(), CVarGetInteger(CVAR_SETTING("InterpolationFPS"), 20)); + return CVarGetInteger(CVAR_SETTING("InterpolationFPS"), 20); } extern "C" void OTRMessage_Init(); @@ -1296,6 +1293,11 @@ extern "C" void Graph_StartFrame() { OTRGlobals::Instance->context->GetWindow()->SetLastScancode(-1); switch (dwScancode) { + case KbScancode::LUS_KB_F1: { + std::shared_ptr modal = static_pointer_cast(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Modal Window")); + modal->RegisterPopup("Menu Moved", "The menubar, accessed by hitting F1, no longer exists.\nThe new menu can be accessed by hitting the Esc button instead.", "OK"); + break; + } case KbScancode::LUS_KB_F5: { if (CVarGetInteger(CVAR_CHEAT("SaveStatesEnabled"), 0) == 0) { Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()-> @@ -1369,6 +1371,10 @@ extern "C" void Graph_StartFrame() { break; } #endif + case KbScancode::LUS_KB_F11: { + CVarSetInteger(CVAR_SETTING("Fullscreen"), !CVarGetInteger(CVAR_SETTING("Fullscreen"), 0)); + break; + } case KbScancode::LUS_KB_TAB: { CVarSetInteger(CVAR_ENHANCEMENT("AltAssets"), !CVarGetInteger(CVAR_ENHANCEMENT("AltAssets"), 0)); break; diff --git a/soh/soh/SohGui/Menu.cpp b/soh/soh/SohGui/Menu.cpp index e130d5b75..0e8f8ab51 100644 --- a/soh/soh/SohGui/Menu.cpp +++ b/soh/soh/SohGui/Menu.cpp @@ -4,6 +4,7 @@ #include "soh/Enhancements/controls/SohInputEditorWindow.h" #include "window/gui/GuiMenuBar.h" #include "window/gui/GuiElement.h" +#include "SohModals.h" #include #include #include "variables.h" @@ -19,7 +20,9 @@ std::vector windowTypeSizes = { {} }; extern std::unordered_map warpPointSceneList; extern void Warp(); -namespace SohGui {} +namespace SohGui { +extern std::shared_ptr mModalWindow; +} namespace Ship { std::string disabledTempTooltip; @@ -104,6 +107,10 @@ void Menu::UpdateWindowBackendObjects() { } } +bool Menu::IsMenuPopped() { + return popped; +} + UIWidgets::Colors Menu::GetMenuThemeColor() { return menuThemeIndex; } @@ -303,21 +310,23 @@ void Menu::MenuDrawItem(WidgetInfo& widget, uint32_t width, UIWidgets::Colors me ImGui::Separator(); } break; case WIDGET_SEPARATOR_TEXT: { - if (widget.options->color != UIWidgets::Colors::NoColor) { - ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::ColorValues.at(widget.options->color)); + auto options = std::static_pointer_cast(widget.options); + if (options->color != UIWidgets::Colors::NoColor) { + ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::ColorValues.at(options->color)); } ImGui::SeparatorText(widget.name.c_str()); - if (widget.options->color != UIWidgets::Colors::NoColor) { + if (options->color != UIWidgets::Colors::NoColor) { ImGui::PopStyleColor(); } } break; case WIDGET_TEXT: { - if (widget.options->color != UIWidgets::Colors::NoColor) { - ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::ColorValues.at(widget.options->color)); + auto options = std::static_pointer_cast(widget.options); + if (options->color != UIWidgets::Colors::NoColor) { + ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::ColorValues.at(options->color)); } ImGui::AlignTextToFramePadding(); ImGui::TextWrapped("%s", widget.name.c_str()); - if (widget.options->color != UIWidgets::Colors::NoColor) { + if (options->color != UIWidgets::Colors::NoColor) { ImGui::PopStyleColor(); } } break; @@ -530,13 +539,13 @@ void Menu::DrawElement() { ImGui::End(); return; } - ImGui::PushFont(OTRGlobals::Instance->fontStandardLargest); ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImGuiStyle& style = ImGui::GetStyle(); windowHeight = window->WorkRect.GetHeight(); windowWidth = window->WorkRect.GetWidth(); + ImGui::PushFont(OTRGlobals::Instance->fontStandardLargest); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f)); const char* headerCvar = CVAR_SETTING("Menu.ActiveHeader"); std::string headerIndex = CVarGetString(headerCvar, "Settings"); @@ -559,12 +568,13 @@ void Menu::DrawElement() { // Full screen menu with widths below 1280, heights below 800. // 5% of screen width/height padding on both sides above those resolutions. - ImVec2 menuSize = { std::fminf(1280, windowWidth), std::fminf(800, windowHeight) }; + // Menu width will never exceed a 16:9 aspect ratio. + ImVec2 menuSize = { windowWidth, windowHeight }; if (windowWidth > 1280) { - menuSize.x = floor(windowWidth * 0.9); + menuSize.x = std::fminf(windowWidth * 0.9f, (windowHeight * 1.77f)); } if (windowHeight > 800) { - menuSize.y = floor(windowHeight * 0.9); + menuSize.y = windowHeight * 0.9f; } pos += window->WorkRect.GetSize() / 2 - menuSize / 2; @@ -581,22 +591,6 @@ void Menu::DrawElement() { headerHeight += style.ScrollbarSize; scrollbar = true; } - UIWidgets::ButtonOptions options = {}; - options.size = UIWidgets::Sizes::Inline; - options.tooltip = "Close Menu (Esc)"; - if (UIWidgets::Button(ICON_FA_TIMES_CIRCLE, options)) { - ToggleVisibility(); - - // Update gamepad navigation after close based on if other menus are still visible - auto mImGuiIo = &ImGui::GetIO(); - if (CVarGetInteger(CVAR_IMGUI_CONTROLLER_NAV, 0) && - Ship::Context::GetInstance()->GetWindow()->GetGui()->GetMenuOrMenubarVisible()) { - mImGuiIo->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - } else { - mImGuiIo->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad; - } - } - ImGui::SameLine(); ImGui::SetNextWindowSizeConstraints({ 0, headerHeight }, { headerWidth, headerHeight }); ImVec2 headerSelSize = { menuSize.x - buttonSize.x * 3 - style.ItemSpacing.x * 3, headerHeight }; if (scrollbar) { @@ -657,7 +651,22 @@ void Menu::DrawElement() { ImGui::PopStyleColor(); } ImGui::EndChild(); - ImGui::SameLine(menuSize.x - (buttonSize.x * 2) - style.ItemSpacing.x); + ImGui::SameLine(menuSize.x - (buttonSize.x * 3) - (style.ItemSpacing.x * 2)); + UIWidgets::ButtonOptions options3 = {}; + options3.color = UIWidgets::Colors::Red; + options3.size = UIWidgets::Sizes::Inline; + options3.tooltip = "Quit SoH"; + if (UIWidgets::Button(ICON_FA_POWER_OFF, options3)) { + SohGui::mModalWindow->RegisterPopup("Quit SoH", "Are you sure you want to quit SoH?", "Quit", "Cancel", []() { + std::shared_ptr menu = static_pointer_cast(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetMenu()); + if (!menu->IsMenuPopped()) { + menu->ToggleVisibility(); + } + Ship::Context::GetInstance()->GetWindow()->Close(); + }, nullptr); + } + ImGui::PopStyleVar(); + ImGui::SameLine(); UIWidgets::ButtonOptions options2 = {}; options2.color = UIWidgets::Colors::Red; options2.size = UIWidgets::Sizes::Inline; @@ -676,17 +685,21 @@ void Menu::DrawElement() { ->Dispatch("reset"); } ImGui::SameLine(); - UIWidgets::ButtonOptions options3 = {}; - options3.color = UIWidgets::Colors::Red; - options3.size = UIWidgets::Sizes::Inline; - options3.tooltip = "Quit SoH"; - if (UIWidgets::Button(ICON_FA_POWER_OFF, options3)) { - if (!popped) { - ToggleVisibility(); + UIWidgets::ButtonOptions options = {}; + options.size = UIWidgets::Sizes::Inline; + options.tooltip = "Close Menu (Esc)"; + if (UIWidgets::Button(ICON_FA_TIMES_CIRCLE, options)) { + ToggleVisibility(); + + // Update gamepad navigation after close based on if other menus are still visible + auto mImGuiIo = &ImGui::GetIO(); + if (CVarGetInteger(CVAR_IMGUI_CONTROLLER_NAV, 0) && + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetMenuOrMenubarVisible()) { + mImGuiIo->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; + } else { + mImGuiIo->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad; } - Ship::Context::GetInstance()->GetWindow()->Close(); } - ImGui::PopStyleVar(); pos.y += headerHeight + style.ItemSpacing.y; pos.x = centerX - menuSize.x / 2 + (style.ItemSpacing.x * (menuEntries.size() + 1)); @@ -696,7 +709,12 @@ void Menu::DrawElement() { float sectionHeight = menuSize.y - headerHeight - 4 - style.ItemSpacing.y * 2; float columnHeight = sectionHeight - style.ItemSpacing.y * 4; ImGui::SetNextWindowPos(pos + style.ItemSpacing * 2); + + // Increase sidebar width on larger screens to accomodate people scaling their menus. float sidebarWidth = 200 - style.ItemSpacing.x; + if (menuSize.x > 1600) { + sidebarWidth = menuSize.x * 0.15f; + } const char* sidebarCvar = menuEntries.at(headerIndex).sidebarCvar; @@ -732,8 +750,8 @@ void Menu::DrawElement() { } } ImGui::EndChild(); + ImGui::PopFont(); - ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger); pos = ImVec2{ sectionCenterX + (sidebarWidth / 2), topY } + style.ItemSpacing * 2; window->DrawList->AddRectFilled(pos, pos + ImVec2{ 4, sectionHeight - style.FramePadding.y * 2 }, ImGui::GetColorU32({ 255, 255, 255, 255 }), true, style.WindowRounding); @@ -802,8 +820,6 @@ void Menu::DrawElement() { if (!useColumns || menuSearchText.length() > 0) { ImGui::EndChild(); } - ImGui::PopFont(); - ImGui::PopFont(); if (!popout) { ImGui::PopStyleVar(); diff --git a/soh/soh/SohGui/Menu.h b/soh/soh/SohGui/Menu.h index d7007bb1e..139f90030 100644 --- a/soh/soh/SohGui/Menu.h +++ b/soh/soh/SohGui/Menu.h @@ -21,6 +21,7 @@ class Menu : public GuiWindow { void InsertSidebarSearch(); void RemoveSidebarSearch(); void UpdateWindowBackendObjects(); + bool IsMenuPopped(); UIWidgets::Colors GetMenuThemeColor(); void MenuDrawItem(WidgetInfo& widget, uint32_t width, UIWidgets::Colors menuThemeIndex); diff --git a/soh/soh/SohGui/MenuTypes.h b/soh/soh/SohGui/MenuTypes.h index 7b979a824..28a89820d 100644 --- a/soh/soh/SohGui/MenuTypes.h +++ b/soh/soh/SohGui/MenuTypes.h @@ -73,7 +73,7 @@ typedef enum { using CVarVariant = std::variant; using OptionsVariant = std::variant; // All the info needed for display and search of all widgets in the menu. @@ -145,6 +145,8 @@ struct WidgetInfo { break; case WIDGET_TEXT: case WIDGET_SEPARATOR_TEXT: + options = std::make_shared(std::get(options_)); + break; case WIDGET_SEPARATOR: default: options = std::make_shared(std::get(options_)); diff --git a/soh/soh/SohGui/ResolutionEditor.cpp b/soh/soh/SohGui/ResolutionEditor.cpp index 8e850682c..6b287fde5 100644 --- a/soh/soh/SohGui/ResolutionEditor.cpp +++ b/soh/soh/SohGui/ResolutionEditor.cpp @@ -360,10 +360,10 @@ void RegisterResolutionWidgets() { WIDGET_TEXT) .PreFunc( [](WidgetInfo& info) { info.isHidden = !(!CVarGetInteger(CVAR_LOW_RES_MODE, 0) && IsDroppingFrames()); }) - .Options(WidgetOptions().Color(Colors::Orange)); + .Options(TextOptions().Color(Colors::Orange)); mSohMenu->AddWidget(path, ICON_FA_QUESTION_CIRCLE " \"N64 Mode\" is overriding these settings.", WIDGET_TEXT) .PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_LOW_RES_MODE, 0); }) - .Options(WidgetOptions().Color(Colors::LightBlue)); + .Options(TextOptions().Color(Colors::LightBlue)); mSohMenu->AddWidget(path, "Click to disable N64 mode", WIDGET_BUTTON) .PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_LOW_RES_MODE, 0); }) .Callback([](WidgetInfo& info) { @@ -391,7 +391,7 @@ void RegisterResolutionWidgets() { } }) .SameLine(true) - .Options(WidgetOptions().Color(Colors::Gray)); + .Options(TextOptions().Color(Colors::Gray)); // Presets mSohMenu->AddWidget(path, "Aspect Ratio", WIDGET_COMBOBOX) .ValuePointer(&item_aspectRatio) @@ -422,10 +422,10 @@ void RegisterResolutionWidgets() { // Declare input interaction bools outside of IF statement to prevent Y field from disappearing. const bool input_X = UIWidgets::SliderFloat("X", &aspectRatioX, UIWidgets::FloatSliderOptions({{ .disabled = disabled_everything }}).Min(0.1f).Max(32.0f).Step(0.001f).Format("%3f") - .Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::Near).ComponentAlignment(UIWidgets::ComponentAlignment::Right)); + .Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPositions::Near).ComponentAlignment(UIWidgets::ComponentAlignments::Right)); const bool input_Y = UIWidgets::SliderFloat("Y", &aspectRatioY, UIWidgets::FloatSliderOptions({{ .disabled = disabled_everything }}).Min(0.1f).Max(24.0f).Step(0.001f).Format("%3f") - .Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::Near).ComponentAlignment(UIWidgets::ComponentAlignment::Right)); + .Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPositions::Near).ComponentAlignment(UIWidgets::ComponentAlignments::Right)); if (input_X || input_Y) { item_aspectRatio = default_aspectRatio; update[UPDATE_aspectRatioX] = true; @@ -517,7 +517,7 @@ void UpdateResolutionVars() { bool IsDroppingFrames() { // a rather imprecise way of checking for frame drops. // but it's mostly there to inform the player of large drops. - const short targetFPS = CVarGetInteger("gInterpolationFPS", 20); + const short targetFPS = OTRGlobals::Instance->GetInterpolationFPS(); const float threshold = targetFPS / 20.0f + 4.1f; return ImGui::GetIO().Framerate < targetFPS - threshold; } diff --git a/soh/soh/SohGui/SohMenu.cpp b/soh/soh/SohGui/SohMenu.cpp index d4aee295a..26770c986 100644 --- a/soh/soh/SohGui/SohMenu.cpp +++ b/soh/soh/SohGui/SohMenu.cpp @@ -64,10 +64,12 @@ WidgetInfo& SohMenu::AddWidget(WidgetPath& pathInfo, std::string widgetName, Wid case WIDGET_COLOR_24: case WIDGET_COLOR_32: break; - case WIDGET_SEARCH: - case WIDGET_SEPARATOR: case WIDGET_SEPARATOR_TEXT: case WIDGET_TEXT: + widget.options = std::make_shared(); + break; + case WIDGET_SEARCH: + case WIDGET_SEPARATOR: default: widget.options = std::make_shared(); } @@ -125,7 +127,7 @@ void SohMenu::InitElement() { }, "Not Available on DirectX" } }, { DISABLE_FOR_MATCH_REFRESH_RATE_ON, - { [](disabledInfo& info) -> bool { return CVarGetInteger(CVAR_SETTING("gMatchRefreshRate"), 0); }, + { [](disabledInfo& info) -> bool { return CVarGetInteger(CVAR_SETTING("MatchRefreshRate"), 0); }, "Match Refresh Rate is Enabled" } }, { DISABLE_FOR_ADVANCED_RESOLUTION_ON, { [](disabledInfo& info) -> bool { return CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled", 0); }, @@ -140,7 +142,7 @@ void SohMenu::InitElement() { { DISABLE_FOR_NULL_PLAY_STATE, { [](disabledInfo& info) -> bool { return gPlayState == NULL; }, "Save Not Loaded" } }, { DISABLE_FOR_DEBUG_MODE_OFF, - { [](disabledInfo& info) -> bool { return !CVarGetInteger("gDeveloperTools.DebugEnabled", 0); }, + { [](disabledInfo& info) -> bool { return !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); }, "Debug Mode is Disabled" } }, { DISABLE_FOR_FRAME_ADVANCE_OFF, { [](disabledInfo& info) -> bool { return !(gPlayState != nullptr && gPlayState->frameAdvCtx.enabled); }, diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 5f4961279..1f3066806 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -34,7 +34,8 @@ void SohMenu::AddMenuEnhancements() { if (iter->first != 0) comboboxTooltip += "\n\n"; comboboxTooltip += std::string(iter->second.label) + " - " + std::string(iter->second.description); } - AddWidget(path, "Enhancement Presets", WIDGET_COMBOBOX) + AddWidget(path, "Enhancement Presets", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Select Preset", WIDGET_COMBOBOX) .ValuePointer(&enhancementPresetSelected) .Callback([](WidgetInfo& info) { const std::string presetTypeCvar = CVAR_GENERAL("SelectedPresets.") + std::to_string(PRESET_TYPE_ENHANCEMENTS); @@ -46,6 +47,7 @@ void SohMenu::AddMenuEnhancements() { .Tooltip(comboboxTooltip.c_str()) ); AddWidget(path, "Apply Preset##Enhancemnts", WIDGET_BUTTON) + .Options(ButtonOptions().Size(UIWidgets::Sizes::Inline)) .Callback([](WidgetInfo& info) { const std::string presetTypeCvar = CVAR_GENERAL("SelectedPresets.") + std::to_string(PRESET_TYPE_ENHANCEMENTS); const PresetTypeDefinition presetTypeDef = presetTypes.at(PRESET_TYPE_ENHANCEMENTS); @@ -64,400 +66,193 @@ void SohMenu::AddMenuEnhancements() { Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); }); - path.sidebarName = "Gameplay"; + // Quality of Life + path.sidebarName = "Quality of Life"; AddSidebarEntry("Enhancements", path.sidebarName, 3); + path.column = SECTION_COLUMN_1; - AddWidget(path, "Boot Sequence", WIDGET_CVAR_COMBOBOX) - .CVar(CVAR_ENHANCEMENT("BootSequence")) - .Options(ComboboxOptions() - .DefaultIndex(BOOTSEQUENCE_DEFAULT) - .ComboMap(bootSequenceLabels) - .Tooltip( - "Configure what happens when starting or resetting the game.\n\n" - "Default: LUS logo -> N64 logo\n" - "Authentic: N64 logo only\n" - "File Select: Skip to file select menu" - ) - ); + AddWidget(path, "Saving", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Autosave", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Autosave")) .Options(CheckboxOptions().Tooltip( "Save the game automatically on a 3 minute interval and when soft-resetting the game. The interval " "autosave will wait if the game is paused in any way (dialogue, pause screen up, cutscenes, " "etc.).\n\n" - "The soft-reset save will *not* trigger in cutscene maps like the Chamber of Sages!" - )); + "The soft-reset save will *not* trigger in cutscene maps like the Chamber of Sages!")); + AddWidget(path, "Remember Save Location", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("RememberSaveLocation")) + .Options(CheckboxOptions().Tooltip( + "When loading a save, places Link at the last entrance he went through.\n" + "This doesn't work if the save was made in grottos, fairy fountains, or dungeons.")); - AddWidget(path, "Audio", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Mute Low HP Alarm", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("LowHPAlarm")) + AddWidget(path, "Containers Match Contents", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Chest Size & Texture Matches Contents", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents")) + .Callback([](WidgetInfo& info) { + if (CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents"), CSMC_DISABLED) == CSMC_DISABLED) { + CVarSetInteger(CVAR_ENHANCEMENT("ChestSizeDependsStoneOfAgony"), 0); + } + }) + .Options(ComboboxOptions() + .ComboMap(chestStyleMatchesContentsOptions) + .DefaultIndex(CSMC_DISABLED) + .Tooltip("Chest sizes and textures are changed to help identify the item inside.\n" + " - Major items: Large gold chests\n" + " - Lesser items: Large brown chests\n" + " - Junk items: Small brown chests\n" + " - Small keys: Small silver chests\n" + " - Boss keys: Vanilla size and texture\n" + " - Skulltula Tokens: Small skulltula chest\n" + "\n" + "NOTE: Textures will not apply if you are using a mod pack with a custom chest model.")); + AddWidget(path, "Chests of Agony", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("ChestSizeDependsStoneOfAgony")) + .PreFunc([](WidgetInfo& info) { + info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchesContents"), CSMC_DISABLED); + }) + .Options(CheckboxOptions().Tooltip("Only change the size/texture of chests if you have the Stone of Agony.")); + + AddWidget(path, "Time of Day", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Nighttime GS Always Spawn", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("NightGSAlwaysSpawn")) + .Options(CheckboxOptions().Tooltip("Nighttime Skulltulas will spawn during both day and night.")); + AddWidget(path, "Pull Grave during the day", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DayGravePull")) + .Options(CheckboxOptions().Tooltip("Allows graves to be pulled when child during the day.")); + AddWidget(path, "Dampe Appears All Night", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DampeAllNight")) .Options(CheckboxOptions().Tooltip( - "Disable the low HP beeping sound." - )); - AddWidget(path, "Disable Navi Call Audio", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DisableNaviCallAudio")) + "Makes Dampe appear anytime during the night, not just his usual working hours.")); + AddWidget(path, "Exit Market at Night", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("MarketSneak")) .Options(CheckboxOptions().Tooltip( - "Disables the voice audio when Navi calls you." - )); + "Allows exiting Hyrule Castle Market Town to Hyrule Field at night by speaking to the guard " + "next to the gate.")); + AddWidget(path, "Shops and Games Always Open", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("OpenAllHours")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = + IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_LOCK_OVERWORLD_DOORS).Is(RO_GENERIC_ON); + }) + .Options( + CheckboxOptions() + .Tooltip("Shops and Minigames are open both day and night. Requires a scene reload to take effect.") + .DisabledTooltip("This is not compatible with the Locked Overworld Doors Randomizer option.")); AddWidget(path, "Pause Menu", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Allow the Cursor to be on any slot", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_ENHANCEMENT("PauseAnyCursor")) - .Options(ComboboxOptions() - .ComboMap(cursorAnywhereValues) - .DefaultIndex(PAUSE_ANY_CURSOR_RANDO_ONLY) - .Tooltip( - "Allows the cursor on the pause menu to be over any slot. Sometimes required in Randomizer " - "to select certain items." - ) - ); - AddWidget(path, "Assignable Tunics and Boots", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("AssignableTunicsAndBoots")) + .Options( + ComboboxOptions() + .ComboMap(cursorAnywhereValues) + .DefaultIndex(PAUSE_ANY_CURSOR_RANDO_ONLY) + .Tooltip("Allows the cursor on the pause menu to be over any slot. Sometimes required in Randomizer " + "to select certain items.")); + AddWidget(path, "Pause Warp", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("PauseWarp")) .Options(CheckboxOptions().Tooltip( - "Allows equipping the Tunics and Boots to C-Buttons/D-Pad." - )); - // TODO: Revist strength toggle, it's currently separate but should probably go here and be locked behind the - // Equipment toggle settings. Also maybe these should all be in Items sidebar? - AddWidget(path, "Equipment Toggle", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("EquipmentCanBeRemoved")) - .Options(CheckboxOptions().Tooltip( - "Allows equipment to be removed by toggling it off on\n the equipment subscreen." - )); - AddWidget(path, "Sword Toggle Options", WIDGET_CVAR_COMBOBOX) - .CVar(CVAR_ENHANCEMENT("SwordToggle")) - .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("EquipmentCanBeRemoved"), 0) == 0; - }) - .Options(ComboboxOptions() - .ComboMap(swordToggleModes) - .DefaultIndex(SWORD_TOGGLE_NONE) - .Tooltip( - "Introduces Options for unequipping Link's sword\n\n" - "None: Only Biggoron's Sword/Giant's Knife can be toggled. Doing so will equip the Master Sword.\n\n" - "Child Toggle: This will allow for completely unequipping any sword as child link.\n\n" - "Both Ages: Any sword can be unequipped as either age. This may lead to swordless glitches as Adult." - ) - ); - - AddWidget(path, "Quality of Life", WIDGET_SEPARATOR_TEXT); - // Maybe should be in Timesavers somewhere? - AddWidget(path, "Link's Cow in Both Time Periods", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CowOfTime")) - .Options(CheckboxOptions().Tooltip( - "Allows the Lon Lon Ranch Obstacle Course reward to be shared across time periods." - )); - // Maybe should be in Difficulty Options somewhere? - AddWidget(path, "Enable Visual Guard Vision", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("GuardVision")); - // Maybe should be in TImesavers somewhere? - AddWidget(path, "Pull Grave during the day", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DayGravePull")) - .Options(CheckboxOptions().Tooltip( - "Allows graves to be pulled when child during the day." - )); + "Selection of warp song in pause menu initiates a warp. Disables song playback.")); + + path.column = SECTION_COLUMN_2; + AddWidget(path, "Controls", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Answer Navi Prompt with L Button", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("NaviOnL")) + .Options(CheckboxOptions().Tooltip("Speak to Navi with L but enter First-Person Camera with C-Up")); AddWidget(path, "Don't Require Input for Credits Sequence", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("NoInputForCredits")) .Options(CheckboxOptions().Tooltip( "Removes the Input Requirement on Text boxes after defeating Ganon, allowing the Credits " - "Sequence to continue to progress." - )); - AddWidget(path, "Answer Navi Prompt with L Button", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("NaviOnL")) - .Options(CheckboxOptions().Tooltip( - "Speak to Navi with L but enter First-Person Camera with C-Up" - )); - AddWidget(path, "Disable Crit Wiggle", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DisableCritWiggle")) - .Options(CheckboxOptions().Tooltip( - "Disable Random Camera Wiggle at Low Health." - )); - AddWidget(path, "Targetable Hookshot Reticle", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("HookshotableReticle")) - .Options(CheckboxOptions().Tooltip( - "Makes the Hookshot Reticle use a different color when aiming at Hookshotable Collision." - )); - AddWidget(path, "Faster Rupee Accumulator", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FasterRupeeAccumulator")) - .Options(CheckboxOptions().Tooltip( - "Causes your Wallet to fill and empty faster when you gain or lose money." - )); - AddWidget(path, "Fun/Aesthetic Options", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Enable Passage of Time on File Select", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("TimeFlowFileSelect")); - AddWidget(path, "Dogs Follow you Everywhere", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DogFollowsEverywhere")) - .Options(CheckboxOptions().Tooltip( - "Allows dogs to follow you anywhere you go, even if you leave the Market." - )); - AddWidget(path, "Enemy Health Bars", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("EnemyHealthBar")) - .Options(CheckboxOptions().Tooltip( - "Renders a health bar for Enemies when Z-Targeted." - )); - - path.column = SECTION_COLUMN_2; - AddWidget(path, "Authentic Bug Fixes", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Fix L&R Pause Menu", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixMenuLR")) - .Options(CheckboxOptions().Tooltip( - "Makes the L and R buttons in the pause menu the same color" - )); - AddWidget(path, "Fix L&Z Page Switch in Pause Menu", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("NGCKaleidoSwitcher")) - .Options(CheckboxOptions().Tooltip( - "Makes L and R switch pages like on the Gamecube. Z opens the Debug Menu instead." - )); - AddWidget(path, "Fix Dungeon Entrances", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixDungeonMinimapIcon")) - .Options(CheckboxOptions().Tooltip( - "Removes the Dungeon Entrance icon on the top-left corner of the screen when no dungeon is present on the " - "current map." - )); - AddWidget(path, "Fix Two-Handled Idle Animations", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("TwoHandedIdle")) - .Options(CheckboxOptions().Tooltip( - "Re-Enables the two-handed idle animation, a seemingly finished animation that was disabled on accident " - "in the original game." - )); - AddWidget(path, "Fix the Gravedigging Tour Glitch", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("GravediggingTourFix")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = IS_RANDO && GameInteractor::IsSaveLoaded(true); - info.options->disabledTooltip = "This setting is always enabled in randomized save files."; - }) - .Options(CheckboxOptions().Tooltip( - "Fixes a bug where the Gravedigging Tour Heart Piece disappears if the area reloads." - )); - AddWidget(path, "Fix Deku Nut Upgrade", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DekuNutUpgradeFix")) - .Options(CheckboxOptions().Tooltip( - "Prevents the Forest Stage Deku Nut upgrade from becoming unobtainable after receiving the Poacher's Saw." - )); - AddWidget(path, "Fix Navi Text HUD Position", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("NaviTextFix")) - .Options(CheckboxOptions().Tooltip( - "Correctly centers the Navi text prompt on the HUD's C-Up button." - )); - AddWidget(path, "Fix Anubis Fireballs", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("AnubisFix")) - .Options(CheckboxOptions().Tooltip( - "Make Anubis Fireballs do Fire damage when reflected back at them with the Mirror Shield." - )); - AddWidget(path, "Fix Megaton Hammer Crouch Stab", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CrouchStabHammerFix")) - .Callback([](WidgetInfo& info) { - if (!CVarGetInteger(CVAR_ENHANCEMENT("CrouchStabHammerFix"), 0)) { - CVarClear(CVAR_ENHANCEMENT("CrouchStabFix")); - } - }) - .Options(CheckboxOptions().Tooltip( - "Make the Megaton Hammer's crouch stab able to destroy rocks without first swinging it normally." - )); - AddWidget(path, "Remove Power Crouch Stab", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CrouchStabFix")) - .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("CrouchStabHammerFix"), 0) == 0; - }) - .Options(CheckboxOptions().Tooltip( - "Make crouch stabbing always do the same damage as a regular slash." - )); - AddWidget(path, "Fix Credits Timing", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CreditsFix")) - .Options(CheckboxOptions().Tooltip( - "Extend certain credits scenes so the music lines up properly with the visuals." - )); - AddWidget(path, "Fix Gerudo Warrior's Clothing Colors", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("GerudoWarriorClothingFix")) - .Options(CheckboxOptions().Tooltip( - "Prevent the Gerudo Warrior's clothes changign color when changing Link's tunic or " - "using Bombs in front of her." - )); - AddWidget(path, "Fix Camera Drift", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixCameraDrift")) - .Options(CheckboxOptions().Tooltip( - "Fixes camera slightly drifting to the left when standing still due to a math error." - )); - AddWidget(path, "Fix Camera Swing", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixCameraSwing")) - .Options(CheckboxOptions().Tooltip( - "Fixes camera getting stuck on collision when standing still. Also fixes slight shift " - "back in camera when Link stops moving." - )); - AddWidget(path, "Fix Hanging Ledge Swing Rate", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixHangingLedgeSwingRate")) - .Options(CheckboxOptions().Tooltip( - "Fixes camera swing rate when the player falls off a ledge and the camera swings around." - )); - AddWidget(path, "Fix Missing Jingle after 5 Silver Rupees", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("SilverRupeeJingleExtend")) - .Options(CheckboxOptions().Tooltip( - "Adds 5 higher pitches for the Silver Rupee Jingle for the rooms with more than 5 Silver Rupees. " - "Only relevant for playthroughs involving Master Quest Dungeons." - )); - AddWidget(path, "Fix Out of Bounds Textures", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixTexturesOOB")) - .Callback([](WidgetInfo& info) { - ApplyAuthenticGfxPatches(); - }) - .Options(CheckboxOptions().Tooltip( - "Fixes authentic out of bounds texture reads, instead loading textures with the correct size." - )); - AddWidget(path, "Fix Poacher's Saw Softlock", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixSawSoftlock")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("SkipText"), 0) == 1; - info.options->disabledTooltip = "This option is forced on when Skip Text is enabled."; - }) - .Options(CheckboxOptions().Tooltip( - "Prevents the Poacher's Saw softlock from mashing through the text, or with Skip Text enabled." - )); - AddWidget(path, "Fix Enemies not Spawning Near Water", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("EnemySpawnsOverWaterboxes")) - .Options(CheckboxOptions().Tooltip( - "Causes respanwing enemies, like Stalchildren, to appear on land near bodies of water. " - "Fixes an incorrect calculation that acted like water underneath ground was above it." - )); - AddWidget(path, "Fix Bush Item Drops", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BushDropFix")) - .Options(CheckboxOptions().Tooltip( - "Fixes the bushes to drop items correctly rather than spawning undefined items." - )); - AddWidget(path, "Fix Falling from Vine Edges", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixVineFall")) - .Options(CheckboxOptions().Tooltip( - "Prevents immediately falling off climbable surfaces if climbing on the edges." - )); - AddWidget(path, "Fix Link's Eyes Open while Sleeping", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixEyesOpenWhileSleeping")) - .Options(CheckboxOptions().Tooltip( - "Fixes Link's eyes being open in the openeing cutscene when he is supposed to be sleeping." - )); - AddWidget(path, "Fix Darunia Dancing Too Fast", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixDaruniaDanceSpeed")) - .Options(CheckboxOptions().Tooltip( - "Fixes Darunia's dancing speed so he dances to the beat of Saria's Song, like in the Original Game." - )); - AddWidget(path, "Fix Raised Floor Switches", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixFloorSwitches")) - .Options(CheckboxOptions().Tooltip( - "Fixes the two raised floor switches, the one in Forest Temple Basement and the one at the top of Fire " - "Temple. This will lower them, making activating them easier." - )); - AddWidget(path, "Fix Zora Hint Dialogue", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixZoraHintDialogue")) - .Options(CheckboxOptions().Tooltip( - "Fixes one Zora's dialogue giving a hint about bringing Ruto's Letter to King Zora to properly occur " - "before moving King Zora rather than after." - )); - AddWidget(path, "Fix Hand Holding Hammer", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixHammerHand")) - .Callback([](WidgetInfo& info) { - UpdatePatchHand(); - }) - .Options(CheckboxOptions().Tooltip( - "Fixes Adult Link having a backwards Left hand when holding the Megaton Hammer." - )); - AddWidget(path, "Fix Broken Giant's Knife Bug", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FixGrokenGiantsKnife")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = IS_RANDO && GameInteractor::IsSaveLoaded(true); - info.options->disabledTooltip = "This setting is forcefully enabled when you are playing a Randomizer."; - }) - .Callback([](WidgetInfo& info) { - bool hasGiantsKnife = CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BIGGORON); - bool hasBrokenKnife = CHECK_OWNED_EQUIP_ALT(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BROKENGIANTKNIFE); - bool knifeIsBroken = gSaveContext.swordHealth == 0.0f; - - if (hasGiantsKnife && (hasBrokenKnife != knifeIsBroken)) { - func_800849EC(gPlayState); - } - }) - .Options(CheckboxOptions().Tooltip( - "Fixes the Broken Giant's Knife flag not being reset when Medigoron fixes it." - )); - - path.column = SECTION_COLUMN_3; - AddWidget(path, "Restorations", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Red Ganon Blood", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("RedGanonBlood")) - .Options(CheckboxOptions().Tooltip( - "Restore the original red blood from NTSC 1.0/1.1. Disable for Green blood." - )); - AddWidget(path, "Fish while Hovering", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("HoverFishing")) - .Options(CheckboxOptions().Tooltip( - "Restore a bug from NSTC 1.0 that allows casting the Fishing Rod while using the Hover Boots." - )); - AddWidget(path, "N64 Weird Frames", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("N64WeirdFrames")) - .Options(CheckboxOptions().Tooltip( - "Restores N64 Weird Frames allwing weirdshots to behave the same as N64." - )); - AddWidget(path, "Bombchus Out of Bounds", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BombchusOOB")) - .Options(CheckboxOptions().Tooltip( - "Allows Bombchus to explode out of bounds. Similar to Gamecube and Wii VC" - )); - AddWidget(path, "Quick Putaway", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("QuickPutaway")) - .Options(CheckboxOptions().Tooltip( - "Restore a bug from NTSC 1.0 that allows putting away an item without an animation and performing " - "Putaway Ocarina Items." - )); - AddWidget(path, "Restore Old Gold Skulltula Cutscene", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("GSCutscene")) - .Options(CheckboxOptions().Tooltip( - "Restore pre-release behavior where defeating a Gold Skulltula will play a cutscene showing it die." - )); - AddWidget(path, "Quick Bongo Kill", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("QuickBongoKill")) - .Options(CheckboxOptions().Tooltip( - "Restore a bug from NTSC 1.0 that allows bypassing Bongo Bongo's intro cutscene to quickly kill him." - )); - AddWidget(path, "Original RBA Values", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("RestoreRBAValues")) - .Options(CheckboxOptions().Tooltip( - "Restores the original outcomes when performing Reverse Bottle Adventure." - )); - AddWidget(path, "Early Eyeball Frog", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("EarlyEyeballFrog")) - .Options(CheckboxOptions().Tooltip( - "Restores a bug from NTSC 1.0/1.1 that allows you to obtain the eyeball frog from King Zora " - "instead of the Zora Tunic by Holding Shield." - )); - AddWidget(path, "Pulsate Boss Icon", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("Pulsate Boss Icon")) - .Options(CheckboxOptions().Tooltip( - "Restores an unfinished feature to pulsate the boss room icon when you are in the boss room." - )); - AddWidget(path, "Pause Buffer Input Window: %d frames", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("PauseBufferWindow")) - .Options(IntSliderOptions() - .Min(0) - .Max(40) - .DefaultValue(0) - .Format("%d frames") - ); + "Sequence to continue to progress.")); AddWidget(path, "Include Held Inputs at the Start of Buffer Input Window", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("IncludeHeldInputsBufferWindow")) .Options(CheckboxOptions().Tooltip( "Typically, inputs that are held prior to the buffer window are not included in the buffer. This " "setting changes that behavior to include them. This may cause some inputs to be re-triggered " - "undesireably, for instance Z-Targetting something you might not want to." - )); + "undesireably, for instance Z-Targetting something you might not want to.")); + AddWidget(path, "Pause Buffer Input Window: %d frames", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("PauseBufferWindow")) + .Options(IntSliderOptions().Min(0).Max(40).DefaultValue(0).Format("%d frames")); AddWidget(path, "Simulated Input Lag: %d frames", WIDGET_CVAR_SLIDER_INT) .CVar(CVAR_SIMULATED_INPUT_LAG) .Options(IntSliderOptions() - .Min(0) - .Max(6) - .DefaultValue(0) - .Format("%d frames") - .Tooltip( - "Buffers your inputs to be executed a specified amount of frames later." - ) - ); + .Min(0) + .Max(6) + .DefaultValue(0) + .Format("%d frames") + .Tooltip("Buffers your inputs to be executed a specified amount of frames later.")); - path.sidebarName = "Time Savers"; + AddWidget(path, "Item Count Messages", WIDGET_SEPARATOR_TEXT); + int numOptions = ARRAY_COUNT(itemCountMessageCVars); + bool allItemCountsChecked = false; + AddWidget(path, "All", WIDGET_CHECKBOX) + .ValuePointer(&allItemCountsChecked) + .PreFunc([](WidgetInfo& info) { + int numOptions = ARRAY_COUNT(itemCountMessageCVars); + *std::get(info.valuePointer) = std::all_of(itemCountMessageCVars, itemCountMessageCVars + numOptions, + [](const char* cvar) { return CVarGetInteger(cvar, 0); }); + }) + .Callback([](WidgetInfo& info) { + int32_t newValue = *std::get(info.valuePointer) ? 1 : 0; + int numOptions = ARRAY_COUNT(itemCountMessageCVars); + std::for_each(itemCountMessageCVars, itemCountMessageCVars + numOptions, + [newValue](const char* cvar) { CVarSetInteger(cvar, newValue); }); + + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); + }); + for (int i = 0; i < numOptions; i++) { + AddWidget(path, itemCountMessageOptions[i], WIDGET_CVAR_CHECKBOX).CVar(itemCountMessageCVars[i]); + } + + path.column = SECTION_COLUMN_3; + AddWidget(path, "Misc", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Disable Crit Wiggle", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DisableCritWiggle")) + .Options(CheckboxOptions().Tooltip("Disable Random Camera Wiggle at Low Health.")); + AddWidget(path, "Better Owl", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BetterOwl")) + .Options(CheckboxOptions().Tooltip( + "The default response to Kaepora Gaebora is always that you understood what he said.")); + + AddWidget(path, "Convenience", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Quit Fishing At Door", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("QuitFishingAtDoor")) + .Options(CheckboxOptions().Tooltip( + "Fisherman asks if you want to quit at the door if you try to leave the Fishing Pond " + "while still holding the Fishing Rod.")); + AddWidget(path, "Instant Putaway", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("InstantPutaway")) + .Options(CheckboxOptions().Tooltip("Allow Link to put items away without having to wait around.")); + AddWidget(path, "Navi Timer Resets", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("ResetNaviTimer")) + .Options( + CheckboxOptions().Tooltip("Resets the Navi timer on scene change. If you have already talked to her, " + "she will try and talk to you again, instead of needing a save warp or death.")); + AddWidget(path, "Link's Cow in Both Time Periods", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CowOfTime")) + .Options(CheckboxOptions().Tooltip( + "Allows the Lon Lon Ranch Obstacle Course reward to be shared across time periods.")); + AddWidget(path, "Play Zelda's Lullaby to Open Sleeping Waterfall", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = + IS_RANDO && + OTRGlobals::Instance->gRandoContext->GetOption(RSK_SLEEPING_WATERFALL).Is(RO_WATERFALL_OPEN); + info.options->disabledTooltip = "This setting is forcefully enabled because a randomizer savefile with " + "\"Sleeping Waterfall: Open\" is loaded."; + }) + .Options( + ComboboxOptions() + .ComboMap(sleepingWaterfallOptions) + .DefaultIndex(WATERFALL_ALWAYS) + .Tooltip( + "Always: Link must always play Zelda's Lullaby to open the waterfall entrance to Zora's Domain.\n" + "Once: Link only needs to play Zelda's Lullaby once to open the waterfall; after that, it stays " + "open permanently.\n" + "Never: Link never needs to play Zelda's Lullaby to open the waterfall. He only needs to have " + "learned it and have an Ocarina.")); + + // Skips & Speed-ups + path.sidebarName = "Skips & Speed-ups"; AddSidebarEntry("Enhancements", path.sidebarName, 3); path.column = SECTION_COLUMN_1; @@ -467,16 +262,16 @@ void SohMenu::AddMenuEnhancements() { .ValuePointer(&allSkipsChecked) .PreFunc([](WidgetInfo& info) { *std::get(info.valuePointer) = - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Entrances"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.LearnSong"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.BossIntro"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.QuickBossDeaths"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipOwlInteractions"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO) && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.DisableTitleCard"), IS_RANDO); + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Entrances"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.LearnSong"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.BossIntro"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.QuickBossDeaths"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipOwlInteractions"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO) && + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.DisableTitleCard"), IS_RANDO); }) .Callback([](WidgetInfo& info) { int32_t newValue = *std::get(info.valuePointer) ? 1 : 0; @@ -529,259 +324,98 @@ void SohMenu::AddMenuEnhancements() { .Options(CheckboxOptions().Tooltip( "Don't skip cutscenes that are associated wiht useful glitches. Currently, it is " "only the Fire Temple Darunia CS, Forest Temple Poe Sisters CS, and the Box Skip One " - "Point in Jabu." - )); - AddWidget(path, "Skip Child Stealth", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("TimeSavers.SkipChildStealth")) - .Options(CheckboxOptions().Tooltip( - "The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards." - )); - AddWidget(path, "Skip Tower Escape", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("TimeSavers.SkipTowerEscape")) - .Options(CheckboxOptions().Tooltip( - "Skip the tower escape sequence between Ganondorf and Ganon." - )); - + "Point in Jabu.")); + AddWidget(path, "Text", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Skip Pickup Messages", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FastDrops")) + .Options(CheckboxOptions().Tooltip("Skip Pickup Messages for new Consumable Items and Bottle Swipes.")); AddWidget(path, "Skip Forced Dialog", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("TimeSavers.SkipForcedDialog")) - .Options(CheckboxOptions().Tooltip( - "Prevent forced conversations with Navi or other NPCs." - )); - AddWidget(path, "Text Speed: %dx", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("TextSpeed")) - .Options(IntSliderOptions() - .Min(1) - .Max(5) - .DefaultValue(1) - .Format("%dx") - ); + .Options(CheckboxOptions().Tooltip("Prevent forced conversations with Navi or other NPCs.")); AddWidget(path, "Skip Text", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("SkipText")) .Options(CheckboxOptions().Tooltip("Holding down B skips text.")); + AddWidget(path, "Text Speed: %dx", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("TextSpeed")) + .Options(IntSliderOptions().Min(1).Max(5).DefaultValue(1).Format("%dx")); AddWidget(path, "Slow Text Speed: %dx", WIDGET_CVAR_SLIDER_INT) .CVar(CVAR_ENHANCEMENT("SlowTextSpeed")) - .Options(IntSliderOptions() - .Min(1) - .Max(5) - .DefaultValue(1) - .Format("%dx") - .Tooltip( - "Changes the speed of sections of text that normally are paced slower than the text surrounding it." - ) - ); - AddWidget(path, "Match Normal Text", WIDGET_BUTTON) - .Callback([](WidgetInfo& info) { - CVarSetInteger(CVAR_ENHANCEMENT("SlowTextSpeed"), CVarGetInteger(CVAR_ENHANCEMENT("TextSpeed"), 1)); - }) - .Options(ButtonOptions().Tooltip( - "Makes the speed of the slow text match the normal text speed above." - )); - AddWidget(path, "Skip Pickup Messages", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FastDrops")) - .Options(CheckboxOptions().Tooltip( - "Skip Pickup Messages for new Consumable Items and Bottle Swipes." - )); - AddWidget(path, "Better Owl", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BetterOwl")) - .Options(CheckboxOptions().Tooltip( - "The default response to Kaepora Gaebora is always that you understood what he said." - )); + .Options(IntSliderOptions().Min(1).Max(5).DefaultValue(1).Format("%dx").Tooltip( + "Changes the speed of sections of text that normally are paced slower than the text surrounding it.")); path.column = SECTION_COLUMN_2; - AddWidget(path, "Gameplay", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Skip Save Confirmation", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("SkipSaveConfirmation")) - .Options(CheckboxOptions().Tooltip("Skip the \"Game Saved\" confirmation screen.")); - AddWidget(path, "Biggoron Forge Time: %d days", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("ForgeTime")) - .Options(IntSliderOptions() - .Min(0) - .Max(3) - .DefaultValue(3) - .Format("%d days") - .Tooltip( - "Allows you to change the number of days it takes for " - "Biggoron to forge the Biggoron's Sword." - ) - ); - AddWidget(path, "Remember Save Location", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("RememberSaveLocation")) + AddWidget(path, "Animations", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Faster Heavy Block Lift", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FasterHeavyBlockLift")) + .Options(CheckboxOptions().Tooltip("Speeds up lifting Silver Rocks and Obelisks.")); + AddWidget(path, "Fast Chests", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FastChests")) + .Options(CheckboxOptions().Tooltip("Makes Link always kick the chest to open it, instead of doing the longer " + "chest opening animation for major items.")); + AddWidget(path, "Skip Water Take Breath Animation", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("SkipSwimDeepEndAnim")) + .Options(CheckboxOptions().Tooltip("Skips Link's taking breath animation after coming up from water. " + "This setting does not interfere with getting items from underwater.")); + AddWidget(path, "Vine/Ladder Climb Speed +%d", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("ClimbSpeed")) + .Options(IntSliderOptions().Min(0).Max(12).DefaultValue(0).Format("+%d")); + AddWidget(path, "Block Pushing Speed +%d", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("FasterBlockPush")) + .Options(IntSliderOptions().Min(0).Max(5).DefaultValue(0).Format("+%d")); + AddWidget(path, "Crawl Speed %dx", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("CrawlSpeed")) + .Options(IntSliderOptions().Min(1).Max(4).DefaultValue(1).Format("%dx")); + AddWidget(path, "King Zora Speed: %.2fx", WIDGET_CVAR_SLIDER_FLOAT) + .CVar(CVAR_ENHANCEMENT("MweepSpeed")) + .Options(FloatSliderOptions().Min(0.1f).Max(5.0f).DefaultValue(1.0f).Format("%.2fx")); + + path.column = SECTION_COLUMN_3; + AddWidget(path, "Misc", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Skip Child Stealth", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("TimeSavers.SkipChildStealth")) .Options(CheckboxOptions().Tooltip( - "When loading a save, places Link at the last entrance he went through.\n" - "This doesn't work if the save was made in grottos, fairy fountains, or dungeons." - )); - AddWidget(path, "Navi Timer Resets", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("ResetNaviTimer")) + "The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards.")); + AddWidget(path, "Skip Tower Escape", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("TimeSavers.SkipTowerEscape")) + .Options(CheckboxOptions().Tooltip("Skip the tower escape sequence between Ganondorf and Ganon.")); + AddWidget(path, "Skip Scarecrow's Song", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("InstantScarecrow")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = + IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_SKIP_SCARECROWS_SONG); + info.options->disabledTooltip = "This setting is forcefully enabled because a randomized " + "save file with the option \"Skip Scarecrow Song\" is currently loaded."; + }) .Options(CheckboxOptions().Tooltip( - "Resets the Navi timer on scene change. If you have already talked to her, " - "she will try and talk to you again, instead of needing a save warp or death." - )); + "Pierre appears when an Ocarina is pulled out. Requires learning the Scarecrow's Song first.")); + AddWidget(path, "Faster Rupee Accumulator", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FasterRupeeAccumulator")) + .Options(CheckboxOptions().Tooltip("Causes your Wallet to fill and empty faster when you gain or lose money.")); AddWidget(path, "No Skulltula Freeze", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("SkulltulaFreeze")) .PreFunc([](WidgetInfo& info) { info.options->disabled = IS_RANDO && GameInteractor::IsSaveLoaded(true); - info.options->disabledTooltip = + info.options->disabledTooltip = "This setting is disabled because a randomizer savefile is loaded. Please use the " "\"Skip Get Item Animation\" option within the randomizer enhancements instead."; }) .Options(CheckboxOptions().Tooltip( "Stops the game from freezing the player when picking up Gold Skulltula Tokens. Does not" - "apply in randomizer savefiles." - )); - AddWidget(path, "Ask to Equip New Items", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("AskToEquip")) - .Options(CheckboxOptions().Tooltip( - "Adds a prompt to equip newly-obtained Swords, Shields, and Tunics." - )); + "apply in randomizer savefiles.")); + AddWidget(path, "Skip Save Confirmation", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("SkipSaveConfirmation")) + .Options(CheckboxOptions().Tooltip("Skip the \"Game Saved\" confirmation screen.")); AddWidget(path, "Link as Default File Name", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("LinkDefaultName")) - .Options(CheckboxOptions().Tooltip( - "Allows you to have \"Link\" as a premade file name." - )); - AddWidget(path, "Quit Fishing At Door", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("QuitFishingAtDoor")) - .Options(CheckboxOptions().Tooltip( - "Fisherman asks if you want to quit at the door if you try to leave the Fishing Pond " - "while still holding the Fishing Rod." - )); - AddWidget(path, "Time Travel with Song of Time", WIDGET_CVAR_COMBOBOX) - .CVar(CVAR_ENHANCEMENT("TimeTravel")) - .Options(ComboboxOptions() - .ComboMap(timeTravelOptions) - .DefaultIndex(0) - .Tooltip( - "Allows Link to freely change age by playing the Song of Time.\n" - "Time Blocks can still be used properly.\n\n" - "Requirements:\n" - " - Obtained the Ocarina of Time (depends on selection)\n" - " - Obtained the Song of Time\n" - " - Obtained the Master Sword\n" - " - Not within range of a Time Block\n" - " - Not within range of Ocarina Playing spots." - ) - ); - AddWidget(path, "Pause Warp", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("PauseWarp")) - .Options(CheckboxOptions().Tooltip( - "Selection of warp song in pause menu initiates a warp. Disables song playback." - )); - AddWidget(path, "Skip Scarecrow's Song", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("InstantScarecrow")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_SKIP_SCARECROWS_SONG); - info.options->disabledTooltip = "This setting is forcefully enabled because a randomized " - "save file with the option \"Skip Scarecrow Song\" is currently loaded."; - }) - .Options(CheckboxOptions().Tooltip( - "Pierre appears when an Ocarina is pulled out. Requires learning the Scarecrow's Song first." - )); - AddWidget(path, "Time of Day", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Nighttime GS Always Spawn", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("NightGSAlwaysSpawn")) - .Options(CheckboxOptions().Tooltip( - "Nighttime Skulltulas will spawn during both day and night." - )); - AddWidget(path, "Dampe Appears All Night", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DampeAllNight")) - .Options(CheckboxOptions().Tooltip( - "Makes Dampe appear anytime during the night, not just his usual working hours." - )); - AddWidget(path, "Exit Market at Night", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("MarketSneak")) - .Options(CheckboxOptions().Tooltip( - "Allows exiting Hyrule Castle Market Town to Hyrule Field at night by speaking to the guard " - "next to the gate." - )); - AddWidget(path, "Shops and Games Always Open", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("OpenAllHours")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_LOCK_OVERWORLD_DOORS).Is(RO_GENERIC_ON); - }) - .Options(CheckboxOptions().Tooltip( - "Shops and Minigames are open both day and night. Requires a scene reload to take effect." - ).DisabledTooltip( - "This is not compatible with the Locked Overworld Doors Randomizer option." - )); - path.column = SECTION_COLUMN_3; - AddWidget(path, "Animations", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "King Zora Speed: %.2fx", WIDGET_CVAR_SLIDER_FLOAT) - .CVar(CVAR_ENHANCEMENT("MweepSpeed")) - .Options(FloatSliderOptions() - .Min(0.1f) - .Max(5.0f) - .DefaultValue(1.0f) - .Format("%.2fx") - ); - AddWidget(path, "Vine/Ladder Climb Speed +%d", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("ClimbSpeed")) - .Options(IntSliderOptions() - .Min(0) - .Max(12) - .DefaultValue(0) - .Format("+%d") - ); - AddWidget(path, "Block Pushing Speed +%d", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("FasterBlockPush")) - .Options(IntSliderOptions() - .Min(0) - .Max(5) - .DefaultValue(0) - .Format("+%d") - ); - AddWidget(path, "Crawl Speed %dx", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("CrawlSpeed")) - .Options(IntSliderOptions() - .Min(1) - .Max(4) - .DefaultValue(1) - .Format("%dx") - ); - AddWidget(path, "Faster Heavy Block Lift", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FasterHeavyBlockLift")) - .Options(CheckboxOptions().Tooltip( - "Speeds up lifting Silver Rocks and Obelisks." - )); - AddWidget(path, "Fast Ocarina Playback", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FastOcarinaPlayback")) - .Options(CheckboxOptions().Tooltip( - "Skip the part where the Ocarina Playback is called when you play a song." - )); - AddWidget(path, "Skip Magic Arrow Equip Animation", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("SkipArrowAnimation")); - AddWidget(path, "Faster Farore's Wind", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FastFarores")) - .Options(CheckboxOptions().Tooltip("Greatly decreases cast time of Farore's Wind magic spell.")); - AddWidget(path, "Fast Chests", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FastChests")) - .Options(CheckboxOptions().Tooltip( - "Makes Link always kick the chest to open it, instead of doing the longer " - "chest opening animation for major items." - )); - AddWidget(path, "Skip Water Take Breath Animation", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("SkipSwimDeepEndAnim")) - .Options(CheckboxOptions().Tooltip( - "Skips Link's taking breath animation after coming up from water. " - "This setting does not interfere with getting items from underwater." - )); - AddWidget(path, "Play Zelda's Lullaby to Open Sleeping Waterfall", WIDGET_CVAR_COMBOBOX) - .CVar(CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_SLEEPING_WATERFALL).Is(RO_WATERFALL_OPEN); - info.options->disabledTooltip = "This setting is forcefully enabled because a randomizer savefile with \"Sleeping Waterfall: Open\" is loaded."; - }) - .Options(ComboboxOptions() - .ComboMap(sleepingWaterfallOptions) - .DefaultIndex(WATERFALL_ALWAYS) - .Tooltip( - "Always: Link must always play Zelda's Lullaby to open the waterfall entrance to Zora's Domain.\n" - "Once: Link only needs to play Zelda's Lullaby once to open the waterfall; after that, it stays " - "open permanently.\n" - "Never: Link never needs to play Zelda's Lullaby to open the waterfall. He only needs to have " - "learned it and have an Ocarina." - ) - ); + .Options(CheckboxOptions().Tooltip("Allows you to have \"Link\" as a premade file name.")); + AddWidget(path, "Biggoron Forge Time: %d days", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("ForgeTime")) + .Options(IntSliderOptions().Min(0).Max(3).DefaultValue(3).Format("%d days").Tooltip( + "Allows you to change the number of days it takes for " + "Biggoron to forge the Biggoron's Sword.")); + // Graphics path.sidebarName = "Graphics"; AddSidebarEntry("Enhancements", path.sidebarName, 3); path.column = SECTION_COLUMN_1; @@ -805,71 +439,23 @@ void SohMenu::AddMenuEnhancements() { "Disables Grottos rotating with the Camera. To be used in conjuction with mods that want to " "replace grottos with 3D objects." )); + AddWidget(path, "Ingame Text Spacing: %d", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("TextSpacing")) + .Options(IntSliderOptions().Min(4).Max(6).DefaultValue(6).Tooltip( + "Space between text characters (useful for HD font textures).")); - - AddWidget(path, "UI", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Minimal UI", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("MinimalUI")) + AddWidget(path, "Models & Textures", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Disable LOD", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DisableLOD")) .Options(CheckboxOptions().Tooltip( - "Hides most of the UI when not needed.\n" - "NOTE: Doesn't activate until scene transition." - )); - AddWidget(path, "Disable Hot/Underwater Warning Text", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DisableTunicWarningText")) + "Turns off the Level of Detail setting, making models use their Higher-Poly variants at any distance.")); + AddWidget(path, "Enemy Health Bars", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("EnemyHealthBar")) + .Options(CheckboxOptions().Tooltip("Renders a health bar for Enemies when Z-Targeted.")); + AddWidget(path, "Enable 3D Dropped Items/Projectiles", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("NewDrops")) .Options(CheckboxOptions().Tooltip( - "Disables warning text when you don't have on the Goron/Zora Tunic " - "in Hot/Underwater conditions." - )); - AddWidget(path, "Remember Minimap State Between Areas", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("RememberMapToggleState")) - .Options(CheckboxOptions().Tooltip( - "Preverse the minimap visibility state when going between areas rather than default it to \"on\" " - "when going through loading zones." - )); - AddWidget(path, "Visual Stone of Agony", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("VisualAgony")) - .Options(CheckboxOptions().Tooltip( - "Displays an icon and plays a sound when Stone of Agony should be activated, for those without rumble." - )); - AddWidget(path, "Disable HUD Heart Animations", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("NoHUDHeartAnimation")) - .Options(CheckboxOptions().Tooltip( - "Disables the Beating Animation of the Hearts on the HUD." - )); - AddWidget(path, "Glitch line-up tick", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DrawLineupTick")) - .Options(CheckboxOptions().Tooltip( - "Displays a tick in the top center of the screen to help with glitch line-ups in SoH, since traditional " - "UI based line-ups do not work outside of 4:3" - )); - AddWidget(path, "Disable Black Bar Letterboxes", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DisableBlackBars")) - .Options(CheckboxOptions().Tooltip( - "Disables Black Bar Letterboxes during cutscenes and Z-Targeting. NOTE: there may be minor visual " - "glitches that were covered up by the black bars. Please disable this setting before reporting a bug." - )); - AddWidget(path, "Dynamic Wallet Icon", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DynamicWalletIcon")) - .Options(CheckboxOptions().Tooltip( - "Changes the Rupee in the Wallet icon to match the wallet size you currently have." - )); - AddWidget(path, "Always Show Dungeon Entrances", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("AlwaysShowDungeonMinimapIcon")) - .Options(CheckboxOptions().Tooltip( - "Always shows dungeon entrance icons on the Minimap." - )); - AddWidget(path, "More Info in File Select", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FileSelectMoreInfo")) - .Options(CheckboxOptions().Tooltip( - "Shows what items you have collected in the File Select screen, like in N64 Randomizer." - )); - AddWidget(path, "Better Ammo Rendering in Pause Menu", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BetterAmmoRendering")) - .Options(CheckboxOptions().Tooltip( - "Ammo counts in the pause menu will work correctly regardless of the position of items in the Inventory." - )); - - AddWidget(path, "Models", WIDGET_SEPARATOR_TEXT); + "Replaces most 2D items and projectiles on the overworld with their equivalent 3D models.")); AddWidget(path, "Invisible Bunny Hood", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("HideBunnyHood")) .Options(CheckboxOptions().Tooltip( @@ -898,11 +484,6 @@ void SohMenu::AddMenuEnhancements() { "Scales all of the Adult Equipment, as well as moving some a bit, to fit on Child Link better. May " "not work properly with some mods." )); - AddWidget(path, "Enable 3D Dropped Items/Projectiles", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("NewDrops")) - .Options(CheckboxOptions().Tooltip( - "Replaces most 2D items and projectiles on the overworld with their equivalent 3D models." - )); AddWidget(path, "Show Gauntlets in First Person", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("FirstPersonGauntlets")) .Options(CheckboxOptions().Tooltip( @@ -910,133 +491,63 @@ void SohMenu::AddMenuEnhancements() { )); AddWidget(path, "Show Chains on Both Sides of Locked Doors", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("ShowDoorLocksOnBothSides")); - - path.column = SECTION_COLUMN_2; - AddWidget(path, "Textures", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Chest Size & Texture Matches Contents", WIDGET_CVAR_COMBOBOX) - .CVar(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents")) - .Callback([](WidgetInfo& info) { - if (CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents"), CSMC_DISABLED) == CSMC_DISABLED) { - CVarSetInteger(CVAR_ENHANCEMENT("ChestSizeDependsStoneOfAgony"), 0); - } - }) - .Options(ComboboxOptions() - .ComboMap(chestStyleMatchesContentsOptions) - .DefaultIndex(CSMC_DISABLED) - .Tooltip( - "Chest sizes and textures are changed to help identify the item inside.\n" - " - Major items: Large gold chests\n" - " - Lesser items: Large brown chests\n" - " - Junk items: Small brown chests\n" - " - Small keys: Small silver chests\n" - " - Boss keys: Vanilla size and texture\n" - " - Skulltula Tokens: Small skulltula chest\n" - "\n" - "NOTE: Textures will not apply if you are using a mod pack with a custom chest model." - ) - ); - AddWidget(path, "Chests of Agony", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("ChestSizeDependsStoneOfAgony")) - .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchesContents"), CSMC_DISABLED); - }) - .Options(CheckboxOptions().Tooltip( - "Only change the size/texture of chests if you have the Stone of Agony." - )); AddWidget(path, "Color Temple of Time's Medallions", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("ToTMedallionsColors")) - .Callback([](WidgetInfo& info) { - PatchToTMedallions(); - }) + .Callback([](WidgetInfo& info) { PatchToTMedallions(); }) .Options(CheckboxOptions().Tooltip( "When Medallions are collected, the Medallion imprints around the Master Sword Pedestal in the Temple " - "of Time will become colored-in." - )); - AddWidget(path, "Fix Vanishing Paths", WIDGET_CVAR_COMBOBOX) - .CVar(CVAR_ENHANCEMENT("SceneSpecificDirtPathFix")) - .Callback([](WidgetInfo& info) { - if (gPlayState != NULL) { - UpdateDirtPathFixState(gPlayState->sceneNum); - } - }) - .Options(ComboboxOptions() - .ComboMap(zFightingOptions) - .DefaultIndex(ZFIGHT_FIX_DISABLED) - .Tooltip( - "Disabled: Paths vanish more the higher the resolution (Z-fighting is based on resolution)\n" - "Consistent: Certain paths vanish the same way in all resolutions\n" - "No Vanish: Paths do not vanish, Link seems to sink in to some paths\n" - "This might affect other decal effects\n" - ) - ); - AddWidget(path, "Text Spacing: %d", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("TextSpacing")) - .Options(IntSliderOptions() - .Min(4) - .Max(6) - .DefaultValue(6) - .Tooltip( - "Space between text characters (useful for HD font textures)." - ) - ); + "of Time will become colored-in.")); + + path.column = SECTION_COLUMN_2; + AddWidget(path, "UI", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Minimal UI", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("MinimalUI")) + .Options(CheckboxOptions().Tooltip("Hides most of the UI when not needed.\n" + "NOTE: Doesn't activate until scene transition.")); + AddWidget(path, "Disable Hot/Underwater Warning Text", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DisableTunicWarningText")) + .Options(CheckboxOptions().Tooltip("Disables warning text when you don't have on the Goron/Zora Tunic " + "in Hot/Underwater conditions.")); + AddWidget(path, "Remember Minimap State Between Areas", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("RememberMapToggleState")) + .Options(CheckboxOptions().Tooltip( + "Preverse the minimap visibility state when going between areas rather than default it to \"on\" " + "when going through loading zones.")); + AddWidget(path, "Visual Stone of Agony", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("VisualAgony")) + .Options(CheckboxOptions().Tooltip( + "Displays an icon and plays a sound when Stone of Agony should be activated, for those without rumble.")); + AddWidget(path, "Disable HUD Heart Animations", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("NoHUDHeartAnimation")) + .Options(CheckboxOptions().Tooltip("Disables the Beating Animation of the Hearts on the HUD.")); + AddWidget(path, "Glitch line-up tick", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DrawLineupTick")) + .Options(CheckboxOptions().Tooltip( + "Displays a tick in the top center of the screen to help with glitch line-ups in SoH, since traditional " + "UI based line-ups do not work outside of 4:3")); + AddWidget(path, "Disable Black Bar Letterboxes", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DisableBlackBars")) + .Options(CheckboxOptions().Tooltip( + "Disables Black Bar Letterboxes during cutscenes and Z-Targeting. NOTE: there may be minor visual " + "glitches that were covered up by the black bars. Please disable this setting before reporting a bug.")); + AddWidget(path, "Dynamic Wallet Icon", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DynamicWalletIcon")) + .Options(CheckboxOptions().Tooltip( + "Changes the Rupee in the Wallet icon to match the wallet size you currently have.")); + AddWidget(path, "Always Show Dungeon Entrances", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("AlwaysShowDungeonMinimapIcon")) + .Options(CheckboxOptions().Tooltip("Always shows dungeon entrance icons on the Minimap.")); + AddWidget(path, "More Info in File Select", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FileSelectMoreInfo")) + .Options(CheckboxOptions().Tooltip( + "Shows what items you have collected in the File Select screen, like in N64 Randomizer.")); + AddWidget(path, "Better Ammo Rendering in Pause Menu", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BetterAmmoRendering")) + .Options(CheckboxOptions().Tooltip( + "Ammo counts in the pause menu will work correctly regardless of the position of items in the Inventory.")); + AddWidget(path, "Enable Passage of Time on File Select", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("TimeFlowFileSelect")); - AddWidget(path, "Rendering", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Disable LOD", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DisableLOD")) - .Options(CheckboxOptions().Tooltip( - "Turns off the Level of Detail setting, making models use their Higher-Poly variants at any distance." - )); - AddWidget(path, "Increase Actor Draw Distance: %dx", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("DisableDrawDistance")) - .Callback([](WidgetInfo& info) { - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) <= 1) { - CVarSetInteger(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), 0); - } - }) - .Options(IntSliderOptions() - .Min(1) - .Max(5) - .DefaultValue(1) - .Format("%dx") - .Tooltip( - "Increases the range in which Actors/Objects are drawn." - ) - ); - AddWidget(path, "Kokiri Draw Distance", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DisableKokiriDrawDistance")) - .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) > 1; - }) - .Options(CheckboxOptions().Tooltip( - "The Kokiri are mystical beings that fade into view when approached. Enabling this will remove their " - "draw distance." - )); - AddWidget(path, "Widescreen Actor Culling", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("WidescreenActorCulling")) - .Options(CheckboxOptions().Tooltip( - "Adjusts the Horizontal Culling Plane to account for Widescreen Resolutions." - )); - AddWidget(path, "Cull Glitch Useful Actors", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("ExtendedCullingExcludeGlitchActors")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = !CVarGetInteger(CVAR_ENHANCEMENT("WidescreenActorCulling"), 0) && - CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) <= 1; - info.options->disabledTooltip = "Requires Actor Draw Distance to be increased or Widscreen Actor Culling to be enabled."; - }) - .Options(CheckboxOptions().Tooltip( - "Exclude Actors that are useful for Glitches from the extended culling ranges. Some actors may still draw " - "in the extended ranges, but will not \"update\" so that certain glitches that leverage the original " - "culling requirements will still work.\n\nThe following actors are excluded:\n" - " - White clothed Gerudos\n" - " - King Zora\n" - " - Gossip Stones\n" - " - Boulders\n" - " - Blue Warps\n" - " - Darunia\n" - " - Gold SKulltulas\n" - )); - - // TODO: Find a better home for these. path.column = SECTION_COLUMN_3; AddWidget(path, "Misc.", WIDGET_SEPARATOR_TEXT); AddWidget(path, "N64 Mode", WIDGET_CVAR_CHECKBOX) @@ -1049,163 +560,67 @@ void SohMenu::AddMenuEnhancements() { .Options(CheckboxOptions().Tooltip( "Remove the Darkness that appears when charging a Spin Attack" )); - + AddWidget(path, "Draw Distance", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Increase Actor Draw Distance: %dx", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("DisableDrawDistance")) + .Callback([](WidgetInfo& info) { + if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) <= 1) { + CVarSetInteger(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), 0); + } + }) + .Options(IntSliderOptions().Min(1).Max(5).DefaultValue(1).Format("%dx").Tooltip( + "Increases the range in which Actors/Objects are drawn.")); + AddWidget(path, "Kokiri Draw Distance", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DisableKokiriDrawDistance")) + .PreFunc( + [](WidgetInfo& info) { info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) > 1; }) + .Options(CheckboxOptions().Tooltip( + "The Kokiri are mystical beings that fade into view when approached. Enabling this will remove their " + "draw distance.")); + AddWidget(path, "Widescreen Actor Culling", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("WidescreenActorCulling")) + .Options( + CheckboxOptions().Tooltip("Adjusts the Horizontal Culling Plane to account for Widescreen Resolutions.")); + AddWidget(path, "Cull Glitch Useful Actors", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("ExtendedCullingExcludeGlitchActors")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = !CVarGetInteger(CVAR_ENHANCEMENT("WidescreenActorCulling"), 0) && + CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) <= 1; + info.options->disabledTooltip = + "Requires Actor Draw Distance to be increased or Widscreen Actor Culling to be enabled."; + }) + .Options(CheckboxOptions().Tooltip( + "Exclude Actors that are useful for Glitches from the extended culling ranges. Some actors may still draw " + "in the extended ranges, but will not \"update\" so that certain glitches that leverage the original " + "culling requirements will still work.\n\nThe following actors are excluded:\n" + " - White clothed Gerudos\n" + " - King Zora\n" + " - Gossip Stones\n" + " - Boulders\n" + " - Blue Warps\n" + " - Darunia\n" + " - Gold SKulltulas\n")); + path.sidebarName = "Items"; - AddSidebarEntry("Enhancements", path.sidebarName, 2); + AddSidebarEntry("Enhancements", path.sidebarName, 3); path.column = SECTION_COLUMN_1; - AddWidget(path, "Controls", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Equipment", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Equip Items on Dpad", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("DpadEquips")) .Options(CheckboxOptions().Tooltip( "Equip items and equipment on the D-Pad. If used with \"D-Pad on Pause Screen\", you must " - "hold C-Up to equip instead of navgiate." - )); - AddWidget(path, "Instant Putaway", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("InstantPutaway")) + "hold C-Up to equip instead of navgiate.")); + AddWidget(path, "Assignable Tunics and Boots", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("AssignableTunicsAndBoots")) + .Options(CheckboxOptions().Tooltip("Allows equipping the Tunics and Boots to C-Buttons/D-Pad.")); + // TODO: Revist strength toggle, it's currently separate but should probably be locked behind the + // Equipment toggle settings or be absorbed by it completely. + AddWidget(path, "Equipment Toggle", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("EquipmentCanBeRemoved")) .Options(CheckboxOptions().Tooltip( - "Allow Link to put items away without having to wait around." - )); - AddWidget(path, "Instant Boomerang Recall", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FastBoomerang")) - .Options(CheckboxOptions().Tooltip( - "Instantly return the boomerang to Link by pressing its item button while " - "it's in the air." - )); - AddWidget(path, "Prevent Dropped Ocarina Inputs", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DpadNoDropOcarinaInput")) - .Options(CheckboxOptions().Tooltip( - "Prevent dropping inputs when playing the Ocarina too quickly." - )); - AddWidget(path, "Masks", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Bunny Hood Effect", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("MMBunnyHood")) - .Options(CheckboxOptions().Tooltip( - "Wearing the Bunny Hood grants a speed increase link in Majora's Mask. " - "The longer jump option is not accounted for in Randomizer logic.\n\n" - "Also disables NPC's reactions to wearing the Bunny Hood." - )); - AddWidget(path, "Masks Equippable as Adult", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("AdultMasks")) - .Options(CheckboxOptions().Tooltip( - "Allows masks to be equipped normally from the pause menu as adult." - )); - AddWidget(path, "Persistent Masks", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("PersistentMasks")) - .Options(CheckboxOptions().Tooltip( - "Stops masks from automatically unequipping on certain situations:\n" - "- When entering a new scene\n" - "- When not in any C button or the D-Pad\n" - "- When saving and quitting\n" - "- When dying\n" - "- When traveling thru time (if \"Masks Equippable as Adult\" is activated)." - )); - AddWidget(path, "Mask Select in Inventory", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("MaskSelect")) - .Options(CheckboxOptions().Tooltip( - "After completing the mask trading sub-quest, press A and any direction on the mask " - "slog to change masks" - )); - AddWidget(path, "Item Count Messages", WIDGET_SEPARATOR_TEXT); - int numOptions = ARRAY_COUNT(itemCountMessageCVars); - bool allItemCountsChecked = false; - AddWidget(path, "All", WIDGET_CHECKBOX) - .ValuePointer(&allItemCountsChecked) - .PreFunc([](WidgetInfo& info) { - int numOptions = ARRAY_COUNT(itemCountMessageCVars); - *std::get(info.valuePointer) = std::all_of(itemCountMessageCVars, itemCountMessageCVars + numOptions, - [](const char* cvar) { return CVarGetInteger(cvar, 0); }); - }) - .Callback([](WidgetInfo& info) { - int32_t newValue = *std::get(info.valuePointer) ? 1 : 0; - int numOptions = ARRAY_COUNT(itemCountMessageCVars); - std::for_each(itemCountMessageCVars, itemCountMessageCVars + numOptions, - [newValue](const char* cvar) { CVarSetInteger(cvar, newValue); }); - - Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); - }); - for (int i = 0; i < numOptions; i++) { - AddWidget(path, itemCountMessageOptions[i], WIDGET_CVAR_CHECKBOX) - .CVar(itemCountMessageCVars[i]); - } - path.column = SECTION_COLUMN_2; - AddWidget(path, "Equipment", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Deku Nuts Explode Bombs", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("NutsExplodeBombs")) - .Options(CheckboxOptions().Tooltip( - "Make Deku Nuts explode Bombs, similar to how they interact with Bombchus. " - "This does not affect Bombflowers." - )); - AddWidget(path, "Equip Multiple Arrows at Once", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("SeparateArrows")) - .Options(CheckboxOptions().Tooltip( - "Allow the Bow and Magic Arrows to be equipped at the same time on different slots. " - "NOTE: This will disable the behavior of the 'Equip Dupe' glitch." - )); - AddWidget(path, "Bow and Child/Slingshot as Adult", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BowSlingshotAmmoFix")) - .Options(CheckboxOptions().Tooltip( - "Allows Child to use a Bow with Arrows.\n" - "Allows Adult to use a Slingshot with Seeds.\n\n" - "Requires glitches or the 'Timeless Equipment' cheat to equip." - )); - AddWidget(path, "Better Farore's Wind", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BetterFarore")) - .Options(CheckboxOptions().Tooltip( - "Helps FW persist between ages, gives Child and Adult separate FW points, and can " - "be used in more places." - )); - AddWidget(path, "Remove Explosive Limit", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("RemoveExplosiveLimit")) - .Options(CheckboxOptions().Tooltip( - "Removes the cap of 3 active explosives being deployed at once." - )); - AddWidget(path, "Static Explosion Radius", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("StaticExplosionRadius")) - .Options(CheckboxOptions().Tooltip( - "Explosions are now a static size, like in Majora's Mask and OoT3D. Makes Bombchu " - "hovering much easier." - )); - AddWidget(path, "Prevent Bombchus Forcing Firs-Person", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("DisableFirstPersonChus")) - .Options(CheckboxOptions().Tooltip( - "Prevent Bombchus from forcing the camera into first-person mode when released." - )); - AddWidget(path, "Better Bombchu Shopping", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BetterBombchuShopping")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = IS_RANDO && GameInteractor::IsSaveLoaded(true); - info.options->disabledTooltip = "This setting is forcefully enabled when you are playing a randomizer."; - }) - .Options(CheckboxOptions().Tooltip( - "Bombchus do not sell out when bought, and a 10 pack of Bombchus costs 99 rupees " - "instead of 100." - )); - AddWidget(path, "Aiming Reticle for the Bow/Slingshot", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BowReticle")) - .Options(CheckboxOptions().Tooltip( - "Aiming with a Bow or Slingshot will display a reticle as with the Hookshot " - "when the projectile is ready to fire." - )); - AddWidget(path, "Aim Boomerang in First-Person Mode", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BoomerangFirstPerson")) - .Callback([](WidgetInfo& info) { - if (!CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { - CVarSetInteger(CVAR_ENHANCEMENT("BoomerangReticle"), 0); - } - }) - .Options(CheckboxOptions().Tooltip( - "Change aiming for the Boomerang from Third-Person to First-Person to see past Link's head." - )); - AddWidget(path, "Aiming Reticle for Boomerang", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BoomerangFirstPerson")) - .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0) != 0; - }) - .Options(CheckboxOptions().Tooltip( - "Aiming with the Boomerang will display a reticle as with the Hookshot." - )); - AddWidget(path, "Allow Strength Equipement to be Toggled", WIDGET_CVAR_CHECKBOX) + "Allows equipment to be removed by toggling it off on\n the equipment subscreen.")); + AddWidget(path, "Allow Strength Equipment to be Toggled", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("ToggleStrength")) .Callback([](WidgetInfo& info) { if (!CVarGetInteger(CVAR_ENHANCEMENT("ToggleStrength"), 0)) { @@ -1215,305 +630,398 @@ void SohMenu::AddMenuEnhancements() { .Options(CheckboxOptions().Tooltip( "Allows Strength to be toggled on and off by pressing A on the Strength Upgrade " "in the Equipment Subscreen of the Pause Menu. This allows performing some glitches " - "that require the player to not have Strength." - )); + "that require the player to not have Strength.")); + AddWidget(path, "Sword Toggle Options", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("SwordToggle")) + .PreFunc( + [](WidgetInfo& info) { info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("EquipmentCanBeRemoved"), 0) == 0; }) + .Options(ComboboxOptions() + .ComboMap(swordToggleModes) + .DefaultIndex(SWORD_TOGGLE_NONE) + .Tooltip("Introduces Options for unequipping Link's sword\n\n" + "None: Only Biggoron's Sword/Giant's Knife can be toggled. Doing so will equip the " + "Master Sword.\n\n" + "Child Toggle: This will allow for completely unequipping any sword as child link.\n\n" + "Both Ages: Any sword can be unequipped as either age. This may lead to swordless " + "glitches as Adult.")); + AddWidget(path, "Ask to Equip New Items", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("AskToEquip")) + .Options(CheckboxOptions().Tooltip("Adds a prompt to equip newly-obtained Swords, Shields, and Tunics.")); + + AddWidget(path, "Ocarina", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Prevent Dropped Ocarina Inputs", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DpadNoDropOcarinaInput")) + .Options(CheckboxOptions().Tooltip("Prevent dropping inputs when playing the Ocarina too quickly.")); + AddWidget(path, "Fast Ocarina Playback", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FastOcarinaPlayback")) + .Options(CheckboxOptions().Tooltip("Skip the part where the Ocarina Playback is called when you play a song.")); + AddWidget(path, "Time Travel with Song of Time", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("TimeTravel")) + .Options(ComboboxOptions() + .ComboMap(timeTravelOptions) + .DefaultIndex(0) + .Tooltip("Allows Link to freely change age by playing the Song of Time.\n" + "Time Blocks can still be used properly.\n\n" + "Requirements:\n" + " - Obtained the Ocarina of Time (depends on selection)\n" + " - Obtained the Song of Time\n" + " - Obtained the Master Sword\n" + " - Not within range of a Time Block\n" + " - Not within range of Ocarina Playing spots.")); + + AddWidget(path, "Masks", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Bunny Hood Effect", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("MMBunnyHood")) + .Options(CheckboxOptions().Tooltip("Wearing the Bunny Hood grants a speed increase link in Majora's Mask. " + "The longer jump option is not accounted for in Randomizer logic.\n\n" + "Also disables NPC's reactions to wearing the Bunny Hood.")); + AddWidget(path, "Masks Equippable as Adult", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("AdultMasks")) + .Options(CheckboxOptions().Tooltip("Allows masks to be equipped normally from the pause menu as adult.")); + AddWidget(path, "Persistent Masks", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("PersistentMasks")) + .Options( + CheckboxOptions().Tooltip("Stops masks from automatically unequipping on certain situations:\n" + "- When entering a new scene\n" + "- When not in any C button or the D-Pad\n" + "- When saving and quitting\n" + "- When dying\n" + "- When traveling thru time (if \"Masks Equippable as Adult\" is activated).")); + AddWidget(path, "Mask Select in Inventory", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("MaskSelect")) + .Options(CheckboxOptions().Tooltip( + "After completing the mask trading sub-quest, press A and any direction on the mask " + "slog to change masks")); + + path.column = SECTION_COLUMN_2; + AddWidget(path, "Explosives", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Deku Nuts Explode Bombs", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("NutsExplodeBombs")) + .Options(CheckboxOptions().Tooltip("Make Deku Nuts explode Bombs, similar to how they interact with Bombchus. " + "This does not affect Bombflowers.")); + AddWidget(path, "Remove Explosive Limit", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("RemoveExplosiveLimit")) + .Options(CheckboxOptions().Tooltip("Removes the cap of 3 active explosives being deployed at once.")); + AddWidget(path, "Static Explosion Radius", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("StaticExplosionRadius")) + .Options(CheckboxOptions().Tooltip( + "Explosions are now a static size, like in Majora's Mask and OoT3D. Makes Bombchu " + "hovering much easier.")); + AddWidget(path, "Prevent Bombchus Forcing First-Person", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DisableFirstPersonChus")) + .Options(CheckboxOptions().Tooltip( + "Prevent Bombchus from forcing the camera into first-person mode when released.")); + AddWidget(path, "Better Bombchu Shopping", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BetterBombchuShopping")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = IS_RANDO && GameInteractor::IsSaveLoaded(true); + info.options->disabledTooltip = "This setting is forcefully enabled when you are playing a randomizer."; + }) + .Options( + CheckboxOptions().Tooltip("Bombchus do not sell out when bought, and a 10 pack of Bombchus costs 99 rupees " + "instead of 100.")); + + AddWidget(path, "Bow / Slingshot", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Equip Multiple Arrows at Once", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("SeparateArrows")) + .Options(CheckboxOptions().Tooltip( + "Allow the Bow and Magic Arrows to be equipped at the same time on different slots. " + "NOTE: This will disable the behavior of the 'Equip Dupe' glitch.")); + AddWidget(path, "Skip Magic Arrow Equip Animation", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("SkipArrowAnimation")); // TODO: See if a Callback could be registered to avoid the need to reload scenes for the next two options. AddWidget(path, "Blue Fire Arrows", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("BlueFireArrows")) .PreFunc([](WidgetInfo& info) { - info.options->disabled = OTRGlobals::Instance->gRandoContext->GetOption(RSK_BLUE_FIRE_ARROWS).Is(RO_GENERIC_ON); + info.options->disabled = + OTRGlobals::Instance->gRandoContext->GetOption(RSK_BLUE_FIRE_ARROWS).Is(RO_GENERIC_ON); info.options->disabledTooltip = "This setting is forcefully enabled because a randomized savefile with " - "\"Blue Fire Arrows\" is currently loaded."; + "\"Blue Fire Arrows\" is currently loaded."; }) .Options(CheckboxOptions().Tooltip( - "Allows Ice Arrows to melt Red Ice. May require a room reload if toggled during gameplay." - )); + "Allows Ice Arrows to melt Red Ice. May require a room reload if toggled during gameplay.")); AddWidget(path, "Sunlight Arrows", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("SunlightArrows")) .PreFunc([](WidgetInfo& info) { - info.options->disabled = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SUNLIGHT_ARROWS).Is(RO_GENERIC_ON); + info.options->disabled = + OTRGlobals::Instance->gRandoContext->GetOption(RSK_SUNLIGHT_ARROWS).Is(RO_GENERIC_ON); info.options->disabledTooltip = "This setting is forcefully enabled because a randomized savefile with " - "\"Sunlight Arrows\" enabled is currently loaded."; + "\"Sunlight Arrows\" enabled is currently loaded."; }) .Options(CheckboxOptions().Tooltip( - "Allows Light Arrows to activate Sun Switches. May require a room reload if toggled during gameplay." - )); + "Allows Light Arrows to activate Sun Switches. May require a room reload if toggled during gameplay.")); + AddWidget(path, "Bow and Child/Slingshot as Adult", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BowSlingshotAmmoFix")) + .Options(CheckboxOptions().Tooltip("Allows Child to use a Bow with Arrows.\n" + "Allows Adult to use a Slingshot with Seeds.\n\n" + "Requires glitches or the 'Timeless Equipment' cheat to equip.")); + AddWidget(path, "Aiming Reticle for the Bow/Slingshot", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BowReticle")) + .Options(CheckboxOptions().Tooltip("Aiming with a Bow or Slingshot will display a reticle as with the Hookshot " + "when the projectile is ready to fire.")); + + path.column = SECTION_COLUMN_3; + AddWidget(path, "Hookshot", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Targetable Hookshot Reticle", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("HookshotableReticle")) + .Options(CheckboxOptions().Tooltip( + "Makes the Hookshot Reticle use a different color when aiming at Hookshotable Collision.")); + + AddWidget(path, "Boomerang", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Instant Boomerang Recall", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FastBoomerang")) + .Options(CheckboxOptions().Tooltip("Instantly return the boomerang to Link by pressing its item button while " + "it's in the air.")); + AddWidget(path, "Aim Boomerang in First-Person Mode", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BoomerangFirstPerson")) + .Callback([](WidgetInfo& info) { + if (!CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + CVarSetInteger(CVAR_ENHANCEMENT("BoomerangReticle"), 0); + } + }) + .Options(CheckboxOptions().Tooltip( + "Change aiming for the Boomerang from Third-Person to First-Person to see past Link's head.")); + AddWidget(path, "Aiming Reticle for Boomerang", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BoomerangFirstPerson")) + .PreFunc( + [](WidgetInfo& info) { info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0) != 0; }) + .Options(CheckboxOptions().Tooltip("Aiming with the Boomerang will display a reticle as with the Hookshot.")); + + AddWidget(path, "Magic Spells", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Better Farore's Wind", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BetterFarore")) + .Options(CheckboxOptions().Tooltip( + "Helps FW persist between ages, gives Child and Adult separate FW points, and can " + "be used in more places.")); + AddWidget(path, "Faster Farore's Wind", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FastFarores")) + .Options(CheckboxOptions().Tooltip("Greatly decreases cast time of Farore's Wind magic spell.")); + + // Fixes + path.sidebarName = "Fixes"; + AddSidebarEntry("Enhancements", path.sidebarName, 3); + path.column = SECTION_COLUMN_1; + AddWidget(path, "Gameplay Fixes", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Fix the Gravedigging Tour Glitch", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("GravediggingTourFix")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = IS_RANDO && GameInteractor::IsSaveLoaded(true); + info.options->disabledTooltip = "This setting is always enabled in randomized save files."; + }) + .Options(CheckboxOptions().Tooltip( + "Fixes a bug where the Gravedigging Tour Heart Piece disappears if the area reloads.")); + AddWidget(path, "Fix Raised Floor Switches", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixFloorSwitches")) + .Options(CheckboxOptions().Tooltip( + "Fixes the two raised floor switches, the one in Forest Temple Basement and the one at the top of Fire " + "Temple. This will lower them, making activating them easier.")); + AddWidget(path, "Fix Zora Hint Dialogue", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixZoraHintDialogue")) + .Options(CheckboxOptions().Tooltip( + "Fixes one Zora's dialogue giving a hint about bringing Ruto's Letter to King Zora to properly occur " + "before moving King Zora rather than after.")); + AddWidget(path, "Fix Falling from Vine Edges", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixVineFall")) + .Options( + CheckboxOptions().Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges.")); + AddWidget(path, "Fix Bush Item Drops", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BushDropFix")) + .Options(CheckboxOptions().Tooltip( + "Fixes the bushes to drop items correctly rather than spawning undefined items.")); + AddWidget(path, "Fix Enemies not Spawning Near Water", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("EnemySpawnsOverWaterboxes")) + .Options(CheckboxOptions().Tooltip( + "Causes respanwing enemies, like Stalchildren, to appear on land near bodies of water. " + "Fixes an incorrect calculation that acted like water underneath ground was above it.")); + AddWidget(path, "Fix Poacher's Saw Softlock", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixSawSoftlock")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("SkipText"), 0) == 1; + info.options->disabledTooltip = "This option is forced on when Skip Text is enabled."; + }) + .Options(CheckboxOptions().Tooltip( + "Prevents the Poacher's Saw softlock from mashing through the text, or with Skip Text enabled.")); + AddWidget(path, "Fix Anubis Fireballs", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("AnubisFix")) + .Options(CheckboxOptions().Tooltip( + "Make Anubis Fireballs do Fire damage when reflected back at them with the Mirror Shield.")); + + AddWidget(path, "Item-related Fixes", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Fix Deku Nut Upgrade", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DekuNutUpgradeFix")) + .Options(CheckboxOptions().Tooltip("Prevents the Forest Stage Deku Nut upgrade from becoming unobtainable " + "after receiving the Poacher's Saw.")); + AddWidget(path, "Fix Megaton Hammer Crouch Stab", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CrouchStabHammerFix")) + .Callback([](WidgetInfo& info) { + if (!CVarGetInteger(CVAR_ENHANCEMENT("CrouchStabHammerFix"), 0)) { + CVarClear(CVAR_ENHANCEMENT("CrouchStabFix")); + } + }) + .Options(CheckboxOptions().Tooltip( + "Make the Megaton Hammer's crouch stab able to destroy rocks without first swinging it normally.")); + AddWidget(path, "Remove Power Crouch Stab", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CrouchStabFix")) + .PreFunc( + [](WidgetInfo& info) { info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("CrouchStabHammerFix"), 0) == 0; }) + .Options(CheckboxOptions().Tooltip("Make crouch stabbing always do the same damage as a regular slash.")); + AddWidget(path, "Fix Broken Giant's Knife Bug", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixGrokenGiantsKnife")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = IS_RANDO && GameInteractor::IsSaveLoaded(true); + info.options->disabledTooltip = "This setting is forcefully enabled when you are playing a Randomizer."; + }) + .Callback([](WidgetInfo& info) { + bool hasGiantsKnife = CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BIGGORON); + bool hasBrokenKnife = CHECK_OWNED_EQUIP_ALT(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BROKENGIANTKNIFE); + bool knifeIsBroken = gSaveContext.swordHealth == 0.0f; + + if (hasGiantsKnife && (hasBrokenKnife != knifeIsBroken)) { + func_800849EC(gPlayState); + } + }) + .Options( + CheckboxOptions().Tooltip("Fixes the Broken Giant's Knife flag not being reset when Medigoron fixes it.")); + + AddWidget(path, "Camera Fixes", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Fix Camera Drift", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixCameraDrift")) + .Options(CheckboxOptions().Tooltip( + "Fixes camera slightly drifting to the left when standing still due to a math error.")); + AddWidget(path, "Fix Camera Swing", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixCameraSwing")) + .Options(CheckboxOptions().Tooltip( + "Fixes camera getting stuck on collision when standing still. Also fixes slight shift " + "back in camera when Link stops moving.")); + AddWidget(path, "Fix Hanging Ledge Swing Rate", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixHangingLedgeSwingRate")) + .Options(CheckboxOptions().Tooltip( + "Fixes camera swing rate when the player falls off a ledge and the camera swings around.")); + path.column = SECTION_COLUMN_2; + AddWidget(path, "Graphical Fixes", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Fix L&R Pause Menu", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixMenuLR")) + .Options(CheckboxOptions().Tooltip("Makes the L and R buttons in the pause menu the same color")); + AddWidget(path, "Fix Dungeon Entrances", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixDungeonMinimapIcon")) + .Options(CheckboxOptions().Tooltip( + "Removes the Dungeon Entrance icon on the top-left corner of the screen when no dungeon is present on the " + "current map.")); + AddWidget(path, "Fix Two-Handled Idle Animations", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("TwoHandedIdle")) + .Options(CheckboxOptions().Tooltip( + "Re-Enables the two-handed idle animation, a seemingly finished animation that was disabled on accident " + "in the original game.")); + AddWidget(path, "Fix Navi Text HUD Position", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("NaviTextFix")) + .Options(CheckboxOptions().Tooltip("Correctly centers the Navi text prompt on the HUD's C-Up button.")); + AddWidget(path, "Fix Gerudo Warrior's Clothing Colors", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("GerudoWarriorClothingFix")) + .Options(CheckboxOptions().Tooltip( + "Prevent the Gerudo Warrior's clothes changing color when changing Link's tunic or " + "using Bombs in front of her.")); + AddWidget(path, "Fix Out of Bounds Textures", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixTexturesOOB")) + .Callback([](WidgetInfo& info) { ApplyAuthenticGfxPatches(); }) + .Options(CheckboxOptions().Tooltip( + "Fixes authentic out of bounds texture reads, instead loading textures with the correct size.")); + AddWidget(path, "Fix Link's Eyes Open while Sleeping", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixEyesOpenWhileSleeping")) + .Options(CheckboxOptions().Tooltip( + "Fixes Link's eyes being open in the openeing cutscene when he is supposed to be sleeping.")); + AddWidget(path, "Fix Hand Holding Hammer", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixHammerHand")) + .Callback([](WidgetInfo& info) { UpdatePatchHand(); }) + .Options(CheckboxOptions().Tooltip( + "Fixes Adult Link having a backwards Left hand when holding the Megaton Hammer.")); + AddWidget(path, "Fix Vanishing Paths", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("SceneSpecificDirtPathFix")) + .Callback([](WidgetInfo& info) { + if (gPlayState != NULL) { + UpdateDirtPathFixState(gPlayState->sceneNum); + } + }) + .Options( + ComboboxOptions() + .ComboMap(zFightingOptions) + .DefaultIndex(ZFIGHT_FIX_DISABLED) + .Tooltip("Disabled: Paths vanish more the higher the resolution (Z-fighting is based on resolution)\n" + "Consistent: Certain paths vanish the same way in all resolutions\n" + "No Vanish: Paths do not vanish, Link seems to sink in to some paths\n" + "This might affect other decal effects\n")); + + AddWidget(path, "Audio Fixes", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Fix Missing Jingle after 5 Silver Rupees", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("SilverRupeeJingleExtend")) + .Options(CheckboxOptions().Tooltip( + "Adds 5 higher pitches for the Silver Rupee Jingle for the rooms with more than 5 Silver Rupees. " + "Only relevant for playthroughs involving Master Quest Dungeons.")); + + AddWidget(path, "Desync Fixes", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Fix Darunia Dancing Too Fast", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FixDaruniaDanceSpeed")) + .Options(CheckboxOptions().Tooltip( + "Fixes Darunia's dancing speed so he dances to the beat of Saria's Song, like in the Original Game.")); + AddWidget(path, "Fix Credits Timing", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CreditsFix")) + .Options(CheckboxOptions().Tooltip( + "Extend certain credits scenes so the music lines up properly with the visuals.")); + + path.column = SECTION_COLUMN_3; + AddWidget(path, "Graphical Restorations", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Red Ganon Blood", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("RedGanonBlood")) + .Options( + CheckboxOptions().Tooltip("Restore the original red blood from NTSC 1.0/1.1. Disable for Green blood.")); + AddWidget(path, "Restore Old Gold Skulltula Cutscene", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("GSCutscene")) + .Options(CheckboxOptions().Tooltip( + "Restore pre-release behavior where defeating a Gold Skulltula will play a cutscene showing it die.")); + AddWidget(path, "Pulsate Boss Icon", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Pulsate Boss Icon")) + .Options(CheckboxOptions().Tooltip( + "Restores an unfinished feature to pulsate the boss room icon when you are in the boss room.")); + + AddWidget(path, "Glitch Restorations", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Fish while Hovering", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("HoverFishing")) + .Options(CheckboxOptions().Tooltip( + "Restore a bug from NSTC 1.0 that allows casting the Fishing Rod while using the Hover Boots.")); + AddWidget(path, "N64 Weird Frames", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("N64WeirdFrames")) + .Options(CheckboxOptions().Tooltip("Restores N64 Weird Frames allwing weirdshots to behave the same as N64.")); + AddWidget(path, "Bombchus Out of Bounds", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BombchusOOB")) + .Options(CheckboxOptions().Tooltip("Allows Bombchus to explode out of bounds. Similar to Gamecube and Wii VC")); + AddWidget(path, "Quick Putaway", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("QuickPutaway")) + .Options(CheckboxOptions().Tooltip( + "Restore a bug from NTSC 1.0 that allows putting away an item without an animation and performing " + "Putaway Ocarina Items.")); + AddWidget(path, "Quick Bongo Kill", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("QuickBongoKill")) + .Options(CheckboxOptions().Tooltip( + "Restore a bug from NTSC 1.0 that allows bypassing Bongo Bongo's intro cutscene to quickly kill him.")); + AddWidget(path, "Original RBA Values", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("RestoreRBAValues")) + .Options(CheckboxOptions().Tooltip("Restores the original outcomes when performing Reverse Bottle Adventure.")); + AddWidget(path, "Early Eyeball Frog", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("EarlyEyeballFrog")) + .Options(CheckboxOptions().Tooltip( + "Restores a bug from NTSC 1.0/1.1 that allows you to obtain the eyeball frog from King Zora " + "instead of the Zora Tunic by Holding Shield.")); + + AddWidget(path, "Misc Restorations", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Fix L&Z Page Switch in Pause Menu", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("NGCKaleidoSwitcher")) + .Options(CheckboxOptions().Tooltip( + "Makes L and R switch pages like on the Gamecube. Z opens the Debug Menu instead.")); + // Difficulty Options path.sidebarName = "Difficulty"; AddSidebarEntry("Enhancements", path.sidebarName, 3); path.column = SECTION_COLUMN_1; - - AddWidget(path, "Shooting Gallery", WIDGET_SEPARATOR_TEXT); - auto shootingGalleryDisabledFunc = [](WidgetInfo& info) { - info.options->disabled = !CVarGetInteger(CVAR_ENHANCEMENT("CustomizeShootingGallery"), 0); - info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off."; - }; - AddWidget(path, "Customize Behavior##Shooting", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CustomizeShootingGallery")) - .Options(CheckboxOptions().Tooltip("Turn on/off changes to the shooting gallery behavior")); - AddWidget(path, "Instant Win", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("InstantShootingGalleryWin")) - .PreFunc(shootingGalleryDisabledFunc) - .Options(CheckboxOptions().Tooltip("Skips the Shooting Gallery minigame")); - AddWidget(path, "No Rupee Randomization", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("ConstantAdultGallery")) - .PreFunc(shootingGalleryDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Forces the rupee order to not be randomized as adult, making it the same as child." - )); - AddWidget(path, "Child Starting Ammunition: %d seeds", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("ShootingGalleryAmmoChild")) - .PreFunc(shootingGalleryDisabledFunc) - .Options(IntSliderOptions() - .Min(10) - .Max(30) - .DefaultValue(15) - .Format("%d seeds") - .Tooltip( - "The ammunition at the start of the Shooting Gallery minigame as Child." - ) - ); - AddWidget(path, "Adult Starting Ammunition: %d arrows", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("ShootingGalleryAmmoAdult")) - .PreFunc(shootingGalleryDisabledFunc) - .Options(IntSliderOptions() - .Min(10) - .Max(30) - .DefaultValue(15) - .Format("%d arrows") - .Tooltip( - "The ammunition at the start of the Shooting Gallery minigame as Adult." - ) - ); - - AddWidget(path, "Bombchu Bowling", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Customize Behavior##Bowling", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CustomizeBombchuBowling")) - .Options(CheckboxOptions().Tooltip( - "Turn on/off changes to the Bombchu Bowling behavior." - )); - auto bombchuBowlingDisabledFunc = [](WidgetInfo& info) { - info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeBombchuBowling"), 0) == 0; - info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off"; - }; - AddWidget(path, "Remove Small Cucco", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BombchuBowlingNoSmallCucco")) - .PreFunc(bombchuBowlingDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Prevents the small Cucco from appearing in the Bombchu Bowling minigame." - )); - AddWidget(path, "Remove Big Cucco", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("BombchuBowlingNoBigCucco")) - .PreFunc(bombchuBowlingDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Prevents the big Cucco from appearing in the Bombchu Bowling minigame." - )); - AddWidget(path, "Bombchu Count: %d bombchus", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("BombchuBowlingAmmo")) - .PreFunc(bombchuBowlingDisabledFunc) - .Options(IntSliderOptions() - .Min(3) - .Max(20) - .DefaultValue(10) - .Format("%d bombchus") - .Tooltip("The number of Bombchus available at the start of the Bombchu Bowling minigame.") - ); - - AddWidget(path, "Fishing", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Customize Behavior##Fishing", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CustomizeFishing")) - .Options(CheckboxOptions().Tooltip( - "Turn on/off changes to the Fishing behavior" - )); - auto fishingDisabledFunc = [](WidgetInfo& info) { - info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) == 0; - info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off."; - }; - AddWidget(path, "Instant Fishing", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("InstantFishing")) - .PreFunc(fishingDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "All fish will be caught instantly." - )); - AddWidget(path, "Guarantee Bite", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("GuaranteeFishingBite")) - .PreFunc(fishingDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "When a line is stable, guarantee bite. Otherwise use Default logic." - )); - AddWidget(path, "Fish Never Escape", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FishNeverEscape")) - .PreFunc(fishingDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Once a hook as been set, Fish will never let go while being reeled in." - )); - AddWidget(path, "Loaches Always Appear", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("LoachesAlwaysAppear")) - .PreFunc(fishingDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Loaches will always appear in the fishing pond instead of every four visits." - )); - AddWidget(path, "Skip Keep Confirmation", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("SkipKeepConfirmation")) - .PreFunc(fishingDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "The Pond Owner will not ask to confirm if you want to keep a smaller Fish." - )); - AddWidget(path, "Child Minimum Weight: %d lbs.", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("MinimumFishWeightChild")) - .PreFunc(fishingDisabledFunc) - .Options(IntSliderOptions() - .Min(3) - .Max(10) - .DefaultValue(10) - .Format("%d lbs.") - .Tooltip( - "The minimum weight for the unique Fishing Reward as a Child." - ) - ); - AddWidget(path, "Adult Minimum Weight: %d lbs.", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("MinimumFishWeightAdult")) - .PreFunc(fishingDisabledFunc) - .Options(IntSliderOptions() - .Min(6) - .Max(13) - .DefaultValue(13) - .Format("%d lbs.") - .Tooltip( - "The minimum weight for the unique fishing reward as an Adult." - ) - ); - AddWidget(path, "All Fish are Hyrule Loaches", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("AllHyruleLoaches")) - .PreFunc(fishingDisabledFunc) - .Options(IntSliderOptions().Tooltip( - "Every fish in the Fishing Pond will always be a Hyrule Loach.\n\n" - "NOTE: This requires reloading the area." - )); - - path.column = SECTION_COLUMN_2; - AddWidget(path, "Lost Woods Ocarina Game", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Customize Behavior##LostWoods", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CustomizeOcarinaGame")) - .Options(CheckboxOptions().Tooltip( - "Turn on/off changes to the Lost Woods Ocarina Game behavior." - )); - auto ocarinaMemoryGameDisabledFunc = [](WidgetInfo& info) { - info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeOcarinaGame"), 0) == 0; - info.options->disabledTooltip = "This options is disabled because \"Customize Behavior\" is turned off."; - }; - AddWidget(path, "Instant Win##LostWoods", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("InstantOcarinaGameWin")) - .PreFunc(ocarinaMemoryGameDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Skips the Lost Woods Ocarina Memory Game." - )); - AddWidget(path, "Note Play Speed: %dx", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("OcarinaGame.NoteSpeed")) - .PreFunc(ocarinaMemoryGameDisabledFunc) - .Options(IntSliderOptions() - .Min(1) - .Max(5) - .DefaultValue(1) - .Format("%dx") - .Tooltip( - "Adjust the speed that the Skull Kids play the notes." - ) - ); - AddWidget(path, "Unlimited Playback Time##LostWoods", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("OcarinaUnlimitedFailTime")) - .PreFunc(ocarinaMemoryGameDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Removes the timer to play back the song." - )); - AddWidget(path, "Number of Starting Notes: %d notes", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("OcarinaGame.StartingNotes")) - .PreFunc(ocarinaMemoryGameDisabledFunc) - .Options(IntSliderOptions() - .Min(1) - .Max(8) - .DefaultValue(3) - .Format("%d notes") - .Tooltip( - "Adjust the number of notes the Skull Kids play to start the first round." - ) - ); - int roundMin = CVarGetInteger(CVAR_ENHANCEMENT("OcarinaGame.StartingNotes"), 3); - AddWidget(path, "Round One Notes: %d notes", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("OcarinaGame.RoundOneNotes")) - .PreFunc(ocarinaMemoryGameDisabledFunc) - .Options(IntSliderOptions() - .Min(roundMin) - .Max(8) - .DefaultValue(5) - .Format("%d notes") - .Tooltip( - "Adjust the number of notes you need to play to end the first round." - ) - ); - AddWidget(path, "Round Two Notes: %d notes", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("OcarinaGame.RoundTwoNotes")) - .PreFunc(ocarinaMemoryGameDisabledFunc) - .Options(IntSliderOptions() - .Min(roundMin) - .Max(8) - .DefaultValue(6) - .Format("%d notes") - .Tooltip( - "Adjust the number of notes you need to play to end the second round." - ) - ); - AddWidget(path, "Round Three Notes: %d notes", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("OcarinaGame.RoundThreeNotes")) - .PreFunc(ocarinaMemoryGameDisabledFunc) - .Options(IntSliderOptions() - .Min(roundMin) - .Max(8) - .DefaultValue(8) - .Format("%d notes") - .Tooltip( - "Adjust the number of notes you need to play to end the third round." - ) - ); - - AddWidget(path, "Frogs' Ocarina Game", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Customize Behavior##Frogs", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("CustomizeFrogsOcarinaGame")) - .Options(CheckboxOptions().Tooltip( - "Turn on/off changes to the Frogs' Ocarina Game behavior." - )); - auto frogsOcarinaGameDisabledFunc = [](WidgetInfo& info) { - info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFrogsOcarinaGame"), 0) == 0; - info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off."; - }; - AddWidget(path, "Instant Win##Frogs", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("InstantFrogsGameWin")) - .PreFunc(frogsOcarinaGameDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Skips the Frogs' Ocarina Game." - )); - AddWidget(path, "Unlimited Playback Time##Frogs", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FrogsUnlimitedFailTime")) - .PreFunc(frogsOcarinaGameDisabledFunc) - .Options(CheckboxOptions().Tooltip( - "Removes the timer to play back the song." - )); - AddWidget(path, "Modify note timer: %dx", WIDGET_CVAR_SLIDER_INT) - .CVar(CVAR_ENHANCEMENT("FrogsModifyFailTime")) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = !CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFrogsOcarinaGame"), 0) || CVarGetInteger(CVAR_ENHANCEMENT("FrogsUnlimitedFailTime"), 0); - info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off or \"Unlimited Playback Time\" is on"; - }) - .Options(IntSliderOptions() - .Min(1) - .Max(5) - .DefaultValue(1) - .Format("%dx") - .Tooltip( - "Adjusts the time allowed for playback before failing." - ) - ); AddWidget(path, "Health", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Permanent Heart Loss", WIDGET_CVAR_CHECKBOX) @@ -1591,7 +1099,7 @@ void SohMenu::AddMenuEnhancements() { "This simulates Hero Mode from other games in the series." )); - path.column = SECTION_COLUMN_3; + path.column = SECTION_COLUMN_2; AddWidget(path, "Drops", WIDGET_SEPARATOR_TEXT); AddWidget(path, "No Random Drops", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("NoRandomDrops")) @@ -1601,7 +1109,9 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Enable Bombchu Drops", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("EnableBombchuDrops")) .PreFunc([](WidgetInfo& info) { - info.options->disabled = OTRGlobals::Instance->gRandoContext->GetOption(RSK_ENABLE_BOMBCHU_DROPS).Is(RO_GENERIC_ON); + info.options->disabled = + IS_RANDO && GameInteractor::IsSaveLoaded(true) && + OTRGlobals::Instance->gRandoContext->GetOption(RSK_ENABLE_BOMBCHU_DROPS).Is(RO_GENERIC_ON); info.options->disabledTooltip = "This setting is forcefully enabled because a randomized savefile with " "\"Enable Bombchu Drops\" is loaded."; }) @@ -1622,22 +1132,6 @@ void SohMenu::AddMenuEnhancements() { ICON_FA_EXCLAMATION_TRIANGLE " WARNING " ICON_FA_EXCLAMATION_TRIANGLE "\nTHIS IS NOT REVERSABLE\nUSE AT YOUR OWN RISK!" )); - AddWidget(path, "Hyper Bosses", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("HyperBosses")) - .Callback([](WidgetInfo& info) { - UpdateHyperBossesState(); - }) - .Options(CheckboxOptions().Tooltip( - "All Major Bosses move and act twice as fast." - )); - AddWidget(path, "Hyper Enemies", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("HyperEnemies")) - .Callback([](WidgetInfo& info) { - UpdateHyperEnemiesState(); - }) - .Options(CheckboxOptions().Tooltip( - "All Regular Enemies and Mini-Bosses move and act twice as fast." - )); AddWidget(path, "Always Win Goron Pot", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("GoronPot")) .Options(CheckboxOptions().Tooltip( @@ -1665,20 +1159,230 @@ void SohMenu::AddMenuEnhancements() { "Cuccos will stay in place longer after putting them down, by a multiple of the value of the slider." ) ); + + path.column = SECTION_COLUMN_3; + AddWidget(path, "Enemies", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Hyper Bosses", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("HyperBosses")) + .Callback([](WidgetInfo& info) { UpdateHyperBossesState(); }) + .Options(CheckboxOptions().Tooltip("All Major Bosses move and act twice as fast.")); + AddWidget(path, "Hyper Enemies", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("HyperEnemies")) + .Callback([](WidgetInfo& info) { UpdateHyperEnemiesState(); }) + .Options(CheckboxOptions().Tooltip("All Regular Enemies and Mini-Bosses move and act twice as fast.")); + AddWidget(path, "Enable Visual Guard Vision", WIDGET_CVAR_CHECKBOX).CVar(CVAR_ENHANCEMENT("GuardVision")); AddWidget(path, "Leever Spawn Rate: %d seconds", WIDGET_CVAR_SLIDER_INT) .CVar(CVAR_ENHANCEMENT("LeeverSpawnRate")) .Options(IntSliderOptions() - .Min(0) - .Max(10) - .DefaultValue(0) - .Format("%d seconds") - .Tooltip( - "The time between groups of Leevers spawning." - ) - ); + .Min(0) + .Max(10) + .DefaultValue(0) + .Format("%d seconds") + .Tooltip("The time between groups of Leevers spawning.")); + // Minigames + path.sidebarName = "Minigames"; + AddSidebarEntry("Enhancements", path.sidebarName, 3); + path.column = SECTION_COLUMN_1; + + AddWidget(path, "Shooting Gallery", WIDGET_SEPARATOR_TEXT); + auto shootingGalleryDisabledFunc = [](WidgetInfo& info) { + info.options->disabled = !CVarGetInteger(CVAR_ENHANCEMENT("CustomizeShootingGallery"), 0); + info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off."; + }; + AddWidget(path, "Customize Behavior##Shooting", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CustomizeShootingGallery")) + .Options(CheckboxOptions().Tooltip("Turn on/off changes to the shooting gallery behavior")); + AddWidget(path, "Instant Win", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("InstantShootingGalleryWin")) + .PreFunc(shootingGalleryDisabledFunc) + .Options(CheckboxOptions().Tooltip("Skips the Shooting Gallery minigame")); + AddWidget(path, "No Rupee Randomization", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("ConstantAdultGallery")) + .PreFunc(shootingGalleryDisabledFunc) + .Options(CheckboxOptions().Tooltip( + "Forces the rupee order to not be randomized as adult, making it the same as child.")); + AddWidget(path, "Child Starting Ammunition: %d seeds", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("ShootingGalleryAmmoChild")) + .PreFunc(shootingGalleryDisabledFunc) + .Options(IntSliderOptions() + .Min(10) + .Max(30) + .DefaultValue(15) + .Format("%d seeds") + .Tooltip("The ammunition at the start of the Shooting Gallery minigame as Child.")); + AddWidget(path, "Adult Starting Ammunition: %d arrows", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("ShootingGalleryAmmoAdult")) + .PreFunc(shootingGalleryDisabledFunc) + .Options(IntSliderOptions() + .Min(10) + .Max(30) + .DefaultValue(15) + .Format("%d arrows") + .Tooltip("The ammunition at the start of the Shooting Gallery minigame as Adult.")); + + AddWidget(path, "Bombchu Bowling", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Customize Behavior##Bowling", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CustomizeBombchuBowling")) + .Options(CheckboxOptions().Tooltip("Turn on/off changes to the Bombchu Bowling behavior.")); + auto bombchuBowlingDisabledFunc = [](WidgetInfo& info) { + info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeBombchuBowling"), 0) == 0; + info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off"; + }; + AddWidget(path, "Remove Small Cucco", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BombchuBowlingNoSmallCucco")) + .PreFunc(bombchuBowlingDisabledFunc) + .Options(CheckboxOptions().Tooltip("Prevents the small Cucco from appearing in the Bombchu Bowling minigame.")); + AddWidget(path, "Remove Big Cucco", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("BombchuBowlingNoBigCucco")) + .PreFunc(bombchuBowlingDisabledFunc) + .Options(CheckboxOptions().Tooltip("Prevents the big Cucco from appearing in the Bombchu Bowling minigame.")); + AddWidget(path, "Bombchu Count: %d bombchus", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("BombchuBowlingAmmo")) + .PreFunc(bombchuBowlingDisabledFunc) + .Options(IntSliderOptions() + .Min(3) + .Max(20) + .DefaultValue(10) + .Format("%d bombchus") + .Tooltip("The number of Bombchus available at the start of the Bombchu Bowling minigame.")); + AddWidget(path, "Frogs' Ocarina Game", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Customize Behavior##Frogs", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CustomizeFrogsOcarinaGame")) + .Options(CheckboxOptions().Tooltip("Turn on/off changes to the Frogs' Ocarina Game behavior.")); + auto frogsOcarinaGameDisabledFunc = [](WidgetInfo& info) { + info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFrogsOcarinaGame"), 0) == 0; + info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off."; + }; + AddWidget(path, "Instant Win##Frogs", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("InstantFrogsGameWin")) + .PreFunc(frogsOcarinaGameDisabledFunc) + .Options(CheckboxOptions().Tooltip("Skips the Frogs' Ocarina Game.")); + AddWidget(path, "Unlimited Playback Time##Frogs", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FrogsUnlimitedFailTime")) + .PreFunc(frogsOcarinaGameDisabledFunc) + .Options(CheckboxOptions().Tooltip("Removes the timer to play back the song.")); + AddWidget(path, "Modify note timer: %dx", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("FrogsModifyFailTime")) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = !CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFrogsOcarinaGame"), 0) || + CVarGetInteger(CVAR_ENHANCEMENT("FrogsUnlimitedFailTime"), 0); + info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off or " + "\"Unlimited Playback Time\" is on"; + }) + .Options(IntSliderOptions().Min(1).Max(5).DefaultValue(1).Format("%dx").Tooltip( + "Adjusts the time allowed for playback before failing.")); + + path.column = SECTION_COLUMN_2; + AddWidget(path, "Lost Woods Ocarina Game", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Customize Behavior##LostWoods", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CustomizeOcarinaGame")) + .Options(CheckboxOptions().Tooltip("Turn on/off changes to the Lost Woods Ocarina Game behavior.")); + auto ocarinaMemoryGameDisabledFunc = [](WidgetInfo& info) { + info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeOcarinaGame"), 0) == 0; + info.options->disabledTooltip = "This options is disabled because \"Customize Behavior\" is turned off."; + }; + AddWidget(path, "Instant Win##LostWoods", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("InstantOcarinaGameWin")) + .PreFunc(ocarinaMemoryGameDisabledFunc) + .Options(CheckboxOptions().Tooltip("Skips the Lost Woods Ocarina Memory Game.")); + AddWidget(path, "Note Play Speed: %dx", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("OcarinaGame.NoteSpeed")) + .PreFunc(ocarinaMemoryGameDisabledFunc) + .Options(IntSliderOptions().Min(1).Max(5).DefaultValue(1).Format("%dx").Tooltip( + "Adjust the speed that the Skull Kids play the notes.")); + AddWidget(path, "Unlimited Playback Time##LostWoods", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("OcarinaUnlimitedFailTime")) + .PreFunc(ocarinaMemoryGameDisabledFunc) + .Options(CheckboxOptions().Tooltip("Removes the timer to play back the song.")); + AddWidget(path, "Number of Starting Notes: %d notes", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("OcarinaGame.StartingNotes")) + .PreFunc(ocarinaMemoryGameDisabledFunc) + .Options(IntSliderOptions() + .Min(1) + .Max(8) + .DefaultValue(3) + .Format("%d notes") + .Tooltip("Adjust the number of notes the Skull Kids play to start the first round.")); + int roundMin = CVarGetInteger(CVAR_ENHANCEMENT("OcarinaGame.StartingNotes"), 3); + AddWidget(path, "Round One Notes: %d notes", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("OcarinaGame.RoundOneNotes")) + .PreFunc(ocarinaMemoryGameDisabledFunc) + .Options(IntSliderOptions() + .Min(roundMin) + .Max(8) + .DefaultValue(5) + .Format("%d notes") + .Tooltip("Adjust the number of notes you need to play to end the first round.")); + AddWidget(path, "Round Two Notes: %d notes", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("OcarinaGame.RoundTwoNotes")) + .PreFunc(ocarinaMemoryGameDisabledFunc) + .Options(IntSliderOptions() + .Min(roundMin) + .Max(8) + .DefaultValue(6) + .Format("%d notes") + .Tooltip("Adjust the number of notes you need to play to end the second round.")); + AddWidget(path, "Round Three Notes: %d notes", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("OcarinaGame.RoundThreeNotes")) + .PreFunc(ocarinaMemoryGameDisabledFunc) + .Options(IntSliderOptions() + .Min(roundMin) + .Max(8) + .DefaultValue(8) + .Format("%d notes") + .Tooltip("Adjust the number of notes you need to play to end the third round.")); + + path.column = SECTION_COLUMN_3; + AddWidget(path, "Fishing", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Customize Behavior##Fishing", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("CustomizeFishing")) + .Options(CheckboxOptions().Tooltip("Turn on/off changes to the Fishing behavior")); + auto fishingDisabledFunc = [](WidgetInfo& info) { + info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) == 0; + info.options->disabledTooltip = "This option is disabled because \"Customize Behavior\" is turned off."; + }; + AddWidget(path, "Instant Fishing", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("InstantFishing")) + .PreFunc(fishingDisabledFunc) + .Options(CheckboxOptions().Tooltip("All fish will be caught instantly.")); + AddWidget(path, "Guarantee Bite", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("GuaranteeFishingBite")) + .PreFunc(fishingDisabledFunc) + .Options(CheckboxOptions().Tooltip("When a line is stable, guarantee bite. Otherwise use Default logic.")); + AddWidget(path, "Fish Never Escape", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FishNeverEscape")) + .PreFunc(fishingDisabledFunc) + .Options(CheckboxOptions().Tooltip("Once a hook as been set, Fish will never let go while being reeled in.")); + AddWidget(path, "Loaches Always Appear", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("LoachesAlwaysAppear")) + .PreFunc(fishingDisabledFunc) + .Options( + CheckboxOptions().Tooltip("Loaches will always appear in the fishing pond instead of every four visits.")); + AddWidget(path, "Skip Keep Confirmation", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("SkipKeepConfirmation")) + .PreFunc(fishingDisabledFunc) + .Options( + CheckboxOptions().Tooltip("The Pond Owner will not ask to confirm if you want to keep a smaller Fish.")); + AddWidget(path, "Child Minimum Weight: %d lbs.", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("MinimumFishWeightChild")) + .PreFunc(fishingDisabledFunc) + .Options(IntSliderOptions().Min(3).Max(10).DefaultValue(10).Format("%d lbs.").Tooltip( + "The minimum weight for the unique Fishing Reward as a Child.")); + AddWidget(path, "Adult Minimum Weight: %d lbs.", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("MinimumFishWeightAdult")) + .PreFunc(fishingDisabledFunc) + .Options(IntSliderOptions().Min(6).Max(13).DefaultValue(13).Format("%d lbs.").Tooltip( + "The minimum weight for the unique fishing reward as an Adult.")); + AddWidget(path, "All Fish are Hyrule Loaches", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_ENHANCEMENT("AllHyruleLoaches")) + .PreFunc(fishingDisabledFunc) + .Options(IntSliderOptions().Tooltip("Every fish in the Fishing Pond will always be a Hyrule Loach.\n\n" + "NOTE: This requires reloading the area.")); + + // Extra Modes path.sidebarName = "Extra Modes"; - AddSidebarEntry("Enhancements", path.sidebarName, 2); + AddSidebarEntry("Enhancements", path.sidebarName, 3); path.column = SECTION_COLUMN_1; AddWidget(path, "Mirrored World", WIDGET_CVAR_COMBOBOX) @@ -1703,25 +1407,15 @@ void SohMenu::AddMenuEnhancements() { " - Dungeons Random (Seeded): Dungeons are mirrored based on the current randomizer seed/file\n" ) ); - AddWidget(path, "Randomized Enemy Sizes", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("RandomizedEnemySizes")) - .Options(CheckboxOptions().Tooltip( - "Enemies and Bosses spawn with random sizes." - )); - AddWidget(path, "Scale Health with Size", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("EnemySizeScalesHealth")) - .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemySizes"), 0) == 0; - }) - .Options(CheckboxOptions().Tooltip( - "Scales normal enemies Health with their randomized size. *This will NOT affect bosses*" - )); AddWidget(path, "Ivan the Fairy (Coop Mode)", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("IvanCoopModeEnabled")) .Options(CheckboxOptions().Tooltip( "Enables Ivan the Fairy upon the next map change. Player 2 can control Ivan and press the C-Buttons to " "use items and mess with Player 1!" )); + AddWidget(path, "Dogs Follow you Everywhere", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("DogFollowsEverywhere")) + .Options(CheckboxOptions().Tooltip("Allows dogs to follow you anywhere you go, even if you leave the Market.")); AddWidget(path, "Rupee Dash Mode", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("RupeeDash")) .Options(CheckboxOptions().Tooltip( @@ -1827,6 +1521,7 @@ void SohMenu::AddMenuEnhancements() { .PreFunc([](WidgetInfo& info) { info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("ExtraTraps.Enabled"), 0) == 0; }); + path.column = SECTION_COLUMN_2; AddWidget(path, "Enemy Randomizer", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_ENHANCEMENT("RandomizedEnemies")) @@ -1843,22 +1538,34 @@ void SohMenu::AddMenuEnhancements() { "- Random (Seeded): Enemies are randomized based on the current randomizer seed/file\n" ) ); + AddWidget(path, "Randomized Enemy Sizes", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("RandomizedEnemySizes")) + .Options(CheckboxOptions().Tooltip("Enemies and Bosses spawn with random sizes.")); + AddWidget(path, "Scale Health with Size", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("EnemySizeScalesHealth")) + .PreFunc( + [](WidgetInfo& info) { info.options->disabled = !CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemySizes"), 0); }) + .Options(CheckboxOptions().Tooltip( + "Scales normal enemies Health with their randomized size. *This will NOT affect bosses*")); AddWidget(path, "Enemy List", WIDGET_SEPARATOR_TEXT) .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0) != ENEMY_RANDOMIZER_RANDOM; + info.isHidden = !CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0); }); AddWidget(path, "Select All Enemies", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("RandomizedEnemyList.All")) .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0) != ENEMY_RANDOMIZER_RANDOM; + info.isHidden = !CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0); }); - AddWidget(path, "Enemy List", WIDGET_SEPARATOR); + AddWidget(path, "Enemy List", WIDGET_SEPARATOR).PreFunc([](WidgetInfo& info) { + info.isHidden = !CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0); + }); for (int i = 0; i < RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE; i++) { AddWidget(path, enemyNameList[i], WIDGET_CVAR_CHECKBOX) .CVar(enemyCVarList[i]) + .Options(CheckboxOptions().DefaultValue(true)) .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0) != ENEMY_RANDOMIZER_RANDOM; - info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0) == 1; + info.isHidden = !CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), 0); + info.options->disabled = CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemyList.All"), 0); info.options->disabledTooltip = "These options are disabled because \"Select All Enemies\" is enabled."; }) .Callback([](WidgetInfo& info) { @@ -1871,81 +1578,6 @@ void SohMenu::AddMenuEnhancements() { AddSidebarEntry("Enhancements", path.sidebarName, 3); path.column = SECTION_COLUMN_1; - AddWidget(path, "Inventory", WIDGET_SEPARATOR_TEXT); - AddWidget(path, "Super Tunic", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("SuperTunic")) - .Options(CheckboxOptions().Tooltip( - "Makes every tunic have the effects of every other tunic." - )); - AddWidget(path, "Easy ISG", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("EasyISG")) - .Options(CheckboxOptions().Tooltip( - "Passive Infinite Sword Glitch\n" - "It makes your sword's swing effect and hitbox stay active indefinitely." - )); - AddWidget(path, "Easy QPA", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("EasyQPA")) - .Options(CheckboxOptions().Tooltip( - "Gives you the glitched damage value of the quick put away glitch." - )); - AddWidget(path, "Timeless Equipment", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("TimelessEquipment")) - .Options(CheckboxOptions().Tooltip( - "Allows any item to be equipped, regardless of age.\n" - "Also allows Child to use Adult strength upgrades." - )); - AddWidget(path, "Unrestricted Items", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("Unrestricted Items")) - .Options(CheckboxOptions().Tooltip( - "Allows you to use any item at any location" - )); - AddWidget(path, "Fireproof Deku Shield", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("FireproofDekuShield")) - .Options(CheckboxOptions().Tooltip( - "Prevents the Deku Shield from burning on contact with fire." - )); - AddWidget(path, "Shield with Two-Handed Weapons", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("ShieldTwoHanded")) - .Options(CheckboxOptions().Tooltip( - "This allows you to put up for shield with any two-handed weapon in hand except for Deku Sticks." - )); - AddWidget(path, "Deku Sticks:", WIDGET_CVAR_COMBOBOX) - .CVar(CVAR_CHEAT("DekuStick")) - .Options(ComboboxOptions().ComboMap( - dekuStickCheat - ).DefaultIndex(DEKU_STICK_NORMAL)); - AddWidget(path, "Bomb Timer Multiplier: %.2fx", WIDGET_CVAR_SLIDER_FLOAT) - .CVar(CVAR_CHEAT("BombTimerMultiplier")) - .Options(FloatSliderOptions() - .Format("%.2f") - .Min(0.1f) - .Max(5.0f) - .DefaultValue(1.0f)); - AddWidget(path, "Hookshot Everything", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("HookshotEverything")) - .Options(CheckboxOptions().Tooltip( - "Makes every surface in the game hookshot-able." - )); - AddWidget(path, "Hookshot Reach Multiplier: %.2fx", WIDGET_CVAR_SLIDER_FLOAT) - .CVar(CVAR_CHEAT("HookshotReachMultiplier")) - .Options(FloatSliderOptions() - .Format("%.2f") - .Min(1.0f) - .Max(5.0f)); - AddWidget(path, "Change Age", WIDGET_BUTTON) - .Options(ButtonOptions().Tooltip("Switches Link's age and reloads the area.")) - .Callback([](WidgetInfo& info){ - SwitchAge(); - }); - AddWidget(path, "Clear Cutscene Pointer", WIDGET_BUTTON) - .Callback([](WidgetInfo& info) { - GameInteractor::RawAction::ClearCutscenePointer(); - }) - .Options(ButtonOptions().Tooltip( - "Clears the cutscene pointer to a value safe for wrong warps." - )); - - path.column = SECTION_COLUMN_2; AddWidget(path, "Infinite...", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Money", WIDGET_CVAR_CHECKBOX).CVar(CVAR_CHEAT("InfiniteMoney")); AddWidget(path, "Health", WIDGET_CVAR_CHECKBOX).CVar(CVAR_CHEAT("InfiniteHealth")); @@ -1954,30 +1586,39 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Nayru's Love", WIDGET_CVAR_CHECKBOX).CVar(CVAR_CHEAT("InfiniteNayru")); AddWidget(path, "Epona Boost", WIDGET_CVAR_CHECKBOX).CVar(CVAR_CHEAT("InfiniteEponaBoost")); - AddWidget(path, "Save States", WIDGET_SEPARATOR_TEXT); - AddWidget(path, ICON_FA_EXCLAMATION_TRIANGLE " WARNING!!!! " ICON_FA_EXCLAMATION_TRIANGLE, WIDGET_TEXT) - .Options(WidgetOptions().Color(Colors::Orange)); - AddWidget(path, - "These are NOT like emulator states. They do not save your game progress " - "and they WILL break across transitions and load zones (like doors). " - "Support for related issues will not be provided.", WIDGET_TEXT - ); - AddWidget(path, "I promise I have read the warning", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("SaveStatePromise")) - .Callback([](WidgetInfo& info) { - CVarSetInteger(CVAR_CHEAT("SaveStatesEnabled"), 0); - Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); - }); - AddWidget(path, "I understand, enable save states", WIDGET_CVAR_CHECKBOX) - .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_CHEAT("SaveStatePromise"), 0) == 0; - }) - .CVar(CVAR_CHEAT("SaveStatesEnabled")) + AddWidget(path, "Items", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Timeless Equipment", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("TimelessEquipment")) + .Options(CheckboxOptions().Tooltip("Allows any item to be equipped, regardless of age.\n" + "Also allows Child to use Adult strength upgrades.")); + AddWidget(path, "Unrestricted Items", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("Unrestricted Items")) + .Options(CheckboxOptions().Tooltip("Allows you to use any item at any location")); + AddWidget(path, "Super Tunic", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("SuperTunic")) + .Options(CheckboxOptions().Tooltip("Makes every tunic have the effects of every other tunic.")); + AddWidget(path, "Fireproof Deku Shield", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("FireproofDekuShield")) + .Options(CheckboxOptions().Tooltip("Prevents the Deku Shield from burning on contact with fire.")); + AddWidget(path, "Shield with Two-Handed Weapons", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("ShieldTwoHanded")) .Options(CheckboxOptions().Tooltip( - "F5 to save, F6 to change slots, F7 to load" - )); - - AddWidget(path, "Behavior", WIDGET_SEPARATOR_TEXT); + "This allows you to put up for shield with any two-handed weapon in hand except for Deku Sticks.")); + AddWidget(path, "Deku Sticks:", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_CHEAT("DekuStick")) + .Options(ComboboxOptions().ComboMap(dekuStickCheat).DefaultIndex(DEKU_STICK_NORMAL)); + AddWidget(path, "Bomb Timer Multiplier: %.2fx", WIDGET_CVAR_SLIDER_FLOAT) + .CVar(CVAR_CHEAT("BombTimerMultiplier")) + .Options(FloatSliderOptions().Format("%.2f").Min(0.1f).Max(5.0f).DefaultValue(1.0f)); + AddWidget(path, "Hookshot Everything", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("HookshotEverything")) + .Options(CheckboxOptions().Tooltip("Makes every surface in the game hookshot-able.")); + AddWidget(path, "Hookshot Reach Multiplier: %.2fx", WIDGET_CVAR_SLIDER_FLOAT) + .CVar(CVAR_CHEAT("HookshotReachMultiplier")) + .Options(FloatSliderOptions().Format("%.2f").Min(1.0f).Max(5.0f)); + + path.column = SECTION_COLUMN_2; + AddWidget(path, "Misc", WIDGET_SEPARATOR_TEXT); AddWidget(path, "No Clip", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("NoClip")) .Options(CheckboxOptions().Tooltip("Allows you to walk through walls.")); @@ -1987,44 +1628,79 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Moon Jump on L", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("MoonJumpOnL")) .Options(CheckboxOptions().Tooltip("Holding L makes you float into the air.")); - AddWidget(path, "New Easy Frame Advancing", WIDGET_CVAR_CHECKBOX) + AddWidget(path, "No ReDead/Gibdo Freeze", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("NoRedeadFreeze")) + .Options( + CheckboxOptions().Tooltip("Prevents ReDeads and Gibdos from being able to freeze you with their scream.")); + AddWidget(path, "Keese/Guay Don't Target You", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("NoKeeseGuayTarget")) + .Options(CheckboxOptions().Tooltip( + "Keese and Guay no longer target you and simply ignore you as if you were wearing the " + "Skull Mask.")); + + AddWidget(path, "Glitch Aids", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Easy Frame Advancing", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("EasyFrameAdvance")) .Options(CheckboxOptions().Tooltip( - "Continue holding START button when unpausing to only advance a single frame and then re-pause." - )); + "Continue holding START button when unpausing to only advance a single frame and then re-pause.")); + AddWidget(path, "Easy ISG", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("EasyISG")) + .Options(CheckboxOptions().Tooltip("Passive Infinite Sword Glitch\n" + "It makes your sword's swing effect and hitbox stay active indefinitely.")); + AddWidget(path, "Easy QPA", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("EasyQPA")) + .Options(CheckboxOptions().Tooltip("Gives you the glitched damage value of the quick put away glitch.")); + AddWidget(path, "Clear Cutscene Pointer", WIDGET_BUTTON) + .Callback([](WidgetInfo& info) { GameInteractor::RawAction::ClearCutscenePointer(); }) + .Options(ButtonOptions() + .Tooltip("Clears the cutscene pointer to a value safe for wrong warps.") + .Size(UIWidgets::Sizes::Inline)); + + AddWidget(path, "Despawn Timers", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Drops Don't Despawn", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("DropsDontDie")) - .Options(CheckboxOptions().Tooltip( - "Drops from enemies, grass, etc. don't disappear after a set amount of time." - )); + .Options( + CheckboxOptions().Tooltip("Drops from enemies, grass, etc. don't disappear after a set amount of time.")); AddWidget(path, "Fish Don't Despawn", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("NoFishDespawn")) - .Options(CheckboxOptions().Tooltip( - "Prevents fish from automatically despawning after a while when dropped." - )); + .Options(CheckboxOptions().Tooltip("Prevents fish from automatically despawning after a while when dropped.")); AddWidget(path, "Bugs Don't Despawn", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("NoBugsDespawn")) - .Options(CheckboxOptions().Tooltip( - "Prevents bugs from automatically despawning after a while when dropped." - )); + .Options(CheckboxOptions().Tooltip("Prevents bugs from automatically despawning after a while when dropped.")); + + AddWidget(path, "Time of Day", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Freeze Time", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("FreezeTime")) .Options(CheckboxOptions().Tooltip("Freezes the time of day")); AddWidget(path, "Time Sync", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("TimeSync")) .Options(CheckboxOptions().Tooltip("Syncs the in-game time with the real world time.")); - AddWidget(path, "No ReDead/Gibdo Freeze", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("NoRedeadFreeze")) - .Options(CheckboxOptions().Tooltip( - "Prevents ReDeads and Gibdos from being able to freeze you with their scream." - )); - AddWidget(path, "Keese/Guay Don't Target You", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_CHEAT("NoKeeseGuayTarget")) - .Options(CheckboxOptions().Tooltip( - "Keese and Guay no longer target you and simply ignore you as if you were wearing the " - "Skull Mask." - )); + + AddWidget(path, "Instant Age Change", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Change Age", WIDGET_BUTTON) + .Options(ButtonOptions().Tooltip("Switches Link's age and reloads the area.").Size(UIWidgets::Sizes::Inline)) + .Callback([](WidgetInfo& info) { SwitchAge(); }); + path.column = SECTION_COLUMN_3; + AddWidget(path, "Save States", WIDGET_SEPARATOR_TEXT); + AddWidget(path, ICON_FA_EXCLAMATION_TRIANGLE " WARNING!!!! " ICON_FA_EXCLAMATION_TRIANGLE, WIDGET_TEXT) + .Options(TextOptions().Color(Colors::Orange)); + AddWidget(path, + "These are NOT like emulator states. They do not save your game progress " + "and they WILL break across transitions and load zones (like doors). " + "Support for related issues will not be provided.", + WIDGET_TEXT); + AddWidget(path, "I promise I have read the warning", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("SaveStatePromise")) + .Callback([](WidgetInfo& info) { + CVarSetInteger(CVAR_CHEAT("SaveStatesEnabled"), 0); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); + }); + AddWidget(path, "I understand, enable save states", WIDGET_CVAR_CHECKBOX) + .PreFunc([](WidgetInfo& info) { info.isHidden = CVarGetInteger(CVAR_CHEAT("SaveStatePromise"), 0) == 0; }) + .CVar(CVAR_CHEAT("SaveStatesEnabled")) + .Options(CheckboxOptions().Tooltip("F5 to save, F6 to change slots, F7 to load")); + AddWidget(path, "Beta Quest", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Enable Beta Quest", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("EnableBetaQuest")) @@ -2100,7 +1776,7 @@ void SohMenu::AddMenuEnhancements() { // Timers path.sidebarName = "Timers"; - AddSidebarEntry("Enhancements", path.sidebarName, 1); + AddSidebarEntry("Enhancements", path.sidebarName, 3); AddWidget(path, "Toggle Timers Window", WIDGET_WINDOW_BUTTON) .CVar(CVAR_WINDOW("TimeDisplayEnabled")) .WindowName("Additional Timers") diff --git a/soh/soh/SohGui/SohMenuNetwork.cpp b/soh/soh/SohGui/SohMenuNetwork.cpp index 29511a9e9..135f7e2be 100644 --- a/soh/soh/SohGui/SohMenuNetwork.cpp +++ b/soh/soh/SohGui/SohMenuNetwork.cpp @@ -42,11 +42,11 @@ void SohMenu::AddMenuNetwork() { .CustomFunction([](WidgetInfo& info) { ImGui::BeginDisabled(Sail::Instance->isEnabled); ImGui::Text("%s", info.name.c_str()); - CVarInputString("##HostSail", CVAR_REMOTE_SAIL("Host"), InputOptions().Color(THEME_COLOR).PlaceholderText("127.0.0.1").DefaultValue("127.0.0.1").Size(ImVec2(ImGui::GetFontSize() * 15, 0)).LabelPosition(LabelPosition::None)); + CVarInputString("##HostSail", CVAR_REMOTE_SAIL("Host"), InputOptions().Color(THEME_COLOR).PlaceholderText("127.0.0.1").DefaultValue("127.0.0.1").Size(ImVec2(ImGui::GetFontSize() * 15, 0)).LabelPosition(LabelPositions::None)); ImGui::SameLine(); ImGui::Text(":"); ImGui::SameLine(); - CVarInputInt("##PortSail", CVAR_REMOTE_SAIL("Port"), InputOptions().Color(THEME_COLOR).PlaceholderText("43384").DefaultValue("43384").Size(ImVec2(ImGui::GetFontSize() * 5, 0)).LabelPosition(LabelPosition::None)); + CVarInputInt("##PortSail", CVAR_REMOTE_SAIL("Port"), InputOptions().Color(THEME_COLOR).PlaceholderText("43384").DefaultValue("43384").Size(ImVec2(ImGui::GetFontSize() * 5, 0)).LabelPosition(LabelPositions::None)); ImGui::EndDisabled(); }); AddWidget(path, "Enable##Sail", WIDGET_BUTTON) @@ -104,11 +104,11 @@ void SohMenu::AddMenuNetwork() { .CustomFunction([](WidgetInfo& info) { ImGui::BeginDisabled(CrowdControl::Instance->isEnabled); ImGui::Text("%s", info.name.c_str()); - CVarInputString("##HostCrowdControl", CVAR_REMOTE_CROWD_CONTROL("Host"), InputOptions().Color(THEME_COLOR).PlaceholderText("127.0.0.1").DefaultValue("127.0.0.1").Size(ImVec2(ImGui::GetFontSize() * 15, 0)).LabelPosition(LabelPosition::None)); + CVarInputString("##HostCrowdControl", CVAR_REMOTE_CROWD_CONTROL("Host"), InputOptions().Color(THEME_COLOR).PlaceholderText("127.0.0.1").DefaultValue("127.0.0.1").Size(ImVec2(ImGui::GetFontSize() * 15, 0)).LabelPosition(LabelPositions::None)); ImGui::SameLine(); ImGui::Text(":"); ImGui::SameLine(); - CVarInputInt("##PortCrowdControl", CVAR_REMOTE_CROWD_CONTROL("Port"), InputOptions().Color(THEME_COLOR).PlaceholderText("43384").DefaultValue("43384").Size(ImVec2(ImGui::GetFontSize() * 5, 0)).LabelPosition(LabelPosition::None)); + CVarInputInt("##PortCrowdControl", CVAR_REMOTE_CROWD_CONTROL("Port"), InputOptions().Color(THEME_COLOR).PlaceholderText("43384").DefaultValue("43384").Size(ImVec2(ImGui::GetFontSize() * 5, 0)).LabelPosition(LabelPositions::None)); ImGui::EndDisabled(); }); AddWidget(path, "Enable##CrowdControl", WIDGET_BUTTON) diff --git a/soh/soh/SohGui/SohMenuRandomizer.cpp b/soh/soh/SohGui/SohMenuRandomizer.cpp index a022d6c40..0d3b52b23 100644 --- a/soh/soh/SohGui/SohMenuRandomizer.cpp +++ b/soh/soh/SohGui/SohMenuRandomizer.cpp @@ -17,8 +17,11 @@ void SohMenu::AddMenuRandomizer() { .CVar(CVAR_WINDOW("RandomizerSettings")) .WindowName("Randomizer Settings") .Options(WindowButtonOptions().Tooltip("Enables the separate Randomizer Settings Window.")); + + // Enhancements path.sidebarName = "Enhancements"; - AddSidebarEntry("Randomizer", path.sidebarName, 1); + AddSidebarEntry("Randomizer", path.sidebarName, 3); + AddWidget(path, "Randomizer Enhancements", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Rando-Relevant Navi Hints", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_RANDOMIZER_ENHANCEMENT("RandoRelevantNavi")) .Options(CheckboxOptions().Tooltip( @@ -34,21 +37,21 @@ void SohMenu::AddMenuRandomizer() { .Options(CheckboxOptions().Tooltip( "Use Custom graphics for Dungeon Keys, Big and Small, so that they can be easily told apart." ).DefaultValue(true)); - AddWidget(path, "Compass Colors Match Dungeon", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_RANDOMIZER_ENHANCEMENT("MatchCompassColors")) + AddWidget(path, "Map & Compass Colors Match Dungeon", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_RANDOMIZER_ENHANCEMENT("ColoredMapsAndCompasses")) .PreFunc([](WidgetInfo& info) { info.options->disabled = !( OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).IsNot(RO_DUNGEON_ITEM_LOC_STARTWITH) && OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).IsNot(RO_DUNGEON_ITEM_LOC_VANILLA) && OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).IsNot(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON) ); - info.options->disabledTooltip = "This setting is disabled because a savefile is loaded without " - "the compass shuffle settings set to Any Dungeon, Overworld, or Anywhere."; + info.options->disabledTooltip = "This setting is disabled because a savefile is loaded without the map & compass\n" + "shuffle settings set to \"Any Dungeon\", \"Overworld\" or \"Anywhere\""; }) .Options(CheckboxOptions().Tooltip( - "Matches the color of compasses to the dungeon they belong to. " - "This helps identify compasses from afar and adds a little bit of flair.\n\nThis only " - "applies to seeds with compasses shuffled to \"Any Dungeon\", \"Overworld\", or \"Anywhere\"." + "Matches the color of maps & compasses to the dungeon they belong to. " + "This helps identify maps & compasses from afar and adds a little bit of flair.\n\nThis only " + "applies to seeds with maps & compasses shuffled to \"Any Dungeon\", \"Overworld\", or \"Anywhere\"." ).DefaultValue(true)); AddWidget(path, "Quest Item Fanfares", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_RANDOMIZER_ENHANCEMENT("QuestItemFanfares")) @@ -75,7 +78,9 @@ void SohMenu::AddMenuRandomizer() { AddWidget(path, "Item Scale: %.2f", WIDGET_CVAR_SLIDER_FLOAT) .CVar(CVAR_RANDOMIZER_ENHANCEMENT("TimeSavers.SkipGetItemAnimationScale")) .PreFunc([](WidgetInfo& info) { - info.isHidden = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("TimeSavers.SkipGetItemAnimation"), SGIA_DISABLED) == SGIA_DISABLED; + info.options->disabled = + !CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("TimeSavers.SkipGetItemAnimation"), SGIA_DISABLED); + info.options->disabledTooltip = "This slider only applies when using the \"Skip Get Item Animations\" option."; }) .Options(FloatSliderOptions() .Min(5.0f) diff --git a/soh/soh/SohGui/SohMenuSettings.cpp b/soh/soh/SohGui/SohMenuSettings.cpp index 5a186b0ae..093e98618 100644 --- a/soh/soh/SohGui/SohMenuSettings.cpp +++ b/soh/soh/SohGui/SohMenuSettings.cpp @@ -55,6 +55,7 @@ void SohMenu::AddMenuSettings() { WidgetPath path = { "Settings", "General", SECTION_COLUMN_1 }; // General - Settings + AddWidget(path, "General Settings", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Menu Theme", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_SETTING("Menu.Theme")) .Options(ComboboxOptions() @@ -65,7 +66,7 @@ void SohMenu::AddMenuSettings() { AddWidget(path, "Menu Controller Navigation", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_IMGUI_CONTROLLER_NAV) .Options(CheckboxOptions().Tooltip( - "Allows controller navigation of the 2Ship menu (Settings, Enhancements,...)\nCAUTION: " + "Allows controller navigation of the port menu (Settings, Enhancements,...)\nCAUTION: " "This will disable game inputs while the menu is visible.\n\nD-pad to move between " "items, A to select, B to move up in scope.")); AddWidget(path, "Cursor Always Visible", WIDGET_CVAR_CHECKBOX) @@ -101,12 +102,26 @@ void SohMenu::AddMenuSettings() { SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); }) .Options(ButtonOptions().Tooltip("Opens the folder that contains the save and mods folders, etc.")); + + AddWidget(path, "Boot", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Boot Sequence", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("BootSequence")) + .Options(ComboboxOptions() + .DefaultIndex(BOOTSEQUENCE_DEFAULT) + .LabelPosition(LabelPositions::Far) + .ComponentAlignment(ComponentAlignments::Right) + .ComboMap(bootSequenceLabels) + .Tooltip("Configure what happens when starting or resetting the game.\n\n" + "Default: LUS logo -> N64 logo\n" + "Authentic: N64 logo only\n" + "File Select: Skip to file select menu")); + AddWidget(path, "Languages", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Translate Title Screen", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_SETTING("TitleScreenTranslation")); AddWidget(path, "Menu Language", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_SETTING("Languages")) - .Options(ComboboxOptions().LabelPosition(LabelPosition::Far).ComponentAlignment(ComponentAlignment::Right).ComboMap(languages).DefaultIndex(LANGUAGE_ENG)); + .Options(ComboboxOptions().LabelPosition(LabelPositions::Far).ComponentAlignment(ComponentAlignments::Right).ComboMap(languages).DefaultIndex(LANGUAGE_ENG)); AddWidget(path, "Accessibility", WIDGET_SEPARATOR_TEXT); #if defined(_WIN32) || defined(__APPLE__) AddWidget(path, "Text to Speech", WIDGET_CVAR_CHECKBOX) @@ -117,11 +132,11 @@ void SohMenu::AddMenuSettings() { .CVar(CVAR_SETTING("A11yDisableIdleCam")) .Options(CheckboxOptions().Tooltip("Disables the automatic re-centering of the camera when idle.")); AddWidget(path, "EXPERIMENTAL", WIDGET_SEPARATOR_TEXT) - .Options(WidgetOptions().Color(Colors::Orange)); + .Options(TextOptions().Color(Colors::Orange)); AddWidget(path, "ImGui Menu Scaling", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_SETTING("ImGuiScale")) .Options(ComboboxOptions().ComboMap(imguiScaleOptions).Tooltip("Changes the scaling of the ImGui menu elements.").DefaultIndex(1) - .ComponentAlignment(ComponentAlignment::Right).LabelPosition(LabelPosition::Far)) + .ComponentAlignment(ComponentAlignments::Right).LabelPosition(LabelPositions::Far)) .Callback([](WidgetInfo& info) { OTRGlobals::Instance->ScaleImGui(); }); @@ -201,20 +216,13 @@ void SohMenu::AddMenuSettings() { AddWidget(path, "Audio API (Needs reload)", WIDGET_AUDIO_BACKEND); // Graphics Settings - static int32_t maxFps; - const char* tooltip = ""; - if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) { - maxFps = 360; - tooltip = "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is " - "purely visual and does not impact game logic, execution of glitches etc.\n\nA higher target " - "FPS than your monitor's refresh rate will waste resources, and might give a worse result."; - } else { - maxFps = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); - tooltip = "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is " - "purely visual and does not impact game logic, execution of glitches etc."; - } + static int32_t maxFps = 360; + const char* tooltip = "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is " + "purely visual and does not impact game logic, execution of glitches etc.\n\nA higher target " + "FPS than your monitor's refresh rate will waste resources, and might give a worse result."; path.sidebarName = "Graphics"; AddSidebarEntry("Settings", "Graphics", 3); + AddWidget(path, "Graphics Options", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Toggle Fullscreen", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_SETTING("Fullscreen")) .Callback([](WidgetInfo& info) { Ship::Context::GetInstance()->GetWindow()->ToggleFullscreen(); }) @@ -276,25 +284,14 @@ void SohMenu::AddMenuSettings() { info.activeDisables.push_back(DISABLE_FOR_MATCH_REFRESH_RATE_ON); }) .Options(IntSliderOptions().Tooltip(tooltip).Min(20).Max(maxFps).DefaultValue(20).Format(fpsFormat)); - AddWidget(path, "Match Refresh Rate", WIDGET_BUTTON) - .Callback([](WidgetInfo& info) { - int hz = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); - if (hz >= 20 && hz <= 360) { - CVarSetInteger(CVAR_SETTING("InterpolationFPS"), hz); - Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); - } - }) - .PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NOT_DIRECTX).active; }) - .Options(ButtonOptions().Tooltip("Matches interpolation value to the current game's window refresh rate.")); AddWidget(path, "Match Refresh Rate", WIDGET_CVAR_CHECKBOX) - .CVar("gMatchRefreshRate") - .PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_DIRECTX).active; }) - .Options(CheckboxOptions().Tooltip("Matches interpolation value to the current game's window refresh rate.")); + .CVar(CVAR_SETTING("MatchRefreshRate")) + .Options(CheckboxOptions().Tooltip("Matches interpolation value to the refresh rate of your display.")); AddWidget(path, "Renderer API (Needs reload)", WIDGET_VIDEO_BACKEND); AddWidget(path, "Enable Vsync", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_VSYNC_ENABLED) .PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NO_VSYNC).active; }) - .Options(CheckboxOptions().Tooltip("Enables Vsync.")); + .Options(CheckboxOptions().Tooltip("Removes tearing, but clamps your max FPS to your displays refresh rate.")); AddWidget(path, "Windowed Fullscreen", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_SDL_WINDOWED_FULLSCREEN) .PreFunc([](WidgetInfo& info) { @@ -311,9 +308,12 @@ void SohMenu::AddMenuSettings() { .CVar(CVAR_TEXTURE_FILTER) .Options(ComboboxOptions().Tooltip("Sets the applied Texture Filtering.").ComboMap(textureFilteringMap)); + path.column = SECTION_COLUMN_2; + AddWidget(path, "Advanced Graphics Options", WIDGET_SEPARATOR_TEXT); // Controls path.sidebarName = "Controls"; + path.column = SECTION_COLUMN_1; AddSidebarEntry("Settings", "Controls", 2); AddWidget(path, "Controller Bindings", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Popout Bindings Window", WIDGET_WINDOW_BUTTON) @@ -321,7 +321,9 @@ void SohMenu::AddMenuSettings() { .WindowName("Configure Controller") .Options(WindowButtonOptions().Tooltip("Enables the separate Bindings Window.")); - path.column = SECTION_COLUMN_2; + // Input Viewer + path.sidebarName = "Input Viewer"; + AddSidebarEntry("Settings", path.sidebarName, 3); AddWidget(path, "Input Viewer", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Toggle Input Viewer", WIDGET_WINDOW_BUTTON) .CVar(CVAR_WINDOW("InputViewer")) @@ -337,7 +339,7 @@ void SohMenu::AddMenuSettings() { // Notifications path.sidebarName = "Notifications"; path.column = SECTION_COLUMN_1; - AddSidebarEntry("Settings", "Notifications", 3); + AddSidebarEntry("Settings", path.sidebarName, 3); AddWidget(path, "Position", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_SETTING("Notifications.Position")) .Options(ComboboxOptions() diff --git a/soh/soh/SohGui/SohModals.cpp b/soh/soh/SohGui/SohModals.cpp index c810d52e6..b1fe0b43b 100644 --- a/soh/soh/SohGui/SohModals.cpp +++ b/soh/soh/SohGui/SohModals.cpp @@ -30,7 +30,6 @@ void SohModalWindow::Draw() { } void SohModalWindow::DrawElement() { - ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger); if (modals.size() > 0) { SohModal curModal = modals.at(0); if (!ImGui::IsPopupOpen(curModal.title_.c_str())) { @@ -62,7 +61,6 @@ void SohModalWindow::DrawElement() { } ImGui::EndPopup(); } - ImGui::PopFont(); } void SohModalWindow::RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function button1callback, std::function button2callback) { diff --git a/soh/soh/SohGui/UIWidgets.cpp b/soh/soh/SohGui/UIWidgets.cpp index 7fbad6705..9875cf7b9 100644 --- a/soh/soh/SohGui/UIWidgets.cpp +++ b/soh/soh/SohGui/UIWidgets.cpp @@ -193,8 +193,8 @@ bool WindowButton(const char* label, const char* cvarName, std::shared_ptrToggleVisibility(); dirty = true; } @@ -285,10 +285,10 @@ bool Checkbox(const char* _label, bool* value, const CheckboxOptions& options) { ImGui::BeginDisabled(options.disabled); - bool above = options.labelPosition == LabelPosition::Above; - bool lpFar = options.labelPosition == LabelPosition::Far; - bool right = options.alignment == ComponentAlignment::Right; - bool none = options.labelPosition == LabelPosition::None; + bool above = options.labelPosition == LabelPositions::Above; + bool lpFar = options.labelPosition == LabelPositions::Far; + bool right = options.alignment == ComponentAlignments::Right; + bool none = options.labelPosition == LabelPositions::None; std::string labelStr = (none ? "##" : ""); labelStr.append(_label); @@ -327,12 +327,12 @@ bool Checkbox(const char* _label, bool* value, const CheckboxOptions& options) { PushStyleCheckbox(options.color); ImVec2 checkPos = pos; ImVec2 labelPos = pos; - if (options.labelPosition == LabelPosition::Above) { + if (options.labelPosition == LabelPositions::Above) { checkPos.y += label_size.y + (style.ItemInnerSpacing.y * 2.0f); } else { labelPos.y += (square_sz / 2) - (label_size.y / 2); } - if (options.alignment == ComponentAlignment::Right) { + if (options.alignment == ComponentAlignments::Right) { checkPos.x = total_bb.Max.x - square_sz; } else { float labelFarOffset = ImGui::GetContentRegionAvail().x - label_size.x; @@ -518,22 +518,22 @@ bool SliderInt(const char* label, int32_t* value, const IntSliderOptions& option ImGui::BeginDisabled(options.disabled); PushStyleSlider(options.color); float width = (options.size == ImVec2(0,0)) ? ImGui::GetContentRegionAvail().x : options.size.x; - if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) { + if (options.labelPosition == LabelPositions::Near || options.labelPosition == LabelPositions::Far) { width = width - (ImGui::CalcTextSize(label).x + ImGui::GetStyle().FramePadding.x); } ImGui::AlignTextToFramePadding(); - if (options.alignment == ComponentAlignment::Right) { + if (options.alignment == ComponentAlignments::Right) { ImGui::Text(label, *value); - if (options.labelPosition == LabelPosition::Above) { + if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); - } else if (options.labelPosition == LabelPosition::Near) { + } else if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); - } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + } else if (options.labelPosition == LabelPositions::Far || options.labelPosition == LabelPositions::None) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); } - } else if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { + } else if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Above) { ImGui::Text(label, *value); } } @@ -576,11 +576,11 @@ bool SliderInt(const char* label, int32_t* value, const IntSliderOptions& option } } - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Near) { + if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); ImGui::Text(label, *value); - } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + } else if (options.labelPosition == LabelPositions::Far || options.labelPosition == LabelPositions::None) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x); ImGui::Text(label, *value); } @@ -611,33 +611,25 @@ bool CVarSliderInt(const char* label, const char* cvarName, const IntSliderOptio } void ClampFloat(float* value, float min, float max, float step) { - int ticks = 0; - float increment = 1.0f; + int factor = 1; if (step < 1.0f) { - ticks++; - increment = 0.1f; + factor *= 10; } if (step < 0.1f) { - ticks++; - increment = 0.01f; + factor *= 10; } if (step < 0.01f) { - ticks++; - increment = 0.001f; + factor *= 10; } if (step < 0.001f) { - ticks++; - increment = 0.0001f; + factor *= 10; } if (step < 0.0001f) { - ticks++; - increment = 0.00001f; + factor *= 10; } if (step < 0.00001f) { - ticks++; - increment = 0.000001f; + factor *= 10; } - int factor = 1 * std::pow(10, ticks); if (*value < min) { *value = min; } else if (*value > max) { @@ -661,24 +653,24 @@ bool SliderFloat(const char* label, float* value, const FloatSliderOptions& opti PushStyleSlider(options.color); float labelSpacing = ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x; float width = (options.size == ImVec2(0, 0)) ? ImGui::GetContentRegionAvail().x : options.size.x; - if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) { + if (options.labelPosition == LabelPositions::Near || options.labelPosition == LabelPositions::Far) { width = width - (ImGui::CalcTextSize(label).x + ImGui::GetStyle().FramePadding.x); } ImGui::AlignTextToFramePadding(); - if (options.alignment == ComponentAlignment::Right) { + if (options.alignment == ComponentAlignments::Right) { ImGui::Text(label, *value); - if (options.labelPosition == LabelPosition::Above) { + if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); - } else if (options.labelPosition == LabelPosition::Near) { + } else if (options.labelPosition == LabelPositions::Near) { width -= labelSpacing; ImGui::SameLine(); - } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + } else if (options.labelPosition == LabelPositions::Far || options.labelPosition == LabelPositions::None) { width -= labelSpacing; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); } - } else if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { + } else if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Above) { ImGui::Text(label, *value); } } @@ -715,11 +707,11 @@ bool SliderFloat(const char* label, float* value, const FloatSliderOptions& opti } } - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Near) { + if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); ImGui::Text(label, *value); - } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + } else if (options.labelPosition == LabelPositions::Far || options.labelPosition == LabelPositions::None) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - labelSpacing); ImGui::Text(label, *value); } @@ -765,19 +757,24 @@ bool InputString(const char* label, std::string* value, const InputOptions& opti ImGui::BeginDisabled(options.disabled); PushStyleInput(options.color); float width = (options.size == ImVec2(0, 0)) ? ImGui::GetContentRegionAvail().x : options.size.x; - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { + if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Above) { ImGui::Text(label, *value->c_str()); } - } else if (options.alignment == ComponentAlignment::Right) { - if (options.labelPosition == LabelPosition::Above) { + } else if (options.alignment == ComponentAlignments::Right) { + if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(width - ImGui::CalcTextSize(label).x); ImGui::Text(label, *value->c_str()); } } ImGui::SetNextItemWidth(width); - if (ImGui::InputText(label, (char*)value->c_str(), value->capacity() + 1, ImGuiInputTextFlags_CallbackResize, InputTextResizeCallback, value)) { + ImGuiInputTextFlags flags = ImGuiInputTextFlags_CallbackResize; + if (options.secret) { + flags |= ImGuiInputTextFlags_Password; + } + flags |= options.addedFlags; + if (ImGui::InputText(label, (char*)value->c_str(), value->capacity() + 1, flags, InputTextResizeCallback, value)) { dirty = true; } if (value->empty() && !options.placeholder.empty()) { @@ -816,19 +813,19 @@ bool InputInt(const char* label, int32_t* value, const InputOptions& options) { ImGui::BeginDisabled(options.disabled); PushStyleInput(options.color); float width = (options.size == ImVec2(0, 0)) ? ImGui::GetContentRegionAvail().x : options.size.x; - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { + if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Above) { ImGui::Text(label, *value); } - } else if (options.alignment == ComponentAlignment::Right) { - if (options.labelPosition == LabelPosition::Above) { + } else if (options.alignment == ComponentAlignments::Right) { + if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(width - ImGui::CalcTextSize(label).x); ImGui::Text(label, *value); } } ImGui::SetNextItemWidth(width); - if (ImGui::InputScalar(label, ImGuiDataType_S32, value)) { + if (ImGui::InputScalar(label, ImGuiDataType_S32, value, nullptr, nullptr, nullptr, options.addedFlags)) { dirty = true; } if ((ImGui::GetItemStatusFlags() & ImGuiItemStatusFlags_Edited) && !options.placeholder.empty()) { diff --git a/soh/soh/SohGui/UIWidgets.hpp b/soh/soh/SohGui/UIWidgets.hpp index ebf483194..325795023 100644 --- a/soh/soh/SohGui/UIWidgets.hpp +++ b/soh/soh/SohGui/UIWidgets.hpp @@ -105,7 +105,7 @@ namespace UIWidgets { const ImVec2 Fill = ImVec2(-1.0f, 0.0f); } - enum LabelPosition { + enum LabelPositions { Near, Far, Above, @@ -113,7 +113,7 @@ namespace UIWidgets { Within, }; - enum ComponentAlignment { + enum ComponentAlignments { Left, Right, }; @@ -122,12 +122,7 @@ namespace UIWidgets { const char* tooltip = ""; bool disabled = false; const char* disabledTooltip = ""; - Colors color = Colors::NoColor; - WidgetOptions& Color(Colors color_) { - color = color = color_; - return *this; - } WidgetOptions& Tooltip(const char* tooltip_) { tooltip = tooltip_; return *this; @@ -142,6 +137,15 @@ namespace UIWidgets { } }; + struct TextOptions : WidgetOptions { + Colors color = Colors::NoColor; + + TextOptions& Color(Colors color_) { + color = color_; + return *this; + } + }; + struct ButtonOptions : WidgetOptions { ImVec2 size = Sizes::Fill; ImVec2 padding = ImVec2(10.0f, 8.0f); @@ -160,7 +164,7 @@ namespace UIWidgets { return *this; } ButtonOptions& Color(Colors color_) { - WidgetOptions::color = color = color_; + color = color_; return *this; } }; @@ -185,7 +189,7 @@ namespace UIWidgets { return *this; } WindowButtonOptions& Color(Colors color_) { - WidgetOptions::color = color = color_; + color = color_; return *this; } WindowButtonOptions& ShowButton(bool showButton_) { @@ -200,19 +204,19 @@ namespace UIWidgets { struct CheckboxOptions : WidgetOptions { bool defaultValue = false; // Only applicable to CVarCheckbox - ComponentAlignment alignment = ComponentAlignment::Left; - LabelPosition labelPosition = LabelPosition::Near; - Colors color = WidgetOptions::color = Colors::LightBlue; + ComponentAlignments alignment = ComponentAlignments::Left; + LabelPositions labelPosition = LabelPositions::Near; + Colors color = Colors::LightBlue; CheckboxOptions& DefaultValue(bool defaultValue_) { defaultValue = defaultValue_; return *this; } - CheckboxOptions& ComponentAlignment(ComponentAlignment alignment_) { + CheckboxOptions& ComponentAlignment(ComponentAlignments alignment_) { alignment = alignment_; return *this; } - CheckboxOptions& LabelPosition(LabelPosition labelPosition_) { + CheckboxOptions& LabelPosition(LabelPositions labelPosition_) { labelPosition = labelPosition_; return *this; } @@ -221,7 +225,7 @@ namespace UIWidgets { return *this; } CheckboxOptions& Color(Colors color_) { - WidgetOptions::color = color = color_; + color = color_; return *this; } CheckboxOptions& DisabledTooltip(const char* disabledTooltip_) { @@ -233,8 +237,8 @@ namespace UIWidgets { struct ComboboxOptions : WidgetOptions { std::unordered_map comboMap = {}; uint32_t defaultIndex = 0; // Only applicable to CVarCombobox - ComponentAlignment alignment = ComponentAlignment::Left; - LabelPosition labelPosition = LabelPosition::Above; + ComponentAlignments alignment = ComponentAlignments::Left; + LabelPositions labelPosition = LabelPositions::Above; ImGuiComboFlags flags = 0; Colors color = Colors::LightBlue; @@ -246,11 +250,11 @@ namespace UIWidgets { defaultIndex = defaultIndex_; return *this; } - ComboboxOptions& ComponentAlignment(ComponentAlignment alignment_) { + ComboboxOptions& ComponentAlignment(ComponentAlignments alignment_) { alignment = alignment_; return *this; } - ComboboxOptions& LabelPosition(LabelPosition labelPosition_) { + ComboboxOptions& LabelPosition(LabelPositions labelPosition_) { labelPosition = labelPosition_; return *this; } @@ -259,7 +263,7 @@ namespace UIWidgets { return *this; } ComboboxOptions& Color(Colors color_) { - WidgetOptions::color = color = color_; + color = color_; return *this; } }; @@ -272,8 +276,8 @@ namespace UIWidgets { int32_t max = 10; int32_t defaultValue = 1; bool clamp = true; - ComponentAlignment alignment = ComponentAlignment::Left; - LabelPosition labelPosition = LabelPosition::Above; + ComponentAlignments alignment = ComponentAlignments::Left; + LabelPositions labelPosition = LabelPositions::Above; Colors color = Colors::Gray; ImGuiSliderFlags flags = 0; ImVec2 size = {0,0}; @@ -302,11 +306,11 @@ namespace UIWidgets { defaultValue = defaultValue_; return *this; } - IntSliderOptions& ComponentAlignment(ComponentAlignment alignment_) { + IntSliderOptions& ComponentAlignment(ComponentAlignments alignment_) { alignment = alignment_; return *this; } - IntSliderOptions& LabelPosition(LabelPosition labelPosition_) { + IntSliderOptions& LabelPosition(LabelPositions labelPosition_) { labelPosition = labelPosition_; return *this; } @@ -315,7 +319,7 @@ namespace UIWidgets { return *this; } IntSliderOptions& Color(Colors color_) { - WidgetOptions::color = color = color_; + color = color_; return *this; } IntSliderOptions& Size(ImVec2 size_) { @@ -337,8 +341,8 @@ namespace UIWidgets { float defaultValue = 1.0f; bool clamp = true; bool isPercentage = false; // Multiplies visual value by 100 - ComponentAlignment alignment = ComponentAlignment::Left; - LabelPosition labelPosition = LabelPosition::Above; + ComponentAlignments alignment = ComponentAlignments::Left; + LabelPositions labelPosition = LabelPositions::Above; Colors color = Colors::Gray; ImGuiSliderFlags flags = 0; ImVec2 size = {0,0}; @@ -367,11 +371,11 @@ namespace UIWidgets { defaultValue = defaultValue_; return *this; } - FloatSliderOptions& ComponentAlignment(ComponentAlignment alignment_) { + FloatSliderOptions& ComponentAlignment(ComponentAlignments alignment_) { alignment = alignment_; return *this; } - FloatSliderOptions& LabelPosition(LabelPosition labelPosition_) { + FloatSliderOptions& LabelPosition(LabelPositions labelPosition_) { labelPosition = labelPosition_; return *this; } @@ -387,7 +391,7 @@ namespace UIWidgets { return *this; } FloatSliderOptions& Color(Colors color_) { - WidgetOptions::color = color = color_; + color = color_; return *this; } FloatSliderOptions& Size(ImVec2 size_) { @@ -402,6 +406,7 @@ namespace UIWidgets { struct RadioButtonsOptions : WidgetOptions { std::unordered_map buttonMap; + Colors color = Colors::LightBlue; RadioButtonsOptions& ButtonMap(std::unordered_map buttonMap_) { buttonMap = buttonMap_; @@ -412,26 +417,28 @@ namespace UIWidgets { return *this; } RadioButtonsOptions& Color(Colors color_) { - WidgetOptions::color = color = color_; + color = color_; return *this; } }; struct InputOptions : WidgetOptions { - ComponentAlignment alignment = ComponentAlignment::Left; - LabelPosition labelPosition = LabelPosition::Above; + ComponentAlignments alignment = ComponentAlignments::Left; + LabelPositions labelPosition = LabelPositions::Above; Colors color = Colors::Gray; ImVec2 size = {0,0}; std::string placeholder = ""; InputTypes type = InputTypes::String; std::string defaultValue = ""; + bool secret = false; + ImGuiInputFlags addedFlags = 0; InputOptions& Tooltip(const char* tooltip_) { WidgetOptions::tooltip = tooltip_; return *this; } InputOptions& Color(Colors color_) { - WidgetOptions::color = color = color_; + color = color_; return *this; } InputOptions& Size(ImVec2 size_) { @@ -439,7 +446,7 @@ namespace UIWidgets { return *this; } - InputOptions& LabelPosition(LabelPosition labelPosition_) { + InputOptions& LabelPosition(LabelPositions labelPosition_) { labelPosition = labelPosition_; return *this; } @@ -463,6 +470,11 @@ namespace UIWidgets { defaultValue = defaultValue_; return *this; } + + InputOptions& IsSecret(bool secret_ = false) { + secret = secret_; + return *this; + } }; void PushStyleMenu(const ImVec4& color); @@ -508,92 +520,6 @@ namespace UIWidgets { void Separator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f); - /*using ComboVariant = std::variant&, const std::vector&>; - - bool Combobox(const char* label, int32_t* value, ComboVariant comboSource, const ComboboxOptions& options = {}) { - bool dirty = false; - float startX = ImGui::GetCursorPosX(); - std::string invisibleLabelStr = "##" + std::string(label); - const char* invisibleLabel = invisibleLabelStr.c_str(); - ImGui::PushID(label); - ImGui::BeginGroup(); - ImGui::BeginDisabled(options.disabled); - PushStyleCombobox(options.color); - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { - ImGui::Text("%s", label); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - } else if (options.labelPosition == LabelPosition::Near) { - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().ItemSpacing.x * 2); - } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { - ImGui::SetNextItemWidth(ImGui::CalcTextSize(comboMap.at(*value)).x + ImGui::GetStyle().FramePadding.x * 4 + ImGui::GetStyle().ItemSpacing.x); - } - } else if (options.alignment == ComponentAlignment::Right) { - if (options.labelPosition == LabelPosition::Above) { - ImGui::NewLine(); - ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); - ImGui::Text("%s", label); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - } else if (options.labelPosition == LabelPosition::Near) { - ImGui::SameLine(ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x * 2); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { - float width = ImGui::CalcTextSize(comboMap.at(*value)).x + ImGui::GetStyle().FramePadding.x * 4; - ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - } - } - if (ImGui::BeginCombo(invisibleLabel, comboMap.at(*value), options.flags)) { - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f)); - for (const auto& pair : comboMap) { - if (strlen(pair.second) > 1) { - if (ImGui::Selectable(pair.second, pair.first == *value)) { - *value = pair.first; - dirty = true; - } - } - } - ImGui::PopStyleVar(); - ImGui::EndCombo(); - } - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Near) { - ImGui::SameLine(); - ImGui::Text("%s", label); - } else if (options.labelPosition == LabelPosition::Far) { - ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); - ImGui::Text("%s", label); - } - } else if (options.alignment == ComponentAlignment::Right) { - if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) { - ImGui::SameLine(startX); - ImGui::Text("%s", label); - } - } - PopStyleCombobox(); - ImGui::EndDisabled(); - ImGui::EndGroup(); - if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.disabledTooltip)) { - ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str()); - } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) { - ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str()); - } - ImGui::PopID(); - return dirty; - } - - bool CVarCombobox(const char* label, const char* cvarName, ComboVariant comboSource, const ComboboxOptions& options = {}) { - bool dirty = false; - int32_t value = CVarGetInteger(cvarName, options.defaultIndex); - if (Combobox(label, &value, comboSource, options)) { - CVarSetInteger(cvarName, value); - Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); - ShipInit::Init(cvarName); - dirty = true; - } - return dirty; - }*/ - float CalcComboWidth(const char* preview_value, ImGuiComboFlags flags); template @@ -619,20 +545,20 @@ namespace UIWidgets { float comboWidth = CalcComboWidth(longest, options.flags); ImGui::AlignTextToFramePadding(); - if (options.labelPosition != LabelPosition::None) { - if (options.alignment == ComponentAlignment::Right) { - ImGui::Text(label); - if (options.labelPosition == LabelPosition::Above) { + if (options.labelPosition != LabelPositions::None) { + if (options.alignment == ComponentAlignments::Right) { + ImGui::Text("%s", label); + if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(ImGui::GetContentRegionAvail().x - comboWidth); - } else if (options.labelPosition == LabelPosition::Near) { + } else if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); - } else if (options.labelPosition == LabelPosition::Far) { + } else if (options.labelPosition == LabelPositions::Far) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - comboWidth); } - } else if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { - ImGui::Text(label); + } else if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Above) { + ImGui::Text("%s", label); } } } @@ -652,12 +578,12 @@ namespace UIWidgets { ImGui::EndCombo(); } - if (options.labelPosition != LabelPosition::None) { - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Near) { + if (options.labelPosition != LabelPositions::None) { + if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); ImGui::Text("%s", label); - } else if (options.labelPosition == LabelPosition::Far) { + } else if (options.labelPosition == LabelPositions::Far) { float width = ImGui::CalcTextSize(comboMap.at(*value)).x + ImGui::GetStyle().FramePadding.x * 2; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); ImGui::Text("%s", label); @@ -699,19 +625,19 @@ namespace UIWidgets { float comboWidth = CalcComboWidth(longest, options.flags); ImGui::AlignTextToFramePadding(); - if (options.labelPosition != LabelPosition::None) { - if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition != LabelPositions::None) { + if (options.alignment == ComponentAlignments::Right) { ImGui::Text("%s", label); - if (options.labelPosition == LabelPosition::Above) { + if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(ImGui::GetContentRegionAvail().x - comboWidth); - } else if (options.labelPosition == LabelPosition::Near) { + } else if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); - } else if (options.labelPosition == LabelPosition::Far) { + } else if (options.labelPosition == LabelPositions::Far) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - comboWidth); } - } else if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { + } else if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Above) { ImGui::Text("%s", label); } } @@ -733,12 +659,12 @@ namespace UIWidgets { ImGui::EndCombo(); } - if (options.labelPosition != LabelPosition::None) { - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Near) { + if (options.labelPosition != LabelPositions::None) { + if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); ImGui::Text("%s", label); - } else if (options.labelPosition == LabelPosition::Far) { + } else if (options.labelPosition == LabelPositions::Far) { float width = ImGui::CalcTextSize(comboVector.at(*value)).x + ImGui::GetStyle().FramePadding.x * 2; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); ImGui::Text("%s", label); @@ -781,19 +707,19 @@ namespace UIWidgets { float comboWidth = CalcComboWidth(longest, options.flags); ImGui::AlignTextToFramePadding(); - if (options.labelPosition != LabelPosition::None) { - if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition != LabelPositions::None) { + if (options.alignment == ComponentAlignments::Right) { ImGui::Text("%s", label); - if (options.labelPosition == LabelPosition::Above) { + if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(ImGui::GetContentRegionAvail().x - comboWidth); - } else if (options.labelPosition == LabelPosition::Near) { + } else if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); - } else if (options.labelPosition == LabelPosition::Far) { + } else if (options.labelPosition == LabelPositions::Far) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - comboWidth); } - } else if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { + } else if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Above) { ImGui::Text("%s", label); } } @@ -815,12 +741,12 @@ namespace UIWidgets { ImGui::EndCombo(); } - if (options.labelPosition != LabelPosition::None) { - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Near) { + if (options.labelPosition != LabelPositions::None) { + if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); ImGui::Text("%s", label); - } else if (options.labelPosition == LabelPosition::Far) { + } else if (options.labelPosition == LabelPositions::Far) { float width = ImGui::CalcTextSize(comboVector.at(*value).c_str()).x + ImGui::GetStyle().FramePadding.x * 2; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); ImGui::Text("%s", label); @@ -866,19 +792,19 @@ namespace UIWidgets { float comboWidth = CalcComboWidth(longest, options.flags); ImGui::AlignTextToFramePadding(); - if (options.labelPosition != LabelPosition::None) { - if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition != LabelPositions::None) { + if (options.alignment == ComponentAlignments::Right) { ImGui::Text("%s", label); - if (options.labelPosition == LabelPosition::Above) { + if (options.labelPosition == LabelPositions::Above) { ImGui::NewLine(); ImGui::SameLine(ImGui::GetContentRegionAvail().x - comboWidth); - } else if (options.labelPosition == LabelPosition::Near) { + } else if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); - } else if (options.labelPosition == LabelPosition::Far) { + } else if (options.labelPosition == LabelPositions::Far) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - comboWidth); } - } else if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { + } else if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Above) { ImGui::Text("%s", label); } } @@ -900,12 +826,12 @@ namespace UIWidgets { ImGui::EndCombo(); } - if (options.labelPosition != LabelPosition::None) { - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Near) { + if (options.labelPosition != LabelPositions::None) { + if (options.alignment == ComponentAlignments::Left) { + if (options.labelPosition == LabelPositions::Near) { ImGui::SameLine(); ImGui::Text("%s", label); - } else if (options.labelPosition == LabelPosition::Far) { + } else if (options.labelPosition == LabelPositions::Far) { float width = ImGui::CalcTextSize(comboArray[*value]).x + ImGui::GetStyle().FramePadding.x * 2; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); ImGui::Text("%s", label); diff --git a/soh/soh/config/ConfigMigrators.h b/soh/soh/config/ConfigMigrators.h index 008d5692a..f3c663f66 100644 --- a/soh/soh/config/ConfigMigrators.h +++ b/soh/soh/config/ConfigMigrators.h @@ -186,7 +186,7 @@ namespace SOH { { MigrationAction::Rename, "gDisableGrottoRotation", "gEnhancements.DisableGrottoRotation" }, { MigrationAction::Rename, "gDisableKokiriDrawDistance", "gEnhancements.DisableKokiriDrawDistance" }, { MigrationAction::Rename, "gDisableLOD", "gEnhancements.DisableLOD" }, - { MigrationAction::Rename, "gDisableNaviCallAudio", "gEnhancements.DisableNaviCallAudio" }, + { MigrationAction::Rename, "gDisableNaviCallAudio", "gAudioEditor.DisableNaviCallAudio" }, { MigrationAction::Rename, "gDisableTunicWarningText", "gEnhancements.DisableTunicWarningText" }, { MigrationAction::Rename, "gDogFollowsEverywhere", "gEnhancements.DogFollowsEverywhere" }, { MigrationAction::Rename, "gDpadNoDropOcarinaInput", "gEnhancements.DpadNoDropOcarinaInput" }, @@ -236,7 +236,7 @@ namespace SOH { { MigrationAction::Rename, "gInstantShootingGalleryWin", "gEnhancements.InstantShootingGalleryWin" }, { MigrationAction::Rename, "gIvanCoopModeEnabled", "gEnhancements.IvanCoopModeEnabled" }, { MigrationAction::Rename, "gLinkDefaultName", "gEnhancements.LinkDefaultName" }, - { MigrationAction::Rename, "gLowHpAlarm", "gEnhancements.LowHpAlarm" }, + { MigrationAction::Rename, "gLowHpAlarm", "gAudioEditor.LowHpAlarm" }, { MigrationAction::Rename, "gMMBunnyHood", "gEnhancements.MMBunnyHood" }, { MigrationAction::Rename, "gMarketSneak", "gEnhancements.MarketSneak" }, { MigrationAction::Rename, "gMaskSelect", "gEnhancements.MaskSelect" }, diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index 022aeee37..f03db52ba 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -150,17 +150,13 @@ bool Scene_CommandObjectList(PlayState* play, SOH::ISceneCommand* cmd) { s32 i; s32 j; s32 k; - ObjectStatus* status; ObjectStatus* status2; - ObjectStatus* firstStatus; // s16* objectEntry = SEGMENTED_TO_VIRTUAL(cmd->objectList.segment); s16* objectEntry = (s16*)cmdObj->GetRawPointer(); void* nextPtr; k = 0; i = play->objectCtx.unk_09; - firstStatus = &play->objectCtx.status[0]; - status = &play->objectCtx.status[i]; // Loop until a mismatch in the object lists // Then clear all object ids past that in the context object list and kill actors for those objects diff --git a/soh/src/code/z_lifemeter.c b/soh/src/code/z_lifemeter.c index 726e8d44d..0deab1a70 100644 --- a/soh/src/code/z_lifemeter.c +++ b/soh/src/code/z_lifemeter.c @@ -651,7 +651,7 @@ void HealthMeter_HandleCriticalAlarm(PlayState* play) { if (interfaceCtx->unk_22A <= 0) { interfaceCtx->unk_22A = 0; interfaceCtx->unk_22C = 0; - if (CVarGetInteger(CVAR_ENHANCEMENT("LowHpAlarm"), 0) == 0 && !Player_InCsMode(play) && (play->pauseCtx.state == 0) && + if (CVarGetInteger(CVAR_AUDIO("LowHpAlarm"), 0) == 0 && !Player_InCsMode(play) && (play->pauseCtx.state == 0) && (play->pauseCtx.debugState == 0) && HealthMeter_IsCritical() && !Play_InCsMode(play)) { Sfx_PlaySfxCentered(NA_SE_SY_HITPOINT_ALARM); } diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index f424b9fcd..8c93b8a57 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2832,7 +2832,7 @@ void Interface_SetNaviCall(PlayState* play, u16 naviCallState) { if (((naviCallState == 0x1D) || (naviCallState == 0x1E)) && !interfaceCtx->naviCalling && (play->csCtx.state == CS_STATE_IDLE)) { - if (!CVarGetInteger(CVAR_ENHANCEMENT("DisableNaviCallAudio"), 0)) { + if (!CVarGetInteger(CVAR_AUDIO("DisableNaviCallAudio"), 0)) { // clang-format off if (naviCallState == 0x1E) { Audio_PlaySoundGeneral(NA_SE_VO_NAVY_CALL, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } diff --git a/soh/src/overlays/actors/ovl_En_Daiku/z_en_daiku.c b/soh/src/overlays/actors/ovl_En_Daiku/z_en_daiku.c index 15c1950aa..d40d25499 100644 --- a/soh/src/overlays/actors/ovl_En_Daiku/z_en_daiku.c +++ b/soh/src/overlays/actors/ovl_En_Daiku/z_en_daiku.c @@ -451,6 +451,10 @@ void EnDaiku_InitSubCamera(EnDaiku* this, PlayState* play) { this->subCamActive = true; this->escapeSubCamTimer = sEscapeSubCamParams[this->actor.params & 3].maxFramesActive; + if (!GameInteractor_Should(VB_PLAY_CARPENTER_FREE_CS, true, this)) { + return; + } + eyePosDeltaLocal.x = sEscapeSubCamParams[this->actor.params & 3].eyePosDeltaLocal.x; eyePosDeltaLocal.y = sEscapeSubCamParams[this->actor.params & 3].eyePosDeltaLocal.y; eyePosDeltaLocal.z = sEscapeSubCamParams[this->actor.params & 3].eyePosDeltaLocal.z; @@ -477,6 +481,10 @@ void EnDaiku_InitSubCamera(EnDaiku* this, PlayState* play) { void EnDaiku_UpdateSubCamera(EnDaiku* this, PlayState* play) { s32 pad; + if (!GameInteractor_Should(VB_PLAY_CARPENTER_FREE_CS, true, this)) { + return; + } + this->subCamAtTarget.x = this->actor.world.pos.x; this->subCamAtTarget.y = this->actor.world.pos.y + 60.0f; this->subCamAtTarget.z = this->actor.world.pos.z; @@ -493,8 +501,10 @@ void EnDaiku_EscapeSuccess(EnDaiku* this, PlayState* play) { Actor* gerudoGuard; Vec3f vec; - Play_ClearCamera(play, this->subCamId); - Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_ACTIVE); + if (GameInteractor_Should(VB_PLAY_CARPENTER_FREE_CS, true, this)) { + Play_ClearCamera(play, this->subCamId); + Play_ChangeCameraStatus(play, MAIN_CAM, CAM_STAT_ACTIVE); + } this->subCamActive = false; if (GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) {