From bd8a5825f94bf226680ce009ce5a50948aa48a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= <159546+serprex@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:24:03 +0000 Subject: [PATCH] Hookify masks / timeless equipment (#7088) --- soh/soh/Enhancements/AdultMasks.cpp | 37 +++++++++ soh/soh/Enhancements/AdultMasks.h | 15 ++++ soh/soh/Enhancements/BunnyHood.cpp | 69 +++++++++++++++++ soh/soh/Enhancements/BunnyHood.h | 13 ++++ .../Enhancements/Cheats/TimelessEquipment.cpp | 15 ++++ soh/soh/Enhancements/PersistentMasks.cpp | 30 ++++++++ soh/soh/Enhancements/SpeedModifiers.cpp | 25 +------ .../Enhancements/TimeSavers/MarketSneak.cpp | 56 +++++++++++++- .../vanilla-behavior/GIVanillaBehavior.h | 75 +++++++++++++++++++ soh/soh/Enhancements/gameplaystats.cpp | 5 +- soh/soh/Enhancements/gameplaystats.h | 2 +- soh/soh/SohGui/SohMenuEnhancements.cpp | 6 +- soh/src/code/z_face_reaction.c | 9 +-- soh/src/code/z_message_PAL.c | 4 +- soh/src/code/z_parameter.c | 15 ++-- soh/src/code/z_play.c | 20 ----- soh/src/code/z_player_lib.c | 2 +- soh/src/code/z_sram.c | 4 - .../actors/ovl_En_Heishi4/z_en_heishi4.c | 38 +--------- .../actors/ovl_player_actor/z_player.c | 21 +----- .../ovl_kaleido_scope/z_kaleido_equipment.c | 25 +++---- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 17 ----- .../misc/ovl_kaleido_scope/z_kaleido_scope.h | 21 +++++- 23 files changed, 366 insertions(+), 158 deletions(-) create mode 100644 soh/soh/Enhancements/AdultMasks.cpp create mode 100644 soh/soh/Enhancements/AdultMasks.h create mode 100644 soh/soh/Enhancements/BunnyHood.cpp create mode 100644 soh/soh/Enhancements/BunnyHood.h create mode 100644 soh/soh/Enhancements/Cheats/TimelessEquipment.cpp create mode 100644 soh/soh/Enhancements/PersistentMasks.cpp diff --git a/soh/soh/Enhancements/AdultMasks.cpp b/soh/soh/Enhancements/AdultMasks.cpp new file mode 100644 index 0000000000..60d0314224 --- /dev/null +++ b/soh/soh/Enhancements/AdultMasks.cpp @@ -0,0 +1,37 @@ +#include "soh/Enhancements/AdultMasks.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/ShipInit.hpp" + +extern "C" { +#include "z64.h" +#include "macros.h" +#include "variables.h" +} + +bool Ship_MasksEquippableAsAdult() { + return CVarGetInteger(CVAR_ADULT_MASKS_NAME, 0) || CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0); +} + +static bool IsMask(int item) { + return item >= ITEM_MASK_KEATON && item <= ITEM_MASK_TRUTH; +} + +static void RegisterAdultMasks() { + bool adultMasks = CVarGetInteger(CVAR_ADULT_MASKS_NAME, 0); + + // Masks drop their child-only age requirement + COND_VB_SHOULD(VB_ITEM_MEETS_AGE_REQ, adultMasks, { + if (IsMask(va_arg(args, int))) { + *should = true; + } + }); + + // Same for the child trade slot, but only while it holds a mask + COND_VB_SHOULD(VB_SLOT_MEETS_AGE_REQ, adultMasks, { + if (va_arg(args, int) == SLOT_TRADE_CHILD && IsMask(INV_CONTENT(ITEM_TRADE_CHILD))) { + *should = true; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterAdultMasks, { CVAR_ADULT_MASKS_NAME }); diff --git a/soh/soh/Enhancements/AdultMasks.h b/soh/soh/Enhancements/AdultMasks.h new file mode 100644 index 0000000000..1417da2834 --- /dev/null +++ b/soh/soh/Enhancements/AdultMasks.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "soh/cvar_prefixes.h" + +#define CVAR_ADULT_MASKS_NAME CVAR_ENHANCEMENT("AdultMasks") + +#ifdef __cplusplus +extern "C" { +#endif +bool Ship_MasksEquippableAsAdult(); +#ifdef __cplusplus +}; +#endif diff --git a/soh/soh/Enhancements/BunnyHood.cpp b/soh/soh/Enhancements/BunnyHood.cpp new file mode 100644 index 0000000000..175c8424c5 --- /dev/null +++ b/soh/soh/Enhancements/BunnyHood.cpp @@ -0,0 +1,69 @@ +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/ShipInit.hpp" +#include "soh/Enhancements/BunnyHood.h" +#include "soh/Enhancements/gameplaystats.h" + +extern "C" { +#include "z64.h" +#include "functions.h" +#include "macros.h" +#include "variables.h" +extern PlayState* gPlayState; +} + +BunnyHoodMode Ship_GetBunnyHoodMode() { + return (BunnyHoodMode)CVarGetInteger(CVAR_BUNNY_HOOD_NAME, BUNNY_HOOD_VANILLA); +} + +float Ship_GetBunnyHoodRunFactor(Player* player) { + if (Ship_GetBunnyHoodMode() != BUNNY_HOOD_VANILLA && player->currentMask == PLAYER_MASK_BUNNY) { + return 1.5f; + } + return 1.0f; +} + +float Ship_GetBunnyHoodJumpFactor(Player* player) { + if (Ship_GetBunnyHoodMode() == BUNNY_HOOD_FAST_AND_JUMP && player->currentMask == PLAYER_MASK_BUNNY) { + return 1.5f; + } + return 1.0f; +} + +static void RegisterBunnyHood() { + bool bunnyHoodActive = Ship_GetBunnyHoodMode() != BUNNY_HOOD_VANILLA; + + // Wearing the hood shouldn't lock you out of NPC interactions, so NPCs ignore it + COND_VB_SHOULD(VB_NPC_REACT_TO_MASK, bunnyHoodActive, { + u8 currentMask = va_arg(args, int); + if (currentMask == PLAYER_MASK_BUNNY) { + *should = false; + } + }); + + // Masks stay usable where trade items are restricted, so the hood can be equipped there + COND_VB_SHOULD(VB_DISABLE_TRADE_ITEM_BUTTON, bunnyHoodActive, { + u8 item = va_arg(args, int); + if (item >= ITEM_MASK_KEATON && item <= ITEM_MASK_TRUTH) { + *should = false; + } + }); + + // Same speed boost as running, for the "Move in first person" setting + COND_VB_SHOULD(VB_PLAYER_MODIFY_FIRST_PERSON_SPEED, bunnyHoodActive, { + Player* player = va_arg(args, Player*); + f32* movementSpeed = va_arg(args, f32*); + *movementSpeed *= Ship_GetBunnyHoodRunFactor(player); + }); + + // Gameplay stat: time spent wearing the hood + COND_HOOK(OnPlayerUpdate, bunnyHoodActive, []() { + if (gSaveContext.ship.stats.gameComplete || (IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.isPaused)) { + return; + } + if (GET_PLAYER(gPlayState)->currentMask == PLAYER_MASK_BUNNY) { + gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD]++; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterBunnyHood, { CVAR_BUNNY_HOOD_NAME }); diff --git a/soh/soh/Enhancements/BunnyHood.h b/soh/soh/Enhancements/BunnyHood.h new file mode 100644 index 0000000000..52724c43f6 --- /dev/null +++ b/soh/soh/Enhancements/BunnyHood.h @@ -0,0 +1,13 @@ +#pragma once + +#include "soh/Enhancements/enhancementTypes.h" +#include "soh/cvar_prefixes.h" + +typedef struct Player Player; + +#define CVAR_BUNNY_HOOD_NAME CVAR_ENHANCEMENT("MMBunnyHood") + +BunnyHoodMode Ship_GetBunnyHoodMode(); +// Speed multipliers the effect applies to the player, 1.0f when it doesn't. +float Ship_GetBunnyHoodRunFactor(Player* player); +float Ship_GetBunnyHoodJumpFactor(Player* player); diff --git a/soh/soh/Enhancements/Cheats/TimelessEquipment.cpp b/soh/soh/Enhancements/Cheats/TimelessEquipment.cpp new file mode 100644 index 0000000000..0897b7b979 --- /dev/null +++ b/soh/soh/Enhancements/Cheats/TimelessEquipment.cpp @@ -0,0 +1,15 @@ +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/ShipInit.hpp" +#include "soh/cvar_prefixes.h" + +#define CVAR_TIMELESS_EQUIPMENT_NAME CVAR_CHEAT("TimelessEquipment") + +static void RegisterTimelessEquipment() { + bool timelessEquipment = CVarGetInteger(CVAR_TIMELESS_EQUIPMENT_NAME, 0); + + COND_VB_SHOULD(VB_PLAYER_MEETS_AGE_REQ, timelessEquipment, { *should = true; }); + COND_VB_SHOULD(VB_ITEM_MEETS_AGE_REQ, timelessEquipment, { *should = true; }); + COND_VB_SHOULD(VB_SLOT_MEETS_AGE_REQ, timelessEquipment, { *should = true; }); +} + +static RegisterShipInitFunc initFunc(RegisterTimelessEquipment, { CVAR_TIMELESS_EQUIPMENT_NAME }); diff --git a/soh/soh/Enhancements/PersistentMasks.cpp b/soh/soh/Enhancements/PersistentMasks.cpp new file mode 100644 index 0000000000..8baa1dfba9 --- /dev/null +++ b/soh/soh/Enhancements/PersistentMasks.cpp @@ -0,0 +1,30 @@ +#include "soh/Enhancements/AdultMasks.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/ShipInit.hpp" + +extern "C" { +#include "z64.h" +#include "macros.h" +#include "variables.h" +} + +#define CVAR_PERSISTENT_MASKS_NAME CVAR_ENHANCEMENT("PersistentMasks") + +static void RegisterPersistentMasks() { + bool persistentMasks = CVarGetInteger(CVAR_PERSISTENT_MASKS_NAME, 0); + + // A mask normally comes off the moment it leaves the buttons, keep it on instead + COND_VB_SHOULD(VB_PLAYER_UNEQUIP_MASK_WITHOUT_BUTTON, persistentMasks, { *should = false; }); + + // Put the remembered mask back on whenever the player actor is built, so it + // survives loading zones, deaths and save loads + COND_ID_HOOK(OnActorInit, ACTOR_PLAYER, persistentMasks, [](void* actorPtr) { + // Forget the mask if it's gone from the inventory, or if adult can't wear it + if (INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_SOLD_OUT || (LINK_IS_ADULT && !Ship_MasksEquippableAsAdult())) { + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; + } + ((Player*)actorPtr)->currentMask = gSaveContext.ship.maskMemory; + }); +} + +static RegisterShipInitFunc initFunc(RegisterPersistentMasks, { CVAR_PERSISTENT_MASKS_NAME }); diff --git a/soh/soh/Enhancements/SpeedModifiers.cpp b/soh/soh/Enhancements/SpeedModifiers.cpp index 92f8974533..9193485e99 100644 --- a/soh/soh/Enhancements/SpeedModifiers.cpp +++ b/soh/soh/Enhancements/SpeedModifiers.cpp @@ -1,7 +1,7 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/ShipInit.hpp" #include "soh/OTRGlobals.h" -#include "soh/Enhancements/enhancementTypes.h" +#include "soh/Enhancements/BunnyHood.h" extern "C" { #include "z64.h" @@ -12,7 +12,6 @@ extern PlayState* gPlayState; } #define CVAR_SPEED_MODIFIER_VALUE_NAME CVAR_CHEAT("SpeedModifier.Value") -#define CVAR_BUNNY_HOOD_NAME CVAR_ENHANCEMENT("MMBunnyHood") static f32 GetSpeedModifierFactor(bool inputAvailable) { f32 value = CVarGetFloat(CVAR_SPEED_MODIFIER_VALUE_NAME, 1.0f); @@ -42,29 +41,13 @@ static f32 GetSpeedModifierJumpFactor() { return GetSpeedModifierFactor(true); } -static f32 GetBunnyHoodRunFactor(Player* player) { - if (CVarGetInteger(CVAR_BUNNY_HOOD_NAME, BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && - player->currentMask == PLAYER_MASK_BUNNY) { - return 1.5f; - } - return 1.0f; -} - -static f32 GetBunnyHoodJumpFactor(Player* player) { - if (CVarGetInteger(CVAR_BUNNY_HOOD_NAME, BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && - player->currentMask == PLAYER_MASK_BUNNY) { - return 1.5f; - } - return 1.0f; -} - static bool ShouldAmplifyJump(Player* player) { - return GetBunnyHoodJumpFactor(player) != 1.0f || GetSpeedModifierJumpFactor() != 1.0f; + return Ship_GetBunnyHoodJumpFactor(player) != 1.0f || GetSpeedModifierJumpFactor() != 1.0f; } static void RegisterSpeedModifiers() { bool speedModifierActive = CVarGetFloat(CVAR_SPEED_MODIFIER_VALUE_NAME, 1.0f) != 1.0f; - bool bunnyHoodActive = CVarGetInteger(CVAR_BUNNY_HOOD_NAME, BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA; + bool bunnyHoodActive = Ship_GetBunnyHoodMode() != BUNNY_HOOD_VANILLA; // Airborne (jump) velocity. z_player clamps linearVelocity to the vanilla run speed limit when this returns true; // skip that clamp so the amplified running velocity carries into the jump. @@ -90,7 +73,7 @@ static void RegisterSpeedModifiers() { COND_VB_SHOULD(VB_PLAYER_MODIFY_RUN_SPEED, speedModifierActive || bunnyHoodActive, { Player* player = va_arg(args, Player*); f32* speedTarget = va_arg(args, f32*); - *speedTarget *= GetBunnyHoodRunFactor(player) * GetSpeedModifierFactor(true); + *speedTarget *= Ship_GetBunnyHoodRunFactor(player) * GetSpeedModifierFactor(true); }); // Swim speed multiplied in place. Called per speed z_player scales; bunny hood does not apply underwater. diff --git a/soh/soh/Enhancements/TimeSavers/MarketSneak.cpp b/soh/soh/Enhancements/TimeSavers/MarketSneak.cpp index b1567cb4c9..ed1bd2b97b 100644 --- a/soh/soh/Enhancements/TimeSavers/MarketSneak.cpp +++ b/soh/soh/Enhancements/TimeSavers/MarketSneak.cpp @@ -1,12 +1,21 @@ #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" #include "soh/Enhancements/randomizer/randomizer.h" +#include "soh/Enhancements/randomizer/randomizer_entrance.h" extern "C" { +#include #include +#include "overlays/actors/ovl_En_Heishi4/z_en_heishi4.h" extern PlayState* gPlayState; -} -// RANDOTODO: Port the rest of the behavior for this enhancement here. +// the guard's idle action func, restored once the sneak prompt is answered +void func_80A56614(EnHeishi4* heishi, PlayState* play); + +u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); +} void BuildNightGuardMessage(uint16_t* textId, bool* loadFromMessageTable) { // Other guards should not have their text overridden @@ -22,9 +31,50 @@ void BuildNightGuardMessage(uint16_t* textId, bool* loadFromMessageTable) { *loadFromMessageTable = false; } +// Answers the choice from BuildNightGuardMessage, letting child Link exit from the Market +// entrance to Hyrule Field at night. +extern "C" void EnHeishi4_MarketSneak(EnHeishi4* heishi, PlayState* play) { + if (Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE && Message_ShouldAdvance(play)) { + switch (play->msgCtx.choiceIndex) { + case 0: // yes + if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES) != RO_GENERIC_OFF) { + play->nextEntranceIndex = + Entrance_OverrideNextIndex(ENTR_HYRULE_FIELD_ON_BRIDGE_SPAWN); // Market Entrance -> HF + } else { + play->nextEntranceIndex = ENTR_HYRULE_FIELD_PAST_BRIDGE_SPAWN; // HF Near bridge (OoT cutscene + // entrance) to not fall in the water + } + play->transitionTrigger = TRANS_TRIGGER_START; + play->transitionType = TRANS_TYPE_CIRCLE(TCA_STARBURST, TCC_WHITE, TCS_FAST); + gSaveContext.nextTransitionType = TRANS_TYPE_CIRCLE(TCA_STARBURST, TCC_WHITE, TCS_FAST); + heishi->actionFunc = func_80A56614; + break; + case 1: // no + heishi->actionFunc = func_80A56614; + break; + } + } +} + void MarketSneak_Register() { COND_ID_HOOK(OnOpenText, TEXT_MARKET_GUARD_NIGHT, CVarGetInteger(CVAR_ENHANCEMENT("MarketSneak"), 0), BuildNightGuardMessage); + + COND_VB_SHOULD(VB_MARKET_NIGHT_GUARD_SET_ACTION_AFTER_TALK, CVarGetInteger(CVAR_ENHANCEMENT("MarketSneak"), 0), { + EnHeishi4* heishi = va_arg(args, EnHeishi4*); + PlayState* play = va_arg(args, PlayState*); + Player* player = GET_PLAYER(play); + + // Only allow sneaking when not wearing a mask as that triggers different dialogue. A mask NPCs + // don't react to (MM Bunny hood) is fine in that case. + if (player->currentMask != PLAYER_MASK_NONE && + GameInteractor_Should(VB_NPC_REACT_TO_MASK, true, player->currentMask)) { + return; + } + + heishi->actionFunc = EnHeishi4_MarketSneak; + *should = false; + }); } -static RegisterShipInitFunc initFunc(MarketSneak_Register, { CVAR_ENHANCEMENT("MarketSneak") }); \ No newline at end of file +static RegisterShipInitFunc initFunc(MarketSneak_Register, { CVAR_ENHANCEMENT("MarketSneak") }); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 895ab4ae46..f4347d94ac 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -3755,4 +3755,79 @@ typedef enum { // #### `args` // - `*EnBox` VB_CHEST_CONSIDER_CHEST_OPEN, + + // #### `result` + // ```c + // true + // ``` + // Whether NPCs give their mask reaction text for the mask being worn. + // #### `args` + // - `u8 currentMask` + VB_NPC_REACT_TO_MASK, + + // #### `result` + // ```c + // true + // ``` + // Whether a trade item button gets greyed out while trade items are restricted. + // #### `args` + // - `u8 item` + VB_DISABLE_TRADE_ITEM_BUTTON, + + // #### `result` + // ```c + // true + // ``` + // Movement speed for the "Move in first person" setting, multiplied in place. + // #### `args` + // - `*Player` + // - `f32*` movementSpeed + VB_PLAYER_MODIFY_FIRST_PERSON_SPEED, + + // #### `result` + // ```c + // true + // ``` + // Whether the market night guard goes back to idle once talked to, rather than + // a hook taking over his action func. + // #### `args` + // - `*EnHeishi4` + // - `*PlayState` + VB_MARKET_NIGHT_GUARD_SET_ACTION_AFTER_TALK, + + // #### `result` + // ```c + // ageReq == AGE_REQ_NONE || ageReq == gSaveContext.linkAge + // ``` + // Whether the player is the right age for something age gated. + // #### `args` + // - `u8 ageReq` an `AGE_REQ_*`, which for adult and child is the matching `LINK_AGE_*` + VB_PLAYER_MEETS_AGE_REQ, + + // #### `result` + // ```c + // gItemAgeReqs[itemIndex] == AGE_REQ_NONE || gItemAgeReqs[itemIndex] == gSaveContext.linkAge + // ``` + // Whether the player is the right age to hold an item. + // #### `args` + // - `u8 itemIndex` + VB_ITEM_MEETS_AGE_REQ, + + // #### `result` + // ```c + // gSlotAgeReqs[slotIndex] == AGE_REQ_NONE || gSlotAgeReqs[slotIndex] == gSaveContext.linkAge + // ``` + // Whether the player is the right age to use an inventory slot. + // #### `args` + // - `u8 slotIndex` + VB_SLOT_MEETS_AGE_REQ, + + // #### `result` + // ```c + // this->currentMask != PLAYER_MASK_NONE + // ``` + // Whether a worn mask comes off once it's no longer on a button. + // #### `args` + // - `*Player` + VB_PLAYER_UNEQUIP_MASK_WITHOUT_BUTTON, } GIVanillaBehavior; diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index de5da8ab11..9602775b1d 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -10,7 +10,7 @@ #include #include -#include "soh/Enhancements/enhancementTypes.h" +#include "soh/Enhancements/BunnyHood.h" #include "soh/OTRGlobals.h" extern "C" { @@ -562,8 +562,7 @@ void DrawGameplayStatsCountsTab() { GameplayStatsRow("Sword Swings:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_SWORD_SWINGS])); GameplayStatsRow("Steps Taken:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_STEPS])); // If using MM Bunny Hood enhancement, show how long it's been equipped (not counting pause time) - if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA || - gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD] > 0) { + if (Ship_GetBunnyHoodMode() != BUNNY_HOOD_VANILLA || gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD] > 0) { GameplayStatsRow("Bunny Hood Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD] / 2)); } diff --git a/soh/soh/Enhancements/gameplaystats.h b/soh/soh/Enhancements/gameplaystats.h index e1fa3b1d7a..2a07775cab 100644 --- a/soh/soh/Enhancements/gameplaystats.h +++ b/soh/soh/Enhancements/gameplaystats.h @@ -231,7 +231,7 @@ typedef enum { COUNT_SWORD_SWINGS, // z_player.c COUNT_SIDEHOPS, // z_player.c COUNT_BACKFLIPS, // z_player.c - COUNT_TIME_BUNNY_HOOD, // z_play.c + COUNT_TIME_BUNNY_HOOD, // BunnyHood.cpp COUNT_MAX diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index a11e2679df..d9c600a43d 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1,6 +1,8 @@ #include "SohMenu.h" #include #include "soh/Enhancements/SwitchAge.h" +#include "soh/Enhancements/AdultMasks.h" +#include "soh/Enhancements/BunnyHood.h" #include #include #include @@ -906,7 +908,7 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Masks", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Bunny Hood Effect", WIDGET_CVAR_COMBOBOX) - .CVar(CVAR_ENHANCEMENT("MMBunnyHood")) + .CVar(CVAR_BUNNY_HOOD_NAME) .Options(ComboboxOptions() .ComboMap(bunnyHoodEffectMap) .Tooltip("Wearing the Bunny Hood grants a speed and jump boost like in Majora's Mask.\n" @@ -914,7 +916,7 @@ void SohMenu::AddMenuEnhancements() { "The effects of either option are not accounted for in Randomizer logic.\n" "Also disables NPC's reactions to wearing the Bunny Hood.")); AddWidget(path, "Masks Equippable as Adult", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("AdultMasks")) + .CVar(CVAR_ADULT_MASKS_NAME) .Options(CheckboxOptions().Tooltip("Allows masks to be equipped normally from the pause menu as adult.")); AddWidget(path, "Persistent Masks", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("PersistentMasks")) diff --git a/soh/src/code/z_face_reaction.c b/soh/src/code/z_face_reaction.c index 0ea94b119a..b6f1c69490 100644 --- a/soh/src/code/z_face_reaction.c +++ b/soh/src/code/z_face_reaction.c @@ -1,5 +1,5 @@ #include "global.h" -#include "soh/Enhancements/enhancementTypes.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" u16 sReactionTextIds[][PLAYER_MASK_MAX] = { { 0x0000, 0x7124, 0x7127, 0x7126, 0x7125, 0x7127, 0x7124, 0x7125, 0x7127 }, @@ -67,10 +67,9 @@ u16 sReactionTextIds[][PLAYER_MASK_MAX] = { u16 Text_GetFaceReaction(PlayState* play, u32 reactionSet) { u8 currentMask = Player_GetMask(play); - if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && - currentMask == PLAYER_MASK_BUNNY) { + if (!GameInteractor_Should(VB_NPC_REACT_TO_MASK, true, currentMask)) { return 0; - } else { - return sReactionTextIds[reactionSet][currentMask]; } + + return sReactionTextIds[reactionSet][currentMask]; } diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index c6c2803b17..66a7baae23 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -2782,10 +2782,10 @@ void Message_OpenText(PlayState* play, u16 textId) { // font->msgOffset), font->msgLength, __FILE__, __LINE__); } else if (CVarGetInteger(CVAR_ENHANCEMENT("AskToEquip"), 0) && - (((LINK_IS_ADULT || CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0)) && + ((GameInteractor_Should(VB_PLAYER_MEETS_AGE_REQ, LINK_IS_ADULT, LINK_AGE_ADULT) && // 0C = Biggoron, 4B = Giant's, 4E = Mirror Shield, 50-51 = Tunics (textId == 0x0C || textId == 0x4B || textId == 0x4E || textId == 0x50 || textId == 0x51)) || - ((!LINK_IS_ADULT || CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0)) && + (GameInteractor_Should(VB_PLAYER_MEETS_AGE_REQ, !LINK_IS_ADULT, LINK_AGE_CHILD) && // 4C = Deku Shield, A4 = Kokiri Sword (textId == 0x4C || textId == 0xA4)) || // 4D == Hylian Shield diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 894a212a0f..69fd6ded3d 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1143,13 +1143,14 @@ void func_80083108(PlayState* play) { if (interfaceCtx->restrictions.tradeItems != 0) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { - if ((CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != - BUNNY_HOOD_VANILLA) && - (gSaveContext.equips.buttonItems[i] >= ITEM_MASK_KEATON) && - (gSaveContext.equips.buttonItems[i] <= ITEM_MASK_TRUTH)) { - gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_ENABLED; - } else if ((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) && - (gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK)) { + if ((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) && + (gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK)) { + if (!GameInteractor_Should(VB_DISABLE_TRADE_ITEM_BUTTON, true, + gSaveContext.equips.buttonItems[i])) { + gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_ENABLED; + continue; + } + if (gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] == BTN_ENABLED) { sp28 = 1; } diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 4a92668c41..37fc299da4 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -559,21 +559,6 @@ void Play_Init(GameState* thisx) { Fault_AddClient(&D_801614B8, ZeldaArena_Display, NULL, NULL); - // 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 { - for (int i = ITEM_MASK_KEATON; i <= ITEM_MASK_TRUTH; i += 1) { - gItemAgeReqs[i] = AGE_REQ_CHILD; - } - gSlotAgeReqs[SLOT_TRADE_CHILD] = AGE_REQ_CHILD; - } - // Handle Rocs Feather requirement gItemAgeReqs[ITEM_ROCS_FEATHER] = AGE_REQ_NONE; gSlotAgeReqs[SLOT_NAYRUS_LOVE] = AGE_REQ_NONE; @@ -1150,11 +1135,6 @@ void Play_Update(PlayState* play) { gSaveContext.ship.stats.playTimer++; gSaveContext.ship.stats.sceneTimer++; gSaveContext.ship.stats.roomTimer++; - - if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && - Player_GetMask(play) == PLAYER_MASK_BUNNY) { - gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD]++; - } } if (play->actorCtx.freezeFlashTimer && (play->actorCtx.freezeFlashTimer-- < 5)) { diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index c9d5ba5d8c..62b003c989 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -782,7 +782,7 @@ s32 Player_GetStrength(void) { return PLAYER_STR_NONE; } - if (CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0) || LINK_IS_ADULT) { + if (GameInteractor_Should(VB_PLAYER_MEETS_AGE_REQ, LINK_IS_ADULT, LINK_AGE_ADULT)) { return strengthUpgrade; } else if (strengthUpgrade != 0) { return PLAYER_STR_BRACELET; diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index ac93b9358f..97c0a6612f 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -143,10 +143,6 @@ void Sram_OpenSave() { break; } - if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { - gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; - } - osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex); osSyncPrintf(VT_RST); diff --git a/soh/src/overlays/actors/ovl_En_Heishi4/z_en_heishi4.c b/soh/src/overlays/actors/ovl_En_Heishi4/z_en_heishi4.c index 47848e10ca..556e7d26aa 100644 --- a/soh/src/overlays/actors/ovl_En_Heishi4/z_en_heishi4.c +++ b/soh/src/overlays/actors/ovl_En_Heishi4/z_en_heishi4.c @@ -1,7 +1,7 @@ #include "z_en_heishi4.h" #include "objects/object_sd/object_sd.h" #include "vt.h" -#include "soh/OTRGlobals.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS (ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_FRIENDLY) @@ -21,7 +21,6 @@ void func_80A56900(EnHeishi4* this, PlayState* play); void func_80A56994(EnHeishi4* this, PlayState* play); void func_80A56A50(EnHeishi4* this, PlayState* play); void func_80A56ACC(EnHeishi4* this, PlayState* play); -void EnHeishi4_MarketSneak(EnHeishi4* this, PlayState* play); const ActorInit En_Heishi4_InitVars = { ACTOR_EN_HEISHI4, @@ -333,14 +332,7 @@ void func_80A56B40(EnHeishi4* this, PlayState* play) { return; } if (this->type == HEISHI4_AT_MARKET_NIGHT) { - Player* player = GET_PLAYER(play); - // Only allow sneaking when not wearing a mask as that triggers different dialogue. MM Bunny hood disables - // these interactions, so bunny hood is fine in that case. - if (CVarGetInteger(CVAR_ENHANCEMENT("MarketSneak"), 0) && - (player->currentMask == PLAYER_MASK_NONE || - (player->currentMask == PLAYER_MASK_BUNNY && CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), 0)))) { - this->actionFunc = EnHeishi4_MarketSneak; - } else { + if (GameInteractor_Should(VB_MARKET_NIGHT_GUARD_SET_ACTION_AFTER_TALK, true, this, play)) { this->actionFunc = func_80A56614; return; } @@ -349,32 +341,6 @@ void func_80A56B40(EnHeishi4* this, PlayState* play) { Actor_OfferTalkNearColChkInfoCylinder(&this->actor, play); } -/*Function that allows child Link to exit from Market entrance to Hyrule Field -at night. -*/ -void EnHeishi4_MarketSneak(EnHeishi4* this, PlayState* play) { - if (Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE && Message_ShouldAdvance(play)) { - switch (play->msgCtx.choiceIndex) { - case 0: // yes - if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES) != RO_GENERIC_OFF) { - play->nextEntranceIndex = - Entrance_OverrideNextIndex(ENTR_HYRULE_FIELD_ON_BRIDGE_SPAWN); // Market Entrance -> HF - } else { - play->nextEntranceIndex = ENTR_HYRULE_FIELD_PAST_BRIDGE_SPAWN; // HF Near bridge (OoT cutscene - // entrance) to not fall in the water - } - play->transitionTrigger = TRANS_TRIGGER_START; - play->transitionType = TRANS_TYPE_CIRCLE(TCA_STARBURST, TCC_WHITE, TCS_FAST); - gSaveContext.nextTransitionType = TRANS_TYPE_CIRCLE(TCA_STARBURST, TCC_WHITE, TCS_FAST); - this->actionFunc = func_80A56614; - break; - case 1: // no - this->actionFunc = func_80A56614; - break; - } - } -} - void EnHeishi4_Update(Actor* thisx, PlayState* play) { EnHeishi4* this = (EnHeishi4*)thisx; s32 pad; 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 f7c75fdf00..fe36b2f4b8 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2497,7 +2497,7 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { s32 item; s32 i; - if (this->currentMask != PLAYER_MASK_NONE && !CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { + if (GameInteractor_Should(VB_PLAYER_UNEQUIP_MASK_WITHOUT_BUTTON, this->currentMask != PLAYER_MASK_NONE, this)) { maskItemAction = this->currentMask - 1 + PLAYER_IA_MASK_KEATON; bool hasOnDpad = false; @@ -5557,10 +5557,6 @@ void func_8083A0F4(PlayState* play, Player* this) { this->interactRangeActor->parent = &this->actor; Player_SetupAction(play, this, Player_Action_WaitForCutscene, 0); this->stateFlags1 |= PLAYER_STATE1_IN_CUTSCENE; - if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0) || - !CVarGetInteger(CVAR_ENHANCEMENT("AdultMasks"), 0)) { - gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; - } } else { LinkAnimationHeader* anim; @@ -9507,9 +9503,6 @@ void func_80843AE8(PlayState* play, Player* this) { OnePointCutscene_Init(play, 9908, 125, &this->actor, CAM_ID_MAIN); } else if (play->gameOverCtx.state == GAMEOVER_DEATH_WAIT_GROUND) { play->gameOverCtx.state = GAMEOVER_DEATH_DELAY_MENU; - if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { - gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; - } } } @@ -10820,13 +10813,6 @@ void Player_Init(Actor* thisx, PlayState* play2) { Player_UseItem(play, this, ITEM_NONE); Player_SetEquipmentData(play, this); this->prevBoots = this->currentBoots; - // keep masks thru loading zones - if (CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { - if (INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_SOLD_OUT) { - gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; - } - this->currentMask = gSaveContext.ship.maskMemory; - } Player_InitCommon(this, play, gPlayerSkelHeaders[((void)0, gSaveContext.linkAge)]); // `giObjectSegment` is used for both "get item" objects and title cards. The maximum size for // get item objects is 0x2000 (see the assert in func_8083AE40), and the maximum size for @@ -12674,10 +12660,7 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) { if (CVarGetInteger(CVAR_SETTING("MoveInFirstPerson"), 0) && CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) { f32 movementSpeed = LINK_IS_ADULT ? 9.0f : 8.25f; - if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && - this->currentMask == PLAYER_MASK_BUNNY) { - movementSpeed *= 1.5f; - } + GameInteractor_Should(VB_PLAYER_MODIFY_FIRST_PERSON_SPEED, true, this, &movementSpeed); f32 relX = (sControlInput->rel.stick_x / 10 * -invertXAxisMulti); f32 relY = (sControlInput->rel.stick_y / 10); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c index f0e7626f20..a8144cc759 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c @@ -773,29 +773,27 @@ void KaleidoScope_DrawEquipment(PlayState* play) { for (rowStart = 0, j = 0, temp = 0, i = 0; i < 4; i++, rowStart += 4, j += 16) { gSPVertex(POLY_OPA_DISP++, &pauseCtx->equipVtx[j], 16, 0); - bool drawGreyItems = !CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0); if (LINK_AGE_IN_YEARS == YEARS_CHILD) { point = CUR_UPG_VALUE(sChildUpgrades[i]); if ((point != 0) && (CUR_UPG_VALUE(sChildUpgrades[i]) != 0)) { + int upgradeItem = sChildUpgradeItemBases[i] + point - 1; // Grey Out the Gauntlets as Child // Grey Out Strength Upgrades when Disabled and the Toggle Strength Option is on - if ((drawGreyItems && - ((sChildUpgradeItemBases[i] + CUR_UPG_VALUE(sChildUpgrades[i]) - 1) == ITEM_GAUNTLETS_SILVER || - (sChildUpgradeItemBases[i] + CUR_UPG_VALUE(sChildUpgrades[i]) - 1) == ITEM_GAUNTLETS_GOLD)) || + if (!CHECK_AGE_REQ_ITEM(upgradeItem) || (CVarGetInteger(CVAR_ENHANCEMENT("ToggleStrength"), 0) && CVarGetInteger(CVAR_ENHANCEMENT("StrengthDisabled"), 0) && sChildUpgrades[i] == UPG_STRENGTH)) { gDPSetGrayscaleColor(POLY_OPA_DISP++, 109, 109, 109, 255); gSPGrayscale(POLY_OPA_DISP++, true); } - KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, - gItemIcons[sChildUpgradeItemBases[i] + point - 1], 32, 32, 0); + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[upgradeItem], 32, 32, 0); gSPGrayscale(POLY_OPA_DISP++, false); } } else { if ((i == 0) && (CUR_UPG_VALUE(sAdultUpgrades[i]) == 0)) { // If the player doesn't have the bow, load the current slingshot ammo upgrade instead. - if (drawGreyItems) { + // Check the base item, the upgrade level can be 0 here + if (!CHECK_AGE_REQ_ITEM(sChildUpgradeItemBases[i])) { gDPSetGrayscaleColor(POLY_OPA_DISP++, 109, 109, 109, 255); // Grey Out Slingshot Bullet Bags gSPGrayscale(POLY_OPA_DISP++, true); } @@ -804,19 +802,18 @@ void KaleidoScope_DrawEquipment(PlayState* play) { 32, 32, 0); gSPGrayscale(POLY_OPA_DISP++, false); } else if (CUR_UPG_VALUE(sAdultUpgrades[i]) != 0) { - // Grey Out the Goron Bracelet when Not Randomized and Toggle Strength Option is off + int upgradeItem = sAdultUpgradeItemBases[i] + CUR_UPG_VALUE(sAdultUpgrades[i]) - 1; + // Grey Out upgrades the wrong age, ie the Goron Bracelet as Adult, + // unless rando or the Toggle Strength Option still has a use for it // Grey Out Strength Upgrades when Disabled and the Toggle Strength Option is on - if ((drawGreyItems && - (((sAdultUpgradeItemBases[i] + CUR_UPG_VALUE(sAdultUpgrades[i]) - 1) == ITEM_BRACELET && - !(IS_RANDO) && !CVarGetInteger(CVAR_ENHANCEMENT("ToggleStrength"), 0)))) || + if ((!CHECK_AGE_REQ_ITEM(upgradeItem) && !(IS_RANDO) && + !CVarGetInteger(CVAR_ENHANCEMENT("ToggleStrength"), 0)) || (CVarGetInteger(CVAR_ENHANCEMENT("ToggleStrength"), 0) && CVarGetInteger(CVAR_ENHANCEMENT("StrengthDisabled"), 0) && sAdultUpgrades[i] == UPG_STRENGTH)) { gDPSetGrayscaleColor(POLY_OPA_DISP++, 109, 109, 109, 255); gSPGrayscale(POLY_OPA_DISP++, true); } - KaleidoScope_DrawQuadTextureRGBA32( - play->state.gfxCtx, gItemIcons[sAdultUpgradeItemBases[i] + CUR_UPG_VALUE(sAdultUpgrades[i]) - 1], - 32, 32, 0); + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[upgradeItem], 32, 32, 0); gSPGrayscale(POLY_OPA_DISP++, false); } } 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 0c98816784..073e10c54f 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 @@ -355,23 +355,6 @@ void KaleidoScope_HandleItemCycles(PlayState* play) { : INV_CONTENT(ITEM_TRADE_CHILD) + 1), true); - // the slot age requirement for the child trade slot has to be updated - // 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("AdultMasks"), 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, SLOT_TRADE_ADULT, IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE), diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h index 6c5fe7ba80..95493ab098 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h @@ -3,6 +3,7 @@ #include #include "global.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" extern u8 gAmmoItems[]; extern s16 D_8082AAEC[]; @@ -20,9 +21,23 @@ extern u8 gAreaGsFlags[]; #define AGE_REQ_CHILD LINK_AGE_CHILD #define AGE_REQ_NONE 9 -#define CHECK_AGE_REQ_EQUIP(i, j) (CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0) || (gEquipAgeReqs[i][j] == AGE_REQ_NONE) || (gEquipAgeReqs[i][j] == ((void)0, gSaveContext.linkAge))) -#define CHECK_AGE_REQ_SLOT(slotIndex) (CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0) || (gSlotAgeReqs[slotIndex] == AGE_REQ_NONE) || gSlotAgeReqs[slotIndex] == ((void)0, gSaveContext.linkAge)) -#define CHECK_AGE_REQ_ITEM(itemIndex) (CVarGetInteger(CVAR_CHEAT("TimelessEquipment"), 0) || (gItemAgeReqs[itemIndex] == AGE_REQ_NONE) || (gItemAgeReqs[itemIndex] == gSaveContext.linkAge)) +#define CHECK_AGE_REQ_EQUIP(i, j) \ + GameInteractor_Should(VB_PLAYER_MEETS_AGE_REQ, \ + (gEquipAgeReqs[i][j] == AGE_REQ_NONE) || \ + (gEquipAgeReqs[i][j] == ((void)0, gSaveContext.linkAge)), \ + gEquipAgeReqs[i][j]) + +#define CHECK_AGE_REQ_SLOT(slotIndex) \ + GameInteractor_Should(VB_SLOT_MEETS_AGE_REQ, \ + (gSlotAgeReqs[slotIndex] == AGE_REQ_NONE) || \ + (gSlotAgeReqs[slotIndex] == ((void)0, gSaveContext.linkAge)), \ + slotIndex) + +#define CHECK_AGE_REQ_ITEM(itemIndex) \ + GameInteractor_Should(VB_ITEM_MEETS_AGE_REQ, \ + (gItemAgeReqs[itemIndex] == AGE_REQ_NONE) || \ + (gItemAgeReqs[itemIndex] == gSaveContext.linkAge), \ + itemIndex) void KaleidoScope_DrawQuestStatus(PlayState* play, GraphicsContext* gfxCtx); s32 KaleidoScope_UpdateQuestStatusPoint(PauseContext* pauseCtx, s32 point);