diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6dc479fb4..ec9f14f5b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
-project(Ship VERSION 9.0.1 LANGUAGES C CXX)
+project(Ship VERSION 9.0.2 LANGUAGES C CXX)
include(CMake/soh-cvars.cmake)
include(CMake/lus-cvars.cmake)
diff --git a/libultraship b/libultraship
index ffc062cbf..35c3a7e80 160000
--- a/libultraship
+++ b/libultraship
@@ -1 +1 @@
-Subproject commit ffc062cbf44ce8dc07ac9fc0185224010bd78cc5
+Subproject commit 35c3a7e80721e5f5a5260753c14499dc943dd3d8
diff --git a/soh/assets/xml/GC_MQ_NTSC_J/textures/item_name_static.xml b/soh/assets/xml/GC_MQ_NTSC_J/textures/item_name_static.xml
index 266b3c200..1bc074c2f 100644
--- a/soh/assets/xml/GC_MQ_NTSC_J/textures/item_name_static.xml
+++ b/soh/assets/xml/GC_MQ_NTSC_J/textures/item_name_static.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/soh/assets/xml/GC_MQ_NTSC_U/textures/item_name_static.xml b/soh/assets/xml/GC_MQ_NTSC_U/textures/item_name_static.xml
index 266b3c200..1bc074c2f 100644
--- a/soh/assets/xml/GC_MQ_NTSC_U/textures/item_name_static.xml
+++ b/soh/assets/xml/GC_MQ_NTSC_U/textures/item_name_static.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/soh/assets/xml/GC_NMQ_NTSC_J/textures/item_name_static.xml b/soh/assets/xml/GC_NMQ_NTSC_J/textures/item_name_static.xml
index 266b3c200..1bc074c2f 100644
--- a/soh/assets/xml/GC_NMQ_NTSC_J/textures/item_name_static.xml
+++ b/soh/assets/xml/GC_NMQ_NTSC_J/textures/item_name_static.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/soh/assets/xml/GC_NMQ_NTSC_J_CE/textures/item_name_static.xml b/soh/assets/xml/GC_NMQ_NTSC_J_CE/textures/item_name_static.xml
index 266b3c200..1bc074c2f 100644
--- a/soh/assets/xml/GC_NMQ_NTSC_J_CE/textures/item_name_static.xml
+++ b/soh/assets/xml/GC_NMQ_NTSC_J_CE/textures/item_name_static.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/soh/assets/xml/GC_NMQ_NTSC_U/textures/item_name_static.xml b/soh/assets/xml/GC_NMQ_NTSC_U/textures/item_name_static.xml
index 266b3c200..1bc074c2f 100644
--- a/soh/assets/xml/GC_NMQ_NTSC_U/textures/item_name_static.xml
+++ b/soh/assets/xml/GC_NMQ_NTSC_U/textures/item_name_static.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/soh/assets/xml/N64_NTSC_10/textures/item_name_static.xml b/soh/assets/xml/N64_NTSC_10/textures/item_name_static.xml
index 266b3c200..1bc074c2f 100644
--- a/soh/assets/xml/N64_NTSC_10/textures/item_name_static.xml
+++ b/soh/assets/xml/N64_NTSC_10/textures/item_name_static.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/soh/assets/xml/N64_NTSC_11/textures/item_name_static.xml b/soh/assets/xml/N64_NTSC_11/textures/item_name_static.xml
index 266b3c200..1bc074c2f 100644
--- a/soh/assets/xml/N64_NTSC_11/textures/item_name_static.xml
+++ b/soh/assets/xml/N64_NTSC_11/textures/item_name_static.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/soh/assets/xml/N64_NTSC_12/textures/item_name_static.xml b/soh/assets/xml/N64_NTSC_12/textures/item_name_static.xml
index 266b3c200..1bc074c2f 100644
--- a/soh/assets/xml/N64_NTSC_12/textures/item_name_static.xml
+++ b/soh/assets/xml/N64_NTSC_12/textures/item_name_static.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/soh/soh/Enhancements/Presets/PresetEntries.cpp b/soh/soh/Enhancements/Presets/PresetEntries.cpp
index ebf6d4a19..c9ca5c24f 100644
--- a/soh/soh/Enhancements/Presets/PresetEntries.cpp
+++ b/soh/soh/Enhancements/Presets/PresetEntries.cpp
@@ -46,7 +46,7 @@ const std::vector vanillaPlusPresetEntries = {
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixZoraHintDialogue"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixVineFall"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("EnemySpawnsOverWaterboxes"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixSawSoftlock"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DekuNutUpgradeFix"), 1),
- PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixGrokenGiantsKnife"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixMenuLR"), 1),
+ PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixBrokenGiantsKnife"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixMenuLR"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixDungeonMinimapIcon"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("TwoHandedIdle"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("NaviTextFix"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("GerudoWarriorClothingFix"), 1),
@@ -125,7 +125,7 @@ const std::vector enhancedPresetEntries = {
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixZoraHintDialogue"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixVineFall"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("EnemySpawnsOverWaterboxes"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixSawSoftlock"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DekuNutUpgradeFix"), 1),
- PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixGrokenGiantsKnife"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixMenuLR"), 1),
+ PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixBrokenGiantsKnife"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixMenuLR"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixDungeonMinimapIcon"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("TwoHandedIdle"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("NaviTextFix"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("GerudoWarriorClothingFix"), 1),
@@ -251,7 +251,7 @@ const std::vector randomizerPresetEntries = {
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("EnemySpawnsOverWaterboxes"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixSawSoftlock"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("DekuNutUpgradeFix"), 1),
- PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixGrokenGiantsKnife"), 1),
+ PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixBrokenGiantsKnife"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixMenuLR"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FixDungeonMinimapIcon"), 1),
PRESET_ENTRY_S32(CVAR_ENHANCEMENT("TwoHandedIdle"), 1),
diff --git a/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h
index eb213640e..c6635b5a7 100644
--- a/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h
+++ b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h
@@ -1,6 +1,6 @@
#include
-class TimeDisplayWindow : public Ship::GuiWindow {
+class TimeDisplayWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/audio/AudioEditor.h b/soh/soh/Enhancements/audio/AudioEditor.h
index a5b0b385a..ca3636d9a 100644
--- a/soh/soh/Enhancements/audio/AudioEditor.h
+++ b/soh/soh/Enhancements/audio/AudioEditor.h
@@ -7,7 +7,7 @@
#include
#include "AudioCollection.h"
-class AudioEditor : public Ship::GuiWindow {
+class AudioEditor final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/controls/InputViewer.h b/soh/soh/Enhancements/controls/InputViewer.h
index c370a4225..67303b7eb 100644
--- a/soh/soh/Enhancements/controls/InputViewer.h
+++ b/soh/soh/Enhancements/controls/InputViewer.h
@@ -17,7 +17,7 @@ typedef enum {
STICK_MODE_ALWAYS_HIDDEN,
} StickMode;
-class InputViewer : public Ship::GuiWindow {
+class InputViewer final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
@@ -33,7 +33,7 @@ class InputViewer : public Ship::GuiWindow {
void RenderButton(std::string btn, std::string btnOutline, int state, ImVec2 size, int outlineMode);
};
-class InputViewerSettingsWindow : public Ship::GuiWindow {
+class InputViewerSettingsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/controls/SohInputEditorWindow.h b/soh/soh/Enhancements/controls/SohInputEditorWindow.h
index 76d33975e..a6815f060 100644
--- a/soh/soh/Enhancements/controls/SohInputEditorWindow.h
+++ b/soh/soh/Enhancements/controls/SohInputEditorWindow.h
@@ -17,7 +17,7 @@ typedef struct {
N64ButtonMask defaultBtn;
} CustomButtonMap;
-class SohInputEditorWindow : public Ship::GuiWindow {
+class SohInputEditorWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
~SohInputEditorWindow();
diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
index e0f530bc2..8074fa707 100644
--- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
+++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
@@ -2376,10 +2376,12 @@ void CosmeticsEditorWindow::DrawElement() {
.Step(0.01f)
.Size(ImVec2(300.0f, 0.0f))
.Color(THEME_COLOR));
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::CVarCheckbox("Randomize All on New Scene", CVAR_COSMETIC("RandomizeAllOnNewScene"),
UIWidgets::CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Enables randomizing all unlocked cosmetics when you enter a new scene."));
+ ImGui::EndDisabled();
UIWidgets::CVarCheckbox(
"Advanced Mode", CVAR_COSMETIC("AdvancedMode"),
UIWidgets::CheckboxOptions()
@@ -2408,13 +2410,15 @@ void CosmeticsEditorWindow::DrawElement() {
}
}
}
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
if (UIWidgets::Button("Randomize All", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) {
CosmeticsEditor_RandomizeAll();
}
+ ImGui::EndDisabled();
+
ImGui::SameLine();
if (UIWidgets::Button("Reset All", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) {
- CVarClearBlock("gCosmetics");
- ApplyOrResetCustomGfxPatches();
+ CosmeticsEditor_ResetAll();
}
if (UIWidgets::Button("Lock All", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) {
for (auto& [id, cosmeticOption] : cosmeticOptions) {
@@ -2432,6 +2436,7 @@ void CosmeticsEditorWindow::DrawElement() {
}
}
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
if (UIWidgets::Button("Rainbow All", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) {
for (auto& [id, cosmeticOption] : cosmeticOptions) {
if (!CVarGetInteger(cosmeticOption.lockedCvar, 0) &&
@@ -2441,6 +2446,8 @@ void CosmeticsEditorWindow::DrawElement() {
}
}
}
+ ImGui::EndDisabled();
+
ImGui::SameLine();
if (UIWidgets::Button("Un-Rainbow All", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) {
for (auto& [id, cosmeticOption] : cosmeticOptions) {
@@ -2470,6 +2477,7 @@ void CosmeticsEditorWindow::DrawElement() {
if (ImGui::BeginTabItem("Keys")) {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::Separator(true, true, 2.0f, 2.0f);
if (UIWidgets::Button("Give all keys dungeon-specific colors",
@@ -2483,6 +2491,7 @@ void CosmeticsEditorWindow::DrawElement() {
DrawCosmeticGroup(COSMETICS_GROUP_SMALL_KEYS);
DrawCosmeticGroup(COSMETICS_GROUP_BOSS_KEYS);
+ ImGui::EndDisabled();
ImGui::EndTabItem();
}
diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h
index 6a2b1efd1..e10583081 100644
--- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h
+++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h
@@ -60,7 +60,7 @@ void CosmeticsEditor_ResetAll();
void CosmeticsEditor_ResetGroup(CosmeticGroup group);
void ApplyOrResetCustomGfxPatches(bool manualChange = true);
-class CosmeticsEditorWindow : public Ship::GuiWindow {
+class CosmeticsEditorWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp
index 278b8db0c..1a6f9ce62 100644
--- a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp
+++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp
@@ -469,6 +469,27 @@ size_t CustomMessage::FindNEWLINE(std::string& str, size_t lastNewline) const {
return newLine;
}
+bool CustomMessage::AddBreakString(std::string& str, size_t pos, std::string breakString) const {
+ if (str[pos] == ' ' || str[pos] == '&') {
+ str.replace(pos, 1, breakString);
+ return false;
+ } else {
+ if (pos <= str.size() - 1) {
+ // If the next char is a new textbox, it has priority, ignore whatever we are replacing it with
+ if (str[pos + 1] == '^') {
+ return false;
+ // otherwise, if it is a line break or space, replace it
+ } else if (str[pos + 1] == ' ' || str[pos + 1] == '&') {
+ str.replace(pos + 1, 1, breakString);
+ return false;
+ }
+ }
+ // otherwise insert after it
+ str.insert(pos + 1, breakString);
+ return true;
+ }
+}
+
void CustomMessage::AutoFormatString(std::string& str) const {
ReplaceAltarIcons(str);
ReplaceColors(str);
@@ -481,7 +502,6 @@ void CustomMessage::AutoFormatString(std::string& str) const {
while (lastNewline + lineLength < str.length() || yesNo != std::string::npos) {
const size_t carrot = str.find('^', lastNewline);
const size_t ampersand = str.find('&', lastNewline);
- const size_t lastSpace = str.rfind(' ', lastNewline + lineLength);
size_t waitForInput = str.find(WAIT_FOR_INPUT()[0], lastNewline);
size_t newLine = FindNEWLINE(str, lastNewline);
if (carrot < waitForInput) {
@@ -513,13 +533,25 @@ void CustomMessage::AutoFormatString(std::string& str) const {
lastNewline = waitForInput + 1;
lineCount = 0;
// some lines need to be split but don't have spaces, look for periods instead
- } else if (lastSpace == std::string::npos) {
- const size_t lastPeriod = str.rfind('.', lastNewline + lineLength);
- str.replace(lastPeriod, 1, ".&");
- lastNewline = lastPeriod + 2;
} else {
- str.replace(lastSpace, 1, "&");
- lastNewline = lastSpace + 1;
+ const size_t lastBreak =
+ str.find_last_of(static_cast(".,!?- "), lastNewline + lineLength);
+ // if none exist or we go backwards, we look forward for a something and allow the overflow
+ if (lastBreak == std::string::npos || lastBreak < lastNewline) {
+ const size_t nextBreak = str.find_first_of(static_cast(".,!?- &^"), lastNewline);
+ if (str[nextBreak] == '^') {
+ lastNewline = nextBreak + 1;
+ lineCount = 0; // increments to 1 at the end
+ } else if (str[nextBreak] == '&') {
+ lastNewline = nextBreak + 1;
+ } else {
+ bool isAdded = AddBreakString(str, nextBreak, "&");
+ lastNewline = nextBreak + 1 + isAdded;
+ }
+ } else {
+ bool isAdded = AddBreakString(str, lastBreak, "&");
+ lastNewline = lastBreak + 1 + isAdded;
+ }
}
lineCount += 1;
} else {
@@ -536,14 +568,23 @@ void CustomMessage::AutoFormatString(std::string& str) const {
// 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) {
- const size_t lastPeriod = str.rfind('.', lastNewline + lineLength);
- str.replace(lastPeriod, 1, ".^" + colorText);
- lastNewline = lastPeriod + 2;
+ // some lines need to be split but don't have spaces, look for punctuation instead
} else {
- str.replace(lastSpace, 1, "^" + colorText);
- lastNewline = lastSpace + 1;
+ const size_t lastBreak =
+ str.find_last_of(static_cast(".,!?- &"), lastNewline + lineLength);
+ // if none exist or we go backwards, we look forward for a something and allow the overflow
+ if (lastBreak == std::string::npos || lastBreak < lastNewline) {
+ const size_t nextBreak = str.find_first_of(static_cast(".,!?- &^"), lastNewline);
+ if (str[nextBreak] == '^') {
+ lastNewline = nextBreak + 1;
+ } else {
+ bool isAdded = AddBreakString(str, nextBreak, "^" + colorText);
+ lastNewline = nextBreak + 1 + isAdded;
+ }
+ } else {
+ bool isAdded = AddBreakString(str, lastBreak, "^" + colorText);
+ lastNewline = lastBreak + 1 + isAdded;
+ }
}
lineCount = 1;
}
diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.h b/soh/soh/Enhancements/custom-message/CustomMessageManager.h
index f312d9f85..3fbd7dfb5 100644
--- a/soh/soh/Enhancements/custom-message/CustomMessageManager.h
+++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.h
@@ -190,6 +190,17 @@ class CustomMessage {
*/
size_t FindNEWLINE(std::string& str, size_t lastNewline) const;
+ /**
+ * @brief Inserts a string into another string, following the rules
+ * of auto-format inserting new lines: spaces and & are replaced while
+ * other chars are appended to.
+ *
+ * @param str the string we are inserting into
+ * @param pos the position in the string to insert
+ * @param breakString the string we are inserting
+ */
+ bool AddBreakString(std::string& str, size_t pos, std::string breakString) const;
+
/**
* @brief formats the string specifically to fit in OoT's
* textboxes, and use it's formatting.
diff --git a/soh/soh/Enhancements/debugger/MessageViewer.cpp b/soh/soh/Enhancements/debugger/MessageViewer.cpp
index 83aac4d6c..c018b0017 100644
--- a/soh/soh/Enhancements/debugger/MessageViewer.cpp
+++ b/soh/soh/Enhancements/debugger/MessageViewer.cpp
@@ -27,6 +27,7 @@ void MessageViewer::InitElement() {
}
void MessageViewer::DrawElement() {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
ImGui::Text("Table ID");
ImGui::SameLine();
PushStyleInput(THEME_COLOR);
@@ -78,6 +79,7 @@ void MessageViewer::DrawElement() {
mDisplayCustomMessageClicked = true;
}
PopStyleButton();
+ ImGui::EndDisabled();
}
void MessageViewer::UpdateElement() {
diff --git a/soh/soh/Enhancements/debugger/MessageViewer.h b/soh/soh/Enhancements/debugger/MessageViewer.h
index 83e290114..9ce8eab05 100644
--- a/soh/soh/Enhancements/debugger/MessageViewer.h
+++ b/soh/soh/Enhancements/debugger/MessageViewer.h
@@ -25,7 +25,7 @@ void MessageDebug_DisplayCustomMessage(const char* customMessage);
#ifdef __cplusplus
}
-class MessageViewer : public Ship::GuiWindow {
+class MessageViewer final : public Ship::GuiWindow {
public:
static inline const char* TABLE_ID = "MessageViewer";
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/debugger/SohConsoleWindow.cpp b/soh/soh/Enhancements/debugger/SohConsoleWindow.cpp
index d5090e7e5..19be376ed 100644
--- a/soh/soh/Enhancements/debugger/SohConsoleWindow.cpp
+++ b/soh/soh/Enhancements/debugger/SohConsoleWindow.cpp
@@ -12,6 +12,7 @@ void SohConsoleWindow::UpdateElement() {
}
void SohConsoleWindow::DrawElement() {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::PushStyleInput(THEME_COLOR);
// Small font (13) to match hardcoded width values in the LUS window.. set large font after below TODO addressed
ImGui::PushFont(OTRGlobals::Instance->fontMonoSmall);
@@ -27,4 +28,5 @@ void SohConsoleWindow::DrawElement() {
ImGui::PopFont();
UIWidgets::PopStyleInput();
+ ImGui::EndDisabled();
}
diff --git a/soh/soh/Enhancements/debugger/SohGfxDebuggerWindow.cpp b/soh/soh/Enhancements/debugger/SohGfxDebuggerWindow.cpp
index 06d81577d..def23cacc 100644
--- a/soh/soh/Enhancements/debugger/SohGfxDebuggerWindow.cpp
+++ b/soh/soh/Enhancements/debugger/SohGfxDebuggerWindow.cpp
@@ -10,7 +10,9 @@ void SohGfxDebuggerWindow::UpdateElement() {
}
void SohGfxDebuggerWindow::DrawElement() {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
GfxDebuggerWindow::DrawElement();
ImGui::PopFont();
+ ImGui::EndDisabled();
}
diff --git a/soh/soh/Enhancements/debugger/SohStatsWindow.h b/soh/soh/Enhancements/debugger/SohStatsWindow.h
index 227ca5500..09b495cdb 100644
--- a/soh/soh/Enhancements/debugger/SohStatsWindow.h
+++ b/soh/soh/Enhancements/debugger/SohStatsWindow.h
@@ -3,7 +3,7 @@
#include
-class SohStatsWindow : public Ship::GuiWindow {
+class SohStatsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
~SohStatsWindow(){};
diff --git a/soh/soh/Enhancements/debugger/actorViewer.cpp b/soh/soh/Enhancements/debugger/actorViewer.cpp
index 8ae940ffb..515da6491 100644
--- a/soh/soh/Enhancements/debugger/actorViewer.cpp
+++ b/soh/soh/Enhancements/debugger/actorViewer.cpp
@@ -849,6 +849,7 @@ void ActorViewer_AddTagForAllActors() {
}
void ActorViewerWindow::DrawElement() {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
static Actor* display;
static Actor empty{};
static Actor* fetch = NULL;
@@ -1186,6 +1187,7 @@ void ActorViewerWindow::DrawElement() {
actors.clear();
}
}
+ ImGui::EndDisabled();
}
void ActorViewerWindow::InitElement() {
diff --git a/soh/soh/Enhancements/debugger/actorViewer.h b/soh/soh/Enhancements/debugger/actorViewer.h
index bab7d1646..5d5bcdf88 100644
--- a/soh/soh/Enhancements/debugger/actorViewer.h
+++ b/soh/soh/Enhancements/debugger/actorViewer.h
@@ -2,7 +2,7 @@
#include
-class ActorViewerWindow : public Ship::GuiWindow {
+class ActorViewerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/debugger/colViewer.cpp b/soh/soh/Enhancements/debugger/colViewer.cpp
index e3abba484..88e943f87 100644
--- a/soh/soh/Enhancements/debugger/colViewer.cpp
+++ b/soh/soh/Enhancements/debugger/colViewer.cpp
@@ -20,7 +20,7 @@ extern "C" {
extern PlayState* gPlayState;
}
-typedef enum ColRenderSetting { ColRenderDisabled, ColRenderSolid, ColRenderTransparent } ColRenderSetting;
+enum ColRenderSetting { ColRenderDisabled, ColRenderSolid, ColRenderTransparent };
static std::unordered_map ColRenderSettingNames = {
{ ColRenderDisabled, "Disabled" },
@@ -58,6 +58,7 @@ using namespace UIWidgets;
// Draws the ImGui window for the collision viewer
void ColViewerWindow::DrawElement() {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
CheckboxOptions checkOpt = CheckboxOptions().Color(THEME_COLOR);
ComboboxOptions comboOpt = ComboboxOptions().Color(THEME_COLOR);
CVarCheckbox("Enabled", CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), checkOpt);
@@ -139,6 +140,7 @@ void ColViewerWindow::DrawElement() {
UIWidgets::Tooltip(colorHelpText.c_str());
}
PopStyleHeader();
+ ImGui::EndDisabled();
}
// Calculates the normal for a triangle at the 3 specified points
diff --git a/soh/soh/Enhancements/debugger/colViewer.h b/soh/soh/Enhancements/debugger/colViewer.h
index eeaca7e43..04f457aa0 100644
--- a/soh/soh/Enhancements/debugger/colViewer.h
+++ b/soh/soh/Enhancements/debugger/colViewer.h
@@ -5,7 +5,7 @@
typedef enum { COLVIEW_DISABLED, COLVIEW_SOLID, COLVIEW_TRANSPARENT } ColViewerRenderSetting;
#ifdef __cplusplus
-class ColViewerWindow : public Ship::GuiWindow {
+class ColViewerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
index a97a41d16..5aa5833ef 100644
--- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
+++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
@@ -106,7 +106,7 @@ char z2ASCII(int code) {
return char(ret);
}
-typedef enum MagicLevel { MAGIC_LEVEL_NONE, MAGIC_LEVEL_SINGLE, MAGIC_LEVEL_DOUBLE };
+enum MagicLevel { MAGIC_LEVEL_NONE, MAGIC_LEVEL_SINGLE, MAGIC_LEVEL_DOUBLE };
std::unordered_map magicLevelMap = {
{ MAGIC_LEVEL_NONE, "None" },
@@ -114,7 +114,7 @@ std::unordered_map magicLevelMap = {
{ MAGIC_LEVEL_DOUBLE, "Double" },
};
-typedef enum AudioOutput {
+enum AudioOutput {
AUDIO_STEREO,
AUDIO_MONO,
AUDIO_HEADSET,
@@ -128,7 +128,7 @@ std::unordered_map audioMap = {
{ AUDIO_SURROUND, "Surround" },
};
-typedef enum ZTarget {
+enum ZTarget {
Z_TARGET_SWITCH,
Z_TARGET_HOLD,
};
@@ -1665,6 +1665,7 @@ void ResetBaseOptions() {
void SaveEditorWindow::DrawElement() {
PushStyleTabs(THEME_COLOR);
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
if (ImGui::BeginTabBar("SaveContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
ResetBaseOptions();
@@ -1706,6 +1707,7 @@ void SaveEditorWindow::DrawElement() {
ImGui::EndTabBar();
}
+ ImGui::EndDisabled();
ImGui::PopFont();
PopStyleTabs();
}
diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.h b/soh/soh/Enhancements/debugger/debugSaveEditor.h
index 4ebad1691..4190b8199 100644
--- a/soh/soh/Enhancements/debugger/debugSaveEditor.h
+++ b/soh/soh/Enhancements/debugger/debugSaveEditor.h
@@ -1770,7 +1770,7 @@ const std::vector state3 = {
"Travelling to Hook Target",
};
-class SaveEditorWindow : public Ship::GuiWindow {
+class SaveEditorWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/debugger/dlViewer.cpp b/soh/soh/Enhancements/debugger/dlViewer.cpp
index 7cedcdf26..a02aa7d95 100644
--- a/soh/soh/Enhancements/debugger/dlViewer.cpp
+++ b/soh/soh/Enhancements/debugger/dlViewer.cpp
@@ -89,6 +89,7 @@ void PerformDisplayListSearch() {
}
void DLViewerWindow::DrawElement() {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
// Debounce the search field as listing otr files is expensive
UIWidgets::PushStyleInput(THEME_COLOR);
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
@@ -122,6 +123,7 @@ void DLViewerWindow::DrawElement() {
if (activeDisplayList == "") {
ImGui::PopFont();
+ ImGui::EndDisabled();
return;
}
@@ -131,6 +133,8 @@ 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();
+ ImGui::EndDisabled();
return;
}
@@ -325,13 +329,10 @@ void DLViewerWindow::DrawElement() {
}
ImGui::EndGroup();
}
- } catch (const std::exception& e) {
- ImGui::Text("Error displaying DL instructions.");
- ImGui::PopFont();
- return;
- }
+ } catch (const std::exception& e) { ImGui::Text("Error displaying DL instructions."); }
ImGui::PopFont();
+ ImGui::EndDisabled();
}
void DLViewerWindow::InitElement() {
diff --git a/soh/soh/Enhancements/debugger/dlViewer.h b/soh/soh/Enhancements/debugger/dlViewer.h
index 3655c8964..a75fead97 100644
--- a/soh/soh/Enhancements/debugger/dlViewer.h
+++ b/soh/soh/Enhancements/debugger/dlViewer.h
@@ -2,7 +2,7 @@
#include
-class DLViewerWindow : public Ship::GuiWindow {
+class DLViewerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/debugger/hookDebugger.cpp b/soh/soh/Enhancements/debugger/hookDebugger.cpp
index 113862282..146db2ddc 100644
--- a/soh/soh/Enhancements/debugger/hookDebugger.cpp
+++ b/soh/soh/Enhancements/debugger/hookDebugger.cpp
@@ -77,6 +77,7 @@ void DrawHookRegisteringInfos(const char* hookName) {
}
void HookDebuggerWindow::DrawElement() {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
#ifndef __cpp_lib_source_location
ImGui::TextColored(yellow, "Some features of the Hook Debugger are unavailable because SoH was compiled "
"without \"\" support "
@@ -93,6 +94,7 @@ void HookDebuggerWindow::DrawElement() {
}
ImGui::PopFont();
+ ImGui::EndDisabled();
}
void HookDebuggerWindow::InitElement() {
diff --git a/soh/soh/Enhancements/debugger/hookDebugger.h b/soh/soh/Enhancements/debugger/hookDebugger.h
index 4d5c776db..1a586a09c 100644
--- a/soh/soh/Enhancements/debugger/hookDebugger.h
+++ b/soh/soh/Enhancements/debugger/hookDebugger.h
@@ -1,6 +1,6 @@
#include
-class HookDebuggerWindow : public Ship::GuiWindow {
+class HookDebuggerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/debugger/valueViewer.cpp b/soh/soh/Enhancements/debugger/valueViewer.cpp
index 1ea117444..4544979cb 100644
--- a/soh/soh/Enhancements/debugger/valueViewer.cpp
+++ b/soh/soh/Enhancements/debugger/valueViewer.cpp
@@ -154,6 +154,7 @@ void RegisterValueViewerHooks() {
RegisterShipInitFunc initFunc(RegisterValueViewerHooks, { CVAR_NAME });
void ValueViewerWindow::DrawElement() {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::CVarCheckbox("Enable Printing", CVAR_NAME, UIWidgets::CheckboxOptions().Color(THEME_COLOR));
ImGui::BeginGroup();
@@ -275,6 +276,7 @@ void ValueViewerWindow::DrawElement() {
}
ImGui::EndGroup();
}
+ ImGui::EndDisabled();
}
void ValueViewerWindow::InitElement() {
diff --git a/soh/soh/Enhancements/debugger/valueViewer.h b/soh/soh/Enhancements/debugger/valueViewer.h
index c5e51a126..04d698d2c 100644
--- a/soh/soh/Enhancements/debugger/valueViewer.h
+++ b/soh/soh/Enhancements/debugger/valueViewer.h
@@ -33,7 +33,7 @@ typedef struct {
uint32_t y;
} ValueTableElement;
-class ValueViewerWindow : public Ship::GuiWindow {
+class ValueViewerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h
index 44d0e643a..e70c0d33e 100644
--- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h
+++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h
@@ -15,12 +15,14 @@ DEFINE_HOOK(OnItemReceive, (GetItemEntry itemEntry));
DEFINE_HOOK(OnSaleEnd, (GetItemEntry itemEntry));
DEFINE_HOOK(OnTransitionEnd, (int16_t sceneNum));
DEFINE_HOOK(OnSceneInit, (int16_t sceneNum));
+DEFINE_HOOK(AfterSceneCommands, (int16_t sceneNum));
DEFINE_HOOK(OnSceneFlagSet, (int16_t sceneNum, int16_t flagType, int16_t flag));
DEFINE_HOOK(OnSceneFlagUnset, (int16_t sceneNum, int16_t flagType, int16_t flag));
DEFINE_HOOK(OnFlagSet, (int16_t flagType, int16_t flag));
DEFINE_HOOK(OnFlagUnset, (int16_t flagType, int16_t flag));
DEFINE_HOOK(OnSceneSpawnActors, ());
DEFINE_HOOK(OnPlayerUpdate, ());
+DEFINE_HOOK(OnSetDoAction, (uint16_t action));
DEFINE_HOOK(OnOcarinaSongAction, ());
DEFINE_HOOK(OnCuccoOrChickenHatch, ());
DEFINE_HOOK(OnShopSlotChange, (uint8_t cursorIndex, int16_t price));
diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp
index 9231da843..08f2660dd 100644
--- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp
+++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp
@@ -45,12 +45,18 @@ void GameInteractor_ExecuteOnTransitionEndHooks(int16_t sceneNum) {
GameInteractor::Instance->ExecuteHooksForFilter(sceneNum);
}
-void GameInteractor_ExecuteOnSceneInitHooks(int16_t sceneNum) {
+void GameInteractor_ExecuteOnSceneInit(int16_t sceneNum) {
GameInteractor::Instance->ExecuteHooks(sceneNum);
GameInteractor::Instance->ExecuteHooksForID(sceneNum, sceneNum);
GameInteractor::Instance->ExecuteHooksForFilter(sceneNum);
}
+void GameInteractor_ExecuteAfterSceneCommands(int16_t sceneNum) {
+ GameInteractor::Instance->ExecuteHooks(sceneNum);
+ GameInteractor::Instance->ExecuteHooksForID(sceneNum, sceneNum);
+ GameInteractor::Instance->ExecuteHooksForFilter(sceneNum);
+}
+
void GameInteractor_ExecuteOnSceneFlagSet(int16_t sceneNum, int16_t flagType, int16_t flag) {
GameInteractor::Instance->ExecuteHooks(sceneNum, flagType, flag);
GameInteractor::Instance->ExecuteHooksForFilter(sceneNum, flagType, flag);
@@ -79,6 +85,10 @@ void GameInteractor_ExecuteOnPlayerUpdate() {
GameInteractor::Instance->ExecuteHooks();
}
+void GameInteractor_ExecuteOnSetDoAction(uint16_t action) {
+ GameInteractor::Instance->ExecuteHooks(action);
+}
+
void GameInteractor_ExecuteOnOcarinaSongAction() {
GameInteractor::Instance->ExecuteHooks();
}
diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h
index 33c8d2681..cd8e7962e 100644
--- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h
+++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h
@@ -18,12 +18,14 @@ void GameInteractor_ExecuteOnItemReceiveHooks(GetItemEntry itemEntry);
void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry);
void GameInteractor_ExecuteOnTransitionEndHooks(int16_t sceneNum);
void GameInteractor_ExecuteOnSceneInit(int16_t sceneNum);
+void GameInteractor_ExecuteAfterSceneCommands(int16_t sceneNum);
void GameInteractor_ExecuteOnSceneFlagSet(int16_t sceneNum, int16_t flagType, int16_t flag);
void GameInteractor_ExecuteOnSceneFlagUnset(int16_t sceneNum, int16_t flagType, int16_t flag);
void GameInteractor_ExecuteOnFlagSet(int16_t flagType, int16_t flag);
void GameInteractor_ExecuteOnFlagUnset(int16_t flagType, int16_t flag);
void GameInteractor_ExecuteOnSceneSpawnActors();
void GameInteractor_ExecuteOnPlayerUpdate();
+void GameInteractor_ExecuteOnSetDoAction(uint16_t action);
void GameInteractor_ExecuteOnOcarinaSongAction();
void GameInteractor_ExecuteOnCuccoOrChickenHatch();
void GameInteractor_ExecuteOnActorInit(void* actor);
diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
index 6c18a6edb..d57d5029a 100644
--- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
+++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
@@ -951,7 +951,7 @@ typedef enum {
// false
// ```
// #### `args`
- // - '*Fishing' (&this)
+ // - '*Fishing'
VB_GIVE_RANDO_GLITCH_FISHING_PRIZE,
// #### `result`
diff --git a/soh/soh/Enhancements/gameplaystatswindow.h b/soh/soh/Enhancements/gameplaystatswindow.h
index 16cf94e53..515820307 100644
--- a/soh/soh/Enhancements/gameplaystatswindow.h
+++ b/soh/soh/Enhancements/gameplaystatswindow.h
@@ -1,6 +1,6 @@
#include
-class GameplayStatsWindow : public Ship::GuiWindow {
+class GameplayStatsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp
index dcae4842c..899bc17bf 100644
--- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp
@@ -219,18 +219,18 @@ void ProcessExits(Region* region, GetAccessibleLocationsStruct& gals, Randomizer
}
ValidateSphereZero(gals);
}
+ // If the exit is accessible and hasn't been added yet, add it to the pool
+ // RANDOTODO do we want to add the region after the loop now, considering we
+ // are processing the new region immediately. Maybe a reverse for loop in ProcessRegion?
+ if (!exitRegion->addedToPool) {
+ exitRegion->addedToPool = true;
+ gals.regionPool.push_back(exit.GetConnectedRegionKey());
+ }
+
// process the region we just expanded to, to reduce looping
ProcessRegion(exitRegion, gals, ignore, stopOnBeatable, addToPlaythrough);
}
- // If the exit is accessible and hasn't been added yet, add it to the pool
- // RANDOTODO do we want to add the region after the loop now, considering we
- // are processing the new region immediately. Maybe a reverse for loop in ProcessRegion?
- if (!exitRegion->addedToPool && exit.ConditionsMet()) {
- exitRegion->addedToPool = true;
- gals.regionPool.push_back(exit.GetConnectedRegionKey());
- }
-
if (addToPlaythrough) {
// RANDOTODO Should this match the regular spheres?
// Add shuffled entrances to the entrance playthrough
@@ -327,13 +327,12 @@ bool IsBeatableWithout(RandomizerCheck excludedCheck, bool replaceItem,
auto ctx = Rando::Context::GetInstance();
RandomizerGet copy = ctx->GetItemLocation(excludedCheck)->GetPlacedRandomizerGet(); // Copy out item
ctx->GetItemLocation(excludedCheck)->SetPlacedItem(RG_NONE); // Write in empty item
- ctx->playthroughBeatable = false;
logic->Reset();
- CheckBeatable(ignore);
+ bool result = CheckBeatable(ignore);
if (replaceItem) {
ctx->GetItemLocation(excludedCheck)->SetPlacedItem(copy); // Immediately put item back
}
- return ctx->playthroughBeatable;
+ return result;
}
// Reset non-Logic-class logic, and optionally apply the initial inventory
@@ -581,6 +580,7 @@ void GeneratePlaythrough() {
// return if the seed is currently beatable or not
bool CheckBeatable(RandomizerGet ignore /* = RG_NONE*/) {
auto ctx = Rando::Context::GetInstance();
+ ctx->playthroughBeatable = false;
GetAccessibleLocationsStruct gals(0);
ResetLogic(ctx, gals, true);
do {
@@ -929,10 +929,8 @@ static void AssumedFill(const std::vector& items, const std::vect
// If ALR is off, then we check beatability after placing the item.
// If the game is beatable, then we can stop placing items with logic.
if (!ctx->GetOption(RSK_ALL_LOCATIONS_REACHABLE)) {
- ctx->playthroughBeatable = false;
logic->Reset();
- CheckBeatable();
- if (ctx->playthroughBeatable) {
+ if (CheckBeatable()) {
SPDLOG_DEBUG("Game beatable, now placing items randomly. " + std::to_string(itemsToPlace.size()) +
" major items remaining.\n\n");
FastFill(itemsToPlace, GetEmptyLocations(allowedLocations), true);
diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp
index 895a11e0e..a1cb845f3 100644
--- a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp
@@ -1458,257 +1458,258 @@ void StaticData::HintTable_Init() {
---------------------------*/
hintTextTable[RHT_JUNK01] = HintText(CustomMessage("They say you must read the names of \"Special Deal\" shop items carefully.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass man die \"Sonderangebote\" im Laden sorgfältig lesen sollte!",
/*french*/ "Selon moi, les \"Offres spéciales\" sont parfois trompeuses... Lisez les attentivement!"));
hintTextTable[RHT_JUNK02] = HintText(CustomMessage("They say that Zelda is a poor leader.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Zelda eine schlechte Anführerin ist.",
/*french*/ "Selon moi, Zelda ne ferait pas un bon monarque."));
hintTextTable[RHT_JUNK03] = HintText(CustomMessage("These hints can be quite useful. This is an exception.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Die Hinweise können sehr nützlich sein. Dies ist eine Ausnahme.",
/*french*/ "Ces indices sont très utiles, à l'exception de celui-ci."));
hintTextTable[RHT_JUNK04] = HintText(CustomMessage("They say that the Lizalfos in Dodongo's Cavern like to play in lava.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass die Echsalfos in Dodongo's Cavern gerne in der Lava spielen.",
/*french*/ "Selon moi, les Lézalfos de la Caverne Dodongo aiment patauger dans la lave."));
hintTextTable[RHT_JUNK05] = HintText(CustomMessage("They say that all the Zora drowned in Wind Waker.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass alle Zoras in Wind Waker ertrunken sind.",
/*french*/ "Selon moi, les Zoras se sont noyés dans Wind Waker."));
hintTextTable[RHT_JUNK06] = HintText(CustomMessage("If Gorons eat rocks, does that mean I'm in danger?",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Goronen essen doch Steine… heißt das, ich sollte mir Sorgen machen?",
/*french*/ "Ne dis pas au Gorons que je suis ici. Ils mangent des roches, tu sais!"));
hintTextTable[RHT_JUNK07] = HintText(CustomMessage("'Member when Ganon was a blue pig?^I 'member.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Erinnert ihr euch noch, als Ganon ein blauer Schwein war?^Ich erinnere mich!“",
/*french*/ "Dans mon temps, Ganon était un cochon bleu...^Pff! Les jeunes de nos jours, et leur Ganondorf!"));
hintTextTable[RHT_JUNK08] = HintText(CustomMessage("One who does not have Triforce can't go in.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Jemand, der nicht im Besitz der Triforce ist, kann nicht eintreten!",
/*french*/ "Ceux sans Triforce doivent rebrousser chemin."));
hintTextTable[RHT_JUNK09] = HintText(CustomMessage("Save your future, end the Happy Mask Salesman.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass der Maskenverkäufer aufgehalten werden muss, wenn man eine sichere Zukunft will.",
/*french*/ "Selon moi, tu t'éviteras des jours de malheur si tu vaincs le vendeur de masques..."));
hintTextTable[RHT_JUNK10] = HintText(CustomMessage("Glitches are a pathway to many abilities some consider to be... Unnatural.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Glitches sind ein Weg zu vielen Fähigkeiten, die manche als... unnatürlich betrachten.",
/*french*/ "Les glitchs sont un moyen d'acquérir de nombreuses facultés considérées par certains comme... contraire "));
hintTextTable[RHT_JUNK11] = HintText(CustomMessage("I'm stoned. Get it?",
- /*german*/ TODO_TRANSLATE,
- /*french*/ "Allez, roche, papier, ciseau...&Roche."));
+ /*german*/ "Ich bin stoned. Verstehst du?",
+ /*french*/ "J'ai été pétrifié.&Tu as compris?"));
hintTextTable[RHT_JUNK12] = HintText(CustomMessage("Hoot! Hoot! Would you like me to repeat that?",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Sei willkommen! Soll ich meine Worte wiederholen?",
/*french*/ "Hou hou! Veux-tu que je répète tout ça?"));
hintTextTable[RHT_JUNK13] = HintText(CustomMessage("Gorons are stupid. They eat rocks.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Goronen sind dumm. Sie essen Felsen.",
/*french*/ "Les Gorons sont des vraies têtes dures."));
hintTextTable[RHT_JUNK14] = HintText(CustomMessage("They say that Lon Lon Ranch prospered under Ingo.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Ingo der Lon-Lon-Farm zu neuem Glanz verholfen hat.",
/*french*/ "Selon moi, le Ranch Lon Lon était plus prospère sous Ingo."));
hintTextTable[RHT_JUNK15] = HintText(CustomMessage("They say without the Lens of Truth, the Treasure Chest Mini-Game is a 1 out of 32 chance.^Good luck!",
- /*german*/ TODO_TRANSLATE,
- /*french*/ "Gagner la Chasse-aux-Trésors est 1 chance sur 32.^Bonne chance!"));
+ /*german*/ "Man erzählt sich, dass du ohne das Auge der Wahrheit beim Schatzkisten-Minispiel nur eine 1-zu-32-Chance hast.^Na dann, viel Glück.",
+ /*french*/ "Selon moi, les chances de gagner la Chasse-aux-Trésors sans Monocle de Vérité est de 1 chance sur 32.^Bonne chance!"));
hintTextTable[RHT_JUNK16] = HintText(CustomMessage("Use bombs wisely.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Setze Bomben mit Bedacht ein.",
/*french*/ "Utilise les bombes avec précaution."));
hintTextTable[RHT_JUNK17] = HintText(CustomMessage("They say that players who select the \"ON\" option for \"MOTION CONTROL\" are the real \"Zelda players!\"",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Spieler, die die Option ‚BEWEGUNGSSTEUERUNG‘ auf ‚EIN‘ stellen, die wahren ‚Zelda-Spieler‘ sind.",
/*french*/ "Selon moi, ceux qui utilisent les contrôles gyroscopiques sont les VRAIS joueurs."));
hintTextTable[RHT_JUNK18] = HintText(CustomMessage("L2P @.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Lern zu spielen, @.",
/*french*/ "Arrête de lire les indices et joue comme un grand, @."));
hintTextTable[RHT_JUNK19] = HintText(CustomMessage("I bet you'd like to have more bombs.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ich wette, du würdest jetzt gerne mehr Bomben haben.",
/*french*/ "Je parie que tu veux plus de bombes."));
hintTextTable[RHT_JUNK20] = HintText(CustomMessage("When all else fails, use Fire.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Wenn alles andere scheitert, benutze Feuer.",
/*french*/ "Quand rien ne marche, utilise le feu."));
hintTextTable[RHT_JUNK21] = HintText(CustomMessage("Here's a hint, @. Don't be bad.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Hier ein Tipp, @: Sei nicht so schlecht.",
/*french*/ "Selon moi, la #Triforce# n'est pas dans le jeu... Duh!"));
hintTextTable[RHT_JUNK22] = HintText(CustomMessage("Game Over. Return of Ganon.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Game Over. Die Rückkehr von Ganon.",
/*french*/ "Partie terminée. RETour de Ganon."));
hintTextTable[RHT_JUNK23] = HintText(CustomMessage("May the way of the Hero lead to the Triforce.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Möge der Weg des Helden zur Triforce führen.",
/*french*/ "Que le chemin du héros te mène à la Triforce."));
hintTextTable[RHT_JUNK24] = HintText(CustomMessage("Can't find an item? Scan an Amiibo.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Du kannst einen Gegenstand nicht finden? Scanne einen Amiibo.",
/*french*/ "Tu cherches de quoi? Utilise un Amiibo!"));
hintTextTable[RHT_JUNK25] = HintText(CustomMessage("They say this game has just a few glitches.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass dieses Spiel nur ein paar Glitches hat.",
/*french*/ "Selon moi, ce jeu est complètement exempt de glitchs."));
hintTextTable[RHT_JUNK26] = HintText(CustomMessage("BRRING BRRING This is Ulrira. Wrong number?",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "BRRING BRRING, hier ist Ulrira. Falsche Nummer.",
/*french*/ "DRING DRING!! Pépé le Ramollo à l'appareil... Quoi? Faux numéro?"));
hintTextTable[RHT_JUNK27] = HintText(CustomMessage("Tingle Tingle Kooloo Limpah!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Tingle Tingle Kuuluu-Limpah!",
/*french*/ "Tingle! Tingle! Kooloolin... Pah!"));
hintTextTable[RHT_JUNK28] = HintText(CustomMessage("L is real 2401",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "L is real 2401",
/*french*/ "L is real 2401"));
hintTextTable[RHT_JUNK29] = HintText(CustomMessage("They say that Ganondorf will appear in the next Mario Tennis.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Ganondorf im nächsten Mario Tennis erscheinen wird.",
/*french*/ "Selon moi, Ganondorf sera la nouvelle recrue dans Mario Tennis."));
hintTextTable[RHT_JUNK30] = HintText(CustomMessage("They say Medigoron sells the earliest Breath of the Wild demo.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Medigoron die früheste Breath of the Wild-Demo verkauft.",
/*french*/ "Selon moi, Medigoron vend une démo de #Breath of the Wild#."));
hintTextTable[RHT_JUNK31] = HintText(CustomMessage("Can you move me? I don't get great service here.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Kannst du mich bewegen? Der Service hier ist nicht gerade gut.",
/*french*/ "Peux-tu me déplacer? J'ai pas une bonne réception ici."));
hintTextTable[RHT_JUNK32] = HintText(CustomMessage("They say if you use Strength on the truck, you can find Mew.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass man mit Stärke am Truck Mew finden kann.",
/*french*/ "Selon moi, #Mew# se trouve dessous le camion... Duh!"));
hintTextTable[RHT_JUNK33] = HintText(CustomMessage("I'm a helpful hint Gossip Stone!^See, I'm helping.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ich bin ein hilfreicher Stein!^Siehst du, ich helfe.",
/*french*/ "Salut! Je suis une pierre de bons conseils!^Tiens, tu vois? J'aide bien, hein?"));
hintTextTable[RHT_JUNK34] = HintText(CustomMessage("Dear @, please come to the castle. I've baked a cake for you.&Yours truly, Princess Zelda.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Lieber @, bitte komm ins Schloss. Ich habe einen Kuchen für dich gebacken. Mit freundlichen Grüßen,^Prinzessin Zelda.",
/*french*/ "Mon très cher @:&Viens vite au château, je t'ai préparé&un délicieux gâteau...^À bientôt, Princesse Zelda"));
hintTextTable[RHT_JUNK35] = HintText(CustomMessage("They say all toasters toast toast.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass alle Toaster Toast toasten.",
/*french*/ "Selon moi, les grille-pains grillent du pain."));
hintTextTable[RHT_JUNK36] = HintText(CustomMessage("You thought it would be a useful hint, but it was me, junk hint!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Du dachtest, es wäre ein nützlicher Hinweis, aber es war ich, der Müll-Hinweis.",
/*french*/ "Tu t'attendais à un bon indice... Mais c'était moi, un mauvais indice!"));
hintTextTable[RHT_JUNK37] = HintText(CustomMessage("They say that quest guidance can be found at a talking rock.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass man Quest-Hinweise bei einem sprechenden Stein finden kann.",
/*french*/ "Selon moi, des #indices# se trouvent auprès d'une pierre parlante... Duh!"));
hintTextTable[RHT_JUNK38] = HintText(CustomMessage("They say that the final item you're looking for can be found somewhere in Hyrule.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass das letzte Item, nach dem du suchst, irgendwo in Hyrule zu finden ist.",
/*french*/ "Selon moi, le #dernier objet# se trouve quelque part dans Hyrule... Duh!"));
hintTextTable[RHT_JUNK39] = HintText(CustomMessage("Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.",
/*french*/ "Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip."));
hintTextTable[RHT_JUNK40] = HintText(CustomMessage("They say that Barinade fears Deku Nuts.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Barinade Angst vor Deku-Nüssen hat.",
/*french*/ "Selon moi, Barinade a la frousse des noix Mojo."));
hintTextTable[RHT_JUNK41] = HintText(CustomMessage("They say that Flare Dancers do not fear Goron-crafted blades.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Flammenderwische keine Angst vor von Goronen geschmiedeten Klingen haben.",
/*french*/ "Selon moi, le danse-flamme n'a pas peur des armes de Goron."));
hintTextTable[RHT_JUNK42] = HintText(CustomMessage("They say that Morpha is easily trapped in a corner.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass man Morpha ganz leicht in die Ecke drängen kann.",
/*french*/ "Selon moi, Morpha est facilement coincé."));
hintTextTable[RHT_JUNK43] = HintText(CustomMessage("They say that Bongo Bongo really hates the cold.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Bongo Bongo die Kälte wirklich hasst.",
/*french*/ "Selon moi, Bongo Bongo a facilement froid aux doigts."));
hintTextTable[RHT_JUNK44] = HintText(CustomMessage("They say that your sword is most powerful when you put it away.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass dein Schwert am mächtigsten ist, wenn du es wegsteckst.",
/*french*/ "Selon moi, ton épée est à pleine puissance quand tu la rengaines."));
hintTextTable[RHT_JUNK45] = HintText(CustomMessage("They say that bombing the hole Volvagia last flew into can be rewarding.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass es sich lohnt, das Loch zu bombardieren, in das Volvagia zuletzt geflogen ist.",
/*french*/ "Selon moi, le trou où se creuse Volvagia est vulnérable aux bombes."));
hintTextTable[RHT_JUNK46] = HintText(CustomMessage("They say that invisible ghosts can be exposed with Deku Nuts.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass unsichtbare Geister mit Deku-Nüssen sichtbar gemacht werden können.",
/*french*/ "Selon moi, des fantômes invisibles apparaissent avec des noix Mojo."));
hintTextTable[RHT_JUNK47] = HintText(CustomMessage("They say that the real Phantom Ganon is bright and loud.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass der wahre Phantom-Ganon durch Helligkeit und Lärm auffällt.",
/*french*/ "Selon moi, le vrai spectre de Ganon est clair et bruyant."));
hintTextTable[RHT_JUNK48] = HintText(CustomMessage("They say that walking backwards is very fast.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass rückwärts laufen sehr schnell ist.",
/*french*/ "Selon moi, tu fais marche arrière très rapidement pour un héros."));
hintTextTable[RHT_JUNK49] = HintText(CustomMessage("They say Ingo is not very good at planning ahead.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Ingo nicht besonders gut darin ist, vorauszuplanen.",
/*french*/ "Selon moi, Ingo ne fait pas un très bon geôlier."));
hintTextTable[RHT_JUNK50] = HintText(CustomMessage("You found a spiritual Stone! By which I mean, I worship Nayru.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Du hast einen heiligen Stein gefunden! Also... eigentlich heißt das nur, dass ich Nayru verehre.",
/*french*/ "Vous avez trouvé une Pierre Ancestrale! En effet, je vénère la déesse Hylia."));
hintTextTable[RHT_JUNK51] = HintText(CustomMessage("Open your eyes.^Open your eyes.^Wake up, @.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Öffne deine Augen.^Öffne deine Augen.^Wach auf, @.",
/*french*/ "Réveille-toi...^Réveille-toi.^Ouvre les yeux, @."));
hintTextTable[RHT_JUNK52] = HintText(CustomMessage("They say that the Nocturne of Shadow can bring you very close to Ganon.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass das Nocturne des Schattens dich Ganon sehr nahe bringen kann.",
/*french*/ "Selon moi, le Nocturne de l'Ombre peut t'amener très près de Ganon."));
hintTextTable[RHT_JUNK53] = HintText(CustomMessage("They say that Twinrova always casts the same spell the first three times.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Twinrova die ersten drei Male immer denselben Zauber benutzt.",
/*french*/ "Selon moi, le Duo Maléfique lance toujours les mêmes trois premiers sorts."));
hintTextTable[RHT_JUNK54] = HintText(CustomMessage("They say that the nightly builds may be unstable.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass die \"nightly builds\" instabil sein könnten.",
/*french*/ "Selon moi, les \"nightly builds\" peuvent être instables."));
hintTextTable[RHT_JUNK55] = HintText(CustomMessage("You're playing a Randomizer. I'm randomized!^Here's a random number: #4#.&Enjoy your Randomizer!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Du spielst einen Randomizer. Ich bin randomisiert!^Hier ist eine zufällige Zahl: #4#.&Viel Spaß mit dem Randomizer!",
/*french*/ "Tu joues à un randomizer. Je suis aléatoire!^Voici un nombre aléatoire: #4#.&Bonne partie!"));
hintTextTable[RHT_JUNK56] = HintText(CustomMessage("They say Ganondorf's bolts can be reflected with glass or steel.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass man Ganondorfs Blitze mit Glas oder Stahl reflektieren kann.",
/*french*/ "Selon moi, les éclairs de Ganon se reflètent sur l'acier et le verre."));
hintTextTable[RHT_JUNK57] = HintText(CustomMessage("They say Ganon's tail is vulnerable to nuts, arrows, swords, explosives, hammers...^...sticks, seeds, "
"boomerangs...^...rods, shovels, iron balls, angry bees...",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Ganons Schwanz verwundbar ist durch Nüsse, Pfeile, Schwerter...^...Sprengstoffe, Hämmer, "
+ "Stöcke...^...Kerne, Bumerangs, Schaufeln, Eisenkugeln, wütende Bienen...",
/*french*/ "Selon moi, la queue de Ganon est vulnérable aux noix, flèches, épées, bombes, marteaux...^...bâtons, "
"graines, boomerangs...^...baguettes, pelles, boulets de fer, abeilles enragées..."));
hintTextTable[RHT_JUNK58] = HintText(CustomMessage("They say that you're wasting time reading this hint, but I disagree. Talk to me again!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass du deine Zeit mit dem Lesen dieses Hinweises verschwendest, aber ich bin anderer Meinung. Sprich noch einmal mit mir.",
/*french*/ "Selon moi... tu sais quoi? Parle-moi encore, et je te le dirai!"));
hintTextTable[RHT_JUNK59] = HintText(CustomMessage("They say Ganondorf knows where to find the instrument of his doom.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Ganondorf weiß, wo er das Instrument seines Untergangs finden kann.",
/*french*/ "Selon moi, Ganondorf sait où il a caché son point faible."));
hintTextTable[RHT_JUNK60] = HintText(CustomMessage("I heard @ is pretty good at Zelda.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ich habe gehört, dass @ ziemlich gut in Zelda ist.",
/*french*/ "Apparemment, @ est super bon à Zelda."));
hintTextTable[RHT_JUNK61] = HintText(CustomMessage("Hi @, we've been trying to reach you about your car's extended warranty. ",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Hallo @, wir haben versucht, dich wegen der erweiterten Garantie für dein Auto zu erreichen.",
/*french*/ "Bonjour, @. Vous avez une voiture? Vous savez, nous offrons des assurances abordables..."));
hintTextTable[RHT_JUNK62] = HintText(CustomMessage("They say that it's actually possible to beat the running man.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass es tatsächlich möglich ist, den Laufenden Mann zu besiegen.",
/*french*/ "Selon moi, il est possible de battre le coureur.&Donc, tu prends ton arc, et..."));
hintTextTable[RHT_JUNK63] = HintText(CustomMessage("They say this hint makes more sense in other languages.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass diese Hinweise besser übersetzt werden könnten… na ja, wer hätte das gedacht.",
/*french*/ "Selon moi, ces indices auraient pu être mieux traduits... Duh!"));
// ^ Junk hints above are from 3drando
@@ -1717,39 +1718,36 @@ void StaticData::HintTable_Init() {
// Please keep hints to stuff related to ship directly, or to Nintendo/Zelda related stuff.
// And nothing that's super obscure that no one's going to understand.
-#define HINT_TEXT_NEEDS_TRANSLATION_FR \
- "Erreur 0x69a504:&Traduction manquante^C'est de la faute à Purple Hato!&J'vous jure!"
-
hintTextTable[RHT_JUNK64] = HintText(CustomMessage("They say Greg is special.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Greg etwas Besonderes ist.",
/*french*/ "Selon moi, Greg est spécial."));
hintTextTable[RHT_JUNK65] = HintText(CustomMessage("They say the longer the Goron's neck, the wiser they are.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass ein Gorone umso weiser wird, je länger sein Hals ist.",
/*french*/ "Selon moi, plus le cou des Gorons est long, plus ils sont sage." ));
hintTextTable[RHT_JUNK66] = HintText(CustomMessage("They say this ship is what all true gamers strive for.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass dieses \"ship\" das ist, wonach alle echten Gamer streben.",
/*french*/ "Selon moi, cette version du port est ce pour quoi luttent tous les vrais gamers."));
hintTextTable[RHT_JUNK67] = HintText(CustomMessage("They say that Glowsticks can be found in the Raveyard.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass Leuchtstäbe auf dem Partyfriedhof zu finden sind.",
/*french*/ "Selon moi, on peut trouver des Bâtons Lumineux sur le dancefloor du cimetière."));
hintTextTable[RHT_JUNK68] = HintText(CustomMessage("They say @'s uncle works for Nintendo.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass @'s Onkel bei Nintendo arbeitet.",
/*french*/ "Selon moi, l'oncle de @ travaille chez Nintendo."));
hintTextTable[RHT_JUNK69] = HintText(CustomMessage("They say pulling all gravestones in the graveyard leads to something magical.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass das Ziehen aller Grabsteine auf dem Friedhof zu etwas Magischem führt.",
/*french*/ "Selon moi, tirer toutes les tombes du Cimetière déclanche un truc magique."));
hintTextTable[RHT_JUNK70] = HintText(CustomMessage("They say holding L while pausing makes you win the game.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich, dass man das Spiel gewinnt, wenn man L gedrückt hält, während man pausiert.",
/*french*/ "Selon moi, maintenir L pendant que vous appuyez sur START vous permet de terminer le jeu."));
hintTextTable[RHT_JUNK71] = HintText(CustomMessage("They say @'s body is ready.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Man erzählt sich... nein weisst du was, ich hab keine lust mehr.",
/*french*/ "Selon moi, ce junk hint ne se traduirait pas bien en français."));
/*--------------------------
@@ -2000,13 +1998,13 @@ void StaticData::HintTable_Init() {
// /*spanish*/$8Los sabios aguardarán a que el héroe&obtenga #[[d]] |medallón|medallones|#.^
hintTextTable[RHT_BRIDGE_REWARDS_HINT] = HintText(CustomMessage("$CThe awakened ones will await for the Hero to collect #[[d]]# |#Spiritual Stone# or #Medallion#|"
- "#Spiritual Stones# and #Medallions#|.^",
- /*german*/ "$CDie Weisen werden darauf warten, daß der Held #[[d]]# |#Heiligen Stein# oder #Amulett#|"
- "#Heilige Steine# oder #Amulette#| sammelt.^",
- /*french*/ "$CLes êtres de sagesse attendront le héros muni de #[[d]]# |#Pierre Ancestrale# ou #Médaillon#"
- "|#Pierres Ancestrales# ou #Médaillons#|.^",
- {QM_YELLOW, QM_BLUE, QM_RED}));
- // /*spanish*/$CLos sabios aguardarán a que el héroe obtenga #[[d]]# |#piedra espiritual# o #medallón#|
+ "#Spiritual Stones# and #Medallions#|.^",
+ /*german*/ "$CDie Weisen werden darauf warten, daß der Held #[[d]]# |#Heiligen Stein# oder #Amulett#|"
+ "#Heilige Steine# oder #Amulette#| sammelt.^",
+ /*french*/ "$CLes êtres de sagesse attendront le héros muni de #[[d]]# |#Pierre Ancestrale# ou #Médaillon#"
+ "|#Pierres Ancestrales# ou #Médaillons#|.^",
+ {QM_YELLOW, QM_BLUE, QM_RED}));
+ // /*spanish*/$CLos sabios aguardarán a que el héroe obtenga #[[d]]# |#piedra espiritual# o #medallón#|
//#piedras espirtuales# y #medallones#|.^
hintTextTable[RHT_BRIDGE_DUNGEONS_HINT] = HintText(CustomMessage("$mThe awakened ones will await for the Hero to conquer #[[d]] Dungeon||s|#.^",
@@ -2022,6 +2020,8 @@ void StaticData::HintTable_Init() {
// /*spanish*/$sLos sabios aguardarán a que el héroe obtenga #[[d]] símbolo||s| de skulltula dorada#.^
hintTextTable[RHT_BRIDGE_GREG_HINT] = HintText(CustomMessage("$gThe awakened ones will await for the Hero to find #Greg#.^",
+ /*german*/ "$gDie Erwachten werden darauf warten, dass der Held #Greg# findet.^",
+ /*french*/ "$gLes êtres de sagesse attendront le héros muni de #Greg#.^",
{QM_GREEN}));
@@ -2214,19 +2214,20 @@ void StaticData::HintTable_Init() {
---------------------------*/
hintTextTable[RHT_GANONDORF_HINT_LA_ONLY] = HintText(CustomMessage("Ha ha ha... You'll never beat me by reflecting my lightning bolts and unleashing the arrows from #[[1]]#!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ha ha ha... Du wirst mich nie besiegen, indem du meine Blitze zurückschlägst und die Pfeile aus #[[1]]# entfesselts!",
/*french*/ "Ha ha ha... Pauvre fou! Tu ne pourras jamais me vaincre sans les flèches que j'ai cachées dans #[[1]]#!",
{QM_RED}));
// /*spanish*/Ja, ja, ja... Nunca me derrotarás reflejando mis esferas de energía y desplegando la flecha de luz de #[[1]]#!
hintTextTable[RHT_GANONDORF_HINT_MS_ONLY] = HintText(CustomMessage("Ha ha ha... You'll never defeat me, drop a castle on me and finish me off with the sacred blade from #[[2]]#!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ha ha ha... Du wirst mich nie besiegen, wirf ein Schloss auf mich und beende mich mit dem heiligen Schwert von #[[2]]#!",
/*french*/ "Ha ha ha... Pauvre fou! Tu ne pourras jamais me vaincre sans l'Épée de Légende cachée dans #[[2]]#!",
{QM_RED}));
hintTextTable[RHT_GANONDORF_HINT_LA_AND_MS] = HintText(CustomMessage("Ha ha ha... You'll never beat me by reflecting my lightning bolts and unleashing the arrows from #[[1]]#!"
"^And even if you do, you'll never find the legendary blade hidden in #[[2]]#!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ha ha ha... Du wirst mich nie besiegen, indem du meine Blitze zurückschlägst und die Pfeile aus #[[1]]# entfesselts!"
+ "^Und selbst wenn du es tust, wirst du nie das legendäre Schwert finden, das in #[[2]]# versteckt ist!",
/*french*/ "Ha ha ha... Pauvre fou! Tu ne pourras jamais me vaincre sans les flèches que j'ai cachées dans #[[1]]#!"
"^Et même si tu les trouves, tu ne touveras jamais l'Épée de Légende cachée dans #[[2]]#!",
{QM_RED, QM_RED}));
@@ -2234,34 +2235,38 @@ void StaticData::HintTable_Init() {
// ^E incluso si lo haces, nunca encontrarás la espada legendaria escondida en #[[2]]#!
hintTextTable[RHT_SHEIK_HINT_LA_ONLY] = HintText(CustomMessage("I overheard Ganondorf say that he misplaced the #Light Arrows# in #[[1]]#.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ich habe Ganondorf sagen hören, dass er die #Lichtpfeile# in #[[1]]# verlegt hat.",
/*french*/ "J'ai entendu dire que Ganondorf aurait caché les #Flèches de Lumière# dans #[[1]]#.",
{QM_YELLOW, QM_RED}));
hintTextTable[RHT_DAMPE_DIARY] = HintText(CustomMessage("Whoever reads this, please enter #[[1]]#. I will let you have my #stretching, shrinking keepsake#.^I'm waiting for you.&--Dampé",
- /*german*/ "Wer immer dies liest, der möge folgenden Ort aufsuchen: #[[1]]#. Ihm gebe ich meinen #dehnenden, schrumpfenden Schatz#.^Ich warte!&Boris", //RANDOTODO color in whatever refers to the hookshot
+ /*german*/ "Wer immer dies liest, der möge folgenden Ort aufsuchen: #[[1]]#. Ihm gebe ich meinen #dehnenden, schrumpfenden Schatz#.^Ich warte!&Boris",
/*french*/ "Toi qui lit ce journal, rends-toi dans #[[1]]#. Et peut-être auras-tu droit à mon précieux #trésor#.^Je t'attends...&--Igor",
{QM_RED, QM_RED}));
hintTextTable[RHT_GREG_HINT] = HintText(CustomMessage("By the way, if you're interested, I saw the shiniest #Green Rupee# somewhere in #[[1]]#.^It's said to have #mysterious powers#...^But then, it could just be another regular rupee.&Oh well.",
- /*german*/ TODO_TRANSLATE,
- /*french*/ "Au fait, si ça t'intéresse, j'ai aperçu le plus éclatant des #Rubis Verts# quelque part à #[[1]]#. On dit qu'il possède des pouvoirs mystérieux... Mais bon, ça pourrait juste être un autre rubis ordinaire.",//RANDOTODO color in mysterious powers
+ /*german*/ "Übrigens, falls es dich interessiert, ich habe irgendwo in #[[1]]# den glänzendsten #Grünen Rubinen# gesehen.^Es soll #mysteriöse Kräfte# haben...^Aber na ja, es könnte auch einfach nur ein normaler Rubin sein. Tja",
+ /*french*/ "Au fait, si ça t'intéresse, j'ai aperçu le plus éclatant des #Rubis Verts# quelque part à #[[1]]#.^On dit qu'il possède des #pouvoirs mystérieux#...^Mais bon, ça pourrait juste être un autre rubis ordinaire.",
{QM_GREEN, QM_RED, QM_RED}));
hintTextTable[RHT_SARIA_TALK_HINT] = HintText(CustomMessage("Did you feel the #surge of magic# recently? A mysterious bird told me it came from #[[1]]#.^You should check that place out, @!",
- /*german*/ TODO_TRANSLATE,
- /*french*/ "As-tu récemment ressenti une vague de #puissance magique#? Un mystérieux hibou m'a dit qu'elle provenait du #[[1]]#. Tu devrais aller y jeter un coup d'oeil, @!",
- {QM_GREEN, QM_RED}));
+ /*german*/ "Hast du kürzlich den #Magieschub# gespürt? Ein geheimnisvoller Vogel hat mir erzählt, dass er aus #[[1]]# kam.^Du solltest dir diesen Ort mal ansehen, @!",
+ /*french*/ "As-tu récemment ressenti une vague de #puissance magique#? Un mystérieux hibou m'a dit qu'elle provenait du #[[1]]#.^Tu devrais aller y jeter un coup d'oeil, @!",
+ {QM_GREEN, QM_RED}));
hintTextTable[RHT_SARIA_SONG_HINT] = HintText(CustomMessage("Did you feel the #surge of magic# recently? A mysterious bird told me it came from #[[1]]#.^You should check that place out, @!\x0B",
- /*german*/ TODO_TRANSLATE,
- /*french*/ "As-tu récemment ressenti une vague de #puissance magique#? Un mystérieux hibou m'a dit qu'elle provenait du #[[1]]#. Tu devrais aller y jeter un coup d'oeil, @!\x0B",
- {QM_GREEN, QM_RED}, {}, TEXTBOX_TYPE_BLUE));
+ /*german*/ "Hast du kürzlich den #Magieschub# gespürt? Ein geheimnisvoller Vogel hat mir erzählt, dass er aus #[[1]]# kam.^Du solltest dir diesen Ort mal ansehen, @!\x0B",
+ /*french*/ "As-tu récemment ressenti une vague de #puissance magique#? Un mystérieux hibou m'a dit qu'elle provenait du #[[1]]#.^Tu devrais aller y jeter un coup d'oeil, @!\x0B",
+ {QM_GREEN, QM_RED}, {}, TEXTBOX_TYPE_BLUE));
hintTextTable[RHT_LOACH_HINT] = HintText(CustomMessage("What?^You wanna know about the&%rHyrule Loach%w?^It's a big fish, but it's so rare that I'll give my %g[[1]]%w to anyone who catches it. Seriously!",
- {QM_RED}));
+ /*german*/ "Was?^Du willst was über den&%rHyrule-Schleicher%w wissen?^Das ist ein riesiger Fisch, aber&so selten, dass ich jedem mein&%g[[1]]%w gebe, der ihn fängt.&Im Ernst."
+ /*french*/ "Quoi?&Tu veux en savoir plus sur le&%rBrochet d'Hyrule%w?^C'est un gros poisson, mais il&est si rare que je donne&%g[[1]]%w&à celui qui l'attrape.^Ouais, j'suis sérieux!",
+ {QM_RED}));
hintTextTable[RHT_FISHING_POLE_HINT] = HintText(CustomMessage("^If I remember correctly, I lost it somewhere in #[[1]]#...&Let me know if you find it!",
+ /*german*/ "Wenn ich mich recht erinnere,&hab ich es irgendwo in #[[1]]#&verloren...&Sag mir Bescheid, wenn du es findest."
+ /*french*/ "Si je me souviens bien, il me&semble que je l'ai perdue&quelque part dans[[1]]#...^Fais-moi signe si jamais&tu la trouves!",
{QM_RED}));
/*--------------------------
@@ -2277,44 +2282,84 @@ void StaticData::HintTable_Init() {
| STATIC LOCATION HINTS |
---------------------------*/
+ /*--------------------------
+ | STATIC LOCATION HINTS |
+ ---------------------------*/
+
hintTextTable[RHT_HBA_HINT_SIGN] = HintText(CustomMessage("#Horseback Archery# Range Prizes:&1000: #[[1]]#&1500: #[[2]]#^@'s Record: #" + CustomMessage::POINTS(HS_HORSE_ARCHERY) + "#",
+ /*german*/ "#Bogenschießen zu Pferde#&Schießstandpreise:&1000: #[[1]]#&1500: #[[2]]#^@'s Record: #" + CustomMessage::POINTS(HS_HORSE_ARCHERY) + "#",
+ /*french*/ "Récompenses de l'#Archerie Montée#:&1000: #[[1]]#&1500: #[[2]]#^Record de @: #" + CustomMessage::POINTS(HS_HORSE_ARCHERY) + "#",
{QM_RED, QM_GREEN, QM_GREEN, QM_GREEN}, {}, TEXTBOX_TYPE_WOODEN));
- hintTextTable[RHT_HBA_HINT_NOT_ON_HORSE] = HintText(CustomMessage("Hey, rookie!&Come back on your #horse# and take on then #Horseback Archery# challenge!^"
+ hintTextTable[RHT_HBA_HINT_NOT_ON_HORSE] = HintText(CustomMessage("Hey, rookie!&Come back on your #horse# and take on the #Horseback Archery# challenge!^"
"Impress me with a high score of 1000 to win a #[[1]]# or score 1500 for #[[2]]#!",
+ /*german*/ "Hey, Neuling!&Komm mit deinem #Pferd# zurück und stell dich der #Pferdebogenschießen#-Herausforderung!^"
+ "Beeindruck mich mit 1000 Punkten und gewinne #[[1]]#! Oder hol dir 1500 Punkte für #[[2]]#!",
+ /*french*/ "Hé, l'nouveau!&Reviens avec ton #cheval# et essaie notre #Terrain d'Archerie Montée#^"
+ "Impressionne-moi avec un score de 1000 pour gagner #[[1]]# ou atteins 1500 pour #[[2]]#!",
{QM_RED, QM_RED, QM_GREEN, QM_GREEN}));
hintTextTable[RHT_HBA_HINT_INITIAL] = HintText(CustomMessage("Hey, rookie!&Want to take on the #Horseback Archery# challenge?^"
"Impress me with a high score of 1000 to win a #[[1]]# or score 1500 for #[[2]]#!\x0B",
+ /*german*/ "Hey, Neuling!&Willst du dich der #Pferdebogenschießen#-Herausforderung stellen?^"
+ "Zeig, was du drauf hast - hol 1000 Punkte für #[[1]]#! Oder knack die 1500 und kassier #[[2]]#!\x0B",
+ /*french*/ "Hé, l'nouveau!&Tu veux essayer notre #Terrain d'Archerie Montée#^"
+ "Impressionne-moi avec un score de 1000 pour gagner #[[1]]# ou atteins 1500 pour #[[2]]#!\x0B",
{QM_RED, QM_GREEN, QM_GREEN}));
hintTextTable[RHT_HBA_HINT_HAVE_1000] = HintText(CustomMessage("Hey, newcomer!&Want to take on the #Horseback Archery# challenge?^"
"Prove yourself to be a horsemaster by scoring 1500 points to win #[[2]]#!\x0B",
+ /*german*/ "Hey, Neuling!&Willst du dich der #Pferdebogenschießen#-Herausforderung stellen?^"
+ "Beweise dein Können als Reitmeister - hol 1500 Punkte und gewinne #[[2]]#!\x0B",
+ /*french*/ "Hé, l'nouveau!&Tu veux essayer notre #Terrain d'Archerie Montée#^"
+ "Prouve que tu es un véritable cavalier en obtenant 1500 points pour gagner #[[2]]#!\x0B",
{QM_RED, QM_GREEN}));
hintTextTable[RHT_MALON_HINT_HOW_IS_EPONA] = HintText(CustomMessage("@! You should come back with Epona and try to beat my time on the #Obstacle Course#!^"
"If you beat my time, I'll give you my favourite #cow# Elsie and her toy #[[1]]#!",
+ /*german*/ "@! Du solltest mit Epona zurückkommen und versuchen, meine Zeit im #Hindernisparcours# zu schlagen!^"
+ "Wenn du meine Zeit schlägst, gebe ich dir meine #Lieblingskuh# Elsie und ihr Spielzeug #[[1]]#!",
+ /*french*/ "@! Tu devrais revenir avec Epona et essayer de battre mon temps sur le #Parcours d'Obstacles#!^"
+ "Si tu bats mon temps, je te donnerai ma vache préférée, Elsie, ainsi que son jouet #[[1]]#!",
{QM_RED, QM_BLUE, QM_GREEN}));
hintTextTable[RHT_MALON_HINT_OBSTICLE_COURSE] = HintText(CustomMessage("How about trying the #Obstacle Course?# If you beat my time I'll let you keep my favourite #cow# Elsie and her toy #[[1]]#!^"
"Challenge the #Obstacle Course?#&\x1BLet's go&No thanks#",
+ /*german*/ "Wie wärs mit dem #Hindernisparcours#? Wenn du meine Zeit schlägst, lasse ich dir meine #LieblingsKuh# Elsie und ihr Spielzeug #[[1]]#!^"
+ "Herausforderung: #Hindernisparcours?#&\x1BLos geht's!&nein, danke#",
+ /*french*/ "Que dirais-tu d'essayer le #Parcours d'Obstacles#? Si tu bats mon temps, je te donnerai ma vache préférée, Elsie, et son jouet #[[1]]#!^"
+ "Tenter le #Parcours d'Obstacles#?&\x1BAllons-y&Non merci#",
{QM_RED, QM_BLUE, QM_GREEN, QM_RED, QM_GREEN}));
hintTextTable[RHT_MALON_HINT_TURNING_EVIL] = HintText(CustomMessage("@? Is that you? ^If I ran the ranch, I'd build an #Obstacle Course#, and whoever gets the best time would win a #cow#!^"
"Elsie loves sharing her #[[1]]# with new people, It'll be fun!^...But Ingo won't let me...",
+ /*german*/ "@? Bist du das? ^Wenn ich die Ranch leiten würde, würde ich einen #Hindernisparcours# bauen, und wer die beste Zeit schafft, gewinnt eine #Kuh#!^"
+ "Elsie liebt es, ihr #[[1]]# mit neuen Leuten zu teilen. Es wird Spaß machen^...Aber Ingo lässt mich nicht",
+ /*french*/ "@? C'est toi?^Si je dirigeais le ranch, je construirais un #Parcours d'Obstacles#, et celui qui obtiendrait le meilleur temps gagnerait une #vache#!^"
+ "Elsie adore partager son #[[1]]# avec de nouvelles personnes, ce serait amusant!^... Mais Ingo ne me laisse pas faire...",
{QM_RED, QM_BLUE, QM_GREEN}));
hintTextTable[RHT_MALON_HINT_INGO_TEMPTED] = HintText(CustomMessage("@! You should come back in the morning and try to beat my time on the #Obstacle Course#!^"
"If you beat my time, I'll give you my favourite #cow# Elsie and her toy #[[1]]#!",
+ /*german*/ "@! Du solltest morgens zurückkommen und versuchen, meine Zeit im #Hindernisparcours# zu schlagen!^"
+ "Wenn du meine Zeit schlägst, gebe ich dir meine #Lieblingskuh# Elsie und ihr Spielzeug #[[1]]#!",
+ /*french*/ "@! Tu devrais revenir le matin et essayer de battre mon temps sur le #Parcours d'Obstacles#!^"
+ "Si tu bats mon temps, je te donnerai ma vache préférée, Elsie, ainsi que son jouet #[[1]]#!",
{QM_RED, QM_BLUE, QM_GREEN}));
hintTextTable[RHT_CHICKENS_HINT] = HintText(CustomMessage("You! Please!&Bring my Cucco's back to my pen!&I'll give you my #[[1]]#!",
+ /*german*/ "Du! Bitte!&Bring meine Hühner zurück in ihren&Stall! Ich gebe dir meine #[[1]]#!",
+ /*french*/ "Mes Cocottes sont perdues!&Dépose toutes les cocottes dans cet enclos!&Je te donnerai #[[1]]#!",
{QM_GREEN}));
hintTextTable[RHT_BIG_POES_HINT] = HintText(CustomMessage("You have #\x1E\x01 Poe Points#! Reach 1000 and you'll get a #[[1]]#!",
+ /*german*/ "Du hast #\x1E\x01 Nachtschwärmer-Punkte#! Erreiche 1000 und du bekommst ein #[[1]]#!",
+ /*french*/ "Tu as #\x1E\x01 Points d'Âme#! Atteins 1000 et tu recevras #[[1]]#!",
{QM_YELLOW, QM_GREEN}));
hintTextTable[RHT_BIGGORON_HINT] = HintText(CustomMessage("Arrrrrre you here to claim my finest #[[1]]#? Shoooooow me your #Claim Check#.",
+ /*german*/ "Arrrrr, bist du hier, um mein feinsten #[[1]]# zu beanspruchen? Zeig mir deinen #Zertifikat#!",
+ /*french*/ "Eeeeeees-tu ici pour réclaaaaaamer mon plus beau #[[1]]#? Moooooontre-moi ton #Certificat#.",
{QM_GREEN, QM_RED}));
hintTextTable[RHT_FROGS_HINT] = HintText(CustomMessage("Some frogs holding #[[1]]# are looking at you from underwater...",
@@ -2323,6 +2368,8 @@ void StaticData::HintTable_Init() {
{QM_GREEN}));
hintTextTable[RHT_OOT_HINT] = HintText(CustomMessage("Bring the #Spiritual Stones# to the past so you can receive #[[1]]# from Zelda and learn #[[2]]#!",
+ /*german*/ "Bringe die #Spirituellen Steine# in die Vergangenheit, damit du #[[1]]# von Zelda erhältst und #[[2]]#! lernst",
+ /*french*/ "Amène les #Pierres Spirituelles# dans le passé et Zelda te donnera #[[1]]# et t'apprendra #[[2]]# !",
{QM_BLUE, QM_GREEN, QM_GREEN}));
hintTextTable[RHT_SKULLS_HINT] = HintText(CustomMessage("Yeaaarrgh! I'm cursed!!^Please save me by destroying #[[d]] Spiders of the Curse# and I will give you my #[[1]]#!",
@@ -2332,6 +2379,10 @@ void StaticData::HintTable_Init() {
hintTextTable[RHT_MASK_SHOP_HINT] = HintText(CustomMessage("Some young scrubs in the #Deku Theatre# love seeing Masks!^"
"They'll give you #[[1]]# if you show them the #Skull Mask#, and #[[2]]# if you show them the #Mask of Truth#!",
+ /*german*/ "Ein paar junge Gören in der #Waldbühne# lieben es, Masken zu sehen!^"
+ "Sie geben dir #[[1]]#, wenn du ihnen die #Schädel-Maske# zeigst, und #[[2]]#, wenn du ihnen die #Maske des Wissens# zeigst!",
+ /*french*/ "De jeunes Pestes Mojo qui se trouvent dans le #Théâtre Mojo# adorent voir des masques !^"
+ "Elles te donneront #[[1]]# si tu leur montres le #Masque de Mort#, et #[[2]]# si tu leur montres le #Masque de Vérité#.",
{QM_GREEN, QM_GREEN, QM_RED, QM_GREEN, QM_RED}));
/*--------------------------
@@ -2339,33 +2390,34 @@ void StaticData::HintTable_Init() {
---------------------------*/
hintTextTable[RHT_GANON_JOKE01] = HintText(CustomMessage("Oh! It's @.&I was expecting someone called Sheik.&Do you know what happened to them?",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Oh! Da ist @.&Ich hatte eigentlich jemanden namens&Sheik erwartet. Weißt du, was mit&ihnen passiert ist?",
/*french*/ "Ah, c'est @.&J'attendais un certain Sheik.&Tu sais ce qui lui est arrivé?"));
// /*spanish*/¡Oh! Pero si es @.&Estaba esperando a alguien llamado Sheik. ¿Sabes qué puede haberle pasado?
hintTextTable[RHT_GANON_JOKE02] = HintText(CustomMessage("I knew I shouldn't have put the key on the other side of my door.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ich wusste, dass ich den Schlüssel nicht auf der anderen Seite meiner Tür legen sollte.",
/*french*/ "J'aurais dû garder la clé ici. Hélas..."));
// /*spanish*/Sabía que no tendría que haber dejado la llave al otro lado de la puerta.
hintTextTable[RHT_GANON_JOKE03] = HintText(CustomMessage("Looks like it's time for a round of tennis.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Sieht so aus, als wäre es Zeit für eine Runde Tennis.",
/*french*/ "C'est l'heure de jouer au tennis."));
// /*spanish*/Parece que es hora de una pachanga de tenis.
hintTextTable[RHT_GANON_JOKE04] = HintText(CustomMessage("You'll never deflect my bolts of energy with your sword, then shoot me with those Light Arrows you happen to have.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Du wirst meine Energiestrahlen nie mit deinem Schwert abwehren und mich dann mit den Lichtpfeilen beschießen, die du zufällig hast.",
/*french*/ "Ne perds pas ton temps à frapper mes éclairs d'énergie avec ton épée et me tirer avec tes flèches de Lumière!"));
// /*spanish*/Nunca reflejarás mis esferas de energía con tu espada, para después dispararme con las flechas de luz que tendrás.
hintTextTable[RHT_GANON_JOKE05] = HintText(CustomMessage("Why did I leave my trident back in the desert?",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Warum habe ich meinen Dreizack wieder in der Wüste gelassen?",
/*french*/ "Sale bêtise... Et j'ai oublié mon trident dans le désert!"));
// /*spanish*/Santa Hylia... ¿Por qué me habré dejado el tridente en el desierto?
hintTextTable[RHT_GANON_JOKE06] = HintText(CustomMessage("Zelda is probably going to do something stupid, like send you back to your own timeline.^So this is "
"quite meaningless. Do you really want to save this moron?",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Zelda wird wahrscheinlich wieder etwas Dummes tun, wie dich zurück in deine eigene Timeline schicken "
+ "^Das ist also ziemlich bedeutungslos. Willst du wirklich diese Idiotin retten?",
/*french*/ "Même si je suis vaincu... Zelda te renverra dans ton ère, et je reviendrai conquérir!^Telle est la "
"prophécie d'Hyrule Historia!"));
// /*spanish*/Seguro que Zelda trata de hacer alguna tontería, como enviarte de vuelta a tu línea temporal.^No tiene
@@ -2373,30 +2425,31 @@ void StaticData::HintTable_Init() {
hintTextTable[RHT_GANON_JOKE07] = HintText(CustomMessage("What about Zelda makes you think&she'd be a better ruler than I?^I saved Lon Lon Ranch,&fed the "
"hungry,&and my castle floats.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Was an Zelda lässt dich glauben&sie wäre eine bessere&Herrscherin als ich?^Ich rettete die Lon Lon Ranch,&fütterte die Hungrigen"
+ "&und mein Schloss schwebt.",
/*french*/ "Zelda ne sera jamais un meilleur monarque que moi!^J'ai un château volant, mes sujets sont des belles "
"amazones... et mes Moblins sont clairement plus puissants que jamais!"));
// /*spanish*/¿Qué te hace pensar que Zelda gobierna mejor que yo?^Yo he salvado el Rancho Lon Lon,&he alimentado a
// los hambrientos&y hasta hago que mi castillo flote.
hintTextTable[RHT_GANON_JOKE08] = HintText(CustomMessage("I've learned this spell,&it's really neat,&I'll keep it later&for your treat!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Ich hab' diesen Zauber gelernt,&er ist wirklich ziemlich fein,&ich heb' ihn auf für später,&und dann soll er dein Geschenk sein!",
/*french*/ "Gamin, ton destin achève,&sous mon sort tu périras!&Cette partie ne fut pas brève,&et cette mort, tu subiras!"));
// /*spanish*/Veamos ahora que harás,&la batalla ha de comenzar,&te enviaré de una vez al más allá,&¿listo para
// afrontar la verdad?
hintTextTable[RHT_GANON_JOKE09] = HintText(CustomMessage("Many tricks are up my sleeve,&to save yourself&you'd better leave!",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Viele Tricks hab' ich im Gepäck,&und um dich zu retten,&solltest du lieber weg.",
/*french*/ "Sale petit garnement,&tu fais erreur!&C'est maintenant que marque&ta dernière heure!"));
// /*spanish*/¿No osarás a mí enfrentarte?&Rimas aparte,&¡voy a matarte!
hintTextTable[RHT_GANON_JOKE10] = HintText(CustomMessage("After what you did to Koholint Island, how can you call me the bad guy?",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Nach dem, was du auf Insel Cocolint getan hast, wie kannst du mich da den Bösewicht nennen?",
/*french*/ "J'admire ce que tu as fait à l'Île Koholint... Toi et moi, nous devrions faire équipe!"));
// /*spanish*/Después de lo que le hiciste a la Isla Koholint, ¿cómo te atreves a llamarme malvado?
hintTextTable[RHT_GANON_JOKE11] = HintText(CustomMessage("Today, let's begin down&'The Hero is Defeated' timeline.",
- /*german*/ TODO_TRANSLATE,
+ /*german*/ "Heute beginnen wir in der&‚Der Held ist besiegt‘-Timeline",
/*french*/ "Si tu me vaincs, Hyrule sera englouti... mais si tu meurs, on aura A Link to the Past, le meilleur opus "
"de la série!"));
// /*spanish*/Hoy daremos lugar a la línea temporal del Héroe Derrotado.&¡Prepárate para el culmen de esta saga!
@@ -2410,7 +2463,9 @@ void StaticData::HintTable_Init() {
/*french*/ "tes poches"));
// /*spanish*/tu bolsillo
- hintTextTable[RHT_ISOLATED_PLACE] = HintText(CustomMessage("an Isolated Place"));
+ hintTextTable[RHT_ISOLATED_PLACE] = HintText(CustomMessage("an Isolated Place",
+ /*german*/ "ein abgelegener Ort",
+ /*french*/ "un lieu isolé"));
hintTextTable[RHT_DUNGEON_ORDINARY] = HintText(CustomMessage(" It's ordinary.",
/*german*/ "&Sieht aus wie immer.",
diff --git a/soh/soh/Enhancements/randomizer/Plandomizer.h b/soh/soh/Enhancements/randomizer/Plandomizer.h
index 0305beb0e..bfb118bbf 100644
--- a/soh/soh/Enhancements/randomizer/Plandomizer.h
+++ b/soh/soh/Enhancements/randomizer/Plandomizer.h
@@ -16,7 +16,7 @@ extern "C" {
#include "soh/Enhancements/randomizer/item.h"
#ifdef __cplusplus
-class PlandomizerWindow : public Ship::GuiWindow {
+class PlandomizerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp b/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp
index 5e864bab5..32548b310 100644
--- a/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp
+++ b/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp
@@ -535,6 +535,8 @@ void Rando::StaticData::RegisterCrateLocations() {
locationTable[RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2] = Location::SmallCrate(RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2, RCQUEST_VANILLA, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-1151, -939), "Before Child Climb Small Crate 2", RHT_CRATE_SPIRIT_TEMPLE, RG_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-512, -4592), "MQ Triple Hallway Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-666, -4671), "MQ Triple Hallway Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2));
+ locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1381, -2115), "MQ Jigglies Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1));
+ locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1341, -2116), "MQ Jigglies Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(1599, -1322), "MQ Frozen Eye Switch Small Crate 1", RHT_CRATE_FOREST_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(2364, -873), "MQ Frozen Eye Switch Small Crate 2", RHT_CRATE_FOREST_TEMPLE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(2312, -874), "MQ Frozen Eye Switch Small Crate 3", RHT_CRATE_FOREST_TEMPLE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3));
diff --git a/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp b/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp
index b8d31144a..b2e485a34 100644
--- a/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp
+++ b/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp
@@ -497,7 +497,7 @@ void Rando::StaticData::RegisterGrassLocations() {
locationTable[RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-91, -2815), "MQ Basement Grass 1", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(231, -3575), "MQ Basement Grass 2", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(305, -3481), "MQ Basement Grass 3", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3));
- locationTable[RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1089, -1489), "MQ Wigglers Grass", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS));
+ locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1089, -1489), "MQ Jigglies Grass", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS));
locationTable[RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(652, -5687), "MQ Like Like Grass", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS));
locationTable[RC_JABU_JABUS_BELLY_MQ_BASEMENT_BOOMERANG_GRASS] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_BASEMENT_BOOMERANG_GRASS, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(1228, -2647), "MQ Basement Boomerang Grass", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_BOOMERANG_GRASS));
locationTable[RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1360, -3606), "MQ After Big Octo Grass 1", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1));
diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp
index 4127ab21a..fa755325e 100644
--- a/soh/soh/Enhancements/randomizer/context.cpp
+++ b/soh/soh/Enhancements/randomizer/context.cpp
@@ -180,6 +180,8 @@ void Context::GenerateLocationPool() {
location.GetRandomizerCheck() == RC_HF_DEKU_SCRUB_GROTTO)) ||
(location.GetRCType() == RCTYPE_ADULT_TRADE && mOptions[RSK_SHUFFLE_ADULT_TRADE].Is(RO_GENERIC_OFF)) ||
(location.GetRCType() == RCTYPE_COW && mOptions[RSK_SHUFFLE_COWS].Is(RO_GENERIC_OFF)) ||
+ (location.GetRandomizerCheck() == RC_LH_HYRULE_LOACH &&
+ mOptions[RSK_FISHSANITY].IsNot(RO_FISHSANITY_HYRULE_LOACH)) ||
(location.GetRCType() == RCTYPE_FISH && !mFishsanity->GetFishLocationIncluded(&location)) ||
(location.GetRCType() == RCTYPE_POT && mOptions[RSK_SHUFFLE_POTS].Is(RO_SHUFFLE_POTS_OFF)) ||
(location.GetRCType() == RCTYPE_GRASS && mOptions[RSK_SHUFFLE_GRASS].Is(RO_SHUFFLE_GRASS_OFF)) ||
diff --git a/soh/soh/Enhancements/randomizer/entrance.cpp b/soh/soh/Enhancements/randomizer/entrance.cpp
index 57cf919ab..2ffb4a185 100644
--- a/soh/soh/Enhancements/randomizer/entrance.cpp
+++ b/soh/soh/Enhancements/randomizer/entrance.cpp
@@ -1489,62 +1489,62 @@ int EntranceShuffler::ShuffleAllEntrances() {
// If a boss room is inside a boss door, make the blue warp go outside the dungeon's entrance
std::map bossExits = {
{ EntranceNameByRegions(RR_DEKU_TREE_BOSS_ROOM, RR_DEKU_TREE_BOSS_ENTRYWAY),
- GetEntrance(EntranceNameByRegions(RR_DEKU_TREE_ENTRYWAY, RR_KF_OUTSIDE_DEKU_TREE)) },
+ GetEntrance(RR_DEKU_TREE_ENTRYWAY, RR_KF_OUTSIDE_DEKU_TREE) },
{ EntranceNameByRegions(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DODONGOS_CAVERN_BOSS_ENTRYWAY),
- GetEntrance(EntranceNameByRegions(RR_DODONGOS_CAVERN_ENTRYWAY, RR_DEATH_MOUNTAIN_TRAIL)) },
+ GetEntrance(RR_DODONGOS_CAVERN_ENTRYWAY, RR_DEATH_MOUNTAIN_TRAIL) },
{ EntranceNameByRegions(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY),
- GetEntrance(EntranceNameByRegions(RR_JABU_JABUS_BELLY_ENTRYWAY, RR_ZORAS_FOUNTAIN)) },
+ GetEntrance(RR_JABU_JABUS_BELLY_ENTRYWAY, RR_ZORAS_FOUNTAIN) },
{ EntranceNameByRegions(RR_FOREST_TEMPLE_BOSS_ROOM, RR_FOREST_TEMPLE_BOSS_ENTRYWAY),
- GetEntrance(EntranceNameByRegions(RR_FOREST_TEMPLE_ENTRYWAY, RR_SACRED_FOREST_MEADOW)) },
+ GetEntrance(RR_FOREST_TEMPLE_ENTRYWAY, RR_SACRED_FOREST_MEADOW) },
{ EntranceNameByRegions(RR_FIRE_TEMPLE_BOSS_ROOM, RR_FIRE_TEMPLE_BOSS_ENTRYWAY),
- GetEntrance(EntranceNameByRegions(RR_FIRE_TEMPLE_ENTRYWAY, RR_DMC_CENTRAL_LOCAL)) },
+ GetEntrance(RR_FIRE_TEMPLE_ENTRYWAY, RR_DMC_CENTRAL_LOCAL) },
{ EntranceNameByRegions(RR_WATER_TEMPLE_BOSS_ROOM, RR_WATER_TEMPLE_BOSS_ENTRYWAY),
- GetEntrance(EntranceNameByRegions(RR_WATER_TEMPLE_ENTRYWAY, RR_LAKE_HYLIA)) },
+ GetEntrance(RR_WATER_TEMPLE_ENTRYWAY, RR_LAKE_HYLIA) },
{ EntranceNameByRegions(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY),
- GetEntrance(EntranceNameByRegions(RR_SPIRIT_TEMPLE_ENTRYWAY, RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE)) },
+ GetEntrance(RR_SPIRIT_TEMPLE_ENTRYWAY, RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE) },
{ EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY),
- GetEntrance(EntranceNameByRegions(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION)) },
+ GetEntrance(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION) },
};
// If a boss room is inside a dungeon entrance (or inside a dungeon which is inside a dungeon entrance), make
// the blue warp go to that dungeon's blue warp target
std::map dungeonExits = {
{ EntranceNameByRegions(RR_DEKU_TREE_ENTRYWAY, RR_KF_OUTSIDE_DEKU_TREE),
- GetEntrance(EntranceNameByRegions(RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE)) },
+ GetEntrance(RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE) },
{ EntranceNameByRegions(RR_DODONGOS_CAVERN_ENTRYWAY, RR_DEATH_MOUNTAIN_TRAIL),
- GetEntrance(EntranceNameByRegions(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL)) },
+ GetEntrance(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL) },
{ EntranceNameByRegions(RR_JABU_JABUS_BELLY_ENTRYWAY, RR_ZORAS_FOUNTAIN),
- GetEntrance(EntranceNameByRegions(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_ZORAS_FOUNTAIN)) },
+ GetEntrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_ZORAS_FOUNTAIN) },
{ EntranceNameByRegions(RR_FOREST_TEMPLE_ENTRYWAY, RR_SACRED_FOREST_MEADOW),
- GetEntrance(EntranceNameByRegions(RR_FOREST_TEMPLE_BOSS_ROOM, RR_SACRED_FOREST_MEADOW)) },
+ GetEntrance(RR_FOREST_TEMPLE_BOSS_ROOM, RR_SACRED_FOREST_MEADOW) },
{ EntranceNameByRegions(RR_FIRE_TEMPLE_ENTRYWAY, RR_DMC_CENTRAL_LOCAL),
- GetEntrance(EntranceNameByRegions(RR_FIRE_TEMPLE_BOSS_ROOM, RR_DMC_CENTRAL_LOCAL)) },
+ GetEntrance(RR_FIRE_TEMPLE_BOSS_ROOM, RR_DMC_CENTRAL_LOCAL) },
{ EntranceNameByRegions(RR_WATER_TEMPLE_ENTRYWAY, RR_LAKE_HYLIA),
- GetEntrance(EntranceNameByRegions(RR_WATER_TEMPLE_BOSS_ROOM, RR_LAKE_HYLIA)) },
+ GetEntrance(RR_WATER_TEMPLE_BOSS_ROOM, RR_LAKE_HYLIA) },
{ EntranceNameByRegions(RR_SPIRIT_TEMPLE_ENTRYWAY, RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE),
- GetEntrance(EntranceNameByRegions(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS)) },
+ GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS) },
{ EntranceNameByRegions(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION),
- GetEntrance(EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION)) },
+ GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION) },
};
// Pair
std::vector bossRoomExitPairs = {
- { GetEntrance(EntranceNameByRegions(RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE)),
- GetEntrance(EntranceNameByRegions(RR_DEKU_TREE_BOSS_ROOM, RR_DEKU_TREE_BOSS_ENTRYWAY)) },
- { GetEntrance(EntranceNameByRegions(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL)),
- GetEntrance(EntranceNameByRegions(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DODONGOS_CAVERN_BOSS_ENTRYWAY)) },
- { GetEntrance(EntranceNameByRegions(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_ZORAS_FOUNTAIN)),
- GetEntrance(EntranceNameByRegions(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY)) },
- { GetEntrance(EntranceNameByRegions(RR_FOREST_TEMPLE_BOSS_ROOM, RR_SACRED_FOREST_MEADOW)),
- GetEntrance(EntranceNameByRegions(RR_FOREST_TEMPLE_BOSS_ROOM, RR_FOREST_TEMPLE_BOSS_ENTRYWAY)) },
- { GetEntrance(EntranceNameByRegions(RR_FIRE_TEMPLE_BOSS_ROOM, RR_DMC_CENTRAL_LOCAL)),
- GetEntrance(EntranceNameByRegions(RR_FIRE_TEMPLE_BOSS_ROOM, RR_FIRE_TEMPLE_BOSS_ENTRYWAY)) },
- { GetEntrance(EntranceNameByRegions(RR_WATER_TEMPLE_BOSS_ROOM, RR_LAKE_HYLIA)),
- GetEntrance(EntranceNameByRegions(RR_WATER_TEMPLE_BOSS_ROOM, RR_WATER_TEMPLE_BOSS_ENTRYWAY)) },
- { GetEntrance(EntranceNameByRegions(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS)),
- GetEntrance(EntranceNameByRegions(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY)) },
- { GetEntrance(EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION)),
- GetEntrance(EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY)) },
+ { GetEntrance(RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE),
+ GetEntrance(RR_DEKU_TREE_BOSS_ROOM, RR_DEKU_TREE_BOSS_ENTRYWAY) },
+ { GetEntrance(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL),
+ GetEntrance(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DODONGOS_CAVERN_BOSS_ENTRYWAY) },
+ { GetEntrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_ZORAS_FOUNTAIN),
+ GetEntrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY) },
+ { GetEntrance(RR_FOREST_TEMPLE_BOSS_ROOM, RR_SACRED_FOREST_MEADOW),
+ GetEntrance(RR_FOREST_TEMPLE_BOSS_ROOM, RR_FOREST_TEMPLE_BOSS_ENTRYWAY) },
+ { GetEntrance(RR_FIRE_TEMPLE_BOSS_ROOM, RR_DMC_CENTRAL_LOCAL),
+ GetEntrance(RR_FIRE_TEMPLE_BOSS_ROOM, RR_FIRE_TEMPLE_BOSS_ENTRYWAY) },
+ { GetEntrance(RR_WATER_TEMPLE_BOSS_ROOM, RR_LAKE_HYLIA),
+ GetEntrance(RR_WATER_TEMPLE_BOSS_ROOM, RR_WATER_TEMPLE_BOSS_ENTRYWAY) },
+ { GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS),
+ GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY) },
+ { GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION),
+ GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY) },
};
for (EntrancePair pair : bossRoomExitPairs) {
diff --git a/soh/soh/Enhancements/randomizer/fishsanity.cpp b/soh/soh/Enhancements/randomizer/fishsanity.cpp
index 8d4435f9a..99636d1a4 100644
--- a/soh/soh/Enhancements/randomizer/fishsanity.cpp
+++ b/soh/soh/Enhancements/randomizer/fishsanity.cpp
@@ -74,13 +74,10 @@ Fishsanity::~Fishsanity() {
bool Fishsanity::GetFishLocationIncluded(Rando::Location* loc, FishsanityOptionsSource optionsSource) {
auto [mode, numFish, ageSplit] = GetOptions(optionsSource);
- if (loc->GetRCType() != RCTYPE_FISH || mode == RO_FISHSANITY_OFF) {
+ if (loc->GetRCType() != RCTYPE_FISH || mode == RO_FISHSANITY_OFF || mode == RO_FISHSANITY_HYRULE_LOACH) {
return false;
}
RandomizerCheck rc = loc->GetRandomizerCheck();
- if (mode == RO_FISHSANITY_HYRULE_LOACH && rc != RC_LH_HYRULE_LOACH) {
- return false;
- }
// Are pond fish enabled, and is this a pond fish location?
if (mode != RO_FISHSANITY_OVERWORLD && numFish > 0 && loc->GetScene() == SCENE_FISHING_POND &&
loc->GetActorID() == ACTOR_FISHING) {
diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp
index f030ac524..c04c4706e 100644
--- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp
+++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp
@@ -245,10 +245,6 @@ void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) {
Flags_SetRandomizerInf(RAND_INF_ZELDAS_LETTER);
}
- if (flagType == FLAG_EVENT_CHECK_INF && flag == EVENTCHKINF_OBTAINED_POCKET_EGG) {
- Flags_SetRandomizerInf(RAND_INF_WEIRD_EGG);
- }
-
RandomizerCheck rc = GetRandomizerCheckFromFlag(flagType, flag);
if (rc == RC_UNKNOWN_CHECK)
return;
@@ -1765,10 +1761,6 @@ void RandomizerOnSceneInitHandler(int16_t sceneNum) {
// Handle updated link spawn positions
Entrance_OverrideSpawnScene(sceneNum, gPlayState->curSpawn);
-
- Entrance_OverrideWeatherState();
- // Need to reinitialize the environment after replacing the weather mode
- Play_InitEnvironment(gPlayState, gPlayState->skyboxId);
}
// LACs & Prelude checks
@@ -1807,6 +1799,13 @@ void RandomizerOnSceneInitHandler(int16_t sceneNum) {
});
}
+void RandomizerAfterSceneCommandsHandler(int16_t sceneNum) {
+ // ENTRTODO: Move all entrance rando handling to a dedicated file
+ if (RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) {
+ Entrance_OverrideWeatherState();
+ }
+}
+
void EnSi_DrawRandomizedItem(EnSi* enSi, PlayState* play) {
GetItemEntry randoItem = enSi->sohGetItemEntry;
if (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0)) {
@@ -2362,6 +2361,7 @@ void RandomizerRegisterHooks() {
static uint32_t onDialogMessageHook = 0;
static uint32_t onVanillaBehaviorHook = 0;
static uint32_t onSceneInitHook = 0;
+ static uint32_t afterSceneCommandsHook = 0;
static uint32_t onActorInitHook = 0;
static uint32_t onActorUpdateHook = 0;
static uint32_t onPlayerUpdateHook = 0;
@@ -2398,6 +2398,7 @@ void RandomizerRegisterHooks() {
GameInteractor::Instance->UnregisterGameHook(onDialogMessageHook);
GameInteractor::Instance->UnregisterGameHook(onVanillaBehaviorHook);
GameInteractor::Instance->UnregisterGameHook(onSceneInitHook);
+ GameInteractor::Instance->UnregisterGameHook(afterSceneCommandsHook);
GameInteractor::Instance->UnregisterGameHook(onActorInitHook);
GameInteractor::Instance->UnregisterGameHook(onActorUpdateHook);
GameInteractor::Instance->UnregisterGameHook(onPlayerUpdateHook);
@@ -2430,6 +2431,7 @@ void RandomizerRegisterHooks() {
onDialogMessageHook = 0;
onVanillaBehaviorHook = 0;
onSceneInitHook = 0;
+ afterSceneCommandsHook = 0;
onActorInitHook = 0;
onActorUpdateHook = 0;
onPlayerUpdateHook = 0;
@@ -2481,6 +2483,8 @@ void RandomizerRegisterHooks() {
RandomizerOnVanillaBehaviorHandler);
onSceneInitHook =
GameInteractor::Instance->RegisterGameHook(RandomizerOnSceneInitHandler);
+ afterSceneCommandsHook = GameInteractor::Instance->RegisterGameHook(
+ RandomizerAfterSceneCommandsHandler);
onActorInitHook =
GameInteractor::Instance->RegisterGameHook(RandomizerOnActorInitHandler);
onActorUpdateHook =
diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp
index 64d6a726c..56001db48 100644
--- a/soh/soh/Enhancements/randomizer/item_list.cpp
+++ b/soh/soh/Enhancements/randomizer/item_list.cpp
@@ -286,12 +286,12 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_TREASURE_GAME_HEART] = Item(RG_TREASURE_GAME_HEART, Text{ "Piece of Heart (WINNER)", "Quart de Coeur (Chasse-aux-Trésors)", "Herzstück (Schatztruhenminispiel)" }, ITEMTYPE_ITEM, GI_HEART_PIECE_WIN, true, LOGIC_PIECE_OF_HEART, RHT_TREASURE_GAME_HEART, ITEM_HEART_PIECE_2, OBJECT_GI_HEARTS, GID_HEART_PIECE, 0xFA, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_NONE);
itemTable[RG_TREASURE_GAME_GREEN_RUPEE] = Item(RG_TREASURE_GAME_GREEN_RUPEE, Text{ "Green Rupee (LOSER)", "Rubis Vert (Chasse-aux-Trésors)", "Grüner Rubin (Schatztruhenminispiel)" }, ITEMTYPE_ITEM, GI_RUPEE_GREEN_LOSE, false, LOGIC_NONE, RHT_TREASURE_GAME_GREEN_RUPEE, ITEM_RUPEE_GREEN, OBJECT_GI_RUPY, GID_RUPEE_GREEN, 0xF4, 0x00, CHEST_ANIM_SHORT, ITEM_CATEGORY_MAJOR, MOD_NONE);
// Shop
- itemTable[RG_BUY_DEKU_NUTS_5] = Item(RG_BUY_DEKU_NUTS_5, Text{ "Buy Deku Nut (5)", "Acheter: Noix Mojo (5)", "Deku-Nuß kaufen (5)" }, ITEMTYPE_SHOP, GI_NUTS_5_2, true, LOGIC_NUTS, RHT_DEKU_NUTS_5, ITEM_NUTS_5, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 15);
+ itemTable[RG_BUY_DEKU_NUTS_5] = Item(RG_BUY_DEKU_NUTS_5, Text{ "Buy Deku Nut (5)", "Acheter: Noix Mojo (5)", "Deku-Nuß kaufen (5)" }, ITEMTYPE_SHOP, GI_NUTS_5_2, true, LOGIC_BUY_NUTS, RHT_DEKU_NUTS_5, ITEM_NUTS_5, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 15);
itemTable[RG_BUY_ARROWS_30] = Item(RG_BUY_ARROWS_30, Text{ "Buy Arrows (30)", "Acheter: Flèches (30)", "Pfeile kaufen (30)" }, ITEMTYPE_SHOP, GI_ARROWS_MEDIUM, true, LOGIC_BUY_ARROW, RHT_ARROWS_30, ITEM_ARROWS_MEDIUM, OBJECT_GI_ARROW, GID_ARROWS_MEDIUM, 0xE6, 0x49, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 60);
itemTable[RG_BUY_ARROWS_50] = Item(RG_BUY_ARROWS_50, Text{ "Buy Arrows (50)", "Acheter: Flèches (50)", "Pfeile kaufen (50)" }, ITEMTYPE_SHOP, GI_ARROWS_LARGE, true, LOGIC_BUY_ARROW, RHT_ARROWS_30, ITEM_ARROWS_LARGE, OBJECT_GI_ARROW, GID_ARROWS_LARGE, 0xE6, 0x4A, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 90);
itemTable[RG_BUY_BOMBS_525] = Item(RG_BUY_BOMBS_525, Text{ "Buy Bombs (5) [25]", "Acheter: Bombes (5) [25]", "Bomben kaufen (5) [25]" }, ITEMTYPE_SHOP, GI_BOMBS_5, true, LOGIC_BUY_BOMB, RHT_BOMBS_5, ITEM_BOMBS_5, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 25);
- itemTable[RG_BUY_DEKU_NUTS_10] = Item(RG_BUY_DEKU_NUTS_10, Text{ "Buy Deku Nut (10)", "Acheter: Noix Mojo (10)", "Deku-Nuß kaufen (10)" }, ITEMTYPE_SHOP, GI_NUTS_10, true, LOGIC_NUTS, RHT_DEKU_NUTS_10, ITEM_NUTS_10, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 30);
- itemTable[RG_BUY_DEKU_STICK_1] = Item(RG_BUY_DEKU_STICK_1, Text{ "Buy Deku Stick (1)", "Acheter: Bâton Mojo (1)", "Deku-Stab kaufen (1)" }, ITEMTYPE_SHOP, GI_STICKS_1, true, LOGIC_STICKS, RHT_DEKU_STICK_1, ITEM_STICK, OBJECT_GI_STICK, GID_STICK, 0x37, 0x0D, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 10);
+ itemTable[RG_BUY_DEKU_NUTS_10] = Item(RG_BUY_DEKU_NUTS_10, Text{ "Buy Deku Nut (10)", "Acheter: Noix Mojo (10)", "Deku-Nuß kaufen (10)" }, ITEMTYPE_SHOP, GI_NUTS_10, true, LOGIC_BUY_NUTS, RHT_DEKU_NUTS_10, ITEM_NUTS_10, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 30);
+ itemTable[RG_BUY_DEKU_STICK_1] = Item(RG_BUY_DEKU_STICK_1, Text{ "Buy Deku Stick (1)", "Acheter: Bâton Mojo (1)", "Deku-Stab kaufen (1)" }, ITEMTYPE_SHOP, GI_STICKS_1, true, LOGIC_BUY_STICKS, RHT_DEKU_STICK_1, ITEM_STICK, OBJECT_GI_STICK, GID_STICK, 0x37, 0x0D, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 10);
itemTable[RG_BUY_BOMBS_10] = Item(RG_BUY_BOMBS_10, Text{ "Buy Bombs (10)", "Acheter: Bombes (10)", "Bomben kaufen (10)" }, ITEMTYPE_SHOP, GI_BOMBS_10, true, LOGIC_BUY_BOMB, RHT_BOMBS_10, ITEM_BOMBS_10, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 50);
itemTable[RG_BUY_FISH] = Item(RG_BUY_FISH, Text{ "Buy Fish", "Acheter: Poisson", "Fisch kaufen" }, ITEMTYPE_SHOP, GI_FISH, true, LOGIC_FISH_ACCESS, RHT_BOTTLE_WITH_FISH, ITEM_FISH, OBJECT_GI_FISH, GID_FISH, 0x47, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, false, 200);
itemTable[RG_BUY_RED_POTION_30] = Item(RG_BUY_RED_POTION_30, Text{ "Buy Red Potion [30]", "Acheter: Potion Rouge [30]", "Rotes Elixier kaufen [30]" }, ITEMTYPE_SHOP, GI_POTION_RED, false, LOGIC_NONE, RHT_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, false, 30);
diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp
index 4cc906680..dc1ddfa2a 100644
--- a/soh/soh/Enhancements/randomizer/location_access.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access.cpp
@@ -633,13 +633,10 @@ std::vector GetShuffleableEntrances(Rando::EntranceType type,
return entrancesToShuffle;
}
-// Get the specific entrance by name
-Rando::Entrance* GetEntrance(const std::string name) {
- for (RandomizerRegion region : Regions::GetAllRegions()) {
- for (auto& exit : RegionTable(region)->exits) {
- if (exit.GetName() == name) {
- return &exit;
- }
+Rando::Entrance* GetEntrance(RandomizerRegion source, RandomizerRegion destination) {
+ for (auto& exit : RegionTable(source)->exits) {
+ if (exit.GetConnectedRegionKey() == destination) {
+ return &exit;
}
}
diff --git a/soh/soh/Enhancements/randomizer/location_access.h b/soh/soh/Enhancements/randomizer/location_access.h
index 2bc4ff78b..c2828ea97 100644
--- a/soh/soh/Enhancements/randomizer/location_access.h
+++ b/soh/soh/Enhancements/randomizer/location_access.h
@@ -350,7 +350,7 @@ extern void DumpWorldGraph(std::string str);
void RegionTable_Init();
Region* RegionTable(const RandomizerRegion regionKey);
std::vector GetShuffleableEntrances(Rando::EntranceType type, bool onlyPrimary = true);
-Rando::Entrance* GetEntrance(const std::string name);
+Rando::Entrance* GetEntrance(RandomizerRegion source, RandomizerRegion destination);
// Overworld
void RegionTable_Init_KokiriForest();
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 ded6c8279..451225273 100644
--- a/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp
@@ -63,8 +63,8 @@ void RegionTable_Init_GanonsCastle() {
}, {
//Locations
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))),
+ LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_POT_1, logic->CanBreakPots() && (logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_DINS_FIRE) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT))))),
+ LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_POT_2, logic->CanBreakPots() && (logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_DINS_FIRE) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT))))),
}, {});
areaTable[RR_GANONS_CASTLE_FIRE_TRIAL] = Region("Ganon's Castle Fire Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, 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 3c45682ae..a43e1b685 100644
--- a/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp
@@ -312,9 +312,11 @@ void RegionTable_Init_JabuJabusBelly() {
}, {
//Locations
LOCATION(RC_JABU_JABUS_BELLY_MQ_COW, logic->CanUse(RG_EPONAS_SONG) && logic->CanUse(RG_FAIRY_SLINGSHOT)),
- LOCATION(RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS, logic->CanCutShrubs()),
+ LOCATION(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS, logic->CanCutShrubs()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1, logic->CanCutShrubs()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2, logic->CanCutShrubs()),
+ LOCATION(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1, logic->CanUse(RG_FAIRY_SLINGSHOT) && logic->CanBreakSmallCrates()),
+ LOCATION(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2, logic->CanUse(RG_FAIRY_SLINGSHOT) && logic->CanBreakSmallCrates()),
}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, []{return logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_FAIRY_SLINGSHOT);}),
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/castle_grounds.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/castle_grounds.cpp
index bdcdf9a4c..dbf467b0f 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/castle_grounds.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/castle_grounds.cpp
@@ -34,7 +34,7 @@ void RegionTable_Init_CastleGrounds() {
}, {
//Exits
Entrance(RR_CASTLE_GROUNDS, []{return true;}),
- Entrance(RR_HC_GARDEN, []{return logic->CanUse(RG_WEIRD_EGG) || !ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}),
+ Entrance(RR_HC_GARDEN, []{return logic->CanUse(RG_WEIRD_EGG) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}),
Entrance(RR_HC_GREAT_FAIRY_FOUNTAIN, []{return logic->BlastOrSmash();}),
Entrance(RR_HC_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}),
});
diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp
index 9eec96606..4c66089c1 100644
--- a/soh/soh/Enhancements/randomizer/logic.cpp
+++ b/soh/soh/Enhancements/randomizer/logic.cpp
@@ -121,8 +121,6 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RG_STONE_OF_AGONY:
case RG_GERUDO_MEMBERSHIP_CARD:
return CheckQuestItem(RandoGetToQuestItem.at(itemName));
- case RG_RUTOS_LETTER:
- return CheckEventChkInf(EVENTCHKINF_OBTAINED_RUTOS_LETTER);
case RG_DOUBLE_DEFENSE:
return GetSaveContext()->isDoubleDefenseAcquired;
case RG_FISHING_POLE:
@@ -171,6 +169,7 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RG_BACK_TOWER_KEY:
case RG_HYLIA_LAB_KEY:
case RG_FISHING_HOLE_KEY:
+ case RG_RUTOS_LETTER:
return CheckRandoInf(RandoGetToRandInf.at(itemName));
// Boss Keys
case RG_EPONA:
@@ -323,11 +322,9 @@ bool Logic::CanUse(RandomizerGet itemName) {
case RG_KOKIRI_SWORD:
return IsChild; // || KokiriSwordAsAdult;
case RG_NUTS:
- return (NutPot || NutCrate || DekuBabaNuts) &&
- AmmoCanDrop; // RANDOTODO BuyNuts currently mixed in with Nuts, should be seperate as BuyNuts are
- // also a Nuts source
+ return ((NutPot || NutCrate || DekuBabaNuts) && AmmoCanDrop) || GetInLogic(LOGIC_BUY_NUTS);
case RG_STICKS:
- return IsChild /* || StickAsAdult;*/ && (StickPot || DekuBabaSticks);
+ return IsChild /* || StickAsAdult;*/ && (StickPot || DekuBabaSticks || GetInLogic(LOGIC_BUY_STICKS));
case RG_DEKU_SHIELD:
return IsChild; // || DekuShieldAsAdult;
case RG_PROGRESSIVE_BOMB_BAG:
@@ -1454,6 +1451,7 @@ std::map Logic::RandoGetToEquipFlag = {
std::map Logic::RandoGetToRandInf = {
{ RG_ZELDAS_LETTER, RAND_INF_ZELDAS_LETTER },
{ RG_WEIRD_EGG, RAND_INF_WEIRD_EGG },
+ { RG_RUTOS_LETTER, RAND_INF_OBTAINED_RUTOS_LETTER },
{ RG_GOHMA_SOUL, RAND_INF_GOHMA_SOUL },
{ RG_KING_DODONGO_SOUL, RAND_INF_KING_DODONGO_SOUL },
{ RG_BARINADE_SOUL, RAND_INF_BARINADE_SOUL },
@@ -1818,7 +1816,7 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
mSaveContext->inventory.items[slot] = itemId;
} break;
case RG_RUTOS_LETTER:
- SetEventChkInf(EVENTCHKINF_OBTAINED_RUTOS_LETTER, state);
+ SetRandoInf(RAND_INF_OBTAINED_RUTOS_LETTER, state);
break;
case RG_GOHMA_SOUL:
case RG_KING_DODONGO_SOUL:
diff --git a/soh/soh/Enhancements/randomizer/option.cpp b/soh/soh/Enhancements/randomizer/option.cpp
index 43fcc2f65..bec719d4b 100644
--- a/soh/soh/Enhancements/randomizer/option.cpp
+++ b/soh/soh/Enhancements/randomizer/option.cpp
@@ -368,7 +368,9 @@ void OptionGroup::Disable() {
bool OptionGroup::RenderImGui() const { // NOLINT(*-no-recursion)
ImGuiWindow* window = ImGui::GetCurrentWindow();
bool changed = false;
- ImGui::BeginDisabled(mDisabled);
+ ImGui::BeginDisabled(mDisabled || CVarGetInteger(CVAR_SETTING("DisableChanges"), 0) ||
+ CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0) ||
+ CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0));
if (mContainerType == WidgetContainerType::TABLE) {
if (ImGui::BeginTable(mName.c_str(), static_cast(mSubGroups.size()),
ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) {
diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp
index 9e59e61a7..831b0cea7 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer.cpp
@@ -1552,7 +1552,7 @@ std::map rcToRandomizerInf = {
{ RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1, RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1 },
{ RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2, RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2 },
{ RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3, RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3 },
- { RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS, RAND_INF_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS },
+ { RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS, RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS },
{ RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1, RAND_INF_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1 },
{ RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2, RAND_INF_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2 },
{ RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS, RAND_INF_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS },
@@ -3023,6 +3023,14 @@ std::map rcToRandomizerInf = {
RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2,
RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2,
},
+ {
+ RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1,
+ RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1,
+ },
+ {
+ RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2,
+ RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2,
+ },
{
RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1,
RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1,
@@ -3690,6 +3698,7 @@ void RandomizerSettingsWindow::DrawElement() {
locationsTabOpen = false;
tricksTabOpen = false;
}
+ ImGui::EndDisabled();
UIWidgets::Spacer(0);
UIWidgets::CVarCheckbox("Manual seed entry", CVAR_RANDOMIZER_SETTING("ManualSeedEntry"),
@@ -3725,9 +3734,7 @@ void RandomizerSettingsWindow::DrawElement() {
}
UIWidgets::Spacer(0);
- ImGui::BeginDisabled((CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0) &&
- gSaveContext.gameMode != GAMEMODE_FILE_SELECT) ||
- GameInteractor::IsSaveLoaded());
+ ImGui::BeginDisabled((gSaveContext.gameMode != GAMEMODE_FILE_SELECT) || GameInteractor::IsSaveLoaded());
if (UIWidgets::Button("Generate Randomizer",
UIWidgets::ButtonOptions().Size(ImVec2(250.f, 0.f)).Color(THEME_COLOR))) {
ctx->SetSpoilerLoaded(false);
@@ -3746,7 +3753,6 @@ void RandomizerSettingsWindow::DrawElement() {
// ImGui::Text("Settings File: %s", presetfilepath.c_str());
UIWidgets::Separator(true, true, 0.f, 0.f);
- ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
ImGuiWindow* window = ImGui::GetCurrentWindow();
static ImVec2 cellPadding(8.0f, 8.0f);
@@ -3762,8 +3768,6 @@ void RandomizerSettingsWindow::DrawElement() {
ImGui::EndTabItem();
}
- ImGui::BeginDisabled(CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) ==
- RO_LOGIC_VANILLA);
if (ImGui::BeginTabItem("Items")) {
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding);
ImGui::BeginDisabled(CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) ==
@@ -3775,23 +3779,23 @@ void RandomizerSettingsWindow::DrawElement() {
ImGui::PopStyleVar(1);
ImGui::EndTabItem();
}
- ImGui::EndDisabled();
- ImGui::BeginDisabled(CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) ==
- RO_LOGIC_VANILLA);
if (ImGui::BeginTabItem("Gameplay")) {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) ==
+ RO_LOGIC_VANILLA);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding);
if (mSettings->GetOptionGroup(RSG_GAMEPLAY_IMGUI_TABLE).RenderImGui()) {
mNeedsUpdate = true;
}
+ ImGui::EndDisabled();
ImGui::PopStyleVar(1);
ImGui::EndTabItem();
}
- ImGui::EndDisabled();
- ImGui::BeginDisabled(CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) ==
- RO_LOGIC_VANILLA);
if (ImGui::BeginTabItem("Locations")) {
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0) || disableEditingRandoSettings ||
+ CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) ==
+ RO_LOGIC_VANILLA);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding);
if (!locationsTabOpen) {
locationsTabOpen = true;
@@ -3924,10 +3928,10 @@ void RandomizerSettingsWindow::DrawElement() {
}
ImGui::PopStyleVar(1);
ImGui::EndTabItem();
+ ImGui::EndDisabled();
} else {
locationsTabOpen = false;
}
- ImGui::EndDisabled();
if (ImGui::BeginTabItem("Tricks/Glitches")) {
if (!tricksTabOpen) {
@@ -3975,8 +3979,9 @@ void RandomizerSettingsWindow::DrawElement() {
ImGui::EndTable();
}
- ImGui::BeginDisabled(CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) ==
- RO_LOGIC_VANILLA);
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0) || disableEditingRandoSettings ||
+ CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) ==
+ RO_LOGIC_VANILLA);
// Tricks
static std::unordered_map areaTreeDisabled{
@@ -4354,9 +4359,6 @@ void RandomizerSettingsWindow::DrawElement() {
ImGui::EndTabBar();
}
UIWidgets::PopStyleTabs();
-
- ImGui::EndDisabled();
- ImGui::EndDisabled();
}
void RandomizerSettingsWindow::UpdateElement() {
diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h
index f70f02eea..63ab99e86 100644
--- a/soh/soh/Enhancements/randomizer/randomizerTypes.h
+++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h
@@ -184,10 +184,10 @@ typedef enum {
LOGIC_GREG,
LOGIC_PIECE_OF_HEART,
LOGIC_HEART_CONTAINER,
- LOGIC_NUTS,
+ LOGIC_BUY_NUTS,
LOGIC_BUY_ARROW,
LOGIC_BUY_BOMB,
- LOGIC_STICKS,
+ LOGIC_BUY_STICKS,
LOGIC_FISH_ACCESS,
LOGIC_BUY_MAGIC_POTION,
LOGIC_BUY_BOMBCHUS,
@@ -2601,6 +2601,8 @@ typedef enum {
// MQ Dungeon Small Crates
RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1,
RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2,
+ RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1,
+ RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2,
RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1,
RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2,
RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3,
@@ -3473,7 +3475,7 @@ typedef enum {
RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1,
RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2,
RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3,
- RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS,
+ RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS,
RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1,
RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2,
RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS,
diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
index aaf0f26ec..aa0dceda8 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
@@ -1258,8 +1258,13 @@ void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flag
windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
}
}
- ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(Color_Background.r / 255.0f, Color_Background.g / 255.0f,
- Color_Background.b / 255.0f, Color_Background.a / 255.0f));
+ auto maybeParent = ImGui::GetCurrentWindow();
+ ImGuiWindow* window = ImGui::FindWindowByName(UniqueName.c_str());
+ if (window != NULL && window->DockTabIsVisible && window->ParentWindow != NULL &&
+ std::string(window->ParentWindow->Name).compare(0, strlen("Main - Deck"), "Main - Deck") == 0) {
+ Color_Background.a = 255;
+ }
+ ImGui::PushStyleColor(ImGuiCol_WindowBg, VecFromRGBA8(Color_Background));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f);
ImGui::Begin(UniqueName.c_str(), &open, windowFlags);
@@ -2075,11 +2080,13 @@ void CheckTrackerSettingsWindow::DrawElement() {
.DefaultIndex(TRACKER_COMBO_BUTTON_L));
}
}
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::CVarCheckbox("Vanilla/MQ Dungeon Spoilers", CVAR_TRACKER_CHECK("MQSpoilers"),
UIWidgets::CheckboxOptions()
.Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. "
"Otherwise, Vanilla/MQ dungeon locations must be unlocked.")
.Color(THEME_COLOR));
+ ImGui::EndDisabled();
if (UIWidgets::CVarCheckbox(
"Hide unshuffled shop item checks", CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"),
UIWidgets::CheckboxOptions()
@@ -2100,6 +2107,7 @@ void CheckTrackerSettingsWindow::DrawElement() {
UIWidgets::CheckboxOptions()
.Tooltip("If enabled, will show a check's logic when hovering over it.")
.Color(THEME_COLOR));
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
if (UIWidgets::CVarCheckbox("Enable Available Checks", CVAR_TRACKER_CHECK("EnableAvailableChecks"),
UIWidgets::CheckboxOptions()
.Tooltip("If enabled, will show the checks that are available to be collected "
@@ -2108,6 +2116,7 @@ void CheckTrackerSettingsWindow::DrawElement() {
enableAvailableChecks = CVarGetInteger(CVAR_TRACKER_CHECK("EnableAvailableChecks"), 0);
RecalculateAvailableChecks();
}
+ ImGui::EndDisabled();
// Filtering settings
UIWidgets::PaddedSeparator();
diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h
index d6fd503b3..7636ab063 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h
@@ -8,7 +8,7 @@
namespace CheckTracker {
-class CheckTrackerSettingsWindow : public Ship::GuiWindow {
+class CheckTrackerSettingsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
~CheckTrackerSettingsWindow(){};
@@ -19,7 +19,7 @@ class CheckTrackerSettingsWindow : public Ship::GuiWindow {
void UpdateElement() override{};
};
-class CheckTrackerWindow : public Ship::GuiWindow {
+class CheckTrackerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void Draw() override;
diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp
index f93172647..b71bae5b3 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp
@@ -690,6 +690,7 @@ void EntranceTrackerSettingsWindow::DrawElement() {
UIWidgets::CheckboxOptions()
.Tooltip("Automatically scroll to the first available entrance in the current scene")
.Color(THEME_COLOR));
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::CVarCheckbox("Highlight previous", CVAR_TRACKER_ENTRANCE("HighlightPrevious"),
UIWidgets::CheckboxOptions()
.Tooltip("Highlight the previous entrance that Link came from")
@@ -698,6 +699,7 @@ void EntranceTrackerSettingsWindow::DrawElement() {
UIWidgets::CheckboxOptions()
.Tooltip("Highlight available entrances in the current scene")
.Color(THEME_COLOR));
+ ImGui::EndDisabled();
UIWidgets::CVarCheckbox("Hide undiscovered", CVAR_TRACKER_ENTRANCE("CollapseUndiscovered"),
UIWidgets::CheckboxOptions()
.Tooltip("Collapse undiscovered entrances towards the bottom of each group")
@@ -724,6 +726,7 @@ void EntranceTrackerSettingsWindow::DrawElement() {
UIWidgets::RadioButtonsOptions().Color(THEME_COLOR).Tooltip("Group entrances by their entrance type"));
ImGui::Text("Spoiler Reveal");
+ ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::CVarCheckbox(
"Show Source", CVAR_TRACKER_ENTRANCE("ShowFrom"),
UIWidgets::CheckboxOptions().Tooltip("Reveal the sourcefor undiscovered entrances").Color(THEME_COLOR));
@@ -731,7 +734,7 @@ void EntranceTrackerSettingsWindow::DrawElement() {
UIWidgets::CheckboxOptions()
.Tooltip("Reveal the destination for undiscovered entrances")
.Color(THEME_COLOR));
-
+ ImGui::EndDisabled();
ImGui::EndTable();
}
diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.h
index ff9462881..4ee33ef62 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.h
@@ -91,7 +91,7 @@ s16 GetLastEntranceOverride();
s16 GetCurrentGrottoId();
const EntranceData* GetEntranceData(s16);
-class EntranceTrackerSettingsWindow : public Ship::GuiWindow {
+class EntranceTrackerSettingsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
@@ -101,7 +101,7 @@ class EntranceTrackerSettingsWindow : public Ship::GuiWindow {
void UpdateElement() override{};
};
-class EntranceTrackerWindow : public Ship::GuiWindow {
+class EntranceTrackerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void Draw() override;
diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h
index 913d37c20..5748f0283 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_inf.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h
@@ -973,6 +973,8 @@ typedef enum {
RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1,
RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2,
+ RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1,
+ RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2,
RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1,
RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2,
RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3,
@@ -1931,7 +1933,7 @@ typedef enum {
RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1,
RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2,
RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3,
- RAND_INF_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS,
+ RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS,
RAND_INF_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1,
RAND_INF_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2,
RAND_INF_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS,
@@ -1952,6 +1954,7 @@ typedef enum {
RAND_INF_DEKU_TREE_QUEEN_GOHMA_GRASS_7,
RAND_INF_DEKU_TREE_QUEEN_GOHMA_GRASS_8,
// End Grass
+ RAND_INF_OBTAINED_RUTOS_LETTER,
// If you add anything to this list, you need to update the size of randomizerInf in z64save.h to be
// ceil(RAND_INF_MAX / 16)
diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
index b86da3c0c..9b7b1fd39 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
@@ -1162,8 +1162,10 @@ void BeginFloatingWindows(std::string UniqueName, ImGuiWindowFlags flags = 0) {
}
}
auto color = VecFromRGBA8(CVarGetColor(CVAR_TRACKER_ITEM("BgColor.Value"), { 0, 0, 0, 0 }));
+ auto maybeParent = ImGui::GetCurrentWindow();
ImGuiWindow* window = ImGui::FindWindowByName(UniqueName.c_str());
- if (window != NULL && window->DockTabIsVisible) {
+ if (window != NULL && window->DockTabIsVisible && window->ParentWindow != NULL &&
+ std::string(window->ParentWindow->Name).compare(0, strlen("Main - Deck"), "Main - Deck") == 0) {
color.w = 1.0f;
}
ImGui::PushStyleColor(ImGuiCol_WindowBg, color);
diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h
index 55f7b8974..7175baeab 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h
@@ -30,7 +30,7 @@ typedef struct ItemTrackerDungeon {
std::vector items;
} ItemTrackerDungeon;
-class ItemTrackerSettingsWindow : public Ship::GuiWindow {
+class ItemTrackerSettingsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
@@ -40,7 +40,7 @@ class ItemTrackerSettingsWindow : public Ship::GuiWindow {
void UpdateElement() override{};
};
-class ItemTrackerWindow : public Ship::GuiWindow {
+class ItemTrackerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void Draw() override;
diff --git a/soh/soh/Enhancements/randomizer/randomizer_settings_window.h b/soh/soh/Enhancements/randomizer/randomizer_settings_window.h
index 034101aba..bf1a2a740 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_settings_window.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_settings_window.h
@@ -6,7 +6,7 @@ namespace Rando {
class Settings;
}
-class RandomizerSettingsWindow : public Ship::GuiWindow {
+class RandomizerSettingsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/Enhancements/timesplits/TimeSplits.h b/soh/soh/Enhancements/timesplits/TimeSplits.h
index ba5f9cb80..8644d6010 100644
--- a/soh/soh/Enhancements/timesplits/TimeSplits.h
+++ b/soh/soh/Enhancements/timesplits/TimeSplits.h
@@ -17,7 +17,7 @@ extern "C" {
#include
#ifdef __cplusplus
-class TimeSplitWindow : public Ship::GuiWindow {
+class TimeSplitWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
@@ -39,7 +39,7 @@ typedef enum SplitStatus {
SPLIT_STATUS_ACTIVE,
SPLIT_STATUS_INACTIVE,
SPLIT_STATUS_COLLECTED,
- SPLIT_STATUS_SKIPPED
+ SPLIT_STATUS_SKIPPED,
} SplitStatus;
typedef enum SplitType {
diff --git a/soh/soh/Enhancements/tts/tts.cpp b/soh/soh/Enhancements/tts/tts.cpp
index 77df9983d..b8a43453f 100644
--- a/soh/soh/Enhancements/tts/tts.cpp
+++ b/soh/soh/Enhancements/tts/tts.cpp
@@ -95,10 +95,8 @@ const char* GetLanguageCode() {
switch (CVarGetInteger(CVAR_SETTING("Languages"), 0)) {
case LANGUAGE_FRA:
return "fr-FR";
- break;
case LANGUAGE_GER:
return "de-DE";
- break;
}
return "en-US";
@@ -1148,6 +1146,44 @@ void RegisterOnSetGameLanguageHook() {
GameInteractor::Instance->RegisterGameHook([]() { InitTTSBank(); });
}
+void RegisterOnSetDoAction() {
+ GameInteractor::Instance->RegisterGameHook([](uint16_t action) {
+ if (CVarGetInteger(CVAR_SETTING("A11yTTS"), 0)) {
+ uint8_t language = CVarGetInteger(CVAR_SETTING("Languages"), 0);
+ const char* text;
+ switch (action) {
+ case DO_ACTION_CHECK:
+ text = language == LANGUAGE_FRA ? "voir" : language == LANGUAGE_GER ? "lesen" : "check";
+ break;
+ case DO_ACTION_ENTER:
+ text = language == LANGUAGE_FRA ? "entrer" : language == LANGUAGE_GER ? "kriechen" : "enter";
+ break;
+ case DO_ACTION_OPEN:
+ text = language == LANGUAGE_FRA ? "ouvrir" : language == LANGUAGE_GER ? "öffnen" : "open";
+ break;
+ case DO_ACTION_CLIMB:
+ text = language == LANGUAGE_FRA ? "monter" : language == LANGUAGE_GER ? "hinauf" : "climb";
+ break;
+ case DO_ACTION_SPEAK:
+ text = language == LANGUAGE_FRA ? "parler" : language == LANGUAGE_GER ? "reden" : "speak";
+ break;
+ case DO_ACTION_GRAB:
+ text = language == LANGUAGE_FRA ? "action" : language == LANGUAGE_GER ? "aktion" : "grab";
+ break;
+ case DO_ACTION_DOWN: {
+ Player* player = GET_PLAYER(gPlayState);
+ if (player == NULL || !(player->stateFlags1 & PLAYER_STATE1_ON_HORSE))
+ return;
+ text = language == LANGUAGE_FRA ? "descendre" : language == LANGUAGE_GER ? "herab" : "down";
+ } break;
+ default:
+ return;
+ }
+ SpeechSynthesizer::Instance->Speak(text, GetLanguageCode());
+ }
+ });
+}
+
void RegisterTTSModHooks() {
RegisterOnSetGameLanguageHook();
RegisterOnDialogMessageHook();
@@ -1156,6 +1192,7 @@ void RegisterTTSModHooks() {
RegisterOnInterfaceUpdateHook();
RegisterOnKaleidoscopeUpdateHook();
RegisterOnUpdateMainMenuSelection();
+ RegisterOnSetDoAction();
}
void RegisterTTS() {
diff --git a/soh/soh/Notification/Notification.h b/soh/soh/Notification/Notification.h
index bc3a93b9b..7eb4bb2d7 100644
--- a/soh/soh/Notification/Notification.h
+++ b/soh/soh/Notification/Notification.h
@@ -19,7 +19,7 @@ struct Options {
float remainingTime = 0.0f; // Seconds
};
-class Window : public Ship::GuiWindow {
+class Window final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index 72030657e..87cb361e1 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -1741,20 +1741,6 @@ std::wstring StringToU16(const std::string& s) {
return utf16;
}
-int CopyStringToCharBuffer(const std::string& inputStr, char* buffer, const int maxBufferSize) {
- if (!inputStr.empty()) {
- // Prevent potential horrible overflow due to implicit conversion of maxBufferSize to an unsigned. Prevents
- // negatives.
- memset(buffer, 0, std::max(0, maxBufferSize));
- // Gaurentee that this value will be greater than 0, regardless of passed variables.
- const int copiedCharLen = std::min(std::max(0, maxBufferSize - 1), inputStr.length());
- memcpy(buffer, inputStr.c_str(), copiedCharLen);
- return copiedCharLen;
- }
-
- return 0;
-}
-
extern "C" void OTRGfxPrint(const char* str, void* printer, void (*printImpl)(void*, char)) {
const std::vector hira1 = {
u'を', u'ぁ', u'ぃ', u'ぅ', u'ぇ', u'ぉ', u'ゃ', u'ゅ', u'ょ', u'っ', u'-', u'あ', u'い',
@@ -1986,7 +1972,7 @@ extern "C" void* getN64WeirdFrame(s32 i) {
return &weirdFrameBytes[i + sizeof(n64WeirdFrames)];
}
-extern "C" int GetEquipNowMessage(char* buffer, char* src, const int maxBufferSize) {
+extern "C" size_t GetEquipNowMessage(char* buffer, char* src, const size_t maxBufferSize) {
CustomMessage customMessage("\x04\x1A\x08"
"Would you like to equip it now?"
"\x09&&"
@@ -2027,7 +2013,7 @@ extern "C" int GetEquipNowMessage(char* buffer, char* src, const int maxBufferSi
if (!str.empty()) {
memset(buffer, 0, maxBufferSize);
- const int copiedCharLen = std::min(maxBufferSize - 1, str.length());
+ const size_t copiedCharLen = std::min(maxBufferSize - 1, str.length());
memcpy(buffer, str.c_str(), copiedCharLen);
return copiedCharLen;
}
@@ -2169,7 +2155,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
uint16_t textId = msgCtx->textId;
Font* font = &msgCtx->font;
char* buffer = font->msgBuf;
- const int maxBufferSize = sizeof(font->msgBuf);
+ const size_t maxBufferSize = sizeof(font->msgBuf);
CustomMessage messageEntry;
s16 actorParams = 0;
if (IS_RANDO) {
@@ -2480,14 +2466,14 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
switch (gSaveContext.language) {
case LANGUAGE_FRA:
return msgCtx->msgLength = font->msgLength =
- CopyStringToCharBuffer(messageEntry.GetFrench(MF_RAW), buffer, maxBufferSize);
+ SohUtils::CopyStringToCharBuffer(buffer, messageEntry.GetFrench(MF_RAW), maxBufferSize);
case LANGUAGE_GER:
return msgCtx->msgLength = font->msgLength =
- CopyStringToCharBuffer(messageEntry.GetGerman(MF_RAW), buffer, maxBufferSize);
+ SohUtils::CopyStringToCharBuffer(buffer, messageEntry.GetGerman(MF_RAW), maxBufferSize);
case LANGUAGE_ENG:
default:
return msgCtx->msgLength = font->msgLength =
- CopyStringToCharBuffer(messageEntry.GetEnglish(MF_RAW), buffer, maxBufferSize);
+ SohUtils::CopyStringToCharBuffer(buffer, messageEntry.GetEnglish(MF_RAW), maxBufferSize);
}
return false;
}
diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h
index b14d322d2..6f83d78ad 100644
--- a/soh/soh/OTRGlobals.h
+++ b/soh/soh/OTRGlobals.h
@@ -121,7 +121,7 @@ int Controller_ShouldRumble(size_t slot);
void Controller_BlockGameInput();
void Controller_UnblockGameInput();
void* getN64WeirdFrame(s32 i);
-int GetEquipNowMessage(char* buffer, char* src, const int maxBufferSize);
+size_t GetEquipNowMessage(char* buffer, char* src, const size_t maxBufferSize);
u32 SpoilerFileExists(const char* spoilerFileName);
Sprite* GetSeedTexture(uint8_t index);
uint8_t GetSeedIconIndex(uint8_t index);
diff --git a/soh/soh/SohGui/Menu.cpp b/soh/soh/SohGui/Menu.cpp
index a1321a6f6..87c362496 100644
--- a/soh/soh/SohGui/Menu.cpp
+++ b/soh/soh/SohGui/Menu.cpp
@@ -65,6 +65,8 @@ uint32_t GetVectorIndexOf(std::vector& vector, std::string value) {
return std::distance(vector.begin(), std::find(vector.begin(), vector.end(), value));
}
+static bool raceDisableActive = false;
+
void Menu::InsertSidebarSearch() {
menuEntries["Settings"].sidebars.emplace("Search", searchSidebarEntry);
uint32_t curIndex = 0;
@@ -228,7 +230,7 @@ std::unordered_map& Menu::GetDisabledMap() {
}
void Menu::MenuDrawItem(WidgetInfo& widget, uint32_t width, UIWidgets::Colors menuThemeIndex) {
- disabledTempTooltip = "This setting is disabled because: \n\n";
+ disabledTempTooltip = "This setting is disabled because: \n";
disabledValue = false;
disabledTooltip = " ";
@@ -241,11 +243,16 @@ void Menu::MenuDrawItem(WidgetInfo& widget, uint32_t width, UIWidgets::Colors me
if (!widget.activeDisables.empty()) {
widget.options->disabled = true;
for (auto option : widget.activeDisables) {
- disabledTempTooltip += std::string("- ") + disabledMap.at(option).reason + std::string("\n");
+ disabledTempTooltip += std::string("\n- ") + disabledMap.at(option).reason;
}
widget.options->disabledTooltip = disabledTempTooltip.c_str();
}
}
+ if (widget.raceDisable && raceDisableActive) {
+ widget.options->disabled = true;
+ disabledTempTooltip += std::string("\n- Race Lockout Active");
+ widget.options->disabledTooltip = disabledTempTooltip.c_str();
+ }
if (widget.sameLine) {
ImGui::SameLine();
@@ -492,6 +499,8 @@ void Menu::DrawElement() {
info.active = info.evaluation(info);
}
+ raceDisableActive = CVarGetInteger(CVAR_SETTING("DisableChanges"), 0);
+
windowHeight = ImGui::GetMainViewport()->WorkSize.y;
windowWidth = ImGui::GetMainViewport()->WorkSize.x;
auto windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
diff --git a/soh/soh/SohGui/MenuTypes.h b/soh/soh/SohGui/MenuTypes.h
index 162f80ac5..de78e8961 100644
--- a/soh/soh/SohGui/MenuTypes.h
+++ b/soh/soh/SohGui/MenuTypes.h
@@ -109,6 +109,7 @@ struct WidgetInfo {
const char* windowName = "";
bool isHidden = false;
bool sameLine = false;
+ bool raceDisable = true;
WidgetInfo& CVar(const char* cVar_) {
cVar = cVar_;
@@ -191,6 +192,10 @@ struct WidgetInfo {
customFunction = customFunction_;
return *this;
}
+ WidgetInfo& RaceDisable(bool disable) {
+ raceDisable = disable;
+ return *this;
+ }
};
struct WidgetPath {
diff --git a/soh/soh/SohGui/ResolutionEditor.cpp b/soh/soh/SohGui/ResolutionEditor.cpp
index 298e2c470..d33a7b43c 100644
--- a/soh/soh/SohGui/ResolutionEditor.cpp
+++ b/soh/soh/SohGui/ResolutionEditor.cpp
@@ -371,29 +371,37 @@ void RegisterResolutionWidgets() {
WidgetPath path = { "Settings", "Graphics", SECTION_COLUMN_2 };
// Resolution visualiser
- mSohMenu->AddWidget(path, "Viewport dimensions: {} x {}", WIDGET_TEXT).PreFunc([](WidgetInfo& info) {
- info.name = fmt::format("Viewport dimensions: {} x {}", gfx_current_game_window_viewport.width,
- gfx_current_game_window_viewport.height);
- });
- mSohMenu->AddWidget(path, "Internal resolution: {} x {}", WIDGET_TEXT).PreFunc([](WidgetInfo& info) {
- info.name =
- fmt::format("Internal resolution: {} x {}", gfx_current_dimensions.width, gfx_current_dimensions.height);
- });
+ mSohMenu->AddWidget(path, "Viewport dimensions: {} x {}", WIDGET_TEXT)
+ .RaceDisable(false)
+ .PreFunc([](WidgetInfo& info) {
+ info.name = fmt::format("Viewport dimensions: {} x {}", gfx_current_game_window_viewport.width,
+ gfx_current_game_window_viewport.height);
+ });
+ mSohMenu->AddWidget(path, "Internal resolution: {} x {}", WIDGET_TEXT)
+ .RaceDisable(false)
+ .PreFunc([](WidgetInfo& info) {
+ info.name = fmt::format("Internal resolution: {} x {}", gfx_current_dimensions.width,
+ gfx_current_dimensions.height);
+ });
// Activator
mSohMenu->AddWidget(path, "Enable advanced settings.", WIDGET_CVAR_CHECKBOX)
- .CVar(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled");
+ .CVar(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled")
+ .RaceDisable(false);
// Error/Warning display
mSohMenu
->AddWidget(path, ICON_FA_EXCLAMATION_TRIANGLE " Significant frame rate (FPS) drops may be occuring.",
WIDGET_TEXT)
+ .RaceDisable(false)
.PreFunc(
[](WidgetInfo& info) { info.isHidden = !(!CVarGetInteger(CVAR_LOW_RES_MODE, 0) && IsDroppingFrames()); })
.Options(TextOptions().Color(Colors::Orange));
mSohMenu->AddWidget(path, ICON_FA_QUESTION_CIRCLE " \"N64 Mode\" is overriding these settings.", WIDGET_TEXT)
+ .RaceDisable(false)
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_LOW_RES_MODE, 0); })
.Options(TextOptions().Color(Colors::LightBlue));
mSohMenu->AddWidget(path, "Click to disable N64 mode", WIDGET_BUTTON)
+ .RaceDisable(false)
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_LOW_RES_MODE, 0); })
.Callback([](WidgetInfo& info) {
CVarSetInteger(CVAR_LOW_RES_MODE, 0);
@@ -401,17 +409,18 @@ void RegisterResolutionWidgets() {
});
// Aspect Ratio
- mSohMenu->AddWidget(path, "AspectSep", WIDGET_SEPARATOR).PreFunc([](WidgetInfo& info) {
+ mSohMenu->AddWidget(path, "AspectSep", WIDGET_SEPARATOR).RaceDisable(false).PreFunc([](WidgetInfo& info) {
if (mSohMenu->GetDisabledMap().at(DISABLE_FOR_ADVANCED_RESOLUTION_OFF).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_OFF);
}
});
- mSohMenu->AddWidget(path, "Force aspect ratio:", WIDGET_TEXT).PreFunc([](WidgetInfo& info) {
+ mSohMenu->AddWidget(path, "Force aspect ratio:", WIDGET_TEXT).RaceDisable(false).PreFunc([](WidgetInfo& info) {
if (mSohMenu->GetDisabledMap().at(DISABLE_FOR_ADVANCED_RESOLUTION_OFF).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_OFF);
}
});
mSohMenu->AddWidget(path, "(Select \"Off\" to disable.)", WIDGET_TEXT)
+ .RaceDisable(false)
.PreFunc([](WidgetInfo& info) {
if (mSohMenu->GetDisabledMap().at(DISABLE_FOR_ADVANCED_RESOLUTION_OFF).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_OFF);
@@ -422,6 +431,7 @@ void RegisterResolutionWidgets() {
// Presets
mSohMenu->AddWidget(path, "Aspect Ratio", WIDGET_COMBOBOX)
.ValuePointer(&item_aspectRatio)
+ .RaceDisable(false)
.PreFunc([](WidgetInfo& info) {
if (mSohMenu->GetDisabledMap().at(DISABLE_FOR_ADVANCED_RESOLUTION_OFF).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_OFF);
@@ -443,44 +453,49 @@ void RegisterResolutionWidgets() {
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
})
.Options(ComboboxOptions().ComboMap(aspectRatioPresetLabels));
- mSohMenu->AddWidget(path, "AspectRatioCustom", WIDGET_CUSTOM).CustomFunction([](WidgetInfo& info) {
- // Hide aspect ratio input fields if using one of the presets.
- if (item_aspectRatio == default_aspectRatio && !showHorizontalResField) {
- // 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::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::LabelPositions::Near)
- .ComponentAlignment(UIWidgets::ComponentAlignments::Right));
- if (input_X || input_Y) {
- item_aspectRatio = default_aspectRatio;
- update[UPDATE_aspectRatioX] = true;
- update[UPDATE_aspectRatioY] = true;
+ mSohMenu->AddWidget(path, "AspectRatioCustom", WIDGET_CUSTOM)
+ .RaceDisable(false)
+ .CustomFunction([](WidgetInfo& info) {
+ // Hide aspect ratio input fields if using one of the presets.
+ if (item_aspectRatio == default_aspectRatio && !showHorizontalResField) {
+ // 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::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::LabelPositions::Near)
+ .ComponentAlignment(UIWidgets::ComponentAlignments::Right));
+ if (input_X || input_Y) {
+ item_aspectRatio = default_aspectRatio;
+ update[UPDATE_aspectRatioX] = true;
+ update[UPDATE_aspectRatioY] = true;
+ }
+ } else if (showHorizontalResField) { // Show calculated aspect ratio
+ if (item_aspectRatio) {
+ ImGui::Dummy({ 0, 2 });
+ const float resolvedAspectRatio =
+ (float)gfx_current_dimensions.width / gfx_current_dimensions.height;
+ ImGui::Text("Aspect ratio: %.2f:1", resolvedAspectRatio);
+ }
}
- } else if (showHorizontalResField) { // Show calculated aspect ratio
- if (item_aspectRatio) {
- ImGui::Dummy({ 0, 2 });
- const float resolvedAspectRatio = (float)gfx_current_dimensions.width / gfx_current_dimensions.height;
- ImGui::Text("Aspect ratio: %.2f:1", resolvedAspectRatio);
- }
- }
- });
- mSohMenu->AddWidget(path, "MoreResolutionSettings", WIDGET_CUSTOM).CustomFunction(ResolutionCustomWidget);
+ });
+ mSohMenu->AddWidget(path, "MoreResolutionSettings", WIDGET_CUSTOM)
+ .CustomFunction(ResolutionCustomWidget)
+ .RaceDisable(false);
}
void UpdateResolutionVars() {
diff --git a/soh/soh/SohGui/SohMenuDevTools.cpp b/soh/soh/SohGui/SohMenuDevTools.cpp
index 0588ae508..91d456c95 100644
--- a/soh/soh/SohGui/SohMenuDevTools.cpp
+++ b/soh/soh/SohGui/SohMenuDevTools.cpp
@@ -93,6 +93,7 @@ void SohMenu::AddMenuDevTools() {
AddSidebarEntry("Dev Tools", path.sidebarName, 1);
AddWidget(path, "Popout Stats Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("SohStats"))
+ .RaceDisable(false)
.WindowName("Stats##Soh")
.Options(WindowButtonOptions().Tooltip("Enables the separate Stats Window."));
diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp
index 786183882..0b78892d4 100644
--- a/soh/soh/SohGui/SohMenuEnhancements.cpp
+++ b/soh/soh/SohGui/SohMenuEnhancements.cpp
@@ -85,6 +85,7 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Saving", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Autosave", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("Autosave"))
+ .RaceDisable(false)
.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, "
@@ -168,9 +169,11 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Controls", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Answer Navi Prompt with L Button", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("NaviOnL"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Removes the Input Requirement on Text boxes after defeating Ganon, allowing the Credits "
"Sequence to continue to progress."));
@@ -202,14 +205,20 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Item Count Messages", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Gold Skulltula Tokens", WIDGET_CVAR_CHECKBOX)
- .CVar(CVAR_ENHANCEMENT("InjectItemCounts.GoldSkulltula"));
- AddWidget(path, "Pieces of Heart", WIDGET_CVAR_CHECKBOX).CVar(CVAR_ENHANCEMENT("InjectItemCounts.HeartPiece"));
- AddWidget(path, "Heart Containers", WIDGET_CVAR_CHECKBOX).CVar(CVAR_ENHANCEMENT("InjectItemCounts.HeartContainer"));
+ .CVar(CVAR_ENHANCEMENT("InjectItemCounts.GoldSkulltula"))
+ .RaceDisable(false);
+ AddWidget(path, "Pieces of Heart", WIDGET_CVAR_CHECKBOX)
+ .CVar(CVAR_ENHANCEMENT("InjectItemCounts.HeartPiece"))
+ .RaceDisable(false);
+ AddWidget(path, "Heart Containers", WIDGET_CVAR_CHECKBOX)
+ .CVar(CVAR_ENHANCEMENT("InjectItemCounts.HeartContainer"))
+ .RaceDisable(false);
path.column = SECTION_COLUMN_3;
AddWidget(path, "Misc", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Disable Crit Wiggle", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("DisableCritWiggle"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Disable Random Camera Wiggle at Low Health."));
AddWidget(path, "Better Owl", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("BetterOwl"))
@@ -430,27 +439,32 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Mods", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Use Alternate Assets", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("AltAssets"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Toggle between standard assets and alternate assets. Usually mods will indicate if "
"this setting has to be used or not."));
AddWidget(path, "Disable Bomb Billboarding", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("DisableBombBillboarding"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Disables bombs always rotating to face the camera. To be used in conjunction with mods that want to "
"replace bombs with 3D objects."));
AddWidget(path, "Disable Grotto Fixed Rotation", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("DisableGrottoRotation"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"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"))
+ .RaceDisable(false)
.Options(IntSliderOptions().Min(4).Max(6).DefaultValue(6).Tooltip(
"Space between text characters (useful for HD font textures)."));
AddWidget(path, "Models & Textures", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Disable LOD", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("DisableLOD"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"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)
@@ -458,18 +472,22 @@ void SohMenu::AddMenuEnhancements() {
.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"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Replaces most 2D items and projectiles on the overworld with their equivalent 3D models."));
AddWidget(path, "Animated Link in Pause Menu", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("PauseMenuAnimatedLink"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Turns the Static Image of Link in the Pause Menu's Equipment Subscreen "
"into a model cycling through his idle animations."));
AddWidget(path, "Show Age-Dependent Equipment", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) { UpdatePatchHand(); })
.Options(CheckboxOptions().Tooltip("Makes all equipment visible, regardless of age."));
AddWidget(path, "Scale Adult Equipment as Child", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("ScaleAdultEquipmentAsChild"))
+ .RaceDisable(false)
.PreFunc([](WidgetInfo& info) {
info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"), 0) == 0;
})
@@ -478,11 +496,14 @@ void SohMenu::AddMenuEnhancements() {
"not work properly with some mods."));
AddWidget(path, "Show Gauntlets in First Person", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("FirstPersonGauntlets"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Renders Gauntlets when using the Bow and Hookshot like in OoT3D."));
AddWidget(path, "Show Chains on Both Sides of Locked Doors", WIDGET_CVAR_CHECKBOX)
- .CVar(CVAR_ENHANCEMENT("ShowDoorLocksOnBothSides"));
+ .CVar(CVAR_ENHANCEMENT("ShowDoorLocksOnBothSides"))
+ .RaceDisable(false);
AddWidget(path, "Color Temple of Time's Medallions", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("ToTMedallionsColors"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) { PatchToTMedallions(); })
.Options(CheckboxOptions().Tooltip(
"When Medallions are collected, the Medallion imprints around the Master Sword Pedestal in the Temple "
@@ -500,15 +521,18 @@ void SohMenu::AddMenuEnhancements() {
"in Hot/Underwater conditions."));
AddWidget(path, "Remember Minimap State Between Areas", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("RememberMapToggleState"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
- "Preverse the minimap visibility state when going between areas rather than default it to \"on\" "
+ "Preserve 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"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.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"))
@@ -517,26 +541,32 @@ void SohMenu::AddMenuEnhancements() {
"UI based line-ups do not work outside of 4:3"));
AddWidget(path, "Disable Black Bar Letterboxes", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("DisableBlackBars"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip("The skybox in the background of the File Select screen will go through the "
"day and night cycle over time."));
@@ -544,14 +574,17 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Misc.", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "N64 Mode", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_LOW_RES_MODE)
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Sets the aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution."));
AddWidget(path, "Remove Spin Attack Darkness", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("RemoveSpinAttackDarkness"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Remove the Darkness that appears when charging a Spin Attack."));
- AddWidget(path, "Draw Distance", WIDGET_SEPARATOR_TEXT);
+ AddWidget(path, "Draw Distance", WIDGET_SEPARATOR_TEXT).RaceDisable(false);
AddWidget(path, "Increase Actor Draw Distance: %dx", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_ENHANCEMENT("DisableDrawDistance"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) <= 1) {
CVarSetInteger(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), 0);
@@ -561,6 +594,7 @@ void SohMenu::AddMenuEnhancements() {
"Increases the range in which Actors/Objects are drawn."));
AddWidget(path, "Kokiri Draw Distance", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"))
+ .RaceDisable(false)
.PreFunc(
[](WidgetInfo& info) { info.isHidden = CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) <= 1; })
.Options(CheckboxOptions().Tooltip(
@@ -860,7 +894,7 @@ void SohMenu::AddMenuEnhancements() {
[](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"))
+ .CVar(CVAR_ENHANCEMENT("FixBrokenGiantsKnife"))
.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.";
@@ -896,22 +930,27 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Graphical Fixes", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Fix L&R Pause Menu", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("FixMenuLR"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.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-Handed Idle Animations", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("TwoHandedIdle"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Prevent the Gerudo Warrior's clothes changing color when changing Link's tunic or "
"using bombs in front of her."));
@@ -922,15 +961,18 @@ void SohMenu::AddMenuEnhancements() {
"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"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."));
AddWidget(path, "Fix Hand Holding Hammer", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("FixHammerHand"))
+ .RaceDisable(false)
.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"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
if (gPlayState != NULL) {
UpdateDirtPathFixState(gPlayState->sceneNum);
@@ -948,6 +990,7 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Audio Fixes", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Fix Missing Jingle after 5 Silver Rupees", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("SilverRupeeJingleExtend"))
+ .RaceDisable(false)
.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."));
@@ -955,10 +998,12 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Desync Fixes", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Fix Darunia Dancing too Fast", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("FixDaruniaDanceSpeed"))
+ .RaceDisable(false)
.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 (PAL)", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("CreditsFix"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Extend certain credits scenes so the music lines up properly with the visuals. (PAL only)"));
@@ -966,6 +1011,7 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Graphical Restorations", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Red Ganon Blood", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("RedGanonBlood"))
+ .RaceDisable(false)
.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)
@@ -974,6 +1020,7 @@ void SohMenu::AddMenuEnhancements() {
"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("PulsateBossIcon"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Restores an unfinished feature to pulsate the boss room icon when you are in the boss room."));
@@ -1657,6 +1704,7 @@ void SohMenu::AddMenuEnhancements() {
path.column = SECTION_COLUMN_1;
AddWidget(path, "Popout Cosmetics Editor Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("CosmeticsEditor"))
+ .RaceDisable(false)
.WindowName("Cosmetics Editor")
.Options(WindowButtonOptions().Tooltip("Enables the separate Cosmetics Editor Window."));
@@ -1665,6 +1713,7 @@ void SohMenu::AddMenuEnhancements() {
AddSidebarEntry("Enhancements", path.sidebarName, 1);
AddWidget(path, "Popout Audio Editor Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("AudioEditor"))
+ .RaceDisable(false)
.WindowName("Audio Editor")
.Options(WindowButtonOptions().Tooltip("Enables the separate Audio Editor Window."));
@@ -1673,6 +1722,7 @@ void SohMenu::AddMenuEnhancements() {
AddSidebarEntry("Enhancements", path.sidebarName, 2);
AddWidget(path, "Popout Gameplay Stats Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("GameplayStats"))
+ .RaceDisable(false)
.WindowName("Gameplay Stats")
.Options(WindowButtonOptions().Tooltip("Enables the separate Gameplay Stats Window."));
@@ -1681,6 +1731,7 @@ void SohMenu::AddMenuEnhancements() {
AddSidebarEntry("Enhancements", path.sidebarName, 1);
AddWidget(path, "Popout Time Splits Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("TimeSplits"))
+ .RaceDisable(false)
.WindowName("Time Splits")
.Options(WindowButtonOptions().Tooltip("Enables the separate Time Splits Window."));
@@ -1689,19 +1740,23 @@ void SohMenu::AddMenuEnhancements() {
AddSidebarEntry("Enhancements", path.sidebarName, 3);
AddWidget(path, "Toggle Timers Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("TimeDisplayEnabled"))
+ .RaceDisable(false)
.WindowName("Additional Timers")
.Options(WindowButtonOptions().Tooltip("Enables the separate Additional Timers Window."));
AddWidget(path, "Font Scale: %.2fx", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_TIME_DISPLAY("FontScale"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) { TimeDisplayInitSettings(); })
.Options(FloatSliderOptions().Min(1.0f).Max(5.0f).DefaultValue(1.0f).Format("%.2fx"));
AddWidget(path, "Hide Background", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_TIME_DISPLAY("ShowWindowBG"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) { TimeDisplayInitSettings(); });
for (auto& timer : timeDisplayList) {
- AddWidget(path, timer.timeLabel, WIDGET_CVAR_CHECKBOX).CVar(timer.timeEnable).Callback([](WidgetInfo& info) {
- TimeDisplayUpdateDisplayOptions();
- });
+ AddWidget(path, timer.timeLabel, WIDGET_CVAR_CHECKBOX)
+ .RaceDisable(false)
+ .CVar(timer.timeEnable)
+ .Callback([](WidgetInfo& info) { TimeDisplayUpdateDisplayOptions(); });
}
}
diff --git a/soh/soh/SohGui/SohMenuNetwork.cpp b/soh/soh/SohGui/SohMenuNetwork.cpp
index 1c67ce28d..637c78285 100644
--- a/soh/soh/SohGui/SohMenuNetwork.cpp
+++ b/soh/soh/SohGui/SohMenuNetwork.cpp
@@ -39,7 +39,7 @@ void SohMenu::AddMenuNetwork() {
})
.Options(ButtonOptions().Tooltip("https://github.com/HarbourMasters/sail"));
AddWidget(path, "Host & Port", WIDGET_CUSTOM).CustomFunction([](WidgetInfo& info) {
- ImGui::BeginDisabled(Sail::Instance->isEnabled);
+ ImGui::BeginDisabled(Sail::Instance->isEnabled || CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
ImGui::Text("%s", info.name.c_str());
CVarInputString("##HostSail", CVAR_REMOTE_SAIL("Host"),
InputOptions()
@@ -111,7 +111,7 @@ void SohMenu::AddMenuNetwork() {
})
.Options(ButtonOptions().Tooltip("https://crowdcontrol.live"));
AddWidget(path, "Host & Port", WIDGET_CUSTOM).CustomFunction([](WidgetInfo& info) {
- ImGui::BeginDisabled(CrowdControl::Instance->isEnabled);
+ ImGui::BeginDisabled(CrowdControl::Instance->isEnabled || CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
ImGui::Text("%s", info.name.c_str());
CVarInputString("##HostCrowdControl", CVAR_REMOTE_CROWD_CONTROL("Host"),
InputOptions()
diff --git a/soh/soh/SohGui/SohMenuRandomizer.cpp b/soh/soh/SohGui/SohMenuRandomizer.cpp
index 9c95431e8..8f4e6e43b 100644
--- a/soh/soh/SohGui/SohMenuRandomizer.cpp
+++ b/soh/soh/SohGui/SohMenuRandomizer.cpp
@@ -29,6 +29,7 @@ void SohMenu::AddMenuRandomizer() {
.DefaultValue(true));
AddWidget(path, "Random Rupee Names", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("RandomizeRupeeNames"))
+ .RaceDisable(false)
.Options(CheckboxOptions()
.Tooltip("When obtaining Rupees, randomize what the Rupee is called in the textbox.")
.DefaultValue(true));
@@ -60,6 +61,7 @@ void SohMenu::AddMenuRandomizer() {
.DefaultValue(true));
AddWidget(path, "Quest Item Fanfares", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("QuestItemFanfares"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Play unique fanfares when obtaining quest items (medallions/stones/songs). Note that these "
"fanfares can be longer than usual."));
@@ -71,6 +73,7 @@ void SohMenu::AddMenuRandomizer() {
"so you never know what you're getting."));
AddWidget(path, "Simpler Boss Soul Models", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("SimplerBossSoulModels"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"When shuffling boss souls, they'll appear as a simpler model instead of showing the boss' models."
"This might make boss souls more distinguishable from a distance, and can help with performance."));
@@ -93,6 +96,7 @@ void SohMenu::AddMenuRandomizer() {
AddSidebarEntry("Randomizer", path.sidebarName, 1);
AddWidget(path, "Popout Plandomizer Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("PlandomizerEditor"))
+ .RaceDisable(false)
.WindowName("Plandomizer Editor")
.Options(WindowButtonOptions().Tooltip("Enables the separate Randomizer Settings Window."));
@@ -103,12 +107,14 @@ void SohMenu::AddMenuRandomizer() {
AddWidget(path, "Item Tracker", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Item Tracker", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ItemTracker"))
+ .RaceDisable(false)
.WindowName("Item Tracker")
.Options(WindowButtonOptions().Tooltip("Toggles the Item Tracker.").EmbedWindow(false));
AddWidget(path, "Item Tracker Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Item Tracker Settings", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ItemTrackerSettings"))
+ .RaceDisable(false)
.WindowName("Item Tracker Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Item Tracker Settings Window."));
@@ -119,12 +125,14 @@ void SohMenu::AddMenuRandomizer() {
AddWidget(path, "Entrance Tracker", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Entrance Tracker", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("EntranceTracker"))
+ .RaceDisable(false)
.WindowName("Entrance Tracker")
.Options(WindowButtonOptions().Tooltip("Toggles the Entrance Tracker.").EmbedWindow(false));
AddWidget(path, "Entrance Tracker Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Entrance Tracker Settings", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("EntranceTrackerSettings"))
+ .RaceDisable(false)
.WindowName("Entrance Tracker Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Entrance Tracker Settings Window."));
@@ -135,12 +143,14 @@ void SohMenu::AddMenuRandomizer() {
AddWidget(path, "Check Tracker", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Check Tracker", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("CheckTracker"))
+ .RaceDisable(false)
.WindowName("Check Tracker")
.Options(WindowButtonOptions().Tooltip("Toggles the Check Tracker.").EmbedWindow(false));
AddWidget(path, "Check Tracker Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Check Tracker Settings", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("CheckTrackerSettings"))
+ .RaceDisable(false)
.WindowName("Check Tracker Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Check Tracker Settings Window."));
}
diff --git a/soh/soh/SohGui/SohMenuSettings.cpp b/soh/soh/SohGui/SohMenuSettings.cpp
index 2b1f77799..909c647bd 100644
--- a/soh/soh/SohGui/SohMenuSettings.cpp
+++ b/soh/soh/SohGui/SohMenuSettings.cpp
@@ -95,6 +95,7 @@ void SohMenu::AddMenuSettings() {
AddWidget(path, "Menu Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Menu Theme", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_SETTING("Menu.Theme"))
+ .RaceDisable(false)
.Options(ComboboxOptions()
.Tooltip("Changes the Theme of the Menu Widgets.")
.ComboMap(menuThemeOptions)
@@ -102,18 +103,21 @@ void SohMenu::AddMenuSettings() {
#if not defined(__SWITCH__) and not defined(__WIIU__)
AddWidget(path, "Menu Controller Navigation", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_IMGUI_CONTROLLER_NAV)
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"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, "Menu Background Opacity", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_SETTING("Menu.BackgroundOpacity"))
+ .RaceDisable(false)
.Options(FloatSliderOptions().DefaultValue(0.85f).IsPercentage().Tooltip(
"Sets the opacity of the background of the port menu."));
AddWidget(path, "General Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Cursor Always Visible", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("CursorVisibility"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetWindow()->SetForceCursorVisibility(
CVarGetInteger(CVAR_SETTING("CursorVisibility"), 0));
@@ -122,6 +126,7 @@ void SohMenu::AddMenuSettings() {
#endif
AddWidget(path, "Search In Sidebar", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("Menu.SidebarSearch"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
if (CVarGetInteger(CVAR_SETTING("Menu.SidebarSearch"), 0)) {
mSohMenu->InsertSidebarSearch();
@@ -133,13 +138,16 @@ void SohMenu::AddMenuSettings() {
"Displays the Search menu as a sidebar entry in Settings instead of in the header."));
AddWidget(path, "Search Input Autofocus", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("Menu.SearchAutofocus"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip(
"Search input box gets autofocus when visible. Does not affect using other widgets."));
AddWidget(path, "Alt Assets Tab hotkey", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("Mods.AlternateAssetsHotkey"))
+ .RaceDisable(false)
.Options(
CheckboxOptions().Tooltip("Allows pressing the Tab key to toggle alternate assets").DefaultValue(true));
AddWidget(path, "Open App Files Folder", WIDGET_BUTTON)
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
std::string filesPath = Ship::Context::GetInstance()->GetAppDirectoryPath();
SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str());
@@ -149,6 +157,7 @@ void SohMenu::AddMenuSettings() {
AddWidget(path, "Boot", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Boot Sequence", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_SETTING("BootSequence"))
+ .RaceDisable(false)
.Options(ComboboxOptions()
.DefaultIndex(BOOTSEQUENCE_DEFAULT)
.LabelPosition(LabelPositions::Far)
@@ -160,9 +169,12 @@ void SohMenu::AddMenuSettings() {
"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, "Translate Title Screen", WIDGET_CVAR_CHECKBOX)
+ .CVar(CVAR_SETTING("TitleScreenTranslation"))
+ .RaceDisable(false);
AddWidget(path, "Language", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_SETTING("Languages"))
+ .RaceDisable(false)
.PreFunc([](WidgetInfo& info) {
auto options = std::static_pointer_cast(info.options);
SohMenu::UpdateLanguageMap(options->comboMap);
@@ -176,14 +188,17 @@ void SohMenu::AddMenuSettings() {
#if defined(_WIN32) || defined(__APPLE__)
AddWidget(path, "Text to Speech", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("A11yTTS"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Enables text to speech for in game dialog"));
#endif
AddWidget(path, "Disable Idle Camera Re-Centering", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("A11yDisableIdleCam"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Disables the automatic re-centering of the camera when idle."));
AddWidget(path, "EXPERIMENTAL", WIDGET_SEPARATOR_TEXT).Options(TextOptions().Color(Colors::Orange));
AddWidget(path, "ImGui Menu Scaling", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_SETTING("ImGuiScale"))
+ .RaceDisable(false)
.Options(ComboboxOptions()
.ComboMap(imguiScaleOptions)
.Tooltip("Changes the scaling of the ImGui menu elements.")
@@ -214,9 +229,11 @@ void SohMenu::AddMenuSettings() {
AddWidget(path, "Master Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.Master"))
+ .RaceDisable(false)
.Options(IntSliderOptions().Min(0).Max(100).DefaultValue(40).ShowButtons(true).Format(""));
AddWidget(path, "Main Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.MainMusic"))
+ .RaceDisable(false)
.Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format(""))
.Callback([](WidgetInfo& info) {
Audio_SetGameVolume(SEQ_PLAYER_BGM_MAIN,
@@ -224,6 +241,7 @@ void SohMenu::AddMenuSettings() {
});
AddWidget(path, "Sub Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.SubMusic"))
+ .RaceDisable(false)
.Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format(""))
.Callback([](WidgetInfo& info) {
Audio_SetGameVolume(SEQ_PLAYER_BGM_SUB,
@@ -231,6 +249,7 @@ void SohMenu::AddMenuSettings() {
});
AddWidget(path, "Fanfare Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.Fanfare"))
+ .RaceDisable(false)
.Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format(""))
.Callback([](WidgetInfo& info) {
Audio_SetGameVolume(SEQ_PLAYER_FANFARE,
@@ -238,11 +257,12 @@ void SohMenu::AddMenuSettings() {
});
AddWidget(path, "Sound Effects Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.SFX"))
+ .RaceDisable(false)
.Options(IntSliderOptions().Min(0).Max(100).DefaultValue(100).ShowButtons(true).Format(""))
.Callback([](WidgetInfo& info) {
Audio_SetGameVolume(SEQ_PLAYER_SFX, ((float)CVarGetInteger(CVAR_SETTING("Volume.SFX"), 100) / 100.0f));
});
- AddWidget(path, "Audio API (Needs reload)", WIDGET_AUDIO_BACKEND);
+ AddWidget(path, "Audio API (Needs reload)", WIDGET_AUDIO_BACKEND).RaceDisable(false);
// Graphics Settings
static int32_t maxFps = 360;
@@ -253,10 +273,12 @@ void SohMenu::AddMenuSettings() {
AddSidebarEntry("Settings", "Graphics", 3);
AddWidget(path, "Graphics Options", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Fullscreen", WIDGET_BUTTON)
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) { Ship::Context::GetInstance()->GetWindow()->ToggleFullscreen(); })
.Options(ButtonOptions().Tooltip("Toggles Fullscreen On/Off."));
AddWidget(path, "Internal Resolution", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_INTERNAL_RESOLUTION)
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(
CVarGetFloat(CVAR_INTERNAL_RESOLUTION, 1));
@@ -281,6 +303,7 @@ void SohMenu::AddMenuSettings() {
#ifndef __WIIU__
AddWidget(path, "Anti-aliasing (MSAA)", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_MSAA_VALUE)
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger(CVAR_MSAA_VALUE, 1));
})
@@ -297,6 +320,7 @@ void SohMenu::AddMenuSettings() {
const char* fpsFormat = fps == 20 ? "Original (%d)" : "%d";
AddWidget(path, "Current FPS", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("InterpolationFPS"))
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
auto options = std::static_pointer_cast(info.options);
int32_t defaultValue = options->defaultValue;
@@ -313,28 +337,33 @@ void SohMenu::AddMenuSettings() {
.Options(IntSliderOptions().Tooltip(tooltip).Min(20).Max(maxFps).DefaultValue(20).Format(fpsFormat));
AddWidget(path, "Match Refresh Rate", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("MatchRefreshRate"))
+ .RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Matches interpolation value to the refresh rate of your display."));
- AddWidget(path, "Renderer API (Needs reload)", WIDGET_VIDEO_BACKEND);
+ AddWidget(path, "Renderer API (Needs reload)", WIDGET_VIDEO_BACKEND).RaceDisable(false);
AddWidget(path, "Enable Vsync", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_VSYNC_ENABLED)
+ .RaceDisable(false)
.PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NO_VSYNC).active; })
.Options(CheckboxOptions()
.Tooltip("Removes tearing, but clamps your max FPS to your displays refresh rate.")
.DefaultValue(true));
AddWidget(path, "Windowed Fullscreen", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SDL_WINDOWED_FULLSCREEN)
+ .RaceDisable(false)
.PreFunc([](WidgetInfo& info) {
info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NO_WINDOWED_FULLSCREEN).active;
})
.Options(CheckboxOptions().Tooltip("Enables Windowed Fullscreen Mode."));
AddWidget(path, "Allow multi-windows", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENABLE_MULTI_VIEWPORTS)
+ .RaceDisable(false)
.PreFunc(
[](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NO_MULTI_VIEWPORT).active; })
.Options(CheckboxOptions().Tooltip(
"Allows multiple windows to be opened at once. Requires a reload to take effect."));
AddWidget(path, "Texture Filter (Needs reload)", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_TEXTURE_FILTER)
+ .RaceDisable(false)
.Options(ComboboxOptions().Tooltip("Sets the applied Texture Filtering.").ComboMap(textureFilteringMap));
path.column = SECTION_COLUMN_2;
@@ -347,6 +376,7 @@ void SohMenu::AddMenuSettings() {
AddWidget(path, "Controller Bindings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Bindings Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ControllerConfiguration"))
+ .RaceDisable(false)
.WindowName("Configure Controller")
.Options(WindowButtonOptions().Tooltip("Enables the separate Bindings Window."));
@@ -356,12 +386,14 @@ void SohMenu::AddMenuSettings() {
AddWidget(path, "Input Viewer", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Input Viewer", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("InputViewer"))
+ .RaceDisable(false)
.WindowName("Input Viewer")
.Options(WindowButtonOptions().Tooltip("Toggles the Input Viewer.").EmbedWindow(false));
AddWidget(path, "Input Viewer Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Input Viewer Settings", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("InputViewerSettings"))
+ .RaceDisable(false)
.WindowName("Input Viewer Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Input Viewer Settings Window."));
@@ -371,12 +403,14 @@ void SohMenu::AddMenuSettings() {
AddSidebarEntry("Settings", path.sidebarName, 3);
AddWidget(path, "Position", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_SETTING("Notifications.Position"))
+ .RaceDisable(false)
.Options(ComboboxOptions()
.Tooltip("Which corner of the screen notifications appear in.")
.ComboMap(notificationPosition)
.DefaultIndex(3));
AddWidget(path, "Duration (seconds):", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_SETTING("Notifications.Duration"))
+ .RaceDisable(false)
.Options(FloatSliderOptions()
.Tooltip("How long notifications are displayed for.")
.Format("%.1f")
@@ -386,12 +420,14 @@ void SohMenu::AddMenuSettings() {
.DefaultValue(10.0f));
AddWidget(path, "Background Opacity", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_SETTING("Notifications.BgOpacity"))
+ .RaceDisable(false)
.Options(FloatSliderOptions()
.Tooltip("How opaque the background of notifications is.")
.DefaultValue(0.5f)
.IsPercentage());
AddWidget(path, "Size:", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_SETTING("Notifications.Size"))
+ .RaceDisable(false)
.Options(FloatSliderOptions()
.Tooltip("How large notifications are.")
.Format("%.1f")
@@ -400,6 +436,7 @@ void SohMenu::AddMenuSettings() {
.Max(5.0f)
.DefaultValue(1.8f));
AddWidget(path, "Test Notification", WIDGET_BUTTON)
+ .RaceDisable(false)
.Callback([](WidgetInfo& info) {
Notification::Emit({
.itemIcon = "__OTR__textures/icon_item_24_static/gQuestIconGoldSkulltulaTex",
diff --git a/soh/soh/SohGui/SohModals.h b/soh/soh/SohGui/SohModals.h
index 31dc99cd2..f74f0b1bf 100644
--- a/soh/soh/SohGui/SohModals.h
+++ b/soh/soh/SohGui/SohModals.h
@@ -4,7 +4,7 @@
#include "window/gui/GuiMenuBar.h"
#include "window/gui/GuiElement.h"
-class SohModalWindow : public Ship::GuiWindow {
+class SohModalWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void Draw() override;
diff --git a/soh/soh/util.cpp b/soh/soh/util.cpp
index 1e5bb2ae8..b3b6b5c7a 100644
--- a/soh/soh/util.cpp
+++ b/soh/soh/util.cpp
@@ -364,8 +364,10 @@ const std::string& SohUtils::GetRandomizerCheckAreaPrefix(int32_t rcarea) {
}
void SohUtils::CopyStringToCharArray(char* destination, std::string source, size_t size) {
- strncpy(destination, source.c_str(), size - 1);
- destination[size - 1] = '\0';
+ if (size > 0) {
+ strncpy(destination, source.c_str(), size - 1);
+ destination[size - 1] = '\0';
+ }
}
std::string SohUtils::Sanitize(std::string stringValue) {
@@ -388,12 +390,9 @@ std::string SohUtils::Sanitize(std::string stringValue) {
}
size_t SohUtils::CopyStringToCharBuffer(char* buffer, const std::string& source, const size_t maxBufferSize) {
- if (!source.empty()) {
- // Prevent potential horrible overflow due to implicit conversion of maxBufferSize to an unsigned. Prevents
- // negatives.
- memset(buffer, 0, std::max(0, maxBufferSize));
- // Gaurentee that this value will be greater than 0, regardless of passed variables.
- const size_t copiedCharLen = std::min(std::max(0, maxBufferSize - 1), source.length());
+ if (!source.empty() && maxBufferSize > 0) {
+ memset(buffer, 0, maxBufferSize);
+ const size_t copiedCharLen = std::min(maxBufferSize - 1, source.length());
memcpy(buffer, source.c_str(), copiedCharLen);
return copiedCharLen;
}
@@ -408,8 +407,5 @@ bool SohUtils::IsStringEmpty(std::string str) {
std::string::size_type end = str.find_last_not_of(' ');
// Check if the string is empty after stripping spaces
- if (start == std::string::npos || end == std::string::npos)
- return true; // The string is empty
- else
- return false; // The string is not empty
+ return start == std::string::npos || end == std::string::npos;
}
diff --git a/soh/soh/z_play_otr.cpp b/soh/soh/z_play_otr.cpp
index 54f4b0016..23e61261c 100644
--- a/soh/soh/z_play_otr.cpp
+++ b/soh/soh/z_play_otr.cpp
@@ -3,7 +3,7 @@
#include
#include "soh/resource/type/Scene.h"
#include
-#include "soh/Enhancements/game-interactor/GameInteractor.h"
+#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "global.h"
#include "vt.h"
#include
@@ -59,7 +59,7 @@ extern "C" void OTRPlay_SpawnScene(PlayState* play, s32 sceneId, s32 spawn) {
osSyncPrintf("ROOM SIZE=%fK\n", roomSize / 1024.0f);
- GameInteractor::Instance->ExecuteHooks(play->sceneNum);
+ GameInteractor_ExecuteOnSceneInit(play->sceneNum);
SPDLOG_INFO("Scene Init - sceneNum: {0:#x}, entranceIndex: {1:#x}", play->sceneNum, gSaveContext.entranceIndex);
}
@@ -79,6 +79,7 @@ void OTRPlay_InitScene(PlayState* play, s32 spawn) {
YREG(15) = 0;
gSaveContext.worldMapArea = 0;
OTRScene_ExecuteCommands(play, (SOH::Scene*)play->sceneSegment);
+ GameInteractor_ExecuteAfterSceneCommands(play->sceneNum);
Play_InitEnvironment(play, play->skyboxId);
/* auto data = static_cast(Ship::Context::GetInstance()
->GetResourceManager()
diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c
index facbbfd81..3423855b6 100644
--- a/soh/src/code/z_parameter.c
+++ b/soh/src/code/z_parameter.c
@@ -2411,6 +2411,9 @@ u8 Item_Give(PlayState* play, u8 item) {
}
}
} else {
+ if (item == ITEM_LETTER_RUTO) {
+ Flags_SetRandomizerInf(RAND_INF_OBTAINED_RUTOS_LETTER);
+ }
for (i = 0; i < 4; i++) {
if (gSaveContext.inventory.items[temp + i] == ITEM_NONE) {
gSaveContext.inventory.items[temp + i] = item;
@@ -2434,6 +2437,9 @@ u8 Item_Give(PlayState* play, u8 item) {
}
} else {
Flags_SetRandomizerInf(item - ITEM_WEIRD_EGG + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG);
+ if (item == ITEM_WEIRD_EGG) {
+ Flags_SetRandomizerInf(RAND_INF_WEIRD_EGG);
+ }
}
}
@@ -2785,6 +2791,7 @@ void Interface_SetDoAction(PlayState* play, u16 action) {
PauseContext* pauseCtx = &play->pauseCtx;
if (interfaceCtx->unk_1F0 != action) {
+ GameInteractor_ExecuteOnSetDoAction(action);
interfaceCtx->unk_1F0 = action;
interfaceCtx->unk_1EC = 1;
interfaceCtx->unk_1F4 = 0.0f;
diff --git a/soh/src/overlays/actors/ovl_Fishing/z_fishing.c b/soh/src/overlays/actors/ovl_Fishing/z_fishing.c
index 94d7e15ca..4d42de65f 100644
--- a/soh/src/overlays/actors/ovl_Fishing/z_fishing.c
+++ b/soh/src/overlays/actors/ovl_Fishing/z_fishing.c
@@ -5170,7 +5170,7 @@ void Fishing_HandleOwnerDialog(Fishing* this, PlayState* play) {
if (Actor_HasParent(&this->actor, play)) {
this->stateAndTimer = 24;
} else {
- if (!GameInteractor_Should(VB_GIVE_RANDO_GLITCH_FISHING_PRIZE, false, &this)) {
+ if (!GameInteractor_Should(VB_GIVE_RANDO_GLITCH_FISHING_PRIZE, false, this)) {
Actor_OfferGetItem(&this->actor, play, GI_SCALE_GOLDEN, 2000.0f, 1000.0f);
}
}
diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c
index ddee9d0af..6638893f5 100644
--- a/soh/src/overlays/actors/ovl_player_actor/z_player.c
+++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c
@@ -12773,9 +12773,8 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
if (!CVarGetInteger(CVAR_SETTING("MoveInFirstPerson"), 0)) {
temp2 += sControlInput->rel.stick_y * 240.0f * invertYAxisMulti * yAxisMulti;
}
- if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0) &&
- fabsf(sControlInput->cur.right_stick_y) > 15.0f) {
- temp2 += sControlInput->cur.right_stick_y * 240.0f * invertYAxisMulti * yAxisMulti;
+ if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) {
+ temp2 += sControlInput->rel.right_stick_y * 240.0f * invertYAxisMulti * yAxisMulti;
}
if (fabsf(sControlInput->cur.gyro_x) > 0.01f) {
temp2 += (-sControlInput->cur.gyro_x) * 750.0f;
@@ -12792,9 +12791,8 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
if (!CVarGetInteger(CVAR_SETTING("MoveInFirstPerson"), 0)) {
temp2 += sControlInput->rel.stick_x * -16.0f * invertXAxisMulti * xAxisMulti;
}
- if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0) &&
- fabsf(sControlInput->cur.right_stick_x) > 15.0f) {
- temp2 += sControlInput->cur.right_stick_x * -16.0f * invertXAxisMulti * xAxisMulti;
+ if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) {
+ temp2 += sControlInput->rel.right_stick_x * -16.0f * invertXAxisMulti * xAxisMulti;
}
if (fabsf(sControlInput->cur.gyro_y) > 0.01f) {
temp2 += (sControlInput->cur.gyro_y) * 750.0f * invertXAxisMulti;
@@ -12810,10 +12808,9 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
(s32)((1.0f - Math_CosS(sControlInput->rel.stick_y * 200)) * 1500.0f) * invertYAxisMulti *
yAxisMulti;
}
- if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0) &&
- fabsf(sControlInput->cur.right_stick_y) > 15.0f) {
- temp3 += ((sControlInput->cur.right_stick_y >= 0) ? 1 : -1) *
- (s32)((1.0f - Math_CosS(sControlInput->cur.right_stick_y * 200)) * 1500.0f) * invertYAxisMulti *
+ if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) {
+ temp3 += ((sControlInput->rel.right_stick_y >= 0) ? 1 : -1) *
+ (s32)((1.0f - Math_CosS(sControlInput->rel.right_stick_y * 200)) * 1500.0f) * invertYAxisMulti *
yAxisMulti;
}
if (fabsf(sControlInput->cur.gyro_x) > 0.01f) {
@@ -12831,10 +12828,9 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
(s32)((1.0f - Math_CosS(sControlInput->rel.stick_x * 200)) * -1500.0f) * invertXAxisMulti *
xAxisMulti;
}
- if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0) &&
- fabsf(sControlInput->cur.right_stick_x) > 15.0f) {
- temp3 += ((sControlInput->cur.right_stick_x >= 0) ? 1 : -1) *
- (s32)((1.0f - Math_CosS(sControlInput->cur.right_stick_x * 200)) * -1500.0f) * invertXAxisMulti *
+ if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) {
+ temp3 += ((sControlInput->rel.right_stick_x >= 0) ? 1 : -1) *
+ (s32)((1.0f - Math_CosS(sControlInput->rel.right_stick_x * 200)) * -1500.0f) * invertXAxisMulti *
xAxisMulti;
}
if (fabsf(sControlInput->cur.gyro_y) > 0.01f) {