summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOtherBlue <93625085+OtherBlue@users.noreply.github.com>2026-01-09 15:04:07 -0300
committerGitHub <noreply@github.com>2026-01-09 13:04:07 -0500
commit0ebb3c8274cb3285346d153e982dccdb9e5ff342 (patch)
treeeb98416db5f269c8d3ec11443d9c26621e4dd5f8
parentb06178e41709d57a97514f638722a87a08080952 (diff)
Unequip Items/Masks from C-Buttons (#1429)
* v0.1 * works on all items and all buttons * mask support * clang format my worst enemy * update keeping VB's alphabetical * addressing feedback improved code flow in general and undid unnecessary edit to dpad equips * claaang formaaat * fix GameInteractor_Should calls * Update GameInteractor_VanillaBehavior.h * allow unequipping magic arrows from bow item * cleanup
-rw-r--r--mm/2s2h/BenGui/BenMenu.cpp4
-rw-r--r--mm/2s2h/Enhancements/Equipment/ItemUnequip.cpp141
-rw-r--r--mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h17
-rw-r--r--mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c3
-rw-r--r--mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c5
-rw-r--r--mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c6
6 files changed, 176 insertions, 0 deletions
diff --git a/mm/2s2h/BenGui/BenMenu.cpp b/mm/2s2h/BenGui/BenMenu.cpp
index 5850badab..a73fea958 100644
--- a/mm/2s2h/BenGui/BenMenu.cpp
+++ b/mm/2s2h/BenGui/BenMenu.cpp
@@ -962,6 +962,10 @@ void BenMenu::AddEnhancements() {
AddWidget(path, "Dpad Equips", WIDGET_CVAR_CHECKBOX)
.CVar("gEnhancements.Dpad.DpadEquips")
.Options(CheckboxOptions().Tooltip("Allows you to equip items to your D-pad."));
+ AddWidget(path, "Unequip Items", WIDGET_CVAR_CHECKBOX)
+ .CVar("gEnhancements.Equipment.ItemUnequip")
+ .Options(CheckboxOptions().Tooltip("In the pause menu, press the same C-button or D-pad button an item is "
+ "equipped to in order to unequip it."));
AddWidget(path, "Fast Magic Arrow Equip Animation", WIDGET_CVAR_CHECKBOX)
.CVar("gEnhancements.Equipment.MagicArrowEquipSpeed")
.Options(CheckboxOptions().Tooltip("Removes the animation for equipping Magic Arrows."));
diff --git a/mm/2s2h/Enhancements/Equipment/ItemUnequip.cpp b/mm/2s2h/Enhancements/Equipment/ItemUnequip.cpp
new file mode 100644
index 000000000..1038c8ef2
--- /dev/null
+++ b/mm/2s2h/Enhancements/Equipment/ItemUnequip.cpp
@@ -0,0 +1,141 @@
+#include <libultraship/bridge.h>
+#include "2s2h/GameInteractor/GameInteractor.h"
+#include "2s2h/ShipInit.hpp"
+#include "2s2h_assets.h"
+
+extern "C" {
+#include "z64.h"
+#include "functions.h"
+#include "macros.h"
+#include "variables.h"
+#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h"
+}
+
+#define CVAR_DPAD_NAME "gEnhancements.Dpad.DpadEquips"
+#define CVAR_DPAD CVarGetInteger(CVAR_DPAD_NAME, 0)
+#define CVAR_NAME "gEnhancements.Equipment.ItemUnequip"
+#define CVAR CVarGetInteger(CVAR_NAME, 0)
+
+void RegisterDpadPageSwitchPrevention() {
+ COND_VB_SHOULD(VB_KALEIDO_SWITCH_PAGE_WITH_DPAD, CVAR_DPAD, {
+ u16 button = va_arg(args, int);
+ Input* input = &gPlayState->state.input[0];
+
+ if (CHECK_BTN_ALL(input->cur.button, button)) {
+ PauseContext* pauseCtx = &gPlayState->pauseCtx;
+
+ // Prevent page switching with D-pad when on item or mask page
+ if ((pauseCtx->pageIndex == PAUSE_ITEM || pauseCtx->pageIndex == PAUSE_MASK) &&
+ pauseCtx->mainState <= PAUSE_MAIN_STATE_IDLE_CURSOR_ON_SONG) {
+ *should = false;
+ }
+ }
+ });
+}
+
+void RegisterItemUnequip() {
+ COND_VB_SHOULD(VB_KALEIDO_EQUIP_ITEM_TO_BUTTON, CVAR, {
+ u16 cursorSlot = va_arg(args, int);
+ u16 cursorItem = va_arg(args, int);
+
+ PauseContext* pauseCtx = &gPlayState->pauseCtx;
+ s32 targetSlot = -1;
+ bool isDpad = false;
+
+ // Determine which button was pressed based on equipTargetCBtn
+ switch (pauseCtx->equipTargetCBtn) {
+ case PAUSE_EQUIP_C_LEFT:
+ targetSlot = EQUIP_SLOT_C_LEFT;
+ break;
+ case PAUSE_EQUIP_C_DOWN:
+ targetSlot = EQUIP_SLOT_C_DOWN;
+ break;
+ case PAUSE_EQUIP_C_RIGHT:
+ targetSlot = EQUIP_SLOT_C_RIGHT;
+ break;
+ case PAUSE_EQUIP_D_RIGHT:
+ targetSlot = EQUIP_SLOT_D_RIGHT;
+ isDpad = true;
+ break;
+ case PAUSE_EQUIP_D_LEFT:
+ targetSlot = EQUIP_SLOT_D_LEFT;
+ isDpad = true;
+ break;
+ case PAUSE_EQUIP_D_DOWN:
+ targetSlot = EQUIP_SLOT_D_DOWN;
+ isDpad = true;
+ break;
+ case PAUSE_EQUIP_D_UP:
+ targetSlot = EQUIP_SLOT_D_UP;
+ isDpad = true;
+ break;
+ default:
+ return;
+ }
+
+ u8 equippedItem;
+ u8 equippedSlot;
+ bool shouldUnequip = false;
+ bool isMask = cursorSlot >= ITEM_NUM_SLOTS;
+
+ // C-buttons vs D-pad
+ if (!isDpad) {
+ equippedItem = BUTTON_ITEM_EQUIP(0, targetSlot);
+ equippedSlot = C_SLOT_EQUIP(0, targetSlot);
+ } else {
+ equippedItem = DPAD_BUTTON_ITEM_EQUIP(0, targetSlot);
+ equippedSlot = DPAD_SLOT_EQUIP(0, targetSlot);
+ }
+
+ // Check if we should unequip
+ if (equippedItem == cursorItem) {
+ if (isMask) {
+ // For masks, check the slot matches (cursorSlot is already offset by ITEM_NUM_SLOTS)
+ if (equippedSlot == cursorSlot) {
+ shouldUnequip = true;
+ }
+ }
+ // For bottles, we need to check the slot too (since there are multiple bottle items)
+ else if (cursorItem >= ITEM_BOTTLE && cursorItem <= ITEM_OBABA_DRINK) {
+ if (equippedSlot == cursorSlot) {
+ shouldUnequip = true;
+ }
+ } else {
+ shouldUnequip = true;
+ }
+ }
+ // Handle magic arrows (bow variants)
+ else if (cursorItem == ITEM_ARROW_FIRE && equippedItem == ITEM_BOW_FIRE) {
+ shouldUnequip = true;
+ } else if (cursorItem == ITEM_ARROW_ICE && equippedItem == ITEM_BOW_ICE) {
+ shouldUnequip = true;
+ } else if (cursorItem == ITEM_ARROW_LIGHT && equippedItem == ITEM_BOW_LIGHT) {
+ shouldUnequip = true;
+ } else if (cursorItem == ITEM_BOW &&
+ (equippedItem == ITEM_BOW_FIRE || equippedItem == ITEM_BOW_ICE || equippedItem == ITEM_BOW_LIGHT)) {
+ shouldUnequip = true;
+ }
+
+ if (shouldUnequip) {
+ if (!isDpad) {
+ // C-buttons
+ BUTTON_ITEM_EQUIP(0, targetSlot) = ITEM_NONE;
+ C_SLOT_EQUIP(0, targetSlot) = SLOT_NONE;
+ Interface_LoadItemIconImpl(gPlayState, targetSlot);
+ } else {
+ // D-pad
+ DPAD_BUTTON_ITEM_EQUIP(0, targetSlot) = ITEM_NONE;
+ DPAD_SLOT_EQUIP(0, targetSlot) = SLOT_NONE;
+ // Manually clear D-pad icon
+ gPlayState->interfaceCtx.iconItemSegment[DPAD_BUTTON(targetSlot) + EQUIP_SLOT_MAX] =
+ (char*)gEmptyTexture;
+ }
+
+ Audio_PlaySfx(NA_SE_SY_DECIDE);
+ *should = false;
+ }
+ });
+}
+
+static RegisterShipInitFunc initFunc(RegisterItemUnequip, { CVAR_NAME });
+static RegisterShipInitFunc initDpadPageSwitch(RegisterDpadPageSwitchPrevention, { CVAR_DPAD_NAME }); \ No newline at end of file
diff --git a/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h b/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h
index c88c54d8c..3f3af18d9 100644
--- a/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h
+++ b/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h
@@ -1106,6 +1106,23 @@ typedef enum {
// true
// ```
// #### `args`
+ // - `u16` (cursor slot)
+ // - `u16` (cursor item)
+ VB_KALEIDO_EQUIP_ITEM_TO_BUTTON,
+
+ // #### `result`
+ // ```c
+ // true
+ // ```
+ // #### `args`
+ // - `u16` (button - BTN_DLEFT or BTN_DRIGHT)
+ VB_KALEIDO_SWITCH_PAGE_WITH_DPAD,
+
+ // #### `result`
+ // ```c
+ // true
+ // ```
+ // #### `args`
// - None
VB_KALEIDO_UNPAUSE_CLOSE,
diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c
index 3a80dfda8..e997224bf 100644
--- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c
+++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_item.c
@@ -733,6 +733,9 @@ void KaleidoScope_UpdateItemCursor(PlayState* play) {
}
}
// #endregion
+ if (!GameInteractor_Should(VB_KALEIDO_EQUIP_ITEM_TO_BUTTON, true, cursorSlot, cursorItem)) {
+ return;
+ }
// Equip item to the C buttons
pauseCtx->equipTargetItem = cursorItem;
diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c
index 757678732..56e285679 100644
--- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c
+++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_mask.c
@@ -661,6 +661,11 @@ void KaleidoScope_UpdateMaskCursor(PlayState* play) {
}
// #endregion
+ if (!GameInteractor_Should(VB_KALEIDO_EQUIP_ITEM_TO_BUTTON, true, cursorSlot + ITEM_NUM_SLOTS,
+ cursorItem)) {
+ return;
+ }
+
// Equip item to the C buttons
pauseCtx->equipTargetItem = cursorItem;
pauseCtx->equipTargetSlot = cursorSlot + ITEM_NUM_SLOTS;
diff --git a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c
index 4209fc257..e2581adfc 100644
--- a/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c
+++ b/mm/src/overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope_NES.c
@@ -545,6 +545,9 @@ void KaleidoScope_HandlePageToggles(PlayState* play, Input* input) {
}
if (CHECK_BTN_ALL(input->cur.button, BTN_DRIGHT) || CHECK_BTN_ALL(input->press.button, BTN_R)) {
+ if (!GameInteractor_Should(VB_KALEIDO_SWITCH_PAGE_WITH_DPAD, true, BTN_DRIGHT)) {
+ return;
+ }
// Switch the page to the right regardless of where the cursor is
if (interfaceCtx->aButtonDoActionDelayed == DO_ACTION_DECIDE) {
Interface_SetAButtonDoAction(play, DO_ACTION_INFO);
@@ -554,6 +557,9 @@ void KaleidoScope_HandlePageToggles(PlayState* play, Input* input) {
}
if (CHECK_BTN_ALL(input->cur.button, BTN_DLEFT) || CHECK_BTN_ALL(input->press.button, BTN_Z)) {
+ if (!GameInteractor_Should(VB_KALEIDO_SWITCH_PAGE_WITH_DPAD, true, BTN_DLEFT)) {
+ return;
+ }
// Switch the page to the left regardless of where the cursor is
if (interfaceCtx->aButtonDoActionDelayed == DO_ACTION_DECIDE) {
Interface_SetAButtonDoAction(play, DO_ACTION_INFO);