From 127f2651df145f1ded52ced4f6cd1d7d47c66132 Mon Sep 17 00:00:00 2001 From: krm01 Date: Sun, 5 Nov 2023 10:07:44 -0800 Subject: [PATCH] vanilla bugfix for wall climbing on edge of polys (#3358) * vanilla bugfix for wall climbing on edge of polys * rename missed vars * add CVar toggle --- soh/soh/SohMenuBar.cpp | 2 + .../actors/ovl_player_actor/z_player.c | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index dd202d02a..fb2ef050d 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -1047,6 +1047,8 @@ void DrawEnhancementsMenu() { "Fixes an incorrect calculation that acted like water underneath ground was above it."); UIWidgets::PaddedEnhancementCheckbox("Fix Bush Item Drops", "gBushDropFix", true, false); UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items."); + UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); + UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); ImGui::EndMenu(); } diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 556b8ccd5..09e33f2e4 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -10101,6 +10101,55 @@ void func_80847BA0(PlayState* play, Player* this) { D_808535F0 = func_80041DB8(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId); + if (CVarGetInteger("gFixVineFall", 0)) { + /* This fixes the "started climbing a wall and then immediately fell off" bug. + * The main idea is if a climbing wall is detected, double-check that it will + * still be valid once climbing begins by doing a second raycast with a small + * margin to make sure it still hits a climbable poly. Then update the flags + * in D_808535F0 again and proceed as normal. + */ + if (D_808535F0 & 8) { + Vec3f checkPosA; + Vec3f checkPosB; + f32 yawCos; + f32 yawSin; + s32 hitWall; + + /* Angle the raycast slightly out towards the side based on the angle of + * attack the player takes coming at the climb wall. This is necessary because + * the player's XZ position actually wobbles very slightly while climbing + * due to small rounding errors in the sin/cos lookup tables. This wobble + * can cause wall checks while climbing to be slightly left or right of + * the wall check to start the climb. By adding this buffer it accounts for + * any possible wobble. The end result is the player has to be further than + * some epsilon distance from the edge of the climbing poly to actually + * start the climb. I divide it by 2 to make that epsilon slightly smaller, + * mainly for visuals. Using the full sp9A leaves a noticeable gap on + * the edges that can't be climbed. But with the half distance it looks like + * the player is climbing right on the edge, and still works. + */ + yawCos = Math_CosS(this->actor.wallYaw - (sp9A / 2) + 0x8000); + yawSin = Math_SinS(this->actor.wallYaw - (sp9A / 2) + 0x8000); + checkPosA.x = this->actor.world.pos.x + (-20.0f * yawSin); + checkPosA.z = this->actor.world.pos.z + (-20.0f * yawCos); + checkPosB.x = this->actor.world.pos.x + (50.0f * yawSin); + checkPosB.z = this->actor.world.pos.z + (50.0f * yawCos); + checkPosB.y = checkPosA.y = this->actor.world.pos.y + 26.0f; + + hitWall = BgCheck_EntityLineTest1(&play->colCtx, &checkPosA, &checkPosB, + &D_80858AA8, &spA0, true, false, false, true, &sp9C); + + if (hitWall) { + this->actor.wallPoly = spA0; + this->actor.wallBgId = sp9C; + this->actor.wallYaw = Math_Atan2S(spA0->normal.z, spA0->normal.x); + sp9A = this->actor.shape.rot.y - (s16)(this->actor.wallYaw + 0x8000); + + D_808535F0 = func_80041DB8(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId); + } + } + } + D_80853608 = ABS(sp9A); sp9A = this->currentYaw - (s16)(this->actor.wallYaw + 0x8000);