From 66750bb0ea512d2b371a31f15bd7d0fde7325512 Mon Sep 17 00:00:00 2001 From: djevangelia Date: Wed, 3 Jun 2026 14:24:21 +0200 Subject: [PATCH 1/2] z_player Dark Link states --- include/audio.h | 2 +- src/audio/game/general.c | 2 +- .../actors/ovl_En_Blkobj/z_en_blkobj.c | 2 +- .../actors/ovl_En_Torch2/z_en_torch2.c | 23 ++++++++++--------- .../actors/ovl_player_actor/z_player.c | 15 +++++++----- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/include/audio.h b/include/audio.h index 0b3e6fa55c1..4f8e5d9b5ff 100644 --- a/include/audio.h +++ b/include/audio.h @@ -1163,7 +1163,7 @@ void Audio_PlayCutsceneEffectsSequence(u8 csEffectType); void func_800F4010(Vec3f* pos, u16 sfxId, f32); void Audio_PlaySfxRandom(Vec3f* pos, u16 baseSfxId, u8 randLim); void func_800F4138(Vec3f* pos, u16 sfxId, f32); -void func_800F4190(Vec3f* pos, u16 sfxId); +void Audio_PlayDarkLinkVoiceSfx(Vec3f* pos, u16 sfxId); void func_800F436C(Vec3f* pos, u16 sfxId, f32 arg2); void func_800F4414(Vec3f* pos, u16 sfxId, f32); void func_800F44EC(s8 arg0, s8 arg1); diff --git a/src/audio/game/general.c b/src/audio/game/general.c index 2e58289d27b..1c5e479c18b 100644 --- a/src/audio/game/general.c +++ b/src/audio/game/general.c @@ -2817,7 +2817,7 @@ void func_800F4138(Vec3f* pos, u16 sfxId, f32 arg2) { Audio_PlaySfxGeneral(sfxId, pos, 4, &D_8016B7B0, &D_8016B7A8, &gSfxDefaultReverb); } -void func_800F4190(Vec3f* pos, u16 sfxId) { +void Audio_PlayDarkLinkVoiceSfx(Vec3f* pos, u16 sfxId) { Audio_PlaySfxGeneral(sfxId, pos, 4, &D_801305B0, &gSfxDefaultFreqAndVolScale, &D_801305B4); } void Audio_PlaySfxRandom(Vec3f* pos, u16 baseSfxId, u8 randLim) { diff --git a/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c b/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c index 813f16ce126..71326170711 100644 --- a/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c +++ b/src/overlays/actors/ovl_En_Blkobj/z_en_blkobj.c @@ -91,7 +91,7 @@ void EnBlkobj_Wait(EnBlkobj* this, PlayState* play) { if (this->dyna.actor.xzDistToPlayer < 120.0f) { EnBlkobj_SetupAction(this, EnBlkobj_SpawnDarkLink); } - player->stateFlags2 |= PLAYER_STATE2_26; + player->stateFlags2 |= PLAYER_STATE2_DARK_LINK_ROOM_REFLECTION; } void EnBlkobj_SpawnDarkLink(EnBlkobj* this, PlayState* play) { diff --git a/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c b/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c index 9d54250bcd5..80cbf9953f0 100644 --- a/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c +++ b/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c @@ -330,7 +330,7 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { } else if (sSwordJumpState != 0) { sStickTilt = 0.0f; - player->stateFlags3 |= PLAYER_STATE3_2; + player->stateFlags3 |= PLAYER_STATE3_DARK_LINK_IMMOBILIZED; Math_SmoothStepToF(&this->actor.world.pos.x, (Math_SinS(player->actor.shape.rot.y - 0x3E8) * 45.0f) + player->actor.world.pos.x, @@ -344,7 +344,7 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { ((player->invincibilityTimer > 0) && (this->meleeWeaponState == 0))) { this->actor.world.rot.y = this->actor.shape.rot.y = this->actor.yawTowardsPlayer; input->cur.button = BTN_A; - player->stateFlags3 &= ~PLAYER_STATE3_2; + player->stateFlags3 &= ~PLAYER_STATE3_DARK_LINK_IMMOBILIZED; sStickTilt = 127.0f; player->skelAnime.curFrame = 3.0f; sStickAngle = this->actor.yawTowardsPlayer + 0x8000; @@ -355,7 +355,7 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { EnTorch2_SwingSword(play, input, this); sSwordJumpState++; } else if (sSwordJumpTimer == 19) { - func_800F4190(&this->actor.projectedPos, NA_SE_VO_LI_AUTO_JUMP); + Audio_PlayDarkLinkVoiceSfx(&this->actor.projectedPos, NA_SE_VO_LI_AUTO_JUMP); } } } else { @@ -373,6 +373,7 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { // Handles the reaction to a one-handed stab. If the conditions are satisfied, // Dark Link jumps on Link's sword. Otherwise he backflips away. + //! @bug Dark Link can jump onto player's sword even when immobilized by Deku Nut if ((this->meleeWeaponState == 0) && (sCounterState == 0) && (player->invincibilityTimer == 0) && @@ -381,7 +382,7 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { sStickTilt = 0.0f; sSwordJumpState = 1; - player->stateFlags3 |= PLAYER_STATE3_2; + player->stateFlags3 |= PLAYER_STATE3_DARK_LINK_IMMOBILIZED; this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; sSwordJumpTimer = 27; player->meleeWeaponState = 0; @@ -507,7 +508,7 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { this->meleeWeaponState = 0; input->cur.stick_x = input->cur.stick_y = 0; if ((this->invincibilityTimer > 0) && (this->actor.world.pos.y < (this->actor.floorHeight - 160.0f))) { - this->stateFlags3 &= ~PLAYER_STATE3_0; + this->stateFlags3 &= ~PLAYER_STATE3_DARK_LINK_FALL; this->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED; this->invincibilityTimer = 0; this->actor.velocity.y = 0.0f; @@ -611,7 +612,7 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { sActionState = ENTORCH2_DEATH; Enemy_StartFinishingBlow(play, &this->actor); Item_DropCollectibleRandom(play, &this->actor, &thisx->world.pos, 0xC0); - this->stateFlags3 &= ~PLAYER_STATE3_2; + this->stateFlags3 &= ~PLAYER_STATE3_DARK_LINK_IMMOBILIZED; } else { func_800F5ACC(NA_BGM_MINI_BOSS); if (this->actor.colChkInfo.damageReaction == 1) { @@ -628,8 +629,8 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { this->knockbackSpeed = 8.0f; this->knockbackRot = this->actor.yawTowardsPlayer + 0x8000; Actor_SetDropFlag(&this->actor, &this->cylinder.elem, true); - this->stateFlags3 &= ~PLAYER_STATE3_2; - this->stateFlags3 |= PLAYER_STATE3_0; + this->stateFlags3 &= ~PLAYER_STATE3_DARK_LINK_IMMOBILIZED; + this->stateFlags3 |= PLAYER_STATE3_DARK_LINK_FALL; sActionState = ENTORCH2_DAMAGE; if (sAlpha == 255) { Actor_SetColorFilter(&this->actor, COLORFILTER_COLORFLAG_RED, 255, COLORFILTER_BUFFLAG_OPA, 12); @@ -645,9 +646,9 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { // Handles being frozen by a deku nut if ((this->actor.colorFilterTimer == 0) || (this->actor.colorFilterParams & 0x4000)) { - this->stateFlags3 &= ~PLAYER_STATE3_2; + this->stateFlags3 &= ~PLAYER_STATE3_DARK_LINK_IMMOBILIZED; } else { - this->stateFlags3 |= PLAYER_STATE3_2; + this->stateFlags3 |= PLAYER_STATE3_DARK_LINK_IMMOBILIZED; this->stateFlags1 &= ~PLAYER_STATE1_26; this->invincibilityTimer = 0; input->press.stick_x = input->press.stick_y = 0; @@ -682,7 +683,7 @@ void EnTorch2_Update(Actor* thisx, PlayState* play2) { } if (staggerThreshold < sStaggerCount) { this->skelAnime.playSpeed *= 0.6f; - func_800F4190(&this->actor.projectedPos, NA_SE_PL_DAMAGE); + Audio_PlayDarkLinkVoiceSfx(&this->actor.projectedPos, NA_SE_PL_DAMAGE); sStaggerTimer = 0; sStaggerCount = 0; } diff --git a/src/overlays/actors/ovl_player_actor/z_player.c b/src/overlays/actors/ovl_player_actor/z_player.c index f1242787066..bd0d890f7b4 100644 --- a/src/overlays/actors/ovl_player_actor/z_player.c +++ b/src/overlays/actors/ovl_player_actor/z_player.c @@ -1884,7 +1884,7 @@ void Player_PlayVoiceSfx(Player* this, u16 sfxId) { if (this->actor.category == ACTORCAT_PLAYER) { Player_PlaySfx(this, sfxId + this->ageProperties->unk_92); } else { - func_800F4190(&this->actor.projectedPos, sfxId); + Audio_PlayDarkLinkVoiceSfx(&this->actor.projectedPos, sfxId); } } @@ -11115,7 +11115,8 @@ void Player_ProcessSceneCollision(PlayState* play, Player* this) { UPDBGCHECKINFO_FLAG_4 | UPDBGCHECKINFO_FLAG_5; } - if (this->stateFlags3 & PLAYER_STATE3_0) { + // Remove ground and water collision checks for Dark Link when damaged + if (this->stateFlags3 & PLAYER_STATE3_DARK_LINK_FALL) { flags &= ~(UPDBGCHECKINFO_FLAG_1 | UPDBGCHECKINFO_FLAG_2); } @@ -11964,7 +11965,7 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { PLAYER_STATE1_SHIELDING); this->stateFlags2 &= ~(PLAYER_STATE2_0 | PLAYER_STATE2_2 | PLAYER_STATE2_3 | PLAYER_STATE2_5 | PLAYER_STATE2_6 | PLAYER_STATE2_8 | PLAYER_STATE2_FORCE_SAND_FLOOR_SOUND | PLAYER_STATE2_12 | - PLAYER_STATE2_14 | PLAYER_STATE2_DO_ACTION_ENTER | PLAYER_STATE2_22 | PLAYER_STATE2_26); + PLAYER_STATE2_14 | PLAYER_STATE2_DO_ACTION_ENTER | PLAYER_STATE2_22 | PLAYER_STATE2_DARK_LINK_ROOM_REFLECTION); this->stateFlags3 &= ~PLAYER_STATE3_4; func_80847298(this); @@ -11981,7 +11982,9 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { sUseHeldItem = sHeldItemButtonIsHeldDown = false; sSavedCurrentMask = this->currentMask; - if (!(this->stateFlags3 & PLAYER_STATE3_2)) { + // Player cannot do action functions if Dark Link is standing on player sword, + // and Dark Link cannot if paralyzed by Deku Nut + if (!(this->stateFlags3 & PLAYER_STATE3_DARK_LINK_IMMOBILIZED)) { this->actionFunc(this, play); } @@ -12076,7 +12079,7 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { this->actor.colChkInfo.mass = 50; } - this->stateFlags3 &= ~PLAYER_STATE3_2; + this->stateFlags3 &= ~PLAYER_STATE3_DARK_LINK_IMMOBILIZED; Collider_ResetCylinderAC(play, &this->cylinder.base); @@ -12292,7 +12295,7 @@ void Player_Draw(Actor* thisx, PlayState* play2) { } } - if (this->stateFlags2 & PLAYER_STATE2_26) { + if (this->stateFlags2 & PLAYER_STATE2_DARK_LINK_ROOM_REFLECTION) { f32 sp78 = BINANG_TO_RAD_ALT2((u16)(play->gameplayFrames * 600)); f32 sp74 = BINANG_TO_RAD_ALT2((u16)(play->gameplayFrames * 1000)); From 9b843e09ad9fb74f2425beef3c1daad32eaf7b8a Mon Sep 17 00:00:00 2001 From: djevangelia Date: Wed, 3 Jun 2026 14:25:43 +0200 Subject: [PATCH 2/2] z_player Dark Link states --- include/player.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/player.h b/include/player.h index 63c9d25b658..6de53a455aa 100644 --- a/include/player.h +++ b/include/player.h @@ -764,16 +764,16 @@ typedef struct WeaponInfo { #define PLAYER_STATE2_23 (1 << 23) #define PLAYER_STATE2_24 (1 << 24) #define PLAYER_STATE2_25 (1 << 25) -#define PLAYER_STATE2_26 (1 << 26) +#define PLAYER_STATE2_DARK_LINK_ROOM_REFLECTION (1 << 26) // Set by Dark Link's room as long as Dark Link is not spawned. Causes Link's reflection to be drawn in the water. #define PLAYER_STATE2_USING_OCARINA (1 << 27) // Playing the ocarina or warping out from an ocarina warp song #define PLAYER_STATE2_IDLE_FIDGET (1 << 28) // Playing a fidget idle animation (under typical circumstances, see `Player_ChooseNextIdleAnim` for more info) #define PLAYER_STATE2_29 (1 << 29) #define PLAYER_STATE2_30 (1 << 30) #define PLAYER_STATE2_31 (1 << 31) -#define PLAYER_STATE3_0 (1 << 0) +#define PLAYER_STATE3_DARK_LINK_FALL (1 << 0) // Set on Dark Link when damaged to remove collision detection and allow him to fall through the floor #define PLAYER_STATE3_1 (1 << 1) -#define PLAYER_STATE3_2 (1 << 2) +#define PLAYER_STATE3_DARK_LINK_IMMOBILIZED (1 << 2) // Set on Link when Dark Link has jumped onto his sword. Set on Dark Link when Link uses Deku Nut. Inhibits action functions. #define PLAYER_STATE3_3 (1 << 3) #define PLAYER_STATE3_4 (1 << 4) #define PLAYER_STATE3_5 (1 << 5)