diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 4c45c36f0..4b2d93bb8 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -291,6 +291,23 @@ extern std::shared_ptr mHudEditorWindow; void DrawEnhancementsMenu() { if (UIWidgets::BeginMenu("Enhancements")) { + if (UIWidgets::BeginMenu("Cycle")) { + UIWidgets::CVarCheckbox("Do no reset Bottle content", "gEnhancements.Cycle.DoNotResetBottleContent", { + .tooltip = "Playing the Song Of Time will not reset the bottles' content." + }); + UIWidgets::CVarCheckbox("Do no reset Consumables", "gEnhancements.Cycle.DoNotResetConsumables", { + .tooltip = "Playing the Song Of Time will not reset the consumables." + }); + UIWidgets::CVarCheckbox("Do no reset Razor Sword", "gEnhancements.Cycle.DoNotResetRazorSword", { + .tooltip = "Playing the Song Of Time will not reset the Sword back to Kokiri Sword." + }); + UIWidgets::CVarCheckbox("Do no reset Rupees", "gEnhancements.Cycle.DoNotResetRupees", { + .tooltip = "Playing the Song Of Time will not reset the your rupees." + }); + + ImGui::EndMenu(); + } + if (UIWidgets::BeginMenu("Masks")) { UIWidgets::CVarCheckbox("Fierce Deity's Mask Anywhere", "gEnhancements.Masks.FierceDeitysAnywhere", { .tooltip = "Allow using Fierce Deity's mask outside of boss rooms." diff --git a/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp b/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp new file mode 100644 index 000000000..c9cc963b0 --- /dev/null +++ b/mm/2s2h/Enhancements/Cycle/EndOfCycle.cpp @@ -0,0 +1,73 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include +#include + +} + +SaveInfo saveInfoCopy; + +void RegisterEndOfCycleSaveHooks() { + + GameInteractor::Instance->RegisterGameHook([]() { + memcpy(&saveInfoCopy, &gSaveContext.save.saveInfo, sizeof(SaveInfo)); + }); + + GameInteractor::Instance->RegisterGameHook([]() { + if (CVarGetInteger("gEnhancements.Cycle.DoNotResetRupees", 0)) { + gSaveContext.save.saveInfo.playerData.rupees = saveInfoCopy.playerData.rupees; + } + + if (CVarGetInteger("gEnhancements.Cycle.DoNotResetConsumables", 0)) { + if (INV_CONTENT(ITEM_BOMB) == ITEM_BOMB) { + INV_CONTENT(ITEM_BOMB) = saveInfoCopy.inventory.items[ITEM_BOMB]; + AMMO(ITEM_BOMB) = saveInfoCopy.inventory.ammo[ITEM_BOMB]; + } + + if (INV_CONTENT(ITEM_DEKU_NUT) == ITEM_DEKU_NUT) { + INV_CONTENT(ITEM_DEKU_NUT) = saveInfoCopy.inventory.items[ITEM_DEKU_NUT]; + AMMO(ITEM_DEKU_NUT) = saveInfoCopy.inventory.ammo[ITEM_DEKU_NUT]; + } + + if (INV_CONTENT(ITEM_DEKU_STICK) == ITEM_DEKU_STICK) { + INV_CONTENT(ITEM_DEKU_STICK) = saveInfoCopy.inventory.items[ITEM_DEKU_STICK]; + AMMO(ITEM_DEKU_STICK) = saveInfoCopy.inventory.ammo[ITEM_DEKU_STICK]; + } + + if (INV_CONTENT(ITEM_BOW) == ITEM_BOW) { + INV_CONTENT(ITEM_BOW) = saveInfoCopy.inventory.items[ITEM_BOW]; + AMMO(ITEM_BOW) = saveInfoCopy.inventory.ammo[ITEM_BOW]; + } + + for (int i = 0; i < ITEM_NUM_SLOTS; i++) { + if (gAmmoItems[i] != ITEM_NONE) { + if ((gSaveContext.save.saveInfo.inventory.items[i] != ITEM_NONE) && (i != SLOT_PICTOGRAPH_BOX)) { + gSaveContext.save.saveInfo.inventory.items[i] = saveInfoCopy.inventory.items[i]; + gSaveContext.save.saveInfo.inventory.ammo[i] = saveInfoCopy.inventory.ammo[i]; + } + } + } + } + + if (CVarGetInteger("gEnhancements.Cycle.DoNotResetBottleContent", 0)) { + for (int i = SLOT_BOTTLE_1; i <= SLOT_BOTTLE_6; i++) { + for (int j = EQUIP_SLOT_C_LEFT; j <= EQUIP_SLOT_C_RIGHT; j++) { + if (GET_CUR_FORM_BTN_ITEM(j) == ITEM_BOTTLE) { + SET_CUR_FORM_BTN_ITEM(j, saveInfoCopy.inventory.items[i]); + } + } + gSaveContext.save.saveInfo.inventory.items[i] = saveInfoCopy.inventory.items[i]; + } + } + + if (CVarGetInteger("gEnhancements.Cycle.DoNotResetRazorSword", 0) && + ((saveInfoCopy.equips.equipment & gEquipMasks[EQUIP_TYPE_SWORD]) >> + gEquipShifts[EQUIP_TYPE_SWORD]) == EQUIP_VALUE_SWORD_RAZOR) { + + SET_EQUIP_VALUE(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_RAZOR); + CUR_FORM_EQUIP(EQUIP_SLOT_B) = ITEM_SWORD_RAZOR; + } + }); +} diff --git a/mm/2s2h/Enhancements/Cycle/EndOfCycle.h b/mm/2s2h/Enhancements/Cycle/EndOfCycle.h new file mode 100644 index 000000000..57e4dfec0 --- /dev/null +++ b/mm/2s2h/Enhancements/Cycle/EndOfCycle.h @@ -0,0 +1,6 @@ +#ifndef CYCLES_END_H +#define CYCLES_END_H + +void RegisterEndOfCycleSaveHooks(); + +#endif // CYCLES_END_H diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index b7d82a9d7..823e06f8f 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -5,6 +5,9 @@ void InitEnhancements() { RegisterInfiniteCheats(); RegisterMoonJumpOnL(); + // Cycle + RegisterEndOfCycleSaveHooks(); + // Masks RegisterFierceDeityAnywhere(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 9332c3860..b06190987 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -3,6 +3,7 @@ #include "Cheats/MoonJump.h" #include "Cheats/Infinite.h" +#include "Cycle/EndOfCycle.h" #include "Masks/FierceDeityAnywhere.h" #include "TimeSavers/TimeSavers.h" diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp index e79eafce8..72cc84543 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.cpp @@ -18,6 +18,14 @@ void GameInteractor_ExecuteOnGameStateUpdate() { GameInteractor::Instance->ExecuteHooks(); } +void GameInteractor_ExecuteBeforeEndOfCycleSave() { + GameInteractor::Instance->ExecuteHooks(); +} + +void GameInteractor_ExecuteAfterEndOfCycleSave() { + GameInteractor::Instance->ExecuteHooks(); +} + void GameInteractor_ExecuteOnSceneInit(s16 sceneId, s8 spawnNum) { GameInteractor::Instance->ExecuteHooks(sceneId, spawnNum); GameInteractor::Instance->ExecuteHooksForID(sceneId, sceneId, spawnNum); diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index ae9efd8b1..b34caae96 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -209,6 +209,8 @@ public: DEFINE_HOOK(OnGameStateMainFinish, ()); DEFINE_HOOK(OnGameStateDrawFinish, ()); DEFINE_HOOK(OnGameStateUpdate, ()); + DEFINE_HOOK(BeforeEndOfCycleSave, ()); + DEFINE_HOOK(AfterEndOfCycleSave, ()); DEFINE_HOOK(OnSceneInit, (s8 sceneId, s8 spawnNum)); DEFINE_HOOK(OnRoomInit, (s8 sceneId, s8 roomNum)); @@ -240,6 +242,8 @@ extern "C" { void GameInteractor_ExecuteOnGameStateMainFinish(); void GameInteractor_ExecuteOnGameStateDrawFinish(); void GameInteractor_ExecuteOnGameStateUpdate(); +void GameInteractor_ExecuteBeforeEndOfCycleSave(); +void GameInteractor_ExecuteAfterEndOfCycleSave(); void GameInteractor_ExecuteOnSceneInit(s16 sceneId, s8 spawnNum); void GameInteractor_ExecuteOnRoomInit(s16 sceneId, s8 roomNum); diff --git a/mm/src/code/z_sram_NES.c b/mm/src/code/z_sram_NES.c index c38571a42..35094b015 100644 --- a/mm/src/code/z_sram_NES.c +++ b/mm/src/code/z_sram_NES.c @@ -4,6 +4,8 @@ #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" #include +#include "Enhancements/GameInteractor/GameInteractor.h" + void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages); void func_80147314(SramContext* sramCtx, s32 fileNum); void func_80147414(SramContext* sramCtx, s32 fileNum, s32 arg2); @@ -426,6 +428,7 @@ void Sram_ClearFlagsAtDawnOfTheFirstDay(void) { * Used by Song of Time (when clicking "Yes") and (indirectly) by the "Dawn of the New Day" cutscene */ void Sram_SaveEndOfCycle(PlayState* play) { + GameInteractor_ExecuteBeforeEndOfCycleSave(); s16 sceneId; s32 j; s32 i; @@ -648,6 +651,7 @@ void Sram_SaveEndOfCycle(PlayState* play) { gSaveContext.rupeeAccumulator = 0; Horse_ResetHorseData(play); + GameInteractor_ExecuteAfterEndOfCycleSave(); } void Sram_IncrementDay(void) {