mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-10-02 12:26:26 -04:00
Hookify FP movement (#7189)
Apply consistent movement effects to first person movement
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "global.h"
|
||||
extern PlayState* gPlayState;
|
||||
void func_8083DF68(Player* player, f32 arg1, s16 arg2);
|
||||
void func_8084029C(Player* player, f32 arg1);
|
||||
s32 Player_GetMovementSpeedAndYaw(Player* player, f32* outSpeedTarget, s16* outYawTarget, f32 speedMode,
|
||||
PlayState* play);
|
||||
}
|
||||
|
||||
#define CVAR_MOVE_IN_FIRST_PERSON_NAME CVAR_SETTING("MoveInFirstPerson")
|
||||
#define CVAR_RIGHT_STICK_AIM_NAME CVAR_SETTING("Controls.RightStickAim")
|
||||
|
||||
// from z_player.c
|
||||
#define SPEED_MODE_CURVED 0.018f
|
||||
|
||||
static void MoveInFirstPerson(Player* player) {
|
||||
f32 speedTarget;
|
||||
s16 yawTarget;
|
||||
|
||||
// Normal movement ignores the stick while unk_6AD says Link is in first person
|
||||
uint8_t firstPersonMode = player->unk_6AD;
|
||||
player->unk_6AD = 0;
|
||||
bool moving = Player_GetMovementSpeedAndYaw(player, &speedTarget, &yawTarget, SPEED_MODE_CURVED, gPlayState);
|
||||
player->unk_6AD = firstPersonMode;
|
||||
|
||||
if ((player->stateFlags1 & PLAYER_STATE1_IN_WATER) && (player->currentBoots != PLAYER_BOOTS_IRON)) {
|
||||
// Swim speed cap from func_8084AEEC. Its speed step only runs on swim stroke frames, so it isn't used here.
|
||||
f32 swimSpeed = R_RUN_SPEED_LIMIT / 100.0f * 0.8f;
|
||||
GameInteractor_Should(VB_PLAYER_MODIFY_SWIM_SPEED, true, player, &swimSpeed, true);
|
||||
speedTarget = CLAMP_MAX(speedTarget, swimSpeed);
|
||||
} else {
|
||||
GameInteractor_Should(VB_PLAYER_MODIFY_FIRST_PERSON_SPEED, true, player, &speedTarget);
|
||||
}
|
||||
|
||||
// Turn instantly so strafing feels direct
|
||||
if (moving) {
|
||||
player->yaw = yawTarget;
|
||||
}
|
||||
func_8083DF68(player, speedTarget, player->yaw);
|
||||
|
||||
if (!(player->stateFlags1 & PLAYER_STATE1_IN_WATER) && (player->linearVelocity > 0.0f)) {
|
||||
func_8084029C(player, (REG(30) / 1000.0f) + ((REG(32) / 1000.0f) * player->linearVelocity));
|
||||
}
|
||||
}
|
||||
|
||||
static void RegisterFirstPerson() {
|
||||
bool moveInFirstPerson =
|
||||
CVarGetInteger(CVAR_MOVE_IN_FIRST_PERSON_NAME, 0) && CVarGetInteger(CVAR_RIGHT_STICK_AIM_NAME, 0);
|
||||
|
||||
// Left stick moves instead of aiming; right stick aims
|
||||
COND_VB_SHOULD(VB_PLAYER_AIM_WITH_LEFT_STICK, moveInFirstPerson, { *should = false; });
|
||||
|
||||
COND_VB_SHOULD(VB_PLAYER_FIRST_PERSON_DECELERATE, moveInFirstPerson, {
|
||||
Player* player = va_arg(args, Player*);
|
||||
MoveInFirstPerson(player);
|
||||
*should = false;
|
||||
});
|
||||
|
||||
// Keep moving where stick points rather than where Link faces. Once stopped, face forward as normal.
|
||||
COND_VB_SHOULD(VB_PLAYER_FIRST_PERSON_ALIGN_YAW, moveInFirstPerson, {
|
||||
Player* player = va_arg(args, Player*);
|
||||
if (player->linearVelocity != 0.0f) {
|
||||
*should = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(RegisterFirstPerson,
|
||||
{ CVAR_MOVE_IN_FIRST_PERSON_NAME, CVAR_RIGHT_STICK_AIM_NAME });
|
||||
@@ -2323,6 +2323,15 @@ typedef enum {
|
||||
// - `*DemoIm`
|
||||
VB_PLAY_ZELDAS_LULLABY_CS,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
// ```
|
||||
// Whether the left stick aims in first person. Off when it moves Link instead.
|
||||
// #### `args`
|
||||
// - `*Player`
|
||||
VB_PLAYER_AIM_WITH_LEFT_STICK,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
@@ -2342,6 +2351,24 @@ typedef enum {
|
||||
// - `PlayState*` play
|
||||
VB_PLAYER_DRAW_BOTTLE,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
// ```
|
||||
// Whether Link's movement direction is set to where he faces in first person.
|
||||
// #### `args`
|
||||
// - `*Player`
|
||||
VB_PLAYER_FIRST_PERSON_ALIGN_YAW,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
// ```
|
||||
// Whether Link slows to a stop in first person. Hooks may set his speed instead.
|
||||
// #### `args`
|
||||
// - `*Player`
|
||||
VB_PLAYER_FIRST_PERSON_DECELERATE,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
|
||||
@@ -12582,8 +12582,7 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
|
||||
|
||||
if (!func_8002DD78(this) && !func_808334B4(this) && (arg2 == 0)) { // First person without weapon
|
||||
// Y Axis
|
||||
if (!(CVarGetInteger(CVAR_SETTING("MoveInFirstPerson"), 0) &&
|
||||
CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0))) {
|
||||
if (GameInteractor_Should(VB_PLAYER_AIM_WITH_LEFT_STICK, true, this)) {
|
||||
temp2 += sControlInput->rel.stick_y * 240.0f * invertYAxisMulti * yAxisMulti;
|
||||
}
|
||||
if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) {
|
||||
@@ -12601,8 +12600,7 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
|
||||
|
||||
// X Axis
|
||||
temp2 = 0;
|
||||
if (!(CVarGetInteger(CVAR_SETTING("MoveInFirstPerson"), 0) &&
|
||||
CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0))) {
|
||||
if (GameInteractor_Should(VB_PLAYER_AIM_WITH_LEFT_STICK, true, this)) {
|
||||
temp2 += sControlInput->rel.stick_x * -16.0f * invertXAxisMulti * xAxisMulti;
|
||||
}
|
||||
if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) {
|
||||
@@ -12617,8 +12615,7 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
|
||||
// Y Axis
|
||||
temp1 = (this->stateFlags1 & PLAYER_STATE1_ON_HORSE) ? 3500 : 14000;
|
||||
|
||||
if (!(CVarGetInteger(CVAR_SETTING("MoveInFirstPerson"), 0) &&
|
||||
CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0))) {
|
||||
if (GameInteractor_Should(VB_PLAYER_AIM_WITH_LEFT_STICK, true, this)) {
|
||||
temp3 += ((sControlInput->rel.stick_y >= 0) ? 1 : -1) *
|
||||
(s32)((1.0f - Math_CosS(sControlInput->rel.stick_y * 200)) * 1500.0f) * invertYAxisMulti *
|
||||
yAxisMulti;
|
||||
@@ -12638,8 +12635,7 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
|
||||
temp1 = 19114;
|
||||
temp2 = this->actor.focus.rot.y - this->actor.shape.rot.y;
|
||||
temp3 = 0;
|
||||
if (!(CVarGetInteger(CVAR_SETTING("MoveInFirstPerson"), 0) &&
|
||||
CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0))) {
|
||||
if (GameInteractor_Should(VB_PLAYER_AIM_WITH_LEFT_STICK, true, this)) {
|
||||
temp3 = ((sControlInput->rel.stick_x >= 0) ? 1 : -1) *
|
||||
(s32)((1.0f - Math_CosS(sControlInput->rel.stick_x * 200)) * -1500.0f) * invertXAxisMulti *
|
||||
xAxisMulti;
|
||||
@@ -12656,34 +12652,6 @@ s16 func_8084ABD8(PlayState* play, Player* this, s32 arg2, s16 arg3) {
|
||||
this->actor.focus.rot.y = CLAMP(temp2, -temp1, temp1) + this->actor.shape.rot.y;
|
||||
}
|
||||
|
||||
if (CVarGetInteger(CVAR_SETTING("MoveInFirstPerson"), 0) &&
|
||||
CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) {
|
||||
f32 movementSpeed = LINK_IS_ADULT ? 9.0f : 8.25f;
|
||||
GameInteractor_Should(VB_PLAYER_MODIFY_FIRST_PERSON_SPEED, true, this, &movementSpeed);
|
||||
|
||||
f32 relX =
|
||||
(sControlInput->rel.stick_x * (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? 1 : -1)) / 10.0f;
|
||||
f32 relY = sControlInput->rel.stick_y / 10.0f;
|
||||
|
||||
// Normalize so that diagonal movement isn't faster
|
||||
f32 relMag = sqrtf((relX * relX) + (relY * relY));
|
||||
if (relMag > 1.0f) {
|
||||
relX /= relMag;
|
||||
relY /= relMag;
|
||||
}
|
||||
|
||||
// Determine what left and right mean based on camera angle
|
||||
f32 relX2 = relX * Math_CosS(this->actor.focus.rot.y) + relY * Math_SinS(this->actor.focus.rot.y);
|
||||
f32 relY2 = relY * Math_CosS(this->actor.focus.rot.y) - relX * Math_SinS(this->actor.focus.rot.y);
|
||||
|
||||
// Calculate distance for footstep sound
|
||||
f32 distance = sqrtf((relX2 * relX2) + (relY2 * relY2)) * movementSpeed;
|
||||
func_8084029C(this, distance / 4.5f);
|
||||
|
||||
this->actor.world.pos.x += (relX2 * movementSpeed) + this->actor.colChkInfo.displacement.x;
|
||||
this->actor.world.pos.z += (relY2 * movementSpeed) + this->actor.colChkInfo.displacement.z;
|
||||
}
|
||||
|
||||
this->unk_6AE_rotFlags |= UNK6AE_ROT_FOCUS_Y;
|
||||
return func_80836AB8(this, (play->shootingGalleryStatus != 0) || func_8002DD78(this) || func_808334B4(this)) - arg3;
|
||||
}
|
||||
@@ -12809,8 +12777,10 @@ void func_8084B158(PlayState* play, Player* this, Input* input, f32 arg3) {
|
||||
void Player_Action_8084B1D8(Player* this, PlayState* play) {
|
||||
if (this->stateFlags1 & PLAYER_STATE1_IN_WATER) {
|
||||
func_8084B000(this);
|
||||
func_8084AEEC(this, &this->linearVelocity, 0, this->actor.shape.rot.y);
|
||||
} else {
|
||||
if (GameInteractor_Should(VB_PLAYER_FIRST_PERSON_DECELERATE, true, this)) {
|
||||
func_8084AEEC(this, &this->linearVelocity, 0, this->actor.shape.rot.y);
|
||||
}
|
||||
} else if (GameInteractor_Should(VB_PLAYER_FIRST_PERSON_DECELERATE, true, this)) {
|
||||
Player_DecelerateToZero(this);
|
||||
}
|
||||
|
||||
@@ -12838,7 +12808,9 @@ void Player_Action_8084B1D8(Player* this, PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
this->yaw = this->actor.shape.rot.y;
|
||||
if (GameInteractor_Should(VB_PLAYER_FIRST_PERSON_ALIGN_YAW, true, this)) {
|
||||
this->yaw = this->actor.shape.rot.y;
|
||||
}
|
||||
}
|
||||
|
||||
s32 func_8084B3CC(PlayState* play, Player* this) {
|
||||
|
||||
Reference in New Issue
Block a user