turn in place (#1728)

This commit is contained in:
engineer124 2024-10-23 11:26:19 +11:00 committed by GitHub
parent 13c42b487d
commit 694d3b3965
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 52 additions and 32 deletions

View File

@ -1240,7 +1240,7 @@ typedef struct Player {
/* 0xAC8 */ f32 skelAnimeUpperBlendWeight; /* 0xAC8 */ f32 skelAnimeUpperBlendWeight;
/* 0xACC */ s16 unk_ACC; /* 0xACC */ s16 unk_ACC;
/* 0xACE */ s8 unk_ACE; /* 0xACE */ s8 unk_ACE;
/* 0xACF */ u8 putAwayCountdown; // Frames to wait before showing "Put Away" on A /* 0xACF */ u8 putAwayCooldownTimer; // Frames to wait before showing "Put Away" on A
/* 0xAD0 */ f32 speedXZ; // Controls horizontal speed, used for `actor.speed`. Current or target value depending on context. /* 0xAD0 */ f32 speedXZ; // Controls horizontal speed, used for `actor.speed`. Current or target value depending on context.
/* 0xAD4 */ s16 yaw; // General yaw value, used both for world and shape rotation. Current or target value depending on context. /* 0xAD4 */ s16 yaw; // General yaw value, used both for world and shape rotation. Current or target value depending on context.
/* 0xAD6 */ s16 parallelYaw; // yaw in "parallel" mode, Z-Target without an actor lock-on /* 0xAD6 */ s16 parallelYaw; // yaw in "parallel" mode, Z-Target without an actor lock-on
@ -1280,7 +1280,7 @@ typedef struct Player {
/* 0xB44 */ f32 unk_B44; /* 0xB44 */ f32 unk_B44;
/* 0xB48 */ f32 unk_B48; /* 0xB48 */ f32 unk_B48;
/* 0xB4C */ s16 unk_B4C; /* 0xB4C */ s16 unk_B4C;
/* 0xB4E */ s16 unk_B4E; /* 0xB4E */ s16 turnRate; // Amount angle is changed every frame when turning in place
/* 0xB50 */ f32 unk_B50; /* 0xB50 */ f32 unk_B50;
/* 0xB54 */ f32 yDistToLedge; // y distance to ground above an interact wall. LEDGE_DIST_MAX if no ground if found /* 0xB54 */ f32 yDistToLedge; // y distance to ground above an interact wall. LEDGE_DIST_MAX if no ground if found
/* 0xB58 */ f32 distToInteractWall; // xyz distance to the interact wall /* 0xB58 */ f32 distToInteractWall; // xyz distance to the interact wall

View File

@ -123,7 +123,7 @@ void Player_Action_6(Player* this, PlayState* play);
void Player_Action_7(Player* this, PlayState* play); void Player_Action_7(Player* this, PlayState* play);
void Player_Action_8(Player* this, PlayState* play); void Player_Action_8(Player* this, PlayState* play);
void Player_Action_9(Player* this, PlayState* play); void Player_Action_9(Player* this, PlayState* play);
void Player_Action_10(Player* this, PlayState* play); void Player_Action_TurnInPlace(Player* this, PlayState* play);
void Player_Action_11(Player* this, PlayState* play); void Player_Action_11(Player* this, PlayState* play);
void Player_Action_12(Player* this, PlayState* play); void Player_Action_12(Player* this, PlayState* play);
void Player_Action_13(Player* this, PlayState* play); void Player_Action_13(Player* this, PlayState* play);
@ -5194,7 +5194,7 @@ s8 sActionHandlerList5[] = {
/* 8 */ -PLAYER_ACTION_HANDLER_7, /* 8 */ -PLAYER_ACTION_HANDLER_7,
}; };
s8 sActionHandlerList6[] = { s8 sActionHandlerListTurnInPlace[] = {
/* 0 */ -PLAYER_ACTION_HANDLER_7, /* 0 */ -PLAYER_ACTION_HANDLER_7,
}; };
@ -8238,7 +8238,7 @@ s32 Player_ActionHandler_6(Player* this, PlayState* play) {
return true; return true;
} }
if ((this->putAwayCountdown == 0) && (this->heldItemAction >= PLAYER_IA_SWORD_KOKIRI) && if ((this->putAwayCooldownTimer == 0) && (this->heldItemAction >= PLAYER_IA_SWORD_KOKIRI) &&
(this->transformation != PLAYER_FORM_FIERCE_DEITY)) { (this->transformation != PLAYER_FORM_FIERCE_DEITY)) {
Player_UseItem(play, this, ITEM_NONE); Player_UseItem(play, this, ITEM_NONE);
} else { } else {
@ -8383,8 +8383,8 @@ void func_8083A794(Player* this, PlayState* play) {
Player_SetAction(play, this, func_8082FBE8(this) ? Player_Action_14 : Player_Action_13, 1); Player_SetAction(play, this, func_8082FBE8(this) ? Player_Action_14 : Player_Action_13, 1);
} }
void func_8083A844(Player* this, PlayState* play, s16 currentYaw) { void func_8083A844(Player* this, PlayState* play, s16 yaw) {
this->yaw = currentYaw; this->yaw = yaw;
this->actor.shape.rot.y = this->yaw; this->actor.shape.rot.y = this->yaw;
func_8083A794(this, play); func_8083A794(this, play);
} }
@ -8560,12 +8560,12 @@ void Player_InitMode_F(PlayState* play, Player* this) {
} }
} }
void func_8083AECC(Player* this, s16 currentYaw, PlayState* play) { void func_8083AECC(Player* this, s16 yaw, PlayState* play) {
Player_SetAction(play, this, Player_Action_6, 1); Player_SetAction(play, this, Player_Action_6, 1);
PlayerAnimation_CopyJointToMorph(play, &this->skelAnime); PlayerAnimation_CopyJointToMorph(play, &this->skelAnime);
this->unk_B38 = 0.0f; this->unk_B38 = 0.0f;
this->unk_B34 = 0.0f; this->unk_B34 = 0.0f;
this->yaw = currentYaw; this->yaw = yaw;
} }
void func_8083AF30(Player* this, PlayState* play) { void func_8083AF30(Player* this, PlayState* play) {
@ -8573,12 +8573,12 @@ void func_8083AF30(Player* this, PlayState* play) {
Player_Anim_PlayLoopMorph(play, this, D_8085BE84[PLAYER_ANIMGROUP_walk][this->modelAnimType]); Player_Anim_PlayLoopMorph(play, this, D_8085BE84[PLAYER_ANIMGROUP_walk][this->modelAnimType]);
} }
void func_8083AF8C(Player* this, s16 currentYaw, PlayState* play) { void func_8083AF8C(Player* this, s16 yaw, PlayState* play) {
Player_SetAction(play, this, Player_Action_15, 1); Player_SetAction(play, this, Player_Action_15, 1);
PlayerAnimation_Change(play, &this->skelAnime, &gPlayerAnim_link_anchor_back_walk, PLAYER_ANIM_NORMAL_SPEED, 0.0f, PlayerAnimation_Change(play, &this->skelAnime, &gPlayerAnim_link_anchor_back_walk, PLAYER_ANIM_NORMAL_SPEED, 0.0f,
Animation_GetLastFrame(&gPlayerAnim_link_anchor_back_walk), ANIMMODE_ONCE, -6.0f); Animation_GetLastFrame(&gPlayerAnim_link_anchor_back_walk), ANIMMODE_ONCE, -6.0f);
this->speedXZ = 8.0f; this->speedXZ = 8.0f;
this->yaw = currentYaw; this->yaw = yaw;
} }
void func_8083B030(Player* this, PlayState* play) { void func_8083B030(Player* this, PlayState* play) {
@ -8592,11 +8592,14 @@ void func_8083B090(Player* this, PlayState* play) {
PlayerAnimation_PlayOnceSetSpeed(play, &this->skelAnime, &gPlayerAnim_link_anchor_back_brake, 6.0f / 3.0f); PlayerAnimation_PlayOnceSetSpeed(play, &this->skelAnime, &gPlayerAnim_link_anchor_back_brake, 6.0f / 3.0f);
} }
void func_8083B0E4(PlayState* play, Player* this, s16 currentYaw) { void Player_SetupTurnInPlace(PlayState* play, Player* this, s16 yaw) {
this->yaw = currentYaw; this->yaw = yaw;
Player_SetAction(play, this, Player_Action_10, 1);
this->unk_B4E = 1200; Player_SetAction(play, this, Player_Action_TurnInPlace, 1);
this->unk_B4E *= sWaterSpeedFactor;
this->turnRate = 0x4B0;
this->turnRate *= sWaterSpeedFactor; // slow turn rate by half when in water
PlayerAnimation_Change(play, &this->skelAnime, D_8085BE84[PLAYER_ANIMGROUP_45_turn][this->modelAnimType], PlayerAnimation_Change(play, &this->skelAnime, D_8085BE84[PLAYER_ANIMGROUP_45_turn][this->modelAnimType],
PLAYER_ANIM_NORMAL_SPEED, 0.0f, 0.0f, ANIMMODE_LOOP, -6.0f); PLAYER_ANIM_NORMAL_SPEED, 0.0f, 0.0f, ANIMMODE_LOOP, -6.0f);
} }
@ -8723,11 +8726,11 @@ s32 func_8083B3B4(PlayState* play, Player* this, Input* input) {
return false; return false;
} }
void func_8083B73C(PlayState* play, Player* this, s16 currentYaw) { void func_8083B73C(PlayState* play, Player* this, s16 yaw) {
Player_SetAction(play, this, Player_Action_57, 0); Player_SetAction(play, this, Player_Action_57, 0);
Player_Anim_PlayLoopSlowMorph(play, this, &gPlayerAnim_link_swimer_swim); Player_Anim_PlayLoopSlowMorph(play, this, &gPlayerAnim_link_swimer_swim);
this->actor.shape.rot.y = currentYaw; this->actor.shape.rot.y = yaw;
this->yaw = currentYaw; this->yaw = yaw;
} }
void func_8083B798(PlayState* play, Player* this) { void func_8083B798(PlayState* play, Player* this) {
@ -8870,7 +8873,7 @@ void func_8083BB4C(PlayState* play, Player* this) {
(((Player_Action_56 != this->actionFunc) && !(this->stateFlags3 & PLAYER_STATE3_8000)) || (((Player_Action_56 != this->actionFunc) && !(this->stateFlags3 & PLAYER_STATE3_8000)) ||
(this->actor.bgCheckFlags & BGCHECKFLAG_GROUND))) { (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND))) {
if (this->skelAnime.moveFlags == 0) { if (this->skelAnime.moveFlags == 0) {
func_8083B0E4(play, this, this->actor.shape.rot.y); Player_SetupTurnInPlace(play, this, this->actor.shape.rot.y);
} }
func_8083B32C(play, this, this->actor.velocity.y); func_8083B32C(play, this, this->actor.velocity.y);
} }
@ -11421,10 +11424,12 @@ void Player_SetDoAction(PlayState* play, Player* this) {
} }
if (doActionA != DO_ACTION_PUTAWAY) { if (doActionA != DO_ACTION_PUTAWAY) {
this->putAwayCountdown = 20; this->putAwayCooldownTimer = 20;
} else if (this->putAwayCountdown != 0) { } else if (this->putAwayCooldownTimer != 0) {
// Replace the "Put Away" Do Action label with a blank label while
// the cooldown timer is counting down
doActionA = DO_ACTION_NONE; doActionA = DO_ACTION_NONE;
this->putAwayCountdown--; this->putAwayCooldownTimer--;
} }
Interface_SetAButtonDoAction(play, doActionA); Interface_SetAButtonDoAction(play, doActionA);
@ -14157,7 +14162,7 @@ void Player_Action_3(Player* this, PlayState* play) {
s16 temp_v0_2 = yawTarget - this->actor.shape.rot.y; s16 temp_v0_2 = yawTarget - this->actor.shape.rot.y;
if (ABS_ALT(temp_v0_2) > 0x320) { if (ABS_ALT(temp_v0_2) > 0x320) {
func_8083B0E4(play, this, yawTarget); Player_SetupTurnInPlace(play, this, yawTarget);
} }
} }
} }
@ -14228,7 +14233,7 @@ void Player_Action_Idle(Player* this, PlayState* play) {
yawDiff = yawTarget - this->actor.shape.rot.y; yawDiff = yawTarget - this->actor.shape.rot.y;
if (ABS_ALT(yawDiff) > 0x320) { if (ABS_ALT(yawDiff) > 0x320) {
func_8083B0E4(play, this, yawTarget); Player_SetupTurnInPlace(play, this, yawTarget);
} else { } else {
Math_ScaledStepToS(&this->actor.shape.rot.y, yawTarget, 0x4B0); Math_ScaledStepToS(&this->actor.shape.rot.y, yawTarget, 0x4B0);
this->yaw = this->actor.shape.rot.y; this->yaw = this->actor.shape.rot.y;
@ -14455,7 +14460,14 @@ void Player_Action_9(Player* this, PlayState* play) {
} }
} }
void Player_Action_10(Player* this, PlayState* play) { /**
* Turn in place until the angle pointed to by the control stick is reached.
*
* This is the state that the speedrunning community refers to as "ESS" or "ESS Position".
* See the bug comment below and https://www.zeldaspeedruns.com/mm/tech/ess-and-hess
* for more information.
*/
void Player_Action_TurnInPlace(Player* this, PlayState* play) {
f32 speedTarget; f32 speedTarget;
s16 yawTarget; s16 yawTarget;
@ -14469,18 +14481,26 @@ void Player_Action_10(Player* this, PlayState* play) {
Player_GetMovementSpeedAndYaw(this, &speedTarget, &yawTarget, SPEED_MODE_CURVED, play); Player_GetMovementSpeedAndYaw(this, &speedTarget, &yawTarget, SPEED_MODE_CURVED, play);
//! @bug This action does not handle xzSpeed in any capacity.
//! Player's current speed value will be maintained the entire time this action is running.
//! This is the core bug that allows many different glitches to manifest.
//!
//! One possible fix is to kill all speed instantly in `Player_SetupTurnInPlace`.
//! Another possible fix is to gradually kill speed by calling `Player_DecelerateToZero`
//! here, which plenty of other "standing" actions do.
if ((this != GET_PLAYER(play)) && (this->focusActor == NULL)) { if ((this != GET_PLAYER(play)) && (this->focusActor == NULL)) {
yawTarget = this->actor.home.rot.y; yawTarget = this->actor.home.rot.y;
} }
if (Player_TryActionHandlerList(play, this, sActionHandlerList6, true)) { if (Player_TryActionHandlerList(play, this, sActionHandlerListTurnInPlace, true)) {
return; return;
} }
if (speedTarget != 0.0f) { if (speedTarget != 0.0f) {
this->actor.shape.rot.y = yawTarget; this->actor.shape.rot.y = yawTarget;
func_8083A794(this, play); func_8083A794(this, play);
} else if (Math_ScaledStepToS(&this->actor.shape.rot.y, yawTarget, this->unk_B4E)) { } else if (Math_ScaledStepToS(&this->actor.shape.rot.y, yawTarget, this->turnRate)) {
func_80839E74(this, play); func_80839E74(this, play);
} }
this->yaw = this->actor.shape.rot.y; this->yaw = this->actor.shape.rot.y;
@ -20841,7 +20861,7 @@ s32 Player_TryCsAction(PlayState* play, Player* this, PlayerCsAction csAction) {
// Specific to Kafei, any negative csAction works // Specific to Kafei, any negative csAction works
if ((this->actor.id == ACTOR_EN_TEST3) && (csAction < 0)) { if ((this->actor.id == ACTOR_EN_TEST3) && (csAction < 0)) {
// PLAYER_CSACTION_NEG1 // PLAYER_CSACTION_NEG1
func_8083B0E4(play, this, this->actor.home.rot.y); Player_SetupTurnInPlace(play, this, this->actor.home.rot.y);
return false; return false;
} }

View File

@ -4510,7 +4510,7 @@
0x8083AF8C:("func_8083AF8C",), 0x8083AF8C:("func_8083AF8C",),
0x8083B030:("func_8083B030",), 0x8083B030:("func_8083B030",),
0x8083B090:("func_8083B090",), 0x8083B090:("func_8083B090",),
0x8083B0E4:("func_8083B0E4",), 0x8083B0E4:("Player_SetupTurnInPlace",),
0x8083B1A0:("func_8083B1A0",), 0x8083B1A0:("func_8083B1A0",),
0x8083B23C:("func_8083B23C",), 0x8083B23C:("func_8083B23C",),
0x8083B29C:("func_8083B29C",), 0x8083B29C:("func_8083B29C",),
@ -4671,7 +4671,7 @@
0x8084A794:("Player_Action_7",), 0x8084A794:("Player_Action_7",),
0x8084A884:("Player_Action_8",), 0x8084A884:("Player_Action_8",),
0x8084A8E8:("Player_Action_9",), 0x8084A8E8:("Player_Action_9",),
0x8084AB4C:("Player_Action_10",), 0x8084AB4C:("Player_Action_TurnInPlace",),
0x8084AC84:("Player_Action_11",), 0x8084AC84:("Player_Action_11",),
0x8084AEEC:("Player_Action_12",), 0x8084AEEC:("Player_Action_12",),
0x8084AF9C:("Player_Action_13",), 0x8084AF9C:("Player_Action_13",),

View File

@ -4854,7 +4854,7 @@
0x8085CFF8:("sActionHandlerList3","UNK_TYPE1","",0x1), 0x8085CFF8:("sActionHandlerList3","UNK_TYPE1","",0x1),
0x8085D004:("sActionHandlerList4","UNK_TYPE1","",0x1), 0x8085D004:("sActionHandlerList4","UNK_TYPE1","",0x1),
0x8085D00C:("sActionHandlerList5","UNK_TYPE1","",0x1), 0x8085D00C:("sActionHandlerList5","UNK_TYPE1","",0x1),
0x8085D018:("sActionHandlerList6","UNK_TYPE1","",0x1), 0x8085D018:("sActionHandlerListTurnInPlace","UNK_TYPE1","",0x1),
0x8085D01C:("sActionHandlerListIdle","UNK_TYPE1","",0x1), 0x8085D01C:("sActionHandlerListIdle","UNK_TYPE1","",0x1),
0x8085D028:("sActionHandlerList8","UNK_TYPE1","",0x1), 0x8085D028:("sActionHandlerList8","UNK_TYPE1","",0x1),
0x8085D034:("sActionHandlerList9","UNK_TYPE1","",0x1), 0x8085D034:("sActionHandlerList9","UNK_TYPE1","",0x1),