From 4c9b9f0e6411fd69c4db59e10a8847941e00aa86 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 26 Apr 2024 22:31:12 -0400 Subject: [PATCH 1/6] Fix drift end kick-out regression from SRB2Kart --- src/k_kart.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index fba7c2f99..ee520775c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10336,7 +10336,7 @@ static INT16 K_GetKartDriftValue(const player_t *player, fixed_t countersteer) } #endif - return basedrift + (FixedMul(driftadjust * FRACUNIT, countersteer) / FRACUNIT); + return basedrift + FixedMul(driftadjust, countersteer); } INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering) @@ -10477,16 +10477,20 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) if (player->drift != 0 && P_IsObjectOnGround(player->mo)) { - fixed_t countersteer = FixedDiv(turnfixed, KART_FULLTURN*FRACUNIT); - - // If we're drifting we have a completely different turning value - if (player->pflags & PF_DRIFTEND) { - countersteer = FRACUNIT; + // Sal: K_GetKartDriftValue is short-circuited to give a weird additive magic number, + // instead of an entirely replaced turn value. This gaslit me years ago when I was doing a + // code readability pass, where I missed that fact because it also returned early. + turnfixed += K_GetKartDriftValue(player, FRACUNIT) * FRACUNIT; + return (turnfixed / FRACUNIT); + } + else + { + // If we're drifting we have a completely different turning value + fixed_t countersteer = FixedDiv(turnfixed, KART_FULLTURN * FRACUNIT); + return K_GetKartDriftValue(player, countersteer); } - - return K_GetKartDriftValue(player, countersteer); } fixed_t finalhandleboost = player->handleboost; From 09e14ae8ae5b92a8884209df07f756e1e3a452ef Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 27 Apr 2024 15:49:52 -0400 Subject: [PATCH 2/6] Increase turn solver snap This value works better with the SRB2Kart drift regression fix --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 1741f36f8..03ec1c7c5 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2338,7 +2338,7 @@ static void P_UpdatePlayerAngle(player_t *player) // That means undoing them takes the same amount of time as doing them. // This can lead to oscillating death spiral states on a multi-tic correction, as we swing past the target angle. // So before we go into death-spirals, if our predicton is _almost_ right... - angle_t leniency = (4*ANG1/3) * min(player->cmd.latency, 6); + angle_t leniency = (8*ANG1/3) * min(player->cmd.latency, 6); // Don't force another turning tic, just give them the desired angle! if (targetDelta == angleChange || (maxTurnRight == 0 && maxTurnLeft == 0)) From 92b8fe633af9acda37d79f5faf4a5d64b51b8e12 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 27 Apr 2024 15:54:29 -0400 Subject: [PATCH 3/6] Reduce turn stiffening at high speed This mechanic has been identical to SRB2Kart, but we go so much faster now that we wanna nerf it a lot. --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index ee520775c..7b1aefe60 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10456,7 +10456,7 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) } else { - p_speed = min(currentSpeed, (p_maxspeed * 2)); + p_speed = min(currentSpeed / 2, p_maxspeed * 2); } if (K_PodiumSequence() == true) From a989fcca50d6690929df966b7e5d3059defc3e90 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 28 Apr 2024 16:12:09 -0700 Subject: [PATCH 4/6] Two-stage turn stiffness dependent on player weight --- src/k_kart.c | 15 +++++++++++++-- src/p_user.c | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 7b1aefe60..da4ab32fd 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10456,7 +10456,16 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) } else { - p_speed = min(currentSpeed / 2, p_maxspeed * 2); + // Turning dampens as you go faster, but at extremely high speeds, keeping some control is important. + // Dampening is applied in two stages, one harsh and one soft. + // The harsh window is larger for characters with better baseline maneuverability. + // TODO COMPATLEVEL + // Was p_speed = min(stageSpeed, p_maxspeed * 2); + fixed_t stageSpeed = min(currentSpeed, (100 + 2*(9-player->kartweight)) * p_maxspeed/100); + if (stageSpeed < currentSpeed) + stageSpeed += (currentSpeed - stageSpeed) / 3; + + p_speed = min(stageSpeed, p_maxspeed * 2); } if (K_PodiumSequence() == true) @@ -10482,6 +10491,7 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) // Sal: K_GetKartDriftValue is short-circuited to give a weird additive magic number, // instead of an entirely replaced turn value. This gaslit me years ago when I was doing a // code readability pass, where I missed that fact because it also returned early. + // TODO COMPATLEVEL (I have no fucking clue what's going on here) turnfixed += K_GetKartDriftValue(player, FRACUNIT) * FRACUNIT; return (turnfixed / FRACUNIT); } @@ -10500,7 +10510,8 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) fixed_t topspeed = K_GetKartSpeed(player, false, false); if (K_Sliptiding(player)) { - finalhandleboost = FixedMul(5*SLIPTIDEHANDLING/4, FixedDiv(player->speed, topspeed)); + // TODO COMPATLEVEL (was 5*SLIPTIDEHANDLING/4) + finalhandleboost = FixedMul(3*SLIPTIDEHANDLING/4, FixedDiv(player->speed, topspeed)); } if (finalhandleboost > 0 && player->respawn.state == RESPAWNST_NONE) diff --git a/src/p_user.c b/src/p_user.c index 03ec1c7c5..4595af553 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2338,6 +2338,7 @@ static void P_UpdatePlayerAngle(player_t *player) // That means undoing them takes the same amount of time as doing them. // This can lead to oscillating death spiral states on a multi-tic correction, as we swing past the target angle. // So before we go into death-spirals, if our predicton is _almost_ right... + // TODO COMPATLEVEL (was 4*ANG1/3) angle_t leniency = (8*ANG1/3) * min(player->cmd.latency, 6); // Don't force another turning tic, just give them the desired angle! From 6d63167a0d291972abb635d06995604acc81c866 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 29 Apr 2024 11:02:03 -0400 Subject: [PATCH 5/6] G_CompatLevel Checks for gameplay differences per DEMOVERSION. Allows us to make necessary handling changes without hurting the staff ghosts. --- src/g_demo.cpp | 18 +++++++++++- src/g_demo.h | 2 ++ src/k_kart.c | 75 ++++++++++++++++++++++++++++++++++++-------------- src/p_user.c | 13 +++++++-- 4 files changed, 84 insertions(+), 24 deletions(-) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index f11e6e214..a22595aad 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -161,7 +161,23 @@ demoghost *ghosts = NULL; // - 0x0009 (older staff ghosts) // - Player names, skin names and color names were 16 // bytes. See get_buffer_sizes(). -#define DEMOVERSION 0x000A +// - 0x000A (Ring Racers v2.0) +// - A bug was preventing control after ending a drift. +// Older behavior is kept around for staff ghost compat. + +#define DEMOVERSION 0x000B + +boolean G_CompatLevel(UINT16 level) +{ + if (demo.playback) + { + // Check gameplay differences for older ghosts + return (demo.version <= level); + } + + return false; +} + #define DEMOHEADER "\xF0" "KartReplay" "\x0F" #define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP|ATTACKING_SPB) // This demo contains time/lap data diff --git a/src/g_demo.h b/src/g_demo.h index feb636640..a881aba3a 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -170,6 +170,8 @@ extern UINT8 demo_writerng; #define DXD_PST_SPECTATING 0x02 #define DXD_PST_LEFT 0x03 +boolean G_CompatLevel(UINT16 level); + // Record/playback tics void G_ReadDemoExtraData(void); void G_WriteDemoExtraData(void); diff --git a/src/k_kart.c b/src/k_kart.c index da4ab32fd..0128a544e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10456,16 +10456,24 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) } else { - // Turning dampens as you go faster, but at extremely high speeds, keeping some control is important. - // Dampening is applied in two stages, one harsh and one soft. - // The harsh window is larger for characters with better baseline maneuverability. - // TODO COMPATLEVEL - // Was p_speed = min(stageSpeed, p_maxspeed * 2); - fixed_t stageSpeed = min(currentSpeed, (100 + 2*(9-player->kartweight)) * p_maxspeed/100); - if (stageSpeed < currentSpeed) - stageSpeed += (currentSpeed - stageSpeed) / 3; + if (G_CompatLevel(0x000A)) + { + // Compat level for 2.0 staff ghosts + p_speed = min(currentSpeed, p_maxspeed * 2); + } + else + { + // Turning dampens as you go faster, but at extremely high speeds, keeping some control is important. + // Dampening is applied in two stages, one harsh and one soft. + // The harsh window is larger for characters with better baseline maneuverability. + fixed_t stageSpeed = min(currentSpeed, (100 + 2*(9-player->kartweight)) * p_maxspeed/100); + if (stageSpeed < currentSpeed) + { + stageSpeed += (currentSpeed - stageSpeed) / 3; + } - p_speed = min(stageSpeed, p_maxspeed * 2); + p_speed = min(stageSpeed, p_maxspeed * 2); + } } if (K_PodiumSequence() == true) @@ -10486,20 +10494,34 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) if (player->drift != 0 && P_IsObjectOnGround(player->mo)) { - if (player->pflags & PF_DRIFTEND) + if (G_CompatLevel(0x000A)) { - // Sal: K_GetKartDriftValue is short-circuited to give a weird additive magic number, - // instead of an entirely replaced turn value. This gaslit me years ago when I was doing a - // code readability pass, where I missed that fact because it also returned early. - // TODO COMPATLEVEL (I have no fucking clue what's going on here) - turnfixed += K_GetKartDriftValue(player, FRACUNIT) * FRACUNIT; - return (turnfixed / FRACUNIT); + // Compat level for 2.0 staff ghosts + fixed_t countersteer = FixedDiv(turnfixed, KART_FULLTURN * FRACUNIT); + + if (player->pflags & PF_DRIFTEND) + { + countersteer = FRACUNIT; + } + + return K_GetKartDriftValue(player, countersteer); } else { - // If we're drifting we have a completely different turning value - fixed_t countersteer = FixedDiv(turnfixed, KART_FULLTURN * FRACUNIT); - return K_GetKartDriftValue(player, countersteer); + if (player->pflags & PF_DRIFTEND) + { + // Sal: K_GetKartDriftValue is short-circuited to give a weird additive magic number, + // instead of an entirely replaced turn value. This gaslit me years ago when I was doing a + // code readability pass, where I missed that fact because it also returned early. + turnfixed += K_GetKartDriftValue(player, FRACUNIT) * FRACUNIT; + return (turnfixed / FRACUNIT); + } + else + { + // If we're drifting we have a completely different turning value + fixed_t countersteer = FixedDiv(turnfixed, KART_FULLTURN * FRACUNIT); + return K_GetKartDriftValue(player, countersteer); + } } } @@ -10510,8 +10532,19 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) fixed_t topspeed = K_GetKartSpeed(player, false, false); if (K_Sliptiding(player)) { - // TODO COMPATLEVEL (was 5*SLIPTIDEHANDLING/4) - finalhandleboost = FixedMul(3*SLIPTIDEHANDLING/4, FixedDiv(player->speed, topspeed)); + fixed_t sliptide_handle; + + if (G_CompatLevel(0x000A)) + { + // Compat level for 2.0 staff ghosts + sliptide_handle = 5 * SLIPTIDEHANDLING / 4; + } + else + { + sliptide_handle = 3 * SLIPTIDEHANDLING / 4; + } + + finalhandleboost = FixedMul(sliptide_handle, FixedDiv(player->speed, topspeed)); } if (finalhandleboost > 0 && player->respawn.state == RESPAWNST_NONE) diff --git a/src/p_user.c b/src/p_user.c index 4595af553..fc0c0bd23 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2338,8 +2338,17 @@ static void P_UpdatePlayerAngle(player_t *player) // That means undoing them takes the same amount of time as doing them. // This can lead to oscillating death spiral states on a multi-tic correction, as we swing past the target angle. // So before we go into death-spirals, if our predicton is _almost_ right... - // TODO COMPATLEVEL (was 4*ANG1/3) - angle_t leniency = (8*ANG1/3) * min(player->cmd.latency, 6); + angle_t leniency_base; + if (G_CompatLevel(0x000A)) + { + // Compat level for 2.0 staff ghosts + leniency_base = 4 * ANG1 / 3; + } + else + { + leniency_base = 8 * ANG1 / 3; + } + angle_t leniency = leniency_base * min(player->cmd.latency, 6); // Don't force another turning tic, just give them the desired angle! if (targetDelta == angleChange || (maxTurnRight == 0 && maxTurnLeft == 0)) From 7250bcc341f68d8aa4aab75beb18b1779f25267d Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 29 Apr 2024 23:27:44 -0700 Subject: [PATCH 6/6] Bump dampening values up for midspeed driving --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 0128a544e..147a0d381 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10466,10 +10466,10 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) // Turning dampens as you go faster, but at extremely high speeds, keeping some control is important. // Dampening is applied in two stages, one harsh and one soft. // The harsh window is larger for characters with better baseline maneuverability. - fixed_t stageSpeed = min(currentSpeed, (100 + 2*(9-player->kartweight)) * p_maxspeed/100); + fixed_t stageSpeed = min(currentSpeed, (110 + 2*(9-player->kartweight)) * p_maxspeed/100); if (stageSpeed < currentSpeed) { - stageSpeed += (currentSpeed - stageSpeed) / 3; + stageSpeed += (currentSpeed - stageSpeed) / 2; } p_speed = min(stageSpeed, p_maxspeed * 2);