diff --git a/README.md b/README.md index 894d043474..5b16fcd769 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows: | Alt fire mode | F | RB | L Trigger | | Alt-fire oneshot | `F + LMB` or `E + LMB` | `A + RT` or `RB + RT` | `A + Z` or `L + Z` | | Quick-detonate | `E + Q` or `E + R` | `A + B` or `A + X` | `A + D-Left`or `A + X` | +| Reset Camera / Crosshair | C | RS CLICK | N/A | ## Building diff --git a/port/include/input.h b/port/include/input.h index 6171c26961..37b75e9ff8 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -102,7 +102,7 @@ enum contkey { CK_STICK_YPOS, CK_ACCEPT, CK_CANCEL, - CK_0040, + CK_0040, // Reset Camera/Crosshair action CK_0080, CK_0100, CK_0200, @@ -181,6 +181,9 @@ s32 inputKeyJustPressed(u32 vk); // idx is controller index, contbtn is one of the CONT_ constants s32 inputButtonPressed(s32 idx, u32 contbtn); +// idx is controller index, ck is one of the CK_ constants +s32 inputBindPressed(s32 idx, u32 ck); + // bind virtkey vk to n64 pad #idx's button/axis ck as represented by its contkey value // if bind is -1, picks a bind slot automatically void inputKeyBind(s32 idx, u32 ck, s32 bind, u32 vk); diff --git a/port/src/input.c b/port/src/input.c index 20137358c1..39e608996e 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -208,6 +208,7 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode) { CK_STICK_XPOS, SDL_SCANCODE_RIGHT, 0 }, { CK_STICK_YNEG, SDL_SCANCODE_DOWN, 0 }, { CK_STICK_YPOS, SDL_SCANCODE_UP, 0 }, + { CK_0040, SDL_SCANCODE_C, 0 }, { CK_4000, SDL_SCANCODE_LSHIFT, 0 }, { CK_2000, SDL_SCANCODE_LCTRL, 0 } }; @@ -228,6 +229,7 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode) { CK_C_L, SDL_CONTROLLER_BUTTON_DPAD_LEFT }, { CK_ACCEPT, SDL_CONTROLLER_BUTTON_A }, { CK_CANCEL, SDL_CONTROLLER_BUTTON_B }, + { CK_0040, SDL_CONTROLLER_BUTTON_RIGHTSTICK }, { CK_8000, SDL_CONTROLLER_BUTTON_LEFTSTICK }, }; @@ -752,7 +754,7 @@ s32 inputInit(void) return connectedMask; } -static inline s32 inputBindPressed(const s32 idx, const u32 ck) +s32 inputBindPressed(const s32 idx, const u32 ck) { for (s32 i = 0; i < INPUT_MAX_BINDS; ++i) { if (binds[idx][ck][i]) { diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index 1390598003..5ed0f2335b 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -1651,27 +1651,28 @@ struct menubind { }; static const struct menubind menuBinds[] = { - { CK_ZTRIG, "Fire [ZT]\n", "N64 Z Trigger\n" }, - { CK_LTRIG, "Fire Mode [LT]\n", "N64 L Trigger\n"}, - { CK_RTRIG, "Aim Mode [RT]\n", "N64 R Trigger\n" }, - { CK_A, "Use / Accept [A]\n", "N64 A Button\n" }, - { CK_B, "Use / Cancel [B]\n", "N64 B Button\n" }, - { CK_START, "Pause Menu [ST]\n", "N64 Start\n" }, - { CK_DPAD_U, "D-Pad Up [DU]\n", "N64 D-Pad Up\n" }, - { CK_DPAD_R, "D-Pad Right [DR]\n", "N64 D-Pad Right\n" }, - { CK_DPAD_L, "Prev Weapon [DL]\n", "N64 D-Pad Left\n" }, - { CK_DPAD_D, "Radial Menu [DD]\n", "N64 D-Pad Down\n" }, - { CK_C_U, "Forward [CU]\n", "N64 C-Up\n" }, - { CK_C_D, "Backward [CD]\n", "N64 C-Down\n" }, - { CK_C_R, "Strafe Right [CR]\n", "N64 C-Right\n" }, - { CK_C_L, "Strafe Left [CL]\n", "N64 C-Left\n" }, - { CK_X, "Reload [X]\n", "N64 Ext X\n" }, - { CK_Y, "Next Weapon [Y]\n", "N64 Ext Y\n" }, - { CK_8000, "Cycle Crouch [+]\n", "N64 Ext 8000\n" }, - { CK_4000, "Half Crouch [+]\n", "N64 Ext 4000\n" }, - { CK_2000, "Full Crouch [+]\n", "N64 Ext 2000\n" }, - { CK_ACCEPT, "UI Accept [+]\n", "EXT UI Accept\n" }, - { CK_CANCEL, "UI Cancel [+]\n", "EXT UI Cancel\n" }, + { CK_ZTRIG, "Fire [ZT]\n", "N64 Z Trigger\n" }, + { CK_LTRIG, "Fire Mode [LT]\n", "N64 L Trigger\n" }, + { CK_RTRIG, "Aim Mode [RT]\n", "N64 R Trigger\n" }, + { CK_A, "Use / Accept [A]\n", "N64 A Button\n" }, + { CK_B, "Use / Cancel [B]\n", "N64 B Button\n" }, + { CK_START, "Pause Menu [ST]\n", "N64 Start\n" }, + { CK_DPAD_U, "D-Pad Up [DU]\n", "N64 D-Pad Up\n" }, + { CK_DPAD_R, "D-Pad Right [DR]\n", "N64 D-Pad Right\n" }, + { CK_DPAD_L, "Prev Weapon [DL]\n", "N64 D-Pad Left\n" }, + { CK_DPAD_D, "Radial Menu [DD]\n", "N64 D-Pad Down\n" }, + { CK_C_U, "Forward [CU]\n", "N64 C-Up\n" }, + { CK_C_D, "Backward [CD]\n", "N64 C-Down\n" }, + { CK_C_R, "Strafe Right [CR]\n", "N64 C-Right\n" }, + { CK_C_L, "Strafe Left [CL]\n", "N64 C-Left\n" }, + { CK_X, "Reload [X]\n", "N64 Ext X\n" }, + { CK_Y, "Next Weapon [Y]\n", "N64 Ext Y\n" }, + { CK_8000, "Cycle Crouch [+]\n", "N64 Ext 8000\n" }, + { CK_4000, "Half Crouch [+]\n", "N64 Ext 4000\n" }, + { CK_2000, "Full Crouch [+]\n", "N64 Ext 2000\n" }, + { CK_0040, "Reset Camera/Crosshair [+]\n", "EXT Reset Camera/Crosshair\n" }, + { CK_ACCEPT, "UI Accept [+]\n", "EXT UI Accept\n" }, + { CK_CANCEL, "UI Cancel [+]\n", "EXT UI Cancel\n" }, }; static const char *menutextBind(struct menuitem *item); @@ -1711,6 +1712,7 @@ struct menuitem g_ExtendedBindsMenuItems[] = { DEFINE_MENU_BIND(), DEFINE_MENU_BIND(), DEFINE_MENU_BIND(), + DEFINE_MENU_BIND(), { MENUITEMTYPE_SEPARATOR, 0, diff --git a/src/game/bondmove.c b/src/game/bondmove.c index 548ade1b17..66253ddc0a 100644 --- a/src/game/bondmove.c +++ b/src/game/bondmove.c @@ -468,6 +468,95 @@ static void bmoveApplyCrosshairSwivel(struct movedata *movedata, f32 mlookscale, #endif } +#ifndef PLATFORM_N64 +/** + * Handle camera/crosshair recentering + */ +void bmoveUpdateCameraRecentering(s32 cidx, bool aim_mode, bool offbike) +{ + static bool prev_reset_pressed[MAX_PLAYERS] = {false, false, false, false}; + static struct { + bool active; + float time; + float duration; + } s_crosshair[MAX_PLAYERS] = { + {false, 0.0f, 0.30f}, {false, 0.0f, 0.30f}, + {false, 0.0f, 0.30f}, {false, 0.0f, 0.30f} + }; + static struct { + bool active; + float time; + float start; + float target; + float duration; + } s_camera[MAX_PLAYERS] = { + {false, 0.0f, 0.0f, 0.0f, 0.24f}, {false, 0.0f, 0.0f, 0.0f, 0.24f}, + {false, 0.0f, 0.0f, 0.0f, 0.24f}, {false, 0.0f, 0.0f, 0.0f, 0.24f} + }; + + bool reset_pressed = inputBindPressed(cidx, CK_0040); + + // Start recentering on button press + if (reset_pressed && !prev_reset_pressed[cidx] && g_Vars.currentplayer) { + if (aim_mode) { + if (fabsf(g_Vars.currentplayer->swivelpos[0]) > 0.01f || fabsf(g_Vars.currentplayer->swivelpos[1]) > 0.01f) { + s_crosshair[cidx].active = true; + s_crosshair[cidx].time = 0.0f; + } + } else { + s_camera[cidx].active = true; + s_camera[cidx].time = 0.0f; + s_camera[cidx].start = g_Vars.currentplayer->vv_verta; + s_camera[cidx].target = 0.0f; + g_Vars.currentplayer->docentreupdown = false; + g_Vars.currentplayer->automovecentre = false; + } + } + prev_reset_pressed[cidx] = reset_pressed; + + // Animate crosshair recentering + if (s_crosshair[cidx].active && g_Vars.currentplayer && g_Vars.currentplayer->insightaimmode) { + float t = s_crosshair[cidx].time / s_crosshair[cidx].duration; + if (t > 1.0f) t = 1.0f; + float smooth = t * t * (3.0f - 2.0f * t); + g_Vars.currentplayer->swivelpos[0] *= (1.0f - smooth); + g_Vars.currentplayer->swivelpos[1] *= (1.0f - smooth); + + s_crosshair[cidx].time += g_Vars.lvupdate60freal / 60.0f; + if (s_crosshair[cidx].time >= s_crosshair[cidx].duration || + (fabsf(g_Vars.currentplayer->swivelpos[0]) < 0.01f && fabsf(g_Vars.currentplayer->swivelpos[1]) < 0.01f)) { + g_Vars.currentplayer->swivelpos[0] = 0.0f; + g_Vars.currentplayer->swivelpos[1] = 0.0f; + s_crosshair[cidx].active = false; + } + } + + // Animate camera vertical recentering + if (s_camera[cidx].active && g_Vars.currentplayer) { + float t = s_camera[cidx].time / s_camera[cidx].duration; + if (t > 1.0f) t = 1.0f; + float smooth = t * t * (3.0f - 2.0f * t); + g_Vars.currentplayer->vv_verta = s_camera[cidx].start + (s_camera[cidx].target - s_camera[cidx].start) * smooth; + + s_camera[cidx].time += g_Vars.lvupdate60freal / 60.0f; + if (s_camera[cidx].time >= s_camera[cidx].duration || + fabsf(g_Vars.currentplayer->vv_verta - s_camera[cidx].target) < 0.01f) { + g_Vars.currentplayer->vv_verta = s_camera[cidx].target; + g_Vars.currentplayer->speedverta = 0.0f; + s_camera[cidx].active = false; + } + } +} + +/** + * Check if recentering is active (used to prevent movements) + */ +bool bmoveIsRecenteringActive(s32 cidx) +{ + return false; +} +#endif + /** * Calculate the lookahead angle. * @@ -694,6 +783,7 @@ void bmoveResetMoveData(struct movedata *data) */ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool ignorec2) { + const s32 cidx = g_Vars.currentplayernum; struct movedata movedata; s32 controlmode; s32 weaponnum; @@ -1983,6 +2073,11 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i offbike = g_Vars.currentplayer->bondmovemode == MOVEMODE_WALK || g_Vars.currentplayer->bondmovemode == MOVEMODE_GRAB; +#ifndef PLATFORM_N64 + // Handle camera/crosshair recentering + bmoveUpdateCameraRecentering(cidx, g_Vars.currentplayer->insightaimmode, offbike); +#endif + if (g_Vars.currentplayer->lookaheadcentreenabled) { if (g_Vars.lvframenum != g_Vars.currentplayer->lookaheadframe && g_Vars.currentplayernum == (g_Vars.lvframenum & 3)) { @@ -2084,15 +2179,22 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i #endif g_Vars.currentplayer->speedverta = -fVar25 * tmp; +#ifndef PLATFORM_N64 + // Pause vertical camera input during camera recentering } else if (movedata.speedvertadown > 0) { +#else + } else if (movedata.speedvertadown > 0) { +#endif bmoveUpdateSpeedVerta(movedata.speedvertadown); - if (movedata.canlookahead && (movedata.analogwalk > 60 || movedata.analogwalk < -60)) { g_Vars.currentplayer->movecentrerelease = true; } +#ifndef PLATFORM_N64 } else if (movedata.speedvertaup > 0) { +#else + } else if (movedata.speedvertaup > 0) { +#endif bmoveUpdateSpeedVerta(-movedata.speedvertaup); - if (movedata.canlookahead && (movedata.analogwalk > 60 || movedata.analogwalk < -60)) { g_Vars.currentplayer->movecentrerelease = true; } @@ -2100,7 +2202,12 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i bmoveUpdateSpeedVerta(0); } +#ifndef PLATFORM_N64 + // Only apply normal speedverta if recentering animated system is not active g_Vars.currentplayer->vv_verta += g_Vars.currentplayer->speedverta * g_Vars.lvupdate60freal * 3.5f; +#else + g_Vars.currentplayer->vv_verta += g_Vars.currentplayer->speedverta * g_Vars.lvupdate60freal * 3.5f; +#endif } } diff --git a/src/include/constants.h b/src/include/constants.h index 2457a7f4ab..02eb50bba9 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -4751,6 +4751,8 @@ enum weaponnum { #define CROUCHMODE_TOGGLE 2 // press the crouch buttons to toggle stance #define CROUCHMODE_TOGGLE_ANALOG (CROUCHMODE_ANALOG | CROUCHMODE_TOGGLE) +#define RESET_CAMERA CK_0040 // reset camera and/or crosshair to default position + #define CROSSHAIR_HEALTH_OFF 0 #define CROSSHAIR_HEALTH_ON_GREEN 1 #define CROSSHAIR_HEALTH_ON_WHITE 2