From 11e07a8f9d82ff10f5654b1d7b2125870e957040 Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Tue, 4 Feb 2025 01:44:02 -0800 Subject: [PATCH] rework assignable tunic/boots to use shipinit and hooks (#4978) * don't put away items when equipping tunics/boots * vb * don't need that return * ok i guess i'm going down the rabbit hole * more rabbit hole * shipinit and more hooks * clean up * use fewer params, add a missing condition * make the loops make sense --- .../Enhancements/AssignableTunicsAndBoots.cpp | 114 ++++++++++++++++++ .../game-interactor/GameInteractor.h | 5 + .../actors/ovl_player_actor/z_player.c | 50 +------- 3 files changed, 122 insertions(+), 47 deletions(-) create mode 100644 soh/soh/Enhancements/AssignableTunicsAndBoots.cpp diff --git a/soh/soh/Enhancements/AssignableTunicsAndBoots.cpp b/soh/soh/Enhancements/AssignableTunicsAndBoots.cpp new file mode 100644 index 000000000..a7e210b95 --- /dev/null +++ b/soh/soh/Enhancements/AssignableTunicsAndBoots.cpp @@ -0,0 +1,114 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" + +extern "C" { +#include "macros.h" +#include "variables.h" + +extern s32 Player_GetItemOnButton(PlayState*, s32); +extern void Inventory_ChangeEquipment(s16, u16); +extern void Player_SetEquipmentData(PlayState*, Player*); +extern void func_808328EC(Player*, u16); +extern PlayState* gPlayState; +} + +static u16 sItemButtons[] = { BTN_B, BTN_CLEFT, BTN_CDOWN, BTN_CRIGHT, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT }; + +void UseTunicBoots(Player* player, PlayState* play, Input* input) { + // Boots and tunics equip despite state + if ( + player->stateFlags1 & (PLAYER_STATE1_INPUT_DISABLED | PLAYER_STATE1_IN_ITEM_CS | PLAYER_STATE1_IN_CUTSCENE | PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD) || + player->stateFlags2 & PLAYER_STATE2_OCARINA_PLAYING + ) { + return; + } + + s32 item = ITEM_NONE; + for (s32 i = 0; i < ARRAY_COUNT(sItemButtons); i++) { + if (CHECK_BTN_ALL(input->press.button, sItemButtons[i])) { + item = Player_GetItemOnButton(play, i); + break; + } + } + + if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) { + if (item >= ITEM_BOOTS_KOKIRI) { + u16 bootsValue = item - ITEM_BOOTS_KOKIRI + 1; + if (CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) == bootsValue) { + Inventory_ChangeEquipment(EQUIP_TYPE_BOOTS, EQUIP_VALUE_BOOTS_KOKIRI); + } else { + Inventory_ChangeEquipment(EQUIP_TYPE_BOOTS, bootsValue); + } + Player_SetEquipmentData(play, player); + func_808328EC(player, CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) == EQUIP_VALUE_BOOTS_IRON ? NA_SE_PL_WALK_HEAVYBOOTS : NA_SE_PL_CHANGE_ARMS); + } else { + u16 tunicValue = item - ITEM_TUNIC_KOKIRI + 1; + if (CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC) == tunicValue) { + Inventory_ChangeEquipment(EQUIP_TYPE_TUNIC, EQUIP_VALUE_TUNIC_KOKIRI); + } else { + Inventory_ChangeEquipment(EQUIP_TYPE_TUNIC, tunicValue); + } + Player_SetEquipmentData(play, player); + func_808328EC(player, NA_SE_PL_CHANGE_ARMS); + } + } +} + +void ClearAssignedTunicsBoots(int32_t unused = 0) { + for (int32_t buttonIndex = 0; buttonIndex < 8; buttonIndex++) { + int32_t item = gSaveContext.equips.buttonItems[buttonIndex]; + + if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) { + gSaveContext.equips.buttonItems[buttonIndex] = ITEM_NONE; + } + } +} + +#define CVAR_TUNICBOOTS_NAME CVAR_ENHANCEMENT("AssignableTunicsAndBoots") +#define CVAR_TUNICBOOTS_DEFAULT 0 +#define CVAR_TUNICBOOTS_VALUE CVarGetInteger(CVAR_TUNICBOOTS_NAME, CVAR_TUNICBOOTS_DEFAULT) + +void RegisterAssignableTunicsBoots() { + // make sure we don't change our held/equipped item when changing tunics/boots + COND_VB_SHOULD(VB_CHANGE_HELD_ITEM_AND_USE_ITEM, CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT, { + int32_t item = va_arg(args, int32_t); + + if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) { + *should = false; + } + }); + + // make sure we don't crash because tunics/boots don't have assoicated item actions + COND_VB_SHOULD(VB_ITEM_ACTION_BE_NONE, CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT, { + int32_t item = va_arg(args, int32_t); + + if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) { + *should = true; + } + }); + + // do something when the player presses a button to use the tunics/boots + COND_VB_SHOULD(VB_EXECUTE_PLAYER_ACTION_FUNC, CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT, { + // if the vanilla condition doesn't want us to run the actionFunc, don't do any of this + if (!*should) { + return; + } + + Input* input = va_arg(args, Input*); + Player* player = GET_PLAYER(gPlayState); + + *should = false; + player->actionFunc(player, gPlayState); + UseTunicBoots(player, gPlayState, input); + }); + + // clear out assigned tunics/boots when the enhancement is toggled off + if (GameInteractor::IsSaveLoaded(true) && CVAR_TUNICBOOTS_VALUE == CVAR_TUNICBOOTS_DEFAULT) { + ClearAssignedTunicsBoots(); + } + + // clear out assigned tunics/boots when loading a save with enhancement turned off + COND_HOOK(OnLoadGame, CVAR_TUNICBOOTS_VALUE == CVAR_TUNICBOOTS_DEFAULT, ClearAssignedTunicsBoots); +} + +static RegisterShipInitFunc initFunc(RegisterAssignableTunicsBoots, { CVAR_TUNICBOOTS_NAME }); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 936a4be99..889ba7f1c 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -532,6 +532,11 @@ typedef enum { VB_SPAWN_SONG_FAIRY, // Opt: *EnGs VB_SPAWN_GOSSIP_STONE_FAIRY, + + /*** Equippable tunics and boots ***/ + VB_CHANGE_HELD_ITEM_AND_USE_ITEM, + VB_ITEM_ACTION_BE_NONE, + VB_EXECUTE_PLAYER_ACTION_FUNC, } GIVanillaBehavior; #ifdef __cplusplus 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 34bee2f6f..77b4a7e27 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2244,16 +2244,12 @@ void Player_InitItemActionWithAnim(PlayState* play, Player* this, s8 itemAction) } s8 Player_ItemToItemAction(s32 item) { - if (item >= ITEM_NONE_FE) { + if (GameInteractor_Should(VB_ITEM_ACTION_BE_NONE, item >= ITEM_NONE_FE, item)) { return PLAYER_IA_NONE; } else if (item == ITEM_LAST_USED) { return PLAYER_IA_SWORD_CS; } else if (item == ITEM_FISHING_POLE) { return PLAYER_IA_FISHING_POLE; - // #region SOH [Enhancement] Added to prevent crashes with assignable equipment - } else if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) { - return PLAYER_IA_NONE; - // #endregion } else { return sItemActions[item]; } @@ -2572,7 +2568,7 @@ void Player_ProcessItemButtons(Player* this, PlayState* play) { if ((item < ITEM_NONE_FE) && (Player_ItemToItemAction(item) == this->heldItemAction)) { sHeldItemButtonIsHeldDown = true; } - } else { + } else if (GameInteractor_Should(VB_CHANGE_HELD_ITEM_AND_USE_ITEM, true, item)) { this->heldItemButton = i; Player_UseItem(play, this, item); } @@ -11883,45 +11879,6 @@ static Vec3f D_80854814 = { 0.0f, 0.0f, 200.0f }; static f32 sWaterConveyorSpeeds[] = { 2.0f, 4.0f, 7.0f }; static f32 sFloorConveyorSpeeds[] = { 0.5f, 1.0f, 3.0f }; -void Player_UseTunicBoots(Player* this, PlayState* play) { - // Boots and tunics equip despite state - if ( - this->stateFlags1 & (PLAYER_STATE1_INPUT_DISABLED | PLAYER_STATE1_IN_ITEM_CS | PLAYER_STATE1_IN_CUTSCENE | PLAYER_STATE1_TALKING | PLAYER_STATE1_DEAD) || - this->stateFlags2 & PLAYER_STATE2_OCARINA_PLAYING - ) { - return; - } - - s32 i; - for (i = 0; i < ARRAY_COUNT(sItemButtons); i++) { - if (CHECK_BTN_ALL(sControlInput->press.button, sItemButtons[i])) { - break; - } - } - s32 item = Player_GetItemOnButton(play, i); - if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) { - if (item >= ITEM_BOOTS_KOKIRI) { - u16 bootsValue = item - ITEM_BOOTS_KOKIRI + 1; - if (CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) == bootsValue) { - Inventory_ChangeEquipment(EQUIP_TYPE_BOOTS, EQUIP_VALUE_BOOTS_KOKIRI); - } else { - Inventory_ChangeEquipment(EQUIP_TYPE_BOOTS, bootsValue); - } - Player_SetEquipmentData(play, this); - func_808328EC(this, CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) == EQUIP_VALUE_BOOTS_IRON ? NA_SE_PL_WALK_HEAVYBOOTS : NA_SE_PL_CHANGE_ARMS); - } else { - u16 tunicValue = item - ITEM_TUNIC_KOKIRI + 1; - if (CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC) == tunicValue) { - Inventory_ChangeEquipment(EQUIP_TYPE_TUNIC, EQUIP_VALUE_TUNIC_KOKIRI); - } else { - Inventory_ChangeEquipment(EQUIP_TYPE_TUNIC, tunicValue); - } - Player_SetEquipmentData(play, this); - func_808328EC(this, NA_SE_PL_CHANGE_ARMS); - } - } -} - void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { s32 pad; @@ -12218,9 +12175,8 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { sUseHeldItem = sHeldItemButtonIsHeldDown = 0; sSavedCurrentMask = this->currentMask; - if (!(this->stateFlags3 & PLAYER_STATE3_PAUSE_ACTION_FUNC)) { + if (GameInteractor_Should(VB_EXECUTE_PLAYER_ACTION_FUNC, !(this->stateFlags3 & PLAYER_STATE3_PAUSE_ACTION_FUNC), input)) { this->actionFunc(this, play); - Player_UseTunicBoots(this, play); } Player_UpdateCamAndSeqModes(play, this);