"Assignable Tunic and Boots" setting now allows shields also (#5953)
This commit is contained in:
@@ -146,6 +146,9 @@ typedef enum {
|
||||
/* 0x1B */ SLOT_BOOTS_KOKIRI,
|
||||
/* 0x1C */ SLOT_BOOTS_IRON,
|
||||
/* 0x1D */ SLOT_BOOTS_HOVER,
|
||||
/* 0x1E */ SLOT_SHIELD_DEKU,
|
||||
/* 0x1F */ SLOT_SHIELD_HYLIAN,
|
||||
/* 0x20 */ SLOT_SHIELD_MIRROR,
|
||||
/* 0xFF */ SLOT_NONE = 0xFF
|
||||
} InventorySlot;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ 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) {
|
||||
static 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) ||
|
||||
@@ -30,7 +30,7 @@ void UseTunicBoots(Player* player, PlayState* play, Input* input) {
|
||||
}
|
||||
}
|
||||
|
||||
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
|
||||
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
|
||||
if (item >= ITEM_BOOTS_KOKIRI) {
|
||||
u16 bootsValue = item - ITEM_BOOTS_KOKIRI + 1;
|
||||
if (CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) == bootsValue) {
|
||||
@@ -41,7 +41,7 @@ void UseTunicBoots(Player* player, PlayState* play, Input* input) {
|
||||
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 {
|
||||
} else if (item >= ITEM_TUNIC_KOKIRI) {
|
||||
u16 tunicValue = item - ITEM_TUNIC_KOKIRI + 1;
|
||||
if (CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC) == tunicValue) {
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_TUNIC, EQUIP_VALUE_TUNIC_KOKIRI);
|
||||
@@ -50,45 +50,93 @@ void UseTunicBoots(Player* player, PlayState* play, Input* input) {
|
||||
}
|
||||
Player_SetEquipmentData(play, player);
|
||||
func_808328EC(player, NA_SE_PL_CHANGE_ARMS);
|
||||
} else {
|
||||
u16 shieldValue = item - ITEM_SHIELD_DEKU + 1;
|
||||
if (CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) != shieldValue) {
|
||||
Inventory_ChangeEquipment(EQUIP_TYPE_SHIELD, shieldValue);
|
||||
Player_SetEquipmentData(play, player);
|
||||
func_808328EC(player, NA_SE_PL_CHANGE_ARMS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClearAssignedTunicsBoots(int32_t unused = 0) {
|
||||
static 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) {
|
||||
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
|
||||
gSaveContext.equips.buttonItems[buttonIndex] = ITEM_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ClearDeletedAssignedEquipment(int16_t equipmentType, uint16_t equipValue) {
|
||||
ItemID itemToRemove = ITEM_NONE;
|
||||
|
||||
if (equipmentType == EQUIP_TYPE_TUNIC) {
|
||||
switch (equipValue) {
|
||||
case EQUIP_VALUE_TUNIC_KOKIRI:
|
||||
break;
|
||||
case EQUIP_VALUE_TUNIC_GORON:
|
||||
itemToRemove = ITEM_TUNIC_GORON;
|
||||
break;
|
||||
case EQUIP_VALUE_TUNIC_ZORA:
|
||||
itemToRemove = ITEM_TUNIC_ZORA;
|
||||
break;
|
||||
}
|
||||
} else if (equipmentType == EQUIP_TYPE_SHIELD) {
|
||||
switch (equipValue) {
|
||||
case EQUIP_VALUE_SHIELD_DEKU:
|
||||
itemToRemove = ITEM_SHIELD_DEKU;
|
||||
break;
|
||||
case EQUIP_VALUE_SHIELD_HYLIAN:
|
||||
itemToRemove = ITEM_SHIELD_HYLIAN;
|
||||
break;
|
||||
case EQUIP_VALUE_SHIELD_MIRROR:
|
||||
itemToRemove = ITEM_SHIELD_MIRROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (itemToRemove == ITEM_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||
if (gSaveContext.equips.buttonItems[i] == itemToRemove) {
|
||||
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
|
||||
gSaveContext.equips.cButtonSlots[i - 1] = SLOT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define CVAR_TUNICBOOTS_NAME CVAR_ENHANCEMENT("AssignableTunicsAndBoots")
|
||||
#define CVAR_TUNICBOOTS_DEFAULT 0
|
||||
#define CVAR_TUNICBOOTS_VALUE CVarGetInteger(CVAR_TUNICBOOTS_NAME, CVAR_TUNICBOOTS_DEFAULT)
|
||||
#define CVAR_TUNICBOOTS_SET (CVAR_TUNICBOOTS_VALUE != 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, {
|
||||
static void RegisterAssignableTunicsBoots() {
|
||||
// make sure we don't change our held/equipped item when changing shield/tunic/boots
|
||||
COND_VB_SHOULD(VB_CHANGE_HELD_ITEM_AND_USE_ITEM, CVAR_TUNICBOOTS_SET, {
|
||||
int32_t item = va_arg(args, int32_t);
|
||||
|
||||
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
|
||||
if (item >= ITEM_SHIELD_DEKU && 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, {
|
||||
COND_VB_SHOULD(VB_ITEM_ACTION_BE_NONE, CVAR_TUNICBOOTS_SET, {
|
||||
int32_t item = va_arg(args, int32_t);
|
||||
|
||||
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
|
||||
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
|
||||
*should = true;
|
||||
}
|
||||
});
|
||||
|
||||
// don't throw items when the pressed button is a tunic or boots
|
||||
COND_VB_SHOULD(VB_THROW_OR_PUT_DOWN_HELD_ITEM, CVAR_TUNICBOOTS_VALUE != CVAR_TUNICBOOTS_DEFAULT, {
|
||||
// don't throw items when the pressed button is a shield, tunic or boots
|
||||
COND_VB_SHOULD(VB_THROW_OR_PUT_DOWN_HELD_ITEM, CVAR_TUNICBOOTS_SET, {
|
||||
// if the vanilla condition doesn't want us to throw/put down the item, early return
|
||||
if (!*should) {
|
||||
return;
|
||||
@@ -104,13 +152,13 @@ void RegisterAssignableTunicsBoots() {
|
||||
}
|
||||
}
|
||||
|
||||
if (item >= ITEM_TUNIC_KOKIRI && item <= ITEM_BOOTS_HOVER) {
|
||||
if (item >= ITEM_SHIELD_DEKU && item <= ITEM_BOOTS_HOVER) {
|
||||
*should = false;
|
||||
}
|
||||
});
|
||||
|
||||
// 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, {
|
||||
COND_VB_SHOULD(VB_EXECUTE_PLAYER_ACTION_FUNC, CVAR_TUNICBOOTS_SET, {
|
||||
// if the vanilla condition doesn't want us to run the actionFunc, don't do any of this
|
||||
if (!*should) {
|
||||
return;
|
||||
@@ -133,13 +181,16 @@ void RegisterAssignableTunicsBoots() {
|
||||
UseTunicBoots(player, gPlayState, input);
|
||||
});
|
||||
|
||||
// remove assigned equipment when it gets deleted
|
||||
COND_HOOK(OnEquipmentDelete, CVAR_TUNICBOOTS_SET, ClearDeletedAssignedEquipment);
|
||||
|
||||
// clear out assigned tunics/boots when the enhancement is toggled off
|
||||
if (GameInteractor::IsSaveLoaded(true) && CVAR_TUNICBOOTS_VALUE == CVAR_TUNICBOOTS_DEFAULT) {
|
||||
if (GameInteractor::IsSaveLoaded(true) && !CVAR_TUNICBOOTS_SET) {
|
||||
ClearAssignedTunicsBoots();
|
||||
}
|
||||
|
||||
// clear out assigned tunics/boots when loading a save with enhancement turned off
|
||||
COND_HOOK(OnLoadGame, CVAR_TUNICBOOTS_VALUE == CVAR_TUNICBOOTS_DEFAULT, ClearAssignedTunicsBoots);
|
||||
COND_HOOK(OnLoadGame, !CVAR_TUNICBOOTS_SET, ClearAssignedTunicsBoots);
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(RegisterAssignableTunicsBoots, { CVAR_TUNICBOOTS_NAME });
|
||||
|
||||
@@ -12,6 +12,7 @@ DEFINE_HOOK(OnExitGame, (int32_t fileNum));
|
||||
DEFINE_HOOK(OnGameStateMainStart, ());
|
||||
DEFINE_HOOK(OnGameFrameUpdate, ());
|
||||
DEFINE_HOOK(OnItemReceive, (GetItemEntry itemEntry));
|
||||
DEFINE_HOOK(OnEquipmentDelete, (int16_t equipmentType, uint16_t equipValue));
|
||||
DEFINE_HOOK(OnSaleEnd, (GetItemEntry itemEntry));
|
||||
DEFINE_HOOK(OnTransitionEnd, (int16_t sceneNum));
|
||||
DEFINE_HOOK(OnSceneInit, (int16_t sceneNum));
|
||||
|
||||
@@ -34,6 +34,11 @@ void GameInteractor_ExecuteOnItemReceiveHooks(GetItemEntry itemEntry) {
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnItemReceive>(itemEntry);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnEquipmentDelete(int16_t equipmentType, uint16_t equipValue) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnEquipmentDelete>(equipmentType, equipValue);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnEquipmentDelete>(equipmentType, equipValue);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSaleEnd>(itemEntry);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnSaleEnd>(itemEntry);
|
||||
|
||||
@@ -15,6 +15,7 @@ void GameInteractor_ExecuteOnExitGame(int32_t fileNum);
|
||||
void GameInteractor_ExecuteOnGameStateMainStart();
|
||||
void GameInteractor_ExecuteOnGameFrameUpdate();
|
||||
void GameInteractor_ExecuteOnItemReceiveHooks(GetItemEntry itemEntry);
|
||||
void GameInteractor_ExecuteOnEquipmentDelete(int16_t equipmentType, uint16_t equipValue);
|
||||
void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry);
|
||||
void GameInteractor_ExecuteOnTransitionEndHooks(int16_t sceneNum);
|
||||
void GameInteractor_ExecuteOnSceneInit(int16_t sceneNum);
|
||||
|
||||
@@ -732,9 +732,9 @@ void SohMenu::AddMenuEnhancements() {
|
||||
.Options(CheckboxOptions().Tooltip(
|
||||
"Equip items and equipment on the D-pad. If used with \"D-pad on Pause Screen\", you must "
|
||||
"hold C-Up to equip instead of navigate."));
|
||||
AddWidget(path, "Assignable Tunics and Boots", WIDGET_CVAR_CHECKBOX)
|
||||
AddWidget(path, "Assignable Shields, Tunics and Boots", WIDGET_CVAR_CHECKBOX)
|
||||
.CVar(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"))
|
||||
.Options(CheckboxOptions().Tooltip("Allows equipping the Tunics and Boots to C-Buttons/D-pad."));
|
||||
.Options(CheckboxOptions().Tooltip("Allows equipping Shields, Tunics and Boots to C-Buttons/D-pad."));
|
||||
// TODO: Revist strength toggle, it's currently separate but should probably be locked behind the
|
||||
// Equipment toggle settings or be absorbed by it completely.
|
||||
AddWidget(path, "Equipment Toggle", WIDGET_CVAR_CHECKBOX)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "global.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "textures/icon_item_static/icon_item_static.h"
|
||||
#include "textures/icon_item_24_static/icon_item_24_static.h"
|
||||
#include "textures/parameter_static/parameter_static.h"
|
||||
@@ -204,20 +205,10 @@ u8 Inventory_DeleteEquipment(PlayState* play, s16 equipment) {
|
||||
|
||||
if (equipment == EQUIP_TYPE_TUNIC) {
|
||||
gSaveContext.equips.equipment |= EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4);
|
||||
// non-vanilla: remove goron and zora tunics from item buttons if assignable tunics is on
|
||||
if (CVarGetInteger(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"), 0) &&
|
||||
equipValue != EQUIP_VALUE_TUNIC_KOKIRI) {
|
||||
ItemID item = (equipValue == EQUIP_VALUE_TUNIC_GORON ? ITEM_TUNIC_GORON : ITEM_TUNIC_ZORA);
|
||||
for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
|
||||
if (gSaveContext.equips.buttonItems[i] == item) {
|
||||
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
|
||||
gSaveContext.equips.cButtonSlots[i - 1] = SLOT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// end non-vanilla
|
||||
}
|
||||
|
||||
GameInteractor_ExecuteOnEquipmentDelete(equipment, equipValue);
|
||||
|
||||
if (equipment == EQUIP_TYPE_SWORD) {
|
||||
gSaveContext.equips.buttonItems[0] = ITEM_NONE;
|
||||
gSaveContext.infTable[29] = 1;
|
||||
|
||||
@@ -642,8 +642,8 @@ void KaleidoScope_DrawEquipment(PlayState* play) {
|
||||
pauseCtx->unk_1E4 = 7;
|
||||
sEquipTimer = 10;
|
||||
} else if (CVarGetInteger(CVAR_ENHANCEMENT("AssignableTunicsAndBoots"), 0) != 0) {
|
||||
// Only allow assigning tunic and boots to c-buttons
|
||||
if (pauseCtx->cursorY[PAUSE_EQUIP] > 1) {
|
||||
// Only allow assigning shield, tunic and boots to c-buttons
|
||||
if (pauseCtx->cursorY[PAUSE_EQUIP] > 0) {
|
||||
if (CHECK_OWNED_EQUIP(pauseCtx->cursorY[PAUSE_EQUIP], pauseCtx->cursorX[PAUSE_EQUIP] - 1)) {
|
||||
u16 slot = 0;
|
||||
switch (cursorItem) {
|
||||
@@ -665,6 +665,15 @@ void KaleidoScope_DrawEquipment(PlayState* play) {
|
||||
case ITEM_BOOTS_HOVER:
|
||||
slot = SLOT_BOOTS_HOVER;
|
||||
break;
|
||||
case ITEM_SHIELD_DEKU:
|
||||
slot = SLOT_SHIELD_DEKU;
|
||||
break;
|
||||
case ITEM_SHIELD_HYLIAN:
|
||||
slot = SLOT_SHIELD_HYLIAN;
|
||||
break;
|
||||
case ITEM_SHIELD_MIRROR:
|
||||
slot = SLOT_SHIELD_MIRROR;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user