summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Dubé <159546+serprex@users.noreply.github.com>2026-04-12 23:03:46 +0000
committerGitHub <noreply@github.com>2026-04-12 23:03:46 +0000
commit25eb09180d9f476cc9bcfaa65214ab2786f75d4c (patch)
treec1f575779cdc16e8dff22e13bc295ac5ecfcf912
parentd855742c2f676af4ae65853e810756cdc5439deb (diff)
Revise Arrow Cycling (#6490)
1. simplify UI, flashing buttons are unnecessary 2. change arrow without drawing a new arrow
-rw-r--r--soh/soh/Enhancements/ArrowCycle.cpp169
1 files changed, 44 insertions, 125 deletions
diff --git a/soh/soh/Enhancements/ArrowCycle.cpp b/soh/soh/Enhancements/ArrowCycle.cpp
index 45d8d3445..202f24c4e 100644
--- a/soh/soh/Enhancements/ArrowCycle.cpp
+++ b/soh/soh/Enhancements/ArrowCycle.cpp
@@ -8,8 +8,7 @@ extern "C" {
#include "overlays/actors/ovl_En_Arrow/z_en_arrow.h"
s32 func_808351D4(Player* thisx, PlayState* play); // Arrow nocked
-s32 func_808353D8(Player* thisx, PlayState* play); // Aiming in first person
-void Player_InitItemAction(PlayState* play, Player* thisx, PlayerItemAction itemAction);
+void EnArrow_Init(Actor* thisx, PlayState* play);
extern PlayState* gPlayState;
}
@@ -20,16 +19,6 @@ extern PlayState* gPlayState;
static const s16 sMagicArrowCosts[] = { 4, 4, 8 };
-#define MINIGAME_STATUS_ACTIVE 1
-
-static const s16 BUTTON_FLASH_DURATION = 3;
-static const s16 BUTTON_FLASH_COUNT = 3;
-static const s16 BUTTON_HIGHLIGHT_ALPHA = 128;
-
-static s16 sButtonFlashTimer = 0;
-static s16 sButtonFlashCount = 0;
-static s16 sJustCycledFrames = 0;
-
static const PlayerItemAction sArrowCycleOrder[] = {
PLAYER_IA_BOW,
PLAYER_IA_BOW_FIRE,
@@ -54,11 +43,11 @@ static bool HasArrowType(PlayerItemAction itemAction) {
case PLAYER_IA_BOW:
return true;
case PLAYER_IA_BOW_FIRE:
- return (INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_ARROW_FIRE);
+ return INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_ARROW_FIRE;
case PLAYER_IA_BOW_ICE:
- return (INV_CONTENT(ITEM_ARROW_ICE) == ITEM_ARROW_ICE);
+ return INV_CONTENT(ITEM_ARROW_ICE) == ITEM_ARROW_ICE;
case PLAYER_IA_BOW_LIGHT:
- return (INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT);
+ return INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT;
default:
return false;
}
@@ -77,15 +66,24 @@ static s32 GetBowItemForArrow(PlayerItemAction itemAction) {
}
}
+static ArrowType GetArrowTypeForArrow(s8 itemAction) {
+ switch (itemAction) {
+ case PLAYER_IA_BOW_FIRE:
+ return ARROW_FIRE;
+ case PLAYER_IA_BOW_ICE:
+ return ARROW_ICE;
+ case PLAYER_IA_BOW_LIGHT:
+ return ARROW_LIGHT;
+ default:
+ return ARROW_NORMAL;
+ }
+}
+
static bool CanCycleArrows() {
Player* player = GET_PLAYER(gPlayState);
- // don't allow cycling during minigames
- if (gSaveContext.minigameState == MINIGAME_STATUS_ACTIVE) {
- return false;
- }
-
- return !(player->stateFlags1 & PLAYER_STATE1_ON_HORSE) && player->rideActor == NULL &&
+ return LINK_IS_ADULT && !gSaveContext.minigameState && gPlayState->sceneNum != SCENE_SHOOTING_GALLERY &&
+ !(player->stateFlags1 & PLAYER_STATE1_ON_HORSE) && player->rideActor == NULL &&
INV_CONTENT(SLOT_BOW) == ITEM_BOW &&
(INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_ARROW_FIRE || INV_CONTENT(ITEM_ARROW_ICE) == ITEM_ARROW_ICE ||
INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_ARROW_LIGHT);
@@ -113,66 +111,6 @@ static s8 GetNextArrowType(s8 currentArrowType) {
static void UpdateButtonAlpha(s16 flashAlpha, bool isButtonBow, u16* buttonAlpha) {
if (isButtonBow) {
*buttonAlpha = flashAlpha;
- if (sButtonFlashTimer == 0) {
- *buttonAlpha = 255;
- }
- }
-}
-
-static void UpdateFlashEffect(PlayState* play) {
- if (sButtonFlashTimer <= 0) {
- return;
- }
-
- sButtonFlashTimer--;
- s16 flashAlpha = (sButtonFlashTimer % 3) ? BUTTON_HIGHLIGHT_ALPHA : 255;
-
- if (sButtonFlashTimer == 0 && sButtonFlashCount < BUTTON_FLASH_COUNT - 1) {
- sButtonFlashTimer = BUTTON_FLASH_DURATION;
- sButtonFlashCount++;
- }
- UpdateButtonAlpha(flashAlpha,
- (gSaveContext.equips.buttonItems[1] == ITEM_BOW) ||
- (gSaveContext.equips.buttonItems[1] >= ITEM_BOW_ARROW_FIRE &&
- gSaveContext.equips.buttonItems[1] <= ITEM_BOW_ARROW_LIGHT),
- &play->interfaceCtx.cLeftAlpha);
-
- UpdateButtonAlpha(flashAlpha,
- (gSaveContext.equips.buttonItems[2] == ITEM_BOW) ||
- (gSaveContext.equips.buttonItems[2] >= ITEM_BOW_ARROW_FIRE &&
- gSaveContext.equips.buttonItems[2] <= ITEM_BOW_ARROW_LIGHT),
- &play->interfaceCtx.cDownAlpha);
-
- UpdateButtonAlpha(flashAlpha,
- (gSaveContext.equips.buttonItems[3] == ITEM_BOW) ||
- (gSaveContext.equips.buttonItems[3] >= ITEM_BOW_ARROW_FIRE &&
- gSaveContext.equips.buttonItems[3] <= ITEM_BOW_ARROW_LIGHT),
- &play->interfaceCtx.cRightAlpha);
-
- if (CVarGetInteger(CVAR_ENHANCEMENT("DpadEquips"), 0)) {
- UpdateButtonAlpha(flashAlpha,
- (gSaveContext.equips.buttonItems[4] == ITEM_BOW) ||
- (gSaveContext.equips.buttonItems[4] >= ITEM_BOW_ARROW_FIRE &&
- gSaveContext.equips.buttonItems[4] <= ITEM_BOW_ARROW_LIGHT),
- &play->interfaceCtx.dpadRightAlpha);
-
- UpdateButtonAlpha(flashAlpha,
- (gSaveContext.equips.buttonItems[5] == ITEM_BOW) ||
- (gSaveContext.equips.buttonItems[5] >= ITEM_BOW_ARROW_FIRE &&
- gSaveContext.equips.buttonItems[5] <= ITEM_BOW_ARROW_LIGHT),
- &play->interfaceCtx.dpadLeftAlpha);
-
- UpdateButtonAlpha(flashAlpha,
- (gSaveContext.equips.buttonItems[6] == ITEM_BOW) ||
- (gSaveContext.equips.buttonItems[6] >= ITEM_BOW_ARROW_FIRE &&
- gSaveContext.equips.buttonItems[6] <= ITEM_BOW_ARROW_LIGHT),
- &play->interfaceCtx.dpadDownAlpha);
-
- UpdateButtonAlpha(flashAlpha,
- (gSaveContext.equips.buttonItems[7] == ITEM_BOW) ||
- (gSaveContext.equips.buttonItems[7] >= ITEM_BOW_ARROW_FIRE &&
- gSaveContext.equips.buttonItems[7] <= ITEM_BOW_ARROW_LIGHT),
- &play->interfaceCtx.dpadUpAlpha);
}
}
@@ -193,72 +131,53 @@ static void UpdateEquippedBow(PlayState* play, s8 arrowType) {
}
gSaveContext.buttonStatus[i] = BTN_ENABLED;
- sButtonFlashTimer = BUTTON_FLASH_DURATION;
- sButtonFlashCount = 0;
}
}
-
- UpdateFlashEffect(play);
}
-static void CycleToNextArrow(PlayState* play, Player* player) {
- s8 nextArrow = GetNextArrowType(player->heldItemAction);
-
- if (player->heldActor != NULL && player->heldActor->id == ACTOR_EN_ARROW) {
- EnArrow* arrow = (EnArrow*)player->heldActor;
-
- if (arrow->actor.child != NULL) {
- Actor_Kill(arrow->actor.child);
- }
-
- Actor_Kill(&arrow->actor);
- }
-
- Player_InitItemAction(play, player, (PlayerItemAction)nextArrow);
- UpdateEquippedBow(play, nextArrow);
- Audio_PlaySoundGeneral(NA_SE_PL_CHANGE_ARMS, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
- &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
- sJustCycledFrames = 2;
-}
-
-void ArrowCycleMain() {
+bool ArrowCycleMain() {
if (gPlayState == nullptr || !CanCycleArrows()) {
- return;
- }
-
- if (sJustCycledFrames > 0) {
- sJustCycledFrames--;
+ return false;
}
- UpdateFlashEffect(gPlayState);
-
Player* player = GET_PLAYER(gPlayState);
- Input* input = &gPlayState->state.input[0];
-
- if (IsAimingBow(player) && CHECK_BTN_ANY(input->press.button, BTN_R)) {
+ if (player->heldActor != NULL && player->heldActor->id == ACTOR_EN_ARROW) {
if (IsHoldingMagicBow(player) && gSaveContext.magicState != MAGIC_STATE_IDLE && player->heldActor == NULL) {
Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
- return;
+ return true;
}
// reset magic state to IDLE before cycling to prevent error sound
gSaveContext.magicState = MAGIC_STATE_IDLE;
- CycleToNextArrow(gPlayState, player);
+ s8 nextArrow = GetNextArrowType(player->heldItemAction);
+ player->heldItemAction = nextArrow;
+ player->itemAction = nextArrow;
+ Actor* arrow = player->heldActor;
+
+ if (arrow->child != NULL) {
+ Actor_Kill(arrow->child);
+ arrow->child = NULL;
+ }
+ arrow->params = GetArrowTypeForArrow(nextArrow);
+ EnArrow_Init(arrow, gPlayState);
+ UpdateEquippedBow(gPlayState, nextArrow);
+ return true;
}
+ return false;
}
void RegisterArrowCycle() {
- COND_ID_HOOK(OnActorUpdate, ACTOR_PLAYER, CVAR_ARROW_CYCLE_VALUE, [](void* actor) { ArrowCycleMain(); });
-
// suppress shield input when R is held while aiming to allow arrow cycling
COND_VB_SHOULD(VB_EXECUTE_PLAYER_ACTION_FUNC, CVAR_ARROW_CYCLE_VALUE, {
Player* player = (Player*)va_arg(args, void*);
Input* input = (Input*)va_arg(args, void*);
- if ((IsAimingBow(player) || sJustCycledFrames > 0) && CHECK_BTN_ANY(input->cur.button, BTN_R)) {
- input->cur.button &= ~BTN_R;
- input->press.button &= ~BTN_R;
+ if (IsAimingBow(player) && CHECK_BTN_ANY(input->press.button, BTN_R)) {
+ if (ArrowCycleMain()) {
+ input->cur.button &= ~BTN_R;
+ input->press.button &= ~BTN_R;
+ }
}
});
@@ -270,9 +189,9 @@ void RegisterArrowCycle() {
if (gSaveContext.magic < sMagicArrowCosts[magicArrowType]) {
*arrowType = ARROW_NORMAL;
+ } else {
+ *should = false;
}
-
- *should = false;
});
COND_VB_SHOULD(VB_EN_ARROW_MAGIC_CONSUMPTION, CVAR_ARROW_CYCLE_VALUE, {