Hookifying Various Cheats and FixVineFall (#6827)

This commit is contained in:
Chris
2026-06-30 00:10:56 -04:00
committed by GitHub
parent 1fd3a467cd
commit c5835669fe
11 changed files with 199 additions and 58 deletions
@@ -0,0 +1,10 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
static void RegisterClimbEverything() {
COND_VB_SHOULD(VB_SURFACE_IS_CLIMBABLE, CVarGetInteger(CVAR_CHEAT("ClimbEverything"), 0), { *should = true; });
COND_VB_SHOULD(VB_SURFACE_ANGLE_IS_CLIMBABLE, CVarGetInteger(CVAR_CHEAT("ClimbEverything"), 0),
{ *should = true; });
}
static RegisterShipInitFunc initFunc(RegisterClimbEverything, { CVAR_CHEAT("ClimbEverything") });
@@ -0,0 +1,8 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
static void RegisterFireproofDekuShield() {
COND_VB_SHOULD(VB_BURN_SHIELD, CVarGetInteger(CVAR_CHEAT("FireproofDekuShield"), 0), { *should = false; });
}
static RegisterShipInitFunc initFunc(RegisterFireproofDekuShield, { CVAR_CHEAT("FireproofDekuShield") });
@@ -0,0 +1,8 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
static void RegisterHookshotEverything() {
COND_VB_SHOULD(VB_SURFACE_IS_HOOKSHOT, CVarGetInteger(CVAR_CHEAT("HookshotEverything"), 0), { *should = true; });
}
static RegisterShipInitFunc initFunc(RegisterHookshotEverything, { CVAR_CHEAT("HookshotEverything") });
@@ -0,0 +1,10 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
static void RegisterInfiniteEponaBoost() {
COND_VB_SHOULD(VB_CONSUME_EPONA_BOOST, CVarGetInteger(CVAR_CHEAT("InfiniteEponaBoost"), 0), { *should = false; });
COND_VB_SHOULD(VB_DRAW_EPONA_BOOST_CARROTS, CVarGetInteger(CVAR_CHEAT("InfiniteEponaBoost"), 0),
{ *should = false; });
}
static RegisterShipInitFunc initFunc(RegisterInfiniteEponaBoost, { CVAR_CHEAT("InfiniteEponaBoost") });
+13
View File
@@ -0,0 +1,13 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
static void RegisterNoClip() {
COND_VB_SHOULD(VB_PERFORM_WALL_COLLISION_CHECK, CVarGetInteger(CVAR_CHEAT("NoClip"), 0), {
Actor* actor = va_arg(args, Actor*);
if (actor != NULL && actor->id == ACTOR_PLAYER) {
*should = false;
}
});
}
static RegisterShipInitFunc initFunc(RegisterNoClip, { CVAR_CHEAT("NoClip") });
@@ -0,0 +1,72 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "functions.h"
}
static void RegisterFixVineFall() {
// conflicts arise from these two being enabled at once, and with ClimbEverything on, FixVineFall is redundant
// anyway
COND_VB_SHOULD(
VB_REVALIDATE_CLIMBED_WALL,
CVarGetInteger(CVAR_ENHANCEMENT("FixVineFall"), 0) && !CVarGetInteger(CVAR_CHEAT("ClimbEverything"), 0), {
PlayState* play = va_arg(args, PlayState*);
Player* player = va_arg(args, Player*);
u32* touchedWallFlags = va_arg(args, u32*);
s16* yawDiff = va_arg(args, s16*);
/* 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 touchedWallFlags again and proceed as normal.
*/
if (*touchedWallFlags & 8) {
Vec3f checkPosA;
Vec3f checkPosB;
Vec3f raycastResult;
CollisionPoly* wallPoly;
s32 wallBgId;
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 yawDiff 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(player->actor.wallYaw - (*yawDiff / 2) + 0x8000);
yawSin = Math_SinS(player->actor.wallYaw - (*yawDiff / 2) + 0x8000);
checkPosA.x = player->actor.world.pos.x + (-20.0f * yawSin);
checkPosA.z = player->actor.world.pos.z + (-20.0f * yawCos);
checkPosB.x = player->actor.world.pos.x + (50.0f * yawSin);
checkPosB.z = player->actor.world.pos.z + (50.0f * yawCos);
checkPosB.y = checkPosA.y = player->actor.world.pos.y + 26.0f;
hitWall = BgCheck_EntityLineTest1(&play->colCtx, &checkPosA, &checkPosB, &raycastResult, &wallPoly,
true, false, false, true, &wallBgId);
if (hitWall) {
player->actor.wallPoly = wallPoly;
player->actor.wallBgId = wallBgId;
player->actor.wallYaw = Math_Atan2S(wallPoly->normal.z, wallPoly->normal.x);
*yawDiff = player->actor.shape.rot.y - (s16)(player->actor.wallYaw + 0x8000);
*touchedWallFlags = func_80041DB8(&play->colCtx, player->actor.wallPoly, player->actor.wallBgId);
}
}
});
}
static RegisterShipInitFunc initFunc(RegisterFixVineFall,
{ CVAR_ENHANCEMENT("FixVineFall"), CVAR_CHEAT("ClimbEverything") });
@@ -285,6 +285,14 @@ typedef enum {
// - `*EnPoField`
VB_BOTTLE_BIG_POE,
// #### `result`
// ```c
// this->currentShield == PLAYER_SHIELD_DEKU
// ```
// #### `args`
// - `*Player`
VB_BURN_SHIELD,
// #### `result`
// ```c
// true
@@ -367,6 +375,14 @@ typedef enum {
// - None
VB_CLOSE_PAUSE_MENU,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*EnHorse`
VB_CONSUME_EPONA_BOOST,
// #### `result`
// ```c
// true
@@ -612,6 +628,14 @@ typedef enum {
// - `*int16_t` (item id)
VB_DRAW_AMMO_COUNT,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_DRAW_EPONA_BOOST_CARROTS,
// #### `args`
// - `Player*` player
// - `PlayState*` play
@@ -1642,6 +1666,14 @@ typedef enum {
// - `*EnOwl`
VB_OWL_INTERACTION,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*Actor`
VB_PERFORM_WALL_COLLISION_CHECK,
// #### `result`
// ```c
// true
@@ -2145,6 +2177,17 @@ typedef enum {
// - `**Gfx` (`&POLY_OPA_DISP`)
VB_RENDER_YES_ON_CONTINUE_PROMPT,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*PlayState`
// - `*Player`
// - `*u32`
// - `*s16`
VB_REVALIDATE_CLIMBED_WALL,
// #### `result`
// ```c
// true
@@ -2488,6 +2531,30 @@ typedef enum {
// - `*BgIceTurara`
VB_STALAGMITE_DROP_ITEM,
// #### `result`
// ```c
// ABS(wallPoly->normal.y) < 600
// ```
// #### `args`
// - None
VB_SURFACE_ANGLE_IS_CLIMBABLE,
// #### `result`
// ```c
// false
// ```
// #### `args`
// - None
VB_SURFACE_IS_CLIMBABLE,
// #### `result`
// ```c
// SurfaceType_GetData(colCtx, poly, bgId, 1) >> 17 & 1
// ```
// #### `args`
// - None
VB_SURFACE_IS_HOOKSHOT,
// #### `result`
// ```c
// varies, never set should to true
+4 -3
View File
@@ -3,6 +3,7 @@
#include "soh/OTRGlobals.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include <assert.h>
#define SS_NULL 0xFFFF
@@ -1892,7 +1893,7 @@ s32 BgCheck_CheckWallImpl(CollisionContext* colCtx, u16 xpFlags, Vec3f* posResul
s32 bgId2;
f32 nx, ny, nz; // unit normal of polygon
if (CVarGetInteger(CVAR_CHEAT("NoClip"), 0) && actor != NULL && actor->id == ACTOR_PLAYER) {
if (!GameInteractor_Should(VB_PERFORM_WALL_COLLISION_CHECK, true, actor)) {
return false;
}
@@ -4011,7 +4012,7 @@ u32 func_80041D94(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
* SurfaceType Get Wall Flags
*/
s32 func_80041DB8(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
if (CVarGetInteger(CVAR_CHEAT("ClimbEverything"), 0) != 0) {
if (GameInteractor_Should(VB_SURFACE_IS_CLIMBABLE, false)) {
return (1 << 3) | D_80119D90[func_80041D94(colCtx, poly, bgId)];
} else {
return D_80119D90[func_80041D94(colCtx, poly, bgId)];
@@ -4108,7 +4109,7 @@ u32 SurfaceType_GetEcho(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId)
* SurfaceType Is Hookshot Surface
*/
u32 SurfaceType_IsHookshotSurface(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
return CVarGetInteger(CVAR_CHEAT("HookshotEverything"), 0) || SurfaceType_GetData(colCtx, poly, bgId, 1) >> 17 & 1;
return GameInteractor_Should(VB_SURFACE_IS_HOOKSHOT, SurfaceType_GetData(colCtx, poly, bgId, 1) >> 17 & 1);
}
/**
+1 -1
View File
@@ -5776,7 +5776,7 @@ void Interface_Draw(PlayState* play) {
if ((play->pauseCtx.state == 0) && (play->pauseCtx.debugState == 0)) {
if (gSaveContext.minigameState != 1) {
// Carrots rendering if the action corresponds to riding a horse
if (interfaceCtx->unk_1EE == 8 && !CVarGetInteger(CVAR_CHEAT("InfiniteEponaBoost"), 0)) {
if (interfaceCtx->unk_1EE == 8 && GameInteractor_Should(VB_DRAW_EPONA_BOOST_CARROTS, true)) {
// Load Carrot Icon
gDPLoadTextureBlock(OVERLAY_DISP++, gCarrotIconTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
@@ -9,6 +9,7 @@
#include "objects/object_horse/object_horse.h"
#include "objects/object_hni/object_hni.h"
#include "scenes/overworld/spot09/spot09_scene.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include <assert.h>
#define FLAGS ACTOR_FLAG_UPDATE_CULLING_DISABLED
@@ -3332,7 +3333,7 @@ void EnHorse_CheckBoost(EnHorse* thisx, PlayState* play2) {
this->stateFlags |= ENHORSE_BOOST;
this->stateFlags |= ENHORSE_FIRST_BOOST_REGEN;
this->stateFlags |= ENHORSE_FLAG_8;
if (!CVarGetInteger(CVAR_CHEAT("InfiniteEponaBoost"), 0)) {
if (GameInteractor_Should(VB_CONSUME_EPONA_BOOST, true, this)) {
this->numBoosts--;
}
this->boostTimer = 0;
@@ -4681,7 +4681,7 @@ int func_8083816C(s32 arg0) {
}
void func_8083819C(Player* this, PlayState* play) {
if (this->currentShield == PLAYER_SHIELD_DEKU && (CVarGetInteger(CVAR_CHEAT("FireproofDekuShield"), 0) == 0)) {
if (GameInteractor_Should(VB_BURN_SHIELD, this->currentShield == PLAYER_SHIELD_DEKU, this)) {
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_SHIELD, this->actor.world.pos.x, this->actor.world.pos.y,
this->actor.world.pos.z, 0, 0, 0, 1);
Inventory_DeleteEquipment(play, EQUIP_TYPE_SHIELD);
@@ -5705,7 +5705,7 @@ s32 func_8083A6AC(Player* this, PlayState* play) {
if (BgCheck_EntityLineTest1(&play->colCtx, &this->actor.world.pos, &sp74, &sp68, &sp84, true, false, false,
true, &sp80) &&
((ABS(sp84->normal.y) < 600) || (CVarGetInteger(CVAR_CHEAT("ClimbEverything"), 0) != 0))) {
GameInteractor_Should(VB_SURFACE_ANGLE_IS_CLIMBABLE, ABS(sp84->normal.y) < 600)) {
f32 nx = COLPOLY_GET_NORMAL(sp84->normal.x);
f32 ny = COLPOLY_GET_NORMAL(sp84->normal.y);
f32 nz = COLPOLY_GET_NORMAL(sp84->normal.z);
@@ -11305,56 +11305,7 @@ void Player_ProcessSceneCollision(PlayState* play, Player* this) {
sTouchedWallFlags = func_80041DB8(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId);
// conflicts arise from these two being enabled at once, and with ClimbEverything on, FixVineFall is redundant
// anyway
if (CVarGetInteger(CVAR_ENHANCEMENT("FixVineFall"), 0) && !CVarGetInteger(CVAR_CHEAT("ClimbEverything"), 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 sTouchedWallFlags again and proceed as normal.
*/
if (sTouchedWallFlags & 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 yawDiff 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 - (yawDiff / 2) + 0x8000);
yawSin = Math_SinS(this->actor.wallYaw - (yawDiff / 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, &sInteractWallCheckResult,
&wallPoly, true, false, false, true, &wallBgId);
if (hitWall) {
this->actor.wallPoly = wallPoly;
this->actor.wallBgId = wallBgId;
this->actor.wallYaw = Math_Atan2S(wallPoly->normal.z, wallPoly->normal.x);
yawDiff = this->actor.shape.rot.y - (s16)(this->actor.wallYaw + 0x8000);
sTouchedWallFlags = func_80041DB8(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId);
}
}
}
GameInteractor_Should(VB_REVALIDATE_CLIMBED_WALL, true, play, this, &sTouchedWallFlags, &yawDiff);
sShapeYawToTouchedWall = ABS(yawDiff);
@@ -11380,7 +11331,7 @@ void Player_ProcessSceneCollision(PlayState* play, Player* this) {
if ((this->actor.bgCheckFlags & 0x200) && (sShapeYawToTouchedWall < 0x3000)) {
CollisionPoly* wallPoly = this->actor.wallPoly;
if (ABS(wallPoly->normal.y) < 600 || (CVarGetInteger(CVAR_CHEAT("ClimbEverything"), 0) != 0)) {
if (GameInteractor_Should(VB_SURFACE_ANGLE_IS_CLIMBABLE, ABS(wallPoly->normal.y) < 600)) {
f32 wallPolyNormalX = COLPOLY_GET_NORMAL(wallPoly->normal.x);
f32 wallPolyNormalY = COLPOLY_GET_NORMAL(wallPoly->normal.y);
f32 wallPolyNormalZ = COLPOLY_GET_NORMAL(wallPoly->normal.z);