From 65f388de3a534ad13cc6026dfc3d0e9f913027c2 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 17 Oct 2025 18:18:05 +0100 Subject: [PATCH] Less spike softlock (resolves ring-racers#65) - Less strength in the first place - Attenuates strength on repeated pokes - Always stumbles since that seemed to be what was happening previously --- src/d_player.h | 1 + src/k_kart.c | 42 ++++++++++++++++++++++++++++++++++++++++-- src/lua_playerlib.c | 4 ++++ src/p_map.c | 9 +++++---- src/p_saveg.cpp | 2 ++ src/p_user.c | 5 +++++ 6 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index e094fa306..ad7bed70e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -769,6 +769,7 @@ struct player_t UINT8 wipeoutslow; // Timer before you slowdown when getting wiped out UINT8 justbumped; // Prevent players from endlessly bumping into each other UINT8 noEbrakeMagnet; // Briefly disable 2.2 responsive ebrake if you're bumped by another player. + UINT8 wallSpikeDampen; // 2.4 wallspikes can softlock in closed quarters... attenuate their violence UINT8 tumbleBounces; UINT16 tumbleHeight; // In *mobjscaled* fracunits, or mfu, not raw fu UINT16 stunned; // Number of tics during which rings cannot be picked up diff --git a/src/k_kart.c b/src/k_kart.c index f36094d72..683f306b9 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1275,12 +1275,50 @@ boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj) if (solidMobj->type == MT_WALLSPIKE) { + if (bounceMobj->hitlag) + { + bounceMobj->player->justbumped = bumptime; + return false; + } + + //CONS_Printf("%sattenuation is %d\n", (leveltime & 1 ? "" : " "), bounceMobj->player->wallSpikeDampen); + // Always thrust out towards the tip // (...don't try to roll our own bad calculations, // just make this behave like a wallspring...) - P_DoSpringEx(bounceMobj, mapobjectscale, 0, solidMobj->info->damage, - solidMobj->angle, SKINCOLOR_NONE); + fixed_t spikeforce = solidMobj->info->damage; + fixed_t deflection = 0; + + if (bounceMobj->player && !G_CompatLevel(0x0011)) + { + // Okay no we need to use bad calculations just to + // prevent softlocks -- repeated touches attenuate + UINT8 atten = bounceMobj->player->wallSpikeDampen; + + deflection = atten * FRACUNIT; + if (bounceMobj->angle - solidMobj->angle >= ANGLE_180) + deflection = -deflection; + + K_StumblePlayer(bounceMobj->player); + bounceMobj->player->tumbleBounces = TUMBLEBOUNCES; // Only one + + atten++; + while (atten) + { + // We want a power relationship - towards zero but not quite reaching it. + spikeforce = (2 * spikeforce) / 3; + atten--; + } + + if (bounceMobj->player->wallSpikeDampen < UINT8_MAX + && bounceMobj->player->justbumped < bumptime-2) + bounceMobj->player->wallSpikeDampen++; + } + + P_DoSpringEx(bounceMobj, mapobjectscale, 0, spikeforce, + solidMobj->angle + R_PointToAngle2(0, 0, spikeforce, deflection), + SKINCOLOR_NONE); K_PlayerJustBumped(bounceMobj->player); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 5c924e51f..3436fec94 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -255,6 +255,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->justbumped); else if (fastcmp(field,"noebrakemagnet")) lua_pushinteger(L, plr->noEbrakeMagnet); + else if (fastcmp(field,"wallspikedampen")) + lua_pushinteger(L, plr->wallSpikeDampen); else if (fastcmp(field,"tumblebounces")) lua_pushinteger(L, plr->tumbleBounces); else if (fastcmp(field,"tumbleheight")) @@ -1033,6 +1035,8 @@ static int player_set(lua_State *L) plr->justbumped = luaL_checkinteger(L, 3); else if (fastcmp(field,"noebrakemagnet")) plr->noEbrakeMagnet = luaL_checkinteger(L, 3); + else if (fastcmp(field,"wallspikedampen")) + plr->wallSpikeDampen = luaL_checkinteger(L, 3); else if (fastcmp(field,"tumblebounces")) plr->tumbleBounces = luaL_checkinteger(L, 3); else if (fastcmp(field,"tumbleheight")) diff --git a/src/p_map.c b/src/p_map.c index 00336754a..c30eaacd4 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1378,12 +1378,12 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (g_tm.thing->z + g_tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (g_tm.thing->player && g_tm.thing->player && g_tm.thing->player->tumbleBounces > 0) + if (g_tm.thing->player && g_tm.thing->player->tumbleBounces) { - return BMIT_CONTINUE; + if (thing->type == MT_SPIKE || G_CompatLevel(0x0011)) + return BMIT_CONTINUE; } - - if (!P_IsObjectOnGround(g_tm.thing) && g_tm.thing->momz * P_MobjFlip(g_tm.thing) < 0) // fell into it + else if (!P_IsObjectOnGround(g_tm.thing) && g_tm.thing->momz * P_MobjFlip(g_tm.thing) < 0) // fell into it { P_DamageMobj(g_tm.thing, thing, thing, 1, DMG_TUMBLE); @@ -1398,6 +1398,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) { if ( thing->type == MT_WALLSPIKE + && G_CompatLevel(0x0011) && g_tm.thing->health && g_tm.thing->player && (g_tm.thing->player->justbumped < bumptime-2) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 0406fd3f3..942d37f33 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -479,6 +479,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].wipeoutslow); WRITEUINT8(save->p, players[i].justbumped); WRITEUINT8(save->p, players[i].noEbrakeMagnet); + WRITEUINT8(save->p, players[i].wallSpikeDampen); WRITEUINT8(save->p, players[i].tumbleBounces); WRITEUINT16(save->p, players[i].tumbleHeight); WRITEUINT16(save->p, players[i].stunned); @@ -1164,6 +1165,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].wipeoutslow = READUINT8(save->p); players[i].justbumped = READUINT8(save->p); players[i].noEbrakeMagnet = READUINT8(save->p); + players[i].wallSpikeDampen = READUINT8(save->p); players[i].tumbleBounces = READUINT8(save->p); players[i].tumbleHeight = READUINT16(save->p); players[i].stunned = READUINT16(save->p); diff --git a/src/p_user.c b/src/p_user.c index 0ce7d3775..1518629b0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4647,6 +4647,11 @@ void P_PlayerThink(player_t *player) player->flashing--; } + if (!player->flashing && !P_PlayerInPain(player)) + { + player->wallSpikeDampen = 0; + } + if (player->nocontrol && player->nocontrol < UINT16_MAX) { player->nocontrol--;