diff --git a/README.md b/README.md index c84059892..e7f929bad 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Official Website: https://www.shipofharkinian.com/ Official Discord: https://discord.com/invite/shipofharkinian -If you're having any trouble after reading through this `README`, feel free ask for help in the Support text channels. Please keep in mind that we do not condone piracy. +If you're having any trouble after reading through this `README`, feel free to ask for help in the Support text channels. Please keep in mind that we do not condone piracy. # Quick Start @@ -73,7 +73,7 @@ Congratulations, you are now sailing with the Ship of Harkinian! Have fun! # Project Overview Ship of Harkinian (SOH) is built atop a custom library dubbed libultraship (LUS). Back in the N64 days, there was an SDK distributed to developers named libultra; LUS is designed to mimic the functionality of libultra on modern hardware. In addition, we are dependant on the source code provided by the OOT decompilation project. -In order for the game to function, you will require a **legally aquired** ROM for Ocarina of Time. Click [here](https://ship.equipment/) to check the compatability of your specific rom. Any copyrighted assets are extracted from the ROM and reformated as a .otr archive file which the code uses. +In order for the game to function, you will require a **legally acquired** ROM for Ocarina of Time. Click [here](https://ship.equipment/) to check the compatibility of your specific rom. Any copyrighted assets are extracted from the ROM and reformatted as a .otr archive file which the code uses. ### Graphics Backends Currently, there are three rendering APIs supported: DirectX11 (Windows), OpenGL (all platforms), and Metal (MacOS). You can change which API to use in the `Settings` menu of the menubar, which requires a restart. If you're having an issue with crashing, you can change the API in the `shipofharkinian.json` file by finding the line `gfxbackend:""` and changing the value to `sdl` for OpenGL. DirectX 11 is the default on Windows. @@ -99,13 +99,13 @@ If you want to playtest a continuous integration build, you can find them at the * [Linux](https://nightly.link/HarbourMasters/Shipwright/workflows/generate-builds/develop/soh-linux.zip) ### Further Reading -More detailed documentation can be found in the 'docs' directory, including the afformentioned [building instructions](docs/BUILDING.md). +More detailed documentation can be found in the 'docs' directory, including the aforementioned [building instructions](docs/BUILDING.md). -*[Credits](docs/CREDITS.md) -*[Custom Music](docs/CUSTOM_MUSIC.md) -*[Controler Maping](docs/GAME_CONTROLLER_DB.md) -*[Modding](docs/MODDING.md) -*[Versioning](docs/VERSIONING.md) +* [Credits](docs/CREDITS.md) +* [Custom Music](docs/CUSTOM_MUSIC.md) +* [Controller Mapping](docs/GAME_CONTROLLER_DB.md) +* [Modding](docs/MODDING.md) +* [Versioning](docs/VERSIONING.md) diff --git a/soh/assets/custom/textures/parameter_static/gMoon.rgba32.png b/soh/assets/custom/textures/parameter_static/gMoon.rgba32.png new file mode 100644 index 000000000..9c1afa577 Binary files /dev/null and b/soh/assets/custom/textures/parameter_static/gMoon.rgba32.png differ diff --git a/soh/assets/custom/textures/parameter_static/gNavi.rgba32.png b/soh/assets/custom/textures/parameter_static/gNavi.rgba32.png new file mode 100644 index 000000000..aae12c339 Binary files /dev/null and b/soh/assets/custom/textures/parameter_static/gNavi.rgba32.png differ diff --git a/soh/assets/custom/textures/parameter_static/gSun.rgba32.png b/soh/assets/custom/textures/parameter_static/gSun.rgba32.png new file mode 100644 index 000000000..954726e05 Binary files /dev/null and b/soh/assets/custom/textures/parameter_static/gSun.rgba32.png differ diff --git a/soh/assets/soh_assets.h b/soh/assets/soh_assets.h index 50a5df2eb..9e171a023 100644 --- a/soh/assets/soh_assets.h +++ b/soh/assets/soh_assets.h @@ -178,6 +178,15 @@ static const ALIGN_ASSET(2) char gSplitEntranceTex[] = dgSplitEntrance; #define dgBossSoul "__OTR__textures/parameter_static/gBossSoul" static const ALIGN_ASSET(2) char gBossSoulTex[] = dgBossSoul; +#define dgMoonIcon "__OTR__textures/parameter_static/gMoon" +static const ALIGN_ASSET(2) char gMoonIconTex[] = dgMoonIcon; + +#define dgSunIcon "__OTR__textures/parameter_static/gSun" +static const ALIGN_ASSET(2) char gSunIconTex[] = dgSunIcon; + +#define dgNaviIcon "__OTR__textures/parameter_static/gNavi" +static const ALIGN_ASSET(2) char gNaviIconTex[] = dgNaviIcon; + #define dgFileSelMQButtonTex "__OTR__textures/title_static/gFileSelMQButtonTex" static const ALIGN_ASSET(2) char gFileSelMQButtonTex[] = dgFileSelMQButtonTex; diff --git a/soh/include/z64item.h b/soh/include/z64item.h index 214d82711..1731800aa 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -306,6 +306,7 @@ typedef enum { /* 0x99 */ ITEM_STICK_UPGRADE_30, /* 0x9A */ ITEM_NUT_UPGRADE_30, /* 0x9B */ ITEM_NUT_UPGRADE_40, + /* 0x9C */ ITEM_SHIP, // SOH [Enhancement] Added to enable custom item gives /* 0xFC */ ITEM_LAST_USED = 0xFC, /* 0xFE */ ITEM_NONE_FE = 0xFE, /* 0xFF */ ITEM_NONE = 0xFF @@ -455,9 +456,10 @@ typedef enum { /* 0x79 */ GI_NUT_UPGRADE_30, /* 0x7A */ GI_NUT_UPGRADE_40, /* 0x7B */ GI_BULLET_BAG_50, - /* 0x7C */ GI_ICE_TRAP, // freezes link when opened from a chest - /* 0x7D */ GI_TEXT_0, // no model appears over Link, shows text id 0 (pocket egg) - /* 0x84 */ GI_MAX + /* 0x7C */ GI_SHIP, // SOH [Enhancement] Added to enable custom item gives + /* 0x7D */ GI_ICE_TRAP, // freezes link when opened from a chest + /* 0x7E */ GI_TEXT_0, // no model appears over Link, shows text id 0 (pocket egg) + /* 0x7F */ GI_MAX } GetItemID; typedef enum { diff --git a/soh/include/z64save.h b/soh/include/z64save.h index bf0d20697..b64efb459 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -735,14 +735,14 @@ typedef enum { #define INFTABLE_12A 0x12A #define INFTABLE_138 0x138 #define INFTABLE_139 0x139 -#define INFTABLE_140 0x140 -#define INFTABLE_RUTO_IN_JJ_MEET_RUTO 0x141 -#define INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME 0x142 -#define INFTABLE_143 0x143 -#define INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE 0x144 -#define INFTABLE_145 0x145 -#define INFTABLE_146 0x146 -#define INFTABLE_147 0x147 +#define INFTABLE_140 0x140 // Left her on blue switch in fork room (causes her to spawn in fork room) +#define INFTABLE_RUTO_IN_JJ_MEET_RUTO 0x141 // Jumped down hole from hole room +#define INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME 0x142 // in the basement +#define INFTABLE_143 0x143 // Sat down in basement (causes her to get upset if this is set when actor is spawned) +#define INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE 0x144 // Entered the room with the sapphire +#define INFTABLE_145 0x145 // Thrown to sapphire (not kidnapped yet) +#define INFTABLE_146 0x146 // Kidnapped +#define INFTABLE_147 0x147 // Brought ruto back up to holes room, causes her to spawn in holes room instead of basement #define INFTABLE_160 0x160 #define INFTABLE_161 0x161 #define INFTABLE_162 0x162 diff --git a/soh/soh/Enhancements/Holiday/Caladius.cpp b/soh/soh/Enhancements/Holiday/Caladius.cpp index 5c4b76499..d068ad91a 100644 --- a/soh/soh/Enhancements/Holiday/Caladius.cpp +++ b/soh/soh/Enhancements/Holiday/Caladius.cpp @@ -19,7 +19,7 @@ uint64_t GetUnixTimestamp(); bool isFeverDisabled = false; bool isExchangeDisabled = false; -float fontScale = 1.0f; +static float fontScale = 1.0f; extern GetItemEntry vanillaQueuedItemEntry; diff --git a/soh/soh/Enhancements/TimeDisplay/TimeDisplay.cpp b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.cpp new file mode 100644 index 000000000..cb9dfbb46 --- /dev/null +++ b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.cpp @@ -0,0 +1,262 @@ +#include "TimeDisplay.h" +#include "soh/Enhancements/gameplaystats.h" +#include + +#include "assets/textures/parameter_static/parameter_static.h" +#include "assets/soh_assets.h" +#include "soh/ImGuiUtils.h" + +extern "C" { +#include "macros.h" +#include "functions.h" +#include "variables.h" +extern PlayState* gPlayState; +uint64_t GetUnixTimestamp(); +} + +float fontScale = 1.0f; +std::string timeDisplayTime = ""; +ImTextureID textureDisplay = 0; +ImVec4 windowBG = ImVec4(0, 0, 0, 0.5f); +ImVec4 textColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + +// ImVec4 Colors +#define COLOR_WHITE ImVec4(1.0f, 1.0f, 1.0f, 1.0f) +#define COLOR_LIGHT_RED ImVec4(1.0f, 0.05f, 0, 1.0f) +#define COLOR_LIGHT_BLUE ImVec4(0, 0.88f, 1.0f, 1.0f) +#define COLOR_LIGHT_GREEN ImVec4(0.52f, 1.0f, 0.23f, 1.0f) +#define COLOR_GREY ImVec4(0.78f, 0.78f, 0.78f, 1.0f) + +const static std::vector> digitList = { + { "DIGIT_0_TEXTURE", gCounterDigit0Tex }, { "DIGIT_1_TEXTURE", gCounterDigit1Tex }, + { "DIGIT_2_TEXTURE", gCounterDigit2Tex }, { "DIGIT_3_TEXTURE", gCounterDigit3Tex }, + { "DIGIT_4_TEXTURE", gCounterDigit4Tex }, { "DIGIT_5_TEXTURE", gCounterDigit5Tex }, + { "DIGIT_6_TEXTURE", gCounterDigit6Tex }, { "DIGIT_7_TEXTURE", gCounterDigit7Tex }, + { "DIGIT_8_TEXTURE", gCounterDigit8Tex }, { "DIGIT_9_TEXTURE", gCounterDigit9Tex }, + { "COLON_TEXTURE", gCounterColonTex }, +}; + +const std::vector timeDisplayList = { + { DISPLAY_IN_GAME_TIMER, "Display Gameplay Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.InGameTimer") }, + { DISPLAY_TIME_OF_DAY, "Display Time of Day", CVAR_ENHANCEMENT("TimeDisplay.Timers.TimeofDay") }, + { DISPLAY_CONDITIONAL_TIMER, "Display Conditional Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.HotWater") }, + { DISPLAY_NAVI_TIMER, "Display Navi Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.NaviTimer") } +}; + +static std::vector activeTimers; + +std::string convertDayTime(uint32_t dayTime) { + uint32_t totalSeconds = 24 * 60 * 60; + uint32_t ss = static_cast(static_cast(dayTime) * (totalSeconds - 1) / 65535); + uint32_t hh = ss / 3600; + uint32_t mm = (ss % 3600) / 60; + return fmt::format("{:0>2}:{:0>2}", hh, mm); +} + +std::string convertNaviTime(uint32_t value) { + uint32_t totalSeconds = value * 0.05; + uint32_t ss = totalSeconds % 60; + uint32_t mm = totalSeconds / 60; + return fmt::format("{:0>2}:{:0>2}", mm, ss); +} + +std::string formatHotWaterDisplay(uint32_t value) { + uint32_t ss = value % 60; + uint32_t mm = value / 60; + return fmt::format("{:0>2}:{:0>2}", mm, ss); +} + +std::string formatTimeDisplay(uint32_t value) { + uint32_t sec = value / 10; + uint32_t hh = sec / 3600; + uint32_t mm = (sec - hh * 3600) / 60; + uint32_t ss = sec - hh * 3600 - mm * 60; + uint32_t ds = value % 10; + return fmt::format("{}:{:0>2}:{:0>2}.{}", hh, mm, ss, ds); +} + +static void TimeDisplayGetTimer(uint32_t timeID) { + timeDisplayTime = ""; + textureDisplay = 0; + textColor = COLOR_WHITE; + + Player* player = GET_PLAYER(gPlayState); + uint32_t timer1 = gSaveContext.timer1Value; + + switch (timeID) { + case DISPLAY_IN_GAME_TIMER: + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("GAMEPLAY_TIMER"); + timeDisplayTime = formatTimeDisplay(GAMEPLAYSTAT_TOTAL_TIME).c_str(); + break; + case DISPLAY_TIME_OF_DAY: + if (gSaveContext.dayTime >= DAY_BEGINS && gSaveContext.dayTime < NIGHT_BEGINS) { + textureDisplay = + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("DAY_TIME_TIMER"); + } else { + textureDisplay = + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("NIGHT_TIME_TIMER"); + } + timeDisplayTime = convertDayTime(gSaveContext.dayTime).c_str(); + break; + case DISPLAY_CONDITIONAL_TIMER: + if (gSaveContext.timer1State > 0) { + timeDisplayTime = formatHotWaterDisplay(gSaveContext.timer1Value).c_str(); + textColor = + gSaveContext.timer1State <= 4 + ? (gPlayState->roomCtx.curRoom.behaviorType2 == ROOM_BEHAVIOR_TYPE2_3 ? COLOR_LIGHT_RED + : COLOR_LIGHT_BLUE) + : COLOR_WHITE; + if (gSaveContext.timer1State <= 4) { + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + gPlayState->roomCtx.curRoom.behaviorType2 == ROOM_BEHAVIOR_TYPE2_3 + ? itemMapping[ITEM_TUNIC_GORON].name + : itemMapping[ITEM_TUNIC_ZORA].name); + } + if (gSaveContext.timer1State >= 6) { + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + itemMapping[ITEM_SWORD_MASTER].name); + } + } else { + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + itemMapping[ITEM_TUNIC_KOKIRI].name); + timeDisplayTime = "-:--"; + } + break; + case DISPLAY_NAVI_TIMER: + if (gSaveContext.naviTimer <= NAVI_PREPARE) { + timeDisplayTime = convertNaviTime(NAVI_PREPARE - gSaveContext.naviTimer).c_str(); + } else if (gSaveContext.naviTimer <= NAVI_ACTIVE) { + timeDisplayTime = convertNaviTime(NAVI_ACTIVE - gSaveContext.naviTimer).c_str(); + textColor = COLOR_LIGHT_GREEN; + } else { + timeDisplayTime = convertNaviTime(NAVI_COOLDOWN - gSaveContext.naviTimer).c_str(); + textColor = COLOR_GREY; + } + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("NAVI_TIMER"); + break; + default: + break; + } +} + +void TimeDisplayUpdateDisplayOptions() { + activeTimers.clear(); + for (auto& timer : timeDisplayList) { + if (CVarGetInteger(timer.timeEnable, 0)) { + activeTimers.push_back(timer); + } + } + + //if (pushBack) { + // activeTimers.push_back(timeDisplayList[timeID]); + //} else { + // uint32_t index = 0; + // for (auto& check : activeTimers) { + // if (check.timeID == timeID) { + // activeTimers.erase(activeTimers.begin() + index); + // return; + // } + // index++; + // } + //} +} + +void TimeDisplayWindow::Draw() { + if (!gPlayState) { + return; + } + if (!CVarGetInteger(CVAR_WINDOW("TimeDisplayEnabled"), 0)) { + return; + } + + ImGui::PushStyleColor(ImGuiCol_WindowBg, windowBG); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); + + ImGui::Begin("TimerDisplay", nullptr, + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar); + ImGui::SetWindowFontScale(fontScale); + if (activeTimers.size() == 0) { + ImGui::Text("No Enabled Timers..."); + } else { + ImGui::BeginTable("Timer List", 2, ImGuiTableFlags_NoClip); + for (auto& timers : activeTimers) { + ImGui::PushID(timers.timeID); + TimeDisplayGetTimer(timers.timeID); + ImGui::TableNextColumn(); + ImGui::Image(textureDisplay, ImVec2(16.0f * fontScale, 16.0f * fontScale)); + ImGui::TableNextColumn(); + + if (timeDisplayTime != "-:--") { + char* textToDecode = new char[timeDisplayTime.size() + 1]; + textToDecode = std::strcpy(textToDecode, timeDisplayTime.c_str()); + size_t textLength = timeDisplayTime.length(); + uint16_t textureIndex = 0; + + for (size_t i = 0; i < textLength; i++) { + ImVec2 originalCursorPos = ImGui::GetCursorPos(); + if (textToDecode[i] == ':' || textToDecode[i] == '.') { + textureIndex = 10; + } else { + textureIndex = textToDecode[i] - '0'; + } + if (textToDecode[i] == '.') { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (8.0f * fontScale)); + ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + digitList[textureIndex].first), + ImVec2(8.0f * fontScale, 8.0f * fontScale), ImVec2(0, 0.5f), ImVec2(1, 1), + textColor, ImVec4(0, 0, 0, 0)); + } else { + ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + digitList[textureIndex].first), + ImVec2(8.0f * fontScale, 16.0f * fontScale), ImVec2(0, 0), ImVec2(1, 1), textColor, + ImVec4(0, 0, 0, 0)); + } + ImGui::SameLine(0, 0); + } + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::End(); + + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(1); +} + +void TimeDisplayInitSettings() { + fontScale = CVarGetFloat(CVAR_ENHANCEMENT("TimeDisplay.FontScale"), 1.0f); + if (fontScale < 1.0f) { + fontScale = 1.0f; + } + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeDisplay.ShowWindowBG"), 0)) { + windowBG = ImVec4(0, 0, 0, 0); + } else { + windowBG = ImVec4(0, 0, 0, 0.5f); + } +} + +static void TimeDisplayInitTimers() { + for (auto& update : timeDisplayList) { + if (CVarGetInteger(update.timeEnable, 0)) { + activeTimers.push_back(update); + } + } +} + +void TimeDisplayWindow::InitElement() { + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("GAMEPLAY_TIMER", gClockIconTex, ImVec4(1, 1, 1, 1)); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("DAY_TIME_TIMER", gSunIconTex, ImVec4(1, 1, 1, 1)); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("NIGHT_TIME_TIMER", gMoonIconTex, ImVec4(1, 1, 1, 1)); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("NAVI_TIMER", gNaviIconTex, ImVec4(1, 1, 1, 1)); + + for (auto& load : digitList) { + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(load.first.c_str(), load.second, ImVec4(1, 1, 1, 1)); + } + + TimeDisplayInitSettings(); + TimeDisplayInitTimers(); +} diff --git a/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h new file mode 100644 index 000000000..090ac2901 --- /dev/null +++ b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h @@ -0,0 +1,37 @@ +#include + +class TimeDisplayWindow : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + + void InitElement() override; + void DrawElement() override {}; + void Draw() override; + void UpdateElement() override {}; +}; + +void TimeDisplayUpdateDisplayOptions(); +void TimeDisplayInitSettings(); + +typedef enum { + DISPLAY_IN_GAME_TIMER, + DISPLAY_TIME_OF_DAY, + DISPLAY_CONDITIONAL_TIMER, + DISPLAY_NAVI_TIMER +}; + +typedef enum { + NAVI_PREPARE = 600, + NAVI_ACTIVE = 3000, + NAVI_COOLDOWN = 25800, + DAY_BEGINS = 17759, + NIGHT_BEGINS = 49155 +}; + +typedef struct { + uint32_t timeID; + std::string timeLabel; + const char* timeEnable; +} TimeObject; + +extern const std::vector timeDisplayList; \ No newline at end of file diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipBlueWarp.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipBlueWarp.cpp index 0bb65a8de..9f9b67fec 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipBlueWarp.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipBlueWarp.cpp @@ -10,7 +10,7 @@ extern "C" { #include "variables.h" } -#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetSelectedOptionIndex() +#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetContextOptionIndex() static bool sEnteredBlueWarp = false; diff --git a/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveJabuJabuElevator.cpp b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveJabuJabuElevator.cpp new file mode 100644 index 000000000..1e1c6ceb5 --- /dev/null +++ b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveJabuJabuElevator.cpp @@ -0,0 +1,27 @@ +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/OTRGlobals.h" + +extern "C" { +#include "src/overlays/actors/ovl_Bg_Bdan_Objects/z_bg_bdan_objects.h" +} + +/** + * Adjusts the behavior of the elevator to start near the bottom if you are entering the room from the bottom + */ +void MoveJabuJabuElevator_Register() { + GameInteractor::Instance->RegisterGameHookForID(ACTOR_BG_BDAN_OBJECTS, [](void* actorRef) { + Player* player = GET_PLAYER(gPlayState); + BgBdanObjects* bgBdanObjects = static_cast(actorRef); + + if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { + return; + } + + if (bgBdanObjects->dyna.actor.params == 1) { + if (player->actor.world.pos.y < -500.0f) { + bgBdanObjects->timer = 220; + } + } + }); +} diff --git a/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/SkipChildRutoInteractions.cpp b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/SkipChildRutoInteractions.cpp new file mode 100644 index 000000000..aaaf1b39f --- /dev/null +++ b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/SkipChildRutoInteractions.cpp @@ -0,0 +1,93 @@ +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/OTRGlobals.h" + +extern "C" { +#include "overlays/actors/ovl_En_Ru1/z_en_ru1.h" +#include "assets/objects/object_ru1/object_ru1.h" + +Actor* func_80AEB124(PlayState* play); +} + +void SkipChildRutoInteractions_Register() { + // Skips the Child Ruto introduction cutscene, where she drops down into the hole in Jabu-Jabu's Belly + REGISTER_VB_SHOULD(VB_PLAY_CHILD_RUTO_INTRO, { + EnRu1* enRu1 = va_arg(args, EnRu1*); + + if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { + return; + } + + Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO); + Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME); + Flags_SetInfTable(INFTABLE_143); + enRu1->drawConfig = 1; + enRu1->actor.world.pos.x = 127.0f; + enRu1->actor.world.pos.y = -340.0f; + enRu1->actor.world.pos.z = -3041.0f; + enRu1->actor.shape.rot.y = enRu1->actor.world.rot.y = -5098; + + if (*should) { + Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildTurnAroundAnim, 1.0f, 0, + Animation_GetLastFrame((void*)&gRutoChildTurnAroundAnim), ANIMMODE_ONCE, -8.0f); + enRu1->action = 10; + } + + *should = false; + }); + + // Skips a short dialogue sequence where Ruto tells you to throw her to the Sapphire + REGISTER_VB_SHOULD(VB_RUTO_WANT_TO_BE_TOSSED_TO_SAPPHIRE, { + if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { + return; + } + + if (*should) { + Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE); + *should = false; + } + }); + + // Prevents Ruto from running to the Sapphire when she wants to be tossed to it, instead she just stands up and waits for link to get closer + REGISTER_VB_SHOULD(VB_RUTO_RUN_TO_SAPPHIRE, { + EnRu1* enRu1 = va_arg(args, EnRu1*); + DynaPolyActor* dynaPolyActor = va_arg(args, DynaPolyActor*); + + if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { + return; + } + + if (*should) { + enRu1->unk_28C = (BgBdanObjects*)dynaPolyActor; + Flags_SetInfTable(INFTABLE_145); + Flags_SetSwitch(gPlayState, 0x02); + Flags_SetSwitch(gPlayState, 0x1F); + enRu1->action = 42; + Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildWait2Anim, 1.0f, 0, + Animation_GetLastFrame((void*)&gRutoChildWait2Anim), ANIMMODE_LOOP, -8.0f); + enRu1->unk_28C->cameraSetting = 1; + Actor* sapphire = func_80AEB124(gPlayState); + if (sapphire != NULL) { + Actor_Kill(sapphire); + } + enRu1->actor.room = gPlayState->roomCtx.curRoom.num; + *should = false; + } + }); + + // This overrides the behavior that causes Ruto to get upset at you before sitting back down again when INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME is set + GameInteractor::Instance->RegisterGameHookForID(ACTOR_EN_RU1, [](void* actorRef) { + EnRu1* enRu1 = static_cast(actorRef); + if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { + return; + } + + if (enRu1->action == 22) { + enRu1->action = 27; + enRu1->drawConfig = 1; + enRu1->actor.flags |= ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY; + Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildSittingAnim, 1.0f, 0.0f, + Animation_GetLastFrame((void*)&gRutoChildSittingAnim), ANIMMODE_LOOP, 0.0f); + } + }); +} diff --git a/soh/soh/Enhancements/TimeSavers/TimeSavers.cpp b/soh/soh/Enhancements/TimeSavers/TimeSavers.cpp index 6814b9332..a198f8289 100644 --- a/soh/soh/Enhancements/TimeSavers/TimeSavers.cpp +++ b/soh/soh/Enhancements/TimeSavers/TimeSavers.cpp @@ -10,7 +10,9 @@ void TimeSavers_Register() { SkipZeldaFleeingCastle_Register(); SkipIntro_Register(); // SkipMiscInteractions + MoveJabuJabuElevator_Register(); MoveMidoInKokiriForest_Register(); + SkipChildRutoInteractions_Register(); FasterHeavyBlockLift_Register(); FasterRupeeAccumulator_Register(); } diff --git a/soh/soh/Enhancements/TimeSavers/TimeSavers.h b/soh/soh/Enhancements/TimeSavers/TimeSavers.h index 0cec3edfa..ad521c6c2 100644 --- a/soh/soh/Enhancements/TimeSavers/TimeSavers.h +++ b/soh/soh/Enhancements/TimeSavers/TimeSavers.h @@ -12,7 +12,9 @@ void TimeSavers_Register(); void SkipZeldaFleeingCastle_Register(); void SkipIntro_Register(); // SkipMiscInteractions + void MoveJabuJabuElevator_Register(); void MoveMidoInKokiriForest_Register(); + void SkipChildRutoInteractions_Register(); void FasterHeavyBlockLift_Register(); void FasterRupeeAccumulator_Register(); diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index 712101824..f628f991b 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -8,8 +8,6 @@ #include #include #include -#include -#include "soh/Enhancements/randomizer/3drando/random.hpp" #include #include "soh/UIWidgets.hpp" @@ -17,10 +15,9 @@ #include "soh/ResourceManagerHelpers.h" extern "C" { -#include +#include "z64.h" #include "macros.h" #include "soh/cvar_prefixes.h" -extern PlayState* gPlayState; #include "objects/object_link_boy/object_link_boy.h" #include "objects/object_link_child/object_link_child.h" #include "objects/object_gi_shield_3/object_gi_shield_3.h" @@ -57,34 +54,46 @@ extern PlayState* gPlayState; #include "scenes/overworld/spot20/spot20_room_0.h" #include "scenes/overworld/spot03/spot03_room_0.h" #include "scenes/overworld/spot15/spot15_room_0.h" +#include "overlays/ovl_Boss_Ganon2/ovl_Boss_Ganon2.h" +#include "overlays/ovl_Magic_Wind/ovl_Magic_Wind.h" +#include "textures/nintendo_rogo_static/nintendo_rogo_static.h" +extern PlayState* gPlayState; void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction); void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const char* patchName, int destinationIndex, int sourceIndex); void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName); u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); } +#define PATCH_GFX(path, name, cvar, index, instruction) \ + if (CVarGetInteger(cvar, 0)) { \ + ResourceMgr_PatchGfxByName(path, name, index, instruction); \ + } else { \ + ResourceMgr_UnpatchGfxByName(path, name); \ + } + // This is used for the greg bridge #define dgEndGrayscaleAndEndDlistDL "__OTR__helpers/cosmetics/gEndGrayscaleAndEndDlistDL" static const ALIGN_ASSET(2) char gEndGrayscaleAndEndDlistDL[] = dgEndGrayscaleAndEndDlistDL; std::map groupLabels = { - { COSMETICS_GROUP_LINK, "Link" }, + { COSMETICS_GROUP_LINK, "Link" }, { COSMETICS_GROUP_MIRRORSHIELD, "Mirror Shield" }, - { COSMETICS_GROUP_SWORDS, "Swords" }, - { COSMETICS_GROUP_GLOVES, "Gloves" }, - { COSMETICS_GROUP_EQUIPMENT, "Equipment" }, - { COSMETICS_GROUP_CONSUMABLE, "Consumables" }, - { COSMETICS_GROUP_HUD, "HUD" }, - { COSMETICS_GROUP_KALEIDO, "Pause Menu" }, - { COSMETICS_GROUP_TITLE, "Title Screen" }, - { COSMETICS_GROUP_NPC, "NPCs" }, - { COSMETICS_GROUP_WORLD, "World" }, - { COSMETICS_GROUP_MAGIC, "Magic Effects" }, - { COSMETICS_GROUP_ARROWS, "Arrow Effects" }, - { COSMETICS_GROUP_SPIN_ATTACK, "Spin Attack" }, - { COSMETICS_GROUP_TRAILS, "Trails" }, - { COSMETICS_GROUP_NAVI, "Navi" }, - { COSMETICS_GROUP_IVAN, "Ivan" } + { COSMETICS_GROUP_SWORDS, "Swords" }, + { COSMETICS_GROUP_GLOVES, "Gloves" }, + { COSMETICS_GROUP_EQUIPMENT, "Equipment" }, + { COSMETICS_GROUP_CONSUMABLE, "Consumables" }, + { COSMETICS_GROUP_HUD, "HUD" }, + { COSMETICS_GROUP_KALEIDO, "Pause Menu" }, + { COSMETICS_GROUP_TITLE, "Title Screen" }, + { COSMETICS_GROUP_NPC, "NPCs" }, + { COSMETICS_GROUP_WORLD, "World" }, + { COSMETICS_GROUP_MAGIC, "Magic Effects" }, + { COSMETICS_GROUP_ARROWS, "Arrow Effects" }, + { COSMETICS_GROUP_SPIN_ATTACK, "Spin Attack" }, + { COSMETICS_GROUP_TRAILS, "Trails" }, + { COSMETICS_GROUP_NAVI, "Navi" }, + { COSMETICS_GROUP_IVAN, "Ivan" }, + { COSMETICS_GROUP_MESSAGE, "Message" }, }; typedef struct { @@ -95,17 +104,22 @@ typedef struct { std::string label; CosmeticGroup group; ImVec4 currentColor; - ImVec4 defaultColor; + Color_RGBA8 defaultColor; bool supportsAlpha; bool supportsRainbow; bool advancedOption; } CosmeticOption; -#define COSMETIC_OPTION(id, label, group, defaultColor, supportsAlpha, supportsRainbow, advancedOption) \ - { id, { \ +Color_RGBA8 ColorRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + Color_RGBA8 color = { r, g, b, a }; + return color; +} + +#define COSMETIC_OPTION(id, label, group, defaultColor, supportsAlpha, supportsRainbow, advancedOption) \ + { id, { \ CVAR_COSMETIC(id ".Value"), CVAR_COSMETIC(id ".Rainbow"), CVAR_COSMETIC(id ".Locked"), CVAR_COSMETIC(id ".Changed"), label, group, \ - defaultColor, defaultColor, \ - supportsAlpha, supportsRainbow, advancedOption \ + ImVec4(defaultColor.r / 255.0f, defaultColor.g / 255.0f, defaultColor.b / 255.0f, defaultColor.a / 255.0f), defaultColor, \ + supportsAlpha, supportsRainbow, advancedOption \ } } /* @@ -182,195 +196,250 @@ typedef struct { colors were darker than the gDPSetPrimColor. You will see many more examples of this below in the `ApplyOrResetCustomGfxPatches` method */ static std::map cosmeticOptions = { - COSMETIC_OPTION("Link.KokiriTunic", "Kokiri Tunic", COSMETICS_GROUP_LINK, ImVec4(255, 0, 0, 255), false, true, false), - COSMETIC_OPTION("Link.GoronTunic", "Goron Tunic", COSMETICS_GROUP_LINK, ImVec4(255, 0, 0, 255), false, true, false), - COSMETIC_OPTION("Link.ZoraTunic", "Zora Tunic", COSMETICS_GROUP_LINK, ImVec4(255, 0, 0, 255), false, true, false), - COSMETIC_OPTION("Link.Hair", "Hair", COSMETICS_GROUP_LINK, ImVec4(255, 173, 27, 255), false, true, true), - COSMETIC_OPTION("Link.Linen", "Linen", COSMETICS_GROUP_LINK, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("Link.Boots", "Boots", COSMETICS_GROUP_LINK, ImVec4( 93, 44, 18, 255), false, true, true), + COSMETIC_OPTION("Link.KokiriTunic", "Kokiri Tunic", COSMETICS_GROUP_LINK, ColorRGBA8(255, 0, 0, 255), false, true, false), + COSMETIC_OPTION("Link.GoronTunic", "Goron Tunic", COSMETICS_GROUP_LINK, ColorRGBA8(255, 0, 0, 255), false, true, false), + COSMETIC_OPTION("Link.ZoraTunic", "Zora Tunic", COSMETICS_GROUP_LINK, ColorRGBA8(255, 0, 0, 255), false, true, false), + COSMETIC_OPTION("Link.Hair", "Hair", COSMETICS_GROUP_LINK, ColorRGBA8(255, 173, 27, 255), false, true, true), + COSMETIC_OPTION("Link.Linen", "Linen", COSMETICS_GROUP_LINK, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Link.Boots", "Boots", COSMETICS_GROUP_LINK, ColorRGBA8( 93, 44, 18, 255), false, true, true), - COSMETIC_OPTION("MirrorShield.Body", "Body", COSMETICS_GROUP_MIRRORSHIELD, ImVec4(215, 0, 0, 255), false, true, false), - COSMETIC_OPTION("MirrorShield.Mirror", "Mirror", COSMETICS_GROUP_MIRRORSHIELD, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("MirrorShield.Emblem", "Emblem", COSMETICS_GROUP_MIRRORSHIELD, ImVec4(205, 225, 255, 255), false, true, true), + COSMETIC_OPTION("MirrorShield.Body", "Body", COSMETICS_GROUP_MIRRORSHIELD, ColorRGBA8(215, 0, 0, 255), false, true, false), + COSMETIC_OPTION("MirrorShield.Mirror", "Mirror", COSMETICS_GROUP_MIRRORSHIELD, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("MirrorShield.Emblem", "Emblem", COSMETICS_GROUP_MIRRORSHIELD, ColorRGBA8(205, 225, 255, 255), false, true, true), - COSMETIC_OPTION("Swords.KokiriBlade", "Kokiri Sword Blade", COSMETICS_GROUP_SWORDS, ImVec4(255, 255, 255, 255), false, true, false), - // COSMETIC_OPTION("Swords.KokiriHilt", "Kokiri Sword Hilt", COSMETICS_GROUP_SWORDS, ImVec4(160, 100, 15, 255), false, true, true), // Todo (Cosmetics): Broken, need a better way to grayscale - COSMETIC_OPTION("Swords.MasterBlade", "Master Sword Blade", COSMETICS_GROUP_SWORDS, ImVec4(255, 255, 255, 255), false, true, false), - // COSMETIC_OPTION("Swords.MasterHilt", "Master Sword Hilt", COSMETICS_GROUP_SWORDS, ImVec4( 80, 80, 168, 255), false, true, true), // Todo (Cosmetics): Broken, need a better way to grayscale - COSMETIC_OPTION("Swords.BiggoronBlade", "Biggoron Sword Blade", COSMETICS_GROUP_SWORDS, ImVec4(255, 255, 255, 255), false, true, false), - // COSMETIC_OPTION("Swords.BiggoronHilt", "Biggoron Sword Hilt", COSMETICS_GROUP_SWORDS, ImVec4( 80, 80, 168, 255), false, true, true), // Todo (Cosmetics): Broken, need a better way to grayscale + COSMETIC_OPTION("Swords.KokiriBlade", "Kokiri Sword Blade", COSMETICS_GROUP_SWORDS, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("Swords.MasterBlade", "Master Sword Blade", COSMETICS_GROUP_SWORDS, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("Swords.BiggoronBlade", "Biggoron Sword Blade", COSMETICS_GROUP_SWORDS, ColorRGBA8(255, 255, 255, 255), false, true, false), + /* Todo (Cosmetics): Broken, need a better way to grayscale + COSMETIC_OPTION("Swords.KokiriHilt", "Kokiri Sword Hilt", COSMETICS_GROUP_SWORDS, ColorRGBA8(160, 100, 15, 255), false, true, true), + COSMETIC_OPTION("Swords.MasterHilt", "Master Sword Hilt", COSMETICS_GROUP_SWORDS, ColorRGBA8( 80, 80, 168, 255), false, true, true), + COSMETIC_OPTION("Swords.BiggoronHilt", "Biggoron Sword Hilt", COSMETICS_GROUP_SWORDS, ColorRGBA8( 80, 80, 168, 255), false, true, true), + */ - COSMETIC_OPTION("Gloves.GoronBracelet", "Goron Bracelet", COSMETICS_GROUP_GLOVES, ImVec4(255, 255, 170, 255), false, true, false), - COSMETIC_OPTION("Gloves.SilverGauntlets", "Silver Gauntlets", COSMETICS_GROUP_GLOVES, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Gloves.GoldenGauntlets", "Golden Gauntlets", COSMETICS_GROUP_GLOVES, ImVec4(254, 207, 15, 255), false, true, false), - COSMETIC_OPTION("Gloves.GauntletsGem", "Gauntlets Gem", COSMETICS_GROUP_GLOVES, ImVec4(255, 60, 100, 255), false, true, true), + COSMETIC_OPTION("Gloves.GoronBracelet", "Goron Bracelet", COSMETICS_GROUP_GLOVES, ColorRGBA8(255, 255, 170, 255), false, true, false), + COSMETIC_OPTION("Gloves.SilverGauntlets", "Silver Gauntlets", COSMETICS_GROUP_GLOVES, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("Gloves.GoldenGauntlets", "Golden Gauntlets", COSMETICS_GROUP_GLOVES, ColorRGBA8(254, 207, 15, 255), false, true, false), + COSMETIC_OPTION("Gloves.GauntletsGem", "Gauntlets Gem", COSMETICS_GROUP_GLOVES, ColorRGBA8(255, 60, 100, 255), false, true, true), - COSMETIC_OPTION("Equipment.BoomerangBody", "Boomerang Body", COSMETICS_GROUP_EQUIPMENT, ImVec4(160, 100, 0, 255), false, true, false), - COSMETIC_OPTION("Equipment.BoomerangGem", "Boomerang Gem", COSMETICS_GROUP_EQUIPMENT, ImVec4(255, 50, 150, 255), false, true, true), - // COSMETIC_OPTION("Equipment.SlingshotBody", "Slingshot Body", COSMETICS_GROUP_EQUIPMENT, ImVec4(160, 100, 0, 255), false, true, true), // Todo (Cosmetics): Broken, need a better way to grayscale - COSMETIC_OPTION("Equipment.SlingshotString", "Slingshot String", COSMETICS_GROUP_EQUIPMENT, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("Equipment.HammerHead", "Hammer Head", COSMETICS_GROUP_EQUIPMENT, ImVec4(155, 192, 201, 255), false, true, false), - COSMETIC_OPTION("Equipment.HammerHandle", "Hammer Handle", COSMETICS_GROUP_EQUIPMENT, ImVec4(110, 60, 0, 255), false, true, true), - // COSMETIC_OPTION("Equipment.HookshotChain", "Hookshot Chain", COSMETICS_GROUP_EQUIPMENT, ImVec4(255, 255, 255, 255), false, true, true), // Todo (Cosmetics): Implement - // COSMETIC_OPTION("Equipment.HookshotTip", "Hookshot Tip", COSMETICS_GROUP_EQUIPMENT, ImVec4(255, 255, 255, 255), false, true, false), // Todo (Cosmetics): Implement - COSMETIC_OPTION("HookshotReticle.Target", "Hookshotable Reticle", COSMETICS_GROUP_EQUIPMENT, ImVec4( 0, 255, 0, 255), false, false, false), - COSMETIC_OPTION("HookshotReticle.NonTarget", "Non-Hookshotable Reticle", COSMETICS_GROUP_EQUIPMENT, ImVec4(255, 0, 0, 255), false, false, false), - COSMETIC_OPTION("Equipment.BowTips", "Bow Tips", COSMETICS_GROUP_EQUIPMENT, ImVec4(200, 0, 0, 255), false, true, true), - COSMETIC_OPTION("Equipment.BowString", "Bow String", COSMETICS_GROUP_EQUIPMENT, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("Equipment.BowBody", "Bow Body", COSMETICS_GROUP_EQUIPMENT, ImVec4(140, 90, 10, 255), false, true, false), - COSMETIC_OPTION("Equipment.BowHandle", "Bow Handle", COSMETICS_GROUP_EQUIPMENT, ImVec4( 50, 150, 255, 255), false, true, true), - COSMETIC_OPTION("Equipment.ChuFace", "Bombchu Face", COSMETICS_GROUP_EQUIPMENT, ImVec4( 0, 100, 150, 255), false, true, true), - COSMETIC_OPTION("Equipment.ChuBody", "Bombchu Body", COSMETICS_GROUP_EQUIPMENT, ImVec4(180, 130, 50, 255), false, true, true), - COSMETIC_OPTION("Equipment.BunnyHood", "Bunny Hood", COSMETICS_GROUP_EQUIPMENT, ImVec4(255, 235, 109, 255), false, true, true), + COSMETIC_OPTION("Equipment.BoomerangBody", "Boomerang Body", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(160, 100, 0, 255), false, true, false), + COSMETIC_OPTION("Equipment.BoomerangGem", "Boomerang Gem", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(255, 50, 150, 255), false, true, true), + /* Todo (Cosmetics): Broken, need a better way to grayscale + COSMETIC_OPTION("Equipment.SlingshotBody", "Slingshot Body", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(160, 100, 0, 255), false, true, true), + */ + COSMETIC_OPTION("Equipment.SlingshotString", "Slingshot String", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Equipment.HammerHead", "Hammer Head", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(155, 192, 201, 255), false, true, false), + COSMETIC_OPTION("Equipment.HammerHandle", "Hammer Handle", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(110, 60, 0, 255), false, true, true), + COSMETIC_OPTION("Equipment.HookshotChain", "Hookshot Chain", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(255, 255, 255, 255), false, true, true), + /* Todo (Cosmetics): Implement + COSMETIC_OPTION("Equipment.HookshotTip", "Hookshot Tip", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(255, 255, 255, 255), false, true, false), + */ + COSMETIC_OPTION("HookshotReticle.Target", "Hookshotable Reticle", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8( 0, 255, 0, 255), false, true, false), + COSMETIC_OPTION("HookshotReticle.NonTarget", "Non-Hookshotable Reticle", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(255, 0, 0, 255), false, true, false), + COSMETIC_OPTION("Equipment.BowTips", "Bow Tips", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(200, 0, 0, 255), false, true, true), + COSMETIC_OPTION("Equipment.BowString", "Bow String", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Equipment.BowBody", "Bow Body", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(140, 90, 10, 255), false, true, false), + COSMETIC_OPTION("Equipment.BowHandle", "Bow Handle", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8( 50, 150, 255, 255), false, true, true), + COSMETIC_OPTION("Equipment.ChuFace", "Bombchu Face", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8( 0, 100, 150, 255), false, true, true), + COSMETIC_OPTION("Equipment.ChuBody", "Bombchu Body", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(180, 130, 50, 255), false, true, true), + COSMETIC_OPTION("Equipment.BunnyHood", "Bunny Hood", COSMETICS_GROUP_EQUIPMENT, ColorRGBA8(255, 235, 109, 255), false, true, true), - COSMETIC_OPTION("Consumable.Hearts", "Hearts", COSMETICS_GROUP_CONSUMABLE, ImVec4(255, 70, 50, 255), false, true, false), - COSMETIC_OPTION("Consumable.HeartBorder", "Heart Border", COSMETICS_GROUP_CONSUMABLE, ImVec4( 50, 40, 60, 255), false, true, true), - COSMETIC_OPTION("Consumable.DDHearts", "DD Hearts", COSMETICS_GROUP_CONSUMABLE, ImVec4(200, 0, 0, 255), false, true, false), - COSMETIC_OPTION("Consumable.DDHeartBorder", "DD Heart Border", COSMETICS_GROUP_CONSUMABLE, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("Consumable.Magic", "Magic", COSMETICS_GROUP_CONSUMABLE, ImVec4( 0, 200, 0, 255), false, true, false), - COSMETIC_OPTION("Consumable.MagicActive", "Magic Active", COSMETICS_GROUP_CONSUMABLE, ImVec4(250, 250, 0, 255), false, true, true), - COSMETIC_OPTION("Consumable_MagicInfinite", "Infinite Magic", COSMETICS_GROUP_CONSUMABLE, ImVec4( 0, 0, 200, 255), false, true, true), - COSMETIC_OPTION("Consumable.MagicBorder", "Magic Border", COSMETICS_GROUP_CONSUMABLE, ImVec4(255, 255, 255, 255), false, false, true), - COSMETIC_OPTION("Consumable.MagicBorderActive", "Magic Border Active", COSMETICS_GROUP_CONSUMABLE, ImVec4(255, 255, 255, 255), false, false, true), - COSMETIC_OPTION("Consumable.GreenRupee", "Green Rupee", COSMETICS_GROUP_CONSUMABLE, ImVec4( 50, 255, 50, 255), false, true, true), - COSMETIC_OPTION("Consumable.BlueRupee", "Blue Rupee", COSMETICS_GROUP_CONSUMABLE, ImVec4( 50, 50, 255, 255), false, true, true), - COSMETIC_OPTION("Consumable.RedRupee", "Red Rupee", COSMETICS_GROUP_CONSUMABLE, ImVec4(255, 50, 50, 255), false, true, true), - COSMETIC_OPTION("Consumable.PurpleRupee", "Purple Rupee", COSMETICS_GROUP_CONSUMABLE, ImVec4(150, 50, 255, 255), false, true, true), - COSMETIC_OPTION("Consumable.GoldRupee", "Gold Rupee", COSMETICS_GROUP_CONSUMABLE, ImVec4(255, 190, 55, 255), false, true, true), - COSMETIC_OPTION("Consumable.SilverRupee", "Silver Rupee", COSMETICS_GROUP_CONSUMABLE, ImVec4(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Consumable.Hearts", "Hearts", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(255, 70, 50, 255), false, true, false), + COSMETIC_OPTION("Consumable.HeartBorder", "Heart Border", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8( 50, 40, 60, 255), false, true, true), + COSMETIC_OPTION("Consumable.DDHearts", "DD Hearts", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(200, 0, 0, 255), false, true, false), + COSMETIC_OPTION("Consumable.DDHeartBorder", "DD Heart Border", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Consumable.Magic", "Magic", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8( 0, 200, 0, 255), false, true, false), + COSMETIC_OPTION("Consumable.MagicActive", "Magic Active", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(250, 250, 0, 255), false, true, true), + COSMETIC_OPTION("Consumable_MagicInfinite", "Infinite Magic", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8( 0, 0, 200, 255), false, true, true), + COSMETIC_OPTION("Consumable.MagicBorder", "Magic Border", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Consumable.MagicBorderActive", "Magic Border Active", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Consumable.GreenRupee", "Green Rupee", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8( 50, 255, 50, 255), false, true, true), + COSMETIC_OPTION("Consumable.BlueRupee", "Blue Rupee", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8( 50, 50, 255, 255), false, true, true), + COSMETIC_OPTION("Consumable.RedRupee", "Red Rupee", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(255, 50, 50, 255), false, true, true), + COSMETIC_OPTION("Consumable.PurpleRupee", "Purple Rupee", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(150, 50, 255, 255), false, true, true), + COSMETIC_OPTION("Consumable.GoldRupee", "Gold Rupee", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(255, 190, 55, 255), false, true, true), + COSMETIC_OPTION("Consumable.SilverRupee", "Silver Rupee", COSMETICS_GROUP_CONSUMABLE, ColorRGBA8(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("HUD.AButton", "A Button", COSMETICS_GROUP_HUD, ImVec4( 90, 90, 255, 255), false, true, false), - COSMETIC_OPTION("HUD.BButton", "B Button", COSMETICS_GROUP_HUD, ImVec4( 0, 150, 0, 255), false, true, false), - COSMETIC_OPTION("HUD.CButtons", "C Buttons", COSMETICS_GROUP_HUD, ImVec4(255, 160, 0, 255), false, true, false), - COSMETIC_OPTION("HUD.CUpButton", "C Up Button", COSMETICS_GROUP_HUD, ImVec4(255, 160, 0, 255), false, true, true), - COSMETIC_OPTION("HUD.CDownButton", "C Down Button", COSMETICS_GROUP_HUD, ImVec4(255, 160, 0, 255), false, true, true), - COSMETIC_OPTION("HUD.CLeftButton", "C Left Button", COSMETICS_GROUP_HUD, ImVec4(255, 160, 0, 255), false, true, true), - COSMETIC_OPTION("HUD.CRightButton", "C Right Button", COSMETICS_GROUP_HUD, ImVec4(255, 160, 0, 255), false, true, true), - COSMETIC_OPTION("HUD.StartButton", "Start Button", COSMETICS_GROUP_HUD, ImVec4(200, 0, 0, 255), false, true, false), - COSMETIC_OPTION("HUD.Dpad", "Dpad", COSMETICS_GROUP_HUD, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("HUD.KeyCount", "Key Count", COSMETICS_GROUP_HUD, ImVec4(200, 230, 255, 255), false, true, true), - COSMETIC_OPTION("HUD.StoneOfAgony", "Stone of Agony", COSMETICS_GROUP_HUD, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("HUD.Minimap", "Minimap", COSMETICS_GROUP_HUD, ImVec4( 0, 255, 255, 255), false, true, false), - COSMETIC_OPTION("HUD.MinimapPosition", "Minimap Position", COSMETICS_GROUP_HUD, ImVec4(200, 255, 0, 255), false, true, true), - COSMETIC_OPTION("HUD.MinimapEntrance", "Minimap Entrance", COSMETICS_GROUP_HUD, ImVec4(200, 0, 0, 255), false, true, true), - COSMETIC_OPTION("HUD.EnemyHealthBar", "Enemy Health Bar", COSMETICS_GROUP_HUD, ImVec4(255, 0, 0, 255), true, true, false), - COSMETIC_OPTION("HUD.EnemyHealthBorder", "Enemy Health Border", COSMETICS_GROUP_HUD, ImVec4(255, 255, 255, 255), true, false, true), - COSMETIC_OPTION("HUD.NameTagActorText", "Nametag Text", COSMETICS_GROUP_HUD, ImVec4(255, 255, 255, 255), true, true, false), - COSMETIC_OPTION("HUD.NameTagActorBackground", "Nametag Background", COSMETICS_GROUP_HUD, ImVec4(0, 0, 0, 80), true, false, true), - // Todo (Cosmetics): re-implement title card colors + COSMETIC_OPTION("HUD.AButton", "A Button", COSMETICS_GROUP_HUD, ColorRGBA8( 90, 90, 255, 255), false, true, false), + COSMETIC_OPTION("HUD.BButton", "B Button", COSMETICS_GROUP_HUD, ColorRGBA8( 0, 150, 0, 255), false, true, false), + COSMETIC_OPTION("HUD.CButtons", "C Buttons", COSMETICS_GROUP_HUD, ColorRGBA8(255, 160, 0, 255), false, true, false), + COSMETIC_OPTION("HUD.CUpButton", "C Up Button", COSMETICS_GROUP_HUD, ColorRGBA8(255, 160, 0, 255), false, true, true), + COSMETIC_OPTION("HUD.CDownButton", "C Down Button", COSMETICS_GROUP_HUD, ColorRGBA8(255, 160, 0, 255), false, true, true), + COSMETIC_OPTION("HUD.CLeftButton", "C Left Button", COSMETICS_GROUP_HUD, ColorRGBA8(255, 160, 0, 255), false, true, true), + COSMETIC_OPTION("HUD.CRightButton", "C Right Button", COSMETICS_GROUP_HUD, ColorRGBA8(255, 160, 0, 255), false, true, true), + COSMETIC_OPTION("HUD.StartButton", "Start Button", COSMETICS_GROUP_HUD, ColorRGBA8(200, 0, 0, 255), false, true, false), + COSMETIC_OPTION("HUD.Dpad", "Dpad", COSMETICS_GROUP_HUD, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("HUD.KeyCount", "Key Count", COSMETICS_GROUP_HUD, ColorRGBA8(200, 230, 255, 255), false, true, true), + COSMETIC_OPTION("HUD.StoneOfAgony", "Stone of Agony", COSMETICS_GROUP_HUD, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("HUD.Minimap", "Minimap", COSMETICS_GROUP_HUD, ColorRGBA8( 0, 255, 255, 255), false, true, false), + COSMETIC_OPTION("HUD.MinimapPosition", "Minimap Position", COSMETICS_GROUP_HUD, ColorRGBA8(200, 255, 0, 255), false, true, true), + COSMETIC_OPTION("HUD.MinimapEntrance", "Minimap Entrance", COSMETICS_GROUP_HUD, ColorRGBA8(200, 0, 0, 255), false, true, true), + COSMETIC_OPTION("HUD.EnemyHealthBar", "Enemy Health Bar", COSMETICS_GROUP_HUD, ColorRGBA8(255, 0, 0, 255), true, true, false), + COSMETIC_OPTION("HUD.EnemyHealthBorder", "Enemy Health Border", COSMETICS_GROUP_HUD, ColorRGBA8(255, 255, 255, 255), true, true, true), + COSMETIC_OPTION("HUD.NameTagActorText", "Nametag Text", COSMETICS_GROUP_HUD, ColorRGBA8(255, 255, 255, 255), true, true, false), + COSMETIC_OPTION("HUD.NameTagActorBackground", "Nametag Background", COSMETICS_GROUP_HUD, ColorRGBA8( 0, 0, 0, 80), true, true, true), + COSMETIC_OPTION("HUD.TitleCard.Map", "Map Title Card", COSMETICS_GROUP_HUD, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("HUD.TitleCard.Boss", "Boss Title Card", COSMETICS_GROUP_HUD, ColorRGBA8(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Kaleido.ItemSelA", "Item Select Color", COSMETICS_GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, false), - COSMETIC_OPTION("Kaleido.ItemSelB", "Item Select Color B", COSMETICS_GROUP_KALEIDO, ImVec4(70, 100, 130, 255), false, true, true), - COSMETIC_OPTION("Kaleido.ItemSelC", "Item Select Color C", COSMETICS_GROUP_KALEIDO, ImVec4(70, 100, 130, 255), false, true, true), - COSMETIC_OPTION("Kaleido.ItemSelD", "Item Select Color D", COSMETICS_GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, true), + #define MESSAGE_COSMETIC_OPTION(id, label, r, g, b) COSMETIC_OPTION("Message." id, label, COSMETICS_GROUP_MESSAGE, ColorRGBA8(r, g, b, 255), false, true, true) - COSMETIC_OPTION("Kaleido.EquipSelA", "Equip Select Color", COSMETICS_GROUP_KALEIDO, ImVec4(10, 50, 40, 255), false, true, false), - COSMETIC_OPTION("Kaleido.EquipSelB", "Equip Select Color B", COSMETICS_GROUP_KALEIDO, ImVec4(90, 100, 60, 255), false, true, true), - COSMETIC_OPTION("Kaleido.EquipSelC", "Equip Select Color C", COSMETICS_GROUP_KALEIDO, ImVec4(90, 100, 60, 255), false, true, true), - COSMETIC_OPTION("Kaleido.EquipSelD", "Equip Select Color D", COSMETICS_GROUP_KALEIDO, ImVec4(10, 50, 80, 255), false, true, true), + MESSAGE_COSMETIC_OPTION("Default.Normal", "Message Default Color", 255, 255, 255), + MESSAGE_COSMETIC_OPTION("Default.NoneNoShadow", "Message Default (None No Shadow) Color", 0, 0, 0), + MESSAGE_COSMETIC_OPTION("Red.Normal", "Message Red Color", 255, 60, 60), + MESSAGE_COSMETIC_OPTION("Red.Wooden", "Message Red (Wooden) Color", 255, 120, 0), + MESSAGE_COSMETIC_OPTION("Adjustable.Normal", "Message Adjustable Color", 70, 255, 80), + MESSAGE_COSMETIC_OPTION("Adjustable.Wooden", "Message Adjustable (Wooden) Color", 70, 255, 80), + MESSAGE_COSMETIC_OPTION("Blue.Normal", "Message Blue Color", 80, 90, 255), + MESSAGE_COSMETIC_OPTION("Blue.Wooden", "Message Blue (Wooden) Color", 80, 110, 255), + MESSAGE_COSMETIC_OPTION("LightBlue.Normal", "Message Light Blue Color", 100, 180, 255), + MESSAGE_COSMETIC_OPTION("LightBlue.Wooden", "Message Light Blue (Wooden) Color", 90, 180, 255), + MESSAGE_COSMETIC_OPTION("LightBlue.LightBlue.NoneNoShadow", "Message Light Blue (None No Shadow) Color", 80, 150, 180), + MESSAGE_COSMETIC_OPTION("Purple.Normal", "Message Purple Color", 255, 150, 180), + MESSAGE_COSMETIC_OPTION("Purple.Wooden", "Message Purple (Wooden) Color", 210, 100, 255), + MESSAGE_COSMETIC_OPTION("Yellow.Normal", "Message Yellow Color", 255, 255, 50), + MESSAGE_COSMETIC_OPTION("Yellow.Wooden", "Message Yellow (Wooden) Color", 255, 255, 30), + MESSAGE_COSMETIC_OPTION("Black", "Message Black Color", 0, 0, 0), - COSMETIC_OPTION("Kaleido.MapSelDunA", "Map Dungeon Color", COSMETICS_GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, true), - COSMETIC_OPTION("Kaleido.MapSelDunB", "Map Dungeon Color B", COSMETICS_GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, true), - COSMETIC_OPTION("Kaleido.MapSelDunC", "Map Dungeon Color C", COSMETICS_GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, true), - COSMETIC_OPTION("Kaleido.MapSelDunD", "Map Dungeon Color D", COSMETICS_GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, true), + #undef MESSAGE_COSMETIC_OPTION - COSMETIC_OPTION("Kaleido.QuestStatusA", "Quest Status Color", COSMETICS_GROUP_KALEIDO, ImVec4(80, 80, 50, 255), false, true, false), - COSMETIC_OPTION("Kaleido.QuestStatusB", "Quest Status Color B", COSMETICS_GROUP_KALEIDO, ImVec4(120, 120, 70, 255), false, true, true), - COSMETIC_OPTION("Kaleido.QuestStatusC", "Quest Status Color C", COSMETICS_GROUP_KALEIDO, ImVec4(120, 120, 70, 255), false, true, true), - COSMETIC_OPTION("Kaleido.QuestStatusD", "Quest Status Color D", COSMETICS_GROUP_KALEIDO, ImVec4(80, 80, 50, 255), false, true, true), + COSMETIC_OPTION("Kaleido.ItemSelA", "Item Select Color", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 10, 50, 80, 255), false, true, false), + COSMETIC_OPTION("Kaleido.ItemSelB", "Item Select Color B", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 70, 100, 130, 255), false, true, true), + COSMETIC_OPTION("Kaleido.ItemSelC", "Item Select Color C", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 70, 100, 130, 255), false, true, true), + COSMETIC_OPTION("Kaleido.ItemSelD", "Item Select Color D", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 10, 50, 80, 255), false, true, true), - COSMETIC_OPTION("Kaleido.MapSelectA", "Map Color", COSMETICS_GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, false), - COSMETIC_OPTION("Kaleido.MapSelectB", "Map Color B", COSMETICS_GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, true), - COSMETIC_OPTION("Kaleido.MapSelectC", "Map Color C", COSMETICS_GROUP_KALEIDO, ImVec4(140, 60, 60, 255), false, true, true), - COSMETIC_OPTION("Kaleido.MapSelectD", "Map Color D", COSMETICS_GROUP_KALEIDO, ImVec4(80, 40, 30, 255), false, true, true), + COSMETIC_OPTION("Kaleido.EquipSelA", "Equip Select Color", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 10, 50, 40, 255), false, true, false), + COSMETIC_OPTION("Kaleido.EquipSelB", "Equip Select Color B", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 90, 100, 60, 255), false, true, true), + COSMETIC_OPTION("Kaleido.EquipSelC", "Equip Select Color C", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 90, 100, 60, 255), false, true, true), + COSMETIC_OPTION("Kaleido.EquipSelD", "Equip Select Color D", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 10, 50, 80, 255), false, true, true), - COSMETIC_OPTION("Kaleido.SaveA", "Save Color", COSMETICS_GROUP_KALEIDO, ImVec4(50, 50, 50, 255), false, true, false), - COSMETIC_OPTION("Kaleido.SaveB", "Save Color B", COSMETICS_GROUP_KALEIDO, ImVec4(110, 110, 110, 255), false, true, true), - COSMETIC_OPTION("Kaleido.SaveC", "Save Color C", COSMETICS_GROUP_KALEIDO, ImVec4(110, 110, 110, 255), false, true, true), - COSMETIC_OPTION("Kaleido.SaveD", "Save Color D", COSMETICS_GROUP_KALEIDO, ImVec4(50, 50, 50, 255), false, true, true), - - COSMETIC_OPTION("Kaleido.NamePanel", "Name Panel", COSMETICS_GROUP_KALEIDO, ImVec4(90,100,130,255), true, true, false), - - COSMETIC_OPTION("Title.FileChoose", "File Choose", COSMETICS_GROUP_TITLE, ImVec4(100, 150, 255, 255), false, true, false), - COSMETIC_OPTION("Title.NintendoLogo", "Nintendo Logo", COSMETICS_GROUP_TITLE, ImVec4( 0, 0, 255, 255), false, true, true), - COSMETIC_OPTION("Title.N64LogoRed", "N64 Red", COSMETICS_GROUP_TITLE, ImVec4(150, 0, 0, 255), false, true, true), - COSMETIC_OPTION("Title.N64LogoBlue", "N64 Blue", COSMETICS_GROUP_TITLE, ImVec4( 0, 50, 150, 255), false, true, true), - COSMETIC_OPTION("Title.N64LogoGreen", "N64 Green", COSMETICS_GROUP_TITLE, ImVec4( 50, 100, 0, 255), false, true, true), - COSMETIC_OPTION("Title.N64LogoYellow", "N64 Yellow", COSMETICS_GROUP_TITLE, ImVec4(200, 150, 0, 255), false, true, true), - // COSMETIC_OPTION("Title.FirePrimary", "Title Fire Primary", COSMETICS_GROUP_TITLE, ImVec4(255, 255, 170, 255), false, true, false), // Todo (Cosmetics): Kinda complicated - // COSMETIC_OPTION("Title.FireSecondary", "Title Fire Secondary", COSMETICS_GROUP_TITLE, ImVec4(255, 100, 0, 255), false, true, true), // Todo (Cosmetics): Kinda complicated - - COSMETIC_OPTION("Arrows.NormalPrimary", "Normal Primary", COSMETICS_GROUP_ARROWS, ImVec4( 0, 150, 0, 0), false, true, false), - COSMETIC_OPTION("Arrows.NormalSecondary", "Normal Secondary", COSMETICS_GROUP_ARROWS, ImVec4(255, 255, 170, 255), false, true, true), - COSMETIC_OPTION("Arrows.FirePrimary", "Fire Primary", COSMETICS_GROUP_ARROWS, ImVec4(255, 200, 0, 0), false, true, false), - COSMETIC_OPTION("Arrows.FireSecondary", "Fire Secondary", COSMETICS_GROUP_ARROWS, ImVec4(255, 0, 0, 255), false, true, true), - COSMETIC_OPTION("Arrows.IcePrimary", "Ice Primary", COSMETICS_GROUP_ARROWS, ImVec4( 0, 0, 255, 255), false, true, false), - COSMETIC_OPTION("Arrows.IceSecondary", "Ice Secondary", COSMETICS_GROUP_ARROWS, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("Arrows.LightPrimary", "Light Primary", COSMETICS_GROUP_ARROWS, ImVec4(255, 255, 0, 255), false, true, false), - COSMETIC_OPTION("Arrows.LightSecondary", "Light Secondary", COSMETICS_GROUP_ARROWS, ImVec4(255, 255, 170, 0), false, true, true), - - // COSMETIC_OPTION("Magic.DinsPrimary", "Din's Primary", COSMETICS_GROUP_MAGIC, ImVec4(255, 255, 255, 255), false, true, false), - // COSMETIC_OPTION("Magic.DinsSecondary", "Din's Secondary", COSMETICS_GROUP_MAGIC, ImVec4(255, 255, 255, 255), false, true, true), - // COSMETIC_OPTION("Magic.FaroresPrimary", "Farore's Primary", COSMETICS_GROUP_MAGIC, ImVec4(255, 255, 255, 255), false, true, false), // Todo (Cosmetics): Implement - // COSMETIC_OPTION("Magic.FaroresSecondary", "Farore's Secondary", COSMETICS_GROUP_MAGIC, ImVec4(255, 255, 255, 255), false, true, true), // Todo (Cosmetics): Implement - // COSMETIC_OPTION("Magic.NayrusPrimary", "Nayru's Primary", COSMETICS_GROUP_MAGIC, ImVec4(255, 255, 255, 255), false, true, false), - // COSMETIC_OPTION("Magic.NayrusSecondary", "Nayru's Secondary", COSMETICS_GROUP_MAGIC, ImVec4(255, 255, 255, 255), false, true, true), - - COSMETIC_OPTION("SpinAttack.Level1Primary", "Level 1 Primary", COSMETICS_GROUP_SPIN_ATTACK, ImVec4(170, 255, 255, 255), false, true, true), - COSMETIC_OPTION("SpinAttack.Level1Secondary", "Level 1 Secondary", COSMETICS_GROUP_SPIN_ATTACK, ImVec4( 0, 100, 255, 255), false, true, false), - COSMETIC_OPTION("SpinAttack.Level2Primary", "Level 2 Primary", COSMETICS_GROUP_SPIN_ATTACK, ImVec4(255, 255, 170, 255), false, true, true), - COSMETIC_OPTION("SpinAttack.Level2Secondary", "Level 2 Secondary", COSMETICS_GROUP_SPIN_ATTACK, ImVec4(255, 100, 0, 255), false, true, false), - - COSMETIC_OPTION("Trails.Bombchu", "Bombchu", COSMETICS_GROUP_TRAILS, ImVec4(250, 0, 0, 255), false, true, true), - COSMETIC_OPTION("Trails.Boomerang", "Boomerang", COSMETICS_GROUP_TRAILS, ImVec4(255, 255, 100, 255), false, true, true), - COSMETIC_OPTION("Trails.KokiriSword", "Kokiri Sword", COSMETICS_GROUP_TRAILS, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Trails.MasterSword", "Master Sword", COSMETICS_GROUP_TRAILS, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Trails.BiggoronSword", "Biggoron Sword", COSMETICS_GROUP_TRAILS, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("Trails.Stick", "Stick", COSMETICS_GROUP_TRAILS, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("Trails.Hammer", "Hammer", COSMETICS_GROUP_TRAILS, ImVec4(255, 255, 255, 255), false, true, true), - - COSMETIC_OPTION("World.BlockOfTime", "Block of Time", COSMETICS_GROUP_WORLD, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("World.Moon", "Moon", COSMETICS_GROUP_WORLD, ImVec4(240, 255, 180, 255), false, true, true), - COSMETIC_OPTION("World.GossipStone", "Gossip Stone", COSMETICS_GROUP_WORLD, ImVec4(200, 200, 200, 255), false, true, true), - COSMETIC_OPTION("World.RedIce", "Red Ice", COSMETICS_GROUP_WORLD, ImVec4(255, 0, 0, 255), false, true, false), - COSMETIC_OPTION("World.MysteryItem", "Mystery Item", COSMETICS_GROUP_WORLD, ImVec4(0, 60, 100, 255), false, true, false), - - COSMETIC_OPTION("Navi.IdlePrimary", "Idle Primary", COSMETICS_GROUP_NAVI, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Navi.IdleSecondary", "Idle Secondary", COSMETICS_GROUP_NAVI, ImVec4( 0, 0, 255, 0), false, true, true), - COSMETIC_OPTION("Navi.NPCPrimary", "NPC Primary", COSMETICS_GROUP_NAVI, ImVec4(150, 150, 255, 255), false, true, false), - COSMETIC_OPTION("Navi.NPCSecondary", "NPC Secondary", COSMETICS_GROUP_NAVI, ImVec4(150, 150, 255, 0), false, true, true), - COSMETIC_OPTION("Navi.EnemyPrimary", "Enemy Primary", COSMETICS_GROUP_NAVI, ImVec4(255, 255, 0, 255), false, true, false), - COSMETIC_OPTION("Navi.EnemySecondary", "Enemy Secondary", COSMETICS_GROUP_NAVI, ImVec4(200, 155, 0, 0), false, true, true), - COSMETIC_OPTION("Navi.PropsPrimary", "Props Primary", COSMETICS_GROUP_NAVI, ImVec4( 0, 255, 0, 255), false, true, false), - COSMETIC_OPTION("Navi.PropsSecondary", "Props Secondary", COSMETICS_GROUP_NAVI, ImVec4( 0, 255, 0, 0), false, true, true), + COSMETIC_OPTION("Kaleido.MapSelDunA", "Map Dungeon Color", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 80, 40, 30, 255), false, true, true), + COSMETIC_OPTION("Kaleido.MapSelDunB", "Map Dungeon Color B", COSMETICS_GROUP_KALEIDO, ColorRGBA8(140, 60, 60, 255), false, true, true), + COSMETIC_OPTION("Kaleido.MapSelDunC", "Map Dungeon Color C", COSMETICS_GROUP_KALEIDO, ColorRGBA8(140, 60, 60, 255), false, true, true), + COSMETIC_OPTION("Kaleido.MapSelDunD", "Map Dungeon Color D", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 80, 40, 30, 255), false, true, true), - COSMETIC_OPTION("Ivan.IdlePrimary", "Ivan Idle Primary", COSMETICS_GROUP_IVAN, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("Ivan.IdleSecondary", "Ivan Idle Secondary", COSMETICS_GROUP_IVAN, ImVec4( 0, 255, 0, 255), false, true, true), + COSMETIC_OPTION("Kaleido.QuestStatusA", "Quest Status Color", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 80, 80, 50, 255), false, true, false), + COSMETIC_OPTION("Kaleido.QuestStatusB", "Quest Status Color B", COSMETICS_GROUP_KALEIDO, ColorRGBA8(120, 120, 70, 255), false, true, true), + COSMETIC_OPTION("Kaleido.QuestStatusC", "Quest Status Color C", COSMETICS_GROUP_KALEIDO, ColorRGBA8(120, 120, 70, 255), false, true, true), + COSMETIC_OPTION("Kaleido.QuestStatusD", "Quest Status Color D", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 80, 80, 50, 255), false, true, true), - COSMETIC_OPTION("NPC.FireKeesePrimary", "Fire Keese Primary", COSMETICS_GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("NPC.FireKeeseSecondary", "Fire Keese Secondary", COSMETICS_GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("NPC.IceKeesePrimary", "Ice Keese Primary", COSMETICS_GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("NPC.IceKeeseSecondary", "Ice Keese Secondary", COSMETICS_GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Kaleido.MapSelectA", "Map Color", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 80, 40, 30, 255), false, true, false), + COSMETIC_OPTION("Kaleido.MapSelectB", "Map Color B", COSMETICS_GROUP_KALEIDO, ColorRGBA8(140, 60, 60, 255), false, true, true), + COSMETIC_OPTION("Kaleido.MapSelectC", "Map Color C", COSMETICS_GROUP_KALEIDO, ColorRGBA8(140, 60, 60, 255), false, true, true), + COSMETIC_OPTION("Kaleido.MapSelectD", "Map Color D", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 80, 40, 30, 255), false, true, true), + + COSMETIC_OPTION("Kaleido.SaveA", "Save Color", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 50, 50, 50, 255), false, true, false), + COSMETIC_OPTION("Kaleido.SaveB", "Save Color B", COSMETICS_GROUP_KALEIDO, ColorRGBA8(110, 110, 110, 255), false, true, true), + COSMETIC_OPTION("Kaleido.SaveC", "Save Color C", COSMETICS_GROUP_KALEIDO, ColorRGBA8(110, 110, 110, 255), false, true, true), + COSMETIC_OPTION("Kaleido.SaveD", "Save Color D", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 50, 50, 50, 255), false, true, true), + + COSMETIC_OPTION("Kaleido.NamePanel", "Name Panel", COSMETICS_GROUP_KALEIDO, ColorRGBA8( 90, 100, 130, 255), true, true, false), + + COSMETIC_OPTION("Title.FileChoose", "File Choose", COSMETICS_GROUP_TITLE, ColorRGBA8(100, 150, 255, 255), false, true, false), + COSMETIC_OPTION("Title.NintendoLogo", "Nintendo Logo", COSMETICS_GROUP_TITLE, ColorRGBA8( 0, 0, 255, 255), false, true, true), + COSMETIC_OPTION("Title.N64LogoRed", "N64 Red", COSMETICS_GROUP_TITLE, ColorRGBA8(150, 0, 0, 255), false, true, true), + COSMETIC_OPTION("Title.N64LogoBlue", "N64 Blue", COSMETICS_GROUP_TITLE, ColorRGBA8( 0, 50, 150, 255), false, true, true), + COSMETIC_OPTION("Title.N64LogoGreen", "N64 Green", COSMETICS_GROUP_TITLE, ColorRGBA8( 50, 100, 0, 255), false, true, true), + COSMETIC_OPTION("Title.N64LogoYellow", "N64 Yellow", COSMETICS_GROUP_TITLE, ColorRGBA8(200, 150, 0, 255), false, true, true), + + /* Todo (Cosmetics): Kinda complicated + COSMETIC_OPTION("Title.FirePrimary", "Title Fire Primary", COSMETICS_GROUP_TITLE, ColorRGBA8(255, 255, 170, 255), false, true, false), + COSMETIC_OPTION("Title.FireSecondary", "Title Fire Secondary", COSMETICS_GROUP_TITLE, ColorRGBA8(255, 100, 0, 255), false, true, true), + */ + COSMETIC_OPTION("Title.Copyright", "Copyright Text", COSMETICS_GROUP_TITLE, ColorRGBA8(255, 255, 255, 255), true, true, false), + + COSMETIC_OPTION("Arrows.NormalPrimary", "Normal Primary", COSMETICS_GROUP_ARROWS, ColorRGBA8( 0, 150, 0, 0), false, true, false), + COSMETIC_OPTION("Arrows.NormalSecondary", "Normal Secondary", COSMETICS_GROUP_ARROWS, ColorRGBA8(255, 255, 170, 255), false, true, true), + COSMETIC_OPTION("Arrows.FirePrimary", "Fire Primary", COSMETICS_GROUP_ARROWS, ColorRGBA8(255, 200, 0, 0), false, true, false), + COSMETIC_OPTION("Arrows.FireSecondary", "Fire Secondary", COSMETICS_GROUP_ARROWS, ColorRGBA8(255, 0, 0, 255), false, true, true), + COSMETIC_OPTION("Arrows.IcePrimary", "Ice Primary", COSMETICS_GROUP_ARROWS, ColorRGBA8( 0, 0, 255, 255), false, true, false), + COSMETIC_OPTION("Arrows.IceSecondary", "Ice Secondary", COSMETICS_GROUP_ARROWS, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Arrows.LightPrimary", "Light Primary", COSMETICS_GROUP_ARROWS, ColorRGBA8(255, 255, 0, 255), false, true, false), + COSMETIC_OPTION("Arrows.LightSecondary", "Light Secondary", COSMETICS_GROUP_ARROWS, ColorRGBA8(255, 255, 170, 0), false, true, true), + + COSMETIC_OPTION("Magic.DinsPrimary", "Din's Primary", COSMETICS_GROUP_MAGIC, ColorRGBA8(255, 200, 0, 255), false, true, false), + COSMETIC_OPTION("Magic.DinsSecondary", "Din's Secondary", COSMETICS_GROUP_MAGIC, ColorRGBA8(255, 0, 0, 255), false, true, true), + COSMETIC_OPTION("Magic.FaroresPrimary", "Farore's Primary", COSMETICS_GROUP_MAGIC, ColorRGBA8(255, 255, 0, 255), false, true, false), + COSMETIC_OPTION("Magic.FaroresSecondary", "Farore's Secondary", COSMETICS_GROUP_MAGIC, ColorRGBA8(100, 200, 0, 255), false, true, true), + COSMETIC_OPTION("Magic.NayrusPrimary", "Nayru's Primary", COSMETICS_GROUP_MAGIC, ColorRGBA8(170, 255, 255, 255), false, true, false), + COSMETIC_OPTION("Magic.NayrusSecondary", "Nayru's Secondary", COSMETICS_GROUP_MAGIC, ColorRGBA8( 0, 100, 255, 255), false, true, true), + + COSMETIC_OPTION("SpinAttack.Level1Primary", "Level 1 Primary", COSMETICS_GROUP_SPIN_ATTACK, ColorRGBA8(170, 255, 255, 255), false, true, true), + COSMETIC_OPTION("SpinAttack.Level1Secondary", "Level 1 Secondary", COSMETICS_GROUP_SPIN_ATTACK, ColorRGBA8( 0, 100, 255, 255), false, true, false), + COSMETIC_OPTION("SpinAttack.Level2Primary", "Level 2 Primary", COSMETICS_GROUP_SPIN_ATTACK, ColorRGBA8(255, 255, 170, 255), false, true, true), + COSMETIC_OPTION("SpinAttack.Level2Secondary", "Level 2 Secondary", COSMETICS_GROUP_SPIN_ATTACK, ColorRGBA8(255, 100, 0, 255), false, true, false), + + COSMETIC_OPTION("Trails.Bombchu", "Bombchu", COSMETICS_GROUP_TRAILS, ColorRGBA8(250, 0, 0, 255), false, true, true), + COSMETIC_OPTION("Trails.Boomerang", "Boomerang", COSMETICS_GROUP_TRAILS, ColorRGBA8(255, 255, 100, 255), false, true, true), + COSMETIC_OPTION("Trails.KokiriSword", "Kokiri Sword", COSMETICS_GROUP_TRAILS, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("Trails.MasterSword", "Master Sword", COSMETICS_GROUP_TRAILS, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("Trails.BiggoronSword", "Biggoron Sword", COSMETICS_GROUP_TRAILS, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Trails.Stick", "Stick", COSMETICS_GROUP_TRAILS, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("Trails.Hammer", "Hammer", COSMETICS_GROUP_TRAILS, ColorRGBA8(255, 255, 255, 255), false, true, true), + + COSMETIC_OPTION("World.BlockOfTime", "Block of Time", COSMETICS_GROUP_WORLD, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("World.Moon", "Moon", COSMETICS_GROUP_WORLD, ColorRGBA8(240, 255, 180, 255), false, true, true), + COSMETIC_OPTION("World.GossipStone", "Gossip Stone", COSMETICS_GROUP_WORLD, ColorRGBA8(200, 200, 200, 255), false, true, true), + COSMETIC_OPTION("World.RedIce", "Red Ice", COSMETICS_GROUP_WORLD, ColorRGBA8(255, 0, 0, 255), false, true, false), + COSMETIC_OPTION("World.MysteryItem", "Mystery Item", COSMETICS_GROUP_WORLD, ColorRGBA8( 0, 60, 100, 255), false, true, false), + + COSMETIC_OPTION("Navi.IdlePrimary", "Idle Primary", COSMETICS_GROUP_NAVI, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("Navi.IdleSecondary", "Idle Secondary", COSMETICS_GROUP_NAVI, ColorRGBA8( 0, 0, 255, 0), false, true, true), + COSMETIC_OPTION("Navi.NPCPrimary", "NPC Primary", COSMETICS_GROUP_NAVI, ColorRGBA8(150, 150, 255, 255), false, true, false), + COSMETIC_OPTION("Navi.NPCSecondary", "NPC Secondary", COSMETICS_GROUP_NAVI, ColorRGBA8(150, 150, 255, 0), false, true, true), + COSMETIC_OPTION("Navi.EnemyPrimary", "Enemy Primary", COSMETICS_GROUP_NAVI, ColorRGBA8(255, 255, 0, 255), false, true, false), + COSMETIC_OPTION("Navi.EnemySecondary", "Enemy Secondary", COSMETICS_GROUP_NAVI, ColorRGBA8(200, 155, 0, 0), false, true, true), + COSMETIC_OPTION("Navi.PropsPrimary", "Props Primary", COSMETICS_GROUP_NAVI, ColorRGBA8( 0, 255, 0, 255), false, true, false), + COSMETIC_OPTION("Navi.PropsSecondary", "Props Secondary", COSMETICS_GROUP_NAVI, ColorRGBA8( 0, 255, 0, 0), false, true, true), + + COSMETIC_OPTION("Ivan.IdlePrimary", "Ivan Idle Primary", COSMETICS_GROUP_IVAN, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("Ivan.IdleSecondary", "Ivan Idle Secondary", COSMETICS_GROUP_IVAN, ColorRGBA8( 0, 255, 0, 255), false, true, true), + + COSMETIC_OPTION("NPC.FireKeesePrimary", "Fire Keese Primary", COSMETICS_GROUP_NPC, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("NPC.FireKeeseSecondary", "Fire Keese Secondary", COSMETICS_GROUP_NPC, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("NPC.IceKeesePrimary", "Ice Keese Primary", COSMETICS_GROUP_NPC, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("NPC.IceKeeseSecondary", "Ice Keese Secondary", COSMETICS_GROUP_NPC, ColorRGBA8(255, 255, 255, 255), false, true, true), // Todo (Cosmetics): Health fairy - COSMETIC_OPTION("NPC.Dog1", "Dog 1", COSMETICS_GROUP_NPC, ImVec4(255, 255, 200, 255), false, true, true), - COSMETIC_OPTION("NPC.Dog2", "Dog 2", COSMETICS_GROUP_NPC, ImVec4(150, 100, 50, 255), false, true, true), - COSMETIC_OPTION("NPC.GoldenSkulltula", "Golden Skulltula", COSMETICS_GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, false), - COSMETIC_OPTION("NPC.Kokiri", "Kokiri", COSMETICS_GROUP_NPC, ImVec4(255, 0, 0, 255), false, true, false), - COSMETIC_OPTION("NPC.Gerudo", "Gerudo", COSMETICS_GROUP_NPC, ImVec4( 90, 0, 140, 255), false, true, false), - COSMETIC_OPTION("NPC.MetalTrap", "Metal Trap", COSMETICS_GROUP_NPC, ImVec4(255, 255, 255, 255), false, true, true), - COSMETIC_OPTION("NPC.IronKnuckles", "Iron Knuckles", COSMETICS_GROUP_NPC, ImVec4(245, 255, 205, 255), false, true, false), + COSMETIC_OPTION("NPC.Dog1", "Dog 1", COSMETICS_GROUP_NPC, ColorRGBA8(255, 255, 200, 255), false, true, true), + COSMETIC_OPTION("NPC.Dog2", "Dog 2", COSMETICS_GROUP_NPC, ColorRGBA8(150, 100, 50, 255), false, true, true), + COSMETIC_OPTION("NPC.GoldenSkulltula", "Golden Skulltula", COSMETICS_GROUP_NPC, ColorRGBA8(255, 255, 255, 255), false, true, false), + COSMETIC_OPTION("NPC.Kokiri", "Kokiri", COSMETICS_GROUP_NPC, ColorRGBA8(255, 0, 0, 255), false, true, false), + COSMETIC_OPTION("NPC.Gerudo", "Gerudo", COSMETICS_GROUP_NPC, ColorRGBA8( 90, 0, 140, 255), false, true, false), + COSMETIC_OPTION("NPC.MetalTrap", "Metal Trap", COSMETICS_GROUP_NPC, ColorRGBA8(255, 255, 255, 255), false, true, true), + COSMETIC_OPTION("NPC.IronKnuckles", "Iron Knuckles", COSMETICS_GROUP_NPC, ColorRGBA8(245, 255, 205, 255), false, true, false), }; static const char* MarginCvarList[] { - CVAR_COSMETIC("HUD.Hearts"), CVAR_COSMETIC("HUD.HeartsCount"), CVAR_COSMETIC("HUD.MagicBar"), CVAR_COSMETIC("HUD.VisualSoA"), CVAR_COSMETIC("HUD.BButton"), CVAR_COSMETIC("HUD.AButton"), CVAR_COSMETIC("HUD.StartButton"), - CVAR_COSMETIC("HUD.CUpButton"), CVAR_COSMETIC("HUD.CDownButton"), CVAR_COSMETIC("HUD.CLeftButton"), CVAR_COSMETIC("HUD.CRightButton"), CVAR_COSMETIC("HUD.Dpad"), CVAR_COSMETIC("HUD.Minimap"), - CVAR_COSMETIC("HUD.SmallKey"), CVAR_COSMETIC("HUD.Rupees"), CVAR_COSMETIC("HUD.Carrots"), CVAR_COSMETIC("HUD.Timers"), CVAR_COSMETIC("HUD.ArcheryScore"), CVAR_COSMETIC("HUD.TitleCard.Map"), CVAR_COSMETIC("HUD.TitleCard.Boss"), CVAR_COSMETIC("HUD.IGT") + CVAR_COSMETIC("HUD.Hearts"), + CVAR_COSMETIC("HUD.HeartsCount"), + CVAR_COSMETIC("HUD.MagicBar"), + CVAR_COSMETIC("HUD.VisualSoA"), + CVAR_COSMETIC("HUD.BButton"), + CVAR_COSMETIC("HUD.AButton"), + CVAR_COSMETIC("HUD.StartButton"), + CVAR_COSMETIC("HUD.CUpButton"), + CVAR_COSMETIC("HUD.CDownButton"), + CVAR_COSMETIC("HUD.CLeftButton"), + CVAR_COSMETIC("HUD.CRightButton"), + CVAR_COSMETIC("HUD.Dpad"), + CVAR_COSMETIC("HUD.Minimap"), + CVAR_COSMETIC("HUD.SmallKey"), + CVAR_COSMETIC("HUD.Rupees"), + CVAR_COSMETIC("HUD.Carrots"), + CVAR_COSMETIC("HUD.Timers"), + CVAR_COSMETIC("HUD.ArcheryScore"), + CVAR_COSMETIC("HUD.TitleCard.Map"), + CVAR_COSMETIC("HUD.TitleCard.Boss"), + CVAR_COSMETIC("HUD.IGT") }; -static const char* MarginCvarNonAnchor[]{ CVAR_COSMETIC("HUD.Carrots"), CVAR_COSMETIC("HUD.Timers"), CVAR_COSMETIC("HUD.ArcheryScore"), CVAR_COSMETIC("HUD.TitleCard.Map"),CVAR_COSMETIC("HUD.TitleCard.Boss") }; -ImVec4 GetRandomValue(int MaximumPossible){ - ImVec4 NewColor; - unsigned long range = 255 - 0; +static const char* MarginCvarNonAnchor[] { + CVAR_COSMETIC("HUD.Carrots"), + CVAR_COSMETIC("HUD.Timers"), + CVAR_COSMETIC("HUD.ArcheryScore"), + CVAR_COSMETIC("HUD.TitleCard.Map"), + CVAR_COSMETIC("HUD.TitleCard.Boss") +}; + +ImVec4 GetRandomValue() { #if !defined(__SWITCH__) && !defined(__WIIU__) std::random_device rd; std::mt19937 rng(rd()); @@ -379,10 +448,11 @@ ImVec4 GetRandomValue(int MaximumPossible){ std::mt19937_64 rng(seed); #endif std::uniform_int_distribution dist(0, 255 - 1); - - NewColor.x = (float)(dist(rng)) / 255; - NewColor.y = (float)(dist(rng)) / 255; - NewColor.z = (float)(dist(rng)) / 255; + + ImVec4 NewColor; + NewColor.x = (float)(dist(rng)) / 255.0f; + NewColor.y = (float)(dist(rng)) / 255.0f; + NewColor.z = (float)(dist(rng)) / 255.0f; return NewColor; } @@ -394,24 +464,22 @@ void SetMarginAll(const char* ButtonName, bool SetActivated) { std::string cvarPosType = std::string(cvarName).append(".PosType"); std::string cvarNameMargins = std::string(cvarName).append(".UseMargins"); if (CVarGetInteger(cvarPosType.c_str(),0) <= 2 && SetActivated) { //Our element is not Hidden or Non anchor - for (int i = 0; i < arrayLengthNonMargin; i++){ + for (int i = 0; i < arrayLengthNonMargin; i++) { if ((strcmp(cvarName, MarginCvarNonAnchor[i]) == 0) && (CVarGetInteger(cvarPosType.c_str(), 0) == 0)) { //Our element is both in original position and do not have anchor by default so we skip it. CVarSetInteger(cvarNameMargins.c_str(), false); //force set off - } - else if ((strcmp(cvarName, MarginCvarNonAnchor[i]) == 0) && (CVarGetInteger(cvarPosType.c_str(), 0) != 0)) { //Our element is not in original position regarless it has no anchor by default since player made it anchored we can toggle margins + } else if ((strcmp(cvarName, MarginCvarNonAnchor[i]) == 0) && (CVarGetInteger(cvarPosType.c_str(), 0) != 0)) { //Our element is not in original position regarless it has no anchor by default since player made it anchored we can toggle margins CVarSetInteger(cvarNameMargins.c_str(), SetActivated); - } - else if (strcmp(cvarName, MarginCvarNonAnchor[i]) != 0) { //Our elements has an anchor by default so regarless of it's position right now that okay to toggle margins. + } else if (strcmp(cvarName, MarginCvarNonAnchor[i]) != 0) { //Our elements has an anchor by default so regarless of it's position right now that okay to toggle margins. CVarSetInteger(cvarNameMargins.c_str(), SetActivated); } } - } - else { //Since the user requested to turn all margin off no need to do any check there. + } else { //Since the user requested to turn all margin off no need to do any check there. CVarSetInteger(cvarNameMargins.c_str(), SetActivated); } } } } + void ResetPositionAll() { if (ImGui::Button("Reset all positions")) { for (auto cvarName : MarginCvarList) { @@ -431,21 +499,21 @@ void CosmeticsUpdateTick() { float rainbowSpeed = CVarGetFloat(CVAR_COSMETIC("RainbowSpeed"), 0.6f); for (auto& [id, cosmeticOption] : cosmeticOptions) { if (cosmeticOption.supportsRainbow && CVarGetInteger(cosmeticOption.rainbowCvar, 0)) { - float frequency = 2 * M_PI / (360 * rainbowSpeed); + double frequency = 2 * M_PI / (360 * rainbowSpeed); Color_RGBA8 newColor; - newColor.r = sin(frequency * (hue + index) + 0) * 127 + 128; - newColor.g = sin(frequency * (hue + index) + (2 * M_PI / 3)) * 127 + 128; - newColor.b = sin(frequency * (hue + index) + (4 * M_PI / 3)) * 127 + 128; + newColor.r = static_cast(sin(frequency * (hue + index) + 0) * 127) + 128; + newColor.g = static_cast(sin(frequency * (hue + index) + (2 * M_PI / 3)) * 127) + 128; + newColor.b = static_cast(sin(frequency * (hue + index) + (4 * M_PI / 3)) * 127) + 128; newColor.a = 255; // For alpha supported options, retain the last set alpha instead of overwriting if (cosmeticOption.supportsAlpha) { - newColor.a = cosmeticOption.currentColor.w * 255; + newColor.a = static_cast(cosmeticOption.currentColor.w * 255.0f); } - cosmeticOption.currentColor.x = newColor.r / 255.0; - cosmeticOption.currentColor.y = newColor.g / 255.0; - cosmeticOption.currentColor.z = newColor.b / 255.0; - cosmeticOption.currentColor.w = newColor.a / 255.0; + cosmeticOption.currentColor.x = newColor.r / 255.0f; + cosmeticOption.currentColor.y = newColor.g / 255.0f; + cosmeticOption.currentColor.z = newColor.b / 255.0f; + cosmeticOption.currentColor.w = newColor.a / 255.0f; CVarSetColor(cosmeticOption.cvar, newColor); } @@ -453,12 +521,14 @@ void CosmeticsUpdateTick() { // Technically this would work if you replaced "60" with 1 but the hue would be so close it's // indistinguishable, 60 gives us a big enough gap to notice the difference. if (!CVarGetInteger(CVAR_COSMETIC("RainbowSync"), 0)) { - index+= (60 * rainbowSpeed); + index += static_cast(60 * rainbowSpeed); } } ApplyOrResetCustomGfxPatches(false); hue++; - if (hue >= (360 * rainbowSpeed)) hue = 0; + if (hue >= (360 * rainbowSpeed)) { + hue = 0; + } } /* @@ -489,10 +559,23 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { PATCH_GFX(spot15_room_0DL_00C748, "Path12", "gLetItSnow", 23, gsDPSetPrimColor(0, 0, 200, 230, 255, 30)); } + static CosmeticOption& magicFaroresPrimary = cosmeticOptions.at("Magic.FaroresPrimary"); + if (manualChange || CVarGetInteger(magicFaroresPrimary.rainbowCvar, 0)) { + Color_RGBA8 color = CVarGetColor(magicFaroresPrimary.cvar, magicFaroresPrimary.defaultColor); + PATCH_GFX(sInnerCylinderDL, "Magic_FaroresPrimary1", magicFaroresPrimary.changedCvar, 24, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + PATCH_GFX(sOuterCylinderDL, "Magic_FaroresPrimary2", magicFaroresPrimary.changedCvar, 24, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + } + + static CosmeticOption& magicFaroresSecondary = cosmeticOptions.at("Magic.FaroresSecondary"); + if (manualChange || CVarGetInteger(magicFaroresSecondary.rainbowCvar, 0)) { + Color_RGBA8 color = CVarGetColor(magicFaroresSecondary.cvar, magicFaroresSecondary.defaultColor); + PATCH_GFX(sInnerCylinderDL, "Magic_FaroresSecondary1", magicFaroresSecondary.changedCvar, 25, gsDPSetEnvColor(color.r, color.g, color.b, 255)); + PATCH_GFX(sOuterCylinderDL, "Magic_FaroresSecondary2", magicFaroresSecondary.changedCvar, 25, gsDPSetEnvColor(color.r, color.g, color.b, 255)); + } + static CosmeticOption& linkGoronTunic = cosmeticOptions.at("Link.GoronTunic"); if (manualChange || CVarGetInteger(linkGoronTunic.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {linkGoronTunic.defaultColor.x, linkGoronTunic.defaultColor.y, linkGoronTunic.defaultColor.z, linkGoronTunic.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(linkGoronTunic.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(linkGoronTunic.cvar, linkGoronTunic.defaultColor); PATCH_GFX(gGiGoronTunicColorDL, "Link_GoronTunic1", linkGoronTunic.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiGoronCollarColorDL, "Link_GoronTunic2", linkGoronTunic.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r / 2, color.g / 2, color.b / 2, 255)); PATCH_GFX(gGiGoronTunicColorDL, "Link_GoronTunic3", linkGoronTunic.changedCvar, 4, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255)); @@ -501,8 +584,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& linkZoraTunic = cosmeticOptions.at("Link.ZoraTunic"); if (manualChange || CVarGetInteger(linkZoraTunic.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {linkZoraTunic.defaultColor.x, linkZoraTunic.defaultColor.y, linkZoraTunic.defaultColor.z, linkZoraTunic.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(linkZoraTunic.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(linkZoraTunic.cvar, linkZoraTunic.defaultColor); PATCH_GFX(gGiZoraTunicColorDL, "Link_ZoraTunic1", linkZoraTunic.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiZoraCollarColorDL, "Link_ZoraTunic2", linkZoraTunic.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r / 2, color.g / 2, color.b / 2, 255)); PATCH_GFX(gGiZoraTunicColorDL, "Link_ZoraTunic3", linkZoraTunic.changedCvar, 4, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255)); @@ -511,31 +593,29 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& linkHair = cosmeticOptions.at("Link.Hair"); if (manualChange || CVarGetInteger(linkHair.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {linkHair.defaultColor.x, linkHair.defaultColor.y, linkHair.defaultColor.z, linkHair.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(linkHair.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(linkHair.cvar, linkHair.defaultColor); PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair1", linkHair.changedCvar, 10, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); PATCH_GFX(gLinkChildHeadFarDL, "Link_Hair2", linkHair.changedCvar, 10, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultHeadNearDL, "Link_Hair3", linkHair.changedCvar, 10, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultHeadFarDL, "Link_Hair4", linkHair.changedCvar, 10, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); if (manualChange) { - PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair5", linkHair.changedCvar, 46, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair6", linkHair.changedCvar, 54, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair7", linkHair.changedCvar, 136, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair8", linkHair.changedCvar, 162, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildHeadFarDL, "Link_Hair9", linkHair.changedCvar, 101, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildHeadFarDL, "Link_Hair10", linkHair.changedCvar, 118, gsSPGrayscale(false)); - PATCH_GFX(gLinkAdultHeadNearDL, "Link_Hair11", linkHair.changedCvar, 125, gsSPGrayscale(true)); - PATCH_GFX(gLinkAdultHeadNearDL, "Link_Hair12", linkHair.changedCvar, 159, gsSPGrayscale(false)); - PATCH_GFX(gLinkAdultHeadFarDL, "Link_Hair13", linkHair.changedCvar, 102, gsSPGrayscale(true)); - PATCH_GFX(gLinkAdultHeadFarDL, "Link_Hair14", linkHair.changedCvar, 122, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair5", linkHair.changedCvar, 46, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair6", linkHair.changedCvar, 54, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair7", linkHair.changedCvar, 136, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildHeadNearDL, "Link_Hair8", linkHair.changedCvar, 162, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildHeadFarDL, "Link_Hair9", linkHair.changedCvar, 101, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildHeadFarDL, "Link_Hair10", linkHair.changedCvar, 118, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultHeadNearDL, "Link_Hair11", linkHair.changedCvar, 125, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultHeadNearDL, "Link_Hair12", linkHair.changedCvar, 159, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultHeadFarDL, "Link_Hair13", linkHair.changedCvar, 102, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultHeadFarDL, "Link_Hair14", linkHair.changedCvar, 122, gsSPGrayscale(false)); } } static CosmeticOption& linkLinen = cosmeticOptions.at("Link.Linen"); if (manualChange || CVarGetInteger(linkLinen.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {linkLinen.defaultColor.x, linkLinen.defaultColor.y, linkLinen.defaultColor.z, linkLinen.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(linkLinen.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(linkLinen.cvar, linkLinen.defaultColor); PATCH_GFX(gLinkAdultLeftArmNearDL, "Link_Linen1", linkLinen.changedCvar, 30, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultLeftArmNearDL, "Link_Linen2", linkLinen.changedCvar, 83, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultLeftArmOutNearDL, "Link_Linen3", linkLinen.changedCvar, 25, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -560,61 +640,59 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { PATCH_GFX(gLinkAdultLeftLegFarDL, "Link_Linen22", linkLinen.changedCvar, 30, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); if (manualChange) { - PATCH_GFX(gLinkAdultLeftArmFarDL, "Link_Linen23", linkLinen.changedCvar, 35, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultLeftArmOutNearDL, "Link_Linen24", linkLinen.changedCvar, 45, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultLeftArmNearDL, "Link_Linen25", linkLinen.changedCvar, 40, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultLeftArmFarDL, "Link_Linen26", linkLinen.changedCvar, 77, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultRightArmFarDL, "Link_Linen27", linkLinen.changedCvar, 35, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultRightArmFarDL, "Link_Linen28", linkLinen.changedCvar, 77, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultRightArmNearDL, "Link_Linen29", linkLinen.changedCvar, 42, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultRightLegNearDL, "Link_Linen30", linkLinen.changedCvar, 43, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultLeftLegNearDL, "Link_Linen31", linkLinen.changedCvar, 43, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultRightLegFarDL, "Link_Linen32", linkLinen.changedCvar, 38, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); - PATCH_GFX(gLinkAdultLeftLegFarDL, "Link_Linen33", linkLinen.changedCvar, 38, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultLeftArmFarDL, "Link_Linen23", linkLinen.changedCvar, 35, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultLeftArmOutNearDL, "Link_Linen24", linkLinen.changedCvar, 45, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultLeftArmNearDL, "Link_Linen25", linkLinen.changedCvar, 40, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultLeftArmFarDL, "Link_Linen26", linkLinen.changedCvar, 77, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultRightArmFarDL, "Link_Linen27", linkLinen.changedCvar, 35, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultRightArmFarDL, "Link_Linen28", linkLinen.changedCvar, 77, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultRightArmNearDL, "Link_Linen29", linkLinen.changedCvar, 42, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultRightLegNearDL, "Link_Linen30", linkLinen.changedCvar, 43, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultLeftLegNearDL, "Link_Linen31", linkLinen.changedCvar, 43, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultRightLegFarDL, "Link_Linen32", linkLinen.changedCvar, 38, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); + PATCH_GFX(gLinkAdultLeftLegFarDL, "Link_Linen33", linkLinen.changedCvar, 38, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)); } } static CosmeticOption& linkBoots = cosmeticOptions.at("Link.Boots"); if (manualChange || CVarGetInteger(linkBoots.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {linkBoots.defaultColor.x, linkBoots.defaultColor.y, linkBoots.defaultColor.z, linkBoots.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(linkBoots.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(linkBoots.cvar, linkBoots.defaultColor); PATCH_GFX(gLinkChildRightShinNearDL, "Link_Boots1", linkBoots.changedCvar, 10, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); PATCH_GFX(gLinkChildRightShinFarDL, "Link_Boots2", linkBoots.changedCvar, 10, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultRightLegNearDL, "Link_Boots3", linkBoots.changedCvar, 10, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultRightLegFarDL, "Link_Boots4", linkBoots.changedCvar, 10, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); if (manualChange) { - PATCH_GFX(gLinkChildRightShinNearDL, "Link_Boots5", linkBoots.changedCvar, 53, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildRightShinNearDL, "Link_Boots6", linkBoots.changedCvar, 69, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildRightShinFarDL, "Link_Boots7", linkBoots.changedCvar, 52, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildRightShinFarDL, "Link_Boots8", linkBoots.changedCvar, 61, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildLeftShinNearDL, "Link_Boots9", linkBoots.changedCvar, 53, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildLeftShinNearDL, "Link_Boots10", linkBoots.changedCvar, 69, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildLeftShinFarDL, "Link_Boots11", linkBoots.changedCvar, 52, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildLeftShinFarDL, "Link_Boots12", linkBoots.changedCvar, 61, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildRightFootNearDL, "Link_Boots13", linkBoots.changedCvar, 30, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildRightFootFarDL, "Link_Boots14", linkBoots.changedCvar, 30, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildLeftFootNearDL, "Link_Boots15", linkBoots.changedCvar, 30, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildLeftFootFarDL, "Link_Boots16", linkBoots.changedCvar, 30, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildLeftThighNearDL, "Link_Boots17", linkBoots.changedCvar, 10, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildLeftThighFarDL, "Link_Boots18", linkBoots.changedCvar, 10, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildHeadNearDL, "Link_Boots19", linkBoots.changedCvar, 20, gsSPGrayscale(false)); - PATCH_GFX(gLinkChildHeadFarDL, "Link_Boots20", linkBoots.changedCvar, 20, gsSPGrayscale(false)); - PATCH_GFX(gLinkAdultRightLegNearDL, "Link_Boots21", linkBoots.changedCvar, 57, gsSPGrayscale(true)); - PATCH_GFX(gLinkAdultRightLegFarDL, "Link_Boots22", linkBoots.changedCvar, 52, gsSPGrayscale(true)); - PATCH_GFX(gLinkAdultLeftLegNearDL, "Link_Boots23", linkBoots.changedCvar, 57, gsSPGrayscale(true)); - PATCH_GFX(gLinkAdultLeftLegFarDL, "Link_Boots24", linkBoots.changedCvar, 52, gsSPGrayscale(true)); - PATCH_GFX(gLinkAdultLeftThighNearDL, "Link_Boots25", linkBoots.changedCvar, 10, gsSPGrayscale(false)); - PATCH_GFX(gLinkAdultLeftThighFarDL, "Link_Boots26", linkBoots.changedCvar, 10, gsSPGrayscale(false)); - PATCH_GFX(gLinkAdultHeadNearDL, "Link_Boots27", linkBoots.changedCvar, 20, gsSPGrayscale(false)); - PATCH_GFX(gLinkAdultHeadFarDL, "Link_Boots28", linkBoots.changedCvar, 20, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildRightShinNearDL, "Link_Boots5", linkBoots.changedCvar, 53, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildRightShinNearDL, "Link_Boots6", linkBoots.changedCvar, 69, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildRightShinFarDL, "Link_Boots7", linkBoots.changedCvar, 52, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildRightShinFarDL, "Link_Boots8", linkBoots.changedCvar, 61, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildLeftShinNearDL, "Link_Boots9", linkBoots.changedCvar, 53, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildLeftShinNearDL, "Link_Boots10", linkBoots.changedCvar, 69, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildLeftShinFarDL, "Link_Boots11", linkBoots.changedCvar, 52, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildLeftShinFarDL, "Link_Boots12", linkBoots.changedCvar, 61, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildRightFootNearDL, "Link_Boots13", linkBoots.changedCvar, 30, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildRightFootFarDL, "Link_Boots14", linkBoots.changedCvar, 30, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildLeftFootNearDL, "Link_Boots15", linkBoots.changedCvar, 30, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildLeftFootFarDL, "Link_Boots16", linkBoots.changedCvar, 30, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildLeftThighNearDL, "Link_Boots17", linkBoots.changedCvar, 10, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildLeftThighFarDL, "Link_Boots18", linkBoots.changedCvar, 10, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildHeadNearDL, "Link_Boots19", linkBoots.changedCvar, 20, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildHeadFarDL, "Link_Boots20", linkBoots.changedCvar, 20, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultRightLegNearDL, "Link_Boots21", linkBoots.changedCvar, 57, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultRightLegFarDL, "Link_Boots22", linkBoots.changedCvar, 52, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultLeftLegNearDL, "Link_Boots23", linkBoots.changedCvar, 57, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultLeftLegFarDL, "Link_Boots24", linkBoots.changedCvar, 52, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultLeftThighNearDL, "Link_Boots25", linkBoots.changedCvar, 10, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultLeftThighFarDL, "Link_Boots26", linkBoots.changedCvar, 10, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultHeadNearDL, "Link_Boots27", linkBoots.changedCvar, 20, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultHeadFarDL, "Link_Boots28", linkBoots.changedCvar, 20, gsSPGrayscale(false)); } } static CosmeticOption& mirrorShieldBody = cosmeticOptions.at("MirrorShield.Body"); if (manualChange || CVarGetInteger(mirrorShieldBody.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {mirrorShieldBody.defaultColor.x, mirrorShieldBody.defaultColor.y, mirrorShieldBody.defaultColor.z, mirrorShieldBody.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(mirrorShieldBody.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(mirrorShieldBody.cvar, mirrorShieldBody.defaultColor); PATCH_GFX(gGiMirrorShieldDL, "MirrorShield_Body1", mirrorShieldBody.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiMirrorShieldDL, "MirrorShield_Body2", mirrorShieldBody.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "MirrorShield_Body3", mirrorShieldBody.changedCvar, 28, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -626,8 +704,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& mirrorShieldMirror = cosmeticOptions.at("MirrorShield.Mirror"); if (manualChange || CVarGetInteger(mirrorShieldMirror.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {mirrorShieldMirror.defaultColor.x, mirrorShieldMirror.defaultColor.y, mirrorShieldMirror.defaultColor.z, mirrorShieldMirror.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(mirrorShieldMirror.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(mirrorShieldMirror.cvar, mirrorShieldMirror.defaultColor); PATCH_GFX(gGiMirrorShieldDL, "MirrorShield_Mirror1", mirrorShieldMirror.changedCvar, 47, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiMirrorShieldDL, "MirrorShield_Mirror2", mirrorShieldMirror.changedCvar, 48, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "MirrorShield_Mirror3", mirrorShieldMirror.changedCvar, 17, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -639,8 +716,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& mirrorShieldEmblem = cosmeticOptions.at("MirrorShield.Emblem"); if (manualChange || CVarGetInteger(mirrorShieldEmblem.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {mirrorShieldEmblem.defaultColor.x, mirrorShieldEmblem.defaultColor.y, mirrorShieldEmblem.defaultColor.z, mirrorShieldEmblem.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(mirrorShieldEmblem.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(mirrorShieldEmblem.cvar, mirrorShieldEmblem.defaultColor); PATCH_GFX(gGiMirrorShieldSymbolDL, "MirrorShield_Emblem1", mirrorShieldEmblem.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 140)); PATCH_GFX(gGiMirrorShieldSymbolDL, "MirrorShield_Emblem2", mirrorShieldEmblem.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "MirrorShield_Emblem3", mirrorShieldEmblem.changedCvar, 165, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -653,58 +729,57 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& swordsKokiriBlade = cosmeticOptions.at("Swords.KokiriBlade"); if (manualChange || CVarGetInteger(swordsKokiriBlade.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {swordsKokiriBlade.defaultColor.x, swordsKokiriBlade.defaultColor.y, swordsKokiriBlade.defaultColor.z, swordsKokiriBlade.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(swordsKokiriBlade.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(swordsKokiriBlade.cvar, swordsKokiriBlade.defaultColor); PATCH_GFX(gLinkChildLeftFistAndKokiriSwordNearDL, "Swords_KokiriBlade1", swordsKokiriBlade.changedCvar, 79, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gLinkChildLeftFistAndKokiriSwordFarDL, "Swords_KokiriBlade2", swordsKokiriBlade.changedCvar, 75, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriBlade3", swordsKokiriBlade.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriBlade4", swordsKokiriBlade.changedCvar, 6, gsDPSetEnvColor(color.r / 4, color.g / 4, color.b / 4, 255)); } - // static CosmeticOption& swordsKokiriHilt = cosmeticOptions.at("Swords.KokiriHilt"); - // if (manualChange || CVarGetInteger(swordsKokiriHilt.rainbowCvar, 0)) { - // static Color_RGBA8 defaultColor = {swordsKokiriHilt.defaultColor.x, swordsKokiriHilt.defaultColor.y, swordsKokiriHilt.defaultColor.z, swordsKokiriHilt.defaultColor.w}; - // Color_RGBA8 color = CVarGetColor(swordsKokiriHilt.cvar, defaultColor); - // PATCH_GFX(gLinkChildLeftFistAndKokiriSwordNearDL, "Swords_KokiriHilt1", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildLeftFistAndKokiriSwordFarDL, "Swords_KokiriHilt2", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildSwordAndSheathNearDL, "Swords_KokiriHilt3", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildSwordAndSheathFarDL, "Swords_KokiriHilt4", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildDekuShieldSwordAndSheathNearDL, "Swords_KokiriHilt5", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildDekuShieldSwordAndSheathFarDL, "Swords_KokiriHilt6", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildHylianShieldSwordAndSheathNearDL, "Swords_KokiriHilt7", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildHylianShieldSwordAndSheathFarDL, "Swords_KokiriHilt8", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriHilt9", swordsKokiriHilt.changedCvar, 64, gsDPSetPrimColor(0, 0, MAX(color.r - 50, 0), MAX(color.g - 50, 0), MAX(color.b - 50, 0), 255)); - // PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriHilt10", swordsKokiriHilt.changedCvar, 66, gsDPSetEnvColor(MAX(color.r - 50, 0) / 3, MAX(color.g - 50, 0) / 3, MAX(color.b - 50, 0) / 3, 255)); - // PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriHilt11", swordsKokiriHilt.changedCvar, 162, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); - // PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriHilt12", swordsKokiriHilt.changedCvar, 164, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); + /* + static CosmeticOption& swordsKokiriHilt = cosmeticOptions.at("Swords.KokiriHilt"); + if (manualChange || CVarGetInteger(swordsKokiriHilt.rainbowCvar, 0)) { + Color_RGBA8 color = CVarGetColor(swordsKokiriHilt.cvar, swordsKokiriHilt.defaultColor); + PATCH_GFX(gLinkChildLeftFistAndKokiriSwordNearDL, "Swords_KokiriHilt1", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildLeftFistAndKokiriSwordFarDL, "Swords_KokiriHilt2", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildSwordAndSheathNearDL, "Swords_KokiriHilt3", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildSwordAndSheathFarDL, "Swords_KokiriHilt4", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildDekuShieldSwordAndSheathNearDL, "Swords_KokiriHilt5", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildDekuShieldSwordAndSheathFarDL, "Swords_KokiriHilt6", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildHylianShieldSwordAndSheathNearDL, "Swords_KokiriHilt7", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildHylianShieldSwordAndSheathFarDL, "Swords_KokiriHilt8", swordsKokiriHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriHilt9", swordsKokiriHilt.changedCvar, 64, gsDPSetPrimColor(0, 0, MAX(color.r - 50, 0), MAX(color.g - 50, 0), MAX(color.b - 50, 0), 255)); + PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriHilt10", swordsKokiriHilt.changedCvar, 66, gsDPSetEnvColor(MAX(color.r - 50, 0) / 3, MAX(color.g - 50, 0) / 3, MAX(color.b - 50, 0) / 3, 255)); + PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriHilt11", swordsKokiriHilt.changedCvar, 162, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + PATCH_GFX(gGiKokiriSwordDL, "Swords_KokiriHilt12", swordsKokiriHilt.changedCvar, 164, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); - // if (manualChange) { - // PATCH_GFX(gLinkChildLeftFistAndKokiriSwordNearDL, "Swords_KokiriHilt13", swordsKokiriHilt.changedCvar, 108, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildLeftFistAndKokiriSwordNearDL, "Swords_KokiriHilt14", swordsKokiriHilt.changedCvar, 134, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildLeftFistAndKokiriSwordFarDL, "Swords_KokiriHilt15", swordsKokiriHilt.changedCvar, 106, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildLeftFistAndKokiriSwordFarDL, "Swords_KokiriHilt16", swordsKokiriHilt.changedCvar, 126, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildSwordAndSheathNearDL, "Swords_KokiriHilt17", swordsKokiriHilt.changedCvar, 100, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildSwordAndSheathNearDL, "Swords_KokiriHilt18", swordsKokiriHilt.changedCvar, 126, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildSwordAndSheathNearDL, "Swords_KokiriHilt19", swordsKokiriHilt.changedCvar, 128, gsSPEndDisplayList()); - // PATCH_GFX(gLinkChildSwordAndSheathFarDL, "Swords_KokiriHilt20", swordsKokiriHilt.changedCvar, 98, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildSwordAndSheathFarDL, "Swords_KokiriHilt21", swordsKokiriHilt.changedCvar, 118, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildSwordAndSheathFarDL, "Swords_KokiriHilt22", swordsKokiriHilt.changedCvar, 120, gsSPEndDisplayList()); - // PATCH_GFX(gLinkChildDekuShieldSwordAndSheathNearDL, "Swords_KokiriHilt23", swordsKokiriHilt.changedCvar, 166, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildDekuShieldSwordAndSheathNearDL, "Swords_KokiriHilt24", swordsKokiriHilt.changedCvar, 192, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildDekuShieldSwordAndSheathNearDL, "Swords_KokiriHilt25", swordsKokiriHilt.changedCvar, 194, gsSPEndDisplayList()); - // PATCH_GFX(gLinkChildDekuShieldSwordAndSheathFarDL, "Swords_KokiriHilt26", swordsKokiriHilt.changedCvar, 156, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildDekuShieldSwordAndSheathFarDL, "Swords_KokiriHilt27", swordsKokiriHilt.changedCvar, 176, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildDekuShieldSwordAndSheathFarDL, "Swords_KokiriHilt28", swordsKokiriHilt.changedCvar, 178, gsSPEndDisplayList()); - // PATCH_GFX(gLinkChildHylianShieldSwordAndSheathNearDL, "Swords_KokiriHilt29", swordsKokiriHilt.changedCvar, 162, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildHylianShieldSwordAndSheathNearDL, "Swords_KokiriHilt30", swordsKokiriHilt.changedCvar, 188, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildHylianShieldSwordAndSheathNearDL, "Swords_KokiriHilt31", swordsKokiriHilt.changedCvar, 190, gsSPEndDisplayList()); - // PATCH_GFX(gLinkChildHylianShieldSwordAndSheathFarDL, "Swords_KokiriHilt32", swordsKokiriHilt.changedCvar, 98, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildHylianShieldSwordAndSheathFarDL, "Swords_KokiriHilt33", swordsKokiriHilt.changedCvar, 118, gsSPGrayscale(false)); - // } - // } + if (manualChange) { + PATCH_GFX(gLinkChildLeftFistAndKokiriSwordNearDL, "Swords_KokiriHilt13", swordsKokiriHilt.changedCvar, 108, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildLeftFistAndKokiriSwordNearDL, "Swords_KokiriHilt14", swordsKokiriHilt.changedCvar, 134, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildLeftFistAndKokiriSwordFarDL, "Swords_KokiriHilt15", swordsKokiriHilt.changedCvar, 106, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildLeftFistAndKokiriSwordFarDL, "Swords_KokiriHilt16", swordsKokiriHilt.changedCvar, 126, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildSwordAndSheathNearDL, "Swords_KokiriHilt17", swordsKokiriHilt.changedCvar, 100, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildSwordAndSheathNearDL, "Swords_KokiriHilt18", swordsKokiriHilt.changedCvar, 126, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildSwordAndSheathNearDL, "Swords_KokiriHilt19", swordsKokiriHilt.changedCvar, 128, gsSPEndDisplayList()); + PATCH_GFX(gLinkChildSwordAndSheathFarDL, "Swords_KokiriHilt20", swordsKokiriHilt.changedCvar, 98, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildSwordAndSheathFarDL, "Swords_KokiriHilt21", swordsKokiriHilt.changedCvar, 118, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildSwordAndSheathFarDL, "Swords_KokiriHilt22", swordsKokiriHilt.changedCvar, 120, gsSPEndDisplayList()); + PATCH_GFX(gLinkChildDekuShieldSwordAndSheathNearDL, "Swords_KokiriHilt23", swordsKokiriHilt.changedCvar, 166, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildDekuShieldSwordAndSheathNearDL, "Swords_KokiriHilt24", swordsKokiriHilt.changedCvar, 192, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildDekuShieldSwordAndSheathNearDL, "Swords_KokiriHilt25", swordsKokiriHilt.changedCvar, 194, gsSPEndDisplayList()); + PATCH_GFX(gLinkChildDekuShieldSwordAndSheathFarDL, "Swords_KokiriHilt26", swordsKokiriHilt.changedCvar, 156, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildDekuShieldSwordAndSheathFarDL, "Swords_KokiriHilt27", swordsKokiriHilt.changedCvar, 176, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildDekuShieldSwordAndSheathFarDL, "Swords_KokiriHilt28", swordsKokiriHilt.changedCvar, 178, gsSPEndDisplayList()); + PATCH_GFX(gLinkChildHylianShieldSwordAndSheathNearDL, "Swords_KokiriHilt29", swordsKokiriHilt.changedCvar, 162, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildHylianShieldSwordAndSheathNearDL, "Swords_KokiriHilt30", swordsKokiriHilt.changedCvar, 188, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildHylianShieldSwordAndSheathNearDL, "Swords_KokiriHilt31", swordsKokiriHilt.changedCvar, 190, gsSPEndDisplayList()); + PATCH_GFX(gLinkChildHylianShieldSwordAndSheathFarDL, "Swords_KokiriHilt32", swordsKokiriHilt.changedCvar, 98, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildHylianShieldSwordAndSheathFarDL, "Swords_KokiriHilt33", swordsKokiriHilt.changedCvar, 118, gsSPGrayscale(false)); + } + } + */ static CosmeticOption& swordsMasterBlade = cosmeticOptions.at("Swords.MasterBlade"); if (manualChange || CVarGetInteger(swordsMasterBlade.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {swordsMasterBlade.defaultColor.x, swordsMasterBlade.defaultColor.y, swordsMasterBlade.defaultColor.z, swordsMasterBlade.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(swordsMasterBlade.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(swordsMasterBlade.cvar, swordsMasterBlade.defaultColor); PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordFarDL, "Swords_MasterBlade1", swordsMasterBlade.changedCvar, 60, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordNearDL, "Swords_MasterBlade2", swordsMasterBlade.changedCvar, 17, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterBlade3", swordsMasterBlade.changedCvar, 13, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -712,113 +787,109 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterBlade5", swordsMasterBlade.changedCvar, 13, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterBlade6", swordsMasterBlade.changedCvar, 14, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255)); } - // static CosmeticOption& swordsMasterHilt = cosmeticOptions.at("Swords.MasterHilt"); - // if (manualChange || CVarGetInteger(swordsMasterHilt.rainbowCvar, 0)) { - // static Color_RGBA8 defaultColor = {swordsMasterHilt.defaultColor.x, swordsMasterHilt.defaultColor.y, swordsMasterHilt.defaultColor.z, swordsMasterHilt.defaultColor.w}; - // Color_RGBA8 color = CVarGetColor(swordsMasterHilt.cvar, defaultColor); - // PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordNearDL, "Swords_MasterHilt1", swordsMasterHilt.changedCvar, 20, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordFarDL, "Swords_MasterHilt2", swordsMasterHilt.changedCvar, 20, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterHilt3", swordsMasterHilt.changedCvar, 16, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkAdultMasterSwordAndSheathNearDL, "Swords_MasterHilt4", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt5", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "Swords_MasterHilt6", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt7", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathNearDL, "Swords_MasterHilt8", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt9", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterHilt10", swordsMasterHilt.changedCvar, 16, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + /* + static CosmeticOption& swordsMasterHilt = cosmeticOptions.at("Swords.MasterHilt"); + if (manualChange || CVarGetInteger(swordsMasterHilt.rainbowCvar, 0)) { + Color_RGBA8 color = CVarGetColor(swordsMasterHilt.cvar, swordsMasterHilt.defaultColor); + PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordNearDL, "Swords_MasterHilt1", swordsMasterHilt.changedCvar, 20, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordFarDL, "Swords_MasterHilt2", swordsMasterHilt.changedCvar, 20, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterHilt3", swordsMasterHilt.changedCvar, 16, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkAdultMasterSwordAndSheathNearDL, "Swords_MasterHilt4", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt5", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "Swords_MasterHilt6", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt7", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathNearDL, "Swords_MasterHilt8", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt9", swordsMasterHilt.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterHilt10", swordsMasterHilt.changedCvar, 16, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // if (manualChange) { - // PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt11", swordsMasterHilt.changedCvar, 38, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt12", swordsMasterHilt.changedCvar, 64, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt13", swordsMasterHilt.changedCvar, 106, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt14", swordsMasterHilt.changedCvar, 120, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultMasterSwordAndSheathNearDL, "Swords_MasterHilt15", swordsMasterHilt.changedCvar, 104, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultMasterSwordAndSheathNearDL, "Swords_MasterHilt16", swordsMasterHilt.changedCvar, 182, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultMasterSwordAndSheathNearDL, "Swords_MasterHilt17", swordsMasterHilt.changedCvar, 184, gsSPEndDisplayList()); - // PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt18", swordsMasterHilt.changedCvar, 80, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt19", swordsMasterHilt.changedCvar, 94, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt20", swordsMasterHilt.changedCvar, 162, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt21", swordsMasterHilt.changedCvar, 180, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathNearDL, "Swords_MasterHilt22", swordsMasterHilt.changedCvar, 154, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathNearDL, "Swords_MasterHilt23", swordsMasterHilt.changedCvar, 232, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt24", swordsMasterHilt.changedCvar, 112, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt25", swordsMasterHilt.changedCvar, 130, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt26", swordsMasterHilt.changedCvar, 172, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt27", swordsMasterHilt.changedCvar, 186, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "Swords_MasterHilt28", swordsMasterHilt.changedCvar, 220, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "Swords_MasterHilt29", swordsMasterHilt.changedCvar, 298, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordFarDL, "Swords_MasterHilt30", swordsMasterHilt.changedCvar, 38, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordFarDL, "Swords_MasterHilt31", swordsMasterHilt.changedCvar, 112, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordNearDL, "Swords_MasterHilt32", swordsMasterHilt.changedCvar, 86, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordNearDL, "Swords_MasterHilt33", swordsMasterHilt.changedCvar, 208, gsSPGrayscale(false)); - // PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterHilt34", swordsMasterHilt.changedCvar, 112, gsSPGrayscale(true)); - // PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterHilt35", swordsMasterHilt.changedCvar, 278, gsSPGrayscale(false)); - // PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterHilt36", swordsMasterHilt.changedCvar, 280, gsSPEndDisplayList()); - // PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterHilt37", swordsMasterHilt.changedCvar, 112, gsSPGrayscale(true)); - // PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterHilt38", swordsMasterHilt.changedCvar, 278, gsSPGrayscale(false)); - // PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterHilt39", swordsMasterHilt.changedCvar, 280, gsSPEndDisplayList()); - // } - // } + if (manualChange) { + PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt11", swordsMasterHilt.changedCvar, 38, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt12", swordsMasterHilt.changedCvar, 64, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt13", swordsMasterHilt.changedCvar, 106, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultMasterSwordAndSheathFarDL, "Swords_MasterHilt14", swordsMasterHilt.changedCvar, 120, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultMasterSwordAndSheathNearDL, "Swords_MasterHilt15", swordsMasterHilt.changedCvar, 104, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultMasterSwordAndSheathNearDL, "Swords_MasterHilt16", swordsMasterHilt.changedCvar, 182, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultMasterSwordAndSheathNearDL, "Swords_MasterHilt17", swordsMasterHilt.changedCvar, 184, gsSPEndDisplayList()); + PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt18", swordsMasterHilt.changedCvar, 80, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt19", swordsMasterHilt.changedCvar, 94, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt20", swordsMasterHilt.changedCvar, 162, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathFarDL, "Swords_MasterHilt21", swordsMasterHilt.changedCvar, 180, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathNearDL, "Swords_MasterHilt22", swordsMasterHilt.changedCvar, 154, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultHylianShieldSwordAndSheathNearDL, "Swords_MasterHilt23", swordsMasterHilt.changedCvar, 232, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt24", swordsMasterHilt.changedCvar, 112, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt25", swordsMasterHilt.changedCvar, 130, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt26", swordsMasterHilt.changedCvar, 172, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathFarDL, "Swords_MasterHilt27", swordsMasterHilt.changedCvar, 186, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "Swords_MasterHilt28", swordsMasterHilt.changedCvar, 220, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultMirrorShieldSwordAndSheathNearDL, "Swords_MasterHilt29", swordsMasterHilt.changedCvar, 298, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordFarDL, "Swords_MasterHilt30", swordsMasterHilt.changedCvar, 38, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordFarDL, "Swords_MasterHilt31", swordsMasterHilt.changedCvar, 112, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordNearDL, "Swords_MasterHilt32", swordsMasterHilt.changedCvar, 86, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultLeftHandHoldingMasterSwordNearDL, "Swords_MasterHilt33", swordsMasterHilt.changedCvar, 208, gsSPGrayscale(false)); + PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterHilt34", swordsMasterHilt.changedCvar, 112, gsSPGrayscale(true)); + PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterHilt35", swordsMasterHilt.changedCvar, 278, gsSPGrayscale(false)); + PATCH_GFX(object_toki_objects_DL_001BD0, "Swords_MasterHilt36", swordsMasterHilt.changedCvar, 280, gsSPEndDisplayList()); + PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterHilt37", swordsMasterHilt.changedCvar, 112, gsSPGrayscale(true)); + PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterHilt38", swordsMasterHilt.changedCvar, 278, gsSPGrayscale(false)); + PATCH_GFX(gGanonMasterSwordDL, "Swords_MasterHilt39", swordsMasterHilt.changedCvar, 280, gsSPEndDisplayList()); + } + } + */ static CosmeticOption& swordsBiggoronBlade = cosmeticOptions.at("Swords.BiggoronBlade"); if (manualChange || CVarGetInteger(swordsBiggoronBlade.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {swordsBiggoronBlade.defaultColor.x, swordsBiggoronBlade.defaultColor.y, swordsBiggoronBlade.defaultColor.z, swordsBiggoronBlade.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(swordsBiggoronBlade.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(swordsBiggoronBlade.cvar, swordsBiggoronBlade.defaultColor); PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronBlade1", swordsBiggoronBlade.changedCvar, 108, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultLeftHandHoldingBgsNearDL, "Swords_BiggoronBlade2", swordsBiggoronBlade.changedCvar, 63, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronBlade3", swordsBiggoronBlade.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronBlade4", swordsBiggoronBlade.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); } - // static CosmeticOption& swordsBiggoronHilt = cosmeticOptions.at("Swords.BiggoronHilt"); - // if (manualChange || CVarGetInteger(swordsBiggoronHilt.rainbowCvar, 0)) { - // static Color_RGBA8 defaultColor = {swordsBiggoronHilt.defaultColor.x, swordsBiggoronHilt.defaultColor.y, swordsBiggoronHilt.defaultColor.z, swordsBiggoronHilt.defaultColor.w}; - // Color_RGBA8 color = CVarGetColor(swordsBiggoronHilt.cvar, defaultColor); - // PATCH_GFX(gLinkAdultLeftHandHoldingBgsNearDL, "Swords_BiggoronHilt1", swordsBiggoronHilt.changedCvar, 20, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronHilt2", swordsBiggoronHilt.changedCvar, 20, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronHilt3", swordsBiggoronHilt.changedCvar, 74, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); - // PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronHilt4", swordsBiggoronHilt.changedCvar, 76, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); - // PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronHilt5", swordsBiggoronHilt.changedCvar, 154, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); - // PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronHilt6", swordsBiggoronHilt.changedCvar, 156, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); - - // if (manualChange) { - // PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronHilt7", swordsBiggoronHilt.changedCvar, 278, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronHilt8", swordsBiggoronHilt.changedCvar, 332, gsSPGrayscale(false)); - // PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronHilt9", swordsBiggoronHilt.changedCvar, 334, gsSPEndDisplayList()); - // PATCH_GFX(gLinkAdultLeftHandHoldingBgsNearDL, "Swords_BiggoronHilt10", swordsBiggoronHilt.changedCvar, 38, gsSPGrayscale(true)); - // PATCH_GFX(gLinkAdultLeftHandHoldingBgsNearDL, "Swords_BiggoronHilt11", swordsBiggoronHilt.changedCvar, 118, gsSPGrayscale(false)); - // } - // } + /* + static CosmeticOption& swordsBiggoronHilt = cosmeticOptions.at("Swords.BiggoronHilt"); + if (manualChange || CVarGetInteger(swordsBiggoronHilt.rainbowCvar, 0)) { + Color_RGBA8 color = CVarGetColor(swordsBiggoronHilt.cvar, swordsBiggoronHilt.defaultColor); + PATCH_GFX(gLinkAdultLeftHandHoldingBgsNearDL, "Swords_BiggoronHilt1", swordsBiggoronHilt.changedCvar, 20, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronHilt2", swordsBiggoronHilt.changedCvar, 20, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronHilt3", swordsBiggoronHilt.changedCvar, 74, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronHilt4", swordsBiggoronHilt.changedCvar, 76, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); + PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronHilt5", swordsBiggoronHilt.changedCvar, 154, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + PATCH_GFX(gGiBiggoronSwordDL, "Swords_BiggoronHilt6", swordsBiggoronHilt.changedCvar, 156, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); + if (manualChange) { + PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronHilt7", swordsBiggoronHilt.changedCvar, 278, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronHilt8", swordsBiggoronHilt.changedCvar, 332, gsSPGrayscale(false)); + PATCH_GFX(gLinkAdultLeftHandHoldingBgsFarDL, "Swords_BiggoronHilt9", swordsBiggoronHilt.changedCvar, 334, gsSPEndDisplayList()); + PATCH_GFX(gLinkAdultLeftHandHoldingBgsNearDL, "Swords_BiggoronHilt10", swordsBiggoronHilt.changedCvar, 38, gsSPGrayscale(true)); + PATCH_GFX(gLinkAdultLeftHandHoldingBgsNearDL, "Swords_BiggoronHilt11", swordsBiggoronHilt.changedCvar, 118, gsSPGrayscale(false)); + } + } + */ static CosmeticOption& glovesGoronBracelet = cosmeticOptions.at("Gloves.GoronBracelet"); if (manualChange || CVarGetInteger(glovesGoronBracelet.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {glovesGoronBracelet.defaultColor.x, glovesGoronBracelet.defaultColor.y, glovesGoronBracelet.defaultColor.z, glovesGoronBracelet.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(glovesGoronBracelet.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(glovesGoronBracelet.cvar, glovesGoronBracelet.defaultColor); PATCH_GFX(gGiGoronBraceletDL, "Gloves_GoronBracelet1", glovesGoronBracelet.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiGoronBraceletDL, "Gloves_GoronBracelet2", glovesGoronBracelet.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkChildGoronBraceletDL, "Gloves_GoronBracelet3", glovesGoronBracelet.changedCvar, 3, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); if (manualChange) { - PATCH_GFX(gLinkChildGoronBraceletDL, "Gloves_GoronBracelet4", glovesGoronBracelet.changedCvar, 11, gsSPGrayscale(true)); - PATCH_GFX(gLinkChildGoronBraceletDL, "Gloves_GoronBracelet5", glovesGoronBracelet.changedCvar, 39, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildGoronBraceletDL, "Gloves_GoronBracelet4", glovesGoronBracelet.changedCvar, 11, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildGoronBraceletDL, "Gloves_GoronBracelet5", glovesGoronBracelet.changedCvar, 39, gsSPGrayscale(false)); } } static CosmeticOption& glovesSilverGauntlets = cosmeticOptions.at("Gloves.SilverGauntlets"); if (manualChange || CVarGetInteger(glovesSilverGauntlets.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {glovesSilverGauntlets.defaultColor.x, glovesSilverGauntlets.defaultColor.y, glovesSilverGauntlets.defaultColor.z, glovesSilverGauntlets.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(glovesSilverGauntlets.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(glovesSilverGauntlets.cvar, glovesSilverGauntlets.defaultColor); PATCH_GFX(gGiSilverGauntletsColorDL, "Gloves_SilverGauntlets1", glovesSilverGauntlets.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiSilverGauntletsColorDL, "Gloves_SilverGauntlets2", glovesSilverGauntlets.changedCvar, 4, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); } static CosmeticOption& glovesGoldenGauntlets = cosmeticOptions.at("Gloves.GoldenGauntlets"); if (manualChange || CVarGetInteger(glovesGoldenGauntlets.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {glovesGoldenGauntlets.defaultColor.x, glovesGoldenGauntlets.defaultColor.y, glovesGoldenGauntlets.defaultColor.z, glovesGoldenGauntlets.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(glovesGoldenGauntlets.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(glovesGoldenGauntlets.cvar, glovesGoldenGauntlets.defaultColor); PATCH_GFX(gGiGoldenGauntletsColorDL, "Gloves_GoldenGauntlets1", glovesGoldenGauntlets.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiGoldenGauntletsColorDL, "Gloves_GoldenGauntlets2", glovesGoldenGauntlets.changedCvar, 4, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); } static CosmeticOption& glovesGauntletsGem = cosmeticOptions.at("Gloves.GauntletsGem"); if (manualChange || CVarGetInteger(glovesGauntletsGem.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {glovesGauntletsGem.defaultColor.x, glovesGauntletsGem.defaultColor.y, glovesGauntletsGem.defaultColor.z, glovesGauntletsGem.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(glovesGauntletsGem.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(glovesGauntletsGem.cvar, glovesGauntletsGem.defaultColor); PATCH_GFX(gGiGauntletsDL, "Gloves_GauntletsGem1", glovesGauntletsGem.changedCvar, 84, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiGauntletsDL, "Gloves_GauntletsGem2", glovesGauntletsGem.changedCvar, 85, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkAdultLeftGauntletPlate2DL, "Gloves_GauntletsGem3", glovesGauntletsGem.changedCvar, 42, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -829,8 +900,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& equipmentBoomerangBody = cosmeticOptions.at("Equipment.BoomerangBody"); if (manualChange || CVarGetInteger(equipmentBoomerangBody.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentBoomerangBody.defaultColor.x, equipmentBoomerangBody.defaultColor.y, equipmentBoomerangBody.defaultColor.z, equipmentBoomerangBody.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentBoomerangBody.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentBoomerangBody.cvar, equipmentBoomerangBody.defaultColor); PATCH_GFX(gGiBoomerangDL, "Equipment_BoomerangBody1", equipmentBoomerangBody.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBoomerangDL, "Equipment_BoomerangBody2", equipmentBoomerangBody.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkChildLeftFistAndBoomerangNearDL, "Equipment_BoomerangBody3", equipmentBoomerangBody.changedCvar, 34, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -839,8 +909,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& equipmentBoomerangGem = cosmeticOptions.at("Equipment.BoomerangGem"); if (manualChange || CVarGetInteger(equipmentBoomerangGem.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentBoomerangGem.defaultColor.x, equipmentBoomerangGem.defaultColor.y, equipmentBoomerangGem.defaultColor.z, equipmentBoomerangGem.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentBoomerangGem.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentBoomerangGem.cvar, equipmentBoomerangGem.defaultColor); PATCH_GFX(gGiBoomerangDL, "Equipment_BoomerangGem1", equipmentBoomerangGem.changedCvar, 84, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBoomerangDL, "Equipment_BoomerangGem2", equipmentBoomerangGem.changedCvar, 85, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkChildLeftFistAndBoomerangNearDL, "Equipment_BoomerangGem3", equipmentBoomerangGem.changedCvar, 16, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -848,35 +917,34 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { // There appears to be no gem rendered on the far LOD variant, not sure if this is an SOH bug or what. // PATCH_GFX(gLinkChildLeftFistAndBoomerangFarDL, "Equipment_BoomerangGem5", equipmentBoomerangGem.changedCvar, 32, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); } + /* + static CosmeticOption& equipmentSlingshotBody = cosmeticOptions.at("Equipment.SlingshotBody"); + if (manualChange || CVarGetInteger(equipmentSlingshotBody.rainbowCvar, 0)) { + Color_RGBA8 color = CVarGetColor(equipmentSlingshotBody.cvar, equipmentSlingshotBody.defaultColor); + PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody1", equipmentSlingshotBody.changedCvar, 10, gsDPSetPrimColor(0, 0, MAX(color.r - 100, 0), MAX(color.g - 100, 0), MAX(color.b - 100, 0), 255)); + PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody2", equipmentSlingshotBody.changedCvar, 12, gsDPSetEnvColor(MAX(color.r - 100, 0) / 3, MAX(color.g - 100, 0) / 3, MAX(color.b - 100, 0) / 3, 255)); + PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody3", equipmentSlingshotBody.changedCvar, 74, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody4", equipmentSlingshotBody.changedCvar, 76, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); + PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody5", equipmentSlingshotBody.changedCvar, 128, gsDPSetPrimColor(0, 0, MAX(color.r - 100, 0), MAX(color.g - 100, 0), MAX(color.b - 100, 0), 255)); + PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody6", equipmentSlingshotBody.changedCvar, 130, gsDPSetEnvColor(MAX(color.r - 100, 0) / 3, MAX(color.g - 100, 0) / 3, MAX(color.b - 100, 0) / 3, 255)); + PATCH_GFX(gLinkChildRightArmStretchedSlingshotDL, "Equipment_SlingshotBody7", equipmentSlingshotBody.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildRightHandHoldingSlingshotNearDL, "Equipment_SlingshotBody8", equipmentSlingshotBody.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gLinkChildRightHandHoldingSlingshotFarDL, "Equipment_SlingshotBody9", equipmentSlingshotBody.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // static CosmeticOption& equipmentSlingshotBody = cosmeticOptions.at("Equipment.SlingshotBody"); - // if (manualChange || CVarGetInteger(equipmentSlingshotBody.rainbowCvar, 0)) { - // static Color_RGBA8 defaultColor = {equipmentSlingshotBody.defaultColor.x, equipmentSlingshotBody.defaultColor.y, equipmentSlingshotBody.defaultColor.z, equipmentSlingshotBody.defaultColor.w}; - // Color_RGBA8 color = CVarGetColor(equipmentSlingshotBody.cvar, defaultColor); - // PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody1", equipmentSlingshotBody.changedCvar, 10, gsDPSetPrimColor(0, 0, MAX(color.r - 100, 0), MAX(color.g - 100, 0), MAX(color.b - 100, 0), 255)); - // PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody2", equipmentSlingshotBody.changedCvar, 12, gsDPSetEnvColor(MAX(color.r - 100, 0) / 3, MAX(color.g - 100, 0) / 3, MAX(color.b - 100, 0) / 3, 255)); - // PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody3", equipmentSlingshotBody.changedCvar, 74, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); - // PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody4", equipmentSlingshotBody.changedCvar, 76, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); - // PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody5", equipmentSlingshotBody.changedCvar, 128, gsDPSetPrimColor(0, 0, MAX(color.r - 100, 0), MAX(color.g - 100, 0), MAX(color.b - 100, 0), 255)); - // PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotBody6", equipmentSlingshotBody.changedCvar, 130, gsDPSetEnvColor(MAX(color.r - 100, 0) / 3, MAX(color.g - 100, 0) / 3, MAX(color.b - 100, 0) / 3, 255)); - // PATCH_GFX(gLinkChildRightArmStretchedSlingshotDL, "Equipment_SlingshotBody7", equipmentSlingshotBody.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildRightHandHoldingSlingshotNearDL, "Equipment_SlingshotBody8", equipmentSlingshotBody.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gLinkChildRightHandHoldingSlingshotFarDL, "Equipment_SlingshotBody9", equipmentSlingshotBody.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - - // if (manualChange) { - // PATCH_GFX(gLinkChildRightArmStretchedSlingshotDL, "Equipment_SlingshotBody10",equipmentSlingshotBody.changedCvar, 20, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildRightArmStretchedSlingshotDL, "Equipment_SlingshotBody11",equipmentSlingshotBody.changedCvar, 74, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildRightHandHoldingSlingshotFarDL, "Equipment_SlingshotBody12",equipmentSlingshotBody.changedCvar, 20, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildRightHandHoldingSlingshotFarDL, "Equipment_SlingshotBody13",equipmentSlingshotBody.changedCvar, 66, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildRightHandHoldingSlingshotNearDL, "Equipment_SlingshotBody14",equipmentSlingshotBody.changedCvar, 96, gsSPGrayscale(true)); - // PATCH_GFX(gLinkChildRightHandHoldingSlingshotNearDL, "Equipment_SlingshotBody15",equipmentSlingshotBody.changedCvar, 136, gsSPGrayscale(false)); - // PATCH_GFX(gLinkChildRightHandHoldingSlingshotNearDL, "Equipment_SlingshotBody16",equipmentSlingshotBody.changedCvar, 138, gsSPEndDisplayList()); - // } - // } + if (manualChange) { + PATCH_GFX(gLinkChildRightArmStretchedSlingshotDL, "Equipment_SlingshotBody10",equipmentSlingshotBody.changedCvar, 20, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildRightArmStretchedSlingshotDL, "Equipment_SlingshotBody11",equipmentSlingshotBody.changedCvar, 74, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildRightHandHoldingSlingshotFarDL, "Equipment_SlingshotBody12",equipmentSlingshotBody.changedCvar, 20, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildRightHandHoldingSlingshotFarDL, "Equipment_SlingshotBody13",equipmentSlingshotBody.changedCvar, 66, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildRightHandHoldingSlingshotNearDL, "Equipment_SlingshotBody14",equipmentSlingshotBody.changedCvar, 96, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildRightHandHoldingSlingshotNearDL, "Equipment_SlingshotBody15",equipmentSlingshotBody.changedCvar, 136, gsSPGrayscale(false)); + PATCH_GFX(gLinkChildRightHandHoldingSlingshotNearDL, "Equipment_SlingshotBody16",equipmentSlingshotBody.changedCvar, 138, gsSPEndDisplayList()); + } + } + */ static CosmeticOption& equipmentSlingshotString = cosmeticOptions.at("Equipment.SlingshotString"); if (manualChange || CVarGetInteger(equipmentSlingshotString.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentSlingshotString.defaultColor.x, equipmentSlingshotString.defaultColor.y, equipmentSlingshotString.defaultColor.z, equipmentSlingshotString.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentSlingshotString.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentSlingshotString.cvar, equipmentSlingshotString.defaultColor); PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotString1",equipmentSlingshotString.changedCvar, 75, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiSlingshotDL, "Equipment_SlingshotString2",equipmentSlingshotString.changedCvar, 76, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255)); PATCH_GFX(gLinkChildSlingshotStringDL, "Equipment_SlingshotString3",equipmentSlingshotString.changedCvar, 9, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -884,8 +952,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& equipmentBowTips = cosmeticOptions.at("Equipment.BowTips"); if (manualChange || CVarGetInteger(equipmentBowTips.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentBowTips.defaultColor.x, equipmentBowTips.defaultColor.y, equipmentBowTips.defaultColor.z, equipmentBowTips.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentBowTips.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentBowTips.cvar, equipmentBowTips.defaultColor); PATCH_GFX(gGiBowDL, "Equipment_BowTips1", equipmentBowTips.changedCvar, 86, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBowDL, "Equipment_BowTips2", equipmentBowTips.changedCvar, 87, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkAdultRightHandHoldingBowFirstPersonDL, "Equipment_BowTips3", equipmentBowTips.changedCvar, 34, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -894,16 +961,14 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& equipmentBowString = cosmeticOptions.at("Equipment.BowString"); if (manualChange || CVarGetInteger(equipmentBowString.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentBowString.defaultColor.x, equipmentBowString.defaultColor.y, equipmentBowString.defaultColor.z, equipmentBowString.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentBowString.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentBowString.cvar, equipmentBowString.defaultColor); PATCH_GFX(gGiBowDL, "Equipment_BowString1", equipmentBowString.changedCvar, 105, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBowDL, "Equipment_BowString2", equipmentBowString.changedCvar, 106, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkAdultBowStringDL, "Equipment_BowString3", equipmentBowString.changedCvar, 9, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); } static CosmeticOption& equipmentBowBody = cosmeticOptions.at("Equipment.BowBody"); if (manualChange || CVarGetInteger(equipmentBowBody.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentBowBody.defaultColor.x, equipmentBowBody.defaultColor.y, equipmentBowBody.defaultColor.z, equipmentBowBody.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentBowBody.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentBowBody.cvar, equipmentBowBody.defaultColor); PATCH_GFX(gGiBowDL, "Equipment_BowBody1", equipmentBowBody.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBowDL, "Equipment_BowBody2", equipmentBowBody.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkAdultRightHandHoldingBowFirstPersonDL, "Equipment_BowBody3", equipmentBowBody.changedCvar, 42, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -912,8 +977,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& equipmentBowHandle = cosmeticOptions.at("Equipment.BowHandle"); if (manualChange || CVarGetInteger(equipmentBowHandle.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentBowHandle.defaultColor.x, equipmentBowHandle.defaultColor.y, equipmentBowHandle.defaultColor.z, equipmentBowHandle.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentBowHandle.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentBowHandle.cvar, equipmentBowHandle.defaultColor); PATCH_GFX(gGiBowDL, "Equipment_BowHandle1", equipmentBowHandle.changedCvar, 51, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBowDL, "Equipment_BowHandle2", equipmentBowHandle.changedCvar, 52, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gLinkAdultRightHandHoldingBowFirstPersonDL, "Equipment_BowHandle3", equipmentBowHandle.changedCvar, 18, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -923,8 +987,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& equipmentHammerHead = cosmeticOptions.at("Equipment.HammerHead"); if (manualChange || CVarGetInteger(equipmentHammerHead.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentHammerHead.defaultColor.x, equipmentHammerHead.defaultColor.y, equipmentHammerHead.defaultColor.z, equipmentHammerHead.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentHammerHead.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentHammerHead.cvar, equipmentHammerHead.defaultColor); PATCH_GFX(gGiHammerDL, "Equipment_HammerHead1", equipmentHammerHead.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiHammerDL, "Equipment_HammerHead2", equipmentHammerHead.changedCvar, 6, gsDPSetEnvColor(color.r / 5, color.g / 5, color.b / 5, 255)); PATCH_GFX(gGiHammerDL, "Equipment_HammerHead3", equipmentHammerHead.changedCvar, 68, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -934,18 +997,22 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& equipmentHammerHandle = cosmeticOptions.at("Equipment.HammerHandle"); if (manualChange || CVarGetInteger(equipmentHammerHandle.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentHammerHandle.defaultColor.x, equipmentHammerHandle.defaultColor.y, equipmentHammerHandle.defaultColor.z, equipmentHammerHandle.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentHammerHandle.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentHammerHandle.cvar, equipmentHammerHandle.defaultColor); PATCH_GFX(gGiHammerDL, "Equipment_HammerHandle1", equipmentHammerHandle.changedCvar, 84, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiHammerDL, "Equipment_HammerHandle2", equipmentHammerHandle.changedCvar, 85, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255)); PATCH_GFX(gLinkAdultLeftHandHoldingHammerNearDL, "Equipment_HammerHandle5", equipmentHammerHandle.changedCvar, 18, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gLinkAdultLeftHandHoldingHammerFarDL, "Equipment_HammerHandle6", equipmentHammerHandle.changedCvar, 18, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); } + + static CosmeticOption& equipmentHookshotChain = cosmeticOptions.at("Equipment.HookshotChain"); + if (manualChange || CVarGetInteger(equipmentHookshotChain.rainbowCvar, 0)) { + Color_RGBA8 color = CVarGetColor(equipmentHookshotChain.cvar, equipmentHookshotChain.defaultColor); + PATCH_GFX(gLinkAdultHookshotChainDL, "Equipment_HookshotChain1", equipmentHookshotChain.changedCvar, 17, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + } static CosmeticOption& equipmentChuFace = cosmeticOptions.at("Equipment.ChuFace"); if (manualChange || CVarGetInteger(equipmentChuFace.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentChuFace.defaultColor.x, equipmentChuFace.defaultColor.y, equipmentChuFace.defaultColor.z, equipmentChuFace.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentChuFace.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentChuFace.cvar, equipmentChuFace.defaultColor); PATCH_GFX(gGiBombchuDL, "Equipment_ChuFace1", equipmentChuFace.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBombchuDL, "Equipment_ChuFace2", equipmentChuFace.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gBombchuDL, "Equipment_ChuFace3", equipmentChuFace.changedCvar, 2, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); @@ -957,8 +1024,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& equipmentChuBody = cosmeticOptions.at("Equipment.ChuBody"); if (manualChange || CVarGetInteger(equipmentChuBody.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentChuBody.defaultColor.x, equipmentChuBody.defaultColor.y, equipmentChuBody.defaultColor.z, equipmentChuBody.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentChuBody.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(equipmentChuBody.cvar, equipmentChuBody.defaultColor); PATCH_GFX(gGiBombchuDL, "Equipment_ChuBody1", equipmentChuBody.changedCvar, 39, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBombchuDL, "Equipment_ChuBody2", equipmentChuBody.changedCvar, 40, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); PATCH_GFX(gGiBombchuDL, "Equipment_ChuBody3", equipmentChuBody.changedCvar, 60, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -968,18 +1034,17 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& equipmentBunnyHood = cosmeticOptions.at("Equipment.BunnyHood"); if (manualChange || CVarGetInteger(equipmentBunnyHood.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {equipmentBunnyHood.defaultColor.x, equipmentBunnyHood.defaultColor.y, equipmentBunnyHood.defaultColor.z, equipmentBunnyHood.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(equipmentBunnyHood.cvar, defaultColor); - PATCH_GFX(gGiBunnyHoodDL, "Equipment_BunnyHood1", equipmentBunnyHood.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); - PATCH_GFX(gGiBunnyHoodDL, "Equipment_BunnyHood2", equipmentBunnyHood.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); - PATCH_GFX(gGiBunnyHoodDL, "Equipment_BunnyHood3", equipmentBunnyHood.changedCvar, 83, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); - PATCH_GFX(gGiBunnyHoodDL, "Equipment_BunnyHood4", equipmentBunnyHood.changedCvar, 84, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); - PATCH_GFX(gLinkChildBunnyHoodDL, "Equipment_BunnyHood5", equipmentBunnyHood.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + Color_RGBA8 color = CVarGetColor(equipmentBunnyHood.cvar, equipmentBunnyHood.defaultColor); + PATCH_GFX(gGiBunnyHoodDL, "Equipment_BunnyHood1", equipmentBunnyHood.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + PATCH_GFX(gGiBunnyHoodDL, "Equipment_BunnyHood2", equipmentBunnyHood.changedCvar, 6, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); + PATCH_GFX(gGiBunnyHoodDL, "Equipment_BunnyHood3", equipmentBunnyHood.changedCvar, 83, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); + PATCH_GFX(gGiBunnyHoodDL, "Equipment_BunnyHood4", equipmentBunnyHood.changedCvar, 84, gsDPSetEnvColor(color.r / 3, color.g / 3, color.b / 3, 255)); + PATCH_GFX(gLinkChildBunnyHoodDL, "Equipment_BunnyHood5", equipmentBunnyHood.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); if (manualChange) { - PATCH_GFX(gLinkChildBunnyHoodDL, "Equipment_BunnyHood6", equipmentBunnyHood.changedCvar, 13, gsSPGrayscale(true)); + PATCH_GFX(gLinkChildBunnyHoodDL, "Equipment_BunnyHood6", equipmentBunnyHood.changedCvar, 13, gsSPGrayscale(true)); if (CVarGetInteger(equipmentBunnyHood.changedCvar, 0)) { - ResourceMgr_PatchGfxByName(gLinkChildBunnyHoodDL, "Equipment_BunnyHood7", 125, gsSPBranchListOTRFilePath(gEndGrayscaleAndEndDlistDL)); + ResourceMgr_PatchGfxByName(gLinkChildBunnyHoodDL, "Equipment_BunnyHood7", 125, gsSPBranchListOTRFilePath(gEndGrayscaleAndEndDlistDL)); } else { ResourceMgr_UnpatchGfxByName(gLinkChildBunnyHoodDL, "Equipment_BunnyHood7"); } @@ -988,8 +1053,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& consumableGreenRupee = cosmeticOptions.at("Consumable.GreenRupee"); if (manualChange || CVarGetInteger(consumableGreenRupee.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {consumableGreenRupee.defaultColor.x, consumableGreenRupee.defaultColor.y, consumableGreenRupee.defaultColor.z, consumableGreenRupee.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(consumableGreenRupee.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(consumableGreenRupee.cvar, consumableGreenRupee.defaultColor); PATCH_GFX(gGiGreenRupeeInnerColorDL, "Consumable_GreenRupee1", consumableGreenRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiGreenRupeeInnerColorDL, "Consumable_GreenRupee2", consumableGreenRupee.changedCvar, 4, gsDPSetEnvColor(color.r / 5, color.g / 5, color.b / 5, 255)); PATCH_GFX(gGiGreenRupeeOuterColorDL, "Consumable_GreenRupee3", consumableGreenRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, MIN(color.r + 100, 255), MIN(color.g + 100, 255), MIN(color.b + 100, 255), 255)); @@ -1008,8 +1072,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& consumableBlueRupee = cosmeticOptions.at("Consumable.BlueRupee"); if (manualChange || CVarGetInteger(consumableBlueRupee.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {consumableBlueRupee.defaultColor.x, consumableBlueRupee.defaultColor.y, consumableBlueRupee.defaultColor.z, consumableBlueRupee.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(consumableBlueRupee.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(consumableBlueRupee.cvar, consumableBlueRupee.defaultColor); PATCH_GFX(gGiBlueRupeeInnerColorDL, "Consumable_BlueRupee1", consumableBlueRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiBlueRupeeInnerColorDL, "Consumable_BlueRupee2", consumableBlueRupee.changedCvar, 4, gsDPSetEnvColor(color.r / 5, color.g / 5, color.b / 5, 255)); PATCH_GFX(gGiBlueRupeeOuterColorDL, "Consumable_BlueRupee3", consumableBlueRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, MIN(color.r + 100, 255), MIN(color.g + 100, 255), MIN(color.b + 100, 255), 255)); @@ -1017,8 +1080,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& consumableRedRupee = cosmeticOptions.at("Consumable.RedRupee"); if (manualChange || CVarGetInteger(consumableRedRupee.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {consumableRedRupee.defaultColor.x, consumableRedRupee.defaultColor.y, consumableRedRupee.defaultColor.z, consumableRedRupee.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(consumableRedRupee.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(consumableRedRupee.cvar, consumableRedRupee.defaultColor); PATCH_GFX(gGiRedRupeeInnerColorDL, "Consumable_RedRupee1", consumableRedRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiRedRupeeInnerColorDL, "Consumable_RedRupee2", consumableRedRupee.changedCvar, 4, gsDPSetEnvColor(color.r / 5, color.g / 5, color.b / 5, 255)); PATCH_GFX(gGiRedRupeeOuterColorDL, "Consumable_RedRupee3", consumableRedRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, MIN(color.r + 100, 255), MIN(color.g + 100, 255), MIN(color.b + 100, 255), 255)); @@ -1026,8 +1088,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& consumablePurpleRupee = cosmeticOptions.at("Consumable.PurpleRupee"); if (manualChange || CVarGetInteger(consumablePurpleRupee.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {consumablePurpleRupee.defaultColor.x, consumablePurpleRupee.defaultColor.y, consumablePurpleRupee.defaultColor.z, consumablePurpleRupee.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(consumablePurpleRupee.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(consumablePurpleRupee.cvar, consumablePurpleRupee.defaultColor); PATCH_GFX(gGiPurpleRupeeInnerColorDL, "Consumable_PurpleRupee1", consumablePurpleRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiPurpleRupeeInnerColorDL, "Consumable_PurpleRupee2", consumablePurpleRupee.changedCvar, 4, gsDPSetEnvColor(color.r / 5, color.g / 5, color.b / 5, 255)); PATCH_GFX(gGiPurpleRupeeOuterColorDL, "Consumable_PurpleRupee3", consumablePurpleRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, MIN(color.r + 100, 255), MIN(color.g + 100, 255), MIN(color.b + 100, 255), 255)); @@ -1035,8 +1096,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& consumableGoldRupee = cosmeticOptions.at("Consumable.GoldRupee"); if (manualChange || CVarGetInteger(consumableGoldRupee.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {consumableGoldRupee.defaultColor.x, consumableGoldRupee.defaultColor.y, consumableGoldRupee.defaultColor.z, consumableGoldRupee.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(consumableGoldRupee.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(consumableGoldRupee.cvar, consumableGoldRupee.defaultColor); PATCH_GFX(gGiGoldRupeeInnerColorDL, "Consumable_GoldRupee1", consumableGoldRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiGoldRupeeInnerColorDL, "Consumable_GoldRupee2", consumableGoldRupee.changedCvar, 4, gsDPSetEnvColor(color.r / 5, color.g / 5, color.b / 5, 255)); PATCH_GFX(gGiGoldRupeeOuterColorDL, "Consumable_GoldRupee3", consumableGoldRupee.changedCvar, 3, gsDPSetPrimColor(0, 0, MIN(color.r + 100, 255), MIN(color.g + 100, 255), MIN(color.b + 100, 255), 255)); @@ -1045,12 +1105,13 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& consumableHearts = cosmeticOptions.at("Consumable.Hearts"); if (manualChange || CVarGetInteger(consumableHearts.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {consumableHearts.defaultColor.x, consumableHearts.defaultColor.y, consumableHearts.defaultColor.z, consumableHearts.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(consumableHearts.cvar, defaultColor); - // PATCH_GFX(gGiRecoveryHeartDL, "Consumable_Hearts1", consumableHearts.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); - // PATCH_GFX(gGiRecoveryHeartDL, "Consumable_Hearts2", consumableHearts.changedCvar, 26, gsSPGrayscale(true)); - // PATCH_GFX(gGiRecoveryHeartDL, "Consumable_Hearts3", consumableHearts.changedCvar, 72, gsSPGrayscale(false)); - // PATCH_GFX(gGiRecoveryHeartDL, "Consumable_Hearts4", consumableHearts.changedCvar, 74, gsSPEndDisplayList()); + Color_RGBA8 color = CVarGetColor(consumableHearts.cvar, consumableHearts.defaultColor); + /* + PATCH_GFX(gGiRecoveryHeartDL, "Consumable_Hearts1", consumableHearts.changedCvar, 4, gsDPSetGrayscaleColor(color.r, color.g, color.b, 255)); + PATCH_GFX(gGiRecoveryHeartDL, "Consumable_Hearts2", consumableHearts.changedCvar, 26, gsSPGrayscale(true)); + PATCH_GFX(gGiRecoveryHeartDL, "Consumable_Hearts3", consumableHearts.changedCvar, 72, gsSPGrayscale(false)); + PATCH_GFX(gGiRecoveryHeartDL, "Consumable_Hearts4", consumableHearts.changedCvar, 74, gsSPEndDisplayList()); + */ PATCH_GFX(gGiHeartPieceDL, "Consumable_Hearts5", consumableHearts.changedCvar, 2, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiHeartPieceDL, "Consumable_Hearts6", consumableHearts.changedCvar, 6, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255)); PATCH_GFX(gGiHeartContainerDL, "Consumable_Hearts7", consumableHearts.changedCvar, 2, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -1060,8 +1121,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } static CosmeticOption& consumableMagic = cosmeticOptions.at("Consumable.Magic"); if (manualChange || CVarGetInteger(consumableMagic.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {consumableMagic.defaultColor.x, consumableMagic.defaultColor.y, consumableMagic.defaultColor.z, consumableMagic.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(consumableMagic.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(consumableMagic.cvar, consumableMagic.defaultColor); PATCH_GFX(gGiMagicJarSmallDL, "Consumable_Magic1", consumableMagic.changedCvar, 31, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gGiMagicJarSmallDL, "Consumable_Magic2", consumableMagic.changedCvar, 32, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255)); PATCH_GFX(gGiMagicJarLargeDL, "Consumable_Magic3", consumableMagic.changedCvar, 31, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -1072,8 +1132,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& npcGoldenSkulltula = cosmeticOptions.at("NPC.GoldenSkulltula"); if (manualChange || CVarGetInteger(npcGoldenSkulltula.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {npcGoldenSkulltula.defaultColor.x, npcGoldenSkulltula.defaultColor.y, npcGoldenSkulltula.defaultColor.z, npcGoldenSkulltula.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(npcGoldenSkulltula.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(npcGoldenSkulltula.cvar, npcGoldenSkulltula.defaultColor); PATCH_GFX(gSkulltulaTokenDL, "NPC_GoldenSkulltula1", npcGoldenSkulltula.changedCvar, 5, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); PATCH_GFX(gSkulltulaTokenDL, "NPC_GoldenSkulltula2", npcGoldenSkulltula.changedCvar, 6, gsDPSetEnvColor(color.r / 2, color.g / 2, color.b / 2, 255)); PATCH_GFX(gSkulltulaTokenFlameDL, "NPC_GoldenSkulltula3", npcGoldenSkulltula.changedCvar, 32, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); @@ -1088,8 +1147,7 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& npcGerudo = cosmeticOptions.at("NPC.Gerudo"); if (manualChange || CVarGetInteger(npcGerudo.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {npcGerudo.defaultColor.x, npcGerudo.defaultColor.y, npcGerudo.defaultColor.z, npcGerudo.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(npcGerudo.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(npcGerudo.cvar, npcGerudo.defaultColor); PATCH_GFX(gGerudoPurpleTorsoDL, "NPC_Gerudo1", npcGerudo.changedCvar, 139, gsDPSetEnvColor( color.r, color.g, color.b, 255)); PATCH_GFX(gGerudoPurpleRightThighDL, "NPC_Gerudo2", npcGerudo.changedCvar, 11, gsDPSetEnvColor(color.r, color.g, color.b, 255)); PATCH_GFX(gGerudoPurpleLeftThighDL, "NPC_Gerudo3", npcGerudo.changedCvar, 11, gsDPSetEnvColor(color.r, color.g, color.b, 255)); @@ -1102,36 +1160,31 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { static CosmeticOption& npcMetalTrap = cosmeticOptions.at("NPC.MetalTrap"); if (manualChange || CVarGetInteger(npcMetalTrap.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {npcMetalTrap.defaultColor.x, npcMetalTrap.defaultColor.y, npcMetalTrap.defaultColor.z, npcMetalTrap.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(npcMetalTrap.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(npcMetalTrap.cvar, npcMetalTrap.defaultColor); PATCH_GFX(gSlidingBladeTrapDL, "NPC_MetalTrap1", npcMetalTrap.changedCvar, 59, gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255)); } static CosmeticOption& n64LogoRed = cosmeticOptions.at("Title.N64LogoRed"); if (manualChange || CVarGetInteger(n64LogoRed.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {n64LogoRed.defaultColor.x, n64LogoRed.defaultColor.y, n64LogoRed.defaultColor.z, n64LogoRed.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(n64LogoRed.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(n64LogoRed.cvar, n64LogoRed.defaultColor); PATCH_GFX(gNintendo64LogoDL, "Title_N64LogoRed1", n64LogoRed.changedCvar, 17, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)) PATCH_GFX(gNintendo64LogoDL, "Title_N64LogoRed2", n64LogoRed.changedCvar, 18, gsDPSetEnvColor(color.r, color.g, color.b, 128)); } static CosmeticOption& n64LogoBlue = cosmeticOptions.at("Title.N64LogoBlue"); if (manualChange || CVarGetInteger(n64LogoBlue.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {n64LogoBlue.defaultColor.x, n64LogoBlue.defaultColor.y, n64LogoBlue.defaultColor.z, n64LogoBlue.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(n64LogoBlue.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(n64LogoBlue.cvar, n64LogoBlue.defaultColor); PATCH_GFX(gNintendo64LogoDL, "Title_N64LogoBlue1", n64LogoBlue.changedCvar, 29, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)) PATCH_GFX(gNintendo64LogoDL, "Title_N64LogoBlue2", n64LogoBlue.changedCvar, 30, gsDPSetEnvColor(color.r, color.g, color.b, 128)); } static CosmeticOption& n64LogoGreen = cosmeticOptions.at("Title.N64LogoGreen"); if (manualChange || CVarGetInteger(n64LogoGreen.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {n64LogoGreen.defaultColor.x, n64LogoGreen.defaultColor.y, n64LogoGreen.defaultColor.z, n64LogoGreen.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(n64LogoGreen.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(n64LogoGreen.cvar, n64LogoGreen.defaultColor); PATCH_GFX(gNintendo64LogoDL, "Title_N64LogoGreen1", n64LogoGreen.changedCvar, 56, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)) PATCH_GFX(gNintendo64LogoDL, "Title_N64LogoGreen2", n64LogoGreen.changedCvar, 57, gsDPSetEnvColor(color.r, color.g, color.b, 128)); } static CosmeticOption& n64LogoYellow = cosmeticOptions.at("Title.N64LogoYellow"); if (manualChange || CVarGetInteger(n64LogoYellow.rainbowCvar, 0)) { - static Color_RGBA8 defaultColor = {n64LogoYellow.defaultColor.x, n64LogoYellow.defaultColor.y, n64LogoYellow.defaultColor.z, n64LogoYellow.defaultColor.w}; - Color_RGBA8 color = CVarGetColor(n64LogoYellow.cvar, defaultColor); + Color_RGBA8 color = CVarGetColor(n64LogoYellow.cvar, n64LogoYellow.defaultColor); PATCH_GFX(gNintendo64LogoDL, "Title_N64LogoYellow1", n64LogoYellow.changedCvar, 81, gsDPSetPrimColor(0, 0, 255, 255, 255, 255)) PATCH_GFX(gNintendo64LogoDL, "Title_N64LogoYellow2", n64LogoYellow.changedCvar, 82, gsDPSetEnvColor(color.r, color.g, color.b, 128)); } @@ -1147,6 +1200,15 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { } } +extern "C" Color_RGBA8 CosmeticsEditor_GetDefaultValue(const char* id) { + return Color_RGBA8 { + (uint8_t)(cosmeticOptions[id].defaultColor.r * 255.0f), + (uint8_t)(cosmeticOptions[id].defaultColor.g * 255.0f), + (uint8_t)(cosmeticOptions[id].defaultColor.b * 255.0f), + (uint8_t)(cosmeticOptions[id].defaultColor.a * 255.0f) + }; +} + void Table_InitHeader(bool has_header = true) { if (has_header) { ImGui::TableHeadersRow(); @@ -1155,14 +1217,16 @@ void Table_InitHeader(bool has_header = true) { ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); //This is to adjust Vertical pos of item in a cell to be normlized. ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 2); - ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x-60); + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - 60); } + void DrawUseMarginsSlider(const std::string ElementName, const std::string CvarName){ std::string CvarLabel = CvarName + ".UseMargins"; std::string Label = ElementName + " use margins"; UIWidgets::EnhancementCheckbox(Label.c_str(), CvarLabel.c_str()); UIWidgets::Tooltip("Using this allow you move the element with General margins sliders"); } + void DrawPositionsRadioBoxes(const std::string CvarName, bool NoAnchorEnabled = true){ std::string CvarLabel = CvarName + ".PosType"; UIWidgets::EnhancementRadioButton("Original position", CvarLabel.c_str(), 0); @@ -1178,22 +1242,25 @@ void DrawPositionsRadioBoxes(const std::string CvarName, bool NoAnchorEnabled = UIWidgets::EnhancementRadioButton("Hidden", CvarLabel.c_str(), 4); UIWidgets::Tooltip("This will make your elements hidden"); } + void DrawPositionSlider(const std::string CvarName, int MinY, int MaxY, int MinX, int MaxX){ std::string PosXCvar = CvarName + ".PosX"; std::string PosYCvar = CvarName + ".PosY"; - std::string InvisibleLabelX = "##"+PosXCvar; - std::string InvisibleLabelY = "##"+PosYCvar; + std::string InvisibleLabelX = "##" + PosXCvar; + std::string InvisibleLabelY = "##" + PosYCvar; UIWidgets::EnhancementSliderInt("Up <-> Down : %d", InvisibleLabelY.c_str(), PosYCvar.c_str(), MinY, MaxY, "", 0); UIWidgets::Tooltip("This slider is used to move Up and Down your elements."); UIWidgets::EnhancementSliderInt("Left <-> Right : %d", InvisibleLabelX.c_str(), PosXCvar.c_str(), MinX, MaxX, "", 0); UIWidgets::Tooltip("This slider is used to move Left and Right your elements."); } -void DrawScaleSlider(const std::string CvarName,float DefaultValue){ - std::string InvisibleLabel = "##"+CvarName; + +void DrawScaleSlider(const std::string CvarName, float DefaultValue){ + std::string InvisibleLabel = "##" + CvarName; std::string CvarLabel = CvarName + ".Scale"; //Disabled for now. feature not done and several fixes needed to be merged. //UIWidgets::EnhancementSliderFloat("Scale : %dx", InvisibleLabel.c_str(), CvarLabel.c_str(), 0.1f, 3.0f,"",DefaultValue,true); } + void Draw_Table_Dropdown(const char* Header_Title, const char* Table_ID, const char* Column_Title, const char* Slider_Title, const char* Slider_ID, int MinY, int MaxY, int MinX, int MaxX, float Default_Value) { if (ImGui::CollapsingHeader(Header_Title)) { if (ImGui::BeginTable(Table_ID, 1, FlagsTable)) { @@ -1208,6 +1275,7 @@ void Draw_Table_Dropdown(const char* Header_Title, const char* Table_ID, const c } } } + void C_Button_Dropdown(const char* Header_Title, const char* Table_ID, const char* Column_Title, const char* Slider_Title, const char* Slider_ID, const char* Int_Type, float Slider_Scale_Value) { if (ImGui::CollapsingHeader(Header_Title)) { if (ImGui::BeginTable(Table_ID, 1, FlagsTable)) { @@ -1216,15 +1284,15 @@ void C_Button_Dropdown(const char* Header_Title, const char* Table_ID, const cha DrawUseMarginsSlider(Slider_Title, Slider_ID); DrawPositionsRadioBoxes(Slider_ID); s16 Min_X_CU = 0; - s16 Max_X_CU = ImGui::GetWindowViewport()->Size.x/2; - if(CVarGetInteger(Int_Type,0) == 2){ + s16 Max_X_CU = static_cast(ImGui::GetWindowViewport()->Size.x / 2); + if(CVarGetInteger(Int_Type, 0) == 2){ Max_X_CU = 294; - } else if(CVarGetInteger(Int_Type,0) == 3){ - Max_X_CU = ImGui::GetWindowViewport()->Size.x/2; - } else if(CVarGetInteger(Int_Type,0) == 4){ - Min_X_CU = (ImGui::GetWindowViewport()->Size.x/2)*-1; + } else if(CVarGetInteger(Int_Type, 0) == 3){ + Max_X_CU = static_cast(ImGui::GetWindowViewport()->Size.x / 2); + } else if(CVarGetInteger(Int_Type, 0) == 4){ + Min_X_CU = static_cast(ImGui::GetWindowViewport()->Size.x / 2) * -1; } - DrawPositionSlider(Slider_ID, 0, ImGui::GetWindowViewport()->Size.y/2, Min_X_CU, Max_X_CU); + DrawPositionSlider(Slider_ID, 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), Min_X_CU, Max_X_CU); DrawScaleSlider(Slider_ID, Slider_Scale_Value); ImGui::NewLine(); ImGui::EndTable(); @@ -1244,14 +1312,15 @@ void C_Button_Dropdown(const char* Header_Title, const char* Table_ID, const cha } } } + void Draw_Placements(){ if (ImGui::BeginTable("tableMargins", 1, FlagsTable)) { ImGui::TableSetupColumn("General margins settings", FlagsCell, TablesCellsWidth); Table_InitHeader(); - UIWidgets::EnhancementSliderInt("Top : %dx", "##UIMARGINT", CVAR_COSMETIC("HUD.Margin.T"), (ImGui::GetWindowViewport()->Size.y/2)*-1, 25, "", 0); - UIWidgets::EnhancementSliderInt("Left: %dx", "##UIMARGINL", CVAR_COSMETIC("HUD.Margin.L"), -25, ImGui::GetWindowViewport()->Size.x, "", 0); - UIWidgets::EnhancementSliderInt("Right: %dx", "##UIMARGINR", CVAR_COSMETIC("HUD.Margin.R"), (ImGui::GetWindowViewport()->Size.x)*-1, 25, "", 0); - UIWidgets::EnhancementSliderInt("Bottom: %dx", "##UIMARGINB", CVAR_COSMETIC("HUD.Margin.B"), (ImGui::GetWindowViewport()->Size.y/2)*-1, 25, "", 0); + UIWidgets::EnhancementSliderInt("Top : %dx", "##UIMARGINT", CVAR_COSMETIC("HUD.Margin.T"), static_cast(ImGui::GetWindowViewport()->Size.y / 2) * -1, 25, "", 0); + UIWidgets::EnhancementSliderInt("Left: %dx", "##UIMARGINL", CVAR_COSMETIC("HUD.Margin.L"), -25, static_cast(ImGui::GetWindowViewport()->Size.x), "", 0); + UIWidgets::EnhancementSliderInt("Right: %dx", "##UIMARGINR", CVAR_COSMETIC("HUD.Margin.R"), static_cast(ImGui::GetWindowViewport()->Size.x) * -1, 25, "", 0); + UIWidgets::EnhancementSliderInt("Bottom: %dx", "##UIMARGINB", CVAR_COSMETIC("HUD.Margin.B"), static_cast(ImGui::GetWindowViewport()->Size.y / 2) * -1, 25, "", 0); SetMarginAll("All margins on",true); UIWidgets::Tooltip("Set most of the elements to use margins\nSome elements with default position will not be affected\nElements without Anchor or Hidden will not be turned on"); ImGui::SameLine(); @@ -1269,8 +1338,8 @@ void Draw_Placements(){ Table_InitHeader(false); DrawUseMarginsSlider("Hearts counts", CVAR_COSMETIC("HUD.Hearts")); DrawPositionsRadioBoxes(CVAR_COSMETIC("HUD.HeartsCount")); - DrawPositionSlider(CVAR_COSMETIC("HUD.HeartsCount"),-22,ImGui::GetWindowViewport()->Size.y,-125,ImGui::GetWindowViewport()->Size.x); - DrawScaleSlider(CVAR_COSMETIC("HUD.HeartsCount"),0.7f); + DrawPositionSlider(CVAR_COSMETIC("HUD.HeartsCount"), -22, static_cast(ImGui::GetWindowViewport()->Size.y), -125, static_cast(ImGui::GetWindowViewport()->Size.x)); + DrawScaleSlider(CVAR_COSMETIC("HUD.HeartsCount"), 0.7f); UIWidgets::EnhancementSliderInt("Heart line length : %d", "##HeartLineLength", CVAR_COSMETIC("HUD.Hearts.LineLength"), 0, 20, "", 10); UIWidgets::Tooltip("This will set the length of a row of hearts. Set to 0 for unlimited length."); ImGui::NewLine(); @@ -1285,34 +1354,34 @@ void Draw_Placements(){ DrawPositionsRadioBoxes(CVAR_COSMETIC("HUD.MagicBar")); UIWidgets::EnhancementRadioButton("Anchor to life bar", CVAR_COSMETIC("HUD.MagicBar.PosType"), 5); UIWidgets::Tooltip("This will make your elements follow the bottom of the life meter"); - DrawPositionSlider(CVAR_COSMETIC("HUD.MagicBar"), 0, ImGui::GetWindowViewport()->Size.y/2, -5, ImGui::GetWindowViewport()->Size.x/2); - DrawScaleSlider(CVAR_COSMETIC("HUD.MagicBar"),1.0f); + DrawPositionSlider(CVAR_COSMETIC("HUD.MagicBar"), 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), -5, static_cast(ImGui::GetWindowViewport()->Size.x / 2)); + DrawScaleSlider(CVAR_COSMETIC("HUD.MagicBar"), 1.0f); ImGui::NewLine(); ImGui::EndTable(); } } - if (CVarGetInteger(CVAR_ENHANCEMENT("VisualAgony"),0) && ImGui::CollapsingHeader("Visual stone of agony position")) { + if (CVarGetInteger(CVAR_ENHANCEMENT("VisualAgony"), 0) && ImGui::CollapsingHeader("Visual stone of agony position")) { if (ImGui::BeginTable("tabledvisualstoneofagony", 1, FlagsTable)) { ImGui::TableSetupColumn("Visual stone of agony settings", FlagsCell, TablesCellsWidth); Table_InitHeader(false); DrawUseMarginsSlider("Visual stone of agony", CVAR_COSMETIC("HUD.VisualSoA")); DrawPositionsRadioBoxes(CVAR_COSMETIC("HUD.VisualSoA")); s16 Min_X_VSOA = 0; - s16 Max_X_VSOA = ImGui::GetWindowViewport()->Size.x/2; - if(CVarGetInteger(CVAR_COSMETIC("HUD.VisualSoA.PosType"),0) == 2){ + s16 Max_X_VSOA = static_cast(ImGui::GetWindowViewport()->Size.x / 2); + if(CVarGetInteger(CVAR_COSMETIC("HUD.VisualSoA.PosType"), 0) == 2){ Max_X_VSOA = 290; - } else if(CVarGetInteger(CVAR_COSMETIC("HUD.VisualSoA.PosType"),0) == 4){ - Min_X_VSOA = (ImGui::GetWindowViewport()->Size.x/2)*-1; + } else if(CVarGetInteger(CVAR_COSMETIC("HUD.VisualSoA.PosType"), 0) == 4){ + Min_X_VSOA = static_cast(ImGui::GetWindowViewport()->Size.x / 2) * -1; } - DrawPositionSlider(CVAR_COSMETIC("HUD.VisualSoA"), 0, ImGui::GetWindowViewport()->Size.y/2, Min_X_VSOA, Max_X_VSOA); - DrawScaleSlider(CVAR_COSMETIC("HUD.VisualSoA"),1.0f); + DrawPositionSlider(CVAR_COSMETIC("HUD.VisualSoA"), 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), Min_X_VSOA, Max_X_VSOA); + DrawScaleSlider(CVAR_COSMETIC("HUD.VisualSoA"), 1.0f); ImGui::NewLine(); ImGui::EndTable(); } } - Draw_Table_Dropdown("B Button position", "tablebbtn", "B Button settings", "B Button", CVAR_COSMETIC("HUD.BButton"), 0, ImGui::GetWindowViewport()->Size.y/4+50, -1, ImGui::GetWindowViewport()->Size.x-50, 0.95f); - Draw_Table_Dropdown("A Button position", "tableabtn", "A Button settings", "A Button", CVAR_COSMETIC("HUD.AButton"), -10, ImGui::GetWindowViewport()->Size.y/4+50, -20, ImGui::GetWindowViewport()->Size.x-50, 0.95f); - Draw_Table_Dropdown("Start Button position", "tablestartbtn", "Start Button settings", "Start Button", CVAR_COSMETIC("HUD.StartButton"), 0, ImGui::GetWindowViewport()->Size.y/2, 0, ImGui::GetWindowViewport()->Size.x/2+70, 0.75f); + Draw_Table_Dropdown("B Button position", "tablebbtn", "B Button settings", "B Button", CVAR_COSMETIC("HUD.BButton"), 0, static_cast(ImGui::GetWindowViewport()->Size.y / 4) + 50, -1, static_cast(ImGui::GetWindowViewport()->Size.x) - 50, 0.95f); + Draw_Table_Dropdown("A Button position", "tableabtn", "A Button settings", "A Button", CVAR_COSMETIC("HUD.AButton"), -10, static_cast(ImGui::GetWindowViewport()->Size.y / 4) + 50, -20, static_cast(ImGui::GetWindowViewport()->Size.x) - 50, 0.95f); + Draw_Table_Dropdown("Start Button position", "tablestartbtn", "Start Button settings", "Start Button", CVAR_COSMETIC("HUD.StartButton"), 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), 0, static_cast(ImGui::GetWindowViewport()->Size.x / 2) + 70, 0.75f); C_Button_Dropdown("C Button Up position", "tablecubtn", "C Button Up settings", "C Button Up", CVAR_COSMETIC("HUD.CUpButton"), CVAR_COSMETIC("HUD.CUpButton.PosType"), 0.5f); C_Button_Dropdown("C Button Down position", "tablecdbtn", "C Button Down settings", "C Button Down", CVAR_COSMETIC("HUD.CDownButton"), CVAR_COSMETIC("HUD.CDownButton.PosType"), 0.87f); C_Button_Dropdown("C Button Left position", "tableclbtn", "C Button Left settings", "C Button Left", CVAR_COSMETIC("HUD.CLeftButton"), CVAR_COSMETIC("HUD.CLeftButton.PosType"), 0.87f); @@ -1324,27 +1393,36 @@ void Draw_Placements(){ DrawUseMarginsSlider("DPad items", CVAR_COSMETIC("HUD.Dpad")); DrawPositionsRadioBoxes(CVAR_COSMETIC("HUD.Dpad")); s16 Min_X_Dpad = 0; - s16 Max_X_Dpad = ImGui::GetWindowViewport()->Size.x/2; - if(CVarGetInteger(CVAR_COSMETIC("HUD.Dpad.PosType"),0) == 2){ + s16 Max_X_Dpad = static_cast(ImGui::GetWindowViewport()->Size.x / 2); + if(CVarGetInteger(CVAR_COSMETIC("HUD.Dpad.PosType"), 0) == 2){ Max_X_Dpad = 290; - } else if(CVarGetInteger(CVAR_COSMETIC("HUD.Dpad.PosType"),0) == 4){ - Min_X_Dpad = (ImGui::GetWindowViewport()->Size.x/2)*-1; + } else if(CVarGetInteger(CVAR_COSMETIC("HUD.Dpad.PosType"), 0) == 4){ + Min_X_Dpad = static_cast(ImGui::GetWindowViewport()->Size.x / 2) * -1; } - DrawPositionSlider(CVAR_COSMETIC("HUD.Dpad"), 0, ImGui::GetWindowViewport()->Size.y/2, Min_X_Dpad, Max_X_Dpad); - DrawScaleSlider(CVAR_COSMETIC("HUD.Dpad"),1.0f); + DrawPositionSlider(CVAR_COSMETIC("HUD.Dpad"), 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), Min_X_Dpad, Max_X_Dpad); + DrawScaleSlider(CVAR_COSMETIC("HUD.Dpad"), 1.0f); ImGui::NewLine(); ImGui::EndTable(); } } - Draw_Table_Dropdown("Minimaps position", "tableminimapspos", "minimaps settings", "Minimap", CVAR_COSMETIC("HUD.Minimap"), (ImGui::GetWindowViewport()->Size.y/3)*-1, ImGui::GetWindowViewport()->Size.y/3, ImGui::GetWindowViewport()->Size.x*-1, ImGui::GetWindowViewport()->Size.x/2, 1.0f); - Draw_Table_Dropdown("Small Keys counter position", "tablesmolekeys", "Small Keys counter settings", "Small Keys counter", CVAR_COSMETIC("HUD.SmallKey"), 0, ImGui::GetWindowViewport()->Size.y/3, -1, ImGui::GetWindowViewport()->Size.x/2, 1.0f); - Draw_Table_Dropdown("Rupee counter position", "tablerupeecount", "Rupee counter settings", "Rupee counter", CVAR_COSMETIC("HUD.Rupees"), -2, ImGui::GetWindowViewport()->Size.y/3, -3, ImGui::GetWindowViewport()->Size.x/2, 1.0f); - Draw_Table_Dropdown("Carrots position", "tableCarrots", "Carrots settings", "Carrots", CVAR_COSMETIC("HUD.Carrots"), 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+25, 1.0f); - Draw_Table_Dropdown("Timers position", "tabletimers", "Timers settings", "Timers", CVAR_COSMETIC("HUD.Timers"), 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2-50, 1.0f); - Draw_Table_Dropdown("Archery Scores position", "tablearchery", "Archery Scores settings", "Archery scores", CVAR_COSMETIC("HUD.ArcheryScore"), 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2-50, 1.0f); - Draw_Table_Dropdown("Title cards (Maps) position", "tabletcmaps", "Titlecard maps settings", "Title cards (overworld)", CVAR_COSMETIC("HUD.TitleCard.Map"), 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+10, 1.0f); - Draw_Table_Dropdown("Title cards (Bosses) position", "tabletcbosses", "Title cards (Bosses) settings", "Title cards (Bosses)", CVAR_COSMETIC("HUD.TitleCard.Boss"), 0, ImGui::GetWindowViewport()->Size.y/2, -50, ImGui::GetWindowViewport()->Size.x/2+10, 1.0f); - Draw_Table_Dropdown("In-game Gameplay Timer position", "tablegameplaytimer", "In-game Gameplay Timer settings", "In-game Gameplay Timer", CVAR_COSMETIC("HUD.IGT"), 0, ImGui::GetWindowViewport()->Size.y / 2, -50, ImGui::GetWindowViewport()->Size.x / 2 + 10, 1.0f); + Draw_Table_Dropdown("Minimaps position", "tableminimapspos", "minimaps settings", "Minimap", CVAR_COSMETIC("HUD.Minimap"), + static_cast(ImGui::GetWindowViewport()->Size.y / 3) * -1, static_cast(ImGui::GetWindowViewport()->Size.y / 3), static_cast(ImGui::GetWindowViewport()->Size.x) * -1, static_cast(ImGui::GetWindowViewport()->Size.x / 2), 1.0f); + Draw_Table_Dropdown("Small Keys counter position", "tablesmolekeys", "Small Keys counter settings", "Small Keys counter", CVAR_COSMETIC("HUD.SmallKey"), + 0, static_cast(ImGui::GetWindowViewport()->Size.y / 3), -1, static_cast(ImGui::GetWindowViewport()->Size.x / 2), 1.0f); + Draw_Table_Dropdown("Rupee counter position", "tablerupeecount", "Rupee counter settings", "Rupee counter", CVAR_COSMETIC("HUD.Rupees"), + -2, static_cast(ImGui::GetWindowViewport()->Size.y / 3), -3, static_cast(ImGui::GetWindowViewport()->Size.x / 2), 1.0f); + Draw_Table_Dropdown("Carrots position", "tableCarrots", "Carrots settings", "Carrots", CVAR_COSMETIC("HUD.Carrots"), + 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), -50, static_cast(ImGui::GetWindowViewport()->Size.x / 2) + 25, 1.0f); + Draw_Table_Dropdown("Timers position", "tabletimers", "Timers settings", "Timers", CVAR_COSMETIC("HUD.Timers"), + 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), -50, static_cast(ImGui::GetWindowViewport()->Size.x / 2) - 50, 1.0f); + Draw_Table_Dropdown("Archery Scores position", "tablearchery", "Archery Scores settings", "Archery scores", CVAR_COSMETIC("HUD.ArcheryScore"), + 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), -50, static_cast(ImGui::GetWindowViewport()->Size.x / 2) - 50, 1.0f); + Draw_Table_Dropdown("Title cards (Maps) position", "tabletcmaps", "Titlecard maps settings", "Title cards (overworld)", CVAR_COSMETIC("HUD.TitleCard.Map"), + 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), -50, static_cast(ImGui::GetWindowViewport()->Size.x / 2) + 10, 1.0f); + Draw_Table_Dropdown("Title cards (Bosses) position", "tabletcbosses", "Title cards (Bosses) settings", "Title cards (Bosses)", CVAR_COSMETIC("HUD.TitleCard.Boss"), + 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), -50, static_cast(ImGui::GetWindowViewport()->Size.x / 2) + 10, 1.0f); + Draw_Table_Dropdown("In-game Gameplay Timer position", "tablegameplaytimer", "In-game Gameplay Timer settings", "In-game Gameplay Timer", CVAR_COSMETIC("HUD.IGT"), + 0, static_cast(ImGui::GetWindowViewport()->Size.y / 2), -50, static_cast(ImGui::GetWindowViewport()->Size.x / 2) + 10, 1.0f); if (ImGui::CollapsingHeader("Enemy Health Bar position")) { if (ImGui::BeginTable("enemyhealthbar", 1, FlagsTable)) { ImGui::TableSetupColumn("Enemy Health Bar settings", FlagsCell, TablesCellsWidth); @@ -1356,7 +1434,7 @@ void Draw_Placements(){ UIWidgets::Tooltip("This will make your elements follow the top edge of your game window"); UIWidgets::EnhancementRadioButton("Anchor to the bottom", posTypeCVar.c_str(), ENEMYHEALTH_ANCHOR_BOTTOM); UIWidgets::Tooltip("This will make your elements follow the bottom edge of your game window"); - DrawPositionSlider(CVAR_COSMETIC("HUD.EnemyHealthBar."), -SCREEN_HEIGHT, SCREEN_HEIGHT, -ImGui::GetWindowViewport()->Size.x / 2, ImGui::GetWindowViewport()->Size.x / 2); + DrawPositionSlider(CVAR_COSMETIC("HUD.EnemyHealthBar."), -SCREEN_HEIGHT, SCREEN_HEIGHT, -static_cast(ImGui::GetWindowViewport()->Size.x / 2), static_cast(ImGui::GetWindowViewport()->Size.x / 2)); if (UIWidgets::EnhancementSliderInt("Health Bar Width: %d", "##EnemyHealthBarWidth", CVAR_COSMETIC("HUD.EnemyHealthBar.Width.Value"), 32, 128, "", 64)) { CVarSetInteger(CVAR_COSMETIC("HUD.EnemyHealthBar.Width.Changed"), 1); } @@ -1372,6 +1450,7 @@ void Draw_Placements(){ } } } + void Reset_Option_Single(const char* Button_Title, const char* name) { ImGui::SameLine(); if (ImGui::Button(Button_Title)) { @@ -1379,6 +1458,7 @@ void Reset_Option_Single(const char* Button_Title, const char* name) { Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } } + void Reset_Option_Double(const char* Button_Title, const char* name) { ImGui::SameLine(); if (ImGui::Button(Button_Title)) { @@ -1387,6 +1467,7 @@ void Reset_Option_Double(const char* Button_Title, const char* name) { Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } } + void DrawSillyTab() { ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0)); if (CVarGetInteger("gLetItSnow", 0)) { @@ -1441,15 +1522,15 @@ void DrawSillyTab() { // allows you create and use multiple shades of the same color. void CopyMultipliedColor(CosmeticOption& cosmeticOptionSrc, CosmeticOption& cosmeticOptionTarget, float amount = 0.75f) { Color_RGBA8 newColor; - newColor.r = MIN((cosmeticOptionSrc.currentColor.x * 255.0) * amount, 255); - newColor.g = MIN((cosmeticOptionSrc.currentColor.y * 255.0) * amount, 255); - newColor.b = MIN((cosmeticOptionSrc.currentColor.z * 255.0) * amount, 255); + newColor.r = static_cast(MIN((cosmeticOptionSrc.currentColor.x * 255.0f) * amount, 255)); + newColor.g = static_cast(MIN((cosmeticOptionSrc.currentColor.y * 255.0f) * amount, 255)); + newColor.b = static_cast(MIN((cosmeticOptionSrc.currentColor.z * 255.0f) * amount, 255)); newColor.a = 255; - cosmeticOptionTarget.currentColor.x = newColor.r / 255.0; - cosmeticOptionTarget.currentColor.y = newColor.g / 255.0; - cosmeticOptionTarget.currentColor.z = newColor.b / 255.0; - cosmeticOptionTarget.currentColor.w = newColor.a / 255.0; + cosmeticOptionTarget.currentColor.x = newColor.r / 255.0f; + cosmeticOptionTarget.currentColor.y = newColor.g / 255.0f; + cosmeticOptionTarget.currentColor.z = newColor.b / 255.0f; + cosmeticOptionTarget.currentColor.w = newColor.a / 255.0f; CVarSetColor(cosmeticOptionTarget.cvar, newColor); CVarSetInteger((cosmeticOptionTarget.rainbowCvar), 0); @@ -1555,33 +1636,34 @@ void ApplySideEffects(CosmeticOption& cosmeticOption) { } void RandomizeColor(CosmeticOption& cosmeticOption) { + ImVec4 randomColor = GetRandomValue(); Color_RGBA8 newColor; - newColor.r = Random(0, 255); - newColor.g = Random(0, 255); - newColor.b = Random(0, 255); + newColor.r = static_cast(randomColor.x * 255.0f); + newColor.g = static_cast(randomColor.y * 255.0f); + newColor.b = static_cast(randomColor.z * 255.0f); newColor.a = 255; // For alpha supported options, retain the last set alpha instead of overwriting if (cosmeticOption.supportsAlpha) { - newColor.a = cosmeticOption.currentColor.w * 255; + newColor.a = static_cast(cosmeticOption.currentColor.w * 255.0f); } - cosmeticOption.currentColor.x = newColor.r / 255.0; - cosmeticOption.currentColor.y = newColor.g / 255.0; - cosmeticOption.currentColor.z = newColor.b / 255.0; - cosmeticOption.currentColor.w = newColor.a / 255.0; + cosmeticOption.currentColor.x = newColor.r / 255.0f; + cosmeticOption.currentColor.y = newColor.g / 255.0f; + cosmeticOption.currentColor.z = newColor.b / 255.0f; + cosmeticOption.currentColor.w = newColor.a / 255.0f; CVarSetColor(cosmeticOption.cvar, newColor); - CVarSetInteger((cosmeticOption.rainbowCvar), 0); - CVarSetInteger((cosmeticOption.changedCvar), 1); + CVarSetInteger(cosmeticOption.rainbowCvar, 0); + CVarSetInteger(cosmeticOption.changedCvar, 1); ApplySideEffects(cosmeticOption); } void ResetColor(CosmeticOption& cosmeticOption) { - Color_RGBA8 defaultColor = {cosmeticOption.defaultColor.x, cosmeticOption.defaultColor.y, cosmeticOption.defaultColor.z, cosmeticOption.defaultColor.w}; - cosmeticOption.currentColor.x = defaultColor.r / 255.0; - cosmeticOption.currentColor.y = defaultColor.g / 255.0; - cosmeticOption.currentColor.z = defaultColor.b / 255.0; - cosmeticOption.currentColor.w = defaultColor.a / 255.0; + Color_RGBA8 defaultColor = {cosmeticOption.defaultColor.r, cosmeticOption.defaultColor.g, cosmeticOption.defaultColor.b, cosmeticOption.defaultColor.a}; + cosmeticOption.currentColor.x = defaultColor.r / 255.0f; + cosmeticOption.currentColor.y = defaultColor.g / 255.0f; + cosmeticOption.currentColor.z = defaultColor.b / 255.0f; + cosmeticOption.currentColor.w = defaultColor.a / 255.0f; CVarClear(cosmeticOption.changedCvar); CVarClear(cosmeticOption.rainbowCvar); @@ -1645,10 +1727,10 @@ void DrawCosmeticRow(CosmeticOption& cosmeticOption) { } if (colorChanged) { Color_RGBA8 color; - color.r = cosmeticOption.currentColor.x * 255.0; - color.g = cosmeticOption.currentColor.y * 255.0; - color.b = cosmeticOption.currentColor.z * 255.0; - color.a = cosmeticOption.currentColor.w * 255.0; + color.r = static_cast(cosmeticOption.currentColor.x * 255.0f); + color.g = static_cast(cosmeticOption.currentColor.y * 255.0f); + color.b = static_cast(cosmeticOption.currentColor.z * 255.0f); + color.a = static_cast(cosmeticOption.currentColor.w * 255.0f); CVarSetColor(cosmeticOption.cvar, color); CVarSetInteger((cosmeticOption.rainbowCvar), 0); @@ -1659,7 +1741,8 @@ void DrawCosmeticRow(CosmeticOption& cosmeticOption) { } ImGui::SameLine(); ImGui::Text("%s", cosmeticOption.label.c_str()); - ImGui::SameLine((ImGui::CalcTextSize("Mirror Shield Mirror").x * 1.0f) + 60.0f); + //the longest option name + ImGui::SameLine((ImGui::CalcTextSize("Message Light Blue (None No Shadow) Color").x * 1.0f) + 60.0f); if (ImGui::Button(("Random##" + cosmeticOption.label).c_str())) { RandomizeColor(cosmeticOption); ApplyOrResetCustomGfxPatches(); @@ -1695,7 +1778,8 @@ void DrawCosmeticRow(CosmeticOption& cosmeticOption) { void DrawCosmeticGroup(CosmeticGroup cosmeticGroup) { std::string label = groupLabels.at(cosmeticGroup); ImGui::Text("%s", label.c_str()); - ImGui::SameLine((ImGui::CalcTextSize("Mirror Shield Mirror").x * 1.0f) + 60.0f); + // the longest option name + ImGui::SameLine((ImGui::CalcTextSize("Message Light Blue (None No Shadow) Color").x * 1.0f) + 60.0f); if (ImGui::Button(("Random##" + label).c_str())) { for (auto& [id, cosmeticOption] : cosmeticOptions) { if (cosmeticOption.group == cosmeticGroup && (!cosmeticOption.advancedOption || CVarGetInteger(CVAR_COSMETIC("AdvancedMode"), 0)) && !CVarGetInteger(cosmeticOption.lockedCvar, 0)) { @@ -1791,6 +1875,36 @@ void CosmeticsEditorWindow::DrawElement() { } Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } + + if (ImGui::Button("Rainbow All", ImVec2(ImGui::GetContentRegionAvail().x / 2, 30.0f))) { + for (auto& [id, cosmeticOption] : cosmeticOptions) { + if ( + !CVarGetInteger(cosmeticOption.lockedCvar, 0) && + ( + !cosmeticOption.advancedOption || + CVarGetInteger(CVAR_COSMETIC("AdvancedMode"), 0) + ) + ) { + CVarSetInteger(cosmeticOption.rainbowCvar, 1); + } + } + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } + ImGui::SameLine(); + if (ImGui::Button("Un-Rainbow All", ImVec2(ImGui::GetContentRegionAvail().x, 30.0f))) { + for (auto& [id, cosmeticOption] : cosmeticOptions) { + if ( + !CVarGetInteger(cosmeticOption.lockedCvar, 0) && + ( + !cosmeticOption.advancedOption || + CVarGetInteger(CVAR_COSMETIC("AdvancedMode"), 0) + ) + ) { + CVarSetInteger(cosmeticOption.rainbowCvar, 0); + } + } + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } if (ImGui::BeginTabBar("CosmeticsContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { if (ImGui::BeginTabItem("Link & Items")) { @@ -1803,7 +1917,7 @@ void CosmeticsEditorWindow::DrawElement() { ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Effects")) { - // DrawCosmeticGroup(COSMETICS_GROUP_MAGIC); // Cosmetics TODO: Implement magic effect colors + DrawCosmeticGroup(COSMETICS_GROUP_MAGIC); DrawCosmeticGroup(COSMETICS_GROUP_ARROWS); DrawCosmeticGroup(COSMETICS_GROUP_SPIN_ATTACK); DrawCosmeticGroup(COSMETICS_GROUP_TRAILS); @@ -1844,6 +1958,13 @@ void CosmeticsEditorWindow::DrawElement() { DrawCosmeticGroup(COSMETICS_GROUP_KALEIDO); ImGui::EndTabItem(); } + + if (CVarGetInteger(CVAR_COSMETIC("AdvancedMode"), 0)) { + if (ImGui::BeginTabItem("Message")) { + DrawCosmeticGroup(COSMETICS_GROUP_MESSAGE); + ImGui::EndTabItem(); + } + } ImGui::EndTabBar(); } } @@ -1871,13 +1992,13 @@ void Cosmetics_RegisterOnSceneInitHook() { void CosmeticsEditorWindow::InitElement() { // Convert the `current color` into the format that the ImGui color picker expects for (auto& [id, cosmeticOption] : cosmeticOptions) { - Color_RGBA8 defaultColor = {cosmeticOption.defaultColor.x, cosmeticOption.defaultColor.y, cosmeticOption.defaultColor.z, cosmeticOption.defaultColor.w}; + Color_RGBA8 defaultColor = {cosmeticOption.defaultColor.r, cosmeticOption.defaultColor.g, cosmeticOption.defaultColor.b, cosmeticOption.defaultColor.a}; Color_RGBA8 cvarColor = CVarGetColor(cosmeticOption.cvar, defaultColor); - cosmeticOption.currentColor.x = cvarColor.r / 255.0; - cosmeticOption.currentColor.y = cvarColor.g / 255.0; - cosmeticOption.currentColor.z = cvarColor.b / 255.0; - cosmeticOption.currentColor.w = cvarColor.a / 255.0; + cosmeticOption.currentColor.x = cvarColor.r / 255.0f; + cosmeticOption.currentColor.y = cvarColor.g / 255.0f; + cosmeticOption.currentColor.z = cvarColor.b / 255.0f; + cosmeticOption.currentColor.w = cvarColor.a / 255.0f; } Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); ApplyOrResetCustomGfxPatches(); diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h index 88f60c76c..55dba5780 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h @@ -1,13 +1,6 @@ #pragma once #include -#define PATCH_GFX(path, name, cvar, index, instruction) \ - if (CVarGetInteger(cvar, 0)) { \ - ResourceMgr_PatchGfxByName(path, name, index, instruction); \ - } else { \ - ResourceMgr_UnpatchGfxByName(path, name); \ - } - // Not to be confused with tabs, groups are 1:1 with the boxes shown in the UI, grouping them allows us to reset/randomize // every item in a group at once. If you are looking for tabs they are rendered manually in ImGui in `DrawCosmeticsEditor` typedef enum { @@ -28,9 +21,19 @@ typedef enum { COSMETICS_GROUP_TRAILS, COSMETICS_GROUP_NAVI, COSMETICS_GROUP_IVAN, + COSMETICS_GROUP_MESSAGE, COSMETICS_GROUP_MAX } CosmeticGroup; +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + + Color_RGBA8 CosmeticsEditor_GetDefaultValue(const char* id); + +#ifdef __cplusplus +} + typedef struct { const std::string Name; const std::string ToolTip; @@ -46,8 +49,7 @@ static float TablesCellsWidth = 300.0f; static ImGuiTableColumnFlags FlagsTable = ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV; static ImGuiTableColumnFlags FlagsCell = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoSort; -void InitCosmeticsEditor();//Init the menu itself -ImVec4 GetRandomValue(int MaximumPossible); +ImVec4 GetRandomValue(); void CosmeticsEditor_RandomizeAll(); void CosmeticsEditor_RandomizeGroup(CosmeticGroup group); void CosmeticsEditor_ResetAll(); @@ -61,4 +63,5 @@ class CosmeticsEditorWindow : public Ship::GuiWindow { void InitElement() override; void DrawElement() override; void UpdateElement() override {}; -}; \ No newline at end of file +}; +#endif //__cplusplus \ No newline at end of file diff --git a/soh/soh/Enhancements/custom-collectible/CustomCollectible.cpp b/soh/soh/Enhancements/custom-collectible/CustomCollectible.cpp new file mode 100644 index 000000000..7bbbd8b55 --- /dev/null +++ b/soh/soh/Enhancements/custom-collectible/CustomCollectible.cpp @@ -0,0 +1,209 @@ +#include "CustomCollectible.h" +#include +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/randomizer/3drando/random.hpp" +#include "soh/frame_interpolation.h" +#include "soh/Enhancements/custom-message/CustomMessageManager.h" + +extern "C" { +#include "z64actor.h" +#include "functions.h" +#include "variables.h" +#include "macros.h" +#include "objects/object_md/object_md.h" +extern PlayState* gPlayState; +} + +EnItem00* CustomCollectible::Spawn(f32 posX, f32 posY, f32 posZ, s16 rot, s16 flags, s16 params, ActorFunc actionFunc, + ActorFunc drawFunc) { + if (!gPlayState) { + return nullptr; + } + + Actor* actor = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_ITEM00, posX, posY, posZ, flags, rot, params, ITEM00_NONE, 0); + EnItem00* enItem00 = (EnItem00*)actor; + + if (actionFunc != NULL) { + enItem00->actionFunc = (EnItem00ActionFunc)actionFunc; + } + + if (drawFunc != NULL) { + actor->draw = drawFunc; + } + + return enItem00; +} + +void CustomCollectible_Init(Actor* actor, PlayState* play) { + EnItem00* enItem00 = (EnItem00*)actor; + + if (CUSTOM_ITEM_FLAGS & CustomCollectible::STOP_BOBBING) { + actor->shape.yOffset = 1250.0f; + } else { + actor->shape.yOffset = (Math_SinS(actor->shape.rot.y) * 150.0f) + 1250.0f; + } + + if (CUSTOM_ITEM_FLAGS & CustomCollectible::HIDE_TILL_OVERHEAD) { + Actor_SetScale(actor, 0.0f); + } else { + Actor_SetScale(actor, 0.015f); + } + + if (CUSTOM_ITEM_FLAGS & CustomCollectible::KEEP_ON_PLAYER) { + Math_Vec3f_Copy(&actor->world.pos, &GET_PLAYER(play)->actor.world.pos); + } + + if (CUSTOM_ITEM_FLAGS & CustomCollectible::TOSS_ON_SPAWN) { + actor->velocity.y = 8.0f; + actor->speedXZ = 2.0f; + actor->gravity = -1.4f; + actor->world.rot.y = Rand_ZeroOne() * 40000.0f; + } + + enItem00->unk_15A = -1; +} + +// By default this will just assume the GID was passed in as the rot z, if you want different functionality you should +// override the draw +void CustomCollectible_Draw(Actor* actor, PlayState* play) { + Matrix_Scale(30.0f, 30.0f, 30.0f, MTXMODE_APPLY); + GetItem_Draw(play, CUSTOM_ITEM_PARAM); +} + +void CustomCollectible_Update(Actor* actor, PlayState* play) { + EnItem00* enItem00 = (EnItem00*)actor; + Player* player = GET_PLAYER(play); + + if (!(CUSTOM_ITEM_FLAGS & CustomCollectible::STOP_SPINNING)) { + actor->shape.rot.y += 960; + } + + if (CUSTOM_ITEM_FLAGS & CustomCollectible::STOP_BOBBING) { + actor->shape.yOffset = 1250.0f; + } else { + actor->shape.yOffset = (Math_SinS(actor->shape.rot.y) * 150.0f) + 1250.0f; + } + + if (CUSTOM_ITEM_FLAGS & CustomCollectible::HIDE_TILL_OVERHEAD) { + Actor_SetScale(actor, 0.0f); + } + + if (CUSTOM_ITEM_FLAGS & CustomCollectible::KEEP_ON_PLAYER) { + actor->gravity = 0.0f; + Math_Vec3f_Copy(&actor->world.pos, &GET_PLAYER(play)->actor.world.pos); + } + + if (CUSTOM_ITEM_FLAGS & CustomCollectible::KILL_ON_TOUCH) { + // Pretty self explanatory, if the player is within range, kill the actor and call the action function + if ((actor->xzDistToPlayer <= 50.0f) && (fabsf(actor->yDistToPlayer) <= fabsf(20.0f))) { + if (enItem00->actionFunc != NULL) { + enItem00->actionFunc(enItem00, play); + CUSTOM_ITEM_FLAGS |= CustomCollectible::CALLED_ACTION; + } + Actor_Kill(actor); + } + } else if (CUSTOM_ITEM_FLAGS & CustomCollectible::GIVE_OVERHEAD) { + // If the item hasn't been picked up (unk_15A == -1) and the player is within range + if (enItem00->unk_15A == -1 && (actor->xzDistToPlayer <= 50.0f) && + (fabsf(actor->yDistToPlayer) <= fabsf(20.0f))) { + // Fire the action function + if (enItem00->actionFunc != NULL) { + enItem00->actionFunc(enItem00, play); + CUSTOM_ITEM_FLAGS |= CustomCollectible::CALLED_ACTION; + } + Sfx_PlaySfxCentered(NA_SE_SY_GET_ITEM); + // Set the unk_15A to 15, this indicates the item has been picked up and will start the overhead animation + enItem00->unk_15A = 15; + CUSTOM_ITEM_FLAGS |= CustomCollectible::STOP_BOBBING; + CUSTOM_ITEM_FLAGS |= CustomCollectible::KEEP_ON_PLAYER; + } + + // If the item has been picked up + if (enItem00->unk_15A > 0) { + // Reduce the size a bit, but also makes it visible for HIDE_TILL_OVERHEAD + Actor_SetScale(actor, 0.010f); + + // Decrement the unk_15A, which will be used to bob the item up and down + enItem00->unk_15A--; + + // Account for the different heights of the player forms + f32 height = 45.0f; + // TODO: Check for adult? + + // Bob the item up and down + actor->world.pos.y += (height + (Math_SinS(enItem00->unk_15A * 15000) * (enItem00->unk_15A * 0.3f))); + } + + // Finally, once the bobbing animation is done, kill the actor + if (enItem00->unk_15A == 0) { + Actor_Kill(actor); + } + } else if (CUSTOM_ITEM_FLAGS & CustomCollectible::GIVE_ITEM_CUTSCENE) { + // If the item hasn't been picked up and the player is within range + if (!Actor_HasParent(actor, play) && enItem00->unk_15A == -1) { + Actor_OfferGetItem(actor, play, GI_SHIP, 50.0f, 20.0f); + } else { + if (enItem00->unk_15A == -1) { + CUSTOM_ITEM_FLAGS |= CustomCollectible::STOP_BOBBING; + CUSTOM_ITEM_FLAGS |= CustomCollectible::KEEP_ON_PLAYER; + CUSTOM_ITEM_FLAGS |= CustomCollectible::HIDE_TILL_OVERHEAD; + } + + // Begin incrementing the unk_15A, indicating the item has been picked up + enItem00->unk_15A++; + + // For the first 20 frames, wait while the player's animation plays + if (enItem00->unk_15A >= 20) { + // After the first 20 frames, show the item and call the action function + if (enItem00->unk_15A == 20 && enItem00->actionFunc != NULL) { + enItem00->actionFunc(enItem00, play); + CUSTOM_ITEM_FLAGS |= CustomCollectible::CALLED_ACTION; + } + // Override the bobbing animation to be a fixed height + actor->shape.yOffset = 900.0f; + Actor_SetScale(actor, 0.007f); + + f32 height = 45.0f; + // TODO: Check for adult? + + actor->world.pos.y += height; + } + + // Once the player is no longer in the "Give Item" state, kill the actor + if (!(player->stateFlags1 & PLAYER_STATE1_GETTING_ITEM)) { + Actor_Kill(actor); + } + } + } + + if (actor->gravity != 0.0f) { + Actor_MoveForward(actor); + Actor_UpdateBgCheckInfo(play, actor, 20.0f, 15.0f, 15.0f, 0x1D); + } + + if (actor->bgCheckFlags & 0x0003) { + actor->speedXZ = 0.0f; + } + + Collider_UpdateCylinder(actor, &enItem00->collider); + CollisionCheck_SetAC(play, &play->colChkCtx, &enItem00->collider.base); +} + +void CustomCollectible::RegisterHooks() { + GameInteractor::Instance->RegisterGameHookForID( + ACTOR_EN_ITEM00, [](void* actorRef, bool* should) { + Actor* actor = (Actor*)actorRef; + if (actor->params != ITEM00_NONE) { + return; + } + + actor->init = CustomCollectible_Init; + actor->update = CustomCollectible_Update; + actor->draw = CustomCollectible_Draw; + actor->destroy = NULL; + + // Set the rotX/rotZ back to 0, the original values can be accessed from actor->home + actor->world.rot.x = 0; + actor->world.rot.z = 0; + }); +} diff --git a/soh/soh/Enhancements/custom-collectible/CustomCollectible.h b/soh/soh/Enhancements/custom-collectible/CustomCollectible.h new file mode 100644 index 000000000..ff2549b0f --- /dev/null +++ b/soh/soh/Enhancements/custom-collectible/CustomCollectible.h @@ -0,0 +1,24 @@ +extern "C" { +#include "z64actor.h" +} + +#define CUSTOM_ITEM_FLAGS (actor->home.rot.x) +#define CUSTOM_ITEM_PARAM (actor->home.rot.z) + +namespace CustomCollectible { + +enum CustomCollectibleFlags : int16_t { + KILL_ON_TOUCH = 1 << 0, // 0000 0000 0000 0001 + GIVE_OVERHEAD = 1 << 1, // 0000 0000 0000 0010 + GIVE_ITEM_CUTSCENE = 1 << 2, // 0000 0000 0000 0100 + HIDE_TILL_OVERHEAD = 1 << 3, // 0000 0000 0000 1000 + KEEP_ON_PLAYER = 1 << 4, // 0000 0000 0001 0000 + STOP_BOBBING = 1 << 5, // 0000 0000 0010 0000 + STOP_SPINNING = 1 << 6, // 0000 0000 0100 0000 + CALLED_ACTION = 1 << 7, // 0000 0000 1000 0000 + TOSS_ON_SPAWN = 1 << 8, // 0000 0001 0000 0000 +}; +void RegisterHooks(); +EnItem00* Spawn(f32 posX, f32 posY, f32 posZ, s16 rot, s16 flags, s16 params, ActorFunc actionFunc = NULL, + ActorFunc drawFunc = NULL); +}; // namespace CustomCollectible diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp index fde95e0c5..05b566b16 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp @@ -357,6 +357,15 @@ static size_t NextLineLength(const std::string* textStr, const size_t lastNewlin nextPosJump = 1; // Assume worst case for player name 12 * 8 (widest character * longest name length) totalPixelWidth += 96; + } else if (textStr->at(currentPos) == '\x05') { + // Skip colour control characters. + nextPosJump = 2; + } else if (textStr->at(currentPos) == '\x1E') { + //For the high score char, we have to take the next Char, then use that to get a worst case scenario. + if (textStr->at(currentPos+1) == '\x01'){ + totalPixelWidth += 28; + } + nextPosJump = 2; } else { // Some characters only one byte while others are two bytes // So check both possibilities when checking for a character @@ -382,6 +391,65 @@ static size_t NextLineLength(const std::string* textStr, const size_t lastNewlin } } +size_t CustomMessage::FindNEWLINE(std::string& str, size_t lastNewline) const { + size_t newLine = str.find(NEWLINE()[0], lastNewline); + bool done; + + // Bail out early + if (newLine == std::string::npos) { + return newLine; + } + + do { + done = true; + if (newLine != 0) { + switch (str[newLine - 1]) { + case '\x05': // COLOR + case '\x06': // SHIFT + case '\x07': // TEXTID + case '\x0C': // BOX_BREAK_DELAYED + case '\x0E': // FADE + case '\x11': // FADE2 + case '\x12': // SFX + case '\x13': // ITEM_ICON + case '\x14': // TEXT_SPEED + case '\x15': // BACKGROUND + case '\x1E': // POINTS/HIGH_SCORE + done = false; + break; + default: + break; + } + if (newLine > 1) { + switch (str[newLine - 2]) { + case '\x07': // TEXTID + case '\x11': // FADE2 + case '\x12': // SFX + case '\x15': // BACKGROUND + done = false; + break; + default: + break; + } + if (newLine > 2) { + if (str[newLine - 3] == '\x15') { // BACKGROUND + done = false; + } + } + } + } + if (!done) { + newLine = str.find(NEWLINE()[0], newLine + 1); + if (newLine == std::string::npos) { + // if we reach the end of the string, quit now to save a loop + done = true; + } + } + } while (!done); + + return newLine; +} + void CustomMessage::AutoFormatString(std::string& str) const { ReplaceAltarIcons(str); ReplaceColors(str); @@ -396,7 +464,7 @@ void CustomMessage::AutoFormatString(std::string& str) const { 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 = str.find(NEWLINE()[0], lastNewline); + size_t newLine = FindNEWLINE(str, lastNewline); if (carrot < waitForInput){ waitForInput = carrot; } diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.h b/soh/soh/Enhancements/custom-message/CustomMessageManager.h index 4c32db015..0c5880c4d 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageManager.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.h @@ -181,6 +181,12 @@ class CustomMessage { */ void FormatString(std::string& str) const; + /** + * @brief finds NEWLINEs in a string, while filtering + * /x01's that are used as opperands + */ + size_t FindNEWLINE(std::string& str, size_t lastNewline) const; + /** * @brief formats the string specifically to fit in OoT's * textboxes, and use it's formatting. diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index 4f65ef9a5..829d1161e 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -1312,6 +1312,7 @@ static constexpr std::array, COSMETICS_GRO {"trials", COSMETICS_GROUP_TRAILS}, {"navi", COSMETICS_GROUP_NAVI}, {"ivan", COSMETICS_GROUP_IVAN}, + {"message", COSMETICS_GROUP_MESSAGE}, }}; static bool CosmeticsHandler(std::shared_ptr Console, const std::vector& args, std::string* output) { diff --git a/soh/soh/Enhancements/debugger/hookDebugger.cpp b/soh/soh/Enhancements/debugger/hookDebugger.cpp index b31ddc396..8ee9b3391 100644 --- a/soh/soh/Enhancements/debugger/hookDebugger.cpp +++ b/soh/soh/Enhancements/debugger/hookDebugger.cpp @@ -4,14 +4,14 @@ #include #include -static std::unordered_map> hookData; +static std::unordered_map*> hookData; const ImVec4 grey = ImVec4(0.75, 0.75, 0.75, 1); const ImVec4 yellow = ImVec4(1, 1, 0, 1); const ImVec4 red = ImVec4(1, 0, 0, 1); void DrawHookRegisteringInfos(const char* hookName) { - if (hookData[hookName].size() == 0) { + if ((*hookData[hookName]).size() == 0) { ImGui::TextColored(grey, "No hooks found"); return; } @@ -27,7 +27,7 @@ void DrawHookRegisteringInfos(const char* hookName) { //ImGui::TableSetupColumn("Stub"); ImGui::TableSetupColumn("Number of Calls"); ImGui::TableHeadersRow(); - for (auto& [id, hookInfo] : hookData[hookName]) { + for (auto& [id, hookInfo] : (*hookData[hookName])) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -100,12 +100,10 @@ void HookDebuggerWindow::DrawElement() { } } -void HookDebuggerWindow::UpdateElement() { - hookData.clear(); - +void HookDebuggerWindow::InitElement() { #define DEFINE_HOOK(name, _) hookData.insert({#name, GameInteractor::Instance->GetHookData()}); #include "../game-interactor/GameInteractor_HookTable.h" #undef DEFINE_HOOK -} \ No newline at end of file +} diff --git a/soh/soh/Enhancements/debugger/hookDebugger.h b/soh/soh/Enhancements/debugger/hookDebugger.h index 90e6886b5..ae6f5113f 100644 --- a/soh/soh/Enhancements/debugger/hookDebugger.h +++ b/soh/soh/Enhancements/debugger/hookDebugger.h @@ -4,7 +4,7 @@ class HookDebuggerWindow : public Ship::GuiWindow { public: using GuiWindow::GuiWindow; - void InitElement() override {}; + void InitElement() override; void DrawElement() override; - void UpdateElement() override; + void UpdateElement() override {}; }; diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index d33ff090c..0eab5514c 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -345,6 +345,19 @@ typedef enum { VB_INFLICT_VOID_DAMAGE, VB_GANONDORF_DECIDE_TO_FIGHT, VB_USE_ITEM, + // Vanilla condition: Close enough & various cutscene checks + // Opt: *EnRu1 + VB_PLAY_CHILD_RUTO_INTRO, + // Vanilla condition: !INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE && in the big okto room + // Opt: *EnRu1 + VB_RUTO_WANT_TO_BE_TOSSED_TO_SAPPHIRE, + // Vanilla condition: Landed on the platform in the big okto room + // Opt: *EnRu1 + VB_RUTO_RUN_TO_SAPPHIRE, + // Vanilla condition: !Flags_GetInfTable(INFTABLE_145) + // Opt: *EnRu1 + VB_RUTO_BE_CONSIDERED_NOT_KIDNAPPED, + /*** Give Items ***/ @@ -658,8 +671,8 @@ public: inline static std::vector hooksForFilter; }; - template std::unordered_map GetHookData() { - return RegisteredGameHooks::hookData; + template std::unordered_map* GetHookData() { + return &RegisteredGameHooks::hookData; } // General Hooks diff --git a/soh/soh/Enhancements/kaleido.cpp b/soh/soh/Enhancements/kaleido.cpp index 9822b1956..33075ca50 100644 --- a/soh/soh/Enhancements/kaleido.cpp +++ b/soh/soh/Enhancements/kaleido.cpp @@ -125,8 +125,8 @@ namespace Rando { std::make_shared( gTriforcePieceTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255,255,255,255 }, 0, yOffset, reinterpret_cast(&gSaveContext.triforcePiecesCollected), - ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetSelectedOptionIndex() + 1, - ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).GetSelectedOptionIndex() + 1)); + ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1, + ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).GetContextOptionIndex() + 1)); yOffset += 18; } if (ctx->GetOption(RSK_SHUFFLE_OCARINA_BUTTONS)) { diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index c88733e22..35c967d5c 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -1038,6 +1038,9 @@ std::vector getEnabledAddTraps () { std::vector enabledAddTraps; for (int i = 0; i < ADD_TRAP_MAX; i++) { if (CVarGetInteger(altTrapTypeCvars[i], 0)) { + if (gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE && (i == ADD_VOID_TRAP || i == ADD_TELEPORT_TRAP)) { + continue; // don't add void or teleport if you're holding the fishing pole, as this causes issues + } enabledAddTraps.push_back(static_cast(i)); } } diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 96b39ba30..9b4482f23 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -242,6 +242,8 @@ const std::vector enhancementsCvars = { CVAR_ENHANCEMENT("AuthenticLogo"), CVAR_ENHANCEMENT("PauseLiveLinkRotationSpeed"), CVAR_ENHANCEMENT("BowReticle"), + CVAR_ENHANCEMENT("BoomerangFirstPerson"), + CVAR_ENHANCEMENT("BoomerangReticle"), CVAR_ENHANCEMENT("FixTexturesOOB"), CVAR_ENHANCEMENT("IvanCoopModeEnabled"), CVAR_ENHANCEMENT("EnemySpawnsOverWaterboxes"), @@ -304,6 +306,7 @@ const std::vector enhancementsCvars = { CVAR_ENHANCEMENT("TimeSavers.SkipChildStealth"), CVAR_ENHANCEMENT("TimeSavers.SkipTowerEscape"), CVAR_ENHANCEMENT("TimeSavers.SkipForcedDialog"), + CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall"), CVAR_ENHANCEMENT("SlowTextSpeed"), }; @@ -549,6 +552,7 @@ const std::vector randomizerCvars = { CVAR_RANDOMIZER_SETTING("SkipChildZelda"), CVAR_RANDOMIZER_SETTING("SkipEponaRace"), CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"), + CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), CVAR_RANDOMIZER_SETTING("StartingAge"), CVAR_RANDOMIZER_SETTING("StartingBoleroOfFire"), CVAR_RANDOMIZER_SETTING("StartingConsumables"), @@ -1175,12 +1179,13 @@ const std::vector s6PresetEntries = { PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipChildZelda"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipEponaRace"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipTowerEscape"), 1), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), RO_WATERFALL_CLOSED), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingAge"), RO_AGE_RANDOM), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingConsumables"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingDekuShield"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingMapsCompasses"), RO_DUNGEON_ITEM_LOC_STARTWITH), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingOcarina"), 1), - PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), 0), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), RO_ZF_CLOSED), }; const std::vector hellModePresetEntries = { @@ -1235,16 +1240,18 @@ const std::vector hellModePresetEntries = { PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipEponaRace"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipTowerEscape"), 1), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), RO_WATERFALL_OPEN), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingAge"), RO_AGE_RANDOM), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingMapsCompasses"), RO_DUNGEON_ITEM_LOC_ANYWHERE), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SunlightArrows"), 1), - PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), 2), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), RO_ZF_OPEN), }; const std::vector BenchmarkPresetEntries = { PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("Forest"), RO_FOREST_CLOSED_DEKU), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("KakarikoGate"), RO_KAK_GATE_OPEN), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("DoorOfTime"), RO_DOOROFTIME_SONGONLY), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), RO_WATERFALL_CLOSED), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), RO_ZF_CLOSED), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("RainbowBridge"), RO_BRIDGE_DUNGEON_REWARDS), diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index 833f4d028..e7a6ce38b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -238,10 +238,10 @@ static int GetMaxGSCount() { int maxBridge = 0; int maxLACS = 0; if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS)) { - maxBridge = ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Value(); + maxBridge = ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).GetContextOptionIndex(); } if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) { - maxLACS = ctx->GetOption(RSK_LACS_TOKEN_COUNT).Value(); + maxLACS = ctx->GetOption(RSK_LACS_TOKEN_COUNT).GetContextOptionIndex(); } maxBridge = std::max(maxBridge, maxLACS); //Get the max amount of GS which could be useful from token reward locations @@ -266,7 +266,7 @@ static int GetMaxGSCount() { maxUseful = 10; } //Return max of the two possible reasons tokens could be important, minus the tokens in the starting inventory - return std::max(maxUseful, maxBridge) - ctx->GetOption(RSK_STARTING_SKULLTULA_TOKEN).Value(); + return std::max(maxUseful, maxBridge) - ctx->GetOption(RSK_STARTING_SKULLTULA_TOKEN).GetContextOptionIndex(); } std::string GetShopItemBaseName(std::string itemName) { @@ -856,11 +856,6 @@ static void AssumedFill(const std::vector& items, const std::vect SPDLOG_DEBUG(Rando::StaticData::RetrieveItem(item).GetName().GetEnglish()); SPDLOG_DEBUG(". TRYING AGAIN...\n"); -#ifdef ENABLE_DEBUG - Regions::DumpWorldGraph(Rando::StaticData::RetrieveItem(item).GetName().GetEnglish()); - PlacementLog_Write(); -#endif - // reset any locations that got an item for (RandomizerCheck loc : attemptedLocations) { ctx->GetItemLocation(loc)->SetPlacedItem(RG_NONE); diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp index 14faa479b..e0097a6f6 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -1177,7 +1177,7 @@ void StaticData::HintTable_Init() { // /*spanish*/la tienda de pociones de la abuela hintTextTable[RHT_GRAVEYARD_DAMPES_HOUSE] = HintText(CustomMessage("Dampé's Hut", - /*german*/ "der #Hut von Boris#", + /*german*/ "die #Hütte von Boris#", /*french*/ "la #Cabane du Fossoyeur#")); // /*spanish*/la cabaña de Dampé @@ -1277,12 +1277,12 @@ void StaticData::HintTable_Init() { // /*spanish*/la #tumba de la Canción del Sol# hintTextTable[RHT_GRAVEYARD_COMPOSERS_GRAVE] = HintText(CustomMessage("the #Composers' Grave#", - /*german*/ "das Königsgrab", + /*german*/ "das #Königsgrab#", /*french*/ "la #Tombe royale#")); // /*spanish*/el #Panteón Real# hintTextTable[RHT_GRAVEYARD_DAMPES_GRAVE] = HintText(CustomMessage("Dampé's Grave", - /*german*/ "das Grab von Boris", + /*german*/ "das #Grab von Boris#", /*french*/ "la #Tombe d'Igor#")); // /*spanish*/la #tumba de Dampé# @@ -2893,7 +2893,7 @@ void StaticData::HintTable_Init() { {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 my #[[1]]#!\x0B", + "Prove yourself to be a horsemaster by scoring 1500 points to win my #[[1]]#!\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#!^" diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp index ee6a638f5..941f0924b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -222,18 +222,18 @@ uint8_t StonesRequiredBySettings() { auto ctx = Rando::Context::GetInstance(); uint8_t stones = 0; if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_STONES)) { - stones = ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT).Value(); + stones = ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT).GetContextOptionIndex(); } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS)) { - stones = ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).Value() - 6; + stones = ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).GetContextOptionIndex() - 6; } else if ((ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS)) && (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON))) { - stones = ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Value() - 6; + stones = ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).GetContextOptionIndex() - 6; } if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) { - stones = std::max({ stones, ctx->GetOption(RSK_LACS_STONE_COUNT).Value() }); + stones = std::max({ stones, ctx->GetOption(RSK_LACS_STONE_COUNT).GetContextOptionIndex() }); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) { - stones = std::max({ stones, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).Value() - 6 )}); + stones = std::max({ stones, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).GetContextOptionIndex() - 6 )}); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS)) { - stones = std::max({ stones, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Value() - 6 )}); + stones = std::max({ stones, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).GetContextOptionIndex() - 6 )}); } return stones; } @@ -242,18 +242,18 @@ uint8_t MedallionsRequiredBySettings() { auto ctx = Rando::Context::GetInstance(); uint8_t medallions = 0; if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_MEDALLIONS)) { - medallions = ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT).Value(); + medallions = ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT).GetContextOptionIndex(); } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS)) { - medallions = ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).Value() - 3; + medallions = ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).GetContextOptionIndex() - 3; } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS) && ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) { - medallions = ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Value() - 3; + medallions = ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).GetContextOptionIndex() - 3; } if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_MEDALLIONS)) { - medallions = std::max({ medallions, ctx->GetOption(RSK_LACS_MEDALLION_COUNT).Value() }); + medallions = std::max({ medallions, ctx->GetOption(RSK_LACS_MEDALLION_COUNT).GetContextOptionIndex() }); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_REWARDS)) { - medallions = std::max({ medallions, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).Value() - 3 )}); + medallions = std::max({ medallions, (uint8_t)(ctx->GetOption(RSK_LACS_REWARD_COUNT).GetContextOptionIndex() - 3 )}); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS) && ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) { - medallions = std::max({ medallions, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Value() - 3 )}); + medallions = std::max({ medallions, (uint8_t)(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).GetContextOptionIndex() - 3 )}); } return medallions; } @@ -262,10 +262,10 @@ uint8_t TokensRequiredBySettings() { auto ctx = Rando::Context::GetInstance(); uint8_t tokens = 0; if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS)) { - tokens = ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Value(); + tokens = ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).GetContextOptionIndex(); } if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) { - tokens = std::max({ tokens, ctx->GetOption(RSK_LACS_TOKEN_COUNT).Value() }); + tokens = std::max({ tokens, ctx->GetOption(RSK_LACS_TOKEN_COUNT).GetContextOptionIndex() }); } return tokens; } @@ -273,7 +273,7 @@ uint8_t TokensRequiredBySettings() { std::vector>> conditionalAlwaysHints = { std::make_pair(RC_MARKET_10_BIG_POES, []() { auto ctx = Rando::Context::GetInstance(); - return ctx->GetOption(RSK_BIG_POE_COUNT).Value() >= 3 && !ctx->GetOption(RSK_BIG_POES_HINT); + return ctx->GetOption(RSK_BIG_POE_COUNT).GetContextOptionIndex() >= 3 && !ctx->GetOption(RSK_BIG_POES_HINT); }), // Remember, the option's value being 3 means 4 are required std::make_pair(RC_DEKU_THEATER_MASK_OF_TRUTH, []() { auto ctx = Rando::Context::GetInstance(); @@ -483,7 +483,7 @@ static void CreateTrialHints(uint8_t copies) { AddGossipStoneHintCopies(copies, HINT_TYPE_HINT_KEY, "Trial", {RHT_ZERO_TRIALS}); } else { std::vector trials = ctx->GetTrials()->GetTrialList(); //there's probably a way to remove this assignment - if (ctx->GetOption(RSK_TRIAL_COUNT).Value() >= 4) {//4 or 5 required trials, get skipped trials + if (ctx->GetOption(RSK_TRIAL_COUNT).GetContextOptionIndex() >= 4) {//4 or 5 required trials, get skipped trials trials = FilterFromPool(trials, [](TrialInfo* trial){return trial->IsSkipped();}); } else {//1 to 3 trials, get requried trials auto requiredTrials = FilterFromPool(trials, [](TrialInfo* trial){return trial->IsRequired();}); @@ -611,7 +611,7 @@ uint8_t PlaceHints(std::vector& selectedHints, std::vectorGetOption(RSK_HINT_DISTRIBUTION).Value()]; + const HintSetting& hintSetting = hintSettingTable[ctx->GetOption(RSK_HINT_DISTRIBUTION).GetContextOptionIndex()]; std::vector distTable = hintSetting.distTable; // Apply impa's song exclusions when zelda is skipped diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 52f6359c5..5d7a290c0 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -655,7 +655,7 @@ static void SetMinimalItemPool() { ReplaceMaxItem(RG_PROGRESSIVE_BOMB_BAG, 1); ReplaceMaxItem(RG_PIECE_OF_HEART, 0); // Need an extra heart container when starting with 1 heart to be able to reach 3 hearts - ReplaceMaxItem(RG_HEART_CONTAINER, (ctx->GetOption(RSK_STARTING_HEARTS).Value() == 18)? 1 : 0); + ReplaceMaxItem(RG_HEART_CONTAINER, (ctx->GetOption(RSK_STARTING_HEARTS).GetContextOptionIndex() == 18)? 1 : 0); } void GenerateItemPool() { @@ -721,7 +721,7 @@ void GenerateItemPool() { if (ctx->GetOption(RSK_TRIFORCE_HUNT)) { ctx->possibleIceTrapModels.push_back(RG_TRIFORCE_PIECE); - AddItemToMainPool(RG_TRIFORCE_PIECE, (ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Value() + 1)); + AddItemToMainPool(RG_TRIFORCE_PIECE, (ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).GetContextOptionIndex() + 1)); ctx->PlaceItemInLocation(RC_TRIFORCE_COMPLETED, RG_TRIFORCE); // Win condition ctx->PlaceItemInLocation(RC_GANON, GetJunkItem(), false, true); } else { @@ -821,7 +821,7 @@ void GenerateItemPool() { if (fsMode.IsNot(RO_FISHSANITY_OFF)) { if (fsMode.Is(RO_FISHSANITY_POND) || fsMode.Is(RO_FISHSANITY_BOTH)) { // 17 max child pond fish - uint8_t pondCt = ctx->GetOption(RSK_FISHSANITY_POND_COUNT).GetSelectedOptionIndex(); + uint8_t pondCt = ctx->GetOption(RSK_FISHSANITY_POND_COUNT).GetContextOptionIndex(); for (uint8_t i = 0; i < pondCt; i++) { AddItemToMainPool(GetJunkItem()); } @@ -1348,7 +1348,7 @@ void GenerateItemPool() { if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) { ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, RG_GANONS_CASTLE_BOSS_KEY); - } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Value() >= RO_GANON_BOSS_KEY_LACS_VANILLA && ctx->GetOption(RSK_GANONS_BOSS_KEY).IsNot(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) { + } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).GetContextOptionIndex() >= RO_GANON_BOSS_KEY_LACS_VANILLA && ctx->GetOption(RSK_GANONS_BOSS_KEY).IsNot(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) { ctx->PlaceItemInLocation(RC_TOT_LIGHT_ARROWS_CUTSCENE, RG_GANONS_CASTLE_BOSS_KEY); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA)) { ctx->PlaceItemInLocation(RC_GANONS_TOWER_BOSS_KEY_CHEST, RG_GANONS_CASTLE_BOSS_KEY); diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp index efb15780e..aa384e665 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp @@ -260,7 +260,7 @@ void RegionTable_Init() { areaTable[RR_ROOT] = Region("Root", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, { //Locations LOCATION(RC_LINKS_POCKET, true), - LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).Value();), + LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex();), LOCATION(RC_SARIA_SONG_HINT, logic->CanUse(RG_SARIAS_SONG)), }, { //Exits @@ -395,7 +395,7 @@ void ReplaceAllInString(std::string& s, std::string const& toReplace, std::strin std::string CleanCheckConditionString(std::string condition) { ReplaceAllInString(condition, "logic->", ""); ReplaceAllInString(condition, "ctx->", ""); - ReplaceAllInString(condition, ".Value()", ""); + ReplaceAllInString(condition, ".GetContextOptionIndex()", ""); ReplaceAllInString(condition, "GetSaveContext()->", ""); return condition; } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp index 55a25ac58..e2e5da9a4 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp @@ -21,138 +21,140 @@ void RegionTable_Init_JabuJabusBelly() { if (ctx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla()) { areaTable[RR_JABU_JABUS_BELLY_BEGINNING] = Region("Jabu Jabus Belly Beginning", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits - Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return logic->CanUseProjectile();}}), + Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return logic->CanUseProjectile();}}), }); - areaTable[RR_JABU_JABUS_BELLY_LIFT_MIDDLE] = Region("Jabu Jabus Belly Lift Middle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { +//Combines Lift room middle and lower, 1F holes room, the forked corridor, and it's side rooms + areaTable[RR_JABU_JABUS_BELLY_MAIN] = Region("Jabu Jabus Belly Main", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->JabuRutoInB1, {[]{return true;}}), + EventAccess(&logic->JabuWestTentacle, {[]{return logic->JabuRutoIn1F && logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_DEKU_SCRUB, logic->HasItem(RG_BRONZE_SCALE) && (logic->IsChild || logic->HasItem(RG_SILVER_SCALE) || ctx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE) || logic->CanUse(RG_IRON_BOOTS)) && logic->CanStunDeku()), + //We can kill the Stingers with ruto + LOCATION(RC_JABU_JABUS_BELLY_BOOMERANG_CHEST, logic->JabuRutoIn1F), + LOCATION(RC_JABU_JABUS_BELLY_MAP_CHEST, logic->JabuWestTentacle), + }, { //Exits Entrance(RR_JABU_JABUS_BELLY_BEGINNING, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_LIFT_LOWER, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return HasAccessTo(RR_JABU_JABUS_BELLY_LIFT_UPPER) || (ctx->GetTrickOption(RT_JABU_BOSS_HOVER) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS));}}), - }); + Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_COMPASS_ROOM, {[]{return logic->JabuWestTentacle;}}), + Entrance(RR_JABU_JABUS_BELLY_BLUE_TENTACLE, {[]{return logic->JabuWestTentacle;}}), + Entrance(RR_JABU_JABUS_BELLY_GREEN_TENTACLE, {[]{return logic->JabuEastTentacle;}}), + Entrance(RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE, {[]{return logic->JabuNorthTentacle;}}), + Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return logic->LoweredJabuPath || (ctx->GetTrickOption(RT_JABU_BOSS_HOVER) && logic->CanUse(RG_HOVER_BOOTS));}}), + }); - areaTable[RR_JABU_JABUS_BELLY_MAIN_UPPER] = Region("Jabu Jabus Belly Main Upper", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_BIGOCTO_ROOM, {[]{return Here(RR_JABU_JABUS_BELLY_GREEN_TENTACLE, []{return logic->CanUse(RG_BOOMERANG);});}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MAIN_LOWER] = Region("Jabu Jabus Belly Main Lower", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { +//contains B1 of hole room (aside from the ledge leading to big octo), 2 octorock room and north water switch room + areaTable[RR_JABU_JABUS_BELLY_B1_NORTH] = Region("Jabu Jabus Belly B1 North", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->JabuRutoIn1F, {[]{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}}), + EventAccess(&logic->FairyPot, {[]{return logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_HOVER_BOOTS);}}), + }, { //Locations LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, logic->HookshotOrBoomerang()), LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, logic->HookshotOrBoomerang()), - }, { + LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HookshotOrBoomerang()), + //PUT 2 OCTO ROOM POTS HERE + }, { //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_SHABOMB_CORRIDOR, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_LOWER_SIDE_ROOM, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return true;}}), + //there's tricks for getting here with bunny-jumps or just side-hops + Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->HasItem(RG_HOVER_BOOTS);}}), + Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, {[]{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}}), }); - areaTable[RR_JABU_JABUS_BELLY_SHABOMB_CORRIDOR] = Region("Jabu Jabus Belly Shabomb Corridor", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE] = Region("Jabu Jabus Belly Water Switch Room Ledge", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { //Events EventAccess(&logic->FairyPot, {[]{return true;}}), }, { //Locations - LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, true), + //this is the logic for climbing back and forth to use the pots to kill the skull... + LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HasItem(RG_BRONZE_SCALE) || + (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || + //or killing the skull before climbing to grab the token + logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW)), + //PUT WATER SWITCH POTS HERE }, { //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN_LOWER, {[]{return logic->HasItem(RG_BRONZE_SCALE);}}), - Entrance(RR_JABU_JABUS_BELLY_LIFT_LOWER, {[]{return logic->HasItem(RG_BRONZE_SCALE) && logic->CanUseProjectile();}}), + Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, {[]{return true;}}), }); - areaTable[RR_JABU_JABUS_BELLY_LOWER_SIDE_ROOM] = Region("Jabu Jabus Belly Lower Side Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return logic->FairyPot || (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_HOVER_BOOTS));}}), - }, {}, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_LIFT_LOWER] = Region("Jabu Jabus Belly Lift Lower", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH] = Region("Jabu Jabus Belly Water Switch Room South", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LOCATION(RC_JABU_JABUS_BELLY_DEKU_SCRUB, logic->HasItem(RG_BRONZE_SCALE) && (logic->IsChild || logic->HasItem(RG_SILVER_SCALE) || ctx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE) || logic->CanUse(RG_IRON_BOOTS)) && logic->CanStunDeku()), + LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HookshotOrBoomerang()), }, { //Exits - Entrance(RR_JABU_JABUS_BELLY_SHABOMB_CORRIDOR, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_FORKED_CORRIDOR] = Region("Jabu Jabus Belly Forked Corridor", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_BOOMERANG_ROOM, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MAP_ROOM, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_COMPASS_ROOM, {[]{return Here(RR_JABU_JABUS_BELLY_MAP_ROOM, []{return logic->CanUse(RG_BOOMERANG);});}}), - Entrance(RR_JABU_JABUS_BELLY_BLUE_TENTACLE, {[]{return Here(RR_JABU_JABUS_BELLY_MAP_ROOM, []{return logic->CanUse(RG_BOOMERANG);});}}), - Entrance(RR_JABU_JABUS_BELLY_GREEN_TENTACLE, {[]{return Here(RR_JABU_JABUS_BELLY_BLUE_TENTACLE, []{return logic->CanUse(RG_BOOMERANG);});}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_BOOMERANG_ROOM] = Region("Jabu Jabus Belly Boomerang Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_BOOMERANG_CHEST, true), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MAP_ROOM] = Region("Jabu Jabus Belly Map Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MAP_CHEST, logic->CanUse(RG_BOOMERANG)), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, {[]{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}}), + Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->HasItem(RG_HOVER_BOOTS);}}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return logic->CanUseProjectile();}}), }); areaTable[RR_JABU_JABUS_BELLY_COMPASS_ROOM] = Region("Jabu Jabus Belly Compass Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LOCATION(RC_JABU_JABUS_BELLY_COMPASS_CHEST, logic->CanAttack()), + //ruto could theoretically clear this room, but it's hard because of the timer and she doesn't appear with you when you respawn after failing, which would force a savewarp + LOCATION(RC_JABU_JABUS_BELLY_COMPASS_CHEST, logic->CanKillEnemy(RE_SHABOM)), }, { //Exits - Entrance(RR_JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return Here(RR_JABU_JABUS_BELLY_COMPASS_ROOM, []{return logic->CanKillEnemy(RE_SHABOM);});}}), }); - areaTable[RR_JABU_JABUS_BELLY_BLUE_TENTACLE] = Region("Jabu Jabus Belly Blue Tentacle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { + areaTable[RR_JABU_JABUS_BELLY_BLUE_TENTACLE] = Region("Jabu Jabus Belly Blue Tentacle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + EventAccess(&logic->JabuEastTentacle, {[]{return logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}}), + }, {}, { //Exits - Entrance(RR_JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return Here(RR_JABU_JABUS_BELLY_BLUE_TENTACLE, []{return logic->CanUse(RG_BOOMERANG);});}}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return logic->JabuEastTentacle;}}), }); - areaTable[RR_JABU_JABUS_BELLY_GREEN_TENTACLE] = Region("Jabu Jabus Belly Green Tentacle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { + areaTable[RR_JABU_JABUS_BELLY_GREEN_TENTACLE] = Region("Jabu Jabus Belly Green Tentacle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + EventAccess(&logic->JabuNorthTentacle, {[]{return logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}}), + }, {}, { //Exits - Entrance(RR_JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return Here(RR_JABU_JABUS_BELLY_GREEN_TENTACLE, []{return logic->CanUse(RG_BOOMERANG);});}}), + //implied logic->CanKillEnemy(RE_BARI) + Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return logic->JabuNorthTentacle;}}), }); - areaTable[RR_JABU_JABUS_BELLY_BIGOCTO_ROOM] = Region("Jabu Jabus Belly Bigocto Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { + areaTable[RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE] = Region("Jabu Jabus Belly Bigocto Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //Only adult can get the token without assistance + LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH)), + //You can get the LOWER skull token from here as aduly with hovers backwalk and a backflip, but it's trickworthy and not relevant unless you can beat tentacles without rang + }, { //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO, {[]{return Here(RR_JABU_JABUS_BELLY_BIGOCTO_ROOM, []{return (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_NUTS)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_STICKS));});}}), + Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO, {[]{return logic->JabuRutoIn1F && Here(RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE, []{return logic->CanKillEnemy(RE_BIG_OCTO);});}}), }); areaTable[RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO] = Region("Jabu Jabus Belly Above Bigocto", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { //Events EventAccess(&logic->FairyPot, {[]{return true;}}), EventAccess(&logic->NutPot, {[]{return true;}}), - }, {}, { + }, { + //Locations + //PUT AFTER OCTO POTS HERE + }, { //Exits Entrance(RR_JABU_JABUS_BELLY_LIFT_UPPER, {[]{return logic->CanUse(RG_BOOMERANG);}}), }); - areaTable[RR_JABU_JABUS_BELLY_LIFT_UPPER] = Region("Jabu Jabus Belly Lift Upper", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { + areaTable[RR_JABU_JABUS_BELLY_LIFT_UPPER] = Region("Jabu Jabus Belly Lift Upper", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->LoweredJabuPath, {[]{return true;}}), + }, {}, { //Exits - Entrance(RR_JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_LIFT_LOWER, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return true;}}), }); areaTable[RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM] = Region("Jabu Jabus Belly Near Boss Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LOCATION(RC_JABU_JABUS_BELLY_GS_NEAR_BOSS, logic->CanAttack()), + LOCATION(RC_JABU_JABUS_BELLY_GS_NEAR_BOSS, logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW)), }, { //Exits - Entrance(RR_JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, {[]{return logic->CanUse(RG_BOOMERANG) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_RANGED) && ((logic->IsAdult && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW))) || (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT)))) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_EXPLOSIVES) && (logic->CanUse(RG_BOMBCHU_5) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_BOMB_BAG))));}}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, {[]{return logic->CanUse(RG_BOOMERANG) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_RANGED) && logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_EXPLOSIVES) && (logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_BOMB_BAG))));}}), }); } @@ -205,7 +207,7 @@ void RegionTable_Init_JabuJabusBelly() { LOCATION(RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), }, { //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return true;}}), + Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, {[]{return true;}}), Entrance(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, {[]{return true;}}), Entrance(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, {[]{return logic->CanUse(RG_BOOMERANG) && logic->HasExplosives() && Here(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT);});}}), Entrance(RR_JABU_JABUS_BELLY_MQ_INVISIBLE_KEESE_ROOM, {[]{return logic->JabuNorthTentacle;}}), diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp index 6ad5ec758..b0be901d9 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp @@ -43,7 +43,12 @@ void RegionTable_Init_ZorasDomain() { Entrance(RR_ZR_FAIRY_GROTTO, {[]{return Here(RR_ZORAS_RIVER, []{return logic->BlastOrSmash();});}}), Entrance(RR_THE_LOST_WOODS, {[]{return logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS);}}), Entrance(RR_ZR_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}), - Entrance(RR_ZR_BEHIND_WATERFALL, {[]{return logic->CanUse(RG_ZELDAS_LULLABY) || (logic->IsChild && ctx->GetTrickOption(RT_ZR_CUCCO)) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_ZR_HOVERS));}}), + Entrance(RR_ZR_BEHIND_WATERFALL, {[]{ + return ctx->GetOption(RSK_SLEEPING_WATERFALL).Is(RO_WATERFALL_OPEN) || + Here(RR_ZORAS_RIVER, []{return logic->CanUse(RG_ZELDAS_LULLABY);}) || + (logic->IsChild && ctx->GetTrickOption(RT_ZR_CUCCO)) || + (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_ZR_HOVERS)); + }}), }); areaTable[RR_ZR_BEHIND_WATERFALL] = Region("ZR Behind Waterfall", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, {}, {}, { diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp index e789b16cf..53b02e036 100644 --- a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -80,14 +80,6 @@ int Playthrough_Init(uint32_t seed, std::set excludedLocations, SPDLOG_ERROR("Writing Spoiler Log Failed"); } StopPerformanceTimer(PT_SPOILER_LOG); -#ifdef ENABLE_DEBUG - SPDLOG_INFO("Writing Placement Log..."); - if (PlacementLog_Write()) { - SPDLOG_INFO("Writing Placement Log Done"); - } else { - SPDLOG_ERROR("Writing Placement Log Failed"); - } -#endif } ctx->playthroughLocations.clear(); diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp index f6c73de32..ecf4ea1be 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp @@ -156,7 +156,7 @@ int GetPriceFromMax(int max) { uint16_t GetPriceFromSettings(Rando::Location *loc, PriceSettingsStruct priceSettings) { auto ctx = Rando::Context::GetInstance(); - switch (ctx->GetOption(priceSettings.main).Value()){ + switch (ctx->GetOption(priceSettings.main).GetContextOptionIndex()){ case RO_PRICE_VANILLA: return loc->GetVanillaPrice(); case RO_PRICE_CHEAP_BALANCED: @@ -172,19 +172,19 @@ uint16_t GetPriceFromSettings(Rando::Location *loc, PriceSettingsStruct priceSet return 150; } case RO_PRICE_FIXED: - return (uint16_t)ctx->GetOption(priceSettings.fixedPrice).Value() * 5; + return (uint16_t)ctx->GetOption(priceSettings.fixedPrice).GetContextOptionIndex() * 5; case RO_PRICE_RANGE:{ - uint16_t range1 = (uint16_t)ctx->GetOption(priceSettings.range1).Value() * 5; - uint16_t range2 = (uint16_t)ctx->GetOption(priceSettings.range2).Value() * 5; + uint16_t range1 = (uint16_t)ctx->GetOption(priceSettings.range1).GetContextOptionIndex() * 5; + uint16_t range2 = (uint16_t)ctx->GetOption(priceSettings.range2).GetContextOptionIndex() * 5; return range1 < range2 ? Random(range1, range2+1) : Random(range2, range1+1); } case RO_PRICE_SET_BY_WALLET:{ - bool isTycoon = ctx->GetOption(RSK_INCLUDE_TYCOON_WALLET).Value(); - uint16_t noWeight = ctx->GetOption(priceSettings.noWallet).Value(); - uint16_t childWeight = ctx->GetOption(priceSettings.childWallet).Value(); - uint16_t adultWeight = ctx->GetOption(priceSettings.adultWallet).Value(); - uint16_t giantWeight = ctx->GetOption(priceSettings.giantWallet).Value(); - uint16_t tycoonWeight = isTycoon ? ctx->GetOption(priceSettings.tycoonWallet).Value() : 0; + bool isTycoon = ctx->GetOption(RSK_INCLUDE_TYCOON_WALLET).GetContextOptionIndex(); + uint16_t noWeight = ctx->GetOption(priceSettings.noWallet).GetContextOptionIndex(); + uint16_t childWeight = ctx->GetOption(priceSettings.childWallet).GetContextOptionIndex(); + uint16_t adultWeight = ctx->GetOption(priceSettings.adultWallet).GetContextOptionIndex(); + uint16_t giantWeight = ctx->GetOption(priceSettings.giantWallet).GetContextOptionIndex(); + uint16_t tycoonWeight = isTycoon ? ctx->GetOption(priceSettings.tycoonWallet).GetContextOptionIndex() : 0; uint16_t totalWeight = noWeight + childWeight + adultWeight + giantWeight + tycoonWeight; if (totalWeight == 0){ //if no weight, return from sane range return Random(0, 501); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index a418b8b5d..a665c4eea 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -6,7 +6,6 @@ #include "../entrance.h" #include "random.hpp" #include "../trial.h" -#include "tinyxml2.h" #include "utils.hpp" #include "hints.hpp" #include "pool_functions.hpp" @@ -56,9 +55,6 @@ void GenerateHash() { int number = std::stoi(hash.substr(j, 2)); ctx->hashIconIndexes[i] = number; } - - // Clear out spoiler log data here, in case we aren't going to re-generate it - // spoilerData = { 0 }; } static auto GetGeneralPath() { @@ -79,7 +75,6 @@ static void WriteLocation( Rando::Location* location = Rando::StaticData::GetLocation(locationKey); Rando::ItemLocation* itemLocation = Rando::Context::GetInstance()->GetItemLocation(locationKey); - // auto node = parentNode->InsertNewChildElement("location"); switch (gSaveContext.language) { case LANGUAGE_ENG: default: @@ -89,35 +84,6 @@ static void WriteLocation( jsonData["playthrough"][sphere][location->GetName()] = itemLocation->GetPlacedItemName().GetFrench(); break; } - // node->SetAttribute("name", location->GetName().c_str()); - // node->SetText(location->GetPlacedItemName().GetEnglish().c_str()); - - // if (withPadding) { - // constexpr int16_t LONGEST_NAME = 56; // The longest name of a location. - // constexpr int16_t PRICE_ATTRIBUTE = 12; // Length of a 3-digit price attribute. - - // // Insert a padding so we get a kind of table in the XML document. - // int16_t requiredPadding = LONGEST_NAME - location->GetName().length(); - // if (location->GetRCType() == RCTYPE_SHOP) { - // // Shop items have short location names, but come with an additional price attribute. - // requiredPadding -= PRICE_ATTRIBUTE; - // } - // if (requiredPadding >= 0) { - // std::string padding(requiredPadding, ' '); - // node->SetAttribute("_", padding.c_str()); - // } - // } - - // if (location->GetRCType() == RCTYPE_SHOP) { - // char price[6]; - // sprintf(price, "%03d", location->GetPrice()); - // node->SetAttribute("price", price); - // } - // if (!location->IsAddedToPool()) { - // #ifdef ENABLE_DEBUG - // node->SetAttribute("not-added", true); - // #endif - // } } //Writes a shuffled entrance to the specified node @@ -176,7 +142,7 @@ static void WriteSettings() { auto allOptionGroups = ctx->GetSettings()->GetOptionGroups(); for (const Rando::OptionGroup& optionGroup : allOptionGroups) { if (optionGroup.GetContainsType() == Rando::OptionGroupType::DEFAULT && optionGroup.PrintInSpoiler()) { - for (const Rando::Option* option : optionGroup.GetOptions()) { + for (Rando::Option* option : optionGroup.GetOptions()) { std::string settingName = optionGroup.GetName() + ":" + option->GetName(); jsonData["settings"][settingName] = option->GetSelectedOptionText(); } @@ -186,26 +152,18 @@ static void WriteSettings() { // Writes the excluded locations to the spoiler log, if there are any. static void WriteExcludedLocations() { - // auto parentNode = spoilerLog.NewElement("excluded-locations"); auto ctx = Rando::Context::GetInstance(); for (size_t i = 1; i < ctx->GetSettings()->GetExcludeLocationsOptions().size(); i++) { for (const auto& location : ctx->GetSettings()->GetExcludeLocationsOptions()[i]) { - if (location->GetSelectedOptionIndex() == RO_LOCATION_INCLUDE) { + if (location->GetContextOptionIndex() == RO_LOCATION_INCLUDE) { continue; } jsonData["excludedLocations"].push_back(RemoveLineBreaks(location->GetName())); - // tinyxml2::XMLElement* node = spoilerLog.NewElement("location"); - // node->SetAttribute("name", RemoveLineBreaks(location->GetName()).c_str()); - // parentNode->InsertEndChild(node); } } - - // if (!parentNode->NoChildren()) { - // spoilerLog.RootElement()->InsertEndChild(parentNode); - // } } // Writes the starting inventory to the spoiler log, if there is any. @@ -214,63 +172,27 @@ static void WriteStartingInventory() { const Rando::OptionGroup& optionGroup = ctx->GetSettings()->GetOptionGroup(RSG_STARTING_INVENTORY); for (const Rando::OptionGroup* subGroup : optionGroup.GetSubGroups()) { if (subGroup->GetContainsType() == Rando::OptionGroupType::DEFAULT) { - for (const Rando::Option* option : subGroup->GetOptions()) { + for (Rando::Option* option : subGroup->GetOptions()) { jsonData["settings"][option->GetName()] = option->GetSelectedOptionText(); } } } } -// Writes the enabled tricks to the spoiler log, if there are any. -static void WriteEnabledTricks(tinyxml2::XMLDocument& spoilerLog) { - //auto parentNode = spoilerLog.NewElement("enabled-tricks"); +//Writes the enabled tricks to the spoiler log, if there are any. +static void WriteEnabledTricks() { auto ctx = Rando::Context::GetInstance(); for (const auto& setting : ctx->GetSettings()->GetOptionGroup(RSG_TRICKS).GetOptions()) { - if (setting->GetSelectedOptionIndex() != RO_GENERIC_ON/* || !setting->IsCategory(OptionCategory::Setting)*/) { + if (setting->GetContextOptionIndex() != RO_GENERIC_ON) { continue; } jsonData["enabledTricks"].push_back(RemoveLineBreaks(setting->GetName()).c_str()); - //auto node = parentNode->InsertNewChildElement("trick"); - //node->SetAttribute("name", RemoveLineBreaks(setting->GetName()).c_str()); } - - // if (!parentNode->NoChildren()) { - // spoilerLog.RootElement()->InsertEndChild(parentNode); - //} } -// Writes the enabled glitches to the spoiler log, if there are any. -// TODO: Implement Glitches -// static void WriteEnabledGlitches(tinyxml2::XMLDocument& spoilerLog) { -// auto parentNode = spoilerLog.NewElement("enabled-glitches"); - -// for (const auto& setting : Settings::glitchCategories) { -// if (setting->Value() == 0) { -// continue; -// } - -// auto node = parentNode->InsertNewChildElement("glitch-category"); -// node->SetAttribute("name", setting->GetName().c_str()); -// node->SetText(setting->GetSelectedOptionText().c_str()); -// } - -// for (const auto& setting : Settings::miscGlitches) { -// if (!setting->Value()) { -// continue; -// } - -// auto node = parentNode->InsertNewChildElement("misc-glitch"); -// node->SetAttribute("name", RemoveLineBreaks(setting->GetName()).c_str()); -// } - -// if (!parentNode->NoChildren()) { -// spoilerLog.RootElement()->InsertEndChild(parentNode); -// } -// } - // Writes the Master Quest dungeons to the spoiler log, if there are any. -static void WriteMasterQuestDungeons(tinyxml2::XMLDocument& spoilerLog) { +static void WriteMasterQuestDungeons() { auto ctx = Rando::Context::GetInstance(); for (const auto* dungeon : ctx->GetDungeons()->GetDungeonList()) { std::string dungeonName; @@ -294,7 +216,6 @@ static void WriteRequiredTrials() { // Writes the intended playthrough to the spoiler log, separated into spheres. static void WritePlaythrough() { - // auto playthroughNode = spoilerLog.NewElement("playthrough"); auto ctx = Rando::Context::GetInstance(); for (uint32_t i = 0; i < ctx->playthroughLocations.size(); ++i) { @@ -306,8 +227,6 @@ static void WritePlaythrough() { WriteLocation(sphereString, key, true); } } - - // spoilerLog.RootElement()->InsertEndChild(playthroughNode); } //Write the randomized entrance playthrough to the spoiler log, if applicable @@ -389,11 +308,6 @@ static void WriteAllLocations() { const char* SpoilerLog_Write() { auto ctx = Rando::Context::GetInstance(); - auto spoilerLog = tinyxml2::XMLDocument(false); - spoilerLog.InsertEndChild(spoilerLog.NewDeclaration()); - - auto rootNode = spoilerLog.NewElement("spoiler-log"); - spoilerLog.InsertEndChild(rootNode); jsonData.clear(); @@ -413,11 +327,8 @@ const char* SpoilerLog_Write() { WriteSettings(); WriteExcludedLocations(); WriteStartingInventory(); - WriteEnabledTricks(spoilerLog); //RANDOTODO clean up spoilerLog refernces - //if (Settings::Logic.Is(LOGIC_GLITCHED)) { - // WriteEnabledGlitches(spoilerLog); - //} - WriteMasterQuestDungeons(spoilerLog); + WriteEnabledTricks(); + WriteMasterQuestDungeons(); WriteRequiredTrials(); WritePlaythrough(); @@ -466,30 +377,3 @@ void PlacementLog_Clear() { placementtxt = ""; } -// RANDOTODO: Do we even use this? -bool PlacementLog_Write() { - auto placementLog = tinyxml2::XMLDocument(false); - placementLog.InsertEndChild(placementLog.NewDeclaration()); - - auto rootNode = placementLog.NewElement("placement-log"); - placementLog.InsertEndChild(rootNode); - - // rootNode->SetAttribute("version", Settings::version.c_str()); - // rootNode->SetAttribute("seed", Settings::seed); - - // WriteSettings(placementLog, true); // Include hidden settings. - // WriteExcludedLocations(placementLog); - // WriteStartingInventory(placementLog); - WriteEnabledTricks(placementLog); - //WriteEnabledGlitches(placementLog); - WriteMasterQuestDungeons(placementLog); - //WriteRequiredTrials(placementLog); - - placementtxt = "\n" + placementtxt; - - auto node = rootNode->InsertNewChildElement("log"); - auto contentNode = node->InsertNewText(placementtxt.c_str()); - contentNode->SetCData(true); - - return true; -} diff --git a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp index 781b54ad3..035259fdb 100644 --- a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp @@ -112,7 +112,7 @@ void GenerateStartingInventory() { // AddItemToInventory(RG_EMPTY_BOTTLE, 1); // } // AddItemToInventory(RG_RUTOS_LETTER, StartingRutoBottle.Value()); - AddItemToInventory(RG_PROGRESSIVE_OCARINA, ctx->GetOption(RSK_STARTING_OCARINA).Value()); + AddItemToInventory(RG_PROGRESSIVE_OCARINA, ctx->GetOption(RSK_STARTING_OCARINA).GetContextOptionIndex()); AddItemToInventory(RG_ZELDAS_LULLABY, ctx->GetOption(RSK_STARTING_ZELDAS_LULLABY) ? 1 : 0); AddItemToInventory(RG_EPONAS_SONG, ctx->GetOption(RSK_STARTING_EPONAS_SONG) ? 1 : 0); AddItemToInventory(RG_SARIAS_SONG, ctx->GetOption(RSK_STARTING_SARIAS_SONG) ? 1 : 0); @@ -153,21 +153,21 @@ void GenerateStartingInventory() { // AddItemToInventory(RG_SPIRIT_MEDALLION, StartingSpiritMedallion.Value()); // AddItemToInventory(RG_SHADOW_MEDALLION, StartingShadowMedallion.Value()); // AddItemToInventory(RG_LIGHT_MEDALLION, StartingLightMedallion.Value()); - AddItemToInventory(RG_GOLD_SKULLTULA_TOKEN, ctx->GetOption(RSK_STARTING_SKULLTULA_TOKEN).Value()); + AddItemToInventory(RG_GOLD_SKULLTULA_TOKEN, ctx->GetOption(RSK_STARTING_SKULLTULA_TOKEN).GetContextOptionIndex()); - int8_t hearts = ctx->GetOption(RSK_STARTING_HEARTS).Value() - 2; + int8_t hearts = ctx->GetOption(RSK_STARTING_HEARTS).GetContextOptionIndex() - 2; AdditionalHeartContainers = 0; if (hearts < 0) { AddItemToInventory(RG_PIECE_OF_HEART, 4); // Plentiful and minimal have less than 4 standard pieces of heart so also replace the winner heart - if (ctx->GetOption(RSK_ITEM_POOL).Value() == 0 || ctx->GetOption(RSK_ITEM_POOL).Value() == 3) { + if (ctx->GetOption(RSK_ITEM_POOL).GetContextOptionIndex() == 0 || ctx->GetOption(RSK_ITEM_POOL).GetContextOptionIndex() == 3) { AddItemToInventory(RG_TREASURE_GAME_HEART); } AdditionalHeartContainers = 1 - hearts; } else if (hearts > 0) { // 16 containers in plentiful, 8 in balanced and 0 in the others - uint8_t maxContainers = 8 * std::max(0, 2 - ctx->GetOption(RSK_ITEM_POOL).Value()); + uint8_t maxContainers = 8 * std::max(0, 2 - ctx->GetOption(RSK_ITEM_POOL).GetContextOptionIndex()); if (hearts <= maxContainers) { AddItemToInventory(RG_HEART_CONTAINER, hearts); diff --git a/soh/soh/Enhancements/randomizer/Plandomizer.cpp b/soh/soh/Enhancements/randomizer/Plandomizer.cpp index fcec76887..f346eeb18 100644 --- a/soh/soh/Enhancements/randomizer/Plandomizer.cpp +++ b/soh/soh/Enhancements/randomizer/Plandomizer.cpp @@ -270,6 +270,16 @@ Rando::Item plandomizerRandoRetrieveItem(RandomizerGet randoGetItem) { return randoGetItemEntry; } +void PlandoPushImageButtonStyle(){ + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f)); +} + +void PlandoPopImageButtonStyle(){ + ImGui::PopStyleColor(3); +} + ImVec4 plandomizerGetItemColor(Rando::Item randoItem) { itemColor = ImVec4( 1.0f, 1.0f, 1.0f, 1.0f ); if (randoItem.GetItemType() == ITEMTYPE_SMALLKEY || randoItem.GetItemType() == ITEMTYPE_FORTRESS_SMALLKEY @@ -698,6 +708,7 @@ void PlandomizerOverlayText(std::pair drawObject ) { void PlandomizerDrawItemPopup(uint32_t index) { if (shouldPopup && ImGui::BeginPopup("ItemList")) { + PlandoPushImageButtonStyle(); ImGui::SeparatorText("Resources"); ImGui::BeginTable("Infinite Item Table", 7); for (auto& item : infiniteItemList) { @@ -759,6 +770,7 @@ void PlandomizerDrawItemPopup(uint32_t index) { PlandomizerRemoveFromItemList(drawnItemsList[temporaryItemIndex].first); PlandomizerAddToItemList(temporaryItem); } + PlandoPopImageButtonStyle(); ImGui::EndTable(); ImGui::EndPopup(); } @@ -767,6 +779,7 @@ void PlandomizerDrawItemPopup(uint32_t index) { void PlandomizerDrawIceTrapPopUp(uint32_t index) { if (shouldTrapPopup && ImGui::BeginPopup("TrapList")) { ImGui::BeginTable("Ice Trap Table", 8); + PlandoPushImageButtonStyle(); for (auto& items : itemImageMap) { if (items.first == RG_ICE_TRAP) { continue; @@ -785,6 +798,7 @@ void PlandomizerDrawIceTrapPopUp(uint32_t index) { ImGui::PopID(); } + PlandoPopImageButtonStyle(); ImGui::EndTable(); ImGui::EndPopup(); } @@ -792,12 +806,14 @@ void PlandomizerDrawIceTrapPopUp(uint32_t index) { void PlandomizerDrawItemSlots(uint32_t index) { ImGui::PushID(index); + PlandoPushImageButtonStyle(); PlandomizerItemImageCorrection(plandoLogData[index].checkRewardItem); if (ImGui::ImageButton(textureID, imageSize, textureUV0, textureUV1, imagePadding, ImVec4(0, 0, 0, 0), itemColor)) { shouldPopup = true; temporaryItem = plandoLogData[index].checkRewardItem; ImGui::OpenPopup("ItemList"); }; + PlandoPopImageButtonStyle(); UIWidgets::Tooltip(plandoLogData[index].checkRewardItem.GetName().english.c_str()); PlandomizerOverlayText(std::make_pair(plandoLogData[index].checkRewardItem, 1)); PlandomizerDrawItemPopup(index); @@ -808,9 +824,19 @@ void PlandomizerDrawShopSlider(uint32_t index) { ImGui::PushID(index); ImGui::Text("Price:"); ImGui::SameLine(); - ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - 20.0f); + std::string MinusBTNName = " - ##Price"; + if (ImGui::Button(MinusBTNName.c_str()) && plandoLogData[index].shopPrice > 0) { + plandoLogData[index].shopPrice--; + } + ImGui::SameLine(); + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - 40.0f); ImGui::SliderInt("", &plandoLogData[index].shopPrice, 0, 999, "%d Rupees"); ImGui::PopItemWidth(); + ImGui::SameLine(); + std::string PlusBTNName = " + ##Price"; + if (ImGui::Button(PlusBTNName.c_str()) && plandoLogData[index].shopPrice < 999) { + plandoLogData[index].shopPrice++; + } ImGui::PopID(); } @@ -825,10 +851,12 @@ void PlandomizerDrawIceTrapSetup(uint32_t index) { ImGui::TableNextColumn(); PlandomizerItemImageCorrection(plandoLogData[index].iceTrapModel); + PlandoPushImageButtonStyle(); if (ImGui::ImageButton(textureID, imageSize, textureUV0, textureUV1, imagePadding, ImVec4(0, 0, 0, 0), itemColor)) { shouldTrapPopup = true; ImGui::OpenPopup("TrapList"); }; + PlandoPopImageButtonStyle(); UIWidgets::Tooltip(plandoLogData[index].iceTrapModel.GetName().english.c_str()); PlandomizerDrawIceTrapPopUp(index); ImGui::SameLine(); @@ -847,7 +875,7 @@ void PlandomizerDrawIceTrapSetup(uint32_t index) { plandoLogData[index].iceTrapName = trapTextInput.c_str(); } - if (plandoLogData[index].shopPrice > -1) { + if (plandoLogData[index].shopPrice >= 0) { PlandomizerDrawShopSlider(index); } ImGui::EndTable(); @@ -860,7 +888,7 @@ void PlandomizerDrawOptions() { ImGui::TableNextColumn(); ImGui::SeparatorText("Load/Save Spoiler Log"); PlandomizerPopulateSeedList(); - static int32_t selectedList = 0; + static size_t selectedList = 0; if (existingSeedList.size() != 0) { if (ImGui::BeginCombo("##JsonFiles", existingSeedList[selectedList].c_str())) { for (size_t i = 0; i < existingSeedList.size(); i++) { @@ -895,15 +923,13 @@ void PlandomizerDrawOptions() { ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (ImGui::GetContentRegionAvail().x * 0.5f) - (34.0f * 5.0f)); if (spoilerLogData.size() > 0) { ImGui::BeginTable("HashIcons", 5); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f)); for (int i = 0; i < 5; i++) { ImGui::TableSetupColumn("Icon", ImGuiTableColumnFlags_WidthFixed, 34.0f); } ImGui::TableNextColumn(); - int32_t index = 0; + size_t index = 0; + PlandoPushImageButtonStyle(); for (auto& hash : plandoHash) { ImGui::PushID(index); textureID = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gSeedTextures[hash].tex); @@ -930,7 +956,7 @@ void PlandomizerDrawOptions() { ImGui::PopID(); index++; } - ImGui::PopStyleColor(3); + PlandoPopImageButtonStyle(); ImGui::EndTable(); } else { ImGui::Text("No Spoiler Log Loaded"); @@ -1039,9 +1065,6 @@ void PlandomizerDrawLocationsWindow(RandomizerCheckArea rcArea) { ImGui::TableSetupColumn("Additional Options"); ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableHeadersRow(); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f)); for (auto& spoilerData : spoilerLogData) { auto checkID = Rando::StaticData::locationNameToEnum[spoilerData.checkName]; @@ -1070,7 +1093,6 @@ void PlandomizerDrawLocationsWindow(RandomizerCheckArea rcArea) { } index++; } - ImGui::PopStyleColor(3); ImGui::EndTable(); ImGui::EndChild(); } diff --git a/soh/soh/Enhancements/randomizer/entrance.cpp b/soh/soh/Enhancements/randomizer/entrance.cpp index bc9cb5513..b8ca9a3d0 100644 --- a/soh/soh/Enhancements/randomizer/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/entrance.cpp @@ -672,11 +672,8 @@ bool EntranceShuffler::PlaceOneWayPriorityEntrance( } } } -#ifdef ENABLE_DEBUG - auto message = "ERROR: Unable to place priority one-way entrance for " + priorityName + "\n"; - SPDLOG_DEBUG(message); - PlacementLog_Write(); -#endif + SPDLOG_DEBUG("ERROR: Unable to place priority one-way entrance for " + priorityName + "\n"); + assert(false); return false; } @@ -1333,12 +1330,12 @@ int EntranceShuffler::ShuffleAllEntrances() { (ctx->GetOption(RSK_MIX_OVERWORLD_ENTRANCES) ? 1 : 0) + (ctx->GetOption(RSK_MIX_INTERIOR_ENTRANCES) ? 1 : 0) + (ctx->GetOption(RSK_MIX_GROTTO_ENTRANCES) ? 1 : 0); if (totalMixedPools < 2) { - ctx->GetOption(RSK_MIXED_ENTRANCE_POOLS).SetSelectedIndex(RO_GENERIC_OFF); - ctx->GetOption(RSK_MIX_DUNGEON_ENTRANCES).SetSelectedIndex(RO_GENERIC_OFF); - ctx->GetOption(RSK_MIX_BOSS_ENTRANCES).SetSelectedIndex(RO_GENERIC_OFF); - ctx->GetOption(RSK_MIX_OVERWORLD_ENTRANCES).SetSelectedIndex(RO_GENERIC_OFF); - ctx->GetOption(RSK_MIX_INTERIOR_ENTRANCES).SetSelectedIndex(RO_GENERIC_OFF); - ctx->GetOption(RSK_MIX_GROTTO_ENTRANCES).SetSelectedIndex(RO_GENERIC_OFF); + ctx->GetOption(RSK_MIXED_ENTRANCE_POOLS).SetContextIndex(RO_GENERIC_OFF); + ctx->GetOption(RSK_MIX_DUNGEON_ENTRANCES).SetContextIndex(RO_GENERIC_OFF); + ctx->GetOption(RSK_MIX_BOSS_ENTRANCES).SetContextIndex(RO_GENERIC_OFF); + ctx->GetOption(RSK_MIX_OVERWORLD_ENTRANCES).SetContextIndex(RO_GENERIC_OFF); + ctx->GetOption(RSK_MIX_INTERIOR_ENTRANCES).SetContextIndex(RO_GENERIC_OFF); + ctx->GetOption(RSK_MIX_GROTTO_ENTRANCES).SetContextIndex(RO_GENERIC_OFF); } if (ctx->GetOption(RSK_MIXED_ENTRANCE_POOLS)) { std::set poolsToMix = {}; diff --git a/soh/soh/Enhancements/randomizer/fishsanity.cpp b/soh/soh/Enhancements/randomizer/fishsanity.cpp index 5fa2974ae..f3ff89d70 100644 --- a/soh/soh/Enhancements/randomizer/fishsanity.cpp +++ b/soh/soh/Enhancements/randomizer/fishsanity.cpp @@ -17,7 +17,7 @@ extern PlayState* gPlayState; #define FSi OTRGlobals::Instance->gRandoContext->GetFishsanity() -#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetSelectedOptionIndex() +#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetContextOptionIndex() /** * @brief Parallel list of pond fish checks for both ages @@ -59,6 +59,7 @@ namespace Rando { const FishIdentity Fishsanity::defaultIdentity = { RAND_INF_MAX, RC_UNKNOWN_CHECK }; bool Fishsanity::fishsanityHelpersInit = false; s16 Fishsanity::fishGroupCounter = 0; + bool Fishsanity::enableAdvance = false; std::unordered_map Fishsanity::pondFishAgeMap; std::vector Fishsanity::childPondFish; std::vector Fishsanity::adultPondFish; @@ -395,22 +396,6 @@ namespace Rando { } } - void Fishsanity::OnFlagSetHandler(int16_t flagType, int16_t flag) { - if (flagType != FLAG_RANDOMIZER_INF) { - return; - } - RandomizerCheck rc = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf((RandomizerInf)flag); - FishsanityCheckType fsType = Rando::Fishsanity::GetCheckType(rc); - if (fsType == FSC_NONE) { - return; - } - - // When a pond fish is caught, advance the pond. - if (fsType == FSC_POND) { - OTRGlobals::Instance->gRandoContext->GetFishsanity()->AdvancePond(); - } - } - void Fishsanity::OnActorUpdateHandler(void* refActor) { if (gPlayState->sceneNum != SCENE_GROTTOS && gPlayState->sceneNum != SCENE_ZORAS_DOMAIN && gPlayState->sceneNum != SCENE_FISHING_POND) { return; @@ -428,6 +413,7 @@ namespace Rando { FishIdentity identity = OTRGlobals::Instance->gRandomizer->IdentifyFish(gPlayState->sceneNum, actor->params); if (identity.randomizerCheck != RC_UNKNOWN_CHECK) { Flags_SetRandomizerInf(identity.randomizerInf); + enableAdvance = true; // Remove uncaught effect if (actor->shape.shadowDraw != NULL) { actor->shape.shadowDraw = NULL; @@ -483,6 +469,13 @@ namespace Rando { } } } + + void Fishsanity::OnItemReceiveHandler(GetItemEntry itemEntry) { + if (enableAdvance) { + enableAdvance = false; + OTRGlobals::Instance->gRandoContext->GetFishsanity()->AdvancePond(); + } + } } // namespace Rando // C interface diff --git a/soh/soh/Enhancements/randomizer/fishsanity.h b/soh/soh/Enhancements/randomizer/fishsanity.h index c98e9ab9c..91d021157 100644 --- a/soh/soh/Enhancements/randomizer/fishsanity.h +++ b/soh/soh/Enhancements/randomizer/fishsanity.h @@ -133,11 +133,6 @@ class Fishsanity { */ static void OnActorInitHandler(void* refActor); - /** - * @brief FlagSet hook handler for fishsanity - */ - static void OnFlagSetHandler(int16_t flagType, int16_t flag); - /** * @brief PlayerUpdate hook handler for fishsanity */ @@ -158,6 +153,8 @@ class Fishsanity { */ static void OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_list originalArgs); + static void OnItemReceiveHandler(GetItemEntry itemEntry); + private: /** * @brief Initialize helper statics if they have not been initialized yet @@ -184,6 +181,7 @@ class Fishsanity { static bool fishsanityHelpersInit; static s16 fishGroupCounter; + static bool enableAdvance; ///////////////////////////////////////////////////////// //// Helper data structures derived from static data //// diff --git a/soh/soh/Enhancements/randomizer/hint.cpp b/soh/soh/Enhancements/randomizer/hint.cpp index 056102195..e248eebe0 100644 --- a/soh/soh/Enhancements/randomizer/hint.cpp +++ b/soh/soh/Enhancements/randomizer/hint.cpp @@ -559,23 +559,23 @@ CustomMessage Hint::GetBridgeReqsText() { } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_STONES)) { bridgeMessage = StaticData::hintTextTable[RHT_BRIDGE_STONES_HINT].GetHintMessage(); - bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT).Value()); + bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_MEDALLIONS)) { bridgeMessage = StaticData::hintTextTable[RHT_BRIDGE_MEDALLIONS_HINT].GetHintMessage(); - bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT).Value()); + bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS)) { bridgeMessage = StaticData::hintTextTable[RHT_BRIDGE_REWARDS_HINT].GetHintMessage(); - bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).Value()); + bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS)) { bridgeMessage = StaticData::hintTextTable[RHT_BRIDGE_DUNGEONS_HINT].GetHintMessage(); - bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Value()); + bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS)) { bridgeMessage = StaticData::hintTextTable[RHT_BRIDGE_TOKENS_HINT].GetHintMessage(); - bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Value()); + bridgeMessage.InsertNumber(ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG)) { return StaticData::hintTextTable[RHT_BRIDGE_GREG_HINT].GetHintMessage(); @@ -613,23 +613,23 @@ CustomMessage Hint::GetGanonBossKeyText() { } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) { ganonBossKeyMessage = StaticData::hintTextTable[RHT_LACS_STONES_HINT].GetHintMessage(); - ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_STONE_COUNT).Value()); + ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_STONE_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_MEDALLIONS)) { ganonBossKeyMessage = StaticData::hintTextTable[RHT_LACS_MEDALLIONS_HINT].GetHintMessage(); - ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_MEDALLION_COUNT).Value()); + ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_MEDALLION_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_REWARDS)) { ganonBossKeyMessage = StaticData::hintTextTable[RHT_LACS_REWARDS_HINT].GetHintMessage(); - ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_REWARD_COUNT).Value()); + ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_REWARD_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS)) { ganonBossKeyMessage = StaticData::hintTextTable[RHT_LACS_DUNGEONS_HINT].GetHintMessage(); - ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Value()); + ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_DUNGEON_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) { ganonBossKeyMessage = StaticData::hintTextTable[RHT_LACS_TOKENS_HINT].GetHintMessage(); - ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_TOKEN_COUNT).Value()); + ganonBossKeyMessage.InsertNumber(ctx->GetOption(RSK_LACS_TOKEN_COUNT).GetContextOptionIndex()); } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) { return StaticData::hintTextTable[RHT_GANON_BK_TRIFORCE_HINT].GetHintMessage(); diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 35badbce6..000081cec 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -51,6 +51,7 @@ extern "C" { #include "src/overlays/actors/ovl_Door_Gerudo/z_door_gerudo.h" #include "src/overlays/actors/ovl_En_Xc/z_en_xc.h" #include "src/overlays/actors/ovl_Fishing/z_fishing.h" +#include "src/overlays/actors/ovl_En_Mk/z_en_mk.h" #include "adult_trade_shuffle.h" #include "draw.h" @@ -60,9 +61,10 @@ extern void func_8084DFAC(PlayState* play, Player* player); extern void Player_SetupActionPreserveAnimMovement(PlayState* play, Player* player, PlayerActionFunc actionFunc, s32 flags); extern s32 Player_SetupWaitForPutAway(PlayState* play, Player* player, AfterPutAwayFunc func); extern void Play_InitEnvironment(PlayState * play, s16 skyboxId); +extern void EnMk_Wait(EnMk* enMk, PlayState* play); } -#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetSelectedOptionIndex() +#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetContextOptionIndex() bool LocMatchesQuest(Rando::Location loc) { if (loc.GetQuest() == RCQUEST_BOTH) { @@ -619,11 +621,11 @@ void func_8083A434_override(PlayState* play, Player* player) { bool ShouldGiveFishingPrize(f32 sFishOnHandLength){ // RANDOTODO: update the enhancement sliders to not allow // values above rando fish weight values when rando'd - if(LINK_IS_CHILD) { + if(LINK_IS_CHILD) { int32_t weight = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) ? CVarGetInteger(CVAR_ENHANCEMENT("MinimumFishWeightChild"), 10) : 10; f32 score = sqrt(((f32)weight - 0.5f) / 0.0036f); return sFishOnHandLength >= score && (IS_RANDO ? !Flags_GetRandomizerInf(RAND_INF_CHILD_FISHING) : !(HIGH_SCORE(HS_FISHING) & HS_FISH_PRIZE_CHILD)); - } else + } else { int32_t weight = CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) ? CVarGetInteger(CVAR_ENHANCEMENT("MinimumFishWeightAdult"), 13) : 13; f32 score = sqrt(((f32)weight - 0.5f) / 0.0036f); @@ -631,6 +633,147 @@ bool ShouldGiveFishingPrize(f32 sFishOnHandLength){ } } +void RandomizerOnDialogMessageHandler() { + MessageContext *msgCtx = &gPlayState->msgCtx; + Actor *actor = msgCtx->talkActor; + auto ctx = Rando::Context::GetInstance(); + bool revealMerchant = ctx->GetOption(RSK_MERCHANT_TEXT_HINT).GetContextOptionIndex() != RO_GENERIC_OFF; + bool nonBeanMerchants = ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL); + + RandomizerCheck reveal = RC_UNKNOWN_CHECK; + if (ctx->GetOption(RSK_CHICKENS_HINT) && (msgCtx->textId >= TEXT_ANJU_PLEASE_BRING_MY_CUCCOS_BACK && msgCtx->textId <= TEXT_ANJU_PLEASE_BRING_1_CUCCO)) { + reveal = RC_KAK_ANJU_AS_CHILD; + } else { + switch (msgCtx->textId) { + case TEXT_SKULLTULA_PEOPLE_IM_CURSED: + if (actor->params == 1 && ctx->GetOption(RSK_KAK_10_SKULLS_HINT)){ + reveal = RC_KAK_10_GOLD_SKULLTULA_REWARD; + } else if (actor->params == 2 && ctx->GetOption(RSK_KAK_20_SKULLS_HINT)){ + reveal = RC_KAK_20_GOLD_SKULLTULA_REWARD; + } else if (actor->params == 3 && ctx->GetOption(RSK_KAK_30_SKULLS_HINT)){ + reveal = RC_KAK_30_GOLD_SKULLTULA_REWARD; + } else if (actor->params == 4 && ctx->GetOption(RSK_KAK_40_SKULLS_HINT)){ + reveal = RC_KAK_40_GOLD_SKULLTULA_REWARD; + } else if (ctx->GetOption(RSK_KAK_50_SKULLS_HINT)){ + reveal = RC_KAK_50_GOLD_SKULLTULA_REWARD; + } + break; + case TEXT_SKULLTULA_PEOPLE_MAKE_YOU_VERY_RICH: + if (ctx->GetOption(RSK_KAK_100_SKULLS_HINT)) { + reveal = RC_KAK_100_GOLD_SKULLTULA_REWARD; + } + break; + case TEXT_MASK_SHOP_SIGN: + if (ctx->GetOption(RSK_MASK_SHOP_HINT)) { + auto itemSkull_loc = ctx->GetItemLocation(RC_DEKU_THEATER_SKULL_MASK); + if (itemSkull_loc->GetCheckStatus() == RCSHOW_UNCHECKED) { + itemSkull_loc->SetCheckStatus(RCSHOW_IDENTIFIED); + } + reveal = RC_DEKU_THEATER_MASK_OF_TRUTH; + } + break; + case TEXT_GHOST_SHOP_EXPLAINATION: + case TEXT_GHOST_SHOP_CARD_HAS_POINTS: + if (ctx->GetOption(RSK_BIG_POES_HINT)) { + reveal = RC_MARKET_10_BIG_POES; + } + break; + case TEXT_MALON_EVERYONE_TURNING_EVIL: + case TEXT_MALON_I_SING_THIS_SONG: + case TEXT_MALON_HOW_IS_EPONA_DOING: + case TEXT_MALON_OBSTICLE_COURSE: + case TEXT_MALON_INGO_MUST_HAVE_BEEN_TEMPTED: + if (ctx->GetOption(RSK_MALON_HINT)) { + reveal = RC_KF_LINKS_HOUSE_COW; + } + break; + case TEXT_FROGS_UNDERWATER: + if (ctx->GetOption(RSK_FROGS_HINT)) { + reveal = RC_ZR_FROGS_OCARINA_GAME; + } + break; + case TEXT_GF_HBA_SIGN: + case TEXT_HBA_NOT_ON_HORSE: + case TEXT_HBA_INITIAL_EXPLAINATION: + case TEXT_HBA_ALREADY_HAVE_1000: + if (ctx->GetOption(RSK_HBA_HINT)) { + auto item1000_loc = ctx->GetItemLocation(RC_GF_HBA_1000_POINTS); + if (item1000_loc->GetCheckStatus() == RCSHOW_UNCHECKED) { + item1000_loc->SetCheckStatus(RCSHOW_IDENTIFIED); + } + reveal = RC_GF_HBA_1500_POINTS; + } + break; + case TEXT_SCRUB_RANDOM: + if (ctx->GetOption(RSK_SCRUB_TEXT_HINT).GetContextOptionIndex() != RO_GENERIC_OFF) { + EnDns* enDns = (EnDns*)actor; + reveal = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf((RandomizerInf)enDns->sohScrubIdentity.randomizerInf); + } + break; + case TEXT_BEAN_SALESMAN_BUY_FOR_10: + if (revealMerchant && (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL))) { + reveal = RC_ZR_MAGIC_BEAN_SALESMAN; + } + break; + case TEXT_GRANNYS_SHOP: + if (revealMerchant && nonBeanMerchants && + (ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) || INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK)) { + reveal = RC_KAK_GRANNYS_SHOP; + } + break; + case TEXT_MEDIGORON: + if (revealMerchant && nonBeanMerchants) { + reveal = RC_GC_MEDIGORON; + } + break; + case TEXT_CARPET_SALESMAN_1: + if (revealMerchant && nonBeanMerchants) { + reveal = RC_WASTELAND_BOMBCHU_SALESMAN; + } + break; + case TEXT_BIGGORON_BETTER_AT_SMITHING: + case TEXT_BIGGORON_WAITING_FOR_YOU: + case TEXT_BIGGORON_RETURN_AFTER_A_FEW_DAYS: + case TEXT_BIGGORON_I_MAAAADE_THISSSS: + if (ctx->GetOption(RSK_BIGGORON_HINT)) { + reveal = RC_DMT_TRADE_CLAIM_CHECK; + } + break; + case TEXT_SHEIK_NEED_HOOK: + case TEXT_SHEIK_HAVE_HOOK: + if (ctx->GetOption(RSK_OOT_HINT) && gPlayState->sceneNum == SCENE_TEMPLE_OF_TIME && + !ctx->GetItemLocation(RC_SONG_FROM_OCARINA_OF_TIME)->HasObtained()) { + auto itemoot_loc = ctx->GetItemLocation(RC_HF_OCARINA_OF_TIME_ITEM); + if (itemoot_loc->GetCheckStatus() == RCSHOW_UNCHECKED) { + itemoot_loc->SetCheckStatus(RCSHOW_IDENTIFIED); + } + reveal = RC_SONG_FROM_OCARINA_OF_TIME; + } + break; + case TEXT_FISHING_CLOUDY: + case TEXT_FISHING_TRY_ANOTHER_LURE: + case TEXT_FISHING_SECRETS: + case TEXT_FISHING_GOOD_FISHERMAN: + case TEXT_FISHING_DIFFERENT_POND: + case TEXT_FISHING_SCRATCHING: + case TEXT_FISHING_TRY_ANOTHER_LURE_WITH_SINKING_LURE: + if (ctx->GetOption(RSK_LOACH_HINT)) { + reveal = RC_LH_HYRULE_LOACH; + } + break; + } + } + + if (reveal != RC_UNKNOWN_CHECK) { + auto item_loc = ctx->GetItemLocation(reveal); + if (item_loc->GetCheckStatus() == RCSHOW_UNCHECKED) { + item_loc->SetCheckStatus(RCSHOW_IDENTIFIED); + } + } +} + void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_list originalArgs) { va_list args; va_copy(args, originalArgs); @@ -860,7 +1003,8 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l // This is typically called when you close the text box after getting an item, in case a previous // function hid the interface. - Interface_ChangeAlpha(gSaveContext.unk_13EE); + gSaveContext.unk_13EA = 0; + Interface_ChangeAlpha(0x32); // EnItem00_SetupAction(item00, func_8001E5C8); // *should = false; } else if (item00->actor.params == ITEM00_SOH_GIVE_ITEM_ENTRY_GI) { @@ -1399,9 +1543,23 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l } break; } + case VB_TRADE_TIMER_EYEDROPS:{ + EnMk* enMk = va_arg(args, EnMk*); + Flags_SetRandomizerInf(RAND_INF_ADULT_TRADES_LH_TRADE_FROG); + enMk->actor.flags &= ~ACTOR_FLAG_WILL_TALK; + enMk->actionFunc = EnMk_Wait; + enMk->flags |= 1; + *should = false; + break; + } + // We need to override the vanilla behavior here because the player might sequence break and get Ruto kidnapped before accessing other + // checks that require Ruto. So if she's kidnapped we allow her to spawn again + case VB_RUTO_BE_CONSIDERED_NOT_KIDNAPPED: { + *should = !Flags_GetInfTable(INFTABLE_145) || Flags_GetInfTable(INFTABLE_146); + break; + } case VB_FREEZE_ON_SKULL_TOKEN: case VB_TRADE_TIMER_ODD_MUSHROOM: - case VB_TRADE_TIMER_EYEDROPS: case VB_TRADE_TIMER_FROG: case VB_ANJU_SET_OBTAINED_TRADE_ITEM: case VB_GIVE_ITEM_FROM_TARGET_IN_WOODS: @@ -2107,6 +2265,7 @@ void RandomizerRegisterHooks() { static uint32_t onPlayerUpdateForRCQueueHook = 0; static uint32_t onPlayerUpdateForItemQueueHook = 0; static uint32_t onItemReceiveHook = 0; + static uint32_t onDialogMessageHook = 0; static uint32_t onVanillaBehaviorHook = 0; static uint32_t onSceneInitHook = 0; static uint32_t onActorInitHook = 0; @@ -2119,10 +2278,10 @@ void RandomizerRegisterHooks() { static uint32_t onKaleidoUpdateHook = 0; static uint32_t fishsanityOnActorInitHook = 0; - static uint32_t fishsanityOnFlagSetHook = 0; static uint32_t fishsanityOnActorUpdateHook = 0; static uint32_t fishsanityOnSceneInitHook = 0; static uint32_t fishsanityOnVanillaBehaviorHook = 0; + static uint32_t fishsanityOnItemReceiveHook = 0; GameInteractor::Instance->RegisterGameHook([](int32_t fileNum) { randomizerQueuedChecks = std::queue(); @@ -2134,6 +2293,7 @@ void RandomizerRegisterHooks() { GameInteractor::Instance->UnregisterGameHook(onPlayerUpdateForRCQueueHook); GameInteractor::Instance->UnregisterGameHook(onPlayerUpdateForItemQueueHook); GameInteractor::Instance->UnregisterGameHook(onItemReceiveHook); + GameInteractor::Instance->UnregisterGameHook(onDialogMessageHook); GameInteractor::Instance->UnregisterGameHook(onVanillaBehaviorHook); GameInteractor::Instance->UnregisterGameHook(onSceneInitHook); GameInteractor::Instance->UnregisterGameHook(onActorInitHook); @@ -2146,16 +2306,17 @@ void RandomizerRegisterHooks() { GameInteractor::Instance->UnregisterGameHook(onKaleidoUpdateHook); GameInteractor::Instance->UnregisterGameHook(fishsanityOnActorInitHook); - GameInteractor::Instance->UnregisterGameHook(fishsanityOnFlagSetHook); GameInteractor::Instance->UnregisterGameHook(fishsanityOnActorUpdateHook); GameInteractor::Instance->UnregisterGameHook(fishsanityOnSceneInitHook); GameInteractor::Instance->UnregisterGameHook(fishsanityOnVanillaBehaviorHook); + GameInteractor::Instance->UnregisterGameHook(fishsanityOnItemReceiveHook); onFlagSetHook = 0; onSceneFlagSetHook = 0; onPlayerUpdateForRCQueueHook = 0; onPlayerUpdateForItemQueueHook = 0; onItemReceiveHook = 0; + onDialogMessageHook = 0; onVanillaBehaviorHook = 0; onSceneInitHook = 0; onActorInitHook = 0; @@ -2168,10 +2329,10 @@ void RandomizerRegisterHooks() { onKaleidoUpdateHook = 0; fishsanityOnActorInitHook = 0; - fishsanityOnFlagSetHook = 0; fishsanityOnActorUpdateHook = 0; fishsanityOnSceneInitHook = 0; fishsanityOnVanillaBehaviorHook = 0; + fishsanityOnItemReceiveHook = 0; if (!IS_RANDO) return; @@ -2188,6 +2349,7 @@ void RandomizerRegisterHooks() { onPlayerUpdateForRCQueueHook = GameInteractor::Instance->RegisterGameHook(RandomizerOnPlayerUpdateForRCQueueHandler); onPlayerUpdateForItemQueueHook = GameInteractor::Instance->RegisterGameHook(RandomizerOnPlayerUpdateForItemQueueHandler); onItemReceiveHook = GameInteractor::Instance->RegisterGameHook(RandomizerOnItemReceiveHandler); + onDialogMessageHook = GameInteractor::Instance->RegisterGameHook(RandomizerOnDialogMessageHandler); onVanillaBehaviorHook = GameInteractor::Instance->RegisterGameHook(RandomizerOnVanillaBehaviorHandler); onSceneInitHook = GameInteractor::Instance->RegisterGameHook(RandomizerOnSceneInitHandler); onActorInitHook = GameInteractor::Instance->RegisterGameHook(RandomizerOnActorInitHandler); @@ -2203,10 +2365,10 @@ void RandomizerRegisterHooks() { OTRGlobals::Instance->gRandoContext->GetFishsanity()->InitializeFromSave(); fishsanityOnActorInitHook = GameInteractor::Instance->RegisterGameHook(Rando::Fishsanity::OnActorInitHandler); - fishsanityOnFlagSetHook = GameInteractor::Instance->RegisterGameHook(Rando::Fishsanity::OnFlagSetHandler); fishsanityOnActorUpdateHook = GameInteractor::Instance->RegisterGameHook(Rando::Fishsanity::OnActorUpdateHandler); fishsanityOnSceneInitHook = GameInteractor::Instance->RegisterGameHook(Rando::Fishsanity::OnSceneInitHandler); fishsanityOnVanillaBehaviorHook = GameInteractor::Instance->RegisterGameHook(Rando::Fishsanity::OnVanillaBehaviorHandler); + fishsanityOnItemReceiveHook = GameInteractor::Instance->RegisterGameHook(Rando::Fishsanity::OnItemReceiveHandler); } }); } diff --git a/soh/soh/Enhancements/randomizer/item_location.cpp b/soh/soh/Enhancements/randomizer/item_location.cpp index 6b1e3003e..9f0f84509 100644 --- a/soh/soh/Enhancements/randomizer/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/item_location.cpp @@ -176,8 +176,8 @@ void ItemLocation::SetHidden(const bool hidden_) { hidden = hidden_; } -bool ItemLocation::IsExcluded() const { - return excludedOption.Value(); +bool ItemLocation::IsExcluded() { + return excludedOption.GetContextOptionIndex(); } Option* ItemLocation::GetExcludedOption() { @@ -197,7 +197,7 @@ void ItemLocation::AddExcludeOption() { // RANDOTODO: this without string compares and loops bool alreadyAdded = false; const Location* loc = StaticData::GetLocation(rc); - for (const Option* location : Context::GetInstance()->GetSettings()->GetExcludeOptionsForArea(loc->GetArea())) { + for (Option* location : Context::GetInstance()->GetSettings()->GetExcludeOptionsForArea(loc->GetArea())) { if (location->GetName() == excludedOption.GetName()) { alreadyAdded = true; } diff --git a/soh/soh/Enhancements/randomizer/item_location.h b/soh/soh/Enhancements/randomizer/item_location.h index d49debf5f..4ec8b8b9e 100644 --- a/soh/soh/Enhancements/randomizer/item_location.h +++ b/soh/soh/Enhancements/randomizer/item_location.h @@ -45,7 +45,7 @@ class ItemLocation { const std::vector& GetHintedBy() const; void AddHintedBy(RandomizerHint hintKey); bool IsHidden() const; - bool IsExcluded() const; + bool IsExcluded(); void AddExcludeOption(); Option* GetExcludedOption(); void SetHidden(bool hidden_); diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 15271534c..da76be1d3 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -415,6 +415,38 @@ namespace Rando { bool killed = false; switch(enemy) { case RE_GOLD_SKULLTULA: + switch (distance){ + case ED_CLOSE: + //hammer jumpslash cannot damage these, but hammer swing can + killed = CanUse(RG_MEGATON_HAMMER); + [[fallthrough]]; + case ED_SHORT_JUMPSLASH: + killed = killed || CanUse(RG_KOKIRI_SWORD); + [[fallthrough]]; + case ED_MASTER_SWORD_JUMPSLASH: + killed = killed || CanUse(RG_MASTER_SWORD); + [[fallthrough]]; + case ED_LONG_JUMPSLASH: + killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS); + [[fallthrough]]; + case ED_BOMB_THROW: + killed = killed || CanUse(RG_BOMB_BAG); + [[fallthrough]]; + case ED_BOOMERANG: + killed = killed || CanUse(RG_BOOMERANG) || CanUse(RG_DINS_FIRE); + [[fallthrough]]; + case ED_HOOKSHOT: + //RANDOTODO test dins and chu range in a practical example + killed = killed || CanUse(RG_HOOKSHOT) || (wallOrFloor && CanUse(RG_BOMBCHU_5)); + [[fallthrough]]; + case ED_LONGSHOT: + killed = killed || CanUse(RG_LONGSHOT); + [[fallthrough]]; + case ED_FAR: + killed = killed || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW); + break; + } + return killed; case RE_GOHMA_LARVA: case RE_MAD_SCRUB: case RE_DEKU_BABA: @@ -618,8 +650,15 @@ namespace Rando { case RE_PURPLE_LEEVER: //dies on it's own, so this is the conditions to spawn it (killing 10 normal leevers) //Sticks and Ice arrows work but will need ammo capacity logic - //other mothods can damage them but not kill them, and they run when hit, making them impractical - return CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD); + //other methods can damage them but not kill them, and they run when hit, making them impractical + return CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD); + case RE_TENTACLE: + return CanUse(RG_BOOMERANG); + case RE_BARI: + return HookshotOrBoomerang() || CanUse(RG_FAIRY_BOW) || HasExplosives() || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_STICKS) || CanUse(RG_DINS_FIRE) || (TakeDamage() && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD))); + case RE_SHABOM: + //RANDOTODO when you add better damage logic, you can kill this by taking hits + return CanUse(RG_BOOMERANG) || CanUse(RG_NUTS) || CanJumpslash() || CanUse(RG_DINS_FIRE) || CanUse(RG_ICE_ARROWS); default: SPDLOG_ERROR("CanKillEnemy reached `default`."); assert(false); @@ -974,7 +1013,7 @@ namespace Rando { 10 for OHKO. This is the number of shifts to apply, not a real multiplier */ - uint8_t Multiplier = (ctx->GetOption(RSK_DAMAGE_MULTIPLIER).Value() < 6) ? ctx->GetOption(RSK_DAMAGE_MULTIPLIER).Value() : 10; + uint8_t Multiplier = (ctx->GetOption(RSK_DAMAGE_MULTIPLIER).GetContextOptionIndex() < 6) ? ctx->GetOption(RSK_DAMAGE_MULTIPLIER).GetContextOptionIndex() : 10; //(Hearts() << (2 + HasItem(RG_DOUBLE_DEFENSE))) is quarter hearts after DD //>> Multiplier halves on normal and does nothing on half, meaning we're working with half hearts on normal damage return ((Hearts() << (2 + HasItem(RG_DOUBLE_DEFENSE))) >> Multiplier) + @@ -1103,21 +1142,21 @@ namespace Rando { bool Logic::CanBuildRainbowBridge(){ return ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_ALWAYS_OPEN) || (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_VANILLA) && HasItem(RG_SHADOW_MEDALLION) && HasItem(RG_SPIRIT_MEDALLION) && CanUse(RG_LIGHT_ARROWS)) || - (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_STONES) && StoneCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG_REWARD)) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT).Value()) || - (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_MEDALLIONS) && MedallionCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG_REWARD)) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT).Value()) || - (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS) && StoneCount() + MedallionCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG_REWARD)) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).Value()) || - (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS) && DungeonCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG_REWARD)) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Value()) || - (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS) && GetGSCount() >= ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Value()) || + (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_STONES) && StoneCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG_REWARD)) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT).GetContextOptionIndex()) || + (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_MEDALLIONS) && MedallionCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG_REWARD)) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT).GetContextOptionIndex()) || + (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS) && StoneCount() + MedallionCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG_REWARD)) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).GetContextOptionIndex()) || + (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS) && DungeonCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG_REWARD)) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).GetContextOptionIndex()) || + (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS) && GetGSCount() >= ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).GetContextOptionIndex()) || (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG) && HasItem(RG_GREG_RUPEE)); } bool Logic::CanTriggerLACS(){ return (ctx->GetSettings()->LACSCondition() == RO_LACS_VANILLA && HasItem(RG_SHADOW_MEDALLION) && HasItem(RG_SPIRIT_MEDALLION)) || - (ctx->GetSettings()->LACSCondition() == RO_LACS_STONES && StoneCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD)) >= ctx->GetOption(RSK_LACS_STONE_COUNT).Value()) || - (ctx->GetSettings()->LACSCondition() == RO_LACS_MEDALLIONS && MedallionCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD)) >= ctx->GetOption(RSK_LACS_MEDALLION_COUNT).Value()) || - (ctx->GetSettings()->LACSCondition() == RO_LACS_REWARDS && StoneCount() + MedallionCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD)) >= ctx->GetOption(RSK_LACS_REWARD_COUNT).Value()) || - (ctx->GetSettings()->LACSCondition() == RO_LACS_DUNGEONS && DungeonCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD)) >= ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Value()) || - (ctx->GetSettings()->LACSCondition() == RO_LACS_TOKENS && GetGSCount() >= ctx->GetOption(RSK_LACS_TOKEN_COUNT).Value()); + (ctx->GetSettings()->LACSCondition() == RO_LACS_STONES && StoneCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD)) >= ctx->GetOption(RSK_LACS_STONE_COUNT).GetContextOptionIndex()) || + (ctx->GetSettings()->LACSCondition() == RO_LACS_MEDALLIONS && MedallionCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD)) >= ctx->GetOption(RSK_LACS_MEDALLION_COUNT).GetContextOptionIndex()) || + (ctx->GetSettings()->LACSCondition() == RO_LACS_REWARDS && StoneCount() + MedallionCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD)) >= ctx->GetOption(RSK_LACS_REWARD_COUNT).GetContextOptionIndex()) || + (ctx->GetSettings()->LACSCondition() == RO_LACS_DUNGEONS && DungeonCount() + (HasItem(RG_GREG_RUPEE) && ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD)) >= ctx->GetOption(RSK_LACS_DUNGEON_COUNT).GetContextOptionIndex()) || + (ctx->GetSettings()->LACSCondition() == RO_LACS_TOKENS && GetGSCount() >= ctx->GetOption(RSK_LACS_TOKEN_COUNT).GetContextOptionIndex()); } bool Logic::SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmount) { @@ -2089,7 +2128,7 @@ namespace Rando { //CanPlantBean = false; BigPoeKill = false; - BaseHearts = ctx->GetOption(RSK_STARTING_HEARTS).Value() + 1; + BaseHearts = ctx->GetOption(RSK_STARTING_HEARTS).GetContextOptionIndex() + 1; //Bridge Requirements @@ -2145,6 +2184,7 @@ namespace Rando { GTGPlatformSilverRupees = false; MQJabuHolesRoomDoor = false; JabuWestTentacle = false; + JabuEastTentacle = false; JabuNorthTentacle = false; LoweredJabuPath = false; MQJabuLiftRoomCow = false; @@ -2158,6 +2198,9 @@ namespace Rando { MQSpiritCrawlBoulder = false; MQSpiritMapRoomEnemies = false; MQSpirit3SunsEnemies = false; + Spirit1FSilverRupees = false; + JabuRutoInB1 = false; + JabuRutoIn1F = false; StopPerformanceTimer(PT_LOGIC_RESET); } diff --git a/soh/soh/Enhancements/randomizer/logic.h b/soh/soh/Enhancements/randomizer/logic.h index de800c3bb..2fafd2cc7 100644 --- a/soh/soh/Enhancements/randomizer/logic.h +++ b/soh/soh/Enhancements/randomizer/logic.h @@ -156,6 +156,7 @@ class Logic { bool GTGPlatformSilverRupees = false; bool MQJabuHolesRoomDoor = false; bool JabuWestTentacle = false; + bool JabuEastTentacle = false; bool JabuNorthTentacle = false; bool LoweredJabuPath = false; bool MQJabuLiftRoomCow = false; @@ -171,6 +172,8 @@ class Logic { bool MQSpiritTimeTravelChest = false; bool MQSpirit3SunsEnemies = false; bool Spirit1FSilverRupees = false; + bool JabuRutoInB1 = false; + bool JabuRutoIn1F = false; /* --- END OF HELPERS AND LOCATION ACCESS --- */ diff --git a/soh/soh/Enhancements/randomizer/option.cpp b/soh/soh/Enhancements/randomizer/option.cpp index af7ba150e..2729bef6e 100644 --- a/soh/soh/Enhancements/randomizer/option.cpp +++ b/soh/soh/Enhancements/randomizer/option.cpp @@ -31,10 +31,7 @@ Option Option::LogicTrick(std::string name_) { } Option::operator bool() const { - if (std::holds_alternative(var)) { - return Value(); - } - return Value() != 0; + return contextSelection != 0; } size_t Option::GetOptionCount() const { @@ -49,12 +46,16 @@ const std::string& Option::GetDescription() const { return description; } -uint8_t Option::GetSelectedOptionIndex() const { - return selectedOption; +uint8_t Option::GetMenuOptionIndex() const { + return menuSelection; +} + +uint8_t Option::GetContextOptionIndex() const { + return contextSelection; } const std::string& Option::GetSelectedOptionText() const { - return options[selectedOption]; + return options[contextSelection]; } const std::string& Option::GetCVarName() const { @@ -63,39 +64,45 @@ const std::string& Option::GetCVarName() const { void Option::SetVariable() { if (std::holds_alternative(var)) { - var.emplace(selectedOption != 0); + var.emplace(menuSelection != 0); } else { - var.emplace(selectedOption); + var.emplace(menuSelection); } } -void Option::SetCVar() const { +void Option::SaveCVar() const { if (!cvarName.empty()) { - CVarSetInteger(cvarName.c_str(), GetSelectedOptionIndex()); + CVarSetInteger(cvarName.c_str(), GetMenuOptionIndex()); } } void Option::SetFromCVar() { if (!cvarName.empty()) { - SetSelectedIndex(CVarGetInteger(cvarName.c_str(), defaultOption)); + SetMenuIndex(CVarGetInteger(cvarName.c_str(), defaultOption)); } } void Option::SetDelayedOption() { - delayedOption = selectedOption; + delayedSelection = contextSelection; } void Option::RestoreDelayedOption() { - selectedOption = delayedOption; + contextSelection = delayedSelection; +} + +void Option::SetMenuIndex(size_t idx) { + menuSelection = idx; + if (menuSelection > options.size() - 1) { + menuSelection = options.size() - 1; + } SetVariable(); } -void Option::SetSelectedIndex(size_t idx) { - selectedOption = idx; - if (selectedOption > options.size() - 1) { - selectedOption = options.size() - 1; +void Option::SetContextIndex(size_t idx) { + contextSelection = idx; + if (contextSelection > options.size() - 1) { + contextSelection = options.size() - 1; } - SetVariable(); } void Option::Hide() { @@ -111,8 +118,8 @@ bool Option::IsHidden() const { } void Option::ChangeOptions(std::vector opts) { - if (selectedOption >= opts.size()) { - selectedOption = opts.size() - 1; + if (menuSelection >= opts.size()) { + menuSelection = opts.size() - 1; } options = std::move(opts); } @@ -177,7 +184,7 @@ Option::Option(uint8_t var_, std::string name_, std::vector options : var(var_), name(std::move(name_)), options(std::move(options_)), category(category_), cvarName(std::move(cvarName_)), description(std::move(description_)), widgetType(widgetType_), defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) { - selectedOption = defaultOption; + menuSelection = contextSelection = defaultOption; hidden = defaultHidden; SetFromCVar(); } @@ -187,7 +194,7 @@ Option::Option(bool var_, std::string name_, std::vector options_, : var(var_), name(std::move(name_)), options(std::move(options_)), category(category_), cvarName(std::move(cvarName_)), description(std::move(description_)), widgetType(widgetType_), defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) { - selectedOption = defaultOption; + menuSelection = contextSelection = defaultOption; hidden = defaultHidden; SetFromCVar(); } @@ -270,7 +277,7 @@ bool Option::RenderCombobox() { bool Option::RenderSlider() { bool changed = false; - int val = GetSelectedOptionIndex(); + int val = GetMenuOptionIndex(); if (val > options.size() - 1) { val = options.size() - 1; CVarSetInteger(cvarName.c_str(), val); diff --git a/soh/soh/Enhancements/randomizer/option.h b/soh/soh/Enhancements/randomizer/option.h index 1bb979ebc..5b7eb5b9d 100644 --- a/soh/soh/Enhancements/randomizer/option.h +++ b/soh/soh/Enhancements/randomizer/option.h @@ -126,42 +126,25 @@ class Option { */ static Option LogicTrick(std::string name_); - /** - * @brief Gets the selected index or boolean value of the Option. - * - * @tparam T uint8_t or bool, depending on how the option was constructed. - * @return T - */ - template T Value() const { - return std::get(var); - } - /** * @brief Determines if the value/selected index of this Option matches the provided value. * - * @tparam T uint8_t, bool, or an enum (which will be cast to uint8_t). * @param other The value to compare. * @return true * @return false */ - template bool Is(T other) const { - static_assert(std::is_integral_v || std::is_enum_v, "T must be an integral type or an enum."); - if constexpr ((std::is_integral_v && !std::is_same_v) || std::is_enum_v) { - return Value() == static_cast(other); - } else { - return Value() == static_cast(other); - } + bool Is(uint32_t other) const { + return contextSelection == other; } /** * @brief Determines if the value/selected index of this Option does not match the provided value. * - * @tparam T uint8_t, book, or an enum (which will be cast to uint8_t). * @param other The value to compare. * @return true * @return false */ - template bool IsNot(T other) const { + bool IsNot(uint32_t other) const { return !Is(other); } @@ -203,11 +186,18 @@ class Option { const std::string& GetCVarName() const; /** - * @brief Get the selected index for this Option. + * @brief Get the menu index for this Option. * * @return uint8_t */ - uint8_t GetSelectedOptionIndex() const; + uint8_t GetMenuOptionIndex() const; + + /** + * @brief Get the rando context index for this Option. + * + * @return uint8_t + */ + uint8_t GetContextOptionIndex() const; /** * @brief Sets the variable to the currently selected index for this Option. @@ -218,7 +208,7 @@ class Option { * @brief Sets the CVar corresponding to the property `cvarName` equal to the value * of the property `selectedValue`. */ - void SetCVar() const; + void SaveCVar() const; /** * @brief Sets the value of property `selectedValue` equal to the CVar corresponding @@ -237,11 +227,18 @@ class Option { void RestoreDelayedOption(); /** - * @brief Set the selected index for this Option. Also calls `SetVariable()`. + * @brief Set the menu index for this Option. Also calls `SetVariable()`. * * @param idx the index to set as the selected index. */ - void SetSelectedIndex(size_t idx); + void SetMenuIndex(size_t idx); + + /** + * @brief Set the rando context index for this Option. Also calls `SetVariable()`. + * + * @param idx the index to set as the selected index. + */ + void SetContextIndex(size_t idx); /** * @brief Hides this Option in the menu. (Not currently being used afaik, we prefer to @@ -324,8 +321,9 @@ protected: std::variant var; std::string name; std::vector options; - uint8_t selectedOption = 0; - uint8_t delayedOption = 0; + uint8_t menuSelection = 0; + uint8_t contextSelection = 0; + uint8_t delayedSelection = 0; bool hidden = false; OptionCategory category = OptionCategory::Setting; std::string cvarName; diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index bd3f5dd77..9446f859a 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -2,30 +2,30 @@ namespace Rando { void Settings::CreateOptionDescriptions() { - mOptionDescriptions[RSK_FOREST] = "Closed - Kokiri sword & shield are required to access " + mOptionDescriptions[RSK_FOREST] = "Closed - Kokiri Sword & Deku Shield are required to access " "the Deku Tree, and completing the Deku Tree is required to " "access the Hyrule Field exit.\n" "\n" "Closed Deku - Kokiri boy no longer blocks the path to Hyrule " - "Field but Mido still requires the Kokiri sword and Deku shield " + "Field but Mido still requires the Kokiri Sword and Deku Shield " "to access the tree.\n" "\n" "Open - Mido no longer blocks the path to the Deku Tree. Kokiri " "boy no longer blocks the path out of the forest."; - mOptionDescriptions[RSK_KAK_GATE] = "Closed - The gate will remain closed until Zelda's letter " + mOptionDescriptions[RSK_KAK_GATE] = "Closed - The gate will remain closed until Zelda's Letter " "is shown to the guard.\n" "\n" - "Open - The gate is always open. The happy mask shop " - "will open immediately after obtaining Zelda's letter."; + "Open - The gate is always open. The Happy Mask Shop " + "will open immediately after obtaining Zelda's Letter."; mOptionDescriptions[RSK_DOOR_OF_TIME] = "Closed - The Ocarina of Time, the Song of Time and all " - "three spiritual stones are required to open the Door of Time.\n" + "three Spiritual Stones are required to open the Door of Time.\n" "\n" "Song only - Play the Song of Time in front of the Door of " "Time to open it.\n" "\n" "Open - The Door of Time is permanently open with no requirements."; mOptionDescriptions[RSK_ZORAS_FOUNTAIN] = "Closed - King Zora obstructs the way to Zora's Fountain. " - "Ruto's letter must be shown as child Link in order to move " + "Ruto's Letter must be shown as child Link in order to move " "him in both time periods.\n" "\n" "Closed as child - Ruto's Letter is only required to move King Zora " @@ -33,6 +33,12 @@ void Settings::CreateOptionDescriptions() { "\n" "Open - King Zora has already mweeped out of the way in both " "time periods. Ruto's Letter is removed from the item pool."; + mOptionDescriptions[RSK_SLEEPING_WATERFALL] = "Closed - Sleeping Waterfall obstructs the entrance to Zora's " + "Domain. Zelda's Lullaby must be played in order to open it " + "(but only once; then it stays open in both time periods).\n" + "\n" + "Open - Sleeping Waterfall is always open. " + "Link may always enter Zora's Domain."; mOptionDescriptions[RSK_STARTING_AGE] = "Choose which age Link will start as.\n\n" "Starting as adult means you start with the Master Sword in your inventory.\n" @@ -54,12 +60,12 @@ void Settings::CreateOptionDescriptions() { "\n" "Always open - No requirements.\n" "\n" - "Stones - Obtain the specified amount of spiritual stones.\n" + "Stones - Obtain the specified amount of Spiritual Stones.\n" "\n" "Medallions - Obtain the specified amount of medallions.\n" "\n" - "Dungeon rewards - Obtain the specified total sum of spiritual " - "stones or medallions.\n" + "Dungeon rewards - Obtain the specified total sum of Spiritual " + "Stones or medallions.\n" "\n" "Dungeons - Complete the specified amount of dungeons. Dungeons " "are considered complete after stepping in to the blue warp after " @@ -83,10 +89,10 @@ void Settings::CreateOptionDescriptions() { "\n" "Skip - No Trials are required and the barrier is already dispelled.\n" "\n" - "Set Number - Select a number of trials that will be required from the" + "Set Number - Select a number of trials that will be required from the " "slider below. Which specific trials you need to complete will be random.\n" "\n" - "Random Number - A Random number and set of trials will be required."; + "Random Number - A random number and set of trials will be required."; mOptionDescriptions[RSK_TRIAL_COUNT] = "Set the number of trials required to enter Ganon's Tower."; mOptionDescriptions[RSK_MQ_DUNGEON_RANDOM] = "Sets the number of Master Quest Dungeons that are shuffled into the pool.\n" @@ -96,7 +102,7 @@ void Settings::CreateOptionDescriptions() { "Set Number - Select a number of dungeons that will be their Master Quest versions " "using the slider below. Which dungeons are set to be the Master Quest variety will be random.\n" "\n" - "Random Number - A Random number and set of dungeons will be their Master Quest varieties.\n" + "Random Number - A random number and set of dungeons will be their Master Quest varieties.\n" "\n" "Selection Only - Specify which dungeons are Vanilla, Master Quest or a 50/50 between the two.\n" "Differs from Random Number in that they are rolled individually, making the exact total a bell curve."; @@ -118,14 +124,14 @@ void Settings::CreateOptionDescriptions() { "Keep in mind seed generation can fail if more ornaments are placed than there are junk items in the item pool."; mOptionDescriptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED] = "The amount of Ornaments required to win the game."; mOptionDescriptions[RSK_SHUFFLE_DUNGEON_ENTRANCES] = - "Shuffle the pool of dungeon entrances, including Bottom of the Well, Ice Cavern and Gerudo Training Grounds.\n" + "Shuffle the pool of dungeon entrances, including Bottom of the Well, Ice Cavern and Gerudo Training Ground.\n" "\n" "Shuffling Ganon's Castle can be enabled separately.\n" "\n" "Additionally, the entrances of Deku Tree, Fire Temple, Bottom of the Well and Gerudo Training Ground are " "opened for both child and adult.\n" "\n" - "- Deku Tree will be open for adult after Mido has seen child Link with a sword and shield.\n" + "- Deku Tree will be open for adult after Mido has seen child Link with a sword and a shield.\n" "- Bottom of the Well will be open for adult after playing Song of Storms to the Windmill guy as child.\n" "- Gerudo Training Ground will be open for child after adult has paid to open the gate once."; mOptionDescriptions[RSK_SHUFFLE_BOSS_ENTRANCES] = @@ -171,23 +177,23 @@ void Settings::CreateOptionDescriptions() { "This also adds the one-way entrance from Gerudo Valley to Lake Hylia in the pool of " "overworld entrances when they are shuffled."; mOptionDescriptions[RSK_MIXED_ENTRANCE_POOLS] = - "Shuffle entrances into a mixed pool instead of separate ones. Has no affect on pools whose " + "Shuffle entrances into a mixed pool instead of separate ones. Has no effect on pools whose " "entrances aren't shuffled, and \"Shuffle Boss Entrances\" must be set to \"Full\" to include them.\n" "\n" "For example, enabling the settings to shuffle grotto, dungeon, and overworld entrances and " "selecting grotto and dungeon entrances here will allow a dungeon to be inside a grotto or " "vice versa, while overworld entrances are shuffled in their own separate pool and indoors stay vanilla."; - mOptionDescriptions[RSK_MIX_DUNGEON_ENTRANCES] = "Dungeon entrances will be part of the mixed pool"; - mOptionDescriptions[RSK_MIX_BOSS_ENTRANCES] = "Boss entrances will be part of the mixed pool"; - mOptionDescriptions[RSK_MIX_OVERWORLD_ENTRANCES] = "Overworld entrances will be part of the mixed pool"; - mOptionDescriptions[RSK_MIX_INTERIOR_ENTRANCES] = "Interior entrances will be part of the mixed pool"; - mOptionDescriptions[RSK_MIX_GROTTO_ENTRANCES] = "Grotto entrances will be part of the mixed pool"; + mOptionDescriptions[RSK_MIX_DUNGEON_ENTRANCES] = "Dungeon entrances will be part of the mixed pool."; + mOptionDescriptions[RSK_MIX_BOSS_ENTRANCES] = "Boss entrances will be part of the mixed pool."; + mOptionDescriptions[RSK_MIX_OVERWORLD_ENTRANCES] = "Overworld entrances will be part of the mixed pool."; + mOptionDescriptions[RSK_MIX_INTERIOR_ENTRANCES] = "Interior entrances will be part of the mixed pool."; + mOptionDescriptions[RSK_MIX_GROTTO_ENTRANCES] = "Grotto entrances will be part of the mixed pool."; mOptionDescriptions[RSK_SHUFFLE_SONGS] = "Song locations - Songs will only appear at locations that normally teach songs.\n" "\n" "Dungeon rewards - Songs appear after beating a major dungeon boss.\n" "The 4 remaining songs are located at:\n" - " - Zelda's lullaby location\n" + " - Zelda's Lullaby location\n" " - Ice Cavern's Serenade of Water location\n" " - Bottom of the Well Lens of Truth location\n" " - Gerudo Training Ground's Ice Arrows location\n" @@ -240,33 +246,33 @@ void Settings::CreateOptionDescriptions() { "\n" "The Weird Egg is required to unlock several events:\n" " - Zelda's Lullaby from Impa\n" - " - Saria's song in Sacred Forest Meadow\n" - " - Epona's song and chicken minigame at Lon Lon Ranch\n" - " - Zelda's letter for Kakariko gate (if set to closed)\n" + " - Saria's Song in Sacred Forest Meadow\n" + " - Epona's Song and chicken minigame at Lon Lon Ranch\n" + " - Zelda's Letter for Kakariko gate (if set to closed)\n" " - Happy Mask Shop sidequest\n"; mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD] = "Shuffles the Gerudo Membership Card into the item pool.\n" "\n" - "The Gerudo Card is required to enter the Gerudo Training Grounds, opening " + "The Gerudo Card is required to enter the Gerudo Training Ground, opening " "the gate to Haunted Wasteland and the Horseback Archery minigame."; mOptionDescriptions[RSK_SHUFFLE_FISHING_POLE] = "Shuffles the fishing pole into the item pool.\n" "\n" "The fishing pole is required to play the fishing pond minigame."; - mOptionDescriptions[RSK_INFINITE_UPGRADES] = "Adds upgrades that hold infinite quanities of items (bombs, arrows, etc.)\n" + mOptionDescriptions[RSK_INFINITE_UPGRADES] = "Adds upgrades that hold infinite quantities of items (bombs, arrows, etc.).\n" "\n" - "Progressive - The infinite upgrades are obtained after getting the last normal capacity upgrade\n" + "Progressive - The infinite upgrades are obtained after getting the last normal capacity upgrade.\n" "\n" - "Condensed Progressive - The infinite upgrades are obtained as the first capacity upgrade (doesn't apply to the infinite wallet or to infinite magic)"; - mOptionDescriptions[RSK_SHUFFLE_DEKU_STICK_BAG] = "Shuffles the deku stick bag into the item pool.\n" + "Condensed Progressive - The infinite upgrades are obtained as the first capacity upgrade (doesn't apply to the infinite wallet or to infinite magic)."; + mOptionDescriptions[RSK_SHUFFLE_DEKU_STICK_BAG] = "Shuffles the Deku Stick bag into the item pool.\n" "\n" - "The deku stick bag is required to hold deku sticks."; - mOptionDescriptions[RSK_SHUFFLE_DEKU_NUT_BAG] = "Shuffles the deku nut bag into the item pool.\n" + "The Deku Stick bag is required to hold Deku Sticks."; + mOptionDescriptions[RSK_SHUFFLE_DEKU_NUT_BAG] = "Shuffles the Deku Nut bag into the item pool.\n" "\n" - "The deku nut bag is required to hold deku nuts."; + "The Deku Nut bag is required to hold Deku Nuts."; mOptionDescriptions[RSK_SHOPSANITY] = "Off - All shop items will be the same as vanilla.\n" "\n" - "Specifc Count - Vanilla shop items will be shuffled among different shops, and " - "each shop will contain a specifc number (0-7) of non-vanilla shop items.\n" + "Specific Count - Vanilla shop items will be shuffled among different shops, and " + "each shop will contain a specific number (0-7) of non-vanilla shop items.\n" "\n" "Random - Vanilla shop items will be shuffled among different shops, and " "each shop will contain a random number (1-7) of non-vanilla shop items."; @@ -279,12 +285,12 @@ void Settings::CreateOptionDescriptions() { "8 Items - All shops will contain 8 non-vanilla shop items.\n" */; mOptionDescriptions[RSK_SHOPSANITY_PRICES] = - "Vanilla - The same price as the item it replaced\n" - "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers\n" - "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers\n" - "Fixed - A fixed number\n" - "Range - A random point between specific ranges\n" - "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen"; + "Vanilla - The same price as the item it replaced.\n" + "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers.\n" + "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers.\n" + "Fixed - A fixed number.\n" + "Range - A random point between specific ranges.\n" + "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen."; mOptionDescriptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE] = "The price for Shopsanity checks."; mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_1] = @@ -300,13 +306,13 @@ void Settings::CreateOptionDescriptions() { mOptionDescriptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT] = "The chance for Shopsanity checks to be purchasable with Giant's Wallet (201-500)."; mOptionDescriptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT] = - "The chance for Shopsanity checks to be purchasable with Tycoon Wallet. (500+)"; + "The chance for Shopsanity checks to be purchasable with Tycoon Wallet (500+)."; mOptionDescriptions[RSK_SHOPSANITY_PRICES_AFFORDABLE] = "After choosing a price, set it to the affordable amount based on the wallet required.\n\n" "Affordable prices per tier: starter = 1, adult = 100, giant = 201, tycoon = 501\n\n" "Use this to enable wallet tier locking, but make shop items not as expensive as they could be."; mOptionDescriptions[RSK_FISHSANITY] = "Off - Fish will not be shuffled. No changes will be made to fishing behavior.\n\n" - "Shuffle only Hyrule Loach - Allows you to earn an item by catching the hyrule loach at the fishing pond and giving it to the owner.\n\n" + "Shuffle only Hyrule Loach - Allows you to earn an item by catching the Hyrule Loach at the fishing pond and giving it to the owner.\n\n" "Shuffle Fishing Pond - The fishing pond's fish will be shuffled. Catching a fish in the fishing pond will grant a reward.\n\n" "Shuffle Overworld Fish - Fish in generic grottos and Zora's Domain will be shuffled. Catching a fish in a bottle will give a reward.\n\n" "Shuffle Both - Both overworld fish and fish in the fishing pond will be shuffled."; @@ -326,12 +332,12 @@ void Settings::CreateOptionDescriptions() { "\n" "All - All Scrubs are shuffled."; mOptionDescriptions[RSK_SCRUBS_PRICES] = - "Vanilla - The same price as the item it replaced\n" - "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers\n" - "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers\n" - "Fixed - A fixed number\n" - "Range - A random point between specific ranges\n" - "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen"; + "Vanilla - The same price as the item it replaced.\n" + "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers.\n" + "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers.\n" + "Fixed - A fixed number.\n" + "Range - A random point between specific ranges.\n" + "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen."; mOptionDescriptions[RSK_SCRUBS_PRICES_FIXED_PRICE] = "The price for Scrub checks."; mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_1] = @@ -347,7 +353,7 @@ void Settings::CreateOptionDescriptions() { mOptionDescriptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT] = "The chance for Scrub checks to be purchasable with Giant's Wallet (201-500)."; mOptionDescriptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT] = - "The chance for Scrub checks to be purchasable with Tycoon Wallet. (500+)"; + "The chance for Scrub checks to be purchasable with Tycoon Wallet (500+)."; mOptionDescriptions[RSK_SCRUBS_PRICES_AFFORDABLE] = "After choosing a price, set it to the affordable amount based on the wallet required.\n\n" "Affordable prices per tier: starter = 1, adult = 100, giant = 201, tycoon = 501\n\n" @@ -360,7 +366,7 @@ void Settings::CreateOptionDescriptions() { "This setting governs if the Bean Salesman, Medigoron, Granny and the Carpet Salesman " "sell a random item.\n" "Beans Only - Only the Bean Salesman will have a check, and a pack of Magic Beans will be added " - " to the item pool." + "to the item pool." "All But Beans - Medigoron, Granny and the Carpet Salesman will have checks, " "A Giant's Knife and a pack of Bombchus will be added to the item pool, and " "one of the bottles will contain a Blue Potion.\n\n" @@ -370,12 +376,12 @@ void Settings::CreateOptionDescriptions() { "Otherwise when off, you will need to have found the Claim Check to buy her item (simulating the trade quest " "is complete)."; mOptionDescriptions[RSK_MERCHANT_PRICES] = - "Vanilla - The same price as the Check in vanilla, 60 for the Bean Salesman\n" - "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers\n" - "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers\n" - "Fixed - A fixed number\n" - "Range - A random point between specific ranges\n" - "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen"; + "Vanilla - The same price as the Check in vanilla, 60 for the Bean Salesman.\n" + "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers.\n" + "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers.\n" + "Fixed - A fixed number.\n" + "Range - A random point between specific ranges.\n" + "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen."; mOptionDescriptions[RSK_MERCHANT_PRICES_FIXED_PRICE] = "The price for Merchant checks."; mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_1] = @@ -391,7 +397,7 @@ void Settings::CreateOptionDescriptions() { mOptionDescriptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT] = "The chance for Merchant checks to be purchasable with Giant's Wallet (201-500)."; mOptionDescriptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT] = - "The chance for Merchant checks to be purchasable with Tycoon Wallet. (500+)"; + "The chance for Merchant checks to be purchasable with Tycoon Wallet (500+)."; mOptionDescriptions[RSK_MERCHANT_PRICES_AFFORDABLE] = "After choosing a price, set it to the affordable amount based on the wallet required.\n\n" "Affordable prices per tier: starter = 1, adult = 100, giant = 201, tycoon = 501\n\n" @@ -416,16 +422,16 @@ void Settings::CreateOptionDescriptions() { "\n" "You can still talk to him multiple times to get Huge Rupees."; mOptionDescriptions[RSK_SHUFFLE_DUNGEON_REWARDS] = - "Shuffles the location of spiritual stones and medallions.\n" + "Shuffles the location of Spiritual Stones and medallions.\n" "\n" - "End of dungeons - Spiritual stones and medallions will be given as rewards " + "End of dungeons - Spiritual Stones and medallions will be given as rewards " "for beating major dungeons. Link will always start with one stone or medallion.\n" "\n" - "Any dungeon - Spiritual stones and medallions can be found inside any dungeon.\n" + "Any dungeon - Spiritual Stones and medallions can be found inside any dungeon.\n" "\n" - "Overworld - Spiritual stones and medallions can only be found outside of dungeons.\n" + "Overworld - Spiritual Stones and medallions can only be found outside of dungeons.\n" "\n" - "Anywhere - Spiritual stones and medallions can appear anywhere."; + "Anywhere - Spiritual Stones and medallions can appear anywhere."; mOptionDescriptions[RSK_SHUFFLE_MAPANDCOMPASS] = "Start with - You will start with Maps & Compasses from all dungeons.\n" "\n" @@ -433,7 +439,7 @@ void Settings::CreateOptionDescriptions() { "\n" "Own dungeon - Maps & Compasses can only appear in their respective dungeon.\n" "\n" - "Any dungeon - Maps & Compasses can only appear inside of any dungon.\n" + "Any dungeon - Maps & Compasses can only appear inside of any dungeon.\n" "\n" "Overworld - Maps & Compasses can only appear outside of dungeons.\n" "\n" @@ -447,18 +453,18 @@ void Settings::CreateOptionDescriptions() { "Own dungeon - Small Keys can only appear in their respective dungeon. " "If Fire Temple is not a Master Quest dungeon, the door to the Boss Key chest will be unlocked.\n" "\n" - "Any dungeon - Small Keys can only appear inside of any dungon.\n" + "Any dungeon - Small Keys can only appear inside of any dungeon.\n" "\n" "Overworld - Small Keys can only appear outside of dungeons.\n" "\n" "Anywhere - Small Keys can appear anywhere in the world."; mOptionDescriptions[RSK_KEYRINGS] = "Keyrings will replace all small keys from a particular dungeon with a single keyring that awards all keys for " - "it's associated dungeon\n" + "its associated dungeon.\n" "\n" "Off - No dungeons will have their keys replaced with keyrings.\n" "\n" - "Random - A random amount of dungeons(0-8 or 9) will have their keys replaced with keyrings.\n" + "Random - A random amount of dungeons (0-8 or 9) will have their keys replaced with keyrings.\n" "\n" "Count - A specified amount of randomly selected dungeons will have their keys replaced with keyrings.\n" "\n" @@ -470,20 +476,20 @@ void Settings::CreateOptionDescriptions() { "If Gerudo Fortress Carpenters is set to Normal, and Gerudo Fortress Keys is set to anything " "other than Vanilla, then the maximum amount of Key Rings that can be selected by Random or " "Count will be 9. Otherwise, the maximum amount of Key Rings will be 8."; - mOptionDescriptions[RSK_GERUDO_KEYS] = "Vanilla - Thieve's Hideout Keys will appear in their vanilla locations.\n" + mOptionDescriptions[RSK_GERUDO_KEYS] = "Vanilla - Thieves' Hideout Keys will appear in their vanilla locations.\n" "\n" - "Any dungeon - Thieve's Hideout Keys can only appear inside of any dungon.\n" + "Any dungeon - Thieves' Hideout Keys can only appear inside of any dungon.\n" "\n" - "Overworld - Thieve's Hideout Keys can only appear outside of dungeons.\n" + "Overworld - Thieves' Hideout Keys can only appear outside of dungeons.\n" "\n" - "Anywhere - Thieve's Hideout Keys can appear anywhere in the world."; + "Anywhere - Thieves' Hideout Keys can appear anywhere in the world."; mOptionDescriptions[RSK_BOSS_KEYSANITY] = "Start with - You will start with Boss keys from all dungeons.\n" "\n" "Vanilla - Boss Keys will appear in their vanilla locations.\n" "\n" "Own dungeon - Boss Keys can only appear in their respective dungeon.\n" "\n" - "Any dungeon - Boss Keys can only appear inside of any dungon.\n" + "Any dungeon - Boss Keys can only appear inside of any dungeon.\n" "\n" "Overworld - Boss Keys can only appear outside of dungeons.\n" "\n" @@ -495,7 +501,7 @@ void Settings::CreateOptionDescriptions() { "\n" "Start with - Places Ganon's Boss Key in your starting inventory." "\n" - "Any dungeon - Ganon's Boss Key Key can only appear inside of any dungon.\n" + "Any dungeon - Ganon's Boss Key Key can only appear inside of any dungeon.\n" "\n" "Overworld - Ganon's Boss Key Key can only appear outside of dungeons.\n" "\n" @@ -504,9 +510,9 @@ void Settings::CreateOptionDescriptions() { "LACS - These settings put the boss key on the Light Arrow Cutscene location, from Zelda in Temple of Time as " "adult, with differing requirements:\n" "- Vanilla: Obtain the Shadow Medallion and Spirit Medallion\n" - "- Stones: Obtain the specified amount of spiritual stones.\n" + "- Stones: Obtain the specified amount of Spiritual Stones.\n" "- Medallions: Obtain the specified amount of medallions.\n" - "- Dungeon rewards: Obtain the specified total sum of spiritual stones or medallions.\n" + "- Dungeon rewards: Obtain the specified total sum of Spiritual Stones or medallions.\n" "- Dungeons: Complete the specified amount of dungeons. Dungeons are considered complete after stepping in to " "the blue warp after the boss.\n" "- Tokens: Obtain the specified amount of Skulltula tokens.\n" @@ -523,7 +529,7 @@ void Settings::CreateOptionDescriptions() { "\n" "Greg as Wildcard - Greg does not change logic, Greg helps obtain GBK, max number of " "rewards on slider does not change."; - mOptionDescriptions[RSK_CUCCO_COUNT] = "The amount of cuccos needed to claim the reward from Anju the cucco lady"; + mOptionDescriptions[RSK_CUCCO_COUNT] = "The amount of cuccos needed to claim the reward from Anju the Cucco Lady."; mOptionDescriptions[RSK_BIG_POE_COUNT] = "The Poe collector will give a reward for turning in this many Big Poes."; mOptionDescriptions[RSK_SKIP_CHILD_STEALTH] = "The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards."; @@ -532,11 +538,11 @@ void Settings::CreateOptionDescriptions() { "until after meeting Zelda. Disables the ability to shuffle Weird Egg."; mOptionDescriptions[RSK_SKIP_EPONA_RACE] = "Epona can be summoned with Epona's Song without needing to race Ingo."; mOptionDescriptions[RSK_COMPLETE_MASK_QUEST] = - "Once the happy mask shop is opened, all masks will be available to be borrowed."; + "Once the Happy Mask Shop is opened, all masks will be available to be borrowed."; mOptionDescriptions[RSK_SKIP_SCARECROWS_SONG] = - "Start with the ability to summon Pierre the scarecrow. Pulling out an ocarina in the usual locations will " + "Start with the ability to summon Pierre the Scarecrow. Pulling out an Ocarina in the usual locations will " "automatically summon him.\n" - "With \"Shuffle Ocarina Buttons\" enabled, you'll need at least two ocarina buttons to summon him."; + "With \"Shuffle Ocarina Buttons\" enabled, you'll need at least two Ocarina buttons to summon him."; mOptionDescriptions[RSK_ITEM_POOL] = "Sets how many major items appear in the item pool.\n" "\n" "Plentiful - Extra major items are added to the pool.\n" @@ -592,12 +598,12 @@ void Settings::CreateOptionDescriptions() { "Very Strong - Many powerful hints."; mOptionDescriptions[RSK_TOT_ALTAR_HINT] = "Reading the Temple of Time altar as child will tell you the locations of the Spiritual Stones.\n" - "Reading the Temple of Time altar as adult will tell you the locations of the Medallions, as well as the " + "Reading the Temple of Time altar as adult will tell you the locations of the medallions, as well as the " "conditions for building the Rainbow Bridge and getting the Boss Key for Ganon's Castle."; mOptionDescriptions[RSK_GANONDORF_HINT] = "Talking to Ganondorf in his boss room will tell you the location of the Light Arrows and Master Sword." "If this option is enabled and Ganondorf is reachable without these items, Gossip Stones will never hint the " - "appropriote items.";//RANDOTODO make this hint text about no dupe hints a global hint for static hints. Add to navi? + "appropriate items.";//RANDOTODO make this hint text about no dupe hints a global hint for static hints. Add to navi? mOptionDescriptions[RSK_SHEIK_LA_HINT] = "Talking to Sheik inside Ganon's Castle will tell you the location of the Light Arrows." "If this option is enabled and Sheik is reachable without Light Arrows, Gossip Stones will never hint the " @@ -613,37 +619,37 @@ void Settings::CreateOptionDescriptions() { mOptionDescriptions[RSK_FISHING_POLE_HINT] = "Talking to the fishing pond owner without the fishing pole will tell you its location."; mOptionDescriptions[RSK_OOT_HINT] = "Sheik in the Temple of Time will tell you the item and song on the Ocarina of Time."; mOptionDescriptions[RSK_FROGS_HINT] = "Standing near the pedestal for the frogs in Zora's River will tell you the " - "reward for the frogs' ocarina game."; + "reward for the frogs' Ocarina game."; mOptionDescriptions[RSK_BIGGORON_HINT] = "Talking to Biggoron will tell you the item he will give you in exchange for the Claim Check."; mOptionDescriptions[RSK_BIG_POES_HINT] = "Talking to the Poe Collector in the Market Guardhouse while adult will tell you what you receive for handing in Big Poes."; - mOptionDescriptions[RSK_CHICKENS_HINT] = "Talking to Anju as a child will tell you the item she will give you for delivering her Cuccos to the pen"; - mOptionDescriptions[RSK_MALON_HINT] = "Talking to Malon as adult will tell you the item on \"Link's cow\", the cow you win from beating her time on the Lon Lon Obsticle Course."; + mOptionDescriptions[RSK_CHICKENS_HINT] = "Talking to Anju as a child will tell you the item she will give you for delivering her cuccos to the pen."; + mOptionDescriptions[RSK_MALON_HINT] = "Talking to Malon as adult will tell you the item on \"Link's cow\", the cow you win from beating her time on the Lon Lon Obstacle Course."; mOptionDescriptions[RSK_HBA_HINT] = "Talking to the Horseback Archery gerudo in Gerudo Fortress, or the nearby sign, will tell you what you win for scoring 1000 and 1500 points on Horseback Archery."; mOptionDescriptions[RSK_WARP_SONG_HINTS] = "Playing a warp song will tell you where it leads. (If warp song destinations are vanilla, this is always enabled.)"; mOptionDescriptions[RSK_SCRUB_TEXT_HINT] = "Business scrubs will reveal the identity of what they're selling."; mOptionDescriptions[RSK_MERCHANT_TEXT_HINT] = "Merchants will reveal the identity of what they're selling (Shops are not affected by this setting)."; - mOptionDescriptions[RSK_KAK_10_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 10 tokens will tell you the reward"; - mOptionDescriptions[RSK_KAK_20_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 20 tokens will tell you the reward"; - mOptionDescriptions[RSK_KAK_30_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 30 tokens will tell you the reward"; - mOptionDescriptions[RSK_KAK_40_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 40 tokens will tell you the reward"; - mOptionDescriptions[RSK_KAK_50_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 50 tokens will tell you the reward"; - mOptionDescriptions[RSK_KAK_100_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 100 tokens will tell you the reward"; + mOptionDescriptions[RSK_KAK_10_SKULLS_HINT] = "Talking to the Cursed Resident in the Skulltula House who is saved after 10 tokens will tell you the reward."; + mOptionDescriptions[RSK_KAK_20_SKULLS_HINT] = "Talking to the Cursed Resident in the Skulltula House who is saved after 20 tokens will tell you the reward."; + mOptionDescriptions[RSK_KAK_30_SKULLS_HINT] = "Talking to the Cursed Resident in the Skulltula House who is saved after 30 tokens will tell you the reward."; + mOptionDescriptions[RSK_KAK_40_SKULLS_HINT] = "Talking to the Cursed Resident in the Skulltula House who is saved after 40 tokens will tell you the reward."; + mOptionDescriptions[RSK_KAK_50_SKULLS_HINT] = "Talking to the Cursed Resident in the Skulltula House who is saved after 50 tokens will tell you the reward."; + mOptionDescriptions[RSK_KAK_100_SKULLS_HINT] = "Talking to the Cursed Resident in the Skulltula House who is saved after 100 tokens will tell you the reward."; mOptionDescriptions[RSK_MASK_SHOP_HINT] = "Reading the mask shop sign will tell you rewards from showing masks at the Deku Theatre."; mOptionDescriptions[RSK_FULL_WALLETS] = "Start with a full wallet. All wallet upgrades come filled with rupees."; mOptionDescriptions[RSK_BOMBCHUS_IN_LOGIC] = - "Bombchus are properly considered in logic. Without this setting, any Bombchu requirement" - " is filled by Bomb Bag + a renewable source of Bombchus\n" + "Bombchus are properly considered in logic. Without this setting, any Bombchu requirement " + "is filled by Bomb Bag + a renewable source of Bombchus.\n" "\n" "The first Bombchu pack will always be 20, and subsequent packs will be " "5 or 10 based on how many you have.\n" "Once found, they can be replenished at the Bombchu shop.\n" "\n" "Bombchu Bowling is opened by obtaining Bombchus."; - mOptionDescriptions[RSK_ENABLE_BOMBCHU_DROPS] = "Once you obtain bombchus for the first time, refills can be found " + mOptionDescriptions[RSK_ENABLE_BOMBCHU_DROPS] = "Once you obtain Bombchus for the first time, refills can be found " "in bushes and other places where bomb drops can normally spawn." "\n" - "If you have Bombchus in Logic disabled, you will also need a" - "Bomb bag for bombchus to drop"; + "If you have Bombchus in Logic disabled, you will also need a " + "Bomb Bag for Bombchus to drop."; mOptionDescriptions[RSK_BLUE_FIRE_ARROWS] = "Ice Arrows act like Blue Fire, making them able to melt red ice. " "Item placement logic will respect this option, so it might be required to use this to progress."; @@ -671,4 +677,4 @@ void Settings::CreateOptionDescriptions() { mOptionDescriptions[RSK_SHUFFLE_BOSS_SOULS] = "Shuffles 8 boss souls (one for each blue warp dungeon). A boss will not appear until you collect its respective soul." "\n\"On + Ganon\" will also hide Ganon and Ganondorf behind a boss soul."; } -} // namespace Rando \ No newline at end of file +} // namespace Rando diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 2255f7b97..49285f82c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1270,7 +1270,7 @@ FishIdentity Randomizer::IdentifyFish(s32 sceneNum, s32 actorParams) { } u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { - return Rando::Context::GetInstance()->GetOption(randoSettingKey).GetSelectedOptionIndex(); + return Rando::Context::GetInstance()->GetOption(randoSettingKey).GetContextOptionIndex(); } GetItemEntry Randomizer::GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogItemId, bool checkObtainability) { diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index fe8910c6d..70a8e19d6 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -568,19 +568,14 @@ typedef enum { RR_DODONGOS_CAVERN_BOSS_ROOM, RR_JABU_JABUS_BELLY_BEGINNING, - RR_JABU_JABUS_BELLY_LIFT_MIDDLE, - RR_JABU_JABUS_BELLY_MAIN_UPPER, - RR_JABU_JABUS_BELLY_MAIN_LOWER, - RR_JABU_JABUS_BELLY_SHABOMB_CORRIDOR, - RR_JABU_JABUS_BELLY_LOWER_SIDE_ROOM, - RR_JABU_JABUS_BELLY_LIFT_LOWER, - RR_JABU_JABUS_BELLY_FORKED_CORRIDOR, - RR_JABU_JABUS_BELLY_BOOMERANG_ROOM, - RR_JABU_JABUS_BELLY_MAP_ROOM, + RR_JABU_JABUS_BELLY_MAIN, + RR_JABU_JABUS_BELLY_B1_NORTH, + RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, + RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE, RR_JABU_JABUS_BELLY_COMPASS_ROOM, RR_JABU_JABUS_BELLY_BLUE_TENTACLE, RR_JABU_JABUS_BELLY_GREEN_TENTACLE, - RR_JABU_JABUS_BELLY_BIGOCTO_ROOM, + RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE, RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO, RR_JABU_JABUS_BELLY_LIFT_UPPER, RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, @@ -3947,6 +3942,7 @@ typedef enum { RSK_KAK_GATE, RSK_DOOR_OF_TIME, RSK_ZORAS_FOUNTAIN, + RSK_SLEEPING_WATERFALL, RSK_STARTING_AGE, RSK_GERUDO_FORTRESS, RSK_RAINBOW_BRIDGE, @@ -4049,7 +4045,8 @@ typedef enum { RSK_GANONS_BOSS_KEY, RSK_SKIP_CHILD_STEALTH, RSK_SKIP_CHILD_ZELDA, - RSK_STARTING_CONSUMABLES, + RSK_STARTING_STICKS, + RSK_STARTING_NUTS, RSK_FULL_WALLETS, RSK_SHUFFLE_CHEST_MINIGAME, RSK_CUCCO_COUNT, @@ -4184,6 +4181,12 @@ typedef enum { RO_ZF_OPEN, } RandoOptionZorasFountain; +//Sleeping Waterfall settings (closed, open) +typedef enum { + RO_WATERFALL_CLOSED, + RO_WATERFALL_OPEN, +} RandoOptionSleepingWaterfall; + //Starting Age settings (child, adult, random) typedef enum { RO_AGE_CHILD, @@ -4630,6 +4633,9 @@ typedef enum { RE_BEAMOS, RE_WALLMASTER, RE_PURPLE_LEEVER, + RE_TENTACLE, + RE_BARI, + RE_SHABOM, } RandomizerEnemy; //RANDOTODO compare child long jumpslash range with adult short diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 2add45f1d..a9d9e72dc 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -1503,7 +1503,10 @@ void DrawLocation(RandomizerCheck rc) { txt = itemLoc->GetPlacedItem().GetName().GetForLanguage(gSaveContext.language); } if (IsVisibleInCheckTracker(rc) && status == RCSHOW_IDENTIFIED && !mystery && !itemLoc->IsAddedToPool()) { - txt += fmt::format(" - {}", OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->GetPrice()); + auto price = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->GetPrice(); + if (price) { + txt += fmt::format(" - {}", price); + } } } else { if (IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID())) { diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index dd6c27257..fd23feb04 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -13,7 +13,10 @@ uint8_t Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); } -void StartingItemGive(GetItemEntry getItemEntry) { +void StartingItemGive(GetItemEntry getItemEntry, RandomizerCheck randomizerCheck) { + if (randomizerCheck != RC_MAX) { + OTRGlobals::Instance->gRandoContext->GetItemLocation(randomizerCheck)->SetCheckStatus(RCSHOW_SAVED); + } if (getItemEntry.modIndex == MOD_NONE) { if (getItemEntry.getItemId == GI_SWORD_BGS) { gSaveContext.bgsFlag = true; @@ -96,8 +99,7 @@ void GiveLinkDekuNuts(int howManyNuts) { void GiveLinksPocketItem() { if (Randomizer_GetSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING) { GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, (GetItemID)RG_NONE); - StartingItemGive(getItemEntry); - Rando::Context::GetInstance()->GetItemLocation(RC_LINKS_POCKET)->SetCheckStatus(RCSHOW_SAVED); + StartingItemGive(getItemEntry, RC_LINKS_POCKET); // If we re-add the above, we'll get the item on save creation, now it's given on first load Flags_SetRandomizerInf(RAND_INF_LINKS_POCKET); } @@ -149,13 +151,11 @@ void SetStartingItems() { INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY; } - if (Randomizer_GetSettingValue(RSK_STARTING_CONSUMABLES)) { - if (!Randomizer_GetSettingValue(RSK_SHUFFLE_DEKU_STICK_BAG)) { - GiveLinkDekuSticks(10); - } - if (!Randomizer_GetSettingValue(RSK_SHUFFLE_DEKU_NUT_BAG)) { - GiveLinkDekuNuts(20); - } + if (Randomizer_GetSettingValue(RSK_STARTING_STICKS) && !Randomizer_GetSettingValue(RSK_SHUFFLE_DEKU_STICK_BAG)) { + GiveLinkDekuSticks(10); + } + if (Randomizer_GetSettingValue(RSK_STARTING_NUTS) && !Randomizer_GetSettingValue(RSK_SHUFFLE_DEKU_NUT_BAG)) { + GiveLinkDekuNuts(20); } if (Randomizer_GetSettingValue(RSK_FULL_WALLETS)) { @@ -251,10 +251,11 @@ extern "C" void Randomizer_InitSaveFile() { // Flags_SetInfTable(INFTABLE_CHILD_MALON_SAID_EPONA_WAS_AFRAID_OF_YOU); // Flags_SetInfTable(INFTABLE_SPOKE_TO_INGO_ONCE_AS_ADULT); + // Now handled by cutscene skips // Ruto already met in jabu and spawns down the hole immediately - Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO); - Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME); - Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE); + // Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO); + // Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME); + // Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE); // Now handled by cutscene skips // Skip cutscenes before Nabooru fight @@ -381,7 +382,7 @@ extern "C" void Randomizer_InitSaveFile() { if (Randomizer_GetSettingValue(RSK_SKIP_CHILD_ZELDA)) { GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_SONG_FROM_IMPA, (GetItemID)RG_ZELDAS_LULLABY); - StartingItemGive(getItemEntry); + StartingItemGive(getItemEntry, RC_SONG_FROM_IMPA); // malon/talon back at ranch Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_POCKET_EGG); @@ -403,7 +404,7 @@ extern "C" void Randomizer_InitSaveFile() { if (Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && startingAge == RO_AGE_ADULT) { GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_TOT_MASTER_SWORD, GI_NONE); - StartingItemGive(getItemEntry); + StartingItemGive(getItemEntry, RC_TOT_MASTER_SWORD); Flags_SetRandomizerInf(RAND_INF_TOT_MASTER_SWORD); } diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index caa9f8304..02c3c0475 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -109,6 +109,7 @@ void Settings::CreateOptions() { mOptions[RSK_KAK_GATE] = Option::U8("Kakariko Gate", {"Closed", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("KakarikoGate"), mOptionDescriptions[RSK_KAK_GATE]); mOptions[RSK_DOOR_OF_TIME] = Option::U8("Door of Time", {"Closed", "Song only", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("DoorOfTime"), mOptionDescriptions[RSK_DOOR_OF_TIME], WidgetType::Combobox); mOptions[RSK_ZORAS_FOUNTAIN] = Option::U8("Zora's Fountain", {"Closed", "Closed as child", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ZorasFountain"), mOptionDescriptions[RSK_ZORAS_FOUNTAIN]); + mOptions[RSK_SLEEPING_WATERFALL] = Option::U8("Sleeping Waterfall", {"Closed", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), mOptionDescriptions[RSK_SLEEPING_WATERFALL]); mOptions[RSK_GERUDO_FORTRESS] = Option::U8("Gerudo Fortress", {"Normal", "Fast", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GerudoFortress"), mOptionDescriptions[RSK_GERUDO_FORTRESS]); mOptions[RSK_RAINBOW_BRIDGE] = Option::U8("Rainbow Bridge", {"Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens", "Greg"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("RainbowBridge"), mOptionDescriptions[RSK_RAINBOW_BRIDGE], WidgetType::Combobox, RO_BRIDGE_VANILLA, false, IMFLAG_NONE); mOptions[RSK_RAINBOW_BRIDGE_STONE_COUNT] = Option::U8("Stone Count", {NumOpts(0, 4)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StoneCount"), "", WidgetType::Slider, 3, true); @@ -287,7 +288,8 @@ void Settings::CreateOptions() { mOptions[RSK_STARTING_DEKU_SHIELD] = Option::Bool("Start with Deku Shield", CVAR_RANDOMIZER_SETTING("StartingDekuShield")); mOptions[RSK_STARTING_KOKIRI_SWORD] = Option::Bool("Start with Kokiri Sword", CVAR_RANDOMIZER_SETTING("StartingKokiriSword")); mOptions[RSK_STARTING_MASTER_SWORD] = Option::Bool("Start with Master Sword", CVAR_RANDOMIZER_SETTING("StartingMasterSword")); - mOptions[RSK_STARTING_CONSUMABLES] = Option::Bool("Start with Consumables", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingConsumables"), "", WidgetType::Checkbox, RO_GENERIC_OFF); + mOptions[RSK_STARTING_STICKS] = Option::Bool("Start with Stick Ammo", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingSticks"), "", WidgetType::Checkbox, RO_GENERIC_OFF); + mOptions[RSK_STARTING_NUTS] = Option::Bool("Start with Nut Ammo", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingNuts"), "", WidgetType::Checkbox, RO_GENERIC_OFF); mOptions[RSK_FULL_WALLETS] = Option::Bool("Full Wallets", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("FullWallets"), mOptionDescriptions[RSK_FULL_WALLETS], WidgetType::Checkbox, RO_GENERIC_OFF); mOptions[RSK_STARTING_ZELDAS_LULLABY] = Option::Bool("Start with Zelda's Lullaby", CVAR_RANDOMIZER_SETTING("StartingZeldasLullaby"), "", IMFLAG_NONE); mOptions[RSK_STARTING_EPONAS_SONG] = Option::Bool("Start with Epona's Song", CVAR_RANDOMIZER_SETTING("StartingEponasSong"), "", IMFLAG_NONE); @@ -318,7 +320,7 @@ void Settings::CreateOptions() { mTrickOptions[RT_DOOM_JUMP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "Doom Jump", "Enables locations requiring doom jumps."); mTrickOptions[RT_EPG] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "EPG", "Enables locations requiring use of the Entrance Point Glitch."); mTrickOptions[RT_EQUIP_SWAP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "Equip Swap", "Enables locations requiring use of equip swap; NOTE: this may expect the 'Allow cursor to be over any slot' enhancement to be turned off."); - mTrickOptions[RT_EQUIP_SWAP_EXPECTS_DINS] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "Equip Swap Require's Din's Fire", "Enables locations requiring use of equip swap once din's fire is found."); + mTrickOptions[RT_EQUIP_SWAP_EXPECTS_DINS] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "Equip Swap Require's Din's Fire", "Enables locations requiring use of equip swap once Din's Fire is found."); mTrickOptions[RT_FLAME_STORAGE] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "Flame Storage", "Enables locations requiring flame storage."); mTrickOptions[RT_GROUND_CLIP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "Ground Clip", "Enables locations requiring ground clips."); mTrickOptions[RT_GROUND_JUMP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "Ground Jump", "Enables locations requiring ground jumps."); @@ -330,7 +332,7 @@ void Settings::CreateOptions() { mTrickOptions[RT_GROTTOS_WITHOUT_AGONY] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::NOVICE}, false, "Hidden Grottos without Stone of Agony", "Allows entering hidden grottos without the Stone of Agony."); mTrickOptions[RT_FEWER_TUNIC_REQUIREMENTS] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::INTERMEDIATE}, false, "Fewer Tunic Requirements", "Allows the following possible without Tunics:\n- Enter Water Temple. The area below the center pillar still requires Zora Tunic. Applies to MQ also.\n- Enter Fire Temple. Volvagia still requires Goron tunic. Applies to MQ also, and includes child access to first floor with dungeon shuffle."); mTrickOptions[RT_RUSTED_SWITCHES] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::NOVICE}, false, "Hammer Rusted Switches Through Walls", "Applies to: - Fire Temple Highest Goron Chest. - MQ Fire Temple Lizalfos Maze. - MQ Spirit Trial."); - mTrickOptions[RT_FLAMING_CHESTS] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::INTERMEDIATE}, false, "Flaming Chests", "The chests encircled in flames in Gerudo Training Grounds and in Spirit Temple can be opened by running into the flames while Link is invincible after taking damage."); + mTrickOptions[RT_FLAMING_CHESTS] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::INTERMEDIATE}, false, "Flaming Chests", "The chests encircled in flames in Gerudo Training Ground and in Spirit Temple can be opened by running into the flames while Link is invincible after taking damage."); // mTrickOptions[RT_BUNNY_HOOD_JUMPS] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, false, "Bunny Hood Jumps", "Allows reaching locations using Bunny Hood's extended jumps."); // mTrickOptions[RT_DAMAGE_BOOST_SIMPLE] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, false, "Simple damage boosts", "Allows damage boosts to reach Hyrule Castle guards, the bomb bag area in DC and the Gerudo Valley crate Piece of Heart. Can be combined with \"Simple hover boosts\" for reaching far distances."); // mTrickOptions[RT_HOVER_BOOST_SIMPLE] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, false, "Simple hover boosts", "Allows equipping of hover boots when link is moving at high speeds to extend distance covered. Can be combined with \"Simple damage boosts\" for greater uses."); @@ -364,7 +366,7 @@ void Settings::CreateOptions() { mTrickOptions[RT_GC_GROTTO] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_GORON_CITY, {Tricks::Tag::ADVANCED}, false, "Goron City Grotto with Hookshot While Taking Damage", "It is possible to reach the Goron City Grotto by quickly using the Hookshot while in the midst of taking damage from the lava floor."); mTrickOptions[RT_GC_LINK_GORON_DINS] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_GORON_CITY, {Tricks::Tag::NOVICE}, false, "Stop Link the Goron with Din\'s Fire", "The timing is quite awkward."); mTrickOptions[RT_DMC_HOVER_BEAN_POH] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_DEATH_MOUNTAIN_CRATER, {Tricks::Tag::NOVICE}, false, "Crater\'s Bean PoH with Hover Boots", "Hover from the base of the bridge near Goron City and walk up the very steep slope."); - mTrickOptions[RT_DMC_BOLERO_JUMP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_DEATH_MOUNTAIN_CRATER, {Tricks::Tag::EXTREME}, false, "Death Mountain Crater Jump to Bolero", "As Adult , using a shield to drop a pot while you have the perfect speed and position, the pot can push you that little extra distance you need to jump across the gap in the bridge."); + mTrickOptions[RT_DMC_BOLERO_JUMP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_DEATH_MOUNTAIN_CRATER, {Tricks::Tag::EXTREME}, false, "Death Mountain Crater Jump to Bolero", "As Adult, using a shield to drop a pot while you have the perfect speed and position, the pot can push you that little extra distance you need to jump across the gap in the bridge."); mTrickOptions[RT_DMC_BOULDER_JS] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_DEATH_MOUNTAIN_CRATER, {Tricks::Tag::NOVICE}, false, "Death Mountain Crater Upper to Lower with Hammer", "With the Hammer, you can jump slash the rock twice in the same jump in order to destroy it before you fall into the lava."); mTrickOptions[RT_DMC_BOULDER_SKIP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_DEATH_MOUNTAIN_CRATER, {Tricks::Tag::INTERMEDIATE}, false, "Death Mountain Crater Upper to Lower Boulder Skip", "As adult, With careful positioning, you can jump to the ledge where the boulder is, then use repeated ledge grabs to shimmy to a climbable ledge. This trick supersedes \"Death Mountain Crater Upper to Lower with Hammer\"."); mTrickOptions[RT_ZR_LOWER] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_ZORAS_RIVER, {Tricks::Tag::INTERMEDIATE}, false, "Zora\'s River Lower Freestanding PoH as Adult with Nothing", "Adult can reach this PoH with a precise jump, no Hover Boots required."); @@ -387,11 +389,11 @@ void Settings::CreateOptions() { mTrickOptions[RT_DEKU_BASEMENT_GS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree Basement Vines GS with Jump Slash", "Can be defeated by doing a precise jump slash."); mTrickOptions[RT_DEKU_B1_SKIP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_DEKU_TREE, {Tricks::Tag::INTERMEDIATE}, false, "Deku Tree Basement without Slingshot", "A precise jump can be used to skip needing to use the Slingshot to go around B1 of the Deku Tree. If used with the \"Closed Forest\" setting, a Slingshot will not be guaranteed to exist somewhere inside the Forest. This trick applies to both Vanilla and Master Quest."); mTrickOptions[RT_DEKU_B1_BOW_WEBS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree Basement Web to Gohma with Bow", "All spider web walls in the Deku Tree basement can be burnt as adult with just a bow by shooting through torches. This trick only applies to the circular web leading to Gohma; the two vertical webs are always in logic. Backflip onto the chest near the torch at the bottom of the vine wall. With precise positioning you can shoot through the torch to the right edge of the circular web. This allows completion of adult Deku Tree with no fire source."); - mTrickOptions[RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree Basement Backflip over Spiked Log", "Allows backflipping over the spiked log in the deku tree basement in vanilla. Only relevant if \"Shuffle Swim\" is enabled."); + mTrickOptions[RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree Basement Backflip over Spiked Log", "Allows backflipping over the spiked log in the Deku Tree basement in vanilla. Only relevant if \"Shuffle Swim\" is enabled."); mTrickOptions[RT_DEKU_MQ_COMPASS_GS] = TrickOption::LogicTrick(RCQUEST_MQ, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree MQ Compass Room GS Boulders with Just Hammer", "Climb to the top of the vines, then let go and jump slash immediately to destroy the boulders using the Hammer, without needing to spawn a Song of Time block."); mTrickOptions[RT_DEKU_MQ_LOG] = TrickOption::LogicTrick(RCQUEST_MQ, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree MQ Roll Under the Spiked Log", "You can get past the spiked log by rolling to briefly shrink your hitbox. As adult, the timing is a bit more precise."); mTrickOptions[RT_DC_SCARECROW_GS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DODONGOS_CAVERN, {Tricks::Tag::NOVICE}, false, "Dodongo\'s Cavern Scarecrow GS with Armos Statue", "You can jump off an Armos Statue to reach the alcove with the Gold Skulltula. It takes quite a long time to pull the statue the entire way. The jump to the alcove can be a bit picky when done as child."); - mTrickOptions[RT_DC_VINES_GS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DODONGOS_CAVERN, {Tricks::Tag::NOVICE}, false, "Dodongo\'s Cavern Vines GS from Below with Longshot", "The vines upon which this Skulltula rests are one- sided collision. You can use the Longshot to get it from below, by shooting it through the vines, bypassing the need to lower the staircase."); + mTrickOptions[RT_DC_VINES_GS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DODONGOS_CAVERN, {Tricks::Tag::NOVICE}, false, "Dodongo\'s Cavern Vines GS from Below with Longshot", "The vines upon which this Skulltula rests are one-sided collision. You can use the Longshot to get it from below, by shooting it through the vines, bypassing the need to lower the staircase."); mTrickOptions[RT_DC_STAIRCASE] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DODONGOS_CAVERN, {Tricks::Tag::NOVICE}, false, "Dodongo\'s Cavern Staircase with Bow", "The Bow can be used to knock down the stairs with two well-timed shots."); mTrickOptions[RT_DC_SLINGSHOT_SKIP] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DODONGOS_CAVERN, {Tricks::Tag::EXPERT}, false, "Dodongo\'s Cavern Child Slingshot Skips", "With precise platforming, child can cross the platforms while the flame circles are there. When enabling this trick, it's recommended that you also enable the Adult variant: \"Dodongo's Cavern Spike Trap Room Jump without Hover Boots\"."); mTrickOptions[RT_DC_SCRUB_ROOM] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DODONGOS_CAVERN, {Tricks::Tag::NOVICE}, false, "Dodongo\'s Cavern Two Scrub Room with Strength", "With help from a conveniently-positioned block, Adult can quickly carry a bomb flower over to destroy the mud wall blocking the room with two Deku Scrubs."); @@ -444,7 +446,7 @@ void Settings::CreateOptions() { mTrickOptions[RT_WATER_CRACKED_WALL] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_WATER_TEMPLE, {Tricks::Tag::INTERMEDIATE}, false, "Water Temple Cracked Wall with No Additional Items", "A precise jump slash (among other methods) will get you to the cracked wall without needing the Hover Boots or to raise the water to the middle level. This trick supersedes \"Water Temple Cracked Wall with Hover Boots\"."); mTrickOptions[RT_WATER_BK_REGION] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_WATER_TEMPLE, {Tricks::Tag::INTERMEDIATE}, false, "Water Temple Boss Key Region with Hover Boots", "With precise Hover Boots movement it is possible to reach the boss key chest's region without needing the Longshot. It is not necessary to take damage from the spikes. The Gold Skulltula Token in the following room can also be obtained with just the Hover Boots."); mTrickOptions[RT_WATER_NORTH_BASEMENT_LEDGE_JUMP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_WATER_TEMPLE, {Tricks::Tag::INTERMEDIATE}, false, "Water Temple North Basement Ledge with Precise Jump", "In the northern basement there's a ledge from where, in vanilla Water Temple, boulders roll out into the room. Normally to jump directly to this ledge logically requires the Hover Boots, but with precise jump, it can be done without them. This trick applies to both Vanilla and Master Quest."); - mTrickOptions[RT_WATER_BK_JUMP_DIVE] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_WATER_TEMPLE, {Tricks::Tag::NOVICE}, false, "Water Temple Boss Key Jump Dive", "Stand on the very edge of the raised corridor leading from the push block room to the rolling boulder corridor. Face the gold skulltula on the waterfall and jump over the boulder corridor floor into the pool of water, swimming right once underwater. This allows access to the boss key room without Iron boots."); + mTrickOptions[RT_WATER_BK_JUMP_DIVE] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_WATER_TEMPLE, {Tricks::Tag::NOVICE}, false, "Water Temple Boss Key Jump Dive", "Stand on the very edge of the raised corridor leading from the push block room to the rolling boulder corridor. Face the Gold Skulltula on the waterfall and jump over the boulder corridor floor into the pool of water, swimming right once underwater. This allows access to the boss key room without Iron boots."); //Also used in MQ logic, but won't be relevent unless a way to enter tower without irons exists (likely a clip + swim) mTrickOptions[RT_WATER_FW_CENTRAL_GS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_WATER_TEMPLE, {Tricks::Tag::NOVICE}, false, "Water Temple Central Pillar GS with Farore\'s Wind", "If you set Farore's Wind inside the central pillar and then return to that warp point after raising the water to the highest level, you can obtain this Skulltula Token with Hookshot or Boomerang."); mTrickOptions[RT_WATER_IRONS_CENTRAL_GS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_WATER_TEMPLE, {Tricks::Tag::NOVICE}, false, "Water Temple Central Pillar GS with Iron Boots", "After opening the middle water level door into the central pillar, the door will stay unbarred so long as you do not leave the room -- even if you were to raise the water up to the highest level. With the Iron Boots to go through the door after the water has been raised, you can obtain the Skulltula Token with the Hookshot."); @@ -696,6 +698,7 @@ void Settings::CreateOptions() { &mOptions[RSK_KAK_GATE], &mOptions[RSK_DOOR_OF_TIME], &mOptions[RSK_ZORAS_FOUNTAIN], + &mOptions[RSK_SLEEPING_WATERFALL], }, false, WidgetContainerType::COLUMN); mOptionGroups[RSG_WORLD_IMGUI] = OptionGroup::SubGroup("World Settings", { &mOptions[RSK_STARTING_AGE], @@ -911,7 +914,8 @@ void Settings::CreateOptions() { }, false, WidgetContainerType::COLUMN); mOptionGroups[RSG_STARTING_ITEMS_IMGUI] = OptionGroup::SubGroup("Starting Items", { &mOptions[RSK_STARTING_OCARINA], - &mOptions[RSK_STARTING_CONSUMABLES], + &mOptions[RSK_STARTING_STICKS], + &mOptions[RSK_STARTING_NUTS], &mOptions[RSK_STARTING_SKULLTULA_TOKEN], &mOptions[RSK_STARTING_HEARTS], }, false, WidgetContainerType::COLUMN); @@ -945,6 +949,7 @@ void Settings::CreateOptions() { &mOptions[RSK_KAK_GATE], &mOptions[RSK_DOOR_OF_TIME], &mOptions[RSK_ZORAS_FOUNTAIN], + &mOptions[RSK_SLEEPING_WATERFALL], &mOptions[RSK_GERUDO_FORTRESS], &mOptions[RSK_RAINBOW_BRIDGE], &mOptions[RSK_RAINBOW_BRIDGE_STONE_COUNT], @@ -1101,7 +1106,8 @@ void Settings::CreateOptions() { &mOptions[RSK_STARTING_PRELUDE_OF_LIGHT], }, false); mOptionGroups[RSG_STARTING_OTHER] = OptionGroup::SubGroup("Other", { - &mOptions[RSK_STARTING_CONSUMABLES], + &mOptions[RSK_STARTING_STICKS], + &mOptions[RSK_STARTING_NUTS], &mOptions[RSK_FULL_WALLETS], &mOptions[RSK_STARTING_SKULLTULA_TOKEN], &mOptions[RSK_STARTING_HEARTS], @@ -1262,6 +1268,7 @@ void Settings::CreateOptions() { { "Open Settings:Kakariko Gate", RSK_KAK_GATE }, { "Open Settings:Door of Time", RSK_DOOR_OF_TIME }, { "Open Settings:Zora's Fountain", RSK_ZORAS_FOUNTAIN }, + { "Open Settings:Sleeping Waterfall", RSK_SLEEPING_WATERFALL }, { "World Settings:Starting Age", RSK_STARTING_AGE }, { "Open Settings:Gerudo Fortress", RSK_GERUDO_FORTRESS }, { "Open Settings:Rainbow Bridge", RSK_RAINBOW_BRIDGE }, @@ -1364,7 +1371,8 @@ void Settings::CreateOptions() { { "Shuffle Dungeon Items:Ganon's Boss Key", RSK_GANONS_BOSS_KEY }, { "Timesaver Settings:Skip Child Stealth", RSK_SKIP_CHILD_STEALTH }, { "Timesaver Settings:Skip Child Zelda", RSK_SKIP_CHILD_ZELDA }, - { "Start with Consumables", RSK_STARTING_CONSUMABLES }, + { "Start with Sticks", RSK_STARTING_STICKS }, + { "Start with Nuts", RSK_STARTING_NUTS }, { "Full Wallets", RSK_FULL_WALLETS }, { "Timesaver Settings:Cuccos to return", RSK_CUCCO_COUNT }, { "Timesaver Settings:Big Poe Target Count", RSK_BIG_POE_COUNT }, @@ -1468,7 +1476,7 @@ TrickOption& Settings::GetTrickOption(const RandomizerTrick key) { void Settings::ResetTrickOptions() { for (int count = 0; count < RT_MAX; count++){ - mTrickOptions[count].SetSelectedIndex(0); //RANDOTODO this can probably be done better + mTrickOptions[count].SetContextIndex(0); //RANDOTODO this can probably be done better }; } @@ -1834,6 +1842,17 @@ void Settings::UpdateOptionProperties() { mOptions[lastKey].AddFlag(IMFLAG_SEPARATOR_BOTTOM); } + if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleDekuStickBag"), 0)) { + mOptions[RSK_STARTING_STICKS].Disable("Disabled because Shuffle Deku Stick Bag is On"); + } else { + mOptions[RSK_STARTING_STICKS].Enable(); + } + if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleDekuNutBag"), 0)) { + mOptions[RSK_STARTING_NUTS].Disable("Disabled because Shuffle Deku Nut Bag is On"); + } else { + mOptions[RSK_STARTING_NUTS].Enable(); + } + // Shuffle Weird Egg - Disabled when Skip Child Zelda is active if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("SkipChildZelda"), RO_GENERIC_DONT_SKIP)) { mOptions[RSK_SHUFFLE_WEIRD_EGG].Disable("This option is disabled because \"Skip Child Zelda\" is enabled."); @@ -2212,6 +2231,9 @@ void Settings::UpdateOptionProperties() { void Settings::FinalizeSettings(const std::set& excludedLocations, const std::set& enabledTricks) { const auto ctx = Rando::Context::GetInstance(); if (!ctx->IsSpoilerLoaded()) { + for (Option& option : mOptions) { + option.SetContextIndex(option.GetMenuOptionIndex()); + } // If we've loaded a spoiler file, the settings have already been populated, so we // only need to do things like resolve the starting age or determine MQ dungeons. // Any logic dependent on cvarSettings should go in this if statement @@ -2219,39 +2241,39 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio // if we skip child zelda, we start with zelda's letter, and malon starts // at the ranch, so we should *not* shuffle the weird egg if (mOptions[RSK_SKIP_CHILD_ZELDA]) { - mOptions[RSK_SHUFFLE_WEIRD_EGG].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_SHUFFLE_WEIRD_EGG].SetContextIndex(RO_GENERIC_OFF); } // With certain access settings, the seed is only beatable if Starting Age is set to Child. if (mOptions[RSK_FOREST].Is(RO_FOREST_CLOSED) || (mOptions[RSK_DOOR_OF_TIME].Is(RO_DOOROFTIME_CLOSED) && !mOptions[RSK_SHUFFLE_OCARINA])) { - mOptions[RSK_STARTING_AGE].SetSelectedIndex(RO_AGE_CHILD); + mOptions[RSK_STARTING_AGE].SetContextIndex(RO_AGE_CHILD); } if (mOptions[RSK_TRIFORCE_HUNT]) { - mOptions[RSK_GANONS_BOSS_KEY].SetSelectedIndex(RO_GANON_BOSS_KEY_TRIFORCE_HUNT); + mOptions[RSK_GANONS_BOSS_KEY].SetContextIndex(RO_GANON_BOSS_KEY_TRIFORCE_HUNT); } // Force 100 GS Shuffle if that's where Ganon's Boss Key is if (mOptions[RSK_GANONS_BOSS_KEY].Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) { - mOptions[RSK_SHUFFLE_100_GS_REWARD].SetSelectedIndex(1); + mOptions[RSK_SHUFFLE_100_GS_REWARD].SetContextIndex(1); } // If we only have MQ, set all dungeons to MQ if (OTRGlobals::Instance->HasMasterQuest() && !OTRGlobals::Instance->HasOriginal()) { - mOptions[RSK_MQ_DUNGEON_RANDOM].SetSelectedIndex(RO_MQ_DUNGEONS_SET_NUMBER); - mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(12); - mOptions[RSK_MQ_DUNGEON_SET].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_MQ_DUNGEON_RANDOM].SetContextIndex(RO_MQ_DUNGEONS_SET_NUMBER); + mOptions[RSK_MQ_DUNGEON_COUNT].SetContextIndex(12); + mOptions[RSK_MQ_DUNGEON_SET].SetContextIndex(RO_GENERIC_OFF); } // If we don't have MQ, set all dungeons to Vanilla if (OTRGlobals::Instance->HasOriginal() && !OTRGlobals::Instance->HasMasterQuest()) { - mOptions[RSK_MQ_DUNGEON_RANDOM].SetSelectedIndex(RO_MQ_DUNGEONS_NONE); + mOptions[RSK_MQ_DUNGEON_RANDOM].SetContextIndex(RO_MQ_DUNGEONS_NONE); } if (mOptions[RSK_MQ_DUNGEON_RANDOM].Is(RO_MQ_DUNGEONS_NONE)) { - mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(0); - mOptions[RSK_MQ_DUNGEON_SET].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_MQ_DUNGEON_COUNT].SetContextIndex(0); + mOptions[RSK_MQ_DUNGEON_SET].SetContextIndex(RO_GENERIC_OFF); } // If any of the individual shuffle settings are on, turn on the main Shuffle Entrances option @@ -2261,53 +2283,60 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio || mOptions[RSK_SHUFFLE_INTERIOR_ENTRANCES].IsNot(RO_INTERIOR_ENTRANCE_SHUFFLE_OFF) || mOptions[RSK_SHUFFLE_GROTTO_ENTRANCES] || mOptions[RSK_SHUFFLE_OWL_DROPS] || mOptions[RSK_SHUFFLE_WARP_SONGS] || mOptions[RSK_SHUFFLE_OVERWORLD_SPAWNS]) { - mOptions[RSK_SHUFFLE_ENTRANCES].SetSelectedIndex(RO_GENERIC_ON); + mOptions[RSK_SHUFFLE_ENTRANCES].SetContextIndex(RO_GENERIC_ON); } else { - mOptions[RSK_SHUFFLE_ENTRANCES].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_SHUFFLE_ENTRANCES].SetContextIndex(RO_GENERIC_OFF); } if (mOptions[RSK_SHUFFLE_DUNGEON_REWARDS].Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) { - mOptions[RSK_LINKS_POCKET].SetSelectedIndex(RO_LINKS_POCKET_DUNGEON_REWARD); + mOptions[RSK_LINKS_POCKET].SetContextIndex(RO_LINKS_POCKET_DUNGEON_REWARD); } if (!ctx->IsSpoilerLoaded()) { ctx->AddExcludedOptions(); for (const auto locationKey : ctx->everyPossibleLocation) { if (const auto location = ctx->GetItemLocation(locationKey); excludedLocations.contains(location->GetRandomizerCheck())) { - location->GetExcludedOption()->SetSelectedIndex(1); + location->GetExcludedOption()->SetContextIndex(1); } else { - location->GetExcludedOption()->SetSelectedIndex(0); + location->GetExcludedOption()->SetContextIndex(0); } } // Tricks ResetTrickOptions(); for (const auto randomizerTrick : enabledTricks) { - mTrickOptions[randomizerTrick].SetSelectedIndex(1); + mTrickOptions[randomizerTrick].SetContextIndex(1); } } if (!mOptions[RSK_SHUFFLE_KOKIRI_SWORD]) { if (mOptions[RSK_STARTING_KOKIRI_SWORD]) { - ctx->GetItemLocation(RC_KF_KOKIRI_SWORD_CHEST)->GetExcludedOption()->SetSelectedIndex(1); + ctx->GetItemLocation(RC_KF_KOKIRI_SWORD_CHEST)->GetExcludedOption()->SetContextIndex(1); } } if (!mOptions[RSK_SHUFFLE_MASTER_SWORD]) { if (mOptions[RSK_STARTING_MASTER_SWORD]) { - ctx->GetItemLocation(RC_MASTER_SWORD_PEDESTAL)->GetExcludedOption()->SetSelectedIndex(1); + ctx->GetItemLocation(RC_MASTER_SWORD_PEDESTAL)->GetExcludedOption()->SetContextIndex(1); } } if (!mOptions[RSK_SHUFFLE_OCARINA]) { if (mOptions[RSK_STARTING_OCARINA].IsNot(RO_STARTING_OCARINA_OFF)) { - ctx->GetItemLocation(RC_LW_GIFT_FROM_SARIA)->GetExcludedOption()->SetSelectedIndex(1); + ctx->GetItemLocation(RC_LW_GIFT_FROM_SARIA)->GetExcludedOption()->SetContextIndex(1); if (mOptions[RSK_STARTING_OCARINA].Is(RO_STARTING_OCARINA_TIME)) { - ctx->GetItemLocation(RC_HF_OCARINA_OF_TIME_ITEM)->GetExcludedOption()->SetSelectedIndex(1); + ctx->GetItemLocation(RC_HF_OCARINA_OF_TIME_ITEM)->GetExcludedOption()->SetContextIndex(1); } } } } + if (mOptions[RSK_SHUFFLE_DEKU_STICK_BAG]) { + mOptions[RSK_STARTING_STICKS].SetContextIndex(false); + } + if (mOptions[RSK_SHUFFLE_DEKU_NUT_BAG]) { + mOptions[RSK_STARTING_NUTS].SetContextIndex(false); + } + // RANDOTODO implement chest shuffle with keysanity - // ShuffleChestMinigame.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]); - mOptions[RSK_SHUFFLE_CHEST_MINIGAME].SetSelectedIndex(RO_CHEST_GAME_OFF); + // ShuffleChestMinigame.SetContextIndex(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]); + mOptions[RSK_SHUFFLE_CHEST_MINIGAME].SetContextIndex(RO_CHEST_GAME_OFF); //TODO: RandomizeAllSettings(true) when implementing the ability to randomize the options themselves. std::array dungeons = ctx->GetDungeons()->GetDungeonList(); @@ -2318,12 +2347,12 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio dungeon->SetDungeonKnown(true); } //if it's selection mode, process the selection directly - if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value() == RO_MQ_DUNGEONS_SELECTION){ - mOptions[RSK_MQ_DUNGEON_SET].SetSelectedIndex(RO_GENERIC_ON); + if (mOptions[RSK_MQ_DUNGEON_RANDOM].GetContextOptionIndex() == RO_MQ_DUNGEONS_SELECTION){ + mOptions[RSK_MQ_DUNGEON_SET].SetContextIndex(RO_GENERIC_ON); //How many dungeons are set to MQ in selection uint8_t mqSet = 0; for (auto dungeon: dungeons) { - switch (mOptions[dungeon->GetMQSetting()].Value()) { + switch (mOptions[dungeon->GetMQSetting()].GetContextOptionIndex()) { case RO_MQ_SET_MQ: dungeon->SetMQ(); mqSet += 1; @@ -2342,11 +2371,11 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio } } //override the dungeons set with the ones set by selection, so it's accurate for anything that wants to know MQ dungeon count - mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(mqSet); + mOptions[RSK_MQ_DUNGEON_COUNT].SetContextIndex(mqSet); //handling set number and random number together - } else if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value() != RO_MQ_DUNGEONS_NONE){ + } else if (mOptions[RSK_MQ_DUNGEON_RANDOM].GetContextOptionIndex() != RO_MQ_DUNGEONS_NONE){ // so we don't have to call this repeatedly - uint8_t mqCount = mOptions[RSK_MQ_DUNGEON_COUNT].Value(); + uint8_t mqCount = mOptions[RSK_MQ_DUNGEON_COUNT].GetContextOptionIndex(); //How many dungeons are set to MQ in selection uint8_t mqSet = 0; //the number of random @@ -2356,7 +2385,7 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio //if dungeons have been preset, process them if (mOptions[RSK_MQ_DUNGEON_SET]){ for (size_t i = 0; i < dungeons.size(); i++) { - switch (mOptions[dungeons[i]->GetMQSetting()].Value()) { + switch (mOptions[dungeons[i]->GetMQSetting()].GetContextOptionIndex()) { case RO_MQ_SET_MQ: dungeons[i]->SetMQ(); mqSet += 1; @@ -2372,22 +2401,22 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio //otherwise, every dungeon is possible } else { //if the count is fixed to 12, we know everything is MQ, so can skip some setps and do not set Known - if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value() == RO_MQ_DUNGEONS_SET_NUMBER && + if (mOptions[RSK_MQ_DUNGEON_RANDOM].GetContextOptionIndex() == RO_MQ_DUNGEONS_SET_NUMBER && mqCount == 12) { randMQOption = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; for (auto dungeon: dungeons) { - mOptions[dungeon->GetMQSetting()].SetSelectedIndex(RO_MQ_SET_MQ); + mOptions[dungeon->GetMQSetting()].SetContextIndex(RO_MQ_SET_MQ); } //if it's fixed to zero, set it to None instead. the rest is processed after - } else if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value() == RO_MQ_DUNGEONS_SET_NUMBER && + } else if (mOptions[RSK_MQ_DUNGEON_RANDOM].GetContextOptionIndex() == RO_MQ_DUNGEONS_SET_NUMBER && mqCount == 0){ - mOptions[RSK_MQ_DUNGEON_RANDOM].SetSelectedIndex(RO_MQ_DUNGEONS_NONE); + mOptions[RSK_MQ_DUNGEON_RANDOM].SetContextIndex(RO_MQ_DUNGEONS_NONE); //otherwise, make everything a possibility and unknown } else { for (size_t i = 0; i < dungeons.size(); i++) { randMQOption.push_back(i); dungeons[i]->SetDungeonKnown(false); - mOptions[dungeons[i]->GetMQSetting()].SetSelectedIndex(RO_MQ_SET_RANDOM); + mOptions[dungeons[i]->GetMQSetting()].SetContextIndex(RO_MQ_SET_RANDOM); } } } @@ -2409,20 +2438,20 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio } else { //if there's no random options, check if we can collapse the setting into None or Selection if (mqSet == 0){ - mOptions[RSK_MQ_DUNGEON_RANDOM].SetSelectedIndex(RO_MQ_DUNGEONS_NONE); + mOptions[RSK_MQ_DUNGEON_RANDOM].SetContextIndex(RO_MQ_DUNGEONS_NONE); } else { - mOptions[RSK_MQ_DUNGEON_RANDOM].SetSelectedIndex(RO_MQ_DUNGEONS_SELECTION); + mOptions[RSK_MQ_DUNGEON_RANDOM].SetContextIndex(RO_MQ_DUNGEONS_SELECTION); } } //reset the value set based on what was actually set - mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(mqToSet + mqSet); + mOptions[RSK_MQ_DUNGEON_COUNT].SetContextIndex(mqToSet + mqSet); } //Not an if else as other settings can become None in processing - if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value() == RO_MQ_DUNGEONS_NONE) { - mOptions[RSK_MQ_DUNGEON_SET].SetSelectedIndex(RO_GENERIC_OFF); - mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(0); + if (mOptions[RSK_MQ_DUNGEON_RANDOM].GetContextOptionIndex() == RO_MQ_DUNGEONS_NONE) { + mOptions[RSK_MQ_DUNGEON_SET].SetContextIndex(RO_GENERIC_OFF); + mOptions[RSK_MQ_DUNGEON_COUNT].SetContextIndex(0); for (auto dungeon: dungeons) { - mOptions[dungeon->GetMQSetting()].SetSelectedIndex(RO_MQ_SET_VANILLA); + mOptions[dungeon->GetMQSetting()].SetContextIndex(RO_MQ_SET_VANILLA); } } @@ -2448,16 +2477,16 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio if (mOptions[RSK_GERUDO_FORTRESS].Is(RO_GF_NORMAL) && mOptions[RSK_GERUDO_KEYS].IsNot(RO_GERUDO_KEYS_VANILLA)) { keyrings.push_back(&mOptions[RSK_KEYRINGS_GERUDO_FORTRESS]); } else { - mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_OFF); + mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].SetContextIndex(RO_KEYRING_FOR_DUNGEON_OFF); } if (mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_RANDOM) || mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT)) { - const uint32_t keyRingCount = mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT) ? mOptions[RSK_KEYRINGS_RANDOM_COUNT].Value() : Random(0, static_cast(keyrings.size())); + const uint32_t keyRingCount = mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT) ? mOptions[RSK_KEYRINGS_RANDOM_COUNT].GetContextOptionIndex() : Random(0, static_cast(keyrings.size())); Shuffle(keyrings); for (size_t i = 0; i < keyRingCount; i++) { - keyrings[i]->SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_ON); + keyrings[i]->SetContextIndex(RO_KEYRING_FOR_DUNGEON_ON); } for (size_t i = keyRingCount; i < keyrings.size(); i++) { - keyrings[i]->SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_OFF); + keyrings[i]->SetContextIndex(RO_KEYRING_FOR_DUNGEON_OFF); } } if (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) { @@ -2492,11 +2521,11 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio trial->SetAsSkipped(); } if(mOptions[RSK_GANONS_TRIALS].Is(RO_GANONS_TRIALS_SKIP)){ - mOptions[RSK_TRIAL_COUNT].SetSelectedIndex(0); + mOptions[RSK_TRIAL_COUNT].SetContextIndex(0); } else if(mOptions[RSK_GANONS_TRIALS].Is(RO_GANONS_TRIALS_RANDOM_NUMBER)) { - mOptions[RSK_TRIAL_COUNT].SetSelectedIndex(Random(0, static_cast(mOptions[RSK_TRIAL_COUNT].GetOptionCount()))); + mOptions[RSK_TRIAL_COUNT].SetContextIndex(Random(0, static_cast(mOptions[RSK_TRIAL_COUNT].GetOptionCount()))); } - for (uint8_t i = 0; i < mOptions[RSK_TRIAL_COUNT].Value(); i++) { + for (uint8_t i = 0; i < mOptions[RSK_TRIAL_COUNT].GetContextOptionIndex(); i++) { trials[i]->SetAsRequired(); } @@ -2504,7 +2533,7 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio (mOptions[RSK_SHUFFLE_INTERIOR_ENTRANCES].Is(RO_INTERIOR_ENTRANCE_SHUFFLE_ALL) || mOptions[RSK_SHUFFLE_OVERWORLD_ENTRANCES] || mOptions[RSK_SHUFFLE_OVERWORLD_SPAWNS] || mOptions[RSK_DECOUPLED_ENTRANCES] || mOptions[RSK_MIXED_ENTRANCE_POOLS])) { - mOptions[RSK_FOREST].SetSelectedIndex(RO_FOREST_CLOSED_DEKU); + mOptions[RSK_FOREST].SetContextIndex(RO_FOREST_CLOSED_DEKU); } if (mOptions[RSK_STARTING_AGE].Is(RO_AGE_RANDOM)) { @@ -2514,7 +2543,7 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio mResolvedStartingAge = RO_AGE_ADULT; } } else { - mResolvedStartingAge = static_cast(mOptions[RSK_STARTING_AGE].Value()); + mResolvedStartingAge = static_cast(mOptions[RSK_STARTING_AGE].GetContextOptionIndex()); } // TODO: Random Starting Time @@ -2535,35 +2564,35 @@ void Settings::FinalizeSettings(const std::set& excludedLocatio if (mOptions[RSK_LOGIC_RULES].Is(RO_LOGIC_VANILLA)) { for (Option* setting : VanillaLogicDefaults) { - setting->SetDelayedOption(); - setting->SetSelectedIndex(0); + //setting->SetDelayedOption(); + setting->SetContextIndex(0); } - mOptions[RSK_KEYSANITY].SetDelayedOption(); - mOptions[RSK_KEYSANITY].SetSelectedIndex(3); + //mOptions[RSK_KEYSANITY].SetDelayedOption(); + mOptions[RSK_KEYSANITY].SetContextIndex(3); } if (!mOptions[RSK_SHUFFLE_WARP_SONGS]) { - mOptions[RSK_WARP_SONG_HINTS].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_WARP_SONG_HINTS].SetContextIndex(RO_GENERIC_OFF); } if (!mOptions[RSK_SHUFFLE_COWS]) { - mOptions[RSK_MALON_HINT].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_MALON_HINT].SetContextIndex(RO_GENERIC_OFF); } if (!mOptions[RSK_SHUFFLE_100_GS_REWARD]) { - mOptions[RSK_KAK_100_SKULLS_HINT].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_KAK_100_SKULLS_HINT].SetContextIndex(RO_GENERIC_OFF); } if (!mOptions[RSK_SHUFFLE_FISHING_POLE]) { - mOptions[RSK_FISHING_POLE_HINT].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_FISHING_POLE_HINT].SetContextIndex(RO_GENERIC_OFF); } if (mOptions[RSK_FISHSANITY].IsNot(RO_FISHSANITY_HYRULE_LOACH)) { - mOptions[RSK_LOACH_HINT].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_LOACH_HINT].SetContextIndex(RO_GENERIC_OFF); } if (mOptions[RSK_CUCCO_COUNT].Is(0)) { - mOptions[RSK_CHICKENS_HINT].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[RSK_CHICKENS_HINT].SetContextIndex(RO_GENERIC_OFF); } } void Settings::ParseJson(nlohmann::json spoilerFileJson) { @@ -2581,115 +2610,122 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { switch (const RandomizerSettingKey index = mSpoilerfileSettingNameToEnum[it.key()]) { case RSK_LOGIC_RULES: if (it.value() == "Glitchless") { - mOptions[index].SetSelectedIndex(RO_LOGIC_GLITCHLESS); + mOptions[index].SetContextIndex(RO_LOGIC_GLITCHLESS); } else if (it.value() == "No Logic") { - mOptions[index].SetSelectedIndex(RO_LOGIC_NO_LOGIC); + mOptions[index].SetContextIndex(RO_LOGIC_NO_LOGIC); } else if (it.value() == "Vanilla") { - mOptions[index].SetSelectedIndex(RO_LOGIC_VANILLA); + mOptions[index].SetContextIndex(RO_LOGIC_VANILLA); } break; case RSK_FOREST: if (it.value() == "Closed") { - mOptions[index].SetSelectedIndex(RO_FOREST_CLOSED); + mOptions[index].SetContextIndex(RO_FOREST_CLOSED); } else if (it.value() == "Open") { - mOptions[index].SetSelectedIndex(RO_FOREST_OPEN); + mOptions[index].SetContextIndex(RO_FOREST_OPEN); } else if (it.value() == "Closed Deku") { - mOptions[index].SetSelectedIndex(RO_FOREST_CLOSED_DEKU); + mOptions[index].SetContextIndex(RO_FOREST_CLOSED_DEKU); } break; case RSK_KAK_GATE: if (it.value() == "Closed") { - mOptions[index].SetSelectedIndex(RO_KAK_GATE_CLOSED); + mOptions[index].SetContextIndex(RO_KAK_GATE_CLOSED); } else if (it.value() == "Open") { - mOptions[index].SetSelectedIndex(RO_KAK_GATE_OPEN); + mOptions[index].SetContextIndex(RO_KAK_GATE_OPEN); } break; case RSK_DOOR_OF_TIME: if (it.value() == "Open") { - mOptions[index].SetSelectedIndex(RO_DOOROFTIME_OPEN); + mOptions[index].SetContextIndex(RO_DOOROFTIME_OPEN); } else if (it.value() == "Song only") { - mOptions[index].SetSelectedIndex(RO_DOOROFTIME_SONGONLY); + mOptions[index].SetContextIndex(RO_DOOROFTIME_SONGONLY); } else if (it.value() == "Closed") { - mOptions[index].SetSelectedIndex(RO_DOOROFTIME_CLOSED); + mOptions[index].SetContextIndex(RO_DOOROFTIME_CLOSED); } break; case RSK_ZORAS_FOUNTAIN: if (it.value() == "Closed") { - mOptions[index].SetSelectedIndex(RO_ZF_CLOSED); + mOptions[index].SetContextIndex(RO_ZF_CLOSED); } else if (it.value() == "Closed as child") { - mOptions[index].SetSelectedIndex(RO_ZF_CLOSED_CHILD); + mOptions[index].SetContextIndex(RO_ZF_CLOSED_CHILD); } else if (it.value() == "Open") { - mOptions[index].SetSelectedIndex(RO_ZF_OPEN); + mOptions[index].SetContextIndex(RO_ZF_OPEN); + } + break; + case RSK_SLEEPING_WATERFALL: + if (it.value() == "Closed") { + mOptions[index].SetContextIndex(RO_WATERFALL_CLOSED); + } else if (it.value() == "Open") { + mOptions[index].SetContextIndex(RO_WATERFALL_OPEN); } break; case RSK_STARTING_AGE: if (it.value() == "Child") { - mOptions[index].SetSelectedIndex(RO_AGE_CHILD); + mOptions[index].SetContextIndex(RO_AGE_CHILD); } else if (it.value() == "Adult") { - mOptions[index].SetSelectedIndex(RO_AGE_ADULT); + mOptions[index].SetContextIndex(RO_AGE_ADULT); } break; case RSK_GERUDO_FORTRESS: if (it.value() == "Normal") { - mOptions[index].SetSelectedIndex(RO_GF_NORMAL); + mOptions[index].SetContextIndex(RO_GF_NORMAL); } else if (it.value() == "Fast") { - mOptions[index].SetSelectedIndex(RO_GF_FAST); + mOptions[index].SetContextIndex(RO_GF_FAST); } else if (it.value() == "Open") { - mOptions[index].SetSelectedIndex(RO_GF_OPEN); + mOptions[index].SetContextIndex(RO_GF_OPEN); } break; case RSK_RAINBOW_BRIDGE: if (it.value() == "Vanilla") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_VANILLA); + mOptions[index].SetContextIndex(RO_BRIDGE_VANILLA); } else if (it.value() == "Always open") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_ALWAYS_OPEN); + mOptions[index].SetContextIndex(RO_BRIDGE_ALWAYS_OPEN); } else if (it.value() == "Stones") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_STONES); + mOptions[index].SetContextIndex(RO_BRIDGE_STONES); } else if (it.value() == "Medallions") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_MEDALLIONS); + mOptions[index].SetContextIndex(RO_BRIDGE_MEDALLIONS); } else if (it.value() == "Dungeon rewards") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_DUNGEON_REWARDS); + mOptions[index].SetContextIndex(RO_BRIDGE_DUNGEON_REWARDS); } else if (it.value() == "Dungeons") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_DUNGEONS); + mOptions[index].SetContextIndex(RO_BRIDGE_DUNGEONS); } else if (it.value() == "Tokens") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_TOKENS); + mOptions[index].SetContextIndex(RO_BRIDGE_TOKENS); } else if (it.value() == "Greg") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_GREG); + mOptions[index].SetContextIndex(RO_BRIDGE_GREG); } break; case RSK_BRIDGE_OPTIONS: if (it.value() == "Standard Rewards") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_STANDARD_REWARD); + mOptions[index].SetContextIndex(RO_BRIDGE_STANDARD_REWARD); } else if (it.value() == "Greg as Reward") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_GREG_REWARD); + mOptions[index].SetContextIndex(RO_BRIDGE_GREG_REWARD); } else if (it.value() == "Greg as Wildcard") { - mOptions[index].SetSelectedIndex(RO_BRIDGE_WILDCARD_REWARD); + mOptions[index].SetContextIndex(RO_BRIDGE_WILDCARD_REWARD); } break; case RSK_LACS_OPTIONS: if (it.value() == "Standard Reward") { - mOptions[index].SetSelectedIndex(RO_LACS_STANDARD_REWARD); + mOptions[index].SetContextIndex(RO_LACS_STANDARD_REWARD); } else if (it.value() == "Greg as Reward") { - mOptions[index].SetSelectedIndex(RO_LACS_GREG_REWARD); + mOptions[index].SetContextIndex(RO_LACS_GREG_REWARD); } else if (it.value() == "Greg as Wildcard") { - mOptions[index].SetSelectedIndex(RO_LACS_WILDCARD_REWARD); + mOptions[index].SetContextIndex(RO_LACS_WILDCARD_REWARD); } break; case RSK_DAMAGE_MULTIPLIER: if (it.value() == "x1/2") { - mOptions[index].SetSelectedIndex(RO_DAMAGE_MULTIPLIER_HALF); + mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_HALF); } else if (it.value() == "x1") { - mOptions[index].SetSelectedIndex(RO_DAMAGE_MULTIPLIER_DEFAULT); + mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_DEFAULT); } else if (it.value() == "x2") { - mOptions[index].SetSelectedIndex(RO_DAMAGE_MULTIPLIER_DOUBLE); + mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_DOUBLE); } else if (it.value() == "x4") { - mOptions[index].SetSelectedIndex(RO_DAMAGE_MULTIPLIER_QUADRUPLE); + mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_QUADRUPLE); } else if (it.value() == "x8") { - mOptions[index].SetSelectedIndex(RO_DAMAGE_MULTIPLIER_OCTUPLE); + mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_OCTUPLE); } else if (it.value() == "x16") { - mOptions[index].SetSelectedIndex(RO_DAMAGE_MULTIPLIER_SEXDECUPLE); + mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_SEXDECUPLE); } else if (it.value() == "OHKO") { - mOptions[index].SetSelectedIndex(RO_DAMAGE_MULTIPLIER_OHKO); + mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_OHKO); } break; case RSK_RAINBOW_BRIDGE_STONE_COUNT: @@ -2709,7 +2745,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_STARTING_SKULLTULA_TOKEN: case RSK_SHOPSANITY_COUNT: numericValueString = it.value(); - mOptions[index].SetSelectedIndex(std::stoi(numericValueString)); + mOptions[index].SetContextIndex(std::stoi(numericValueString)); break; // Same as the above section, but the indexes are off by one from the text // (i.e. 10 Big Poes is index 9). @@ -2718,49 +2754,49 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_TRIFORCE_HUNT_PIECES_REQUIRED: case RSK_STARTING_HEARTS: numericValueString = it.value(); - mOptions[index].SetSelectedIndex(std::stoi(numericValueString) - 1); + mOptions[index].SetContextIndex(std::stoi(numericValueString) - 1); break; case RSK_GANONS_TRIALS: if (it.value() == "Skip") { - mOptions[index].SetSelectedIndex(RO_GANONS_TRIALS_SKIP); + mOptions[index].SetContextIndex(RO_GANONS_TRIALS_SKIP); } else if (it.value() == "Set Number") { - mOptions[index].SetSelectedIndex(RO_GANONS_TRIALS_SET_NUMBER); + mOptions[index].SetContextIndex(RO_GANONS_TRIALS_SET_NUMBER); } else if (it.value() == "Random Number") { - mOptions[index].SetSelectedIndex(RO_GANONS_TRIALS_RANDOM_NUMBER); + mOptions[index].SetContextIndex(RO_GANONS_TRIALS_RANDOM_NUMBER); } case RSK_SHOPSANITY: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_SHOPSANITY_OFF); + mOptions[index].SetContextIndex(RO_SHOPSANITY_OFF); } else if (it.value() == "Specific Count") { - mOptions[index].SetSelectedIndex(RO_SHOPSANITY_SPECIFIC_COUNT); + mOptions[index].SetContextIndex(RO_SHOPSANITY_SPECIFIC_COUNT); } else if (it.value() == "Random") { - mOptions[index].SetSelectedIndex(RO_SHOPSANITY_RANDOM); + mOptions[index].SetContextIndex(RO_SHOPSANITY_RANDOM); } break; case RSK_SHOPSANITY_PRICES: case RSK_SCRUBS_PRICES: case RSK_MERCHANT_PRICES: if (it.value() == "Vanilla") { - mOptions[index].SetSelectedIndex(RO_PRICE_VANILLA); + mOptions[index].SetContextIndex(RO_PRICE_VANILLA); } else if (it.value() == "Cheap Balanced") { - mOptions[index].SetSelectedIndex(RO_PRICE_CHEAP_BALANCED); + mOptions[index].SetContextIndex(RO_PRICE_CHEAP_BALANCED); } else if (it.value() == "Balanced") { - mOptions[index].SetSelectedIndex(RO_PRICE_BALANCED); + mOptions[index].SetContextIndex(RO_PRICE_BALANCED); } else if (it.value() == "Fixed") { - mOptions[index].SetSelectedIndex(RO_PRICE_FIXED); + mOptions[index].SetContextIndex(RO_PRICE_FIXED); } else if (it.value() == "Range") { - mOptions[index].SetSelectedIndex(RO_PRICE_RANGE); + mOptions[index].SetContextIndex(RO_PRICE_RANGE); } else if (it.value() == "Set By Wallet") { - mOptions[index].SetSelectedIndex(RO_PRICE_SET_BY_WALLET); + mOptions[index].SetContextIndex(RO_PRICE_SET_BY_WALLET); } break; case RSK_SHUFFLE_SCRUBS: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_SCRUBS_OFF); + mOptions[index].SetContextIndex(RO_SCRUBS_OFF); } else if (it.value() == "Major Items Only") { - mOptions[index].SetSelectedIndex(RO_SCRUBS_MAJOR_ONLY); + mOptions[index].SetContextIndex(RO_SCRUBS_MAJOR_ONLY); } else if (it.value() == "All") { - mOptions[index].SetSelectedIndex(RO_SCRUBS_ALL); + mOptions[index].SetContextIndex(RO_SCRUBS_ALL); } break; case RSK_SHUFFLE_FISHING_POLE: @@ -2848,20 +2884,20 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_SHUFFLE_DEKU_NUT_BAG: case RSK_SHUFFLE_DEKU_STICK_BAG: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_GENERIC_OFF); + mOptions[index].SetContextIndex(RO_GENERIC_OFF); } else if (it.value() == "On") { - mOptions[index].SetSelectedIndex(RO_GENERIC_ON); + mOptions[index].SetContextIndex(RO_GENERIC_ON); } break; case RSK_KEYRINGS: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_KEYRINGS_OFF); + mOptions[index].SetContextIndex(RO_KEYRINGS_OFF); } else if (it.value() == "Random") { - mOptions[index].SetSelectedIndex(RO_KEYRINGS_RANDOM); + mOptions[index].SetContextIndex(RO_KEYRINGS_RANDOM); } else if (it.value() == "Count") { - mOptions[index].SetSelectedIndex(RO_KEYRINGS_COUNT); + mOptions[index].SetContextIndex(RO_KEYRINGS_COUNT); } else if (it.value() == "Selection") { - mOptions[index].SetSelectedIndex(RO_KEYRINGS_SELECTION); + mOptions[index].SetContextIndex(RO_KEYRINGS_SELECTION); } break; case RSK_KEYRINGS_GERUDO_FORTRESS: @@ -2874,283 +2910,284 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_KEYRINGS_GTG: case RSK_KEYRINGS_GANONS_CASTLE: if (it.value() == "No") { - mOptions[index].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_OFF); + mOptions[index].SetContextIndex(RO_KEYRING_FOR_DUNGEON_OFF); } else if (it.value() == "Random") { - mOptions[index].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_RANDOM); + mOptions[index].SetContextIndex(RO_KEYRING_FOR_DUNGEON_RANDOM); } else if (it.value() == "Yes") { - mOptions[index].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_ON); + mOptions[index].SetContextIndex(RO_KEYRING_FOR_DUNGEON_ON); } break; case RSK_SHUFFLE_MERCHANTS: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_OFF); + mOptions[index].SetContextIndex(RO_SHUFFLE_MERCHANTS_OFF); } else if (it.value() == "Beans Only") { - mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_BEANS_ONLY); + mOptions[index].SetContextIndex(RO_SHUFFLE_MERCHANTS_BEANS_ONLY); } else if (it.value() == "All but Beans") { - mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS); + mOptions[index].SetContextIndex(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS); } else if (it.value() == "All") { - mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_ALL); + mOptions[index].SetContextIndex(RO_SHUFFLE_MERCHANTS_ALL); } break; // Uses Ammo Drops option for now. "Off" not yet implemented // TODO: Change to Ammo Drops case RSK_ENABLE_BOMBCHU_DROPS: if (it.value() == "Yes") { - mOptions[index].SetSelectedIndex(RO_AMMO_DROPS_ON); + mOptions[index].SetContextIndex(RO_AMMO_DROPS_ON); // } else if (it.value() == "On + Bombchu") { - // mOptions[index].SetSelectedIndex(RO_AMMO_DROPS_ON_PLUS_BOMBCHU); + // mOptions[index].SetContextIndex(RO_AMMO_DROPS_ON_PLUS_BOMBCHU); } else if (it.value() == "No") { - mOptions[index].SetSelectedIndex(RO_AMMO_DROPS_OFF); + mOptions[index].SetContextIndex(RO_AMMO_DROPS_OFF); } break; case RSK_FISHSANITY: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_FISHSANITY_OFF); + mOptions[index].SetContextIndex(RO_FISHSANITY_OFF); } else if (it.value() == "Shuffle Fishing Pond") { - mOptions[index].SetSelectedIndex(RO_FISHSANITY_POND); + mOptions[index].SetContextIndex(RO_FISHSANITY_POND); } else if (it.value() == "Shuffle Overworld Fish") { - mOptions[index].SetSelectedIndex(RO_FISHSANITY_OVERWORLD); + mOptions[index].SetContextIndex(RO_FISHSANITY_OVERWORLD); } else if (it.value() == "Shuffle Both") { - mOptions[index].SetSelectedIndex(RO_FISHSANITY_BOTH); + mOptions[index].SetContextIndex(RO_FISHSANITY_BOTH); } break; case RSK_SHUFFLE_BOSS_SOULS: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_BOSS_SOULS_OFF); + mOptions[index].SetContextIndex(RO_BOSS_SOULS_OFF); } else if (it.value() == "On") { - mOptions[index].SetSelectedIndex(RO_BOSS_SOULS_ON); + mOptions[index].SetContextIndex(RO_BOSS_SOULS_ON); } else if (it.value() == "On + Ganon") { - mOptions[index].SetSelectedIndex(RO_BOSS_SOULS_ON_PLUS_GANON); + mOptions[index].SetContextIndex(RO_BOSS_SOULS_ON_PLUS_GANON); } case RSK_STARTING_OCARINA: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_STARTING_OCARINA_OFF); + mOptions[index].SetContextIndex(RO_STARTING_OCARINA_OFF); } else if (it.value() == "Fairy Ocarina") { - mOptions[index].SetSelectedIndex(RO_STARTING_OCARINA_FAIRY); + mOptions[index].SetContextIndex(RO_STARTING_OCARINA_FAIRY); } break; case RSK_ITEM_POOL: if (it.value() == "Plentiful") { - mOptions[index].SetSelectedIndex(RO_ITEM_POOL_PLENTIFUL); + mOptions[index].SetContextIndex(RO_ITEM_POOL_PLENTIFUL); } else if (it.value() == "Balanced") { - mOptions[index].SetSelectedIndex(RO_ITEM_POOL_BALANCED); + mOptions[index].SetContextIndex(RO_ITEM_POOL_BALANCED); } else if (it.value() == "Scarce") { - mOptions[index].SetSelectedIndex(RO_ITEM_POOL_SCARCE); + mOptions[index].SetContextIndex(RO_ITEM_POOL_SCARCE); } else if (it.value() == "Minimal") { - mOptions[index].SetSelectedIndex(RO_ITEM_POOL_MINIMAL); + mOptions[index].SetContextIndex(RO_ITEM_POOL_MINIMAL); } break; case RSK_ICE_TRAPS: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_ICE_TRAPS_OFF); + mOptions[index].SetContextIndex(RO_ICE_TRAPS_OFF); } else if (it.value() == "Normal") { - mOptions[index].SetSelectedIndex(RO_ICE_TRAPS_NORMAL); + mOptions[index].SetContextIndex(RO_ICE_TRAPS_NORMAL); } else if (it.value() == "Extra") { - mOptions[index].SetSelectedIndex(RO_ICE_TRAPS_EXTRA); + mOptions[index].SetContextIndex(RO_ICE_TRAPS_EXTRA); } else if (it.value() == "Mayhem") { - mOptions[index].SetSelectedIndex(RO_ICE_TRAPS_MAYHEM); + mOptions[index].SetContextIndex(RO_ICE_TRAPS_MAYHEM); } else if (it.value() == "Onslaught") { - mOptions[index].SetSelectedIndex(RO_ICE_TRAPS_ONSLAUGHT); + mOptions[index].SetContextIndex(RO_ICE_TRAPS_ONSLAUGHT); } break; case RSK_GOSSIP_STONE_HINTS: if (it.value() == "No Hints") { - mOptions[index].SetSelectedIndex(RO_GOSSIP_STONES_NONE); + mOptions[index].SetContextIndex(RO_GOSSIP_STONES_NONE); } else if (it.value() == "Need Nothing") { - mOptions[index].SetSelectedIndex(RO_GOSSIP_STONES_NEED_NOTHING); + mOptions[index].SetContextIndex(RO_GOSSIP_STONES_NEED_NOTHING); } else if (it.value() == "Mask of Truth") { - mOptions[index].SetSelectedIndex(RO_GOSSIP_STONES_NEED_TRUTH); + mOptions[index].SetContextIndex(RO_GOSSIP_STONES_NEED_TRUTH); } else if (it.value() == "Stone of Agony") { - mOptions[index].SetSelectedIndex(RO_GOSSIP_STONES_NEED_STONE); + mOptions[index].SetContextIndex(RO_GOSSIP_STONES_NEED_STONE); } break; case RSK_HINT_CLARITY: if (it.value() == "Obscure") { - mOptions[index].SetSelectedIndex(RO_HINT_CLARITY_OBSCURE); + mOptions[index].SetContextIndex(RO_HINT_CLARITY_OBSCURE); } else if (it.value() == "Ambiguous") { - mOptions[index].SetSelectedIndex(RO_HINT_CLARITY_AMBIGUOUS); + mOptions[index].SetContextIndex(RO_HINT_CLARITY_AMBIGUOUS); } else if (it.value() == "Clear") { - mOptions[index].SetSelectedIndex(RO_HINT_CLARITY_CLEAR); + mOptions[index].SetContextIndex(RO_HINT_CLARITY_CLEAR); } break; case RSK_HINT_DISTRIBUTION: if (it.value() == "Useless") { - mOptions[index].SetSelectedIndex(RO_HINT_DIST_USELESS); + mOptions[index].SetContextIndex(RO_HINT_DIST_USELESS); } else if (it.value() == "Balanced") { - mOptions[index].SetSelectedIndex(RO_HINT_DIST_BALANCED); + mOptions[index].SetContextIndex(RO_HINT_DIST_BALANCED); } else if (it.value() == "Strong") { - mOptions[index].SetSelectedIndex(RO_HINT_DIST_STRONG); + mOptions[index].SetContextIndex(RO_HINT_DIST_STRONG); } else if (it.value() == "Very Strong") { - mOptions[index].SetSelectedIndex(RO_HINT_DIST_VERY_STRONG); + mOptions[index].SetContextIndex(RO_HINT_DIST_VERY_STRONG); } break; case RSK_GERUDO_KEYS: if (it.value() == "Vanilla") { - mOptions[index].SetSelectedIndex(RO_GERUDO_KEYS_VANILLA); + mOptions[index].SetContextIndex(RO_GERUDO_KEYS_VANILLA); } else if (it.value() == "Any Dungeon") { - mOptions[index].SetSelectedIndex(RO_GERUDO_KEYS_ANY_DUNGEON); + mOptions[index].SetContextIndex(RO_GERUDO_KEYS_ANY_DUNGEON); } else if (it.value() == "Overworld") { - mOptions[index].SetSelectedIndex(RO_GERUDO_KEYS_OVERWORLD); + mOptions[index].SetContextIndex(RO_GERUDO_KEYS_OVERWORLD); } else if (it.value() == "Anywhere") { - mOptions[index].SetSelectedIndex(RO_GERUDO_KEYS_ANYWHERE); + mOptions[index].SetContextIndex(RO_GERUDO_KEYS_ANYWHERE); } break; case RSK_KEYSANITY: case RSK_BOSS_KEYSANITY: case RSK_SHUFFLE_MAPANDCOMPASS: if (it.value() == "Start With") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ITEM_LOC_STARTWITH); + mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_STARTWITH); } else if (it.value() == "Vanilla") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ITEM_LOC_VANILLA); + mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_VANILLA); } else if (it.value() == "Own Dungeon") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); + mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); } else if (it.value() == "Any Dungeon") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON); + mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON); } else if (it.value() == "Overworld") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ITEM_LOC_OVERWORLD); + mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_OVERWORLD); } else if (it.value() == "Anywhere") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ITEM_LOC_ANYWHERE); + mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_ANYWHERE); } break; case RSK_GANONS_BOSS_KEY: if (it.value() == "Vanilla") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_VANILLA); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_VANILLA); } else if (it.value() == "Own dungeon") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_OWN_DUNGEON); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_OWN_DUNGEON); } else if (it.value() == "Start with") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_STARTWITH); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_STARTWITH); } else if (it.value() == "Any Dungeon") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_ANY_DUNGEON); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_ANY_DUNGEON); } else if (it.value() == "Overworld") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_OVERWORLD); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_OVERWORLD); } else if (it.value() == "Anywhere") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_ANYWHERE); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_ANYWHERE); } else if (it.value() == "LACS-Vanilla") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_LACS_VANILLA); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_VANILLA); } else if (it.value() == "LACS-Stones") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_LACS_STONES); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_STONES); } else if (it.value() == "LACS-Medallions") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_LACS_MEDALLIONS); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_MEDALLIONS); } else if (it.value() == "LACS-Rewards") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_LACS_REWARDS); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_REWARDS); } else if (it.value() == "LACS-Dungeons") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_LACS_DUNGEONS); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_DUNGEONS); } else if (it.value() == "LACS-Tokens") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_LACS_TOKENS); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_TOKENS); } else if (it.value() == "100 GS Reward") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_KAK_TOKENS); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_KAK_TOKENS); } else if (it.value() == "Triforce Hunt") { - mOptions[index].SetSelectedIndex(RO_GANON_BOSS_KEY_TRIFORCE_HUNT); + mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_TRIFORCE_HUNT); } break; case RSK_MQ_DUNGEON_RANDOM: if (it.value() == "None") { - mOptions[index].SetSelectedIndex(RO_MQ_DUNGEONS_NONE); + mOptions[index].SetContextIndex(RO_MQ_DUNGEONS_NONE); } else if (it.value() == "Random Number") { - mOptions[index].SetSelectedIndex(RO_MQ_DUNGEONS_RANDOM_NUMBER); + mOptions[index].SetContextIndex(RO_MQ_DUNGEONS_RANDOM_NUMBER); } else if (it.value() == "Set Number") { - mOptions[index].SetSelectedIndex(RO_MQ_DUNGEONS_SET_NUMBER); + mOptions[index].SetContextIndex(RO_MQ_DUNGEONS_SET_NUMBER); } else if (it.value() == "Selection Only") { - mOptions[index].SetSelectedIndex(RO_MQ_DUNGEONS_SELECTION); + mOptions[index].SetContextIndex(RO_MQ_DUNGEONS_SELECTION); } break; - case RSK_STARTING_CONSUMABLES: + case RSK_STARTING_STICKS: + case RSK_STARTING_NUTS: case RSK_FULL_WALLETS: if (it.value() == "No") { - mOptions[index].SetSelectedIndex(RO_GENERIC_NO); + mOptions[index].SetContextIndex(RO_GENERIC_NO); } else if (it.value() == "Yes") { - mOptions[index].SetSelectedIndex(RO_GENERIC_YES); + mOptions[index].SetContextIndex(RO_GENERIC_YES); } break; case RSK_SKIP_CHILD_ZELDA: case RSK_SKIP_CHILD_STEALTH: case RSK_SKIP_EPONA_RACE: if (it.value() == "Don't Skip") { - mOptions[index].SetSelectedIndex(RO_GENERIC_DONT_SKIP); + mOptions[index].SetContextIndex(RO_GENERIC_DONT_SKIP); } else if (it.value() == "Skip") { - mOptions[index].SetSelectedIndex(RO_GENERIC_SKIP); + mOptions[index].SetContextIndex(RO_GENERIC_SKIP); } break; case RSK_SHUFFLE_DUNGEON_REWARDS: if (it.value() == "End of dungeons") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_REWARDS_END_OF_DUNGEON); + mOptions[index].SetContextIndex(RO_DUNGEON_REWARDS_END_OF_DUNGEON); } else if (it.value() == "Any dungeon") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_REWARDS_ANY_DUNGEON); + mOptions[index].SetContextIndex(RO_DUNGEON_REWARDS_ANY_DUNGEON); } else if (it.value() == "Overworld") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_REWARDS_OVERWORLD); + mOptions[index].SetContextIndex(RO_DUNGEON_REWARDS_OVERWORLD); } else if (it.value() == "Anywhere") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_REWARDS_ANYWHERE); + mOptions[index].SetContextIndex(RO_DUNGEON_REWARDS_ANYWHERE); } break; case RSK_SHUFFLE_SONGS: if (it.value() == "Song locations") { - mOptions[index].SetSelectedIndex(RO_SONG_SHUFFLE_SONG_LOCATIONS); + mOptions[index].SetContextIndex(RO_SONG_SHUFFLE_SONG_LOCATIONS); } else if (it.value() == "Dungeon rewards") { - mOptions[index].SetSelectedIndex(RO_SONG_SHUFFLE_DUNGEON_REWARDS); + mOptions[index].SetContextIndex(RO_SONG_SHUFFLE_DUNGEON_REWARDS); } else if (it.value() == "Anywhere") { - mOptions[index].SetSelectedIndex(RO_SONG_SHUFFLE_ANYWHERE); + mOptions[index].SetContextIndex(RO_SONG_SHUFFLE_ANYWHERE); } break; case RSK_SHUFFLE_TOKENS: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_TOKENSANITY_OFF); + mOptions[index].SetContextIndex(RO_TOKENSANITY_OFF); } else if (it.value() == "Dungeons") { - mOptions[index].SetSelectedIndex(RO_TOKENSANITY_DUNGEONS); + mOptions[index].SetContextIndex(RO_TOKENSANITY_DUNGEONS); } else if (it.value() == "Overworld") { - mOptions[index].SetSelectedIndex(RO_TOKENSANITY_OVERWORLD); + mOptions[index].SetContextIndex(RO_TOKENSANITY_OVERWORLD); } else if (it.value() == "All Tokens") { - mOptions[index].SetSelectedIndex(RO_TOKENSANITY_ALL); + mOptions[index].SetContextIndex(RO_TOKENSANITY_ALL); } break; case RSK_LINKS_POCKET: if (it.value() == "Dungeon Reward") { - mOptions[index].SetSelectedIndex(RO_LINKS_POCKET_DUNGEON_REWARD); + mOptions[index].SetContextIndex(RO_LINKS_POCKET_DUNGEON_REWARD); } else if (it.value() == "Advancement") { - mOptions[index].SetSelectedIndex(RO_LINKS_POCKET_ADVANCEMENT); + mOptions[index].SetContextIndex(RO_LINKS_POCKET_ADVANCEMENT); } else if (it.value() == "Anything") { - mOptions[index].SetSelectedIndex(RO_LINKS_POCKET_ANYTHING); + mOptions[index].SetContextIndex(RO_LINKS_POCKET_ANYTHING); } else if (it.value() == "Nothing") { - mOptions[index].SetSelectedIndex(RO_LINKS_POCKET_NOTHING); + mOptions[index].SetContextIndex(RO_LINKS_POCKET_NOTHING); } break; case RSK_MQ_DUNGEON_COUNT: numericValueString = it.value(); - mOptions[index].SetSelectedIndex(std::stoi(numericValueString)); + mOptions[index].SetContextIndex(std::stoi(numericValueString)); break; case RSK_SHUFFLE_DUNGEON_ENTRANCES: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF); + mOptions[index].SetContextIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF); } else if (it.value() == "On") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_ON); + mOptions[index].SetContextIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_ON); } else if (it.value() == "On + Ganon") { - mOptions[index].SetSelectedIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_ON_PLUS_GANON); + mOptions[index].SetContextIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_ON_PLUS_GANON); } break; case RSK_SHUFFLE_BOSS_ENTRANCES: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); + mOptions[index].SetContextIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); } else if (it.value() == "Age Restricted") { - mOptions[index].SetSelectedIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_AGE_RESTRICTED); + mOptions[index].SetContextIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_AGE_RESTRICTED); } else if (it.value() == "Full") { - mOptions[index].SetSelectedIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL); + mOptions[index].SetContextIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL); } break; case RSK_SHUFFLE_INTERIOR_ENTRANCES: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_OFF); + mOptions[index].SetContextIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_OFF); } else if (it.value() == "Simple") { - mOptions[index].SetSelectedIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_SIMPLE); + mOptions[index].SetContextIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_SIMPLE); } else if (it.value() == "All") { - mOptions[index].SetSelectedIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_ALL); + mOptions[index].SetContextIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_ALL); } break; case RSK_SHUFFLE_CHEST_MINIGAME: if (it.value() == "Off") { - mOptions[index].SetSelectedIndex(RO_CHEST_GAME_OFF); + mOptions[index].SetContextIndex(RO_CHEST_GAME_OFF); } else if (it.value() == "On (Separate)") { - mOptions[index].SetSelectedIndex(RO_CHEST_GAME_SINGLE_KEYS); + mOptions[index].SetContextIndex(RO_CHEST_GAME_SINGLE_KEYS); } else if (it.value() == "On (Pack)") { - mOptions[index].SetSelectedIndex(RO_CHEST_GAME_PACK); + mOptions[index].SetContextIndex(RO_CHEST_GAME_PACK); } break; case RSK_MQ_DEKU_TREE: @@ -3166,11 +3203,11 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_MQ_GTG: case RSK_MQ_GANONS_CASTLE: if (it.value() == "Vanilla") { - mOptions[index].SetSelectedIndex(RO_MQ_SET_VANILLA); + mOptions[index].SetContextIndex(RO_MQ_SET_VANILLA); } else if (it.value() == "Master Quest") { - mOptions[index].SetSelectedIndex(RO_MQ_SET_MQ); + mOptions[index].SetContextIndex(RO_MQ_SET_MQ); } else if (it.value() == "Random") { - mOptions[index].SetSelectedIndex(RO_MQ_SET_RANDOM); + mOptions[index].SetContextIndex(RO_MQ_SET_RANDOM); } break; default: @@ -3186,13 +3223,13 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { ctx->AddExcludedOptions(); for (auto it = jsonExcludedLocations.begin(); it != jsonExcludedLocations.end(); ++it) { const RandomizerCheck rc = Rando::StaticData::locationNameToEnum[it.value()]; - ctx->GetItemLocation(rc)->GetExcludedOption()->SetSelectedIndex(RO_GENERIC_ON); + ctx->GetItemLocation(rc)->GetExcludedOption()->SetContextIndex(RO_GENERIC_ON); } nlohmann::json enabledTricksJson = spoilerFileJson["enabledTricks"]; for (auto it = enabledTricksJson.begin(); it != enabledTricksJson.end(); ++it) { const RandomizerTrick rt = mTrickNameToEnum[it.value()]; - GetTrickOption(rt).SetSelectedIndex(RO_GENERIC_ON); + GetTrickOption(rt).SetContextIndex(RO_GENERIC_ON); } } diff --git a/soh/soh/Enhancements/randomizer/static_data.cpp b/soh/soh/Enhancements/randomizer/static_data.cpp index 5c6f7903b..15697d9e0 100644 --- a/soh/soh/Enhancements/randomizer/static_data.cpp +++ b/soh/soh/Enhancements/randomizer/static_data.cpp @@ -13,7 +13,7 @@ std::unordered_map StaticData::hintTypeNames = { {HINT_TYPE_ITEM_AREA, CustomMessage("Item Area")}, {HINT_TYPE_ALTAR_CHILD, CustomMessage("Child Altar")}, {HINT_TYPE_ALTAR_ADULT, CustomMessage("Adult Altar")}, - {HINT_TYPE_WOTH, CustomMessage("Way of the Hero")}, + {HINT_TYPE_WOTH, CustomMessage("Way of the Hero")}, {HINT_TYPE_FOOLISH, CustomMessage("Foolish")}, {HINT_TYPE_MESSAGE, CustomMessage("Hardcoded Message")} }; @@ -60,7 +60,7 @@ std::unordered_map StaticData::hintNames = { {RH_LH_SOUTHEAST_GOSSIP_STONE, CustomMessage("LH Southeast Gossip Stone")}, {RH_LH_SOUTHWEST_GOSSIP_STONE, CustomMessage("LH Southwest Gossip Stone")}, {RH_GV_GOSSIP_STONE, CustomMessage("Gerudo Valley Gossip Stone")}, - {RH_COLOSSUS_GOSSIP_STONE, CustomMessage("Desert Collosus Gossip Stone")}, + {RH_COLOSSUS_GOSSIP_STONE, CustomMessage("Desert Colossus Gossip Stone")}, {RH_DODONGOS_CAVERN_GOSSIP_STONE, CustomMessage("Dodongo's Cavern Gossip Stone")}, {RH_GANONDORF_HINT, CustomMessage("Ganondorf Hint")}, {RH_GANONDORF_JOKE, CustomMessage("Ganondorf Joke")}, @@ -189,7 +189,7 @@ std::unordered_map StaticData::trialData = { std::unordered_map StaticData::staticHintInfoMap = { // RH_GANONDORF_HINT is special cased due to being different based on master sword shuffle // Altar hints are special cased due to special hint marking rules - // warp song hints are special cased due to entrences not being done properly yet + // warp song hints are special cased due to entrances not being done properly yet // Ganondorf Joke is special cased as the text is random {RH_SHEIK_HINT, StaticHintInfo(HINT_TYPE_AREA, {RHT_SHEIK_HINT_LA_ONLY}, RSK_SHEIK_LA_HINT, true, {}, {RG_LIGHT_ARROWS}, {RC_SHEIK_HINT_GC, RC_SHEIK_HINT_MQ_GC}, true)}, {RH_DAMPES_DIARY, StaticHintInfo(HINT_TYPE_AREA, {RHT_DAMPE_DIARY}, RSK_DAMPES_DIARY_HINT, true, {}, {RG_PROGRESSIVE_HOOKSHOT}, {RC_DAMPE_HINT})}, @@ -301,4 +301,4 @@ std::unordered_map StaticData::grottoChestParamsToHint{ }; std::array StaticData::hintTextTable = {}; -} \ No newline at end of file +} diff --git a/soh/soh/Enhancements/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/timesaver_hook_handlers.cpp index d3b478dfc..581ec2781 100644 --- a/soh/soh/Enhancements/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/timesaver_hook_handlers.cpp @@ -35,10 +35,13 @@ extern SaveContext gSaveContext; extern PlayState* gPlayState; extern int32_t D_8011D3AC; +extern void func_808ADEF0(BgSpot03Taki* bgSpot03Taki, PlayState* play); +extern void BgSpot03Taki_ApplyOpeningAlpha(BgSpot03Taki* bgSpot03Taki, s32 bufferIndex); + extern void func_80AF36EC(EnRu2* enRu2, PlayState* play); } -#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetSelectedOptionIndex() +#define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetContextOptionIndex() void EnMa1_EndTeachSong(EnMa1* enMa1, PlayState* play) { if (Message_GetState(&gPlayState->msgCtx) == TEXT_STATE_CLOSING) { @@ -96,6 +99,9 @@ void EnDntDemo_JudgeSkipToReward(EnDntDemo* enDntDemo, PlayState* play) { } } +void BgSpot03Taki_KeepOpen(BgSpot03Taki* bgSpot03Taki, PlayState* play) { +} + static int successChimeCooldown = 0; void RateLimitedSuccessChime() { if (successChimeCooldown == 0) { @@ -263,7 +269,7 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li // The switch in jabu that you are intended to press with a box to reach barrinade // can be skipped by either a frame perfect roll open or with OI // The One Point for that switch is used in common setups for the former and is required for the latter to work - if (actor->params == 14848 && gPlayState->sceneNum == SCENE_JABU_JABU && !CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)){ + if (actor->params == 14848 && gPlayState->sceneNum == SCENE_JABU_JABU && CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)){ break; } BgBdanSwitch* switchActor = (BgBdanSwitch*)actor; @@ -280,19 +286,11 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li RateLimitedSuccessChime(); break; } - case ACTOR_BG_HIDAN_FWBIG: { - *should = false; - break; - } - case ACTOR_EN_EX_ITEM: { - *should = false; - break; - } - case ACTOR_EN_DNT_NOMAL: { - *should = false; - break; - } - case ACTOR_EN_DNT_DEMO: { + case ACTOR_BG_HIDAN_FWBIG: + case ACTOR_EN_EX_ITEM: + case ACTOR_EN_DNT_NOMAL: + case ACTOR_EN_DNT_DEMO: + case ACTOR_BG_HAKA_ZOU: { *should = false; break; } @@ -311,6 +309,8 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li case ACTOR_BG_SPOT18_BASKET: case ACTOR_BG_HIDAN_CURTAIN: case ACTOR_BG_MORI_HINERI: + case ACTOR_BG_MIZU_SHUTTER: + case ACTOR_SHOT_SUN: *should = false; RateLimitedSuccessChime(); break; @@ -699,6 +699,8 @@ static uint32_t enFuUpdateHook = 0; static uint32_t enFuKillHook = 0; static uint32_t bgSpot02UpdateHook = 0; static uint32_t bgSpot02KillHook = 0; +static uint32_t bgSpot03UpdateHook = 0; +static uint32_t bgSpot03KillHook = 0; static uint32_t enPoSistersUpdateHook = 0; static uint32_t enPoSistersKillHook = 0; void TimeSaverOnActorInitHandler(void* actorRef) { @@ -754,6 +756,10 @@ void TimeSaverOnActorInitHandler(void* actorRef) { }); } + if (actor->id == ACTOR_EN_OWL && gPlayState->sceneNum == SCENE_ZORAS_RIVER && CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall"), 0) == 2) { + Actor_Kill(actor); + } + if (actor->id == ACTOR_BG_SPOT02_OBJECTS && actor->params == 2) { bgSpot02UpdateHook = GameInteractor::Instance->RegisterGameHook([](void* innerActorRef) mutable { Actor* innerActor = static_cast(innerActorRef); @@ -776,6 +782,61 @@ void TimeSaverOnActorInitHandler(void* actorRef) { }); } + if (actor->id == ACTOR_BG_SPOT03_TAKI) { + bgSpot03UpdateHook = GameInteractor::Instance->RegisterGameHook([](void* innerActorRef) mutable { + Actor* innerActor = static_cast(innerActorRef); + + if (innerActor->id != ACTOR_BG_SPOT03_TAKI) { + return; + } + + bool shouldKeepOpen; + switch (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall"), 0)) { + case 1: + shouldKeepOpen = Flags_GetEventChkInf(EVENTCHKINF_OPENED_ZORAS_DOMAIN); + break; + case 2: + if (IS_RANDO && RAND_GET_OPTION(RSK_SLEEPING_WATERFALL) == RO_WATERFALL_OPEN) { + shouldKeepOpen = true; + } else { + shouldKeepOpen = CHECK_QUEST_ITEM(QUEST_SONG_LULLABY) && + (INV_CONTENT(ITEM_OCARINA_TIME) == ITEM_OCARINA_TIME || + INV_CONTENT(ITEM_OCARINA_FAIRY) == ITEM_OCARINA_FAIRY); + } + break; + default: + shouldKeepOpen = false; + break; + } + + if (!shouldKeepOpen) { + return; + } + + BgSpot03Taki* bgSpot03 = static_cast(innerActorRef); + if (bgSpot03->actionFunc == func_808ADEF0) { + bgSpot03->actionFunc = BgSpot03Taki_KeepOpen; + bgSpot03->state = WATERFALL_OPENED; + bgSpot03->openingAlpha = 0.0f; + Flags_SetSwitch(gPlayState, bgSpot03->switchFlag); + func_8003EBF8(gPlayState, &gPlayState->colCtx.dyna, bgSpot03->dyna.bgId); + BgSpot03Taki_ApplyOpeningAlpha(bgSpot03, 0); + BgSpot03Taki_ApplyOpeningAlpha(bgSpot03, 1); + + GameInteractor::Instance->UnregisterGameHook(bgSpot03UpdateHook); + GameInteractor::Instance->UnregisterGameHook(bgSpot03KillHook); + bgSpot03UpdateHook = 0; + bgSpot03KillHook = 0; + } + }); + bgSpot03KillHook = GameInteractor::Instance->RegisterGameHook([](int16_t sceneNum) mutable { + GameInteractor::Instance->UnregisterGameHook(bgSpot03UpdateHook); + GameInteractor::Instance->UnregisterGameHook(bgSpot03KillHook); + bgSpot03UpdateHook = 0; + bgSpot03KillHook = 0; + }); + } + if (actor->id == ACTOR_EN_DNT_DEMO && (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO))) { EnDntDemo* enDntDemo = static_cast(actorRef); enDntDemo->actionFunc = EnDntDemo_JudgeSkipToReward; @@ -786,7 +847,7 @@ void TimeSaverOnActorInitHandler(void* actorRef) { // or poes from which the cutscene is triggered until we can have a "BeforeActorInit" hook. // So for now we're just going to set the flag before they get to the room the cutscene is in if (gPlayState->sceneNum == SCENE_FOREST_TEMPLE && actor->id == ACTOR_EN_ST && !Flags_GetSwitch(gPlayState, 0x1B)) { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) { + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), 0) && !CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) { Flags_SetSwitch(gPlayState, 0x1B); } } @@ -812,7 +873,7 @@ void TimeSaverOnActorInitHandler(void* actorRef) { // Fire Temple Darunia cutscene if (actor->id == ACTOR_EN_DU && gPlayState->sceneNum == SCENE_FIRE_TEMPLE) { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) { + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), 0) && !CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) { Flags_SetInfTable(INFTABLE_SPOKE_TO_DARUNIA_IN_FIRE_TEMPLE); Actor_Kill(actor); } diff --git a/soh/soh/Enhancements/timesplits/TimeSplits.cpp b/soh/soh/Enhancements/timesplits/TimeSplits.cpp index 7471acfa7..330e39989 100644 --- a/soh/soh/Enhancements/timesplits/TimeSplits.cpp +++ b/soh/soh/Enhancements/timesplits/TimeSplits.cpp @@ -301,6 +301,16 @@ void TimeSplitsGetImageSize(uint32_t item) { } } +void SplitsPushImageButtonStyle(){ + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f)); +} + +void SplitsPopImageButtonStyle(){ + ImGui::PopStyleColor(3); +} + void TimeSplitsUpdateSplitStatus() { uint32_t index = 0; for (auto& data : splitList) { @@ -310,7 +320,7 @@ void TimeSplitsUpdateSplitStatus() { } index++; } - for (int i = index; i < splitList.size(); i++) { + for (size_t i = index; i < splitList.size(); i++) { if (splitList[i].splitTimeStatus != SPLIT_STATUS_ACTIVE && splitList[i].splitTimeStatus != SPLIT_STATUS_COLLECTED) { splitList[i].splitTimeStatus = SPLIT_STATUS_INACTIVE; } @@ -421,11 +431,28 @@ void TimeSplitsPopUpContext() { if (popupID == ITEM_SKULL_TOKEN) { ImGui::BeginTable("Token Table", 2); ImGui::TableNextColumn(); + SplitsPushImageButtonStyle(); ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("QUEST_SKULL_TOKEN"), ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 2.0f, ImVec4(0, 0, 0, 0)); ImGui::TableNextColumn(); + SplitsPopImageButtonStyle(); ImGui::PushItemWidth(150.0f); + + ImGui::BeginGroup(); + std::string MinusBTNName = " - ##Set Tokens"; + ImGui::SameLine(); + if (ImGui::Button(MinusBTNName.c_str()) && skullTokenCount > 0) { + skullTokenCount--; + } + ImGui::SameLine(); ImGui::SliderInt("##count", &skullTokenCount, 0, 100, "%d Tokens"); + std::string PlusBTNName = " + ##Set Tokens"; + ImGui::SameLine(); + if (ImGui::Button(PlusBTNName.c_str()) && skullTokenCount < 100) { + skullTokenCount++; + } + ImGui::EndGroup(); + ImGui::PopItemWidth(); if (ImGui::Button("Set Tokens")) { auto findID = std::find_if(splitObjectList.begin(), splitObjectList.end(), [&](const SplitObject& obj) { return obj.splitID == ITEM_SKULL_TOKEN; }); @@ -442,6 +469,7 @@ void TimeSplitsPopUpContext() { ImGui::EndTable(); } else { int rowIndex = 0; + SplitsPushImageButtonStyle(); for (auto item : popupList[popupID]) { auto findID = std::find_if(splitObjectList.begin(), splitObjectList.end(), [&](const SplitObject& obj) { return obj.splitID == item; }); if (findID == splitObjectList.end()) { @@ -468,7 +496,7 @@ void TimeSplitsPopUpContext() { if (popupID <= ITEM_SLINGSHOT && popupID != -1) { ImVec2 imageMin = ImGui::GetItemRectMin(); ImVec2 imageMax = ImGui::GetItemRectMax(); - ImVec2 imageSize = ImVec2(imageMax.x - imageMin.x, imageMax.y - imageMin.y); + //ImVec2 imageSize = ImVec2(imageMax.x - imageMin.x, imageMax.y - imageMin.y); UNUSED ImVec2 textPos = ImVec2(imageMax.x - ImGui::CalcTextSize("00").x - 5, imageMax.y - ImGui::CalcTextSize("00").y - 5); @@ -484,6 +512,7 @@ void TimeSplitsPopUpContext() { } rowIndex++; } + SplitsPopImageButtonStyle(); } ImGui::EndPopup(); } @@ -610,10 +639,8 @@ void TimeSplitsDrawSplitsList() { ImGui::TableSetupColumn("Prev. Best"); ImGui::TableHeadersRow(); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f)); + SplitsPushImageButtonStyle(); for (auto& split : splitList) { ImGui::TableNextColumn(); TimeSplitsSplitBestTimeDisplay(split); @@ -648,10 +675,10 @@ void TimeSplitsDrawSplitsList() { dragIndex++; } + SplitsPopImageButtonStyle(); TimeSplitsPostDragAndDrop(); - ImGui::PopStyleColor(3); ImGui::PopStyleVar(1); ImGui::EndTable(); ImGui::EndChild(); @@ -677,7 +704,7 @@ void TimeSplitsDrawItemList(uint32_t type) { ImGui::BeginChild("Item Child"); ImGui::BeginTable("Item List", tableSize); - for (int i = 0; i < tableSize; i++) { + for (size_t i = 0; i < tableSize; i++) { if (i == 0) { ImGui::TableSetupColumn("Item Image", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHeaderLabel, 39.0f); } else { @@ -689,15 +716,12 @@ void TimeSplitsDrawItemList(uint32_t type) { } } - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f)); - for (auto& split : splitObjectList) { if (split.splitType == type) { ImGui::TableNextColumn(); ImGui::PushID(split.splitID); TimeSplitsGetImageSize(split.splitID); + SplitsPushImageButtonStyle(); if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(split.splitImage), imageSize, ImVec2(0, 0), ImVec2(1, 1), imagePadding, ImVec4(0, 0, 0, 0), split.splitTint)) { @@ -715,6 +739,7 @@ void TimeSplitsDrawItemList(uint32_t type) { } } } + SplitsPopImageButtonStyle(); TimeSplitsPopUpContext(); ImGui::PopID(); @@ -729,7 +754,6 @@ void TimeSplitsDrawItemList(uint32_t type) { } } - ImGui::PopStyleColor(3); ImGui::EndTable(); ImGui::EndChild(); } diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 0d3548814..87e1fee5a 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -84,6 +84,7 @@ Sail* Sail::Instance; #include "Enhancements/mods.h" #include "Enhancements/game-interactor/GameInteractor.h" #include "Enhancements/randomizer/draw.h" +#include "Enhancements/custom-collectible/CustomCollectible.h" #include // Resource Types/Factories @@ -703,6 +704,7 @@ extern "C" void VanillaItemTable_Init() { GET_ITEM(ITEM_NUT_UPGRADE_30, OBJECT_GI_NUTS, GID_NUTS, 0xA7, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_LESSER, MOD_NONE, GI_NUT_UPGRADE_30), GET_ITEM(ITEM_NUT_UPGRADE_40, OBJECT_GI_NUTS, GID_NUTS, 0xA8, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_LESSER, MOD_NONE, GI_NUT_UPGRADE_40), GET_ITEM(ITEM_BULLET_BAG_50, OBJECT_GI_DEKUPOUCH, GID_BULLET_BAG_50, 0x6C, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_NONE, GI_BULLET_BAG_50), + GET_ITEM(ITEM_SHIP, OBJECT_UNSET_16E, GID_MAXIMUM, 0x00, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_NONE, GI_SHIP), GET_ITEM_NONE, GET_ITEM_NONE, GET_ITEM_NONE // GI_MAX - if you need to add to this table insert it before this entry. @@ -874,6 +876,7 @@ std::unordered_map ItemIDtoRandomizerGetMap { { ITEM_KOKIRI_EMERALD, RG_KOKIRI_EMERALD }, { ITEM_GORON_RUBY, RG_GORON_RUBY }, { ITEM_ZORA_SAPPHIRE, RG_ZORA_SAPPHIRE }, + { ITEM_SWORD_MASTER, RG_MASTER_SWORD }, }; extern "C" RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID) { @@ -1172,6 +1175,7 @@ extern "C" void InitOTR() { DebugConsole_Init(); InitMods(); + CustomCollectible::RegisterHooks(); ActorDB::AddBuiltInCustomActors(); // #region SOH [Randomizer] TODO: Remove these and refactor spoiler file handling for randomizer CVarClear(CVAR_GENERAL("RandomizerNewFileDropped")); @@ -1932,7 +1936,7 @@ extern "C" u32 SpoilerFileExists(const char* spoilerFileName) { } extern "C" u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey) { - return OTRGlobals::Instance->gRandoContext->GetOption(randoSettingKey).GetSelectedOptionIndex(); + return OTRGlobals::Instance->gRandoContext->GetOption(randoSettingKey).GetContextOptionIndex(); } extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams) { @@ -2152,7 +2156,6 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { } else if (textId >= TEXT_SHOP_ITEM_RANDOM_CONFIRM && textId <= TEXT_SHOP_ITEM_RANDOM_CONFIRM_END){ RandomizerCheck rc = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf((RandomizerInf)((textId - TEXT_SHOP_ITEM_RANDOM_CONFIRM) + RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1)); messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(rc, TEXT_SHOP_ITEM_RANDOM_CONFIRM); - // textId: TEXT_SCRUB_RANDOM + (randomizerInf - RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT) } else if (textId == TEXT_SCRUB_RANDOM) { EnDns* enDns = (EnDns*)GET_PLAYER(play)->talkActor; RandomizerCheck rc = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf((RandomizerInf)enDns->sohScrubIdentity.randomizerInf); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index f2cc04fe9..bda7e9392 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -180,7 +180,7 @@ void SaveManager::LoadRandomizerVersion1() { int key, value; SaveManager::Instance->LoadData("sk" + std::to_string(i), key); SaveManager::Instance->LoadData("sv" + std::to_string(i), value); - randoContext->GetOption(RandomizerSettingKey(key)).SetSelectedIndex(value); + randoContext->GetOption(RandomizerSettingKey(key)).SetContextIndex(value); } for (int i = 0; i < 50; i++) { @@ -286,7 +286,7 @@ void SaveManager::LoadRandomizerVersion2() { SaveManager::Instance->LoadArray("randoSettings", RSK_MAX, [&](size_t i) { int value = 0; SaveManager::Instance->LoadData("", value); - randoContext->GetOption(RandomizerSettingKey(i)).SetSelectedIndex(value); + randoContext->GetOption(RandomizerSettingKey(i)).SetContextIndex(value); }); SaveManager::Instance->LoadArray("hintLocations", RH_ZR_OPEN_GROTTO_GOSSIP_STONE + 1, [&](size_t i) { @@ -435,7 +435,7 @@ void SaveManager::LoadRandomizerVersion3() { SaveManager::Instance->LoadArray("randoSettings", RSK_MAX, [&](size_t i) { int value = 0; SaveManager::Instance->LoadData("", value); - randoContext->GetOption(RandomizerSettingKey(i)).SetSelectedIndex(value); + randoContext->GetOption(RandomizerSettingKey(i)).SetContextIndex(value); }); SaveManager::Instance->LoadArray("hintLocations", RH_MAX, [&](size_t i) { @@ -464,7 +464,7 @@ void SaveManager::LoadRandomizerVersion3() { }); randoContext->GetTrials()->SkipAll(); - SaveManager::Instance->LoadArray("requiredTrials", randoContext->GetOption(RSK_TRIAL_COUNT).GetSelectedOptionIndex()+1, [&](size_t i) { + SaveManager::Instance->LoadArray("requiredTrials", randoContext->GetOption(RSK_TRIAL_COUNT).GetContextOptionIndex() + 1, [&](size_t i) { size_t trialId; SaveManager::Instance->LoadData("", trialId); randoContext->GetTrial(trialId)->SetAsRequired(); @@ -513,7 +513,7 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f SaveManager::Instance->SaveData("finalSeed", randoContext->GetSettings()->GetSeed()); SaveManager::Instance->SaveArray("randoSettings", RSK_MAX, [&](size_t i) { - SaveManager::Instance->SaveData("", randoContext->GetOption((RandomizerSettingKey(i))).GetSelectedOptionIndex()); + SaveManager::Instance->SaveData("", randoContext->GetOption((RandomizerSettingKey(i))).GetContextOptionIndex()); }); SaveManager::Instance->SaveArray("hintLocations", RH_MAX, [&](size_t i) { diff --git a/soh/soh/SohGui.cpp b/soh/soh/SohGui.cpp index 4280c8114..34dee0948 100644 --- a/soh/soh/SohGui.cpp +++ b/soh/soh/SohGui.cpp @@ -39,6 +39,7 @@ #include "Enhancements/debugger/MessageViewer.h" #include "soh/Notification/Notification.h" #include "soh/Enhancements/Holiday/Caladius.h" +#include "soh/Enhancements/TimeDisplay/TimeDisplay.h" bool isBetaQuestEnabled = false; @@ -138,6 +139,7 @@ namespace SohGui { std::shared_ptr mModalWindow; std::shared_ptr mNotificationWindow; std::shared_ptr mCaladiusWindow; + std::shared_ptr mTimeDisplayWindow; void SetupGuiElements() { auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); @@ -226,6 +228,8 @@ namespace SohGui { mCaladiusWindow = std::make_shared(CVAR_WINDOW("Holiday Cal"), "Holiday Cal"); gui->AddGuiWindow(mCaladiusWindow); mCaladiusWindow->Show(); + mTimeDisplayWindow = std::make_shared(CVAR_WINDOW("TimeDisplayEnabled"), "Additional Timers"); + gui->AddGuiWindow(mTimeDisplayWindow); } void Destroy() { @@ -262,6 +266,7 @@ namespace SohGui { mTimeSplitWindow = nullptr; mCaladiusWindow = nullptr; mPlandomizerWindow = nullptr; + mTimeDisplayWindow = nullptr; } void RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function button1callback, std::function button2callback) { diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 28d68a16f..5263066d6 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -45,6 +45,7 @@ #include "Enhancements/timesplits/TimeSplits.h" #include "Enhancements/Holiday/Holiday.hpp" #include "Enhancements/randomizer/Plandomizer.h" +#include "Enhancements/TimeDisplay/TimeDisplay.h" // FA icons are kind of wonky, if they worked how I expected them to the "+ 2.0f" wouldn't be needed, but // they don't work how I expect them to so I added that because it looked good when I eyeballed it @@ -84,6 +85,7 @@ static const char* imguiScaleOptions[4] = { "Small", "Normal", "Large", "X-Large static const char* chestStyleMatchesContentsOptions[4] = { "Disabled", "Both", "Texture Only", "Size Only" }; static const char* skipGetItemAnimationOptions[3] = { "Disabled", "Junk Items", "All Items" }; static const char* skipForcedDialogOptions[4] = { "None", "Navi Only", "NPCs Only", "All" }; + static const char* sleepingWaterfallOptions[3] = { "Always", "Once", "Never" }; static const char* bunnyHoodOptions[3] = { "Disabled", "Faster Run & Longer Jump", "Faster Run" }; static const char* mirroredWorldModes[9] = { "Disabled", "Always", "Random", "Random (Seeded)", "Dungeons", @@ -124,7 +126,7 @@ static const char* imguiScaleOptions[4] = { "Small", "Normal", "Large", "X-Large CVAR_ENHANCEMENT("InjectItemCounts.HeartPiece"), CVAR_ENHANCEMENT("InjectItemCounts.HeartContainer"), }; - static const char* itemCountMessageOptions[sizeof(itemCountMessageCVars) / sizeof(const char*)] = { + static const char* itemCountMessageOptions[ARRAY_COUNT(itemCountMessageCVars)] = { "Gold Skulltula Tokens", "Pieces of Heart", "Heart Containers", @@ -584,9 +586,9 @@ void DrawSettingsMenu() { ImGui::Text("Position"); UIWidgets::EnhancementCombobox(CVAR_SETTING("Notifications.Position"), notificationPosition, 0); - UIWidgets::EnhancementSliderFloat("Duration: %.0f seconds", "##NotificationDuration", CVAR_SETTING("Notifications.Duration"), 3.0f, 30.0f, "", 10.0f, false, false, false); - UIWidgets::EnhancementSliderFloat("BG Opacity: %.1f %%", "##NotificaitonBgOpacity", CVAR_SETTING("Notifications.BgOpacity"), 0.0f, 1.0f, "", 0.5f, true, false, false); - UIWidgets::EnhancementSliderFloat("Size: %.1f", "##NotificaitonSize", CVAR_SETTING("Notifications.Size"), 1.0f, 5.0f, "", 1.8f, false, false, false); + UIWidgets::EnhancementSliderFloat("Duration: %.1f seconds", "##NotificationDuration", CVAR_SETTING("Notifications.Duration"), 3.0f, 30.0f, "", 10.0f, false, true, false); + UIWidgets::EnhancementSliderFloat("BG Opacity: %.1f %%", "##NotificaitonBgOpacity", CVAR_SETTING("Notifications.BgOpacity"), 0.0f, 1.0f, "", 0.5f, true, true, false); + UIWidgets::EnhancementSliderFloat("Size: %.1f", "##NotificaitonSize", CVAR_SETTING("Notifications.Size"), 1.0f, 20.0f, "", 1.8f, false, true, false); UIWidgets::Spacer(0); @@ -607,6 +609,7 @@ extern std::shared_ptr mAudioEditorWindow; extern std::shared_ptr mCosmeticsEditorWindow; extern std::shared_ptr mGameplayStatsWindow; extern std::shared_ptr mTimeSplitWindow; +extern std::shared_ptr mTimeDisplayWindow; void DrawEnhancementsMenu() { if (ImGui::BeginMenu("Enhancements")) @@ -682,8 +685,8 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedEnhancementCheckbox("Skip Owl Interactions", CVAR_ENHANCEMENT("TimeSavers.SkipOwlInteractions"), false, false, false, "", UIWidgets::CheckboxGraphics::Cross, IS_RANDO); UIWidgets::PaddedEnhancementCheckbox("Skip Misc Interactions", CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), false, false, false, "", UIWidgets::CheckboxGraphics::Cross, IS_RANDO); UIWidgets::PaddedEnhancementCheckbox("Disable Title Card", CVAR_ENHANCEMENT("TimeSavers.DisableTitleCard"), false, false, false, "", UIWidgets::CheckboxGraphics::Cross, IS_RANDO); - UIWidgets::PaddedEnhancementCheckbox("Skip Glitch-Aiding Cutscenes", CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), false, false, false, "", UIWidgets::CheckboxGraphics::Cross, 0); - UIWidgets::Tooltip("Skip cutscenes that are associated with useful glitches, currently this is only the Fire Temple Darunia CS and Forest Temple Poe Sisters CS"); + UIWidgets::PaddedEnhancementCheckbox("Exclude Glitch-Aiding Cutscenes", CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), false, false, false, "", UIWidgets::CheckboxGraphics::Cross, 0); + UIWidgets::Tooltip("Don't skip cutscenes that are associated with useful glitches, currently this is only the Fire Temple Darunia CS, Forest Temple Poe Sisters CS and the Box Skip One Point in Jabu"); UIWidgets::PaddedEnhancementCheckbox("Skip Child Stealth", CVAR_ENHANCEMENT("TimeSavers.SkipChildStealth"), false, false, false, "", UIWidgets::CheckboxGraphics::Cross, false); UIWidgets::Tooltip("The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards."); UIWidgets::PaddedEnhancementCheckbox("Skip Tower Escape", CVAR_ENHANCEMENT("TimeSavers.SkipTowerEscape"), false, false, false, "", UIWidgets::CheckboxGraphics::Cross, false); @@ -715,23 +718,15 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedEnhancementSliderInt("Crawl speed %dx", "##CRAWLSPEED", CVAR_ENHANCEMENT("CrawlSpeed"), 1, 4, "", 1, true, false, true); UIWidgets::PaddedEnhancementCheckbox("Faster Heavy Block Lift", CVAR_ENHANCEMENT("FasterHeavyBlockLift"), false, false); UIWidgets::Tooltip("Speeds up lifting silver rocks and obelisks"); - UIWidgets::PaddedEnhancementCheckbox("Faster Rupee Accumulator", CVAR_ENHANCEMENT("TimeSavers.FasterRupeeAccumulator"), false, false); UIWidgets::PaddedEnhancementCheckbox("Skip Pickup Messages", CVAR_ENHANCEMENT("FastDrops"), true, false); UIWidgets::Tooltip("Skip pickup messages for new consumable items and bottle swipes"); UIWidgets::PaddedEnhancementCheckbox("Fast Ocarina Playback", CVAR_ENHANCEMENT("FastOcarinaPlayback"), true, false); UIWidgets::Tooltip("Skip the part where the Ocarina playback is called when you play a song"); - bool forceSkipScarecrow = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_SCARECROWS_SONG); - static const char* forceSkipScarecrowText = "This setting is forcefully enabled because a savefile\nwith \"Skip Scarecrow Song\" is loaded"; - UIWidgets::PaddedEnhancementCheckbox("Skip Scarecrow Song", CVAR_ENHANCEMENT("InstantScarecrow"), true, false, - forceSkipScarecrow, forceSkipScarecrowText, UIWidgets::CheckboxGraphics::Checkmark); - UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song."); UIWidgets::PaddedEnhancementCheckbox("Skip Magic Arrow Equip Animation", CVAR_ENHANCEMENT("SkipArrowAnimation"), true, false); UIWidgets::PaddedEnhancementCheckbox("Skip save confirmation", CVAR_ENHANCEMENT("SkipSaveConfirmation"), true, false); UIWidgets::Tooltip("Skip the \"Game saved.\" confirmation screen"); UIWidgets::PaddedEnhancementCheckbox("Faster Farore's Wind", CVAR_ENHANCEMENT("FastFarores"), true, false); UIWidgets::Tooltip("Greatly decreases cast time of Farore's Wind magic spell."); - UIWidgets::PaddedEnhancementCheckbox("Skip water take breath animation", CVAR_ENHANCEMENT("SkipSwimDeepEndAnim"), true, false); - UIWidgets::Tooltip("Skips Link's taking breath animation after coming up from water. This setting does not interfere with getting items from underwater."); ImGui::TableNextColumn(); UIWidgets::Spacer(0); @@ -798,6 +793,30 @@ void DrawEnhancementsMenu() { "- Not within range of Ocarina playing spots"); UIWidgets::PaddedEnhancementCheckbox("Pause Warp", CVAR_ENHANCEMENT("PauseWarp"), true, false); UIWidgets::Tooltip("Selection of warp song in pause menu initiates warp. Disables song playback."); + UIWidgets::PaddedEnhancementCheckbox("Skip water take breath animation", CVAR_ENHANCEMENT("SkipSwimDeepEndAnim"), true, false); + UIWidgets::Tooltip("Skips Link's taking breath animation after coming up from water. This setting does not interfere with getting items from underwater."); + bool forceSkipScarecrow = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_SCARECROWS_SONG); + static const char* forceSkipScarecrowText = "This setting is forcefully enabled because a savefile\nwith \"Skip Scarecrow Song\" is loaded"; + UIWidgets::PaddedEnhancementCheckbox("Skip Scarecrow Song", CVAR_ENHANCEMENT("InstantScarecrow"), true, false, + forceSkipScarecrow, forceSkipScarecrowText, UIWidgets::CheckboxGraphics::Checkmark); + UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song."); + bool forceSleepingWaterfallEnhancement = + IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SLEEPING_WATERFALL) == RO_WATERFALL_OPEN; + uint8_t forceSleepingWaterfallValue = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SLEEPING_WATERFALL) + 1; + static const char* forceSleepingWaterfallText = + "This setting is forcefully enabled because a randomizer savefile with \"Sleeping Waterfall: Open\" is loaded."; + UIWidgets::PaddedText("Play Zelda's Lullaby to open Sleeping Waterfall", true, false); + UIWidgets::EnhancementCombobox(CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall"), + sleepingWaterfallOptions, 0, forceSleepingWaterfallEnhancement, + forceSleepingWaterfallText, forceSleepingWaterfallValue); + UIWidgets::Tooltip( + "Always: Link must always play Zelda's Lullaby to open " + "the waterfall entrance to Zora's Domain.\n" + "Once: Link only needs to play Zelda's Lullaby once to " + "open the waterfall; after that, it stays open permanently.\n" + "Never: Link never needs to play Zelda's Lullaby to open the " + "waterfall; he only needs to have learned it and have an ocarina." + ); ImGui::EndTable(); ImGui::EndMenu(); @@ -856,6 +875,17 @@ void DrawEnhancementsMenu() { "Toggling while inside the shop will not change prices or restock any SOLD OUTs"); UIWidgets::PaddedEnhancementCheckbox("Aiming reticle for the bow/slingshot", CVAR_ENHANCEMENT("BowReticle"), true, false); UIWidgets::Tooltip("Aiming with a bow or slingshot will display a reticle as with the hookshot when the projectile is ready to fire."); + if (UIWidgets::PaddedEnhancementCheckbox("Aim boomerang in first-person mode", CVAR_ENHANCEMENT("BoomerangFirstPerson"), true, false)) { + if (!CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + CVarSetInteger(CVAR_ENHANCEMENT("BoomerangReticle"), 0); + } + } + UIWidgets::Tooltip( + "Change aiming for the boomerang from third person to first person to see past Link's head"); + if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + UIWidgets::PaddedEnhancementCheckbox("Aiming reticle for boomerang", CVAR_ENHANCEMENT("BoomerangReticle"), true, false); + UIWidgets::Tooltip("Aiming with the boomerang will display a reticle as with the hookshot"); + } if (UIWidgets::PaddedEnhancementCheckbox("Allow strength equipment to be toggled", CVAR_ENHANCEMENT("ToggleStrength"), true, false)) { if (!CVarGetInteger(CVAR_ENHANCEMENT("ToggleStrength"), 0)) { CVarSetInteger(CVAR_ENHANCEMENT("StrengthDisabled"), 0); @@ -868,7 +898,7 @@ void DrawEnhancementsMenu() { UIWidgets::Spacer(0); if (ImGui::BeginMenu("Item Count Messages")) { - int numOptions = sizeof(itemCountMessageCVars) / sizeof(const char*); + int numOptions = ARRAY_COUNT(itemCountMessageCVars); bool allItemCountsChecked = std::all_of(itemCountMessageCVars, itemCountMessageCVars + numOptions, [](const char* cvar) { return CVarGetInteger(cvar, 0); }); bool someItemCountsChecked = std::any_of(itemCountMessageCVars, itemCountMessageCVars + numOptions, @@ -1270,6 +1300,9 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedEnhancementCheckbox("Targetable Hookshot Reticle", CVAR_ENHANCEMENT("HookshotableReticle"), true, false); UIWidgets::Tooltip("Use a different color when aiming at hookshotable collision"); + UIWidgets::PaddedEnhancementCheckbox("Faster Rupee Accumulator", CVAR_ENHANCEMENT("TimeSavers.FasterRupeeAccumulator"), true, false); + UIWidgets::Tooltip("Causes your wallet to fill and empty faster when you gain or lose money."); + ImGui::EndMenu(); } @@ -1693,6 +1726,36 @@ void DrawEnhancementsMenu() { mTimeSplitWindow->ToggleVisibility(); } } + + if (mTimeDisplayWindow) { + if (ImGui::Button(GetWindowButtonText("Additional Timers", CVarGetInteger(CVAR_WINDOW("TimeDisplayEnabled"), 0)).c_str(), ImVec2(-1.0f, 0.0f))) { + mTimeDisplayWindow->ToggleVisibility(); + } + } + if (mTimeDisplayWindow->IsVisible()) { + ImGui::SeparatorText("Timer Display Options"); + + if (!gPlayState) { + ImGui::Text("Additional Timer options\n" + "available when a file is\n" + "loaded..."); + } else { + if (UIWidgets::PaddedEnhancementSliderFloat("Font Scale: %.2fx", "##FontScale", CVAR_ENHANCEMENT("TimeDisplay.FontScale"), + 1.0f, 5.0f, "", 1.0f, false, true, false, true)) { + TimeDisplayInitSettings(); + } + if (UIWidgets::PaddedEnhancementCheckbox("Hide Background", CVAR_ENHANCEMENT("TimeDisplay.ShowWindowBG"), + false, false)) { + TimeDisplayInitSettings(); + } + ImGui::Separator(); + for (auto& timer : timeDisplayList) { + if (UIWidgets::PaddedEnhancementCheckbox(timer.timeLabel.c_str(), timer.timeEnable, false, false)) { + TimeDisplayUpdateDisplayOptions(); + } + } + } + } ImGui::PopStyleVar(3); ImGui::PopStyleColor(1); diff --git a/soh/soh/UIWidgets.cpp b/soh/soh/UIWidgets.cpp index 1d7a56c00..a371ef52b 100644 --- a/soh/soh/UIWidgets.cpp +++ b/soh/soh/UIWidgets.cpp @@ -593,7 +593,7 @@ namespace UIWidgets { #if defined(__SWITCH__) || defined(__WIIU__) srand(time(NULL)); #endif - ImVec4 color = GetRandomValue(255); + ImVec4 color = GetRandomValue(); colors->x = color.x; colors->y = color.y; colors->z = color.z; diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index e00fa81bf..942990e03 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -2,6 +2,7 @@ #include "vt.h" #include "overlays/actors/ovl_Arms_Hook/z_arms_hook.h" +#include "overlays/actors/ovl_En_Arrow/z_en_arrow.h" #include "overlays/actors/ovl_En_Part/z_en_part.h" #include "objects/gameplay_keep/gameplay_keep.h" #include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h" @@ -1081,14 +1082,11 @@ void TitleCard_InitPlaceName(PlayState* play, TitleCardContext* titleCtx, void* } void TitleCard_Update(PlayState* play, TitleCardContext* titleCtx) { - const Color_RGB8 TitleCard_Colors_ori = {255,255,255}; - Color_RGB8 TitleCard_Colors = {255,255,255}; - if (titleCtx->isBossCard && CVarGetInteger(CVAR_COSMETIC("HUD.TitleCard.Boss.Changed"), 1) == 2) { - TitleCard_Colors = CVarGetColor24(CVAR_COSMETIC("HUD.TitleCard.Boss.Value"), TitleCard_Colors_ori); - } else if (!titleCtx->isBossCard && CVarGetInteger(CVAR_COSMETIC("HUD.TitleCard.Map.Changed"), 1) == 2) { - TitleCard_Colors = CVarGetColor24(CVAR_COSMETIC("HUD.TitleCard.Map.Value"), TitleCard_Colors_ori); - } else { - TitleCard_Colors = TitleCard_Colors_ori; + Color_RGB8 TitleCard_Colors = { 255, 255, 255 }; + if (titleCtx->isBossCard && CVarGetInteger(CVAR_COSMETIC("HUD.TitleCard.Boss.Changed"), 0) == 1) { + TitleCard_Colors = CVarGetColor24(CVAR_COSMETIC("HUD.TitleCard.Boss.Value"), TitleCard_Colors); + } else if (!titleCtx->isBossCard && CVarGetInteger(CVAR_COSMETIC("HUD.TitleCard.Map.Changed"), 0) == 1) { + TitleCard_Colors = CVarGetColor24(CVAR_COSMETIC("HUD.TitleCard.Map.Value"), TitleCard_Colors); } if (DECR(titleCtx->delayTimer) == 0) { @@ -2350,8 +2348,14 @@ void Actor_DrawFaroresWindPointer(PlayState* play) { } else if (D_8015BC18 > 0.0f) { static Vec3f effectVel = { 0.0f, -0.05f, 0.0f }; static Vec3f effectAccel = { 0.0f, -0.025f, 0.0f }; - static Color_RGBA8 effectPrimCol = { 255, 255, 255, 0 }; - static Color_RGBA8 effectEnvCol = { 100, 200, 0, 0 }; + Color_RGBA8 effectPrimCol = { 255, 255, 255, 0 }; + Color_RGBA8 effectEnvCol = { 100, 200, 0, 0 }; + if (CVarGetInteger(CVAR_COSMETIC("Magic.FaroresSecondary.Changed"), 0)) { + effectEnvCol = CVarGetColor(CVAR_COSMETIC("Magic.FaroresSecondary.Value"), effectEnvCol); + } + if (CVarGetInteger(CVAR_COSMETIC("Magic.FaroresPrimary.Changed"), 0)) { + effectPrimCol = CVarGetColor(CVAR_COSMETIC("Magic.FaroresPrimary.Value"), effectPrimCol); + } Vec3f* curPos = &gSaveContext.respawn[RESPAWN_MODE_TOP].pos; Vec3f* nextPos = &gSaveContext.respawn[RESPAWN_MODE_DOWN].pos; f32 prevNum = D_8015BC18; @@ -2446,8 +2450,16 @@ void Actor_DrawFaroresWindPointer(PlayState* play) { Matrix_Push(); gDPPipeSync(POLY_XLU_DISP++); - gDPSetPrimColor(POLY_XLU_DISP++, 128, 128, 255, 255, 200, alpha); - gDPSetEnvColor(POLY_XLU_DISP++, 100, 200, 0, 255); + Color_RGB8 Spell_env = { 100, 200, 0 }; + Color_RGB8 Spell_col = { 255, 255, 200 }; + if (CVarGetInteger(CVAR_COSMETIC("Magic.FaroresSecondary.Changed"), 0)) { + Spell_env = CVarGetColor24(CVAR_COSMETIC("Magic.FaroresSecondary.Value"), Spell_env); + } + if (CVarGetInteger(CVAR_COSMETIC("Magic.FaroresPrimary.Changed"), 0)) { + Spell_col = CVarGetColor24(CVAR_COSMETIC("Magic.FaroresPrimary.Value"), Spell_col); + } + gDPSetPrimColor(POLY_XLU_DISP++, 128, 128, Spell_col.r, Spell_col.g, Spell_col.b, alpha); + gDPSetEnvColor(POLY_XLU_DISP++, Spell_env.r, Spell_env.g, Spell_env.b, 255); Matrix_RotateZ(((play->gameplayFrames * 1500) & 0xFFFF) * M_PI / 32768.0f, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), @@ -3854,8 +3866,14 @@ Actor* Actor_GetProjectileActor(PlayState* play, Actor* refActor, f32 radius) { // it can also be an arrow. // Luckily, the field at the same offset in the arrow actor is the x component of a vector // which will rarely ever be 0. So it's very unlikely for this bug to cause an issue. + // + // SoH [Port] We're making a change here, it doesn't technically fix the bug but makes it behave + // more like hardware. Because of pointer size differences in SoH this was accessing a different + // place in memory and causing issues with Dark link behavior, and probably other places too if ((Math_Vec3f_DistXYZ(&refActor->world.pos, &actor->world.pos) > radius) || - (((ArmsHook*)actor)->timer == 0)) { + (actor->id == ACTOR_ARMS_HOOK && ((ArmsHook*)actor)->timer == 0) || + (actor->id == ACTOR_EN_ARROW && ((EnArrow*)actor)->unk_210.x == 0) + ) { actor = actor->next; } else { deltaX = Math_SinS(actor->world.rot.y) * (actor->speedXZ * 10.0f); diff --git a/soh/src/code/z_draw.c b/soh/src/code/z_draw.c index e27f230b1..caf31a234 100644 --- a/soh/src/code/z_draw.c +++ b/soh/src/code/z_draw.c @@ -399,6 +399,9 @@ DrawItemTableEntry sDrawItemTable[] = { * Calls the corresponding draw function for the given draw ID */ void GetItem_Draw(PlayState* play, s16 drawId) { + if (drawId < 0 || drawId >= GID_MAXIMUM) { + return; + } sDrawItemTable[drawId].drawFunc(play, drawId); } diff --git a/soh/src/code/z_game_over.c b/soh/src/code/z_game_over.c index a2bdfc1a5..1850133aa 100644 --- a/soh/src/code/z_game_over.c +++ b/soh/src/code/z_game_over.c @@ -1,5 +1,7 @@ #include "global.h" #include "soh/OTRGlobals.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" void GameOver_Init(PlayState* play) { play->gameOverCtx.state = GAMEOVER_INACTIVE; @@ -34,7 +36,7 @@ void GameOver_Update(PlayState* play) { gSaveContext.eventInf[1] &= ~1; // search inventory for spoiling items and revert if necessary - if (!(IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE))) { + if (GameInteractor_Should(VB_REVERT_SPOILING_ITEMS, true)) { for (i = 0; i < ARRAY_COUNT(gSpoilingItems); i++) { if (INV_CONTENT(ITEM_POCKET_EGG) == gSpoilingItems[i]) { INV_CONTENT(gSpoilingItemReverts[i]) = gSpoilingItemReverts[i]; diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index ca76b16d1..501e49195 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -7,6 +7,7 @@ #include "textures/parameter_static/parameter_static.h" #include "textures/message_static/message_static.h" #include "textures/message_texture_static/message_texture_static.h" +#include "soh/Enhancements/cosmetics/CosmeticsEditor.h" #include "soh/Enhancements/cosmetics/cosmeticsTypes.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" @@ -367,6 +368,80 @@ void Message_FindCreditsMessage(PlayState* play, u16 textId) { } } +#pragma region [SoH] Cosmetics + +#define MESSAGE_COSMETICS_HANDLE_COLOR(id) \ + if (CVarGetInteger(CVAR_COSMETIC("Message." id ".Changed"), 0)) { \ + Color_RGBA8 color = CVarGetColor(CVAR_COSMETIC("Message." id ".Value"), CosmeticsEditor_GetDefaultValue("Message." id)); \ + msgCtx->textColorR = color.r; \ + msgCtx->textColorG = color.g; \ + msgCtx->textColorB = color.b; \ + } + +void Cosmetics_MaybeSetTextColor(MessageContext* msgCtx, u16 colorParameter) { + switch (colorParameter) { + case MSGCOL_RED: + if (msgCtx->textBoxType == TEXTBOX_TYPE_WOODEN) { + MESSAGE_COSMETICS_HANDLE_COLOR("Red.Wooden") + } else { + MESSAGE_COSMETICS_HANDLE_COLOR("Red.Normal") + } + break; + case MSGCOL_ADJUSTABLE: + if (msgCtx->textBoxType == TEXTBOX_TYPE_WOODEN) { + MESSAGE_COSMETICS_HANDLE_COLOR("Adjustable.Wooden") + } else { + MESSAGE_COSMETICS_HANDLE_COLOR("Adjustable.Normal") + } + break; + case MSGCOL_BLUE: + if (msgCtx->textBoxType == TEXTBOX_TYPE_WOODEN) { + MESSAGE_COSMETICS_HANDLE_COLOR("Blue.Wooden") + } else { + MESSAGE_COSMETICS_HANDLE_COLOR("Blue.Normal") + } + break; + case MSGCOL_LIGHTBLUE: + if (msgCtx->textBoxType == TEXTBOX_TYPE_WOODEN) { + MESSAGE_COSMETICS_HANDLE_COLOR("LightBlue.Wooden") + } else if (msgCtx->textBoxType == TEXTBOX_TYPE_NONE_NO_SHADOW) { + MESSAGE_COSMETICS_HANDLE_COLOR("LightBlue.NoneNoShadow") + } else { + MESSAGE_COSMETICS_HANDLE_COLOR("LightBlue.Normal") + } + break; + case MSGCOL_PURPLE: + if (msgCtx->textBoxType == TEXTBOX_TYPE_WOODEN) { + MESSAGE_COSMETICS_HANDLE_COLOR("Purple.Wooden") + } else { + MESSAGE_COSMETICS_HANDLE_COLOR("Purple.Normal") + } + break; + case MSGCOL_YELLOW: + if (msgCtx->textBoxType == TEXTBOX_TYPE_WOODEN) { + MESSAGE_COSMETICS_HANDLE_COLOR("Yellow.Wooden") + } else { + MESSAGE_COSMETICS_HANDLE_COLOR("Yellow.Normal") + } + break; + case MSGCOL_BLACK: + MESSAGE_COSMETICS_HANDLE_COLOR("Black") + break; + case MSGCOL_DEFAULT: + default: + if (msgCtx->textBoxType == TEXTBOX_TYPE_NONE_NO_SHADOW) { + MESSAGE_COSMETICS_HANDLE_COLOR("Default.NoneNoShadow") + } else { + MESSAGE_COSMETICS_HANDLE_COLOR("Default.Normal") + } + break; + } +} + +#undef MESSAGE_COSMETICS_HANDLE_COLOR + +#pragma endregion + void Message_SetTextColor(MessageContext* msgCtx, u16 colorParameter) { switch (colorParameter) { case MSGCOL_RED: @@ -451,6 +526,7 @@ void Message_SetTextColor(MessageContext* msgCtx, u16 colorParameter) { } break; } + Cosmetics_MaybeSetTextColor(msgCtx, colorParameter); } void Message_DrawTextboxIcon(PlayState* play, Gfx** p, s16 x, s16 y) { @@ -853,6 +929,8 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) { msgCtx->textColorR = msgCtx->textColorG = msgCtx->textColorB = 255; } + Cosmetics_MaybeSetTextColor(msgCtx, MSGCOL_DEFAULT); + msgCtx->unk_E3D0 = 0; charTexIdx = 0; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 8cd28d4df..71bc672ac 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1891,6 +1891,12 @@ u8 Return_Item(u8 itemID, ModIndex modId, ItemID returnItem) { * @return u8 */ u8 Item_Give(PlayState* play, u8 item) { + // TODO: Add ShouldItemGive + // if (!GameInteractor_ShouldItemGive(item) || item == ITEM_SHIP) { + if (item == ITEM_SHIP) { + return ITEM_NONE; + } + //prevents getting sticks without the bag in case something got missed if ( IS_RANDO && @@ -2486,6 +2492,11 @@ u8 Item_CheckObtainability(u8 item) { s16 slot = SLOT(item); s32 temp; + // SOH [Enhancements] Added to enable custom item gives + if (item == ITEM_SHIP) { + return ITEM_NONE; + } + if (item >= ITEM_STICKS_5) { slot = SLOT(sExtraItemBases[item - ITEM_STICKS_5]); } @@ -3388,6 +3399,11 @@ void Interface_UpdateMagicBar(PlayState* play) { default: gSaveContext.magicState = MAGIC_STATE_IDLE; + if (CVarGetInteger(CVAR_COSMETIC("Consumable.MagicBorder.Changed"), 0)) { + sMagicBorder = CVarGetColor24(CVAR_COSMETIC("Consumable.MagicBorder.Value"), sMagicBorder_ori); + } else { + sMagicBorder = sMagicBorder_ori; + } break; } } @@ -3617,8 +3633,8 @@ void Interface_DrawEnemyHealthBar(TargetContext* targetCtx, PlayState* play) { s32 healthbar_offsetY = CVarGetInteger(CVAR_COSMETIC("HUD.EnemyHealthBar.PosY"), 0); s8 anchorType = CVarGetInteger(CVAR_COSMETIC("HUD.EnemyHealthBar.PosType"), ENEMYHEALTH_ANCHOR_ACTOR); - if (CVarGetInteger(CVAR_COSMETIC("HUD.EnemyHealthBar..Changed"), 0)) { - healthbar_red = CVarGetColor(CVAR_COSMETIC("HUD.EnemyHealthBar..Value"), healthbar_red); + if (CVarGetInteger(CVAR_COSMETIC("HUD.EnemyHealthBar.Changed"), 0)) { + healthbar_red = CVarGetColor(CVAR_COSMETIC("HUD.EnemyHealthBar.Value"), healthbar_red); } if (CVarGetInteger(CVAR_COSMETIC("HUD.EnemyHealthBorder.Changed"), 0)) { healthbar_border = CVarGetColor(CVAR_COSMETIC("HUD.EnemyHealthBorder.Value"), healthbar_border); @@ -5713,17 +5729,19 @@ void Interface_Draw(PlayState* play) { } // Revert any spoiling trade quest items - for (svar1 = 0; svar1 < ARRAY_COUNT(gSpoilingItems); svar1++) { - if (INV_CONTENT(ITEM_TRADE_ADULT) == gSpoilingItems[svar1]) { - gSaveContext.eventInf[0] &= 0x7F80; - osSyncPrintf("EVENT_INF=%x\n", gSaveContext.eventInf[0]); - play->nextEntranceIndex = spoilingItemEntrances[svar1]; - INV_CONTENT(gSpoilingItemReverts[svar1]) = gSpoilingItemReverts[svar1]; + if (GameInteractor_Should(VB_REVERT_SPOILING_ITEMS, true)) { + for (svar1 = 0; svar1 < ARRAY_COUNT(gSpoilingItems); svar1++) { + if (INV_CONTENT(ITEM_TRADE_ADULT) == gSpoilingItems[svar1]) { + gSaveContext.eventInf[0] &= 0x7F80; + osSyncPrintf("EVENT_INF=%x\n", gSaveContext.eventInf[0]); + play->nextEntranceIndex = spoilingItemEntrances[svar1]; + INV_CONTENT(gSpoilingItemReverts[svar1]) = gSpoilingItemReverts[svar1]; - for (svar2 = 1; svar2 < ARRAY_COUNT(gSaveContext.equips.buttonItems); svar2++) { - if (gSaveContext.equips.buttonItems[svar2] == gSpoilingItems[svar1]) { - gSaveContext.equips.buttonItems[svar2] = gSpoilingItemReverts[svar1]; - Interface_LoadItemIcon1(play, svar2); + for (svar2 = 1; svar2 < ARRAY_COUNT(gSaveContext.equips.buttonItems); svar2++) { + if (gSaveContext.equips.buttonItems[svar2] == gSpoilingItems[svar1]) { + gSaveContext.equips.buttonItems[svar2] = gSpoilingItemReverts[svar1]; + Interface_LoadItemIcon1(play, svar2); + } } } } @@ -6094,7 +6112,7 @@ void Interface_Draw(PlayState* play) { svar5 = CVarGetInteger(CVAR_COSMETIC("HUD.Timers.PosX"), 0)+204+X_Margins_Timer; } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Timers.PosType"), 0) == 4) {//Hidden svar5 = -9999; - } + } } OVERLAY_DISP = diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index f44f21a18..52a2d49fa 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -888,6 +888,16 @@ s32 Player_HoldsSlingshot(Player* this) { return this->heldItemAction == PLAYER_IA_SLINGSHOT; } +// #region SOH [Enhancement] +s32 Player_HoldsBoomerang(Player* this) { + return this->heldItemAction == PLAYER_IA_BOOMERANG; +} + +s32 Player_AimsBoomerang(Player* this) { + return Player_HoldsBoomerang(this) && (this->unk_834 != 0); +} +// #endregion + s32 func_8008F128(Player* this) { return Player_HoldsHookshot(this) && (this->heldActor == NULL); } @@ -1798,6 +1808,9 @@ Vec3f sLeftRightFootLimbModelFootPos[] = { void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { Player* this = (Player*)thisx; + const Vec3s BoomerangViewAdult = { -31200, -9200, 17000 }; + const Vec3s BoomerangViewChild = { -31200, -8700, 17000 }; + if (*dList != NULL) { Matrix_MultVec3f(&sZeroVec, D_80160000); } @@ -2005,6 +2018,8 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Ve play, this, ((this->heldItemAction == PLAYER_IA_HOOKSHOT) ? 38600.0f : 77600.0f) * CVarGetFloat(CVAR_CHEAT("HookshotReachMultiplier"), 1.0f)); } } + + // #region SOH [Enhancement] } else if (CVarGetInteger(CVAR_ENHANCEMENT("BowReticle"), 0) && ( (this->heldItemAction == PLAYER_IA_BOW_FIRE) || (this->heldItemAction == PLAYER_IA_BOW_ICE) || @@ -2023,6 +2038,21 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Ve Player_DrawHookshotReticle(play, this, RETICLE_MAX); } } + } else if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangReticle"), 0) && (this->heldItemAction == PLAYER_IA_BOOMERANG)) { + if (Player_HoldsBoomerang(this)) { + if (LINK_IS_ADULT) { + Matrix_RotateZYX(BoomerangViewAdult.x, BoomerangViewAdult.y, BoomerangViewAdult.z, + MTXMODE_APPLY); + } else { + Matrix_RotateZYX(BoomerangViewChild.x, BoomerangViewChild.y, BoomerangViewChild.z, MTXMODE_APPLY); + } + + if (Player_AimsBoomerang(this)) { + Matrix_Translate(500.0f, 300.0f, 0.0f, MTXMODE_APPLY); + Player_DrawHookshotReticle(play, this, RETICLE_MAX); + } + } + // #endregion } if ((this->unk_862 != 0) || ((func_8002DD6C(this) == 0) && (heldActor != NULL))) { diff --git a/soh/src/overlays/actors/ovl_En_Mag/z_en_mag.c b/soh/src/overlays/actors/ovl_En_Mag/z_en_mag.c index bad7e9b52..77773e92a 100644 --- a/soh/src/overlays/actors/ovl_En_Mag/z_en_mag.c +++ b/soh/src/overlays/actors/ovl_En_Mag/z_en_mag.c @@ -931,8 +931,21 @@ void EnMag_DrawInnerVanilla(Actor* thisx, PlayState* play, Gfx** gfxp) { gDPSetAlphaCompare(gfx++, G_AC_NONE); gDPSetCombineMode(gfx++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); - gDPSetPrimColor(gfx++, 0, 0, (s16)this->copyrightAlpha, (s16)this->copyrightAlpha, (s16)this->copyrightAlpha, - (s16)this->copyrightAlpha); + if (CVarGetInteger(CVAR_COSMETIC("Title.Copyright.Changed"), 0)) { + Color_RGBA8 copyrightColor = CVarGetColor(CVAR_COSMETIC("Title.Copyright.Value"), (Color_RGBA8){ 255, 255, 255, 255 }); + gDPSetPrimColor( + gfx++, + 0, + 0, + (s16)(((f32)copyrightColor.r / 255.0f) * this->copyrightAlpha), + (s16)(((f32)copyrightColor.g / 255.0f) * this->copyrightAlpha), + (s16)(((f32)copyrightColor.b / 255.0f) * this->copyrightAlpha), + (s16)(((f32)copyrightColor.a / 255.0f) * this->copyrightAlpha) + ); + } else { + gDPSetPrimColor(gfx++, 0, 0, (s16)this->copyrightAlpha, (s16)this->copyrightAlpha, (s16)this->copyrightAlpha, + (s16)this->copyrightAlpha); + } if ((s16)this->copyrightAlpha != 0) { gDPLoadTextureBlock(gfx++, copy_tex, G_IM_FMT_IA, G_IM_SIZ_8b, copy_width, 16, 0, G_TX_NOMIRROR | G_TX_CLAMP, diff --git a/soh/src/overlays/actors/ovl_En_Mk/z_en_mk.c b/soh/src/overlays/actors/ovl_En_Mk/z_en_mk.c index f5549f86e..4e020f7ec 100644 --- a/soh/src/overlays/actors/ovl_En_Mk/z_en_mk.c +++ b/soh/src/overlays/actors/ovl_En_Mk/z_en_mk.c @@ -98,9 +98,8 @@ void func_80AACA40(EnMk* this, PlayState* play) { void func_80AACA94(EnMk* this, PlayState* play) { if (Actor_HasParent(&this->actor, play) != 0 || !GameInteractor_Should(VB_TRADE_FROG, true, this)) { this->actor.parent = NULL; - this->actionFunc = func_80AACA40; - Flags_SetRandomizerInf(RAND_INF_ADULT_TRADES_LH_TRADE_FROG); - if (GameInteractor_Should(VB_TRADE_TIMER_EYEDROPS, true)) { + if (GameInteractor_Should(VB_TRADE_TIMER_EYEDROPS, true, this)) { + this->actionFunc = func_80AACA40; func_80088AA0(240); gSaveContext.eventInf[1] &= ~1; } diff --git a/soh/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c b/soh/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c index 9b6e4601e..df5b7e106 100644 --- a/soh/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c +++ b/soh/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c @@ -8,6 +8,7 @@ #include "objects/object_ru1/object_ru1.h" #include "vt.h" #include "soh/ResourceManagerHelpers.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_CAN_PRESS_SWITCH) @@ -763,14 +764,6 @@ void func_80AEC2C0(EnRu1* this, PlayState* play) { func_80AEC070(this, play, something); } -// Convenience function used so that Ruto always spawns in Jabu in rando, even after she's been kidnapped -// Equivalent to !Flags_GetInfTable(INFTABLE_145) in vanilla -bool shouldSpawnRuto() { - // Flags_GetInfTable(INFTABLE_146) check is to prevent Ruto from spawning during the short period of time when - // she's on the Zora's Sapphire pedestal but hasn't been kidnapped yet (would result in multiple Rutos otherwise) - return !Flags_GetInfTable(INFTABLE_145) || (IS_RANDO && (Flags_GetInfTable(INFTABLE_146))); -} - void func_80AEC320(EnRu1* this, PlayState* play) { s8 actorRoom; @@ -778,7 +771,10 @@ void func_80AEC320(EnRu1* this, PlayState* play) { func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); this->action = 7; EnRu1_SetMouthIndex(this, 1); - } else if ((Flags_GetInfTable(INFTABLE_147)) && !Flags_GetInfTable(INFTABLE_140) && shouldSpawnRuto()) { + } else if ( + Flags_GetInfTable(INFTABLE_147) && !Flags_GetInfTable(INFTABLE_140) && + GameInteractor_Should(VB_RUTO_BE_CONSIDERED_NOT_KIDNAPPED, !Flags_GetInfTable(INFTABLE_145), this) + ) { if (!func_80AEB020(this, play)) { func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); actorRoom = this->actor.room; @@ -867,9 +863,9 @@ void func_80AEC780(EnRu1* this, PlayState* play) { s32 pad; Player* player = GET_PLAYER(play); - if ((func_80AEC5FC(this, play)) && (!Play_InCsMode(play)) && + if (GameInteractor_Should(VB_PLAY_CHILD_RUTO_INTRO, (func_80AEC5FC(this, play)) && (!Play_InCsMode(play)) && (!(player->stateFlags1 & (PLAYER_STATE1_HANGING_OFF_LEDGE | PLAYER_STATE1_CLIMBING_LEDGE | PLAYER_STATE1_CLIMBING_LADDER))) && - (player->actor.bgCheckFlags & 1)) { + (player->actor.bgCheckFlags & 1), this)) { play->csCtx.segment = &D_80AF0880; gSaveContext.cutsceneTrigger = 1; @@ -1183,8 +1179,11 @@ void func_80AED414(EnRu1* this, PlayState* play) { void func_80AED44C(EnRu1* this, PlayState* play) { s8 actorRoom; - if ((Flags_GetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO)) && shouldSpawnRuto() && !Flags_GetInfTable(INFTABLE_140) && - !Flags_GetInfTable(INFTABLE_147)) { + if ( + Flags_GetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO) && + GameInteractor_Should(VB_RUTO_BE_CONSIDERED_NOT_KIDNAPPED, !Flags_GetInfTable(INFTABLE_145), this) && + !Flags_GetInfTable(INFTABLE_140) && !Flags_GetInfTable(INFTABLE_147) + ) { if (!func_80AEB020(this, play)) { func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); actorRoom = this->actor.room; @@ -1550,8 +1549,8 @@ s32 func_80AEE394(EnRu1* this, PlayState* play) { colCtx = &play->colCtx; floorBgId = this->actor.floorBgId; // necessary match, can't move this out of this block unfortunately dynaPolyActor = DynaPoly_GetActor(colCtx, floorBgId); - if (dynaPolyActor != NULL && dynaPolyActor->actor.id == ACTOR_BG_BDAN_OBJECTS && - dynaPolyActor->actor.params == 0 && !Player_InCsMode(play) && play->msgCtx.msgLength == 0) { + if (GameInteractor_Should(VB_RUTO_RUN_TO_SAPPHIRE, dynaPolyActor != NULL && dynaPolyActor->actor.id == ACTOR_BG_BDAN_OBJECTS && + dynaPolyActor->actor.params == 0 && !Player_InCsMode(play) && play->msgCtx.msgLength == 0, this, dynaPolyActor)) { func_80AEE02C(this); play->csCtx.segment = &D_80AF10A4; gSaveContext.cutsceneTrigger = 1; @@ -1611,7 +1610,7 @@ s32 func_80AEE6D0(EnRu1* this, PlayState* play) { s32 pad; s8 curRoomNum = play->roomCtx.curRoom.num; - if (!Flags_GetInfTable(INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE) && (func_80AEB124(play) != 0)) { + if (GameInteractor_Should(VB_RUTO_WANT_TO_BE_TOSSED_TO_SAPPHIRE, !Flags_GetInfTable(INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE) && (func_80AEB124(play) != 0), this)) { if (!Player_InCsMode(play)) { Animation_Change(&this->skelAnime, &gRutoChildSeesSapphireAnim, 1.0f, 0, Animation_GetLastFrame(&gRutoChildSquirmAnim), ANIMMODE_LOOP, -8.0f); @@ -2190,8 +2189,11 @@ void func_80AEFF40(EnRu1* this, PlayState* play) { void func_80AEFF94(EnRu1* this, PlayState* play) { s8 actorRoom; - if ((Flags_GetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO)) && (Flags_GetInfTable(INFTABLE_140)) && shouldSpawnRuto() && - (!(func_80AEB020(this, play)))) { + if ( + Flags_GetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO) && Flags_GetInfTable(INFTABLE_140) && + GameInteractor_Should(VB_RUTO_BE_CONSIDERED_NOT_KIDNAPPED, !Flags_GetInfTable(INFTABLE_145), this) && + (!(func_80AEB020(this, play))) + ) { func_80AEB264(this, &gRutoChildWait2Anim, 0, 0, 0); actorRoom = this->actor.room; this->action = 22; diff --git a/soh/src/overlays/actors/ovl_Magic_Dark/z_magic_dark.c b/soh/src/overlays/actors/ovl_Magic_Dark/z_magic_dark.c index db1ea8208..069e7ddbe 100644 --- a/soh/src/overlays/actors/ovl_Magic_Dark/z_magic_dark.c +++ b/soh/src/overlays/actors/ovl_Magic_Dark/z_magic_dark.c @@ -198,10 +198,14 @@ void MagicDark_DiamondDraw(Actor* thisx, PlayState* play) { MagicDark* this = (MagicDark*)thisx; s32 pad; u16 gameplayFrames = play->gameplayFrames; - Color_RGB8 Spell_env_ori = {0, 100, 255}; - Color_RGB8 Spell_col_ori = {170, 255, 255}; - Color_RGB8 Spell_env = CVarGetColor24(CVAR_COSMETIC("Magic.NayrusSecondary.Value"), Spell_env_ori); - Color_RGB8 Spell_col = CVarGetColor24(CVAR_COSMETIC("Magic.NayrusPrimary.Value"), Spell_col_ori); + Color_RGB8 Spell_env = { 0, 100, 255 }; + Color_RGB8 Spell_col = { 170, 255, 255 }; + if (CVarGetInteger(CVAR_COSMETIC("Magic.NayrusSecondary.Changed"), 0)) { + Spell_env = CVarGetColor24(CVAR_COSMETIC("Magic.NayrusSecondary.Value"), Spell_env); + } + if (CVarGetInteger(CVAR_COSMETIC("Magic.NayrusPrimary.Changed"), 0)) { + Spell_col = CVarGetColor24(CVAR_COSMETIC("Magic.NayrusPrimary.Value"), Spell_col); + } OPEN_DISPS(play->state.gfxCtx); @@ -224,13 +228,8 @@ void MagicDark_DiamondDraw(Actor* thisx, PlayState* play) { Matrix_RotateY(this->actor.shape.rot.y * (M_PI / 0x8000), MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - if (CVarGetInteger(CVAR_COSMETIC("UseSpellsColors"),0)) { - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, Spell_col.r, Spell_col.g, Spell_col.b, (s32)(this->primAlpha * 0.6f) & 0xFF); - gDPSetEnvColor(POLY_XLU_DISP++, Spell_env.r, Spell_env.g, Spell_env.b, 128); - } else { - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 170, 255, 255, (s32)(this->primAlpha * 0.6f) & 0xFF); - gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, 128); - } + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, Spell_col.r, Spell_col.g, Spell_col.b, (s32)(this->primAlpha * 0.6f) & 0xFF); + gDPSetEnvColor(POLY_XLU_DISP++, Spell_env.r, Spell_env.g, Spell_env.b, 128); gSPDisplayList(POLY_XLU_DISP++, sDiamondMaterialDL); gSPDisplayList(POLY_XLU_DISP++, Gfx_TwoTexScroll(play->state.gfxCtx, 0, gameplayFrames * 2, gameplayFrames * -4, 32, 32, 1, @@ -271,8 +270,18 @@ void MagicDark_OrbDraw(Actor* thisx, PlayState* play) { OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL_25Xlu(play->state.gfxCtx); - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, 170, 255, 255, 255); - gDPSetEnvColor(POLY_XLU_DISP++, 0, 150, 255, 255); + + Color_RGB8 Spell_env = { 0, 150, 255 }; + Color_RGB8 Spell_col = { 170, 255, 255 }; + if (CVarGetInteger(CVAR_COSMETIC("Magic.NayrusSecondary.Changed"), 0)) { + Spell_env = CVarGetColor24(CVAR_COSMETIC("Magic.NayrusSecondary.Value"), Spell_env); + } + if (CVarGetInteger(CVAR_COSMETIC("Magic.NayrusPrimary.Changed"), 0)) { + Spell_col = CVarGetColor24(CVAR_COSMETIC("Magic.NayrusPrimary.Value"), Spell_col); + } + + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, Spell_col.r, Spell_col.g, Spell_col.b, 255); + gDPSetEnvColor(POLY_XLU_DISP++, Spell_env.r, Spell_env.g, Spell_env.b, 255); Matrix_Translate(pos.x, pos.y, pos.z, MTXMODE_NEW); Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); Matrix_Mult(&play->billboardMtxF, MTXMODE_APPLY); diff --git a/soh/src/overlays/actors/ovl_Magic_Fire/z_magic_fire.c b/soh/src/overlays/actors/ovl_Magic_Fire/z_magic_fire.c index 46fdccaa6..da0fb02e5 100644 --- a/soh/src/overlays/actors/ovl_Magic_Fire/z_magic_fire.c +++ b/soh/src/overlays/actors/ovl_Magic_Fire/z_magic_fire.c @@ -217,10 +217,14 @@ void MagicFire_Draw(Actor* thisx, PlayState* play) { s32 pad2; s32 i; u8 alpha; - Color_RGB8 Spell_env_ori = {255, 0, 0}; - Color_RGB8 Spell_col_ori = {255, 200, 0}; - Color_RGB8 Spell_env = CVarGetColor24(CVAR_COSMETIC("Magic.DinsSecondary.Value"), Spell_env_ori); - Color_RGB8 Spell_col = CVarGetColor24(CVAR_COSMETIC("Magic.DinsPrimaryary.Value"), Spell_col_ori); + Color_RGB8 Spell_env = { 255, 0, 0 }; + Color_RGB8 Spell_col = { 255, 200, 0 }; + if (CVarGetInteger(CVAR_COSMETIC("Magic.DinsSecondary.Changed"), 0)) { + Spell_env = CVarGetColor24(CVAR_COSMETIC("Magic.DinsSecondary.Value"), Spell_env); + } + if (CVarGetInteger(CVAR_COSMETIC("Magic.DinsPrimaryary.Changed"), 0)) { + Spell_col = CVarGetColor24(CVAR_COSMETIC("Magic.DinsPrimary.Value"), Spell_col); + } if (this->action > 0) { OPEN_DISPS(play->state.gfxCtx); @@ -232,13 +236,8 @@ void MagicFire_Draw(Actor* thisx, PlayState* play) { gDPSetColorDither(POLY_XLU_DISP++, G_CD_DISABLE); gDPFillRectangle(POLY_XLU_DISP++, 0, 0, 319, 239); Gfx_SetupDL_25Xlu(play->state.gfxCtx); - if (CVarGetInteger(CVAR_COSMETIC("UseSpellsColors"),0)) { - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, Spell_col.r, Spell_col.g, Spell_col.b, (u8)(this->alphaMultiplier * 255)); - gDPSetEnvColor(POLY_XLU_DISP++, Spell_env.r, Spell_env.g, Spell_env.b, (u8)(this->alphaMultiplier * 255)); - } else { - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, Spell_col_ori.r, Spell_col_ori.g, Spell_col_ori.b, (u8)(this->alphaMultiplier * 255)); - gDPSetEnvColor(POLY_XLU_DISP++, Spell_env_ori.r, Spell_env_ori.g, Spell_env_ori.b, (u8)(this->alphaMultiplier * 255)); - } + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, Spell_col.r, Spell_col.g, Spell_col.b, (u8)(this->alphaMultiplier * 255)); + gDPSetEnvColor(POLY_XLU_DISP++, Spell_env.r, Spell_env.g, Spell_env.b, (u8)(this->alphaMultiplier * 255)); Matrix_Scale(0.15f, 0.15f, 0.15f, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); 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 cd79fc591..11ed30ad8 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -3238,7 +3238,11 @@ s32 func_808358F0(Player* this, PlayState* play) { AnimationContext_SetCopyAll(play, this->skelAnime.limbCount, this->upperSkelAnime.jointTable, this->skelAnime.jointTable); } else { - LinkAnimation_Update(play, &this->upperSkelAnime); + // #region SOH [Enhancement] + if (!CVarGetInteger(CVAR_ENHANCEMENT("BoomerangReticle"), 0)) { + // #endregion + LinkAnimation_Update(play, &this->upperSkelAnime); + } } func_80834EB8(this, play); @@ -5825,7 +5829,13 @@ s32 func_8083AD4C(PlayState* play, Player* this) { camMode = shouldUseBowCamera ? CAM_MODE_BOWARROW : CAM_MODE_SLINGSHOT; } else { - camMode = CAM_MODE_BOOMERANG; + // #region SOH [Enhancement] + if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + camMode = CAM_MODE_FIRSTPERSON; + // #endregion + } else { + camMode = CAM_MODE_BOOMERANG; + } } } else { camMode = CAM_MODE_FIRSTPERSON; @@ -7302,6 +7312,7 @@ s32 Player_ActionHandler_2(Player* this, PlayState* play) { interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != ITEM00_HEART_PIECE && interactedActor->params != ITEM00_SMALL_KEY && + interactedActor->params != ITEM00_NONE && interactedActor->params != ITEM00_SOH_GIVE_ITEM_ENTRY && interactedActor->params != ITEM00_SOH_GIVE_ITEM_ENTRY_GI ) || @@ -11488,7 +11499,13 @@ void Player_UpdateCamAndSeqModes(PlayState* play, Player* this) { camMode = CAM_MODE_TALK; } else if (this->stateFlags1 & PLAYER_STATE1_FRIENDLY_ACTOR_FOCUS) { if (this->stateFlags1 & PLAYER_STATE1_BOOMERANG_THROWN) { - camMode = CAM_MODE_FOLLOWBOOMERANG; + // #region SOH [Enhancement] + if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + camMode = CAM_MODE_TARGET; + // #endregion + } else { + camMode = CAM_MODE_FOLLOWBOOMERANG; + } } else { camMode = CAM_MODE_FOLLOWTARGET; } @@ -11499,7 +11516,13 @@ void Player_UpdateCamAndSeqModes(PlayState* play, Player* this) { } else if (this->stateFlags1 & PLAYER_STATE1_CHARGING_SPIN_ATTACK) { camMode = CAM_MODE_CHARGE; } else if (this->stateFlags1 & PLAYER_STATE1_BOOMERANG_THROWN) { - camMode = CAM_MODE_FOLLOWBOOMERANG; + // #region SOH [Enhancement] + if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + camMode = CAM_MODE_TARGET; + // #endregion + } else { + camMode = CAM_MODE_FOLLOWBOOMERANG; + } Camera_SetParam(Play_GetCamera(play, 0), 8, this->boomerangActor); } else if (this->stateFlags1 & (PLAYER_STATE1_HANGING_OFF_LEDGE | PLAYER_STATE1_CLIMBING_LEDGE)) { if (Player_FriendlyLockOnOrParallel(this)) {