From 44382575b815073f94a042071bde165608e9c2b8 Mon Sep 17 00:00:00 2001 From: djevangelia Date: Fri, 17 Jul 2026 18:52:16 +0200 Subject: [PATCH] Player_Action_Climbing and related functions/names --- include/bgcheck.h | 10 +- include/player.h | 9 +- src/code/z_actor.c | 6 +- src/code/z_bgcheck.c | 14 +- src/code/z_camera.c | 10 +- src/code/z_parameter.c | 4 +- src/code/z_player_lib.c | 4 +- .../z_bg_jya_zurerukabe.c | 2 +- src/overlays/actors/ovl_En_Rd/z_en_rd.c | 4 +- src/overlays/actors/ovl_En_Ru1/z_en_ru1.c | 2 +- src/overlays/actors/ovl_En_Sw/z_en_sw.c | 2 +- .../actors/ovl_player_actor/z_player.c | 228 ++++++++++-------- 12 files changed, 163 insertions(+), 132 deletions(-) diff --git a/include/bgcheck.h b/include/bgcheck.h index 13b85705822..98745f82691 100644 --- a/include/bgcheck.h +++ b/include/bgcheck.h @@ -144,9 +144,9 @@ typedef enum WallType { } WallType; #define WALL_FLAG_0 (1 << 0) -#define WALL_FLAG_1 (1 << 1) -#define WALL_FLAG_2 (1 << 2) -#define WALL_FLAG_3 (1 << 3) +#define WALL_FLAG_LADDER (1 << 1) +#define WALL_FLAG_LADDER_TOP (1 << 2) +#define WALL_FLAG_CLIMBABLE (1 << 3) #define WALL_FLAG_CRAWLSPACE_1 (1 << 4) #define WALL_FLAG_CRAWLSPACE_2 (1 << 5) #define WALL_FLAG_6 (1 << 6) @@ -441,8 +441,8 @@ u32 SurfaceType_GetFloorType(CollisionContext* colCtx, CollisionPoly* poly, s32 u32 func_80041D70(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); s32 SurfaceType_GetWallFlags(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); s32 SurfaceType_CheckWallFlag0(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); -s32 SurfaceType_CheckWallFlag1(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); -s32 SurfaceType_CheckWallFlag2(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); +s32 SurfaceType_CheckWallFlagLadder(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); +s32 SurfaceType_CheckWallFlagLadderTop(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); u32 SurfaceType_GetFloorProperty(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); u32 SurfaceType_IsSoft(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); u32 SurfaceType_IsHorseBlocked(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId); diff --git a/include/player.h b/include/player.h index 63c9d25b658..3e4f434f2b9 100644 --- a/include/player.h +++ b/include/player.h @@ -689,7 +689,7 @@ typedef struct PlayerAgeProperties { /* 0xA4 */ LinkAnimationHeader* unk_A4; /* 0xA8 */ LinkAnimationHeader* unk_A8; /* 0xAC */ LinkAnimationHeader* unk_AC[4]; - /* 0xBC */ LinkAnimationHeader* unk_BC[2]; + /* 0xBC */ LinkAnimationHeader* sideClimbAnim[2]; // Climbing walls sideways /* 0xC4 */ LinkAnimationHeader* unk_C4[2]; /* 0xCC */ LinkAnimationHeader* unk_CC[2]; } PlayerAgeProperties; // size = 0xD4 @@ -726,7 +726,7 @@ typedef struct WeaponInfo { #define PLAYER_STATE1_18 (1 << 18) #define PLAYER_STATE1_19 (1 << 19) #define PLAYER_STATE1_20 (1 << 20) -#define PLAYER_STATE1_21 (1 << 21) +#define PLAYER_STATE1_CLIMBING (1 << 21) // Player is on a climbable wall/ladder #define PLAYER_STATE1_SHIELDING (1 << 22) // Shielding in any form (regular, hylian shield as child, "shielding" with a two handed sword, etc.) #define PLAYER_STATE1_23 (1 << 23) #define PLAYER_STATE1_USING_BOOMERANG (1 << 24) // Currently using the boomerang. This includes all phases (aiming, throwing, and catching). @@ -750,7 +750,7 @@ typedef struct WeaponInfo { #define PLAYER_STATE2_FORCE_SAND_FLOOR_SOUND (1 << 9) // Forces sand footstep sounds regardless of current floor type #define PLAYER_STATE2_10 (1 << 10) #define PLAYER_STATE2_11 (1 << 11) -#define PLAYER_STATE2_12 (1 << 12) +#define PLAYER_STATE2_CLIMB_STILL (1 << 12) // Climbing but currently not moving #define PLAYER_STATE2_LOCK_ON_WITH_SWITCH (1 << 13) // Actor lock-on is active, specifically with Switch Targeting. Hold Targeting checks the state of the Z button instead of this flag. #define PLAYER_STATE2_14 (1 << 14) #define PLAYER_STATE2_15 (1 << 15) @@ -917,6 +917,7 @@ typedef struct Player { s8 facingUpSlope; // Player_Action_SlideOnSlope: Facing uphill when sliding on a slope s8 isLakeHyliaCs; // Player_Action_BlueWarpArrive: In Lake Hylia CS after Water Temple. Floating down is delayed until a specific point in the cutscene. s8 bottleCatchType; // Player_Action_SwingBottle: entry type for `sBottleCatchInfo`, corresponds to actor caught in a bottle + s8 isClimbWall; // Player_Action_Climbing: True if climbed wall is a climbable wall and not ladder } av1; // "Action Variable 1": context dependent variable that has different meanings depending on what action is currently running /* 0x0850 */ union { @@ -929,6 +930,8 @@ typedef struct Player { s16 csDelayTimer; // Player_Action_WaitForCutscene: Number of frames to wait before responding to a cutscene s16 playedLandingSfx; // Player_Action_BlueWarpArrive: Played sfx when landing on the ground s16 appearTimer; // Player_Action_FaroresWindArrive: Counts up, appear at 20 frames (1 second) + s16 climbStartAnimFinished; // Player_Action_Climbing: Negative if start climb animation has not finished yet + s16 leftFootAbove; // Player_Action_Climbing: 1 = left foot higher up during climb } av2; // "Action Variable 2": context dependent variable that has different meanings depending on what action is currently running /* 0x0854 */ f32 unk_854; diff --git a/src/code/z_actor.c b/src/code/z_actor.c index a117131176b..13d76daa288 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -1171,7 +1171,7 @@ s32 func_8002DDE4(PlayState* play) { s32 func_8002DDF4(PlayState* play) { Player* player = GET_PLAYER(play); - return player->stateFlags2 & PLAYER_STATE2_12; + return player->stateFlags2 & PLAYER_STATE2_CLIMB_STILL; } /** @@ -1866,7 +1866,7 @@ s32 Actor_OfferGetItem(Actor* actor, PlayState* play, s32 getItemId, f32 xzRange if (!(player->stateFlags1 & (PLAYER_STATE1_DEAD | PLAYER_STATE1_CHARGING_SPIN_ATTACK | PLAYER_STATE1_13 | PLAYER_STATE1_14 | - PLAYER_STATE1_18 | PLAYER_STATE1_19 | PLAYER_STATE1_20 | PLAYER_STATE1_21)) && + PLAYER_STATE1_18 | PLAYER_STATE1_19 | PLAYER_STATE1_20 | PLAYER_STATE1_CLIMBING)) && Player_GetExplosiveHeld(player) < 0) { if ((((player->heldActor != NULL) || (player->talkActor == actor)) && (getItemId > GI_NONE) && (getItemId < GI_MAX)) || @@ -1940,7 +1940,7 @@ u32 Actor_SetRideActor(PlayState* play, Actor* horse, s32 mountSide) { if (!(player->stateFlags1 & (PLAYER_STATE1_DEAD | PLAYER_STATE1_CARRYING_ACTOR | PLAYER_STATE1_CHARGING_SPIN_ATTACK | PLAYER_STATE1_13 | - PLAYER_STATE1_14 | PLAYER_STATE1_18 | PLAYER_STATE1_19 | PLAYER_STATE1_20 | PLAYER_STATE1_21))) { + PLAYER_STATE1_14 | PLAYER_STATE1_18 | PLAYER_STATE1_19 | PLAYER_STATE1_20 | PLAYER_STATE1_CLIMBING))) { player->rideActor = horse; player->mountSide = mountSide; return true; diff --git a/src/code/z_bgcheck.c b/src/code/z_bgcheck.c index 656bb04b5ba..ebf50257039 100644 --- a/src/code/z_bgcheck.c +++ b/src/code/z_bgcheck.c @@ -69,9 +69,9 @@ void BgCheck_ResetPolyCheckTbl(SSNodeList* nodeList, s32 numPolys); s32 D_80119D90[WALL_TYPE_MAX] = { 0, // WALL_TYPE_0 WALL_FLAG_0, // WALL_TYPE_1 - WALL_FLAG_0 | WALL_FLAG_1, // WALL_TYPE_2 - WALL_FLAG_0 | WALL_FLAG_2, // WALL_TYPE_3 - WALL_FLAG_3, // WALL_TYPE_4 + WALL_FLAG_0 | WALL_FLAG_LADDER, // WALL_TYPE_2 + WALL_FLAG_0 | WALL_FLAG_LADDER_TOP, // WALL_TYPE_3 + WALL_FLAG_CLIMBABLE, // WALL_TYPE_4 WALL_FLAG_CRAWLSPACE_1, // WALL_TYPE_5 WALL_FLAG_CRAWLSPACE_2, // WALL_TYPE_6 WALL_FLAG_6, // WALL_TYPE_7 @@ -4129,12 +4129,12 @@ s32 SurfaceType_CheckWallFlag0(CollisionContext* colCtx, CollisionPoly* poly, s3 return (SurfaceType_GetWallFlags(colCtx, poly, bgId) & WALL_FLAG_0) ? true : false; } -s32 SurfaceType_CheckWallFlag1(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) { - return (SurfaceType_GetWallFlags(colCtx, poly, bgId) & WALL_FLAG_1) ? true : false; +s32 SurfaceType_CheckWallFlagLadder(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) { + return (SurfaceType_GetWallFlags(colCtx, poly, bgId) & WALL_FLAG_LADDER) ? true : false; } -s32 SurfaceType_CheckWallFlag2(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) { - return (SurfaceType_GetWallFlags(colCtx, poly, bgId) & WALL_FLAG_2) ? true : false; +s32 SurfaceType_CheckWallFlagLadderTop(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) { + return (SurfaceType_GetWallFlags(colCtx, poly, bgId) & WALL_FLAG_LADDER_TOP) ? true : false; } u32 SurfaceType_GetFloorProperty2(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) { diff --git a/src/code/z_camera.c b/src/code/z_camera.c index 3baaf6579fc..16eb6a2b4d8 100644 --- a/src/code/z_camera.c +++ b/src/code/z_camera.c @@ -1211,7 +1211,7 @@ s32 Camera_CalcAtForParallel(Camera* camera, VecGeo* arg1, f32 yOffset, f32* arg } if (camera->playerGroundY == camera->playerPosRot.pos.y || camera->player->actor.gravity > -0.1f || - camera->player->stateFlags1 & PLAYER_STATE1_21) { + camera->player->stateFlags1 & PLAYER_STATE1_CLIMBING) { *arg3 = Camera_LERPCeilF(playerPosRot->pos.y, *arg3, CAM_GLOBAL_43, 0.1f); phi_f20 = playerPosRot->pos.y - *arg3; playerToAtOffsetTarget.y -= phi_f20; @@ -1317,7 +1317,7 @@ s32 Camera_CalcAtForLockOn(Camera* camera, VecGeo* eyeAtDir, Vec3f* targetPos, f playerToAtOffsetTarget.z += lookFromOffset.z; if (camera->playerGroundY == camera->playerPosRot.pos.y || camera->player->actor.gravity > -0.1f || - camera->player->stateFlags1 & PLAYER_STATE1_21) { + camera->player->stateFlags1 & PLAYER_STATE1_CLIMBING) { *yPosOffset = Camera_LERPCeilF(playerPosRot->pos.y, *yPosOffset, CAM_GLOBAL_43, 0.1f); yPosDelta = playerPosRot->pos.y - *yPosOffset; playerToAtOffsetTarget.y -= yPosDelta; @@ -2256,7 +2256,7 @@ s32 Camera_Parallel1(Camera* camera) { } if (camera->playerGroundY == camera->playerPosRot.pos.y || camera->player->actor.gravity > -0.1f || - camera->player->stateFlags1 & PLAYER_STATE1_21) { + camera->player->stateFlags1 & PLAYER_STATE1_CLIMBING) { rwData->yTarget = playerPosRot->pos.y; sp6A = 0; } else { @@ -3029,7 +3029,7 @@ s32 Camera_Battle1(Camera* camera) { } if (camera->playerGroundY == camera->playerPosRot.pos.y || camera->player->actor.gravity > -0.1f || - camera->player->stateFlags1 & PLAYER_STATE1_21) { + camera->player->stateFlags1 & PLAYER_STATE1_CLIMBING) { isOffGround = false; rwData->yPosOffset = playerPosRot->pos.y; } else { @@ -3353,7 +3353,7 @@ s32 Camera_KeepOn1(Camera* camera) { rwData->unk_0C = NULL; cont: if (camera->playerGroundY == camera->playerPosRot.pos.y || camera->player->actor.gravity > -0.1f || - camera->player->stateFlags1 & PLAYER_STATE1_21) { + camera->player->stateFlags1 & PLAYER_STATE1_CLIMBING) { rwData->unk_08 = playerPosRot->pos.y; isOffGround = false; } else { diff --git a/src/code/z_parameter.c b/src/code/z_parameter.c index 1eb2b08ab67..7af08dfc886 100644 --- a/src/code/z_parameter.c +++ b/src/code/z_parameter.c @@ -808,7 +808,7 @@ void func_80083108(PlayState* play) { } Interface_ChangeHudVisibilityMode(HUD_VISIBILITY_ALL); - } else if ((player->stateFlags1 & PLAYER_STATE1_21) || (player->stateFlags2 & PLAYER_STATE2_CRAWLING)) { + } else if ((player->stateFlags1 & PLAYER_STATE1_CLIMBING) || (player->stateFlags2 & PLAYER_STATE2_CRAWLING)) { if (gSaveContext.buttonStatus[0] != BTN_DISABLED) { gSaveContext.buttonStatus[0] = BTN_DISABLED; gSaveContext.buttonStatus[1] = BTN_DISABLED; @@ -2911,7 +2911,7 @@ void Interface_DrawItemButtons(PlayState* play) { (gSaveContext.hudVisibilityMode == HUD_VISIBILITY_NOTHING_ALT) || (gSaveContext.hudVisibilityMode == HUD_VISIBILITY_A_HEARTS_MAGIC_FORCE)) { temp = 0; - } else if ((player->stateFlags1 & PLAYER_STATE1_21) || + } else if ((player->stateFlags1 & PLAYER_STATE1_CLIMBING) || (Player_GetEnvironmentalHazard(play) == PLAYER_ENV_HAZARD_UNDERWATER_FREE) || (player->stateFlags2 & PLAYER_STATE2_CRAWLING)) { temp = 70; diff --git a/src/code/z_player_lib.c b/src/code/z_player_lib.c index c701f379db8..7a45733fbff 100644 --- a/src/code/z_player_lib.c +++ b/src/code/z_player_lib.c @@ -750,12 +750,12 @@ void Player_ReleaseLockOn(Player* this) { */ void Player_ClearZTargeting(Player* this) { if ((this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) || - (this->stateFlags1 & (PLAYER_STATE1_21 | PLAYER_STATE1_23 | PLAYER_STATE1_27)) || + (this->stateFlags1 & (PLAYER_STATE1_CLIMBING | PLAYER_STATE1_23 | PLAYER_STATE1_27)) || (!(this->stateFlags1 & (PLAYER_STATE1_18 | PLAYER_STATE1_19)) && ((this->actor.world.pos.y - this->actor.floorHeight) < 100.0f))) { this->stateFlags1 &= ~(PLAYER_STATE1_Z_TARGETING | PLAYER_STATE1_FRIENDLY_ACTOR_FOCUS | PLAYER_STATE1_PARALLEL | PLAYER_STATE1_18 | PLAYER_STATE1_19 | PLAYER_STATE1_LOCK_ON_FORCED_TO_RELEASE); - } else if (!(this->stateFlags1 & (PLAYER_STATE1_18 | PLAYER_STATE1_19 | PLAYER_STATE1_21))) { + } else if (!(this->stateFlags1 & (PLAYER_STATE1_18 | PLAYER_STATE1_19 | PLAYER_STATE1_CLIMBING))) { this->stateFlags1 |= PLAYER_STATE1_19; } diff --git a/src/overlays/actors/ovl_Bg_Jya_Zurerukabe/z_bg_jya_zurerukabe.c b/src/overlays/actors/ovl_Bg_Jya_Zurerukabe/z_bg_jya_zurerukabe.c index 148d6c00985..e65479c1b83 100644 --- a/src/overlays/actors/ovl_Bg_Jya_Zurerukabe/z_bg_jya_zurerukabe.c +++ b/src/overlays/actors/ovl_Bg_Jya_Zurerukabe/z_bg_jya_zurerukabe.c @@ -91,7 +91,7 @@ void BgJyaZurerukabe_InitDynaPoly(BgJyaZurerukabe* this, PlayState* play, Collis void func_8089B4C8(BgJyaZurerukabe* this, PlayState* play) { Player* player = GET_PLAYER(play); - if ((player->stateFlags1 == PLAYER_STATE1_21) && (player->actor.wallPoly != NULL)) { + if ((player->stateFlags1 == PLAYER_STATE1_CLIMBING) && (player->actor.wallPoly != NULL)) { s32 i; for (i = 0; i < ARRAY_COUNT(D_8089BA18); i++) { diff --git a/src/overlays/actors/ovl_En_Rd/z_en_rd.c b/src/overlays/actors/ovl_En_Rd/z_en_rd.c index 11d7ac0b6f7..f7e46fb575c 100644 --- a/src/overlays/actors/ovl_En_Rd/z_en_rd.c +++ b/src/overlays/actors/ovl_En_Rd/z_en_rd.c @@ -380,7 +380,7 @@ void EnRd_WalkToPlayer(EnRd* this, PlayState* play) { if ((ABS(yaw) < 0x1554) && (Actor_WorldDistXYZToActor(&this->actor, &player->actor) <= 150.0f)) { if (!(player->stateFlags1 & (PLAYER_STATE1_DEAD | PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_18 | - PLAYER_STATE1_19 | PLAYER_STATE1_21)) && + PLAYER_STATE1_19 | PLAYER_STATE1_CLIMBING)) && !(player->stateFlags2 & PLAYER_STATE2_7)) { if (this->playerStunWaitTimer == 0) { if (!(this->rdFlags & 0x80)) { @@ -464,7 +464,7 @@ void EnRd_WalkToHome(EnRd* this, PlayState* play) { SkelAnime_Update(&this->skelAnime); if (!(player->stateFlags1 & (PLAYER_STATE1_DEAD | PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_18 | - PLAYER_STATE1_19 | PLAYER_STATE1_21)) && + PLAYER_STATE1_19 | PLAYER_STATE1_CLIMBING)) && !(player->stateFlags2 & PLAYER_STATE2_7) && (Actor_WorldDistXYZToPoint(&player->actor, &this->actor.home.pos) < 150.0f)) { this->actor.attentionRangeType = ATTENTION_RANGE_0; diff --git a/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c b/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c index fd5e4e909d4..d6e96b0c5ef 100644 --- a/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c +++ b/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c @@ -956,7 +956,7 @@ void EnRu1_CheckStartFirstEncounter(EnRu1* this, PlayState* play) { Player* player = GET_PLAYER(play); if ((EnRu1_IsPlayerInRangeForFirstEncounter(this, play)) && (!Play_InCsMode(play)) && - (!(player->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_21))) && + (!(player->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_CLIMBING))) && (player->actor.bgCheckFlags & BGCHECKFLAG_GROUND)) { play->csCtx.script = gRutoFirstMeetingCs; diff --git a/src/overlays/actors/ovl_En_Sw/z_en_sw.c b/src/overlays/actors/ovl_En_Sw/z_en_sw.c index b2a2ecdd94f..33f2a1c6a6f 100644 --- a/src/overlays/actors/ovl_En_Sw/z_en_sw.c +++ b/src/overlays/actors/ovl_En_Sw/z_en_sw.c @@ -725,7 +725,7 @@ s32 func_80B0DEA8(EnSw* this, PlayState* play, s32 arg2) { s32 sp54; Vec3f sp48; - if (!(player->stateFlags1 & PLAYER_STATE1_21) && arg2) { + if (!(player->stateFlags1 & PLAYER_STATE1_CLIMBING) && arg2) { return false; } else if (func_8002DDF4(play) && arg2) { return false; diff --git a/src/overlays/actors/ovl_player_actor/z_player.c b/src/overlays/actors/ovl_player_actor/z_player.c index 84dd1e6f522..600ae89a0c1 100644 --- a/src/overlays/actors/ovl_player_actor/z_player.c +++ b/src/overlays/actors/ovl_player_actor/z_player.c @@ -319,7 +319,7 @@ void Player_Action_8084B898(Player* this, PlayState* play); void Player_Action_8084B9E4(Player* this, PlayState* play); void Player_Action_8084BBE4(Player* this, PlayState* play); void Player_Action_8084BDFC(Player* this, PlayState* play); -void Player_Action_8084BF1C(Player* this, PlayState* play); +void Player_Action_Climbing(Player* this, PlayState* play); void Player_Action_8084C5F8(Player* this, PlayState* play); void Player_Action_8084C760(Player* this, PlayState* play); void Player_Action_8084C81C(Player* this, PlayState* play); @@ -457,7 +457,7 @@ static PlayerAgeProperties sAgeProperties[] = { &gPlayerAnim_link_normal_climb_startB, // unk_A8 { &gPlayerAnim_link_normal_climb_upL, &gPlayerAnim_link_normal_climb_upR, &gPlayerAnim_link_normal_Fclimb_upL, &gPlayerAnim_link_normal_Fclimb_upR }, // unk_AC - { &gPlayerAnim_link_normal_Fclimb_sideL, &gPlayerAnim_link_normal_Fclimb_sideR }, // unk_BC + { &gPlayerAnim_link_normal_Fclimb_sideL, &gPlayerAnim_link_normal_Fclimb_sideR }, // sideClimbAnim { &gPlayerAnim_link_normal_climb_endAL, &gPlayerAnim_link_normal_climb_endAR }, // unk_C4 { &gPlayerAnim_link_normal_climb_endBR, &gPlayerAnim_link_normal_climb_endBL }, // unk_CC }, @@ -509,7 +509,7 @@ static PlayerAgeProperties sAgeProperties[] = { &gPlayerAnim_clink_normal_climb_startB, // unk_A8 { &gPlayerAnim_clink_normal_climb_upL, &gPlayerAnim_clink_normal_climb_upR, &gPlayerAnim_link_normal_Fclimb_upL, &gPlayerAnim_link_normal_Fclimb_upR }, // unk_AC - { &gPlayerAnim_link_normal_Fclimb_sideL, &gPlayerAnim_link_normal_Fclimb_sideR }, // unk_BC + { &gPlayerAnim_link_normal_Fclimb_sideL, &gPlayerAnim_link_normal_Fclimb_sideR }, // sideClimbAnim { &gPlayerAnim_clink_normal_climb_endAL, &gPlayerAnim_clink_normal_climb_endAR }, // unk_C4 { &gPlayerAnim_clink_normal_climb_endBR, &gPlayerAnim_clink_normal_climb_endBL }, // unk_CC }, @@ -1828,7 +1828,7 @@ void func_80832440(PlayState* play, Player* this) { func_80832340(play, this); Camera_SetFinishedFlag(Play_GetCamera(play, CAM_ID_MAIN)); - this->stateFlags1 &= ~(PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_20 | PLAYER_STATE1_21); + this->stateFlags1 &= ~(PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_20 | PLAYER_STATE1_CLIMBING); this->stateFlags2 &= ~(PLAYER_STATE2_4 | PLAYER_STATE2_7 | PLAYER_STATE2_CRAWLING); this->actor.shape.rot.x = 0; @@ -4678,7 +4678,7 @@ void func_80837C0C(PlayState* play, Player* this, s32 hitResponseType, f32 speed } else if ((hitResponseType == PLAYER_HIT_RESPONSE_KNOCKBACK_LARGE) || (hitResponseType == PLAYER_HIT_RESPONSE_KNOCKBACK_SMALL) || !(this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) || - (this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_21))) { + (this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_CLIMBING))) { Player_SetupAction(play, this, Player_Action_8084377C, 0); this->stateFlags3 |= PLAYER_STATE3_1; @@ -4911,7 +4911,7 @@ s32 func_808382DC(Player* this, PlayState* play) { } } - if (!(this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_21))) { + if (!(this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_CLIMBING))) { this->speedXZ = -18.0f; this->yaw = this->actor.shape.rot.y; } @@ -5670,15 +5670,15 @@ void func_8083A388(PlayState* play, Player* this) { Player_SetupAction(play, this, Player_Action_8084B78C, 0); } -void func_8083A3B0(PlayState* play, Player* this) { - s32 sp1C = this->av2.actionVar2; - s32 sp18 = this->av1.actionVar1; +void Player_SetupClimbing(PlayState* play, Player* this) { + s32 av2 = this->av2.climbStartAnimFinished; + s32 av1 = this->av1.isClimbWall; - Player_SetupActionPreserveAnimMovement(play, this, Player_Action_8084BF1C, 0); + Player_SetupActionPreserveAnimMovement(play, this, Player_Action_Climbing, 0); this->actor.velocity.y = 0.0f; - this->av2.actionVar2 = sp1C; - this->av1.actionVar1 = sp18; + this->av2.climbStartAnimFinished = av2; + this->av1.isClimbWall = av1; } void func_8083A40C(PlayState* play, Player* this) { @@ -5777,7 +5777,7 @@ s32 func_8083A6AC(Player* this, PlayState* play) { sp54 = Math3D_UDistPlaneToPos(nx, ny, nz, sp84->dist, &this->actor.world.pos); sp50 = (sPrevFloorProperty == FLOOR_PROPERTY_6); - if (!sp50 && (SurfaceType_GetWallFlags(&play->colCtx, sp84, sp80) & WALL_FLAG_3)) { + if (!sp50 && (SurfaceType_GetWallFlags(&play->colCtx, sp84, sp80) & WALL_FLAG_CLIMBABLE)) { sp50 = 1; } @@ -5785,12 +5785,12 @@ s32 func_8083A6AC(Player* this, PlayState* play) { sp50 ? &gPlayerAnim_link_normal_Fclimb_startB : &gPlayerAnim_link_normal_fall); if (sp50) { - Player_SetupWaitForPutAway(play, this, func_8083A3B0); + Player_SetupWaitForPutAway(play, this, Player_SetupClimbing); this->yaw += 0x8000; this->actor.shape.rot.y = this->yaw; - this->stateFlags1 |= PLAYER_STATE1_21; + this->stateFlags1 |= PLAYER_STATE1_CLIMBING; Player_StartAnimMovement(play, this, ANIM_FLAG_UPDATE_XZ | ANIM_FLAG_UPDATE_Y | ANIM_FLAG_DISABLE_CHILD_ROOT_ADJUSTMENT | ANIM_FLAG_ENABLE_MOVEMENT | @@ -7483,14 +7483,17 @@ s32 Player_ActionHandler_9(Player* this, PlayState* play) { return 0; } +/** + * Try start climbing + */ s32 func_8083EC18(Player* this, PlayState* play, u32 wallFlags) { if (this->yDistToLedge >= 79.0f) { if (!(this->stateFlags1 & PLAYER_STATE1_27) || (this->currentBoots == PLAYER_BOOTS_IRON) || (this->actor.depthInWater < this->ageProperties->unk_2C)) { - s32 sp8C = (wallFlags & WALL_FLAG_3) ? 2 : 0; + s32 climbable = (wallFlags & WALL_FLAG_CLIMBABLE) ? 2 : 0; - if ((sp8C != 0) || (wallFlags & WALL_FLAG_1) || - SurfaceType_CheckWallFlag2(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId)) { + if ((climbable != 0) || (wallFlags & WALL_FLAG_LADDER) || + SurfaceType_CheckWallFlagLadderTop(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId)) { f32 phi_f20; CollisionPoly* wallPoly = this->actor.wallPoly; f32 sp80; @@ -7500,7 +7503,7 @@ s32 func_8083EC18(Player* this, PlayState* play, u32 wallFlags) { phi_f20 = phi_f12 = 0.0f; - if (sp8C != 0) { + if (climbable != 0) { sp80 = this->actor.world.pos.x; sp7C = this->actor.world.pos.z; } else { @@ -7545,39 +7548,43 @@ s32 func_8083EC18(Player* this, PlayState* play, u32 wallFlags) { phi_f12 = fabsf(phi_f12); } + // Start climbing wall/ladder if (phi_f12 < 8.0f) { f32 wallPolyNormalX = COLPOLY_GET_NORMAL(wallPoly->normal.x); f32 wallPolyNormalZ = COLPOLY_GET_NORMAL(wallPoly->normal.z); - f32 sp34 = this->distToInteractWall; + f32 distWall = this->distToInteractWall; LinkAnimationHeader* anim; - Player_SetupWaitForPutAway(play, this, func_8083A3B0); - this->stateFlags1 |= PLAYER_STATE1_21; + Player_SetupWaitForPutAway(play, this, Player_SetupClimbing); + this->stateFlags1 |= PLAYER_STATE1_CLIMBING; this->stateFlags1 &= ~PLAYER_STATE1_27; - if ((sp8C != 0) || (wallFlags & WALL_FLAG_1)) { - if ((this->av1.actionVar1 = sp8C) != 0) { + if ((climbable != 0) || (wallFlags & WALL_FLAG_LADDER)) { + if ((this->av1.actionVar1 = climbable) != 0) { if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { - anim = &gPlayerAnim_link_normal_Fclimb_startA; + anim = &gPlayerAnim_link_normal_Fclimb_startA; // Climb from ground } else { - anim = &gPlayerAnim_link_normal_Fclimb_hold2upL; + anim = &gPlayerAnim_link_normal_Fclimb_hold2upL; // Grabbing wall while falling } - sp34 = (this->ageProperties->wallCheckRadius - 1.0f) - sp34; - } else { + distWall = (this->ageProperties->wallCheckRadius - 1.0f) - distWall; + } else { // Climb ladder from below anim = this->ageProperties->unk_A4; - sp34 = sp34 - 1.0f; + distWall = distWall - 1.0f; } this->av2.actionVar2 = -2; this->actor.world.pos.y += phi_f20; this->actor.shape.rot.y = this->yaw = this->actor.wallYaw + 0x8000; - } else { + } else { // Climb ladder from top anim = this->ageProperties->unk_A8; this->av2.actionVar2 = -4; this->actor.shape.rot.y = this->yaw = this->actor.wallYaw; } - this->actor.world.pos.x = (sp34 * wallPolyNormalX) + sp80; - this->actor.world.pos.z = (sp34 * wallPolyNormalZ) + sp7C; + //! @bug This position change, after climbing has been started, can cause + //! player to face a new wallPoly which might not be climbable. Causes the + //! fail to climb bug, falling off the wall instantly after climb start. + this->actor.world.pos.x = (distWall * wallPolyNormalX) + sp80; + this->actor.world.pos.z = (distWall * wallPolyNormalZ) + sp7C; func_80832224(this); Math_Vec3f_Copy(&this->actor.prevPos, &this->actor.world.pos); Player_AnimPlayOnce(play, this, anim); @@ -7881,17 +7888,24 @@ void func_8083FB14(Player* this, PlayState* play) { Player_AnimPlayOnce(play, this, GET_PLAYER_ANIM(PLAYER_ANIMGROUP_pull_start, this->modelAnimType)); } +/** + * When detaching during a climb + */ void func_8083FB7C(Player* this, PlayState* play) { - this->stateFlags1 &= ~(PLAYER_STATE1_21 | PLAYER_STATE1_27); + this->stateFlags1 &= ~(PLAYER_STATE1_CLIMBING | PLAYER_STATE1_27); func_80837B9C(this, play); this->speedXZ = -0.4f; } -s32 func_8083FBC0(Player* this, PlayState* play) { +/** + * Check if player is still on a climbable wall/ladder and hasn't pressed A + * @return true if detaching, else false + */ +s32 Player_DetachFromClimb(Player* this, PlayState* play) { if (!CHECK_BTN_ALL(sControlInput->press.button, BTN_A) && (this->actor.bgCheckFlags & BGCHECKFLAG_PLAYER_WALL_INTERACT) && - ((sTouchedWallFlags & WALL_FLAG_3) || (sTouchedWallFlags & WALL_FLAG_1) || - SurfaceType_CheckWallFlag2(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId))) { + ((sTouchedWallFlags & WALL_FLAG_CLIMBABLE) || (sTouchedWallFlags & WALL_FLAG_LADDER) || + SurfaceType_CheckWallFlagLadderTop(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId))) { return false; } @@ -10944,7 +10958,7 @@ void Player_UpdateInterface(PlayState* play, Player* this) { } else { doAction = DO_ACTION_CHECK; } - } else if ((this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_21)) || + } else if ((this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_CLIMBING)) || ((this->stateFlags1 & PLAYER_STATE1_23) && (this->stateFlags2 & PLAYER_STATE2_22))) { doAction = DO_ACTION_DOWN; } else if (this->stateFlags2 & PLAYER_STATE2_DO_ACTION_ENTER) { @@ -11271,7 +11285,7 @@ void Player_ProcessSceneCollision(PlayState* play, Player* this) { &sInteractWallCheckResult) && (wallYawDiff = this->actor.wallYaw - Math_Atan2S(poly->normal.z, poly->normal.x), ABS(wallYawDiff) < 0x4000) && - !SurfaceType_CheckWallFlag1(&play->colCtx, poly, bgId)) { + !SurfaceType_CheckWallFlagLadder(&play->colCtx, poly, bgId)) { this->yDistToLedge = LEDGE_DIST_MAX; } else if (SurfaceType_CheckWallFlag0(&play->colCtx, wallPoly, this->actor.wallBgId) == 0) { if (this->ageProperties->unk_1C <= this->yDistToLedge) { @@ -11400,13 +11414,13 @@ void Player_UpdateCamAndSeqModes(PlayState* play, Player* this) { } else if (this->stateFlags1 & (PLAYER_STATE1_PARALLEL | PLAYER_STATE1_LOCK_ON_FORCED_TO_RELEASE)) { if (func_8002DD78(this) || func_808334B4(this)) { camMode = CAM_MODE_Z_AIM; - } else if (this->stateFlags1 & PLAYER_STATE1_21) { + } else if (this->stateFlags1 & PLAYER_STATE1_CLIMBING) { camMode = CAM_MODE_Z_WALL_CLIMB; } else { camMode = CAM_MODE_Z_PARALLEL; } - } else if (this->stateFlags1 & (PLAYER_STATE1_18 | PLAYER_STATE1_21)) { - if ((Player_Action_80845668 == this->actionFunc) || (this->stateFlags1 & PLAYER_STATE1_21)) { + } else if (this->stateFlags1 & (PLAYER_STATE1_18 | PLAYER_STATE1_CLIMBING)) { + if ((Player_Action_80845668 == this->actionFunc) || (this->stateFlags1 & PLAYER_STATE1_CLIMBING)) { camMode = CAM_MODE_WALL_CLIMB; } else { camMode = CAM_MODE_JUMP; @@ -11840,7 +11854,7 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { Actor_UpdateVelocityXZGravity(&this->actor); if ((this->pushedSpeed != 0.0f) && !Player_InCsMode(play) && - !(this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_21)) && + !(this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_CLIMBING)) && (Player_Action_80845668 != this->actionFunc) && (Player_Action_808507F4 != this->actionFunc)) { this->actor.velocity.x += this->pushedSpeed * Math_SinS(this->pushedYaw); this->actor.velocity.z += this->pushedSpeed * Math_CosS(this->pushedYaw); @@ -11907,7 +11921,7 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { func_8083D53C(play, this); if ((this->actor.category == ACTORCAT_PLAYER) && (gSaveContext.save.info.playerData.health == 0)) { - if (this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_21)) { + if (this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_CLIMBING)) { func_80832440(play, this); func_80837B9C(this, play); } else if ((this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) || (this->stateFlags1 & PLAYER_STATE1_27)) { @@ -11945,7 +11959,7 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { if (this->csAction != PLAYER_CSACTION_NONE) { if ((this->csAction != PLAYER_CSACTION_7) || - !(this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_21 | PLAYER_STATE1_26))) { + !(this->stateFlags1 & (PLAYER_STATE1_13 | PLAYER_STATE1_14 | PLAYER_STATE1_CLIMBING | PLAYER_STATE1_26))) { this->unk_6AD = 3; } else if (Player_Action_CsAction != this->actionFunc) { func_80852944(play, this, NULL); @@ -11963,7 +11977,7 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { this->stateFlags1 &= ~(PLAYER_STATE1_SWINGING_BOTTLE | PLAYER_STATE1_9 | PLAYER_STATE1_CHARGING_SPIN_ATTACK | 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_8 | PLAYER_STATE2_FORCE_SAND_FLOOR_SOUND | PLAYER_STATE2_CLIMB_STILL | PLAYER_STATE2_14 | PLAYER_STATE2_DO_ACTION_ENTER | PLAYER_STATE2_22 | PLAYER_STATE2_26); this->stateFlags3 &= ~PLAYER_STATE3_4; @@ -12823,53 +12837,60 @@ void func_8084BEE4(Player* this) { : NA_SE_PL_WALK_GROUND + SURFACE_SFX_OFFSET_WOOD); } -void Player_Action_8084BF1C(Player* this, PlayState* play) { +/** + * Climbing vines, ladders, nets etc. + * actionVars are preserved by setup function when this action is set up + */ +void Player_Action_Climbing(Player* this, PlayState* play) { static Vec3f D_8085488C = { 0.0f, 0.0f, 26.0f }; - s32 sp84; - s32 sp80; - f32 phi_f0; - f32 phi_f2; - Vec3f sp6C; + s32 inputY; + s32 inputX; + f32 speed; + f32 animSpeed; + Vec3f wallMoveDiff; s32 sp68; Vec3f sp5C; DynaPolyActor* wallPolyActor; LinkAnimationHeader* anim1; LinkAnimationHeader* anim2; - sp84 = sControlInput->rel.stick_y; - sp80 = sControlInput->rel.stick_x; + inputY = sControlInput->rel.stick_y; + inputX = sControlInput->rel.stick_x; this->fallStartHeight = this->actor.world.pos.y; this->stateFlags2 |= PLAYER_STATE2_6; - if ((this->av1.actionVar1 != 0) && (ABS(sp84) < ABS(sp80))) { - phi_f0 = ABS(sp80) * 0.0325f; - sp84 = 0; + // If not ladder + if (this->av1.isClimbWall && (ABS(inputY) < ABS(inputX))) { + speed = ABS(inputX) * 0.0325f; + inputY = 0; } else { - phi_f0 = ABS(sp84) * 0.05f; - sp80 = 0; + speed = ABS(inputY) * 0.05f; + inputX = 0; } - if (phi_f0 < 1.0f) { - phi_f0 = 1.0f; - } else if (phi_f0 > 3.35f) { - phi_f0 = 3.35f; + // Min-max climbing speed + if (speed < 1.0f) { + speed = 1.0f; + } else if (speed > 3.35f) { + speed = 3.35f; } if (this->skelAnime.playSpeed >= 0.0f) { - phi_f2 = 1.0f; + animSpeed = 1.0f; } else { - phi_f2 = -1.0f; + animSpeed = -1.0f; } - this->skelAnime.playSpeed = phi_f2 * phi_f0; + this->skelAnime.playSpeed = animSpeed * speed; - if (this->av2.actionVar2 >= 0) { + if (this->av2.climbStartAnimFinished >= 0) { + // If climbing moving wall (Spirit Temple) if ((this->actor.wallPoly != NULL) && (this->actor.wallBgId != BGCHECK_SCENE)) { wallPolyActor = DynaPoly_GetActor(&play->colCtx, this->actor.wallBgId); if (wallPolyActor != NULL) { - Math_Vec3f_Diff(&wallPolyActor->actor.world.pos, &wallPolyActor->actor.prevPos, &sp6C); - Math_Vec3f_Sum(&this->actor.world.pos, &sp6C, &this->actor.world.pos); + Math_Vec3f_Diff(&wallPolyActor->actor.world.pos, &wallPolyActor->actor.prevPos, &wallMoveDiff); + Math_Vec3f_Sum(&this->actor.world.pos, &wallMoveDiff, &this->actor.world.pos); } } @@ -12878,26 +12899,29 @@ void Player_Action_8084BF1C(Player* this, PlayState* play) { func_8083F360(play, this, 26.0f, this->ageProperties->unk_3C, 50.0f, -20.0f); } - if ((this->av2.actionVar2 < 0) || !func_8083FBC0(this, play)) { + if ((this->av2.climbStartAnimFinished < 0) || !Player_DetachFromClimb(this, play)) { if (LinkAnimation_Update(play, &this->skelAnime)) { - if (this->av2.actionVar2 < 0) { - this->av2.actionVar2 = ABS(this->av2.actionVar2) & 1; + // Starting climb animation ended, set actionVar2 to non-negative (= from animation to foot position marker) + if (this->av2.climbStartAnimFinished < 0) { + this->av2.leftFootAbove = ABS(this->av2.climbStartAnimFinished) & 1; return; } - if (sp84 != 0) { - f32 temp_f0; + // Direction up/down + if (inputY != 0) { + f32 wallHeight; - sp68 = this->av1.actionVar1 + this->av2.actionVar2; + sp68 = this->av1.isClimbWall + this->av2.leftFootAbove; - if (sp84 > 0) { + if (inputY > 0) { // Direction up D_8085488C.y = this->ageProperties->unk_40; - temp_f0 = func_8083973C(play, this, &D_8085488C, &sp5C); + wallHeight = func_8083973C(play, this, &D_8085488C, &sp5C); - if (this->actor.world.pos.y < temp_f0) { - if (this->av1.actionVar1 != 0) { - this->actor.world.pos.y = temp_f0; - this->stateFlags1 &= ~PLAYER_STATE1_21; + // Dismount up from climb + if (this->actor.world.pos.y < wallHeight) { + if (this->av1.isClimbWall) { // Regular wall + this->actor.world.pos.y = wallHeight; + this->stateFlags1 &= ~PLAYER_STATE1_CLIMBING; func_8083A5C4(play, this, this->actor.wallPoly, this->ageProperties->unk_3C, &gPlayerAnim_link_normal_jump_climb_up_free); this->yaw += 0x8000; @@ -12905,24 +12929,25 @@ void Player_Action_8084BF1C(Player* this, PlayState* play) { func_8083A9B8(this, &gPlayerAnim_link_normal_jump_climb_up_free, play); this->stateFlags1 |= PLAYER_STATE1_14; } else { - func_8083F070(this, this->ageProperties->unk_CC[this->av2.actionVar2], play); + func_8083F070(this, this->ageProperties->unk_CC[this->av2.leftFootAbove], play); } - } else { + } else { // Climb upwards this->skelAnime.prevTransl = this->ageProperties->unk_4A[sp68]; Player_AnimPlayOnce(play, this, this->ageProperties->unk_AC[sp68]); } - } else { + } else { // Direction down + // Dismount down from climb if ((this->actor.world.pos.y - this->actor.floorHeight) < 15.0f) { - if (this->av1.actionVar1 != 0) { + if (this->av1.isClimbWall) { // Regular wall func_8083FB7C(this, play); - } else { - if (this->av2.actionVar2 != 0) { + } else { // Ladder + if (this->av2.leftFootAbove != 0) { this->skelAnime.prevTransl = this->ageProperties->unk_44; } func_8083F070(this, this->ageProperties->unk_C4[this->av2.actionVar2], play); - this->av2.actionVar2 = 1; + this->av2.leftFootAbove = 1; } - } else { + } else { // Climb downwards sp68 ^= 1; this->skelAnime.prevTransl = this->ageProperties->unk_62[sp68]; anim1 = this->ageProperties->unk_AC[sp68]; @@ -12930,21 +12955,23 @@ void Player_Action_8084BF1C(Player* this, PlayState* play) { ANIMMODE_ONCE, 0.0f); } } - this->av2.actionVar2 ^= 1; + this->av2.leftFootAbove ^= 1; } else { - if ((this->av1.actionVar1 != 0) && (sp80 != 0)) { - anim2 = this->ageProperties->unk_BC[this->av2.actionVar2]; + // Direction sideways + if (this->av1.isClimbWall && (inputX != 0)) { + anim2 = this->ageProperties->sideClimbAnim[this->av2.leftFootAbove]; - if (sp80 > 0) { - this->skelAnime.prevTransl = this->ageProperties->unk_7A[this->av2.actionVar2]; + if (inputX > 0) { // Right + this->skelAnime.prevTransl = this->ageProperties->unk_7A[this->av2.leftFootAbove]; Player_AnimPlayOnce(play, this, anim2); - } else { - this->skelAnime.prevTransl = this->ageProperties->unk_86[this->av2.actionVar2]; + } else { // Left + this->skelAnime.prevTransl = this->ageProperties->unk_86[this->av2.leftFootAbove]; LinkAnimation_Change(play, &this->skelAnime, anim2, -1.0f, Animation_GetLastFrame(anim2), 0.0f, ANIMMODE_ONCE, 0.0f); } + // Stand still } else { - this->stateFlags2 |= PLAYER_STATE2_12; + this->stateFlags2 |= PLAYER_STATE2_CLIMB_STILL; } } @@ -12952,8 +12979,9 @@ void Player_Action_8084BF1C(Player* this, PlayState* play) { } } - if (this->av2.actionVar2 < 0) { - if (((this->av2.actionVar2 == -2) && + // -2 = start from below (climbwall and ladder), -4 = start from above (only ladder) + if (this->av2.climbStartAnimFinished < 0) { + if (((this->av2.climbStartAnimFinished == -2) && (LinkAnimation_OnFrame(&this->skelAnime, 14.0f) || LinkAnimation_OnFrame(&this->skelAnime, 29.0f))) || ((this->av2.actionVar2 == -4) && (LinkAnimation_OnFrame(&this->skelAnime, 22.0f) || LinkAnimation_OnFrame(&this->skelAnime, 35.0f) || @@ -12989,13 +13017,13 @@ void Player_Action_8084C5F8(Player* this, PlayState* play) { interruptResult = Player_TryActionInterrupt(play, this, &this->skelAnime, 4.0f); if (interruptResult == PLAYER_INTERRUPT_NEW_ACTION) { - this->stateFlags1 &= ~PLAYER_STATE1_21; + this->stateFlags1 &= ~PLAYER_STATE1_CLIMBING; return; } if ((interruptResult >= PLAYER_INTERRUPT_MOVE) || LinkAnimation_Update(play, &this->skelAnime)) { func_8083C0E8(this, play); - this->stateFlags1 &= ~PLAYER_STATE1_21; + this->stateFlags1 &= ~PLAYER_STATE1_CLIMBING; return; }