From 70a2141351ed982d941b8f59d3842ec731cc18b7 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Fri, 11 Oct 2024 01:16:41 +0200 Subject: [PATCH] Mask improvements (#3431) * Add gKeepMasks * Add gSaveMasksToFile * Add gKeepMasksOnDeath & gKeepBunnyHoodThroughTime * Fix mask bleedthrough * Update cvar names * Change bunny hood enhancements to all mask ones * Consolidate multiple enhancements into PersistentMasks * Move keeping masks thru loading zones to PersistentMasks * I forgot * Update z_player.c * Update z64save.h Merge commit excluded this removal for some reason. --------- Co-authored-by: Malkierian Co-authored-by: Malkierian --- soh/include/z64save.h | 1 + soh/soh/Enhancements/presets.h | 14 ++--- soh/soh/SaveManager.cpp | 3 + soh/soh/SohMenuBar.cpp | 13 ++++- soh/src/code/z_play.c | 19 +++--- soh/src/code/z_sram.c | 4 ++ .../actors/ovl_player_actor/z_player.c | 58 ++++++++----------- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 21 +++---- 8 files changed, 72 insertions(+), 61 deletions(-) diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 1c2172563..0233819ce 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -280,6 +280,7 @@ typedef struct { /* */ u8 pendingIceTrapCount; /* */ SohStats sohStats; /* */ FaroresWindData backupFW; + /* */ u8 maskMemory; // #endregion // #region SOH [Randomizer] // Upstream TODO: Move these to their own struct or name to more obviously specific to Randomizer diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index b05af71d5..98c5eead1 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -83,7 +83,7 @@ const std::vector enhancementsCvars = { CVAR_ENHANCEMENT("NoForcedNavi"), CVAR_ENHANCEMENT("SkulltulaFreeze"), CVAR_ENHANCEMENT("MMBunnyHood"), - CVAR_ENHANCEMENT("AdultBunnyHood"), + CVAR_ENHANCEMENT("AdultMasks"), CVAR_ENHANCEMENT("FastChests"), CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents"), CVAR_ENHANCEMENT("FastDrops"), @@ -698,7 +698,7 @@ const std::vector enhancedPresetEntries = { // MM Bunny Hood PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_FAST_AND_JUMP), // Adult Bunny Hood - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultBunnyHood"), 1), + PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultMasks"), 1), // Fast Chests PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FastChests"), 1), // Fast Drops @@ -825,7 +825,7 @@ const std::vector randomizerPresetEntries = { // MM Bunny Hood PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_FAST_AND_JUMP), // Adult Bunny Hood - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultBunnyHood"), 1), + PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultMasks"), 1), // Fast Chests PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FastChests"), 1), // Fast Drops @@ -931,7 +931,7 @@ const std::vector spockRacePresetEntries = { PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MarketSneak"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("InstantPutaway"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FastBoomerang"), 1), - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultBunnyHood"), 1), + PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultMasks"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_FAST), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("SeparateArrows"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"), 1), @@ -1003,7 +1003,7 @@ const std::vector spockRacePresetEntries = { }; const std::vector spockRaceNoLogicPresetEntries = { - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultBunnyHood"), 1), + PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultMasks"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MinimumFishWeightAdult"), 6), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"), 1), PRESET_ENTRY_S32(CVAR_CHEAT("EasyPauseBuffer"), 1), @@ -1099,7 +1099,7 @@ const std::vector s6PresetEntries = { PRESET_ENTRY_S32(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents"), CSMC_BOTH), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FastChests"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_FAST), - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultBunnyHood"), 1), + PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultMasks"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("BigPoeTargetCount"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("CuccosToReturn"), 4), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("DoorOfTime"), RO_DOOROFTIME_OPEN), @@ -1133,7 +1133,7 @@ const std::vector hellModePresetEntries = { PRESET_ENTRY_S32(CVAR_ENHANCEMENT("ChestSizeAndTextureMatchContents"), CSMC_BOTH), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("FastChests"), 1), PRESET_ENTRY_S32(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_FAST), - PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultBunnyHood"), 1), + PRESET_ENTRY_S32(CVAR_ENHANCEMENT("AdultMasks"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("BigPoeTargetCount"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("BlueFireArrows"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("BossKeysanity"), RO_DUNGEON_ITEM_LOC_ANYWHERE), diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 83d22c940..4b6e0b4af 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -858,6 +858,7 @@ void SaveManager::InitFileNormal() { gSaveContext.pendingSaleMod = MOD_NONE; gSaveContext.isBossRushPaused = 0; gSaveContext.pendingIceTrapCount = 0; + gSaveContext.maskMemory = PLAYER_MASK_NONE; // Init with normal quest unless only an MQ rom is provided gSaveContext.questId = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; @@ -2178,6 +2179,7 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags); }); SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); + SaveManager::Instance->LoadData("maskMemory", gSaveContext.maskMemory); } void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSave) { @@ -2347,6 +2349,7 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav SaveManager::Instance->SaveData("tempCollectFlags", saveContext->backupFW.tempCollectFlags); }); SaveManager::Instance->SaveData("dogParams", saveContext->dogParams); + SaveManager::Instance->SaveData("maskMemory", saveContext->maskMemory); } // Load a string into a char array based on size and ensuring it is null terminated when overflowed diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index a8ae3f834..3e8201b9d 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -778,8 +778,17 @@ void DrawEnhancementsMenu() { "Wearing the Bunny Hood grants a speed increase like in Majora's Mask. The longer jump option is not accounted for in randomizer logic.\n\n" "Also disables NPC's reactions to wearing the Bunny Hood." ); - UIWidgets::PaddedEnhancementCheckbox("Bunny Hood Equippable as Adult", CVAR_ENHANCEMENT("AdultBunnyHood"), true, false, (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) == BUNNY_HOOD_VANILLA), "Only available with increased bunny hood speed", UIWidgets::CheckboxGraphics::Cross, false); - UIWidgets::Tooltip("Allows the bunny hood to be equipped normally from the pause menu as adult."); + UIWidgets::PaddedEnhancementCheckbox("Masks Equippable as Adult", CVAR_ENHANCEMENT("AdultMasks"), true, false); + UIWidgets::Tooltip("Allows masks to be equipped normally from the pause menu as adult."); + UIWidgets::PaddedEnhancementCheckbox("Persistent masks", CVAR_ENHANCEMENT("PersistentMasks"), true, false); + UIWidgets::Tooltip( + "Stops masks from automatically unequipping on certain situations:\n" + "- When entering a new scene\n" + "- When not in any C button or the D-Pad\n" + "- When saving and quitting\n" + "- When dying\n" + "- When traveling thru time (if \"Masks Equippable as Adult\" is activated)" + ); UIWidgets::PaddedEnhancementCheckbox("Mask Select in Inventory", CVAR_ENHANCEMENT("MaskSelect"), true, false); UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", CVAR_ENHANCEMENT("NutsExplodeBombs"), true, false); diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 56c786889..50416be1f 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -539,14 +539,19 @@ void Play_Init(GameState* thisx) { (s32)(zAllocAligned + zAllocSize) - (s32)(zAllocAligned - zAlloc)); Fault_AddClient(&D_801614B8, ZeldaArena_Display, NULL, NULL); - // In order to keep bunny hood equipped on first load, we need to pre-set the age reqs for the item and slot - if ((CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && CVarGetInteger(CVAR_ENHANCEMENT("AdultBunnyHood"), 0)) || CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0)) { - gItemAgeReqs[ITEM_MASK_BUNNY] = AGE_REQ_NONE; - if(INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_MASK_BUNNY) + // In order to keep masks equipped on first load, we need to pre-set the age reqs for the item and slot + if (CVarGetInteger(CVAR_ENHANCEMENT("AdultMasks"), 0) || CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0)) { + for (int i = ITEM_MASK_KEATON; i <= ITEM_MASK_TRUTH; i += 1) { + gItemAgeReqs[i] = AGE_REQ_NONE; + } + if (INV_CONTENT(ITEM_TRADE_CHILD) >= ITEM_MASK_KEATON && INV_CONTENT(ITEM_TRADE_CHILD) <= ITEM_MASK_TRUTH) { gSlotAgeReqs[SLOT_TRADE_CHILD] = AGE_REQ_NONE; - } - else { - gItemAgeReqs[ITEM_MASK_BUNNY] = gSlotAgeReqs[SLOT_TRADE_CHILD] = AGE_REQ_CHILD; + } + } else { + for (int i = ITEM_MASK_KEATON; i <= ITEM_MASK_TRUTH; i += 1) { + gItemAgeReqs[i] = AGE_REQ_CHILD; + } + gSlotAgeReqs[SLOT_TRADE_CHILD] = AGE_REQ_CHILD; } func_800304DC(play, &play->actorCtx, play->linkActorEntry); diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 08ddef62d..94a1baeb7 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -140,6 +140,10 @@ void Sram_OpenSave() { break; } + if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { + gSaveContext.maskMemory = PLAYER_MASK_NONE; + } + osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex); osSyncPrintf(VT_RST); diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 22d15157f..b179f2427 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -1089,7 +1089,6 @@ static s8 sItemActions[] = { PLAYER_IA_SWORD_BIGGORON, // ITEM_SWORD_BIGGORON }; -static u8 sMaskMemory; u8 gWalkSpeedToggle1; u8 gWalkSpeedToggle2; @@ -2251,37 +2250,20 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { s32 item; s32 i; - if (this->currentMask != PLAYER_MASK_NONE) { - if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) { - s32 maskItem = this->currentMask - PLAYER_MASK_KEATON + ITEM_MASK_KEATON; - bool hasOnDpad = false; - if (CVarGetInteger(CVAR_SETTING("DpadEquips"), 0) != 0) { - for (int buttonIndex = 4; buttonIndex < 8; buttonIndex++) { - hasOnDpad |= gSaveContext.equips.buttonItems[buttonIndex] == maskItem; - } - } + if (this->currentMask != PLAYER_MASK_NONE && !CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { + maskItemAction = this->currentMask - 1 + PLAYER_IA_MASK_KEATON; - if (gSaveContext.equips.buttonItems[0] != maskItem && gSaveContext.equips.buttonItems[1] != maskItem && - gSaveContext.equips.buttonItems[2] != maskItem && gSaveContext.equips.buttonItems[3] != maskItem && - !hasOnDpad) { - this->currentMask = sMaskMemory = PLAYER_MASK_NONE; - func_808328EC(this, NA_SE_PL_CHANGE_ARMS); - } - } else { - maskItemAction = this->currentMask - 1 + PLAYER_IA_MASK_KEATON; - - bool hasOnDpad = false; - if (CVarGetInteger(CVAR_SETTING("DpadEquips"), 0) != 0) { - for (int buttonIndex = 0; buttonIndex < 4; buttonIndex++) { - hasOnDpad |= Player_ItemIsItemAction(DPAD_ITEM(buttonIndex), maskItemAction); - } - } - if (!Player_ItemIsItemAction(C_BTN_ITEM(0), maskItemAction) && - !Player_ItemIsItemAction(C_BTN_ITEM(1), maskItemAction) && - !Player_ItemIsItemAction(C_BTN_ITEM(2), maskItemAction) && !hasOnDpad) { - this->currentMask = PLAYER_MASK_NONE; + bool hasOnDpad = false; + if (CVarGetInteger(CVAR_SETTING("DpadEquips"), 0) != 0) { + for (int buttonIndex = 0; buttonIndex < 4; buttonIndex++) { + hasOnDpad |= Player_ItemIsItemAction(DPAD_ITEM(buttonIndex), maskItemAction); } } + if (!Player_ItemIsItemAction(C_BTN_ITEM(0), maskItemAction) && + !Player_ItemIsItemAction(C_BTN_ITEM(1), maskItemAction) && + !Player_ItemIsItemAction(C_BTN_ITEM(2), maskItemAction) && !hasOnDpad) { + this->currentMask = PLAYER_MASK_NONE; + } } if (!(this->stateFlags1 & (PLAYER_STATE1_ITEM_OVER_HEAD | PLAYER_STATE1_IN_CUTSCENE)) && !func_8008F128(this)) { @@ -3221,7 +3203,8 @@ void Player_UseItem(PlayState* play, Player* this, s32 item) { this->currentMask = itemAction - PLAYER_IA_MASK_KEATON + 1; } - sMaskMemory = this->currentMask; + gSaveContext.maskMemory = this->currentMask; + func_808328EC(this, NA_SE_PL_CHANGE_ARMS); } else if (((itemAction >= PLAYER_IA_OCARINA_FAIRY) && (itemAction <= PLAYER_IA_OCARINA_OF_TIME)) || (itemAction >= PLAYER_IA_BOTTLE_FISH)) { @@ -5069,7 +5052,9 @@ void func_8083A0F4(PlayState* play, Player* this) { this->interactRangeActor->parent = &this->actor; Player_SetupAction(play, this, Player_Action_8084F608, 0); this->stateFlags1 |= PLAYER_STATE1_IN_CUTSCENE; - sMaskMemory = PLAYER_MASK_NONE; + if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0) || !CVarGetInteger(CVAR_ENHANCEMENT("AdultMasks"), 0)) { + gSaveContext.maskMemory = PLAYER_MASK_NONE; + } } else { LinkAnimationHeader* anim; @@ -8940,7 +8925,9 @@ void func_80843AE8(PlayState* play, Player* this) { OnePointCutscene_Init(play, 9908, 125, &this->actor, MAIN_CAM); } else if (play->gameOverCtx.state == GAMEOVER_DEATH_WAIT_GROUND) { play->gameOverCtx.state = GAMEOVER_DEATH_DELAY_MENU; - sMaskMemory = PLAYER_MASK_NONE; + if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { + gSaveContext.maskMemory = PLAYER_MASK_NONE; + } } } @@ -10191,11 +10178,12 @@ void Player_Init(Actor* thisx, PlayState* play2) { Player_UseItem(play, this, ITEM_NONE); Player_SetEquipmentData(play, this); this->prevBoots = this->currentBoots; - if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) { + //keep masks thru loading zones + if (CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { if (INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_SOLD_OUT) { - sMaskMemory = PLAYER_MASK_NONE; + gSaveContext.maskMemory = PLAYER_MASK_NONE; } - this->currentMask = sMaskMemory; + this->currentMask = gSaveContext.maskMemory; } Player_InitCommon(this, play, gPlayerSkelHeaders[((void)0, gSaveContext.linkAge)]); this->giObjectSegment = (void*)(((uintptr_t)ZELDA_ARENA_MALLOC_DEBUG(0x3008) + 8) & ~0xF); 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 d34ce4d8a..3214de005 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 @@ -342,24 +342,25 @@ void KaleidoScope_HandleItemCycles(PlayState* play) { ); //the slot age requirement for the child trade slot has to be updated - //in case it currently holds the bunny hood + //in case it currently holds a mask //to allow adult link to wear it if the setting is enabled gSlotAgeReqs[SLOT_TRADE_CHILD] = ( - ((CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger(CVAR_ENHANCEMENT("AdultBunnyHood"), 0)) || + CVarGetInteger(CVAR_ENHANCEMENT("AdultMasks"), 0) || CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0) ) && - INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_MASK_BUNNY - ? AGE_REQ_NONE - : AGE_REQ_CHILD; - - //also update the age requirement for the bunny hood itself - gItemAgeReqs[ITEM_MASK_BUNNY] = - ((CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger(CVAR_ENHANCEMENT("AdultBunnyHood"), 0)) || - CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0) + INV_CONTENT(ITEM_TRADE_CHILD) >= ITEM_MASK_KEATON && + INV_CONTENT(ITEM_TRADE_CHILD) <= ITEM_MASK_TRUTH ? AGE_REQ_NONE : AGE_REQ_CHILD; + //also update the age requirements for the masks itself + for (int i = ITEM_MASK_KEATON; i <= ITEM_MASK_TRUTH; i += 1) { + gItemAgeReqs[i] = CVarGetInteger(CVAR_ENHANCEMENT("AdultMasks"), 0) || CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0) + ? AGE_REQ_NONE + : AGE_REQ_CHILD; + } + //handle the adult trade select KaleidoScope_HandleItemCycleExtras( play,