diff --git a/CMakeLists.txt b/CMakeLists.txt index 53b6b0ac386..9ae0360d8bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") -project(Ship VERSION 8.0.2 LANGUAGES C CXX) -set(PROJECT_BUILD_NAME "MacReady Charlie" CACHE STRING "") +project(Ship VERSION 8.0.3 LANGUAGES C CXX) +set(PROJECT_BUILD_NAME "MacReady Delta" CACHE STRING "") set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "") set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh) diff --git a/libultraship b/libultraship index f717dd265af..59427a67bf9 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit f717dd265aff2eff359de26915d8ad4e498ffdaf +Subproject commit 59427a67bf9af060a4928bb72e3acce3b0782177 diff --git a/soh/assets/custom/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_0 b/soh/assets/custom/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_0 index 3637534b99f..4f60b10fe4b 100644 --- a/soh/assets/custom/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_0 +++ b/soh/assets/custom/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_0 @@ -1,72 +1,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_1 b/soh/assets/custom/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_1 index ef51d7124c0..80931181f14 100644 --- a/soh/assets/custom/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_1 +++ b/soh/assets/custom/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_1 @@ -1,107 +1,107 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_0 b/soh/assets/custom/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_0 index d9a5075af2b..366463fd9cc 100644 --- a/soh/assets/custom/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_0 +++ b/soh/assets/custom/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_0 @@ -1,72 +1,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_1 b/soh/assets/custom/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_1 index 8c2f954e7c3..8085ae95ab8 100644 --- a/soh/assets/custom/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_1 +++ b/soh/assets/custom/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_1 @@ -1,96 +1,96 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_blue_mat b/soh/assets/custom/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_blue_mat index 18d8436b2ba..6ba4d88f9b2 100644 --- a/soh/assets/custom/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_blue_mat +++ b/soh/assets/custom/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_blue_mat @@ -8,7 +8,7 @@ - + diff --git a/soh/assets/custom/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_0 b/soh/assets/custom/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_0 index 5122e290427..90dc38784f0 100644 --- a/soh/assets/custom/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_0 +++ b/soh/assets/custom/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_0 @@ -1,72 +1,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_1 b/soh/assets/custom/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_1 index 988bfb67356..ef4ea40e42a 100644 --- a/soh/assets/custom/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_1 +++ b/soh/assets/custom/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_1 @@ -1,410 +1,410 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_Green_mat b/soh/assets/custom/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_Green_mat index 35d57dfeae7..94418f24fc5 100644 --- a/soh/assets/custom/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_Green_mat +++ b/soh/assets/custom/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_Green_mat @@ -8,7 +8,7 @@ - + diff --git a/soh/assets/custom/textures/parameter_static/gTriforcePiece.rgba32.png b/soh/assets/custom/textures/parameter_static/gTriforcePiece.rgba32.png index cc67b6a133d..eace659af29 100644 Binary files a/soh/assets/custom/textures/parameter_static/gTriforcePiece.rgba32.png and b/soh/assets/custom/textures/parameter_static/gTriforcePiece.rgba32.png differ diff --git a/soh/assets/xml/GC_MQ_D/objects/object_mo.xml b/soh/assets/xml/GC_MQ_D/objects/object_mo.xml index f25286df87c..f31a345d6a4 100644 --- a/soh/assets/xml/GC_MQ_D/objects/object_mo.xml +++ b/soh/assets/xml/GC_MQ_D/objects/object_mo.xml @@ -79,7 +79,7 @@ - + diff --git a/soh/assets/xml/GC_MQ_D/overlays/ovl_Boss_Dodongo.xml b/soh/assets/xml/GC_MQ_D/overlays/ovl_Boss_Dodongo.xml index f2ee5b7b8c0..0e2c84f578b 100644 --- a/soh/assets/xml/GC_MQ_D/overlays/ovl_Boss_Dodongo.xml +++ b/soh/assets/xml/GC_MQ_D/overlays/ovl_Boss_Dodongo.xml @@ -1,6 +1,6 @@ - + diff --git a/soh/assets/xml/GC_MQ_PAL_F/objects/object_mo.xml b/soh/assets/xml/GC_MQ_PAL_F/objects/object_mo.xml index 2a6247c9f5c..b4528ef3176 100644 --- a/soh/assets/xml/GC_MQ_PAL_F/objects/object_mo.xml +++ b/soh/assets/xml/GC_MQ_PAL_F/objects/object_mo.xml @@ -8,7 +8,7 @@ - + @@ -69,17 +69,17 @@ - + - + - + diff --git a/soh/assets/xml/GC_MQ_PAL_F/overlays/ovl_Boss_Dodongo.xml b/soh/assets/xml/GC_MQ_PAL_F/overlays/ovl_Boss_Dodongo.xml index 0e1303c17d7..8a1c4ee94cc 100644 --- a/soh/assets/xml/GC_MQ_PAL_F/overlays/ovl_Boss_Dodongo.xml +++ b/soh/assets/xml/GC_MQ_PAL_F/overlays/ovl_Boss_Dodongo.xml @@ -1,6 +1,6 @@ - - + + diff --git a/soh/assets/xml/GC_MQ_PAL_F/text/message_data_static.xml b/soh/assets/xml/GC_MQ_PAL_F/text/message_data_static.xml index 400a27e27d0..5241e3ef766 100644 --- a/soh/assets/xml/GC_MQ_PAL_F/text/message_data_static.xml +++ b/soh/assets/xml/GC_MQ_PAL_F/text/message_data_static.xml @@ -1,14 +1,14 @@ - + - + - + - + diff --git a/soh/assets/xml/GC_NMQ_D/objects/object_mo.xml b/soh/assets/xml/GC_NMQ_D/objects/object_mo.xml index 2a6247c9f5c..b4528ef3176 100644 --- a/soh/assets/xml/GC_NMQ_D/objects/object_mo.xml +++ b/soh/assets/xml/GC_NMQ_D/objects/object_mo.xml @@ -8,7 +8,7 @@ - + @@ -69,17 +69,17 @@ - + - + - + diff --git a/soh/assets/xml/GC_NMQ_D/overlays/ovl_Boss_Dodongo.xml b/soh/assets/xml/GC_NMQ_D/overlays/ovl_Boss_Dodongo.xml index f6a52f04433..d31e4abcc60 100644 --- a/soh/assets/xml/GC_NMQ_D/overlays/ovl_Boss_Dodongo.xml +++ b/soh/assets/xml/GC_NMQ_D/overlays/ovl_Boss_Dodongo.xml @@ -1,6 +1,6 @@ - + diff --git a/soh/assets/xml/GC_NMQ_PAL_F/objects/object_mo.xml b/soh/assets/xml/GC_NMQ_PAL_F/objects/object_mo.xml index 2a6247c9f5c..b4528ef3176 100644 --- a/soh/assets/xml/GC_NMQ_PAL_F/objects/object_mo.xml +++ b/soh/assets/xml/GC_NMQ_PAL_F/objects/object_mo.xml @@ -8,7 +8,7 @@ - + @@ -69,17 +69,17 @@ - + - + - + diff --git a/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Boss_Dodongo.xml b/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Boss_Dodongo.xml index f2ee5b7b8c0..67d85d16896 100644 --- a/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Boss_Dodongo.xml +++ b/soh/assets/xml/GC_NMQ_PAL_F/overlays/ovl_Boss_Dodongo.xml @@ -1,6 +1,6 @@ - - - + + + diff --git a/soh/assets/xml/N64_PAL_10/objects/object_mo.xml b/soh/assets/xml/N64_PAL_10/objects/object_mo.xml index 2a6247c9f5c..b4528ef3176 100644 --- a/soh/assets/xml/N64_PAL_10/objects/object_mo.xml +++ b/soh/assets/xml/N64_PAL_10/objects/object_mo.xml @@ -8,7 +8,7 @@ - + @@ -69,17 +69,17 @@ - + - + - + diff --git a/soh/assets/xml/N64_PAL_10/overlays/ovl_Boss_Dodongo.xml b/soh/assets/xml/N64_PAL_10/overlays/ovl_Boss_Dodongo.xml index 8f0c7612c2e..5e4975bc1d4 100644 --- a/soh/assets/xml/N64_PAL_10/overlays/ovl_Boss_Dodongo.xml +++ b/soh/assets/xml/N64_PAL_10/overlays/ovl_Boss_Dodongo.xml @@ -1,6 +1,6 @@ - + diff --git a/soh/assets/xml/N64_PAL_11/objects/object_mo.xml b/soh/assets/xml/N64_PAL_11/objects/object_mo.xml index 2a6247c9f5c..b4528ef3176 100644 --- a/soh/assets/xml/N64_PAL_11/objects/object_mo.xml +++ b/soh/assets/xml/N64_PAL_11/objects/object_mo.xml @@ -8,7 +8,7 @@ - + @@ -69,17 +69,17 @@ - + - + - + diff --git a/soh/assets/xml/N64_PAL_11/overlays/ovl_Boss_Dodongo.xml b/soh/assets/xml/N64_PAL_11/overlays/ovl_Boss_Dodongo.xml index cd9069e13f2..d6f77448d1e 100644 --- a/soh/assets/xml/N64_PAL_11/overlays/ovl_Boss_Dodongo.xml +++ b/soh/assets/xml/N64_PAL_11/overlays/ovl_Boss_Dodongo.xml @@ -1,6 +1,6 @@ - + diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index 935935c4801..eb69f3cc852 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -312,6 +312,7 @@ namespace GameControlEditor { DrawHelpIcon("Allows the cursor on the pause menu to be over any slot. Sometimes required in rando to select " "certain items."); UIWidgets::Spacer(0); + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); UIWidgets::PaddedEnhancementCheckbox("Enable walk speed modifiers", "gEnableWalkModify", true, false); DrawHelpIcon("Hold the assigned button to change the maximum walking speed\nTo change the assigned button, go into the Ports tabs above"); if (CVarGetInteger("gEnableWalkModify", 0)) { @@ -323,6 +324,7 @@ namespace GameControlEditor { UIWidgets::PaddedEnhancementSliderFloat("Modifier 2: %d %%", "##WalkMod2", "gWalkModifierTwo", 0.0f, 5.0f, "", 1.0f, true, true, false, true); window->EndGroupPanelPublic(0); } + ImGui::EndDisabled(); UIWidgets::Spacer(0); UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL"); DrawHelpIcon("Speak to Navi with L but enter first-person camera with C-Up"); diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index 0c5ba8ed390..6b5b5d7a4df 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -1485,6 +1485,7 @@ void Draw_Placements(){ } void DrawSillyTab() { + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); if (CVarGetInteger("gLetItSnow", 0)) { if (UIWidgets::EnhancementCheckbox("Let It Snow", "gLetItSnow")) { LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); @@ -1569,6 +1570,7 @@ void DrawSillyTab() { CVarClear("gCosmetics.Kak_Windmill_Speed.Changed"); LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } + ImGui::EndDisabled(); } // Copies the RGB values from one cosmetic option to another, multiplied by the passed in amount, this diff --git a/soh/soh/Enhancements/enhancementTypes.h b/soh/soh/Enhancements/enhancementTypes.h index 529ebed81ed..c8461bbf1a3 100644 --- a/soh/soh/Enhancements/enhancementTypes.h +++ b/soh/soh/Enhancements/enhancementTypes.h @@ -1,3 +1,6 @@ +#ifndef _ENHANCEMENT_TYPES_H_ +#define _ENHANCEMENT_TYPES_H_ + typedef enum { WARP_MODE_OVERRIDE_OFF, WARP_MODE_OVERRIDE_MQ_AS_VANILLA, @@ -74,3 +77,5 @@ typedef enum { DEKU_STICK_UNBREAKABLE, DEKU_STICK_UNBREAKABLE_AND_ALWAYS_ON_FIRE, } DekuStickType; + +#endif diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index a8242f963ec..34066c7abe6 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -48,6 +48,7 @@ void ReloadSceneTogglingLinkAge() { void RegisterInfiniteMoney() { GameInteractor::Instance->RegisterGameHook([]() { + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gInfiniteMoney", 0) != 0) { if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) { gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET); @@ -58,6 +59,7 @@ void RegisterInfiniteMoney() { void RegisterInfiniteHealth() { GameInteractor::Instance->RegisterGameHook([]() { + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gInfiniteHealth", 0) != 0) { if (gSaveContext.health < gSaveContext.healthCapacity) { gSaveContext.health = gSaveContext.healthCapacity; @@ -68,6 +70,7 @@ void RegisterInfiniteHealth() { void RegisterInfiniteAmmo() { GameInteractor::Instance->RegisterGameHook([]() { + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gInfiniteAmmo", 0) != 0) { // Deku Sticks if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) { @@ -104,6 +107,7 @@ void RegisterInfiniteAmmo() { void RegisterInfiniteMagic() { GameInteractor::Instance->RegisterGameHook([]() { + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gInfiniteMagic", 0) != 0) { if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) { gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30; @@ -114,6 +118,7 @@ void RegisterInfiniteMagic() { void RegisterInfiniteNayrusLove() { GameInteractor::Instance->RegisterGameHook([]() { + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gInfiniteNayru", 0) != 0) { gSaveContext.nayrusLoveTimer = 0x44B; } @@ -122,7 +127,7 @@ void RegisterInfiniteNayrusLove() { void RegisterMoonJumpOnL() { GameInteractor::Instance->RegisterGameHook([]() { - if (!gPlayState) return; + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gMoonJumpOnL", 0) != 0) { Player* player = GET_PLAYER(gPlayState); @@ -137,7 +142,7 @@ void RegisterMoonJumpOnL() { void RegisterInfiniteISG() { GameInteractor::Instance->RegisterGameHook([]() { - if (!gPlayState) return; + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gEzISG", 0) != 0) { Player* player = GET_PLAYER(gPlayState); @@ -149,7 +154,7 @@ void RegisterInfiniteISG() { //Permanent quick put away (QPA) glitched damage value void RegisterEzQPA() { GameInteractor::Instance->RegisterGameHook([]() { - if (!gPlayState) return; + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gEzQPA", 0) != 0) { Player* player = GET_PLAYER(gPlayState); @@ -161,7 +166,7 @@ void RegisterEzQPA() { void RegisterUnrestrictedItems() { GameInteractor::Instance->RegisterGameHook([]() { - if (!gPlayState) return; + if (!GameInteractor::IsSaveLoaded()) return; if (CVarGetInteger("gNoRestrictItems", 0) != 0) { u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong; @@ -189,14 +194,16 @@ void RegisterFreezeTime() { /// Switches Link's age and respawns him at the last entrance he entered. void RegisterSwitchAge() { GameInteractor::Instance->RegisterGameHook([]() { + if (!GameInteractor::IsSaveLoaded()) { + CVarClear("gSwitchAge"); + return; + } static bool warped = false; static Vec3f playerPos; static int16_t playerYaw; static RoomContext* roomCtx; static s32 roomNum; - if (!gPlayState) return; - if (CVarGetInteger("gSwitchAge", 0) && !warped) { playerPos = GET_PLAYER(gPlayState)->actor.world.pos; playerYaw = GET_PLAYER(gPlayState)->actor.shape.rot.y; @@ -216,7 +223,7 @@ void RegisterSwitchAge() { func_80097534(gPlayState, roomCtx); // load map for new room (unloading the previous room) } warped = false; - CVarSetInteger("gSwitchAge", 0); + CVarClear("gSwitchAge"); } }); } @@ -225,7 +232,8 @@ void RegisterSwitchAge() { void RegisterOcarinaTimeTravel() { GameInteractor::Instance->RegisterGameHook([]() { - if (!gPlayState) { + if (!GameInteractor::IsSaveLoaded()) { + CVarClear("gTimeTravel"); return; } @@ -1033,8 +1041,16 @@ void RegisterRandomizedEnemySizes() { Player* player = GET_PLAYER(gPlayState); Actor* actor = static_cast(refActor); - // Only apply to enemies and bosses. Exclude the wobbly platforms in Jabu because they need to act like platforms. - if (!CVarGetInteger("gRandomizedEnemySizes", 0) || (actor->category != ACTORCAT_ENEMY && actor->category != ACTORCAT_BOSS) || actor->id == ACTOR_EN_BROB) { + // Exclude wobbly platforms in Jabu because they need to act like platforms. + // Exclude Dead Hand hands and Bongo Bongo main body because they make the fights (near) impossible. + uint8_t excludedEnemy = actor->id == ACTOR_EN_BROB || actor->id == ACTOR_EN_DHA || (actor->id == ACTOR_BOSS_SST && actor->params == -1); + + // Dodongo, Volvagia and Dead Hand are always smaller because they're impossible when bigger. + uint8_t smallOnlyEnemy = + actor->id == ACTOR_BOSS_DODONGO || actor->id == ACTOR_BOSS_FD || actor->id == ACTOR_BOSS_FD2 || ACTOR_EN_DH; + + // Only apply to enemies and bosses. + if (!CVarGetInteger("gRandomizedEnemySizes", 0) || (actor->category != ACTORCAT_ENEMY && actor->category != ACTORCAT_BOSS) || excludedEnemy) { return; } @@ -1043,9 +1059,8 @@ void RegisterRandomizedEnemySizes() { uint8_t bigActor = rand() % 2; - // Big actor. Dodongo and Volvagia are always smaller because they're impossible when bigger. - if (bigActor && actor->id != ACTOR_BOSS_DODONGO && actor->id != ACTOR_BOSS_FD && - actor->id != ACTOR_BOSS_FD2) { + // Big actor + if (bigActor && !smallOnlyEnemy) { randomNumber = rand() % 200; // Between 100% and 300% size. randomScale = 1.0f + (randomNumber / 100); diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index f0f586e0031..22c9dd7db3d 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -217,6 +217,31 @@ const std::vector enhancementsCvars = { "gFixTexturesOOB", "gIvanCoopModeEnabled", "gEnemySpawnsOverWaterboxes", + "gTreeStickDrops", + "gShadowTag", + "gRandomizedEnemySizes", + "gRandomizedEnemies", + "gMirroredWorldMode", + "gMirroredWorld", + "gHyperEnemies", + "gHookshotableReticle", + "gHideBunnyHood", + "gFixVineFall", + "gFileSelectMoreInfo", + "gEnemyHealthBar", + "gBushDropFix", + "gAllDogsRichard", + "gAddTraps.enabled", + "gAddTraps.Ammo", + "gAddTraps.Bomb", + "gAddTraps.Burn", + "gAddTraps.Ice", + "gAddTraps.Kill", + "gAddTraps.Knock", + "gAddTraps.Shock", + "gAddTraps.Speed", + "gAddTraps.Tele", + "gAddTraps.Void", }; const std::vector cheatCvars = { @@ -269,7 +294,23 @@ const std::vector cheatCvars = { "gNoRedeadFreeze", "gBombTimerMultiplier", "gNoFishDespawn", - "gNoBugsDespawn" + "gNoBugsDespawn", + "gWalkModifierDoesntChangeJump", + "gStatsEnabled", + "gSaveStatesEnabled", + "gSaveStatePromise", + "gRegEditEnabled", + "gPreset0", + "gPreset1", + "gDekuStickCheat", + "gDebugWarpScreenTranslation", + "gDebugSaveFileMode", + "gCosmetics.Link_BodyScale.Changed", + "gCosmetics.Link_BodyScale.Value", + "gCosmetics.Link_HeadScale.Changed", + "gCosmetics.Link_HeadScale.Value", + "gCosmetics.Link_SwordScale.Changed", + "gCosmetics.Link_SwordScale.Value", }; const std::vector randomizerCvars = { @@ -399,6 +440,15 @@ const std::vector randomizerCvars = { "gRandomizeGregHint", "gRandoManualSeedEntry", "gRandomizerSettingsEnabled", + "gRandomizeTriforceHuntTotalPieces", + "gRandomizeTriforceHuntRequiredPieces", + "gRandomizeTriforceHunt", + "gRandomizeShuffleMasterSword", + "gRandomizeSariaHint", + "gRandomizeRupeeNames", + "gRandomizeFrogsHint", + "gRandoRelevantNavi", + "gRandoQuestItemFanfares", }; const std::vector vanillaPlusPresetEntries = { diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp index 577de1c1958..0ab29d8692d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp @@ -24,11 +24,11 @@ void LocationTable_Init() { //Lost Woods locationTable[LW_NEAR_SHORTCUTS_GROTTO_CHEST] = ItemLocation::Chest (RC_LW_NEAR_SHORTCUTS_GROTTO_CHEST, 0x3E, 0x14, "LW Near Shortcuts Grotto Chest", LW_NEAR_SHORTCUTS_GROTTO_CHEST, BLUE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); - locationTable[LW_SKULL_KID] = ItemLocation::Base (RC_LW_SKULL_KID, 0x5B, "LW Skull Kid", LW_SKULL_KID, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(30), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_SKULL_KID] = ItemLocation::Base (RC_LW_SKULL_KID, 0x5B, "LW Skull Kid", LW_SKULL_KID, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(22), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_TRADE_COJIRO] = ItemLocation::Base (RC_LW_TRADE_COJIRO, 0x5B, "LW Trade Cojiro", LW_TRADE_COJIRO, ODD_MUSHROOM, {Category::cAdultTrade}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); - locationTable[LW_TRADE_ODD_POTION] = ItemLocation::Base (RC_LW_TRADE_ODD_POTION, 0x5B, "LW Trade Odd Potion", LW_TRADE_ODD_POTION, ODD_POTION, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(57), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); - locationTable[LW_OCARINA_MEMORY_GAME] = ItemLocation::Base (RC_LW_OCARINA_MEMORY_GAME, 0x5B, "LW Ocarina Memory Game", LW_OCARINA_MEMORY_GAME, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(31), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); - locationTable[LW_TARGET_IN_WOODS] = ItemLocation::Base (RC_LW_TARGET_IN_WOODS, 0x5B, "LW Target in Woods", LW_TARGET_IN_WOODS, PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(21), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_TRADE_ODD_POTION] = ItemLocation::Base (RC_LW_TRADE_ODD_POTION, 0x5B, "LW Trade Odd Potion", LW_TRADE_ODD_POTION, ODD_POTION, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(49), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_OCARINA_MEMORY_GAME] = ItemLocation::Base (RC_LW_OCARINA_MEMORY_GAME, 0x5B, "LW Ocarina Memory Game", LW_OCARINA_MEMORY_GAME, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(23), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_TARGET_IN_WOODS] = ItemLocation::Base (RC_LW_TARGET_IN_WOODS, 0x5B, "LW Target in Woods", LW_TARGET_IN_WOODS, PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(29), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, 0x5B, "LW Deku Scrub Near Deku Theater Right",LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, BUY_DEKU_NUT_5, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, 0x5B, "LW Deku Scrub Near Deku Theater Left", LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, BUY_DEKU_STICK_1, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); locationTable[LW_DEKU_SCRUB_NEAR_BRIDGE] = ItemLocation::Base (RC_LW_DEKU_SCRUB_NEAR_BRIDGE, 0x5B, "LW Deku Scrub Near Bridge", LW_DEKU_SCRUB_NEAR_BRIDGE, PROGRESSIVE_STICK_UPGRADE, {Category::cDekuScrub, Category::cDekuScrubUpgrades}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); @@ -53,7 +53,7 @@ void LocationTable_Init() { //Lake Hylia locationTable[LH_CHILD_FISHING] = ItemLocation::Base (RC_LH_CHILD_FISHING, 0x49, "LH Child Fishing", LH_CHILD_FISHING, PIECE_OF_HEART, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_ADULT_FISHING] = ItemLocation::Base (RC_LH_ADULT_FISHING, 0x49, "LH Adult Fishing", LH_ADULT_FISHING, PROGRESSIVE_SCALE, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); - locationTable[LH_LAB_DIVE] = ItemLocation::Base (RC_LH_LAB_DIVE, 0x38, "LH Lab Dive", LH_LAB_DIVE, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(24), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_LAB_DIVE] = ItemLocation::Base (RC_LH_LAB_DIVE, 0x38, "LH Lab Dive", LH_LAB_DIVE, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(16), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_TRADE_FROG] = ItemLocation::Base (RC_LH_TRADE_FROG, 0x38, "LH Lab Trade Eyeball Frog", LH_TRADE_FROG, EYEDROPS, {Category::cAdultTrade}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_UNDERWATER_ITEM] = ItemLocation::Base (RC_LH_UNDERWATER_ITEM, 0x57, "LH Underwater Item", LH_UNDERWATER_ITEM, RUTOS_LETTER, {}, SpoilerCollectionCheck::EventChkInf(0x31), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); locationTable[LH_SUN] = ItemLocation::Base (RC_LH_SUN, 0x57, "LH Sun", LH_SUN, FIRE_ARROWS, {}, SpoilerCollectionCheck::Chest(0x57, 0x1F), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); @@ -73,7 +73,7 @@ void LocationTable_Init() { //Gerudo Fortress locationTable[GF_CHEST] = ItemLocation::Chest (RC_GF_CHEST, 0x5D, 0x00, "GF Chest", GF_CHEST, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_HBA_1000_POINTS] = ItemLocation::Base (RC_GF_HBA_1000_POINTS, 0x5D, "GF HBA 1000 Points", GF_HBA_1000_POINTS, PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(0x19, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); - locationTable[GF_HBA_1500_POINTS] = ItemLocation::Base (RC_GF_HBA_1500_POINTS, 0x5D, "GF HBA 1500 Points", GF_HBA_1500_POINTS, PROGRESSIVE_BOW, {}, SpoilerCollectionCheck::ItemGetInf(7), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_HBA_1500_POINTS] = ItemLocation::Base (RC_GF_HBA_1500_POINTS, 0x5D, "GF HBA 1500 Points", GF_HBA_1500_POINTS, PROGRESSIVE_BOW, {}, SpoilerCollectionCheck::ItemGetInf(15), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_GERUDO_MEMBERSHIP_CARD] = ItemLocation::Base (RC_GF_GERUDO_MEMBERSHIP_CARD, 0x0C, "GF Gerudo Membership Card", GF_GERUDO_MEMBERSHIP_CARD, GERUDO_MEMBERSHIP_CARD, {}, SpoilerCollectionCheck::GerudoToken(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_NORTH_F1_CARPENTER] = ItemLocation::Collectable(RC_GF_NORTH_F1_CARPENTER, 0x0C, 0x0C, "GF North F1 Carpenter", GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[GF_NORTH_F2_CARPENTER] = ItemLocation::Collectable(RC_GF_NORTH_F2_CARPENTER, 0x0C, 0x0A, "GF North F2 Carpenter", GF_NORTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); @@ -90,12 +90,12 @@ void LocationTable_Init() { locationTable[COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, 0xFD, "Colossus Deku Scrub Grotto Front", COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); //Market - locationTable[MARKET_TREASURE_CHEST_GAME_REWARD] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_REWARD, 0x10, "MK Treasure Chest Game Reward", MARKET_TREASURE_CHEST_GAME_REWARD, TREASURE_GAME_HEART, {}, SpoilerCollectionCheck::ItemGetInf(19), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); - locationTable[MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, 0x4B, "MK Bombchu Bowling First Prize", MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, PROGRESSIVE_BOMB_BAG, {}, SpoilerCollectionCheck::ItemGetInf(25), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); - locationTable[MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, 0x4B, "MK Bombchu Bowling Second Prize", MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(26), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_REWARD] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_REWARD, 0x10, "MK Treasure Chest Game Reward", MARKET_TREASURE_CHEST_GAME_REWARD, TREASURE_GAME_HEART, {}, SpoilerCollectionCheck::ItemGetInf(27), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, 0x4B, "MK Bombchu Bowling First Prize", MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, PROGRESSIVE_BOMB_BAG, {}, SpoilerCollectionCheck::ItemGetInf(17), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, 0x4B, "MK Bombchu Bowling Second Prize", MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(18), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_BOMBCHU_BOWLING_BOMBCHUS] = ItemLocation::Base (RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, 0x4B, "MK Bombchu Bowling Bombchus", NONE, BOMBCHU_DROP, {}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_LOST_DOG] = ItemLocation::Base (RC_MARKET_LOST_DOG, 0x35, "MK Lost Dog", MARKET_LOST_DOG, PIECE_OF_HEART, {}, SpoilerCollectionCheck::InfTable(0x19, 0x09), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); - locationTable[MARKET_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_MARKET_SHOOTING_GALLERY_REWARD, 0x42, "MK Shooting Gallery", MARKET_SHOOTING_GALLERY_REWARD, PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_MARKET_SHOOTING_GALLERY_REWARD, 0x42, "MK Shooting Gallery", MARKET_SHOOTING_GALLERY_REWARD, PROGRESSIVE_SLINGSHOT, {}, SpoilerCollectionCheck::ItemGetInf(13), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_10_BIG_POES] = ItemLocation::Base (RC_MARKET_10_BIG_POES, 0x4D, "MK 10 Big Poes", MARKET_10_BIG_POES, EMPTY_BOTTLE, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_1] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, 0x10, 0x01, "MK Chest Game First Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_1, TREASURE_GAME_SMALL_KEY, {Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_2] = ItemLocation::Chest (RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, 0x10, 0x03, "MK Chest Game Second Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_2, TREASURE_GAME_SMALL_KEY, {Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); @@ -115,14 +115,14 @@ void LocationTable_Init() { locationTable[KAK_30_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_30_GOLD_SKULLTULA_REWARD, 0x50, "Kak 30 Gold Skulltula Reward", KAK_30_GOLD_SKULLTULA_REWARD, PROGRESSIVE_WALLET, {}, SpoilerCollectionCheck::EventChkInf(0xDC), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_40_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_40_GOLD_SKULLTULA_REWARD, 0x50, "Kak 40 Gold Skulltula Reward", KAK_40_GOLD_SKULLTULA_REWARD, BOMBCHU_10, {}, SpoilerCollectionCheck::EventChkInf(0xDD), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_50_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_50_GOLD_SKULLTULA_REWARD, 0x50, "Kak 50 Gold Skulltula Reward", KAK_50_GOLD_SKULLTULA_REWARD, PIECE_OF_HEART, {}, SpoilerCollectionCheck::EventChkInf(0xDE), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_100_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_100_GOLD_SKULLTULA_REWARD, 0x50, "Kak 100 Gold Skulltula Reward", KAK_100_GOLD_SKULLTULA_REWARD, HUGE_RUPEE, {}, SpoilerCollectionCheck::EventChkInf(0xDF), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_MAN_ON_ROOF] = ItemLocation::Base (RC_KAK_MAN_ON_ROOF, 0x52, "Kak Man on Roof", KAK_MAN_ON_ROOF, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(29), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_100_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (RC_KAK_100_GOLD_SKULLTULA_REWARD, 0x50, "Kak 100 Gold Skulltula Reward", KAK_100_GOLD_SKULLTULA_REWARD, HUGE_RUPEE, {}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_MAN_ON_ROOF] = ItemLocation::Base (RC_KAK_MAN_ON_ROOF, 0x52, "Kak Man on Roof", KAK_MAN_ON_ROOF, PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(21), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (RC_KAK_SHOOTING_GALLERY_REWARD, 0x42, "Kak Shooting Gallery Reward", KAK_SHOOTING_GALLERY_REWARD, PROGRESSIVE_BOW, {}, SpoilerCollectionCheck::Chest(0x42, 0x1F), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_TRADE_ODD_MUSHROOM] = ItemLocation::Base (RC_KAK_TRADE_ODD_MUSHROOM, 0x4E, "Kak Trade Odd Mushroom", KAK_TRADE_ODD_MUSHROOM, ODD_POTION, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(56), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_TRADE_ODD_MUSHROOM] = ItemLocation::Base (RC_KAK_TRADE_ODD_MUSHROOM, 0x4E, "Kak Trade Odd Mushroom", KAK_TRADE_ODD_MUSHROOM, ODD_POTION, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(48), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_GRANNYS_SHOP] = ItemLocation::Base (RC_KAK_GRANNYS_SHOP, 0x4E, "Kak Granny's Shop", KAK_GRANNYS_SHOP, BLUE_POTION_REFILL, {Category::cMerchant}, SpoilerCollectionCheck::RandomizerInf(), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_ANJU_AS_ADULT] = ItemLocation::Base (RC_KAK_ANJU_AS_ADULT, 0x52, "Kak Anju as Adult", KAK_ANJU_AS_ADULT, CLAIM_CHECK, {}, SpoilerCollectionCheck::ItemGetInf(36), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_ANJU_AS_CHILD] = ItemLocation::Base (RC_KAK_ANJU_AS_CHILD, 0x52, "Kak Anju as Child", KAK_ANJU_AS_CHILD, EMPTY_BOTTLE, {}, SpoilerCollectionCheck::ItemGetInf(4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[KAK_TRADE_POCKET_CUCCO] = ItemLocation::Base (RC_KAK_TRADE_POCKET_CUCCO, 0x52, "Kak Trade Pocket Cucco", KAK_TRADE_POCKET_CUCCO, COJIRO, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(38), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_ANJU_AS_ADULT] = ItemLocation::Base (RC_KAK_ANJU_AS_ADULT, 0x52, "Kak Anju as Adult", KAK_ANJU_AS_ADULT, CLAIM_CHECK, {}, SpoilerCollectionCheck::ItemGetInf(44), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_ANJU_AS_CHILD] = ItemLocation::Base (RC_KAK_ANJU_AS_CHILD, 0x52, "Kak Anju as Child", KAK_ANJU_AS_CHILD, EMPTY_BOTTLE, {}, SpoilerCollectionCheck::ItemGetInf(12), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_TRADE_POCKET_CUCCO] = ItemLocation::Base (RC_KAK_TRADE_POCKET_CUCCO, 0x52, "Kak Trade Pocket Cucco", KAK_TRADE_POCKET_CUCCO, COJIRO, {Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(46), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = ItemLocation::Collectable(RC_KAK_IMPAS_HOUSE_FREESTANDING_POH, 0x37, 0x01, "Kak Impas House Freestanding PoH", KAK_IMPAS_HOUSE_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[KAK_WINDMILL_FREESTANDING_POH] = ItemLocation::Collectable(RC_KAK_WINDMILL_FREESTANDING_POH, 0x48, 0x01, "Kak Windmill Freestanding PoH", KAK_WINDMILL_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); @@ -133,7 +133,7 @@ void LocationTable_Init() { locationTable[GRAVEYARD_HOOKSHOT_CHEST] = ItemLocation::Chest (RC_GRAVEYARD_HOOKSHOT_CHEST, 0x48, 0x00, "GY Hookshot Chest", GRAVEYARD_HOOKSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[GRAVEYARD_DAMPE_RACE_FREESTANDING_POH] = ItemLocation::Collectable(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, 0x48, 0x07, "GY Dampe Race Freestanding PoH", GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); locationTable[GRAVEYARD_FREESTANDING_POH] = ItemLocation::Collectable(RC_GRAVEYARD_FREESTANDING_POH, 0x53, 0x04, "GY Freestanding PoH", GRAVEYARD_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); - locationTable[GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR] = ItemLocation::Collectable(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, 0x53, "GY Dampe Gravedigging Tour", GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, PIECE_OF_HEART, {}, SpoilerCollectionCheck::Gravedigger(0x53, 0x1F), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR] = ItemLocation::Collectable(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, 0x53, "GY Dampe Gravedigging Tour", GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, PIECE_OF_HEART, {}, SpoilerCollectionCheck::Gravedigger(0x53, 0x19), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); //Death Mountain locationTable[DMT_CHEST] = ItemLocation::Chest (RC_DMT_CHEST, 0x60, 0x01, "DMT Chest", DMT_CHEST, PURPLE_RUPEE, {}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); @@ -191,7 +191,7 @@ void LocationTable_Init() { locationTable[ZF_BOTTOM_FREESTANDING_POH] = ItemLocation::Collectable(RC_ZF_BOTTOM_FREESTANDING_POH, 0x59, 0x14, "ZF Bottom Freestanding PoH", ZF_BOTTOM_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); //Lon Lon Ranch - locationTable[LLR_TALONS_CHICKENS] = ItemLocation::Base (RC_LLR_TALONS_CHICKENS, 0x4C, "LLR Talons Chickens", LLR_TALONS_CHICKENS, BOTTLE_WITH_MILK, {}, SpoilerCollectionCheck::ItemGetInf(10), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_TALONS_CHICKENS] = ItemLocation::Base (RC_LLR_TALONS_CHICKENS, 0x4C, "LLR Talons Chickens", LLR_TALONS_CHICKENS, BOTTLE_WITH_MILK, {}, SpoilerCollectionCheck::ItemGetInf(2), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); locationTable[LLR_FREESTANDING_POH] = ItemLocation::Collectable(RC_LLR_FREESTANDING_POH, 0x4C, 0x01, "LLR Freestanding PoH", LLR_FREESTANDING_POH, PIECE_OF_HEART, {}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); locationTable[LLR_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, 0xFC, "LLR Deku Scrub Grotto Left", LLR_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); locationTable[LLR_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, 0xFC, "LLR Deku Scrub Grotto Right", LLR_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp index 088ba506756..62042246c36 100644 --- a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -1,5 +1,6 @@ #include "playthrough.hpp" +#include #include #include "custom_messages.hpp" #include "fill.hpp" @@ -8,6 +9,7 @@ #include "random.hpp" #include "spoiler_log.hpp" #include "soh/Enhancements/randomizer/randomizerTypes.h" +#include "variables.h" namespace Playthrough { @@ -39,6 +41,10 @@ int Playthrough_Init(uint32_t seed, std::unordered_map{}(std::to_string(Settings::seed) + settingsStr); Random_Init(finalHash); Settings::hash = std::to_string(finalHash); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 1705f9776d8..d9342e92ae9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -361,37 +361,35 @@ std::unordered_map SpoilerfileSettingNameToEn { "Shuffle Dungeon Quest:Ganon's Castle", RSK_MQ_GANONS_CASTLE }, }; -std::string sanitize(std::string stringValue) { - // Add backslashes. - for (auto i = stringValue.begin();;) { - auto const pos = std::find_if(i, stringValue.end(), [](char const c) { return '\\' == c || '\'' == c || '"' == c; }); - if (pos == stringValue.end()) { - break; - } - i = std::next(stringValue.insert(pos, '\\'), 2); - } - - // Removes others. - stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(), [](char const c) { - return '\n' == c || '\r' == c || '\0' == c || '\x1A' == c; }), stringValue.end()); - - return stringValue; -} - #pragma optimize("", off) #pragma GCC push_options #pragma GCC optimize ("O0") bool Randomizer::SpoilerFileExists(const char* spoilerFileName) { - if (strcmp(spoilerFileName, "") != 0) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); - if (!spoilerFileStream) { - return false; - } else { + try { + if (strcmp(spoilerFileName, "") != 0) { + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); + if (!spoilerFileStream) { + return false; + } + + json spoilerFileJson; + spoilerFileStream >> spoilerFileJson; + + if (!spoilerFileJson.contains("version") || !spoilerFileJson.contains("finalSeed")) { + return false; + } + return true; } - } - return false; + return false; + } catch (std::exception& e) { + SPDLOG_ERROR("Error checking if spoiler file exists: {}", e.what()); + return false; + } catch (...) { + SPDLOG_ERROR("Error checking if spoiler file exists"); + return false; + } } #pragma GCC pop_options #pragma optimize("", on) @@ -660,7 +658,7 @@ void Randomizer::LoadMasterQuestDungeons(const char* spoilerFileName) { } void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) return; @@ -1294,7 +1292,7 @@ std::string FormatJsonHintText(std::string jsonHint) { } void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) return; @@ -1395,7 +1393,7 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { } void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) { return; } @@ -1416,7 +1414,7 @@ void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { } void Randomizer::ParseMasterQuestDungeonsFile(const char* spoilerFileName) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) { return; } @@ -1496,7 +1494,7 @@ int16_t Randomizer::GetVanillaMerchantPrice(RandomizerCheck check) { } void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) return; @@ -1559,7 +1557,7 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent } void Randomizer::ParseEntranceDataFile(const char* spoilerFileName, bool silent) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) { return; } @@ -2548,6 +2546,7 @@ std::map rcToRandomizerInf = { { RC_LH_CHILD_FISHING, RAND_INF_CHILD_FISHING }, { RC_LH_ADULT_FISHING, RAND_INF_ADULT_FISHING }, { RC_MARKET_10_BIG_POES, RAND_INF_10_BIG_POES }, + { RC_KAK_100_GOLD_SKULLTULA_REWARD, RAND_INF_KAK_100_GOLD_SKULLTULA_REWARD }, }; RandomizerCheckObject Randomizer::GetCheckObjectFromActor(s16 actorId, s16 sceneNum, s32 actorParams = 0x00) { @@ -3144,7 +3143,9 @@ void RandomizerSettingsWindow::DrawElement() { UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); } + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); DrawPresetSelector(PRESET_TYPE_RANDOMIZER); + ImGui::EndDisabled(); UIWidgets::Spacer(0); UIWidgets::EnhancementCheckbox("Manual seed entry", "gRandoManualSeedEntry", false, ""); @@ -3167,13 +3168,17 @@ void RandomizerSettingsWindow::DrawElement() { } UIWidgets::Spacer(0); + ImGui::BeginDisabled(CVarGetInteger("gRandomizerDontGenerateSpoiler", 0) && gSaveContext.gameMode != GAMEMODE_FILE_SELECT); if (ImGui::Button("Generate Randomizer")) { GenerateRandomizer(CVarGetInteger("gRandoManualSeedEntry", 0) ? seedString : ""); } + ImGui::EndDisabled(); UIWidgets::Spacer(0); - std::string spoilerfilepath = CVarGetString("gSpoilerLog", ""); - ImGui::Text("Spoiler File: %s", spoilerfilepath.c_str()); + if (!CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) { + std::string spoilerfilepath = CVarGetString("gSpoilerLog", ""); + ImGui::Text("Spoiler File: %s", spoilerfilepath.c_str()); + } // RANDOTODO settings presets // std::string presetfilepath = CVarGetString("gLoadedPreset", ""); @@ -3181,6 +3186,8 @@ void RandomizerSettingsWindow::DrawElement() { UIWidgets::PaddedSeparator(); + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); + ImGuiWindow* window = ImGui::GetCurrentWindow(); static ImVec2 cellPadding(8.0f, 8.0f); @@ -5224,6 +5231,8 @@ void RandomizerSettingsWindow::DrawElement() { ImGui::EndTabBar(); } + + ImGui::EndDisabled(); if (disableEditingRandoSettings) { UIWidgets::ReEnableComponent(""); diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp index d7f99edfb9c..d551108615b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp @@ -39,7 +39,7 @@ std::map rcObjects = { RC_OBJECT(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x01, GI_STICKS_1, "Deku Scrub Near Deku Theater Left", "LW Deku Scrub Near Deku Theater Left", false), RC_OBJECT(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x09, GI_STICK_UPGRADE_20, "Deku Scrub Near Bridge", "LW Deku Scrub Near Bridge", true), RC_OBJECT(RC_LW_DEKU_SCRUB_GROTTO_REAR, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03,0xF5), GI_SEEDS_30, "Deku Scrub Grotto Rear", "LW Deku Scrub Grotto Rear", false), - RC_OBJECT(RC_LW_DEKU_SCRUB_GROTTO_FRONT, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x0A,0xF5), GI_NUT_UPGRADE_30, "Deku Scrub Grotto Front", "LW Deku Scrub Grotto Front", false), + RC_OBJECT(RC_LW_DEKU_SCRUB_GROTTO_FRONT, RCVORMQ_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x0A,0xF5), GI_NUT_UPGRADE_30, "Deku Scrub Grotto Front", "LW Deku Scrub Grotto Front", true), RC_OBJECT(RC_DEKU_THEATER_SKULL_MASK, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_LOST_WOODS, ACTOR_ID_MAX, SCENE_GROTTOS, 0x00, GI_NONE, "Deku Theater Skull Mask", "Deku Theater Skull Mask", true), RC_OBJECT(RC_DEKU_THEATER_MASK_OF_TRUTH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_LOST_WOODS, ACTOR_ID_MAX, SCENE_GROTTOS, 0x00, GI_NONE, "Deku Theater Mask of Truth", "Deku Theater Mask of Truth", true), RC_OBJECT(RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_LOST_WOODS, ACTOR_EN_SI, SCENE_LOST_WOODS, 27905, GI_SKULL_TOKEN, "GS Bean Patch Near Bridge", "LW GS Bean Patch Near Bridge", true), @@ -238,7 +238,7 @@ std::map rcObjects = { RC_OBJECT(RC_GRAVEYARD_HOOKSHOT_CHEST, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_BOX, SCENE_WINDMILL_AND_DAMPES_GRAVE, 4352, GI_HOOKSHOT, "Hookshot Chest", "GY Hookshot Chest", true), RC_OBJECT(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_WINDMILL_AND_DAMPES_GRAVE, 1798, GI_HEART_PIECE, "Dampe Race Freestanding PoH", "GY Dampe Race Freestanding PoH", true), RC_OBJECT(RC_GRAVEYARD_FREESTANDING_POH, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_GRAVEYARD, 1030, GI_HEART_PIECE, "Freestanding PoH", "GY Freestanding PoH", true), - RC_OBJECT(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_GRAVEYARD, 7942, GI_HEART_PIECE, "Dampe Gravedigging Tour", "GY Dampe Gravedigging Tour", true), + RC_OBJECT(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, RCVORMQ_BOTH, RCTYPE_STANDARD, RCAREA_GRAVEYARD, ACTOR_EN_ITEM00, SCENE_GRAVEYARD, 6406, GI_HEART_PIECE, "Dampe Gravedigging Tour", "GY Dampe Gravedigging Tour", true), RC_OBJECT(RC_GRAVEYARD_GS_WALL, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_GRAVEYARD, ACTOR_EN_SI, SCENE_GRAVEYARD, 20608, GI_SKULL_TOKEN, "GS Wall", "Graveyard GS Wall", true), RC_OBJECT(RC_GRAVEYARD_GS_BEAN_PATCH, RCVORMQ_BOTH, RCTYPE_SKULL_TOKEN, RCAREA_GRAVEYARD, ACTOR_EN_SI, SCENE_GRAVEYARD, 28673, GI_SKULL_TOKEN, "GS Bean Patch", "Graveyard GS Bean Patch", true), RC_OBJECT(RC_SONG_FROM_ROYAL_FAMILYS_TOMB, RCVORMQ_BOTH, RCTYPE_SONG_LOCATION, RCAREA_GRAVEYARD, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, GI_NONE, "Song from Composers Grave", "Song from Composers Grave", true), diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 6123c1a2797..003c8c135a9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -73,21 +73,12 @@ bool showLinksPocket; bool fortressFast; bool fortressNormal; -bool bypassRandoCheck = true; // persistent during gameplay bool initialized; bool doAreaScroll; bool previousShowHidden = false; bool hideShopRightChecks = true; -bool checkCollected = false; -int checkLoops = 0; -int checkCounter = 0; -u16 savedFrames = 0; -bool messageCloseCheck = false; -bool pendingSaleCheck = false; -bool transitionCheck = false; - std::map startingShopItem = { { SCENE_KOKIRI_SHOP, RC_KF_SHOP_ITEM_1 }, { SCENE_BAZAAR, RC_MARKET_BAZAAR_ITEM_1 }, { SCENE_POTION_SHOP_MARKET, RC_MARKET_POTION_SHOP_ITEM_1 }, @@ -118,12 +109,9 @@ bool showVOrMQ; s8 areaChecksGotten[32]; //| "Kokiri Forest (4/9)" bool optCollapseAll; // A bool that will collapse all checks once bool optExpandAll; // A bool that will expand all checks once -RandomizerCheck lastItemGetCheck = RC_UNKNOWN_CHECK; RandomizerCheck lastLocationChecked = RC_UNKNOWN_CHECK; RandomizerCheckArea previousArea = RCAREA_INVALID; RandomizerCheckArea currentArea = RCAREA_INVALID; -std::vector checkAreas; -std::vector itemsReceived; OSContPad* trackerButtonsPressed; void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flags = 0); @@ -194,10 +182,6 @@ Color_RGBA8 Color_Saved_Extra = { 0, 185, 0, 255 }; // Green std::vector buttons = { BTN_A, BTN_B, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT, BTN_L, BTN_Z, BTN_R, BTN_START, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT }; -void SetLastItemGetRC(RandomizerCheck rc) { - lastItemGetCheck = rc; -} - void DefaultCheckData(RandomizerCheck rc) { gSaveContext.checkTrackerData[rc].status = RCSHOW_UNCHECKED; gSaveContext.checkTrackerData[rc].skipped = 0; @@ -253,9 +237,6 @@ void SetCheckCollected(RandomizerCheck rc) { } else { gSaveContext.checkTrackerData[rc].skipped = false; } - if (!checkAreas.empty()) { - checkAreas.erase(checkAreas.begin()); - } SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true); doAreaScroll = true; @@ -360,32 +341,18 @@ bool vector_contains_scene(std::vector vec, const int16_t scene) { std::vector skipScenes = {SCENE_GANON_BOSS, SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR, SCENE_GANON_BOSS, SCENE_INSIDE_GANONS_CASTLE_COLLAPSE, SCENE_GANONS_TOWER_COLLAPSE_INTERIOR}; -bool EvaluateCheck(RandomizerCheckObject rco) { - if (HasItemBeenCollected(rco.rc) && gSaveContext.checkTrackerData[rco.rc].status != RCSHOW_COLLECTED && - gSaveContext.checkTrackerData[rco.rc].status != RCSHOW_SAVED) { - SetCheckCollected(rco.rc); - return true; - } - return false; -} - -bool CheckByArea(RandomizerCheckArea area = RCAREA_INVALID) { - if (area == RCAREA_INVALID) { - area = checkAreas.front(); - } - if (area != RCAREA_INVALID) { - auto areaChecks = checksByArea.find(area)->second; - if (checkCounter >= areaChecks.size()) { - checkCounter = 0; - checkLoops++; - } - auto rco = areaChecks.at(checkCounter); - return EvaluateCheck(rco); +void ClearAreaChecksAndTotals() { + for (auto& [rcArea, vec] : checksByArea) { + vec.clear(); + areaChecksGotten[rcArea] = 0; } } void SetShopSeen(uint32_t sceneNum, bool prices) { RandomizerCheck start = startingShopItem.find(sceneNum)->second; + if (sceneNum == SCENE_POTION_SHOP_KAKARIKO && !LINK_IS_ADULT) { + return; + } if (GetCheckArea() == RCAREA_KAKARIKO_VILLAGE && sceneNum == SCENE_BAZAAR) { start = RC_KAK_BAZAAR_ITEM_1; } @@ -509,12 +476,6 @@ void CheckTrackerLoadGame(int32_t fileNum) { UpdateInventoryChecks(); } -void CheckTrackerDialogClosed() { - if (messageCloseCheck) { - messageCloseCheck = false; - } -} - void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) { if (gPlayState->sceneNum == SCENE_HAPPY_MASK_SHOP) { // Happy Mask Shop is not used in rando, so is not tracked return; @@ -536,10 +497,6 @@ void CheckTrackerTransition(uint32_t sceneNum) { if (!GameInteractor::IsSaveLoaded()) { return; } - gSaveContext; - if (transitionCheck) { - transitionCheck = false; - } doAreaScroll = true; previousArea = currentArea; currentArea = GetCheckArea(); @@ -560,29 +517,13 @@ void CheckTrackerFrame() { if (!GameInteractor::IsSaveLoaded()) { return; } - if (!checkAreas.empty() && !transitionCheck && !messageCloseCheck && !pendingSaleCheck) { - for (int i = 0; i < 10; i++) { - if (CheckByArea()) { - checkCounter = 0; - break; - } else { - checkCounter++; - } - } - if (checkLoops > 15) { - checkAreas.erase(checkAreas.begin()); - checkLoops = 0; + // TODO: Move to OnAmmoChange hook once it gets added. + if (gSaveContext.checkTrackerData[RC_ZR_MAGIC_BEAN_SALESMAN].status != RCSHOW_COLLECTED && + gSaveContext.checkTrackerData[RC_ZR_MAGIC_BEAN_SALESMAN].status != RCSHOW_SAVED) { + if (BEANS_BOUGHT >= 10) { + SetCheckCollected(RC_ZR_MAGIC_BEAN_SALESMAN); } } - if (savedFrames > 0 && !pendingSaleCheck && !messageCloseCheck) { - savedFrames--; - } -} - -void CheckTrackerSaleEnd(GetItemEntry giEntry) { - if (pendingSaleCheck) { - pendingSaleCheck = false; - } } void CheckTrackerItemReceive(GetItemEntry giEntry) { @@ -593,7 +534,7 @@ void CheckTrackerItemReceive(GetItemEntry giEntry) { // Vanilla special item checks if (!IS_RANDO) { if (giEntry.itemId == ITEM_SHIELD_DEKU) { - SetCheckCollected(RC_KF_SHOP_ITEM_3); + SetCheckCollected(RC_KF_SHOP_ITEM_1); return; }else if (giEntry.itemId == ITEM_KOKIRI_EMERALD) { SetCheckCollected(RC_QUEEN_GOHMA); @@ -622,16 +563,19 @@ void CheckTrackerItemReceive(GetItemEntry giEntry) { } else if (giEntry.itemId == ITEM_MEDALLION_LIGHT) { SetCheckCollected(RC_GIFT_FROM_SAGES); return; - } else if (giEntry.itemId == ITEM_SONG_LULLABY) { - SetCheckCollected(RC_SONG_FROM_IMPA); - return; } else if (giEntry.itemId == ITEM_SONG_EPONA) { SetCheckCollected(RC_SONG_FROM_MALON); return; } else if (giEntry.itemId == ITEM_SONG_SARIA) { SetCheckCollected(RC_SONG_FROM_SARIA); return; - } else if (giEntry.itemId == ITEM_SONG_SUN) { + } else if (giEntry.itemId == ITEM_BEAN) { + SetCheckCollected(RC_ZR_MAGIC_BEAN_SALESMAN); + return; + } else if (giEntry.itemId == ITEM_BRACELET) { + SetCheckCollected(RC_GC_DARUNIAS_JOY); + return; + }/* else if (giEntry.itemId == ITEM_SONG_SUN) { SetCheckCollected(RC_SONG_FROM_ROYAL_FAMILYS_TOMB); return; } else if (giEntry.itemId == ITEM_SONG_TIME) { @@ -658,42 +602,127 @@ void CheckTrackerItemReceive(GetItemEntry giEntry) { } else if (giEntry.itemId == ITEM_SONG_PRELUDE) { SetCheckCollected(RC_SHEIK_AT_TEMPLE); return; - } else if (giEntry.itemId == ITEM_BRACELET) { - SetCheckCollected(RC_GC_DARUNIAS_JOY); - return; - } else if (giEntry.itemId == ITEM_LETTER_ZELDA) { - SetCheckCollected(RC_HC_ZELDAS_LETTER); - return; - } else if (giEntry.itemId == ITEM_WEIRD_EGG) { - SetCheckCollected(RC_HC_MALON_EGG); - return; - } else if (giEntry.itemId == ITEM_BEAN) { - SetCheckCollected(RC_ZR_MAGIC_BEAN_SALESMAN); - return; - } + }*/ } - auto checkArea = GetCheckArea(); - if (gSaveContext.pendingSale != ITEM_NONE) { - pendingSaleCheck = true; - checkAreas.push_back(checkArea); +} + +void CheckTrackerSceneFlagSet(int16_t sceneNum, int16_t flagType, int32_t flag) { + if (flagType != FLAG_SCENE_TREASURE && flagType != FLAG_SCENE_COLLECTIBLE) { return; } - if (scene == SCENE_DESERT_COLOSSUS && (gSaveContext.entranceIndex == 485 || gSaveContext.entranceIndex == 489)) { - checkAreas.push_back(RCAREA_SPIRIT_TEMPLE); + if (sceneNum == SCENE_GRAVEYARD && flag == 0x19 && flagType == FLAG_SCENE_COLLECTIBLE) { // Gravedigging tour special case + SetCheckCollected(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR); return; } - if (GET_PLAYER(gPlayState) == nullptr) { - transitionCheck = true; - return; + for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) { + if (!IsVisibleInCheckTracker(rcObj)) { + continue; + } + SpoilerCollectionCheckType checkMatchType = flagType == FLAG_SCENE_TREASURE ? SpoilerCollectionCheckType::SPOILER_CHK_CHEST : SpoilerCollectionCheckType::SPOILER_CHK_COLLECTABLE; + SpoilerCollectionCheck scCheck = Location(rc)->GetCollectionCheck(); + if (scCheck.scene == sceneNum && scCheck.flag == flag && scCheck.type == checkMatchType) { + SetCheckCollected(rc); + return; + } + } +} + +void CheckTrackerFlagSet(int16_t flagType, int32_t flag) { + SpoilerCollectionCheckType checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_NONE; + switch (flagType) { + case FLAG_GS_TOKEN: + checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_GOLD_SKULLTULA; + break; + case FLAG_EVENT_CHECK_INF: + if ((flag == EVENTCHKINF_CARPENTERS_FREE(0) || flag == EVENTCHKINF_CARPENTERS_FREE(1) || + flag == EVENTCHKINF_CARPENTERS_FREE(2) || flag == EVENTCHKINF_CARPENTERS_FREE(3)) + && GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) { + SetCheckCollected(RC_GF_GERUDO_MEMBERSHIP_CARD); + return; + } + checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF; + break; + case FLAG_INF_TABLE: + if (flag == INFTABLE_190) { + SetCheckCollected(RC_GF_HBA_1000_POINTS); + return; + } else if (flag == INFTABLE_11E) { + SetCheckCollected(RC_GC_ROLLING_GORON_AS_CHILD); + return; + } else if (flag == INFTABLE_GORON_CITY_DOORS_UNLOCKED) { + SetCheckCollected(RC_GC_ROLLING_GORON_AS_ADULT); + return; + } else if (flag == INFTABLE_139) { + SetCheckCollected(RC_ZD_KING_ZORA_THAWED); + return; + } else if (flag == INFTABLE_191) { + SetCheckCollected(RC_MARKET_LOST_DOG); + return; + } + if (!IS_RANDO) { + if (flag == INFTABLE_192) { + SetCheckCollected(RC_LW_DEKU_SCRUB_NEAR_BRIDGE); + return; + } else if (flag == INFTABLE_193) { + SetCheckCollected(RC_LW_DEKU_SCRUB_GROTTO_FRONT); + return; + } + } + break; + case FLAG_ITEM_GET_INF: + if (!IS_RANDO) { + if (flag == ITEMGETINF_OBTAINED_STICK_UPGRADE_FROM_STAGE) { + SetCheckCollected(RC_DEKU_THEATER_SKULL_MASK); + return; + } else if (flag == ITEMGETINF_OBTAINED_NUT_UPGRADE_FROM_STAGE) { + SetCheckCollected(RC_DEKU_THEATER_MASK_OF_TRUTH); + return; + } else if (flag == ITEMGETINF_0B) { + SetCheckCollected(RC_HF_DEKU_SCRUB_GROTTO); + return; + } + } + checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_ITEM_GET_INF; + break; + case FLAG_RANDOMIZER_INF: + checkMatchType = SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF; + break; } - if (gPlayState->msgCtx.msgMode != MSGMODE_NONE) { - checkAreas.push_back(checkArea); - messageCloseCheck = true; + if (checkMatchType == SpoilerCollectionCheckType::SPOILER_CHK_NONE) { return; } - if (IS_RANDO || (!IS_RANDO && giEntry.getItemCategory != ITEM_CATEGORY_JUNK)) { - checkAreas.push_back(checkArea); - checkCollected = true; + for (auto [rc, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) { + if ((!IS_RANDO && ((rcObj.vOrMQ == RCVORMQ_MQ && !IS_MASTER_QUEST) || + (rcObj.vOrMQ == RCVORMQ_VANILLA && IS_MASTER_QUEST))) || + (IS_RANDO && ((OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) && + rcObj.vOrMQ == RCVORMQ_VANILLA) || + !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) && + rcObj.vOrMQ == RCVORMQ_MQ))) { + continue; + } + SpoilerCollectionCheck scCheck = Location(rc)->GetCollectionCheck(); + SpoilerCollectionCheckType scCheckType = scCheck.type; + if (checkMatchType == SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF && + (scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_MERCHANT || + scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_SHOP_ITEM || + scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_COW || + scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_SCRUB || + scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_MASTER_SWORD || + scCheckType == SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF)) { + if (flag == OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(rc)) { + SetCheckCollected(rc); + return; + } + continue; + } + int16_t checkFlag = scCheck.flag; + if (checkMatchType == SpoilerCollectionCheckType::SPOILER_CHK_GOLD_SKULLTULA) { + checkFlag = rcObj.actorParams; + } + if (checkFlag == flag && scCheck.type == checkMatchType) { + SetCheckCollected(rc); + return; + } } } @@ -711,7 +740,7 @@ void InitTrackerData(bool isDebug) { void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) { SaveManager::Instance->SaveArray("checks", ARRAY_COUNT(saveContext->checkTrackerData), [&](size_t i) { if (saveContext->checkTrackerData[i].status == RCSHOW_COLLECTED) { - if (gameSave || savedFrames > 0) { + if (gameSave) { gSaveContext.checkTrackerData[i].status = saveContext->checkTrackerData[i].status = RCSHOW_SAVED; UpdateAllOrdering(); UpdateInventoryChecks(); @@ -730,9 +759,6 @@ void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) { void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) { SaveTrackerData(saveContext, sectionID, fullSave); - if (fullSave) { - savedFrames = 40; - } } void LoadFile() { @@ -748,14 +774,9 @@ void LoadFile() { void Teardown() { initialized = false; - for (auto& [rcArea, vec] : checksByArea) { - vec.clear(); - areaChecksGotten[rcArea] = 0; - } + ClearAreaChecksAndTotals(); checksByArea.clear(); areasSpoiled = 0; - checkCollected = false; - checkLoops = 0; lastLocationChecked = RC_UNKNOWN_CHECK; } @@ -925,7 +946,11 @@ void CheckTrackerWindow::DrawElement() { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f, extraColor.b / 255.0f, extraColor.a / 255.0f)); - isThisAreaSpoiled = areasSpoiled & areaMask || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0); + isThisAreaSpoiled = areasSpoiled & areaMask || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0) || !IS_RANDO || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_NONE || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SELECTION || + (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER && + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) == 12); if (isThisAreaSpoiled) { if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) { @@ -1151,8 +1176,8 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) { } else if (rcObj.vanillaCompletion) { return (rcObj.vOrMQ == RCVORMQ_BOTH || - rcObj.vOrMQ == RCVORMQ_MQ && OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) || - rcObj.vOrMQ == RCVORMQ_VANILLA && !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) || + (rcObj.vOrMQ == RCVORMQ_MQ && IS_MASTER_QUEST) || + (rcObj.vOrMQ == RCVORMQ_VANILLA && !IS_MASTER_QUEST) || rcObj.rc == RC_GIFT_FROM_SAGES) && rcObj.rc != RC_LINKS_POCKET; } return false; @@ -1541,10 +1566,11 @@ void CheckTrackerWindow::InitElement() { Teardown(); }); GameInteractor::Instance->RegisterGameHook(CheckTrackerItemReceive); - GameInteractor::Instance->RegisterGameHook(CheckTrackerSaleEnd); GameInteractor::Instance->RegisterGameHook(CheckTrackerFrame); GameInteractor::Instance->RegisterGameHook(CheckTrackerTransition); GameInteractor::Instance->RegisterGameHook(CheckTrackerShopSlotChange); + GameInteractor::Instance->RegisterGameHook(CheckTrackerSceneFlagSet); + GameInteractor::Instance->RegisterGameHook(CheckTrackerFlagSet); LocationTable_Init(); } diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h index b2193f696e0..a8928cca3e4 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h @@ -48,10 +48,7 @@ void Teardown(); void UpdateAllOrdering(); bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj); void InitTrackerData(bool isDebug); -void SetLastItemGetRC(RandomizerCheck rc); RandomizerCheckArea GetCheckArea(); -void CheckTrackerDialogClosed(); -void ToggleShopRightChecks(); void UpdateCheck(uint32_t, RandomizerCheckTrackerData); } // namespace CheckTracker diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index f2f1a8a3f35..e6ec3fef3fa 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -76,7 +76,7 @@ static s16 newIceCavernEntrance = ICE_CAVERN_ENTRANCE; static s8 hasCopiedEntranceTable = 0; static s8 hasModifiedEntranceTable = 0; -void Entrance_SetEntranceDiscovered(u16 entranceIndex); +void Entrance_SetEntranceDiscovered(u16 entranceIndex, u8 isReversedEntrance); u8 Entrance_EntranceIsNull(EntranceOverride* entranceOverride) { return entranceOverride->index == 0 && entranceOverride->destination == 0 && entranceOverride->blueWarp == 0 @@ -276,13 +276,13 @@ s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) { return nextEntranceIndex; } - Entrance_SetEntranceDiscovered(nextEntranceIndex); + Entrance_SetEntranceDiscovered(nextEntranceIndex, false); EntranceTracker_SetLastEntranceOverride(nextEntranceIndex); return Grotto_OverrideSpecialEntrance(Entrance_GetOverride(nextEntranceIndex)); } s16 Entrance_OverrideDynamicExit(s16 dynamicExitIndex) { - Entrance_SetEntranceDiscovered(dynamicExitList[dynamicExitIndex]); + Entrance_SetEntranceDiscovered(dynamicExitList[dynamicExitIndex], false); EntranceTracker_SetLastEntranceOverride(dynamicExitList[dynamicExitIndex]); return Grotto_OverrideSpecialEntrance(Entrance_GetOverride(dynamicExitList[dynamicExitIndex])); } @@ -784,7 +784,7 @@ u8 Entrance_GetIsEntranceDiscovered(u16 entranceIndex) { return 0; } -void Entrance_SetEntranceDiscovered(u16 entranceIndex) { +void Entrance_SetEntranceDiscovered(u16 entranceIndex, u8 isReversedEntrance) { // Skip if already set to save time from setting the connected entrance or // if this entrance is outside of the randomized entrance range (i.e. is a dynamic entrance) if (entranceIndex > MAX_ENTRANCE_RANDO_USED_INDEX || Entrance_GetIsEntranceDiscovered(entranceIndex)) { @@ -796,14 +796,20 @@ void Entrance_SetEntranceDiscovered(u16 entranceIndex) { if (idx < SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT) { u32 entranceBit = 1 << (entranceIndex - (idx * bitsPerIndex)); gSaveContext.sohStats.entrancesDiscovered[idx] |= entranceBit; - // Set connected - for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) { - if (entranceIndex == gSaveContext.entranceOverrides[i].index) { - Entrance_SetEntranceDiscovered(gSaveContext.entranceOverrides[i].overrideDestination); - break; + + // Set reverse entrance when not decoupled + if (!Randomizer_GetSettingValue(RSK_DECOUPLED_ENTRANCES) && !isReversedEntrance) { + for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) { + if (entranceIndex == gSaveContext.entranceOverrides[i].index) { + Entrance_SetEntranceDiscovered(gSaveContext.entranceOverrides[i].overrideDestination, true); + break; + } } } } - // Save entrancesDiscovered - Save_SaveSection(SECTION_ID_ENTRANCES); + + // Save entrancesDiscovered when it is not the reversed entrance + if (!isReversedEntrance) { + Save_SaveSection(SECTION_ID_ENTRANCES); + } } diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.h b/soh/soh/Enhancements/randomizer/randomizer_entrance.h index c00f29701b5..c71b2493ab6 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.h +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.h @@ -63,7 +63,7 @@ void Entrance_OverrideSpawnScene(int32_t sceneNum, int32_t spawn); int32_t Entrance_OverrideSpawnSceneRoom(int32_t sceneNum, int32_t spawn, int32_t room); void Entrance_EnableFW(void); uint8_t Entrance_GetIsEntranceDiscovered(uint16_t entranceIndex); -void Entrance_SetEntranceDiscovered(uint16_t entranceIndex); +void Entrance_SetEntranceDiscovered(uint16_t entranceIndex, uint8_t isReversedEntrance); #ifdef __cplusplus } #endif diff --git a/soh/soh/Enhancements/randomizer/randomizer_grotto.c b/soh/soh/Enhancements/randomizer/randomizer_grotto.c index 408dc01601e..78e429fb229 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_grotto.c +++ b/soh/soh/Enhancements/randomizer/randomizer_grotto.c @@ -140,7 +140,7 @@ s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) { // If Link hits a grotto exit, load the entrance index from the grotto exit list // based on the current grotto ID if (nextEntranceIndex == 0x7FFF) { - Entrance_SetEntranceDiscovered(ENTRANCE_RANDO_GROTTO_EXIT_START + grottoId); + Entrance_SetEntranceDiscovered(ENTRANCE_RANDO_GROTTO_EXIT_START + grottoId, false); EntranceTracker_SetLastEntranceOverride(ENTRANCE_RANDO_GROTTO_EXIT_START + grottoId); nextEntranceIndex = grottoExitList[grottoId]; } @@ -211,7 +211,7 @@ void Grotto_OverrideActorEntrance(Actor* thisx) { if (grottoContent == grottoLoadTable[index].content && gPlayState->sceneNum == grottoLoadTable[index].scene) { // Find the override for the matching index from the grotto Load List - Entrance_SetEntranceDiscovered(ENTRANCE_RANDO_GROTTO_LOAD_START + index); + Entrance_SetEntranceDiscovered(ENTRANCE_RANDO_GROTTO_LOAD_START + index, false); EntranceTracker_SetLastEntranceOverride(ENTRANCE_RANDO_GROTTO_LOAD_START + index); index = grottoLoadList[index]; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index b7703d0a5b9..6949577e173 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -49,6 +49,9 @@ #include "Fonts.h" #include #include "Enhancements/custom-message/CustomMessageManager.h" +#include "Enhancements/presets.h" +#include "util.h" +#include #if not defined (__SWITCH__) && not defined(__WIIU__) #include "Extractor/Extract.h" @@ -253,15 +256,26 @@ OTRGlobals::OTRGlobals() { OTRFiles.push_back(sohOtrPath); } std::string patchesPath = LUS::Context::LocateFileAcrossAppDirs("mods", appShortName); + std::vector patchOTRs = {}; if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) { if (std::filesystem::is_directory(patchesPath)) { for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath, std::filesystem::directory_options::follow_directory_symlink)) { if (StringHelper::IEquals(p.path().extension().string(), ".otr")) { - OTRFiles.push_back(p.path().generic_string()); + patchOTRs.push_back(p.path().generic_string()); } } } } + std::sort(patchOTRs.begin(), patchOTRs.end(), [](const std::string& a, const std::string& b) { + return std::lexicographical_compare( + a.begin(), a.end(), + b.begin(), b.end(), + [](char c1, char c2) { + return std::tolower(c1) < std::tolower(c2); + } + ); + }); + OTRFiles.insert(OTRFiles.end(), patchOTRs.begin(), patchOTRs.end()); std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, @@ -1048,6 +1062,10 @@ extern "C" void InitOTR() { tm *tm_now = localtime(&now); CVarRegisterInteger("gLetItSnow", 1); + CVarRegisterInteger("gCosmetics.Consumable_Hearts.Changed", 1); + CVarRegisterColor("gCosmetics.Consumable_Hearts.Value", Color_RGBA8{ 255, 158, 0, 255 }); + CVarRegisterInteger("gCosmetics.Consumable_Magic.Changed", 1); + CVarRegisterColor("gCosmetics.Consumable_Magic.Value", Color_RGBA8{ 255, 0, 0, 255 }); srand(now); #ifdef ENABLE_CROWD_CONTROL @@ -2562,6 +2580,70 @@ extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* repla gfx_register_blended_texture(name, mask, replacement); } -extern "C" void CheckTracker_OnMessageClose() { - CheckTracker::CheckTrackerDialogClosed(); +// #region SOH [TODO] Ideally this should move to being event based, it's currently run every frame on the file select screen +extern "C" void SoH_ProcessDroppedFiles() { + const char* droppedFile = CVarGetString("gDroppedFile", ""); + if (CVarGetInteger("gNewFileDropped", 0) && strcmp(droppedFile, "") != 0) { + try { + std::ifstream configStream(SohUtils::Sanitize(droppedFile)); + if (!configStream) { + return; + } + + nlohmann::json configJson; + configStream >> configJson; + + if (!configJson.contains("CVars")) { + return; + } + + clearCvars(enhancementsCvars); + clearCvars(cheatCvars); + clearCvars(randomizerCvars); + + // Flatten everything under CVars into a single array + auto cvars = configJson["CVars"].flatten(); + + for (auto& [key, value] : cvars.items()) { + // Replace slashes with dots in key, and remove leading dot + std::string path = key; + std::replace(path.begin(), path.end(), '/', '.'); + if (path[0] == '.') { + path.erase(0, 1); + } + if (value.is_string()) { + CVarSetString(path.c_str(), value.get().c_str()); + } else if (value.is_number_integer()) { + CVarSetInteger(path.c_str(), value.get()); + } else if (value.is_number_float()) { + CVarSetFloat(path.c_str(), value.get()); + } + } + + auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); + gui->GetGuiWindow("Console")->Hide(); + gui->GetGuiWindow("Actor Viewer")->Hide(); + gui->GetGuiWindow("Collision Viewer")->Hide(); + gui->GetGuiWindow("Save Editor")->Hide(); + gui->GetGuiWindow("Display List Viewer")->Hide(); + gui->GetGuiWindow("Stats")->Hide(); + std::dynamic_pointer_cast(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->ClearBindings(); + + gui->SaveConsoleVariablesOnNextTick(); + + uint32_t finalHash = boost::hash_32{}(configJson.dump()); + gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Configuration Loaded. Hash: %d", finalHash); + } catch (std::exception& e) { + SPDLOG_ERROR("Failed to load config file: {}", e.what()); + auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); + gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file"); + return; + } catch (...) { + SPDLOG_ERROR("Failed to load config file"); + auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); + gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file"); + return; + } + } } +// #endregion diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 9b42e689550..88c57ced336 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -175,6 +175,7 @@ void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex); void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement); void SaveManager_ThreadPoolWait(); void CheckTracker_OnMessageClose(); +void SoH_ProcessDroppedFiles(); int32_t GetGIID(uint32_t itemID); #endif diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 10af75ca840..6cb37092868 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -492,6 +492,8 @@ extern std::shared_ptr mGameplayStatsWindow; void DrawEnhancementsMenu() { if (ImGui::BeginMenu("Enhancements")) { + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); + DrawPresetSelector(PRESET_TYPE_ENHANCEMENTS); UIWidgets::PaddedSeparator(); @@ -605,7 +607,7 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", "gNutsExplodeBombs", true, false); UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers."); UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false); - UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots"); + UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots. (Note this will disable the behaviour of the 'Equip Dupe' glitch)"); UIWidgets::PaddedEnhancementCheckbox("Bow as Child/Slingshot as Adult", "gBowSlingShotAmmoFix", true, false); UIWidgets::Tooltip("Allows child to use bow with arrows.\nAllows adult to use slingshot with seeds.\n\nRequires glitches or 'Timeless Equipment' cheat to equip."); UIWidgets::PaddedEnhancementCheckbox("Better Farore's Wind", "gBetterFW", true, false); @@ -1066,6 +1068,9 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false); UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."); + UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed", + true, false, false, "", UIWidgets::CheckboxGraphics::Cross, true); + UIWidgets::Tooltip("Fixes Darunia's dancing speed so he dances to the beat of Saria's Song, like in vanilla."); ImGui::EndMenu(); } @@ -1201,6 +1206,8 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedSeparator(true, true, 2.0f, 2.0f); + ImGui::EndDisabled(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); @@ -1242,6 +1249,8 @@ void DrawEnhancementsMenu() { void DrawCheatsMenu() { if (ImGui::BeginMenu("Cheats")) { + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); + if (ImGui::BeginMenu("Infinite...")) { UIWidgets::EnhancementCheckbox("Money", "gInfiniteMoney"); UIWidgets::PaddedEnhancementCheckbox("Health", "gInfiniteHealth", true, false); @@ -1396,6 +1405,8 @@ void DrawCheatsMenu() { } UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); + ImGui::EndDisabled(); + ImGui::EndMenu(); } } @@ -1409,6 +1420,8 @@ extern std::shared_ptr mDLViewerWindow; void DrawDeveloperToolsMenu() { if (ImGui::BeginMenu("Developer Tools")) { + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); + UIWidgets::EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); UIWidgets::Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad Right, and open the debug menu with L on the pause screen"); if (CVarGetInteger("gDebugEnabled", 0)) { @@ -1481,6 +1494,8 @@ void DrawDeveloperToolsMenu() { ImGui::PopStyleVar(3); ImGui::PopStyleColor(1); + ImGui::EndDisabled(); + ImGui::EndMenu(); } } diff --git a/soh/soh/util.cpp b/soh/soh/util.cpp index 62e1d2dce23..856432cbbd2 100644 --- a/soh/soh/util.cpp +++ b/soh/soh/util.cpp @@ -2,6 +2,7 @@ #include #include +#include std::vector sceneNames = { "Inside the Deku Tree", @@ -318,3 +319,20 @@ void SohUtils::CopyStringToCharArray(char* destination, std::string source, size strncpy(destination, source.c_str(), size - 1); destination[size - 1] = '\0'; } + +std::string SohUtils::Sanitize(std::string stringValue) { + // Add backslashes. + for (auto i = stringValue.begin();;) { + auto const pos = std::find_if(i, stringValue.end(), [](char const c) { return '\\' == c || '\'' == c || '"' == c; }); + if (pos == stringValue.end()) { + break; + } + i = std::next(stringValue.insert(pos, '\\'), 2); + } + + // Removes others. + stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(), [](char const c) { + return '\n' == c || '\r' == c || '\0' == c || '\x1A' == c; }), stringValue.end()); + + return stringValue; +} diff --git a/soh/soh/util.h b/soh/soh/util.h index bdbfcd777fb..db5af8636a3 100644 --- a/soh/soh/util.h +++ b/soh/soh/util.h @@ -12,4 +12,6 @@ namespace SohUtils { // Copies a string and ensures the destination is null terminated if the source string is larger than size // Only up to size-1 characters are copied from the source string void CopyStringToCharArray(char* destination, std::string source, size_t size); + + std::string Sanitize(std::string stringValue); } // namespace SohUtils diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index f90e8bb9370..6bbd1eca9bd 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -72,6 +72,9 @@ MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) { _message_0xFFFC_nes = (char*)file->messages[i].msg.c_str(); } + // Assert that the first message starts at the first text ID + assert(table[0].textId == 0x0001); + return table; } @@ -104,6 +107,9 @@ extern "C" void OTRMessage_Init() sStaffMessageEntryTablePtr[i].segment = file2->messages[i].msg.c_str(); sStaffMessageEntryTablePtr[i].msgSize = file2->messages[i].msg.size(); } + + // Assert staff credits start at the first credits ID + assert(sStaffMessageEntryTablePtr[0].textId == 0x0500); } CustomMessageManager::Instance->AddCustomMessageTable(customMessageTableID); diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index da0f5f55fe2..7bb3803fcc6 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -3384,7 +3384,7 @@ void Message_Update(PlayState* play) { } sLastPlayedSong = 0xFF; osSyncPrintf("OCARINA_MODE=%d chk_ocarina_no=%d\n", play->msgCtx.ocarinaMode, msgCtx->unk_E3F2); - CheckTracker_OnMessageClose(); + // TODO: OnMessageClose hook break; case MSGMODE_PAUSED: break; diff --git a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c index 9d26561c98e..43381c7d69a 100644 --- a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c +++ b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c @@ -17,6 +17,10 @@ void gfx_texture_cache_clear(); #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED) +#define LAVA_TEX_WIDTH 32 +#define LAVA_TEX_HEIGHT 64 +#define LAVA_TEX_SIZE 2048 + void BossDodongo_Init(Actor* thisx, PlayState* play); void BossDodongo_Destroy(Actor* thisx, PlayState* play); void BossDodongo_Update(Actor* thisx, PlayState* play); @@ -70,8 +74,8 @@ static u8 sMaskTexLava[32 * 64] = { { 0 } }; static u32* sLavaFloorModifiedTexRaw = NULL; static u32* sLavaWavyTexRaw = NULL; -static u16 sLavaFloorModifiedTex[4096]; -static u16 sLavaWavyTex[2048]; +static u16 sLavaFloorModifiedTex[LAVA_TEX_SIZE]; +static u16 sLavaWavyTex[LAVA_TEX_SIZE]; static u8 hasRegisteredBlendedHook = 0; @@ -105,7 +109,7 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() { // When the texture is HD (raw) we need to work with u32 values for RGBA32 // Otherwise the original asset is u16 for RGBA16 - if (ResourceMgr_TexIsRaw(sLavaFloorLavaTex)) { + if (ResourceMgr_TexIsRaw(gDodongosCavernBossLavaFloorTex)) { u32* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex); size_t lavaSize = ResourceGetSizeByName(sLavaFloorLavaTex); size_t floorSize = ResourceGetSizeByName(gDodongosCavernBossLavaFloorTex); @@ -127,14 +131,13 @@ void BossDodongo_RegisterBlendedLavaTextureUpdate() { // Register the blended effect for the raw texture Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaWavyTexRaw); } else { - u16* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex); - memcpy(sLavaFloorModifiedTex, lavaTex, sizeof(sLavaFloorModifiedTex)); - // When KD is dead, just immediately copy the rock texture if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) { u16* rockTex = ResourceGetDataByName(sLavaFloorRockTex); - size_t rockSize = ResourceGetSizeByName(sLavaFloorRockTex); - memcpy(sLavaFloorModifiedTex, rockTex, rockSize); + memcpy(sLavaFloorModifiedTex, rockTex, sizeof(sLavaFloorModifiedTex)); + } else { + u16* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex); + memcpy(sLavaFloorModifiedTex, lavaTex, sizeof(sLavaFloorModifiedTex)); } // Register the blended effect for the non-raw texture @@ -183,7 +186,7 @@ void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) { // Applying sqrt(multiplier) to arg3 is to control how many pixels move left/right for the selected row // Applying to arg2 and M_PI help to space out the wave effect // It's not perfect but close enough - u16 multiplier = width / 32; + u16 multiplier = width / LAVA_TEX_WIDTH; for (i = 0; i < size; i += width) { temp = sinf((((i / width) + (s32)(((arg2 * multiplier) * 50.0f) / 100.0f)) & (width - 1)) * (M_PI / (16 * multiplier))) * (arg3 * sqrt(multiplier)); @@ -1166,14 +1169,14 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) { s16 i2; // Get the scale based on the original texture size - u16 widthScale = width / 32; - u16 heightScale = height / 64; + u16 widthScale = width / LAVA_TEX_WIDTH; + u16 heightScale = height / LAVA_TEX_HEIGHT; u32 size = width * height; for (i2 = 0; i2 < 20; i2++) { - s16 new_var = this->unk_1C2 & 0x7FF; + s16 new_var = this->unk_1C2 & (LAVA_TEX_SIZE - 1); // Compute the index to a scaled position (scaling pseudo x,y as a 1D value) - s32 indexStart = ((new_var % 32) * widthScale) + ((new_var / 32) * width * heightScale); + s32 indexStart = ((new_var % LAVA_TEX_WIDTH) * widthScale) + ((new_var / LAVA_TEX_WIDTH) * width * heightScale); // From the starting index, apply extra pixels right/down based on the scale for (size_t j = 0; j < heightScale; j++) { diff --git a/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c b/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c index 66514fd4bd9..32a2cf81f50 100644 --- a/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c +++ b/soh/src/overlays/actors/ovl_En_ChristmasTree/z_en_christmastree.c @@ -131,7 +131,7 @@ void EnChristmasTree_HandleEndTitle(EnChristmasTree* this, PlayState* play) { // Hide player so he's not visible in the final screen. Also move him so target arrow on tree dissapears. player->actor.scale.x = player->actor.scale.y = player->actor.scale.z = 0.00001f; - player->actor.world.pos.y = -200.0f; + player->actor.world.pos.z = 500.0f; // Hide HUD Interface_ChangeAlpha(1); diff --git a/soh/src/overlays/actors/ovl_En_Du/z_en_du.c b/soh/src/overlays/actors/ovl_En_Du/z_en_du.c index 3a98074b146..40454811e17 100644 --- a/soh/src/overlays/actors/ovl_En_Du/z_en_du.c +++ b/soh/src/overlays/actors/ovl_En_Du/z_en_du.c @@ -96,6 +96,26 @@ static AnimationInfo sAnimationInfo[] = { { &gDaruniaDancingEndAnim, 1.0f, 0.0f, -1.0f, ANIMMODE_ONCE, -6.0f }, }; +// #region SOH [Enhancement] Only animations too fast need to be slowed down, otherwise not touched +static AnimationInfo sAnimationInfoFix[] = { + { NULL }, + { NULL }, + { NULL }, + { NULL }, + { NULL }, + { NULL }, + { NULL }, + { &gDaruniaDancingLoop1Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, -10.0f }, // + { &gDaruniaDancingLoop1Anim, 0.77f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // hop + { &gDaruniaDancingLoop2Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // from hop to spin + { &gDaruniaDancingLoop3Anim, 0.77f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // spin + { NULL }, + { NULL }, + { &gDaruniaDancingLoop4Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // from spin to hop + { NULL }, +}; +// #endregion + void EnDu_SetupAction(EnDu* this, EnDuActionFunc actionFunc) { this->actionFunc = actionFunc; } @@ -256,7 +276,13 @@ void func_809FE040(EnDu* this) { if (this->unk_1E6 >= 8) { this->unk_1E6 = 0; } - Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]); + // #region SOH[Enhancement] + if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1)) { + Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, animationIndices[this->unk_1E6]); + // #endregion + } else { + Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]); + } } } @@ -272,7 +298,13 @@ void func_809FE104(EnDu* this) { if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { this->unk_1E6++; if (this->unk_1E6 < 4) { - Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]); + // #region SOH[Enhancement] + if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1) && this->unk_1E6 <= 1) { + Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, animationIndices[this->unk_1E6]); + // #endregion + } else { + Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]); + } } } } @@ -466,7 +498,13 @@ void func_809FE890(EnDu* this, PlayState* play) { } if (csAction->action == 7 || csAction->action == 8) { this->unk_1E6 = 0; - Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENDU_ANIM_7); + // #region SOH[Enhancement] + if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1)) { + Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, ENDU_ANIM_7); + // #endregion + } else { + Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENDU_ANIM_7); + } } this->unk_1EA = csAction->action; if (this->unk_1EA == 7) { diff --git a/soh/src/overlays/actors/ovl_En_Insect/z_en_insect.c b/soh/src/overlays/actors/ovl_En_Insect/z_en_insect.c index f1dff358a61..393e10a918b 100644 --- a/soh/src/overlays/actors/ovl_En_Insect/z_en_insect.c +++ b/soh/src/overlays/actors/ovl_En_Insect/z_en_insect.c @@ -211,6 +211,13 @@ void EnInsect_Init(Actor* thisx, PlayState* play2) { func_80A7D39C(this); + // For bugs that aren't linked to a soil patch, we remove the "short lived" flag to prevent them from despawning + // And exit early to not increment the "bugs dropped count" + if (CVarGetInteger("gNoBugsDespawn", 0) && this->soilActor == NULL) { + this->unk_314 &= ~4; + return; + } + D_80A7DEB8++; } else { rand = Rand_ZeroOne(); @@ -394,9 +401,6 @@ void func_80A7CAD0(EnInsect* this, PlayState* play) { } void func_80A7CBC8(EnInsect* this) { - if (CVarGetInteger("gNoBugsDespawn", 0) != 0) { - return; - } this->unk_31A = 60; func_80A7BF58(this); this->skelAnime.playSpeed = 1.9f; diff --git a/soh/src/overlays/actors/ovl_En_Sth/z_en_sth.c b/soh/src/overlays/actors/ovl_En_Sth/z_en_sth.c index e7cbb0fc37f..a7f96df2be5 100644 --- a/soh/src/overlays/actors/ovl_En_Sth/z_en_sth.c +++ b/soh/src/overlays/actors/ovl_En_Sth/z_en_sth.c @@ -314,7 +314,9 @@ void EnSth_GiveReward(EnSth* this, PlayState* play) { this->actor.parent = NULL; EnSth_SetupAction(this, EnSth_RewardObtainedTalk); gSaveContext.eventChkInf[EVENTCHKINF_SKULLTULA_REWARD_INDEX] |= this->eventFlag; - GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, (EVENTCHKINF_SKULLTULA_REWARD_INDEX << 4) + sEventFlagsShift[this->actor.params]); + if (this->eventFlag != 0) { + GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, (EVENTCHKINF_SKULLTULA_REWARD_INDEX << 4) + sEventFlagsShift[this->actor.params]); + } } else { EnSth_GivePlayerItem(this, play); } diff --git a/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.c b/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.c index 3f0fabdf6c5..bf737cc47f1 100644 --- a/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.c +++ b/soh/src/overlays/actors/ovl_En_Tk/z_en_tk.c @@ -409,7 +409,7 @@ s32 EnTk_ChooseReward(EnTk* this) { f32 luck; s32 reward; - if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, 0x1F) && this->heartPieceSpawned == 0) { + if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE) && this->heartPieceSpawned == 0) { return 3; } @@ -625,10 +625,8 @@ void EnTk_Dig(EnTk* this, PlayState* play) { this->currentReward = EnTk_ChooseReward(this); - // merging in dampe tour fix seems messy, so i'm just wrapping this whole thing - // in an n64dd check for now - if (IS_RANDO || CVarGetInteger("gDampeWin", 0)) { - if (this->currentReward == 3) { + if (this->currentReward == 3) { + if (IS_RANDO || CVarGetInteger("gDampeWin", 0)) { /* * Upgrade the purple rupee reward to the heart piece if this * is the first grand prize dig. @@ -636,37 +634,31 @@ void EnTk_Dig(EnTk* this, PlayState* play) { if (!Flags_GetItemGetInf(ITEMGETINF_1C) && !(IS_RANDO || CVarGetInteger("gDampeWin", 0))) { Flags_SetItemGetInf(ITEMGETINF_1C); this->currentReward = 4; - } else if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, 0x1F) && this->heartPieceSpawned == 0) { + } else if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE) && this->heartPieceSpawned == 0) { this->currentReward = 4; } } - - if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && this->currentReward == 4) { - Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, rewardPos.x, rewardPos.y, rewardPos.z, 0, - 0, 0, 0x1F06, true); - this->heartPieceSpawned = 1; - } else { - Item_DropCollectible(play, &rewardPos, rewardParams[this->currentReward]); - } - } else { - if (this->currentReward == 3) { - /* - * Upgrade the purple rupee reward to the heart piece if this - * is the first grand prize dig. - */ - // If vanilla itemGetInf flag is not set, it's impossible for the new flag to be set, so return true. - // Otherwise if the gGravediggingTourFix is enabled and the new flag hasn't been set, return true. - // If true, spawn the heart piece and set the vanilla itemGetInf flag and new temp clear flag. - if (!heartPieceSpawned && - (!(gSaveContext.itemGetInf[1] & ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE) || - CVarGetInteger("gGravediggingTourFix", 0) && - !Flags_GetCollectible(play, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE))) { - this->currentReward = 4; - gSaveContext.itemGetInf[1] |= ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE; - heartPieceSpawned = true; - } + /* + * Upgrade the purple rupee reward to the heart piece if this + * is the first grand prize dig. + */ + // If vanilla itemGetInf flag is not set, it's impossible for the new flag to be set, so return true. + // Otherwise if the gGravediggingTourFix is enabled and the new flag hasn't been set, return true. + // If true, spawn the heart piece and set the vanilla itemGetInf flag and new temp clear flag. + if (!heartPieceSpawned && + (!(gSaveContext.itemGetInf[1] & ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE) || + CVarGetInteger("gGravediggingTourFix", 0) && + !Flags_GetCollectible(play, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE))) { + this->currentReward = 4; + gSaveContext.itemGetInf[1] |= ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE; + heartPieceSpawned = true; } + } + if (IS_RANDO && this->currentReward == 4) { + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, rewardPos.x, rewardPos.y, rewardPos.z, 0, 0, 0, 0x1906, true); + this->heartPieceSpawned = 1; + } else { EnItem00* reward = Item_DropCollectible(play, &rewardPos, rewardParams[this->currentReward]); if (this->currentReward == 4) { reward->collectibleFlag = COLLECTFLAG_GRAVEDIGGING_HEART_PIECE; diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 9c83f9322cd..9e6150593d2 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -1,6 +1,7 @@ #include "file_choose.h" #include +#include #include "textures/title_static/title_static.h" #include "textures/parameter_static/parameter_static.h" @@ -1024,7 +1025,7 @@ void FileChoose_UpdateRandomizer() { return; } - if (!SpoilerFileExists(CVarGetString("gSpoilerLog", ""))) { + if (!SpoilerFileExists(CVarGetString("gSpoilerLog", "")) && !CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) { CVarSetString("gSpoilerLog", ""); fileSelectSpoilerFileLoaded = false; } @@ -1051,6 +1052,10 @@ void FileChoose_UpdateRandomizer() { Randomizer_LoadMasterQuestDungeons(fileLoc); Randomizer_LoadEntranceOverrides(fileLoc, silent); fileSelectSpoilerFileLoaded = true; + + if (SpoilerFileExists(CVarGetString("gSpoilerLog", "")) && CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) { + remove(fileLoc); + } } } @@ -1071,6 +1076,7 @@ void FileChoose_UpdateMainMenu(GameState* thisx) { Input* input = &this->state.input[0]; bool dpad = CVarGetInteger("gDpadText", 0); + SoH_ProcessDroppedFiles(); FileChoose_UpdateRandomizer(); if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) { @@ -1261,6 +1267,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { s8 i = 0; bool dpad = CVarGetInteger("gDpadText", 0); + SoH_ProcessDroppedFiles(); FileChoose_UpdateRandomizer(); if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { @@ -3686,4 +3693,7 @@ void FileChoose_Init(GameState* thisx) { Font_LoadOrderedFont(&this->font); Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA); func_800F5E18(SEQ_PLAYER_BGM_MAIN, NA_BGM_FILE_SELECT, 0, 7, 1); + + // Originally this was only set when transitioning from the title screen, but gSkipLogoTitle skips that process so we're ensuring it's set here + gSaveContext.gameMode = GAMEMODE_FILE_SELECT; } diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 74460691056..665c95b81af 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -1054,8 +1054,9 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { //Fix for Equip Dupe if (pauseCtx->equipTargetItem == ITEM_BOW) { - if ((gSaveContext.equips.buttonItems[otherButtonIndex] >= ITEM_BOW_ARROW_FIRE) && - (gSaveContext.equips.buttonItems[otherButtonIndex] <= ITEM_BOW_ARROW_LIGHT)) { + if (gSaveContext.equips.buttonItems[otherButtonIndex] >= ITEM_BOW_ARROW_FIRE && + gSaveContext.equips.buttonItems[otherButtonIndex] <= ITEM_BOW_ARROW_LIGHT && + !CVarGetInteger("gSeparateArrows", 0)) { gSaveContext.equips.buttonItems[otherButtonIndex] = gSaveContext.equips.buttonItems[targetButtonIndex]; gSaveContext.equips.cButtonSlots[otherSlotIndex] = gSaveContext.equips.cButtonSlots[pauseCtx->equipTargetCBtn]; Interface_LoadItemIcon2(play, otherButtonIndex);