From f6b62b6ac6c4a80478a51084c0ff0fcb9b52dbc8 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 11:07:25 -0400 Subject: [PATCH 1/7] Clean up water skip conditions - Use Digital Empire's water running conditions (fully prevents ever being able to water-run on water that isn't level) - Code cleanup of other parts of this code - Made the threshold for water skipping much more strict - Fixed water skip being scaled to player scale instead of map scale - Make water run / tripwire easier for rubberbanding bots --- src/k_kart.c | 27 +++++++++++- src/k_kart.h | 2 + src/p_mobj.c | 121 +++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 119 insertions(+), 31 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 5406e6427..369830fb7 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3232,7 +3232,7 @@ tripwirepass_t K_TripwirePassConditions(player_t *player) if ( player->flamedash || - player->speed > 2 * K_GetKartSpeed(player, false, true) + player->speed > 2 * K_GetKartSpeed(player, false, false) ) return TRIPWIRE_BOOST; @@ -3250,6 +3250,11 @@ boolean K_TripwirePass(player_t *player) return (player->tripwirePass != TRIPWIRE_NONE); } +boolean K_MovingHorizontally(mobj_t *mobj) +{ + return (P_AproxDistance(mobj->momx, mobj->momy) / 5 > abs(mobj->momz)); +} + boolean K_WaterRun(player_t *player) { if ( @@ -3257,12 +3262,30 @@ boolean K_WaterRun(player_t *player) player->sneakertimer || player->tiregrease || player->flamedash || - player->speed > 2 * K_GetKartSpeed(player, false, true) + player->speed > 2 * K_GetKartSpeed(player, false, false) ) return true; return false; } +boolean K_WaterSkip(player_t *player) +{ + if (player->waterskip >= 2) + { + // Already finished waterskipping. + return false; + } + + if (player->waterskip > 0) + { + // Already waterskipping. + // Simply make sure you haven't slowed down drastically. + return (player->speed > 20 * mapobjectscale); + } + + return K_MovingHorizontally(player->mo); +} + static fixed_t K_FlameShieldDashVar(INT32 val) { // 1 second = 75% + 50% top speed diff --git a/src/k_kart.h b/src/k_kart.h index 1c75288e5..7bb9f2b6a 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -142,7 +142,9 @@ boolean K_ApplyOffroad(player_t *player); boolean K_SlopeResistance(player_t *player); tripwirepass_t K_TripwirePassConditions(player_t *player); boolean K_TripwirePass(player_t *player); +boolean K_MovingHorizontally(mobj_t *mobj); boolean K_WaterRun(player_t *player); +boolean K_WaterSkip(player_t *player); void K_ApplyTripWire(player_t *player, tripwirestate_t state); INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 9b868360a..c4640cc3a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3073,25 +3073,92 @@ boolean P_SceneryZMovement(mobj_t *mo) return true; } +// // P_CanRunOnWater // -// Returns true if player can waterrun on the 3D floor +// Returns true if player can water run on a 3D floor // boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) { - boolean flip = player->mo->eflags & MFE_VERTICALFLIP; - fixed_t surfaceheight = flip ? player->mo->waterbottom : player->mo->watertop; - fixed_t playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z; - fixed_t clip = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); - fixed_t span = player->mo->watertop - player->mo->waterbottom; + const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP); + fixed_t surfaceheight = INT32_MAX; + fixed_t playerbottom = INT32_MAX; + fixed_t surfDiff = INT32_MAX; + fixed_t maxStep = INT32_MAX; + boolean doifit = false; - return - clip > -(player->mo->height / 2) && - span > player->mo->height && - player->speed / 5 > abs(player->mo->momz) && - player->speed > K_GetKartSpeed(player, false, false) && - K_WaterRun(player) && - (rover->flags & FF_SWIMMABLE); + pslope_t *waterSlope = NULL; + angle_t ourZAng = 0; + angle_t waterZAng = 0; + + if (rover == NULL) + { + // No rover. + return false; + } + + if (!(rover->flags & FF_SWIMMABLE)) + { + // It's not even a water FOF. + return false; + } + + if (player->carry != CR_NONE) // Special carry state. + { + // No good player state. + return false; + } + + if (P_IsObjectOnGround(player->mo) == false) + { + // Don't allow jumping onto water to start a water run. + // (Already water running still counts as being on the ground.) + return false; + } + + if (K_WaterRun(player) == false) + { + // Basic conditions for enabling water run. + return false; + } + + if (player->mo->standingslope != NULL) + { + ourZAng = player->mo->standingslope->zangle; + } + + waterSlope = (flip ? *rover->b_slope : *rover->t_slope); + if (waterSlope != NULL) + { + waterZAng = waterSlope->zangle; + } + + if (ourZAng != waterZAng) + { + // The surface slopes are different. + return false; + } + + surfaceheight = flip ? P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y) : P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); + playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z; + + doifit = flip ? (surfaceheight - player->mo->floorz >= player->mo->height) : (player->mo->ceilingz - surfaceheight >= player->mo->height); + + if (!doifit) + { + // Player can't fit in this space. + return false; + } + + surfDiff = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); + maxStep = P_GetThingStepUp(player->mo); + if (surfDiff <= maxStep && surfDiff >= 0) + { + // We start water run IF we can step-down! + return true; + } + + return false; } boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover) @@ -3308,23 +3375,19 @@ void P_MobjCheckWater(mobj_t *mobj) splish->destscale = mobj->scale; P_SetScale(splish, mobj->scale); + + // skipping stone! + if (K_WaterSkip(p) == true) + { + const fixed_t hop = 5 * mapobjectscale; + + mobj->momx = (4*mobj->momx)/5; + mobj->momy = (4*mobj->momy)/5; + mobj->momz = hop * P_MobjFlip(mobj); + + p->waterskip++; + } } - - // skipping stone! - if (p && p->waterskip < 2 - && ((p->speed/3 > abs(mobj->momz)) // Going more forward than horizontal, so you can skip across the water. - || (p->speed > 20*mapobjectscale && p->waterskip)) // Already skipped once, so you can skip once more! - && (splashValid == true)) - { - const fixed_t hop = 5 * mobj->scale; - - mobj->momx = (4*mobj->momx)/5; - mobj->momy = (4*mobj->momy)/5; - mobj->momz = hop * P_MobjFlip(mobj); - - p->waterskip++; - } - } else if (P_MobjFlip(mobj) * mobj->momz > 0) { From 884f710269b8d91fa59503c702dc3683857b3d4a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 11:43:55 -0400 Subject: [PATCH 2/7] Add minimum strafe to water physics --- src/k_kart.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 369830fb7..028bd84ce 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8871,12 +8871,13 @@ INT32 K_GetUnderwaterTurnAdjust(player_t *player) { INT32 steer = (K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE); + fixed_t minimum = INT32_MAX; if (!player->drift) steer = 9 * steer / 5; - return FixedMul(steer, 8 * FixedDiv(player->speed, - 2 * K_GetKartSpeed(player, false, true) / 3)); + minimum = 2 * K_GetKartSpeed(player, false, true) / 3; + return FixedMul(steer, 8 * FixedDiv(max(player->speed, minimum), minimum)); } else return 0; From 841bcf36195bfef62bec3ead5601ff6a28b460c7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 12:31:33 -0400 Subject: [PATCH 3/7] Allow non-players to water skip/run Water skipping is enabled for Orbinaut, Jawz, and Ballhog currently. Jawz can water run, as long as their target is on/above the plane they're at -- once their target goes into the water, they'll start skipping. --- src/d_player.h | 1 - src/k_kart.c | 90 +++++++++++++++++++++++++++++++++++---------- src/k_kart.h | 4 +- src/lua_baselib.c | 5 ++- src/lua_mobjlib.c | 8 ++++ src/lua_playerlib.c | 4 -- src/p_local.h | 6 +-- src/p_map.c | 6 +-- src/p_maputl.c | 4 +- src/p_mobj.c | 89 ++++++++++++++++++++++++++------------------ src/p_mobj.h | 1 + src/p_saveg.c | 13 ++++++- 12 files changed, 158 insertions(+), 73 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index c31837757..fcf87c520 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -438,7 +438,6 @@ typedef struct player_s INT32 underwatertilt; fixed_t offroad; // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed - UINT8 waterskip; // Water skipping counter UINT16 tiregrease; // Reduced friction timer after hitting a spring UINT16 springstars; // Spawn stars around a player when they hit a spring diff --git a/src/k_kart.c b/src/k_kart.c index 078e4f831..5a83d51cc 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3255,35 +3255,90 @@ boolean K_MovingHorizontally(mobj_t *mobj) return (P_AproxDistance(mobj->momx, mobj->momy) / 5 > abs(mobj->momz)); } -boolean K_WaterRun(player_t *player) +boolean K_WaterRun(mobj_t *mobj) { - if ( - player->invincibilitytimer || - player->sneakertimer || - player->tiregrease || - player->flamedash || - player->speed > 2 * K_GetKartSpeed(player, false, false) - ) - return true; - return false; + switch (mobj->type) + { + case MT_JAWZ: + { + if (mobj->tracer != NULL && P_MobjWasRemoved(mobj->tracer) == false) + { + fixed_t jawzFeet = P_GetMobjFeet(mobj); + fixed_t chaseFeet = P_GetMobjFeet(mobj->tracer); + fixed_t footDiff = (chaseFeet - jawzFeet) * P_MobjFlip(mobj); + + // Water run if the player we're chasing is above/equal to us. + // Start water skipping if they're underneath the water. + return (footDiff > -mobj->tracer->height); + } + + return false; + } + + case MT_PLAYER: + { + if (mobj->player == NULL) + { + return false; + } + + if (mobj->player->invincibilitytimer + || mobj->player->sneakertimer + || mobj->player->tiregrease + || mobj->player->flamedash + || mobj->player->speed > 2 * K_GetKartSpeed(mobj->player, false, false)) + { + return true; + } + + return false; + } + + default: + { + return false; + } + } } -boolean K_WaterSkip(player_t *player) +boolean K_WaterSkip(mobj_t *mobj) { - if (player->waterskip >= 2) + if (mobj->waterskip >= 2) { // Already finished waterskipping. return false; } - if (player->waterskip > 0) + switch (mobj->type) + { + case MT_PLAYER: + case MT_ORBINAUT: + case MT_JAWZ: + case MT_BALLHOG: + { + // Allow + break; + } + + default: + { + // Don't allow + return false; + } + } + + if (mobj->waterskip > 0) { // Already waterskipping. // Simply make sure you haven't slowed down drastically. - return (player->speed > 20 * mapobjectscale); + return (P_AproxDistance(mobj->momx, mobj->momy) > 20 * mapobjectscale); + } + else + { + // Need to be moving horizontally and not vertically + // to be able to start a water skip. + return K_MovingHorizontally(mobj); } - - return K_MovingHorizontally(player->mo); } static fixed_t K_FlameShieldDashVar(INT32 val) @@ -7980,9 +8035,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } - if (P_IsObjectOnGround(player->mo)) - player->waterskip = 0; - if (player->instashield) player->instashield--; diff --git a/src/k_kart.h b/src/k_kart.h index 7bb9f2b6a..71169fec0 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -143,8 +143,8 @@ boolean K_SlopeResistance(player_t *player); tripwirepass_t K_TripwirePassConditions(player_t *player); boolean K_TripwirePass(player_t *player); boolean K_MovingHorizontally(mobj_t *mobj); -boolean K_WaterRun(player_t *player); -boolean K_WaterSkip(player_t *player); +boolean K_WaterRun(mobj_t *mobj); +boolean K_WaterSkip(mobj_t *mobj); void K_ApplyTripWire(player_t *player, tripwirestate_t state); INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index bd05ae8b5..7a72b31dc 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -954,12 +954,15 @@ static int lib_pCheckDeathPitCollide(lua_State *L) static int lib_pCheckSolidLava(lua_State *L) { + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); //HUDSAFE INLEVEL + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); if (!rover) return LUA_ErrInvalid(L, "ffloor_t"); - lua_pushboolean(L, P_CheckSolidLava(rover)); + lua_pushboolean(L, P_CheckSolidLava(mo, rover)); return 1; } diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 418a43bf9..ecd87f49f 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -100,6 +100,7 @@ enum mobj_e { mobj_spryoff, mobj_sprzoff, mobj_hitlag, + mobj_waterskip, mobj_dispoffset }; @@ -181,6 +182,7 @@ static const char *const mobj_opt[] = { "spryoff", "sprzoff", "hitlag", + "waterskip", "dispoffset", NULL}; @@ -460,6 +462,9 @@ static int mobj_get(lua_State *L) case mobj_hitlag: lua_pushinteger(L, mo->hitlag); break; + case mobj_waterskip: + lua_pushinteger(L, mo->waterskip); + break; case mobj_dispoffset: lua_pushinteger(L, mo->dispoffset); break; @@ -835,6 +840,9 @@ static int mobj_set(lua_State *L) case mobj_hitlag: mo->hitlag = luaL_checkinteger(L, 3); break; + case mobj_waterskip: + mo->waterskip = (UINT8)luaL_checkinteger(L, 3); + break; case mobj_dispoffset: mo->dispoffset = luaL_checkinteger(L, 3); break; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 85e73a12f..c5f5cc4d0 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -264,8 +264,6 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->aizdriftturn); else if (fastcmp(field,"offroad")) lua_pushinteger(L, plr->offroad); - else if (fastcmp(field,"waterskip")) - lua_pushinteger(L, plr->waterskip); else if (fastcmp(field,"tiregrease")) lua_pushinteger(L, plr->tiregrease); else if (fastcmp(field,"springstars")) @@ -634,8 +632,6 @@ static int player_set(lua_State *L) plr->aizdriftturn = luaL_checkinteger(L, 3); else if (fastcmp(field,"offroad")) plr->offroad = luaL_checkinteger(L, 3); - else if (fastcmp(field,"waterskip")) - plr->waterskip = luaL_checkinteger(L, 3); else if (fastcmp(field,"tiregrease")) plr->tiregrease = luaL_checkinteger(L, 3); else if (fastcmp(field,"springstars")) diff --git a/src/p_local.h b/src/p_local.h index 5fc73f1a2..37edb2b67 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -315,7 +315,7 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover); boolean P_CheckDeathPitCollide(mobj_t *mo); -boolean P_CheckSolidLava(ffloor_t *rover); +boolean P_CheckSolidLava(mobj_t *mobj, ffloor_t *rover); void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype); mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type); @@ -337,8 +337,8 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled void P_Attract(mobj_t *source, mobj_t *enemy, boolean nightsgrab); mobj_t *P_GetClosestAxis(mobj_t *source); -boolean P_CanRunOnWater(player_t *player, ffloor_t *rover); -boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover); +boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover); +boolean P_CheckSolidFFloorSurface(mobj_t *mobj, ffloor_t *rover); void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot); diff --git a/src/p_map.c b/src/p_map.c index 07d610fb8..ba2147bac 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1940,7 +1940,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) continue; } - if (thing->player && P_CheckSolidFFloorSurface(thing->player, rover)) + if (P_CheckSolidFFloorSurface(thing, rover)) ; else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE)) ; @@ -2524,9 +2524,7 @@ static boolean P_WaterRunning(mobj_t *thing) static boolean P_WaterStepUp(mobj_t *thing) { - player_t *player = thing->player; - return (player && player->waterskip) || - P_WaterRunning(thing); + return (thing->waterskip > 0 || P_WaterRunning(thing)); } fixed_t P_BaseStepUp(void) diff --git a/src/p_maputl.c b/src/p_maputl.c index 09e5cdd5d..74fe2331d 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -777,7 +777,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (!(rover->flags & FF_EXISTS)) continue; - if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover)) + if (P_CheckSolidFFloorSurface(mobj, rover)) ; else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) || (rover->flags & FF_BLOCKOTHERS && !mobj->player))) @@ -821,7 +821,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (!(rover->flags & FF_EXISTS)) continue; - if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover)) + if (P_CheckSolidFFloorSurface(mobj, rover)) ; else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) || (rover->flags & FF_BLOCKOTHERS && !mobj->player))) diff --git a/src/p_mobj.c b/src/p_mobj.c index ac6306823..8f350cbe7 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1105,6 +1105,11 @@ fixed_t P_GetMobjGravity(mobj_t *mo) } } + if (mo->waterskip > 0) + { + gravityadd = (4*gravityadd)/3; + } + if (mo->player) { if (mo->flags2 & MF2_OBJECTFLIP) @@ -1118,11 +1123,6 @@ fixed_t P_GetMobjGravity(mobj_t *mo) P_PlayerFlip(mo); } - if (mo->player->waterskip) - { - gravityadd = (4*gravityadd)/3; - } - if (mo->player->trickpanel >= 2) { gravityadd = (5*gravityadd)/2; @@ -1938,7 +1938,7 @@ void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype) topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL); bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL); - if (mo->player && P_CheckSolidFFloorSurface(mo->player, rover)) // only the player should stand on lava or run on water + if (P_CheckSolidFFloorSurface(mo, rover)) // only the player should stand on lava or run on water ; else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only continue; @@ -2097,11 +2097,18 @@ boolean P_CheckDeathPitCollide(mobj_t *mo) return false; } -boolean P_CheckSolidLava(ffloor_t *rover) +boolean P_CheckSolidLava(mobj_t *mobj, ffloor_t *rover) { + if (mobj->player == NULL) + { + return false; + } + if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 && !(rover->master->flags & ML_BLOCKPLAYERS)) - return true; + { + return true; + } return false; } @@ -3084,11 +3091,13 @@ boolean P_SceneryZMovement(mobj_t *mo) // // Returns true if player can water run on a 3D floor // -boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) +boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) { - const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP); + const boolean flip = (mobj->eflags & MFE_VERTICALFLIP); + player_t *player = mobj->player; + fixed_t surfaceheight = INT32_MAX; - fixed_t playerbottom = INT32_MAX; + fixed_t mobjbottom = INT32_MAX; fixed_t surfDiff = INT32_MAX; fixed_t maxStep = INT32_MAX; boolean doifit = false; @@ -3109,28 +3118,29 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) return false; } - if (player->carry != CR_NONE) // Special carry state. + if (player != NULL + && player->carry != CR_NONE) // Special carry state. { // No good player state. return false; } - if (P_IsObjectOnGround(player->mo) == false) + if (P_IsObjectOnGround(mobj) == false) { // Don't allow jumping onto water to start a water run. // (Already water running still counts as being on the ground.) return false; } - if (K_WaterRun(player) == false) + if (K_WaterRun(mobj) == false) { // Basic conditions for enabling water run. return false; } - if (player->mo->standingslope != NULL) + if (mobj->standingslope != NULL) { - ourZAng = player->mo->standingslope->zangle; + ourZAng = mobj->standingslope->zangle; } waterSlope = (flip ? *rover->b_slope : *rover->t_slope); @@ -3145,19 +3155,19 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) return false; } - surfaceheight = flip ? P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y) : P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); - playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z; + surfaceheight = flip ? P_GetFFloorBottomZAt(rover, mobj->x, mobj->y) : P_GetFFloorTopZAt(rover, mobj->x, mobj->y); + mobjbottom = flip ? (mobj->z + mobj->height) : mobj->z; - doifit = flip ? (surfaceheight - player->mo->floorz >= player->mo->height) : (player->mo->ceilingz - surfaceheight >= player->mo->height); + doifit = flip ? (surfaceheight - mobj->floorz >= mobj->height) : (mobj->ceilingz - surfaceheight >= mobj->height); if (!doifit) { - // Player can't fit in this space. + // Object can't fit in this space. return false; } - surfDiff = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); - maxStep = P_GetThingStepUp(player->mo); + surfDiff = flip ? (surfaceheight - mobjbottom) : (mobjbottom - surfaceheight); + maxStep = P_GetThingStepUp(mobj); if (surfDiff <= maxStep && surfDiff >= 0) { // We start water run IF we can step-down! @@ -3167,10 +3177,10 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) return false; } -boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover) +boolean P_CheckSolidFFloorSurface(mobj_t *mobj, ffloor_t *rover) { - return P_CheckSolidLava(rover) || - P_CanRunOnWater(player, rover); + return P_CheckSolidLava(mobj, rover) || + P_CanRunOnWater(mobj, rover); } // @@ -3286,16 +3296,24 @@ void P_MobjCheckWater(mobj_t *mobj) return; } - if (p && !p->waterskip && - p->curshield != KSHIELD_BUBBLE && wasinwater) + if (P_IsObjectOnGround(mobj) == true) { - S_StartSound(mobj, sfx_s3k38); + mobj->waterskip = 0; } - if ((p) // Players - || (mobj->flags & MF_PUSHABLE) // Pushables - || ((mobj->info->flags & MF_PUSHABLE) && mobj->fuse) // Previously pushable, might be moving still - ) + if (mobj->waterskip == 0 && wasinwater) + { + if (p && p->curshield == KSHIELD_BUBBLE) + { + ; + } + else + { + S_StartSound(mobj, sfx_s3k38); + } + } + + if (mobj->flags & MF_APPLYTERRAIN) { fixed_t waterZ = INT32_MAX; fixed_t solidZ = INT32_MAX; @@ -3383,7 +3401,7 @@ void P_MobjCheckWater(mobj_t *mobj) P_SetScale(splish, mobj->scale); // skipping stone! - if (K_WaterSkip(p) == true) + if (K_WaterSkip(mobj) == true) { const fixed_t hop = 5 * mapobjectscale; @@ -3391,11 +3409,11 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->momy = (4*mobj->momy)/5; mobj->momz = hop * P_MobjFlip(mobj); - p->waterskip++; + mobj->waterskip++; } } } - else if (P_MobjFlip(mobj) * mobj->momz > 0) + else { if (splashValid == true && !(mobj->eflags & MFE_UNDERWATER)) // underwater check to prevent splashes on opposite side { @@ -9935,6 +9953,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->colorized = false; mobj->hitlag = 0; + mobj->waterskip = 0; // Set shadowscale here, before spawn hook so that Lua can change it P_DefaultMobjShadowScale(mobj); diff --git a/src/p_mobj.h b/src/p_mobj.h index 4cdacea6d..8ef307aab 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -409,6 +409,7 @@ typedef struct mobj_s struct mobj_s *terrainOverlay; // Overlay sprite object for terrain INT32 hitlag; // Sal-style hit lag, straight from Captain Fetch's jowls + UINT8 waterskip; // Water skipping counter INT32 dispoffset; diff --git a/src/p_saveg.c b/src/p_saveg.c index 233056f21..dd77337b9 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -280,7 +280,6 @@ static void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].underwatertilt); WRITEFIXED(save_p, players[i].offroad); - WRITEUINT8(save_p, players[i].waterskip); WRITEUINT16(save_p, players[i].tiregrease); WRITEUINT16(save_p, players[i].springstars); @@ -577,7 +576,6 @@ static void P_NetUnArchivePlayers(void) players[i].underwatertilt = READINT32(save_p); players[i].offroad = READFIXED(save_p); - players[i].waterskip = READUINT8(save_p); players[i].tiregrease = READUINT16(save_p); players[i].springstars = READUINT16(save_p); @@ -1638,6 +1636,7 @@ typedef enum MD2_ITNEXT = 1<<27, MD2_LASTMOMZ = 1<<28, MD2_TERRAIN = 1<<29, + MD2_WATERSKIP = 1<<30, } mobj_diff2_t; typedef enum @@ -1872,6 +1871,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) } if (mobj->hitlag) diff2 |= MD2_HITLAG; + if (mobj->waterskip) + diff2 |= MD2_WATERSKIP; if (mobj->dispoffset) diff2 |= MD2_DISPOFFSET; if (mobj == waypointcap) @@ -2082,6 +2083,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) { WRITEINT32(save_p, mobj->hitlag); } + if (diff2 & MD2_WATERSKIP) + { + WRITEUINT8(save_p, mobj->waterskip); + } if (diff2 & MD2_DISPOFFSET) { WRITEINT32(save_p, mobj->dispoffset); @@ -3191,6 +3196,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) { mobj->hitlag = READINT32(save_p); } + if (diff2 & MD2_WATERSKIP) + { + mobj->waterskip = READUINT8(save_p); + } if (diff2 & MD2_DISPOFFSET) { mobj->dispoffset = READINT32(save_p); From 6ca979d53ee9234ee0be0ef0dbb750477ce7cd34 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 12:35:23 -0400 Subject: [PATCH 4/7] Oops, thought this was a splash, not the gasp... Whoops! --- src/p_mobj.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 8f350cbe7..ca77a8f14 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3301,16 +3301,13 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->waterskip = 0; } - if (mobj->waterskip == 0 && wasinwater) + if (p != NULL + && p->curshield != KSHIELD_BUBBLE + && mobj->waterskip == 0 + && wasinwater) { - if (p && p->curshield == KSHIELD_BUBBLE) - { - ; - } - else - { - S_StartSound(mobj, sfx_s3k38); - } + // Play the gasp sound + S_StartSound(mobj, sfx_s3k38); } if (mobj->flags & MF_APPLYTERRAIN) From afc2a0dcdc09c9dcd34e00682feb9719c4d2cd1a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 13:09:30 -0400 Subject: [PATCH 5/7] Properly spawn effects for the other objects --- src/k_kart.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/k_kart.h | 1 + src/p_mobj.c | 28 +++++++--- src/p_user.c | 94 --------------------------------- 4 files changed, 167 insertions(+), 102 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 5a83d51cc..43e14fbdd 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3341,6 +3341,152 @@ boolean K_WaterSkip(mobj_t *mobj) } } +void K_SpawnWaterRunParticles(mobj_t *mobj) +{ + fixed_t runSpeed = 14 * mobj->scale; + fixed_t curSpeed = INT32_MAX; + fixed_t topSpeed = INT32_MAX; + fixed_t trailScale = FRACUNIT; + + if (mobj->momz != 0) + { + // Only while touching ground. + return; + } + + if (mobj->watertop == INT32_MAX || mobj->waterbottom == INT32_MIN) + { + // Invalid water plane. + return; + } + + if (mobj->player != NULL) + { + if (mobj->player->spectator) + { + // Not as spectator. + return; + } + + if (mobj->player->carry == CR_SLIDING) + { + // Not in water slides. + return; + } + + topSpeed = K_GetKartSpeed(mobj->player, false, false); + runSpeed = FixedMul(runSpeed, mobj->movefactor); + } + else + { + topSpeed = FixedMul(mobj->scale, K_GetKartSpeedFromStat(5)); + } + + curSpeed = P_AproxDistance(mobj->momx, mobj->momy); + + if (curSpeed <= runSpeed) + { + // Not fast enough. + return; + } + + // Near the water plane. + if ((!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height >= mobj->watertop && mobj->z <= mobj->watertop) + || (mobj->eflags & MFE_VERTICALFLIP && mobj->z + mobj->height >= mobj->waterbottom && mobj->z <= mobj->waterbottom)) + { + if (topSpeed > runSpeed) + { + trailScale = FixedMul(FixedDiv(curSpeed - runSpeed, topSpeed - runSpeed), mapobjectscale); + } + else + { + trailScale = mapobjectscale; // Scaling is based off difference between runspeed and top speed + } + + if (trailScale > 0) + { + const angle_t forwardangle = K_MomentumAngle(mobj); + const fixed_t playerVisualRadius = mobj->radius + (8 * mobj->scale); + const size_t numFrames = S_WATERTRAIL8 - S_WATERTRAIL1; + const statenum_t curOverlayFrame = S_WATERTRAIL1 + (leveltime % numFrames); + const statenum_t curUnderlayFrame = S_WATERTRAILUNDERLAY1 + (leveltime % numFrames); + fixed_t x1, x2, y1, y2; + mobj_t *water; + + x1 = mobj->x + mobj->momx + P_ReturnThrustX(mobj, forwardangle + ANGLE_90, playerVisualRadius); + y1 = mobj->y + mobj->momy + P_ReturnThrustY(mobj, forwardangle + ANGLE_90, playerVisualRadius); + x1 = x1 + P_ReturnThrustX(mobj, forwardangle, playerVisualRadius); + y1 = y1 + P_ReturnThrustY(mobj, forwardangle, playerVisualRadius); + + x2 = mobj->x + mobj->momx + P_ReturnThrustX(mobj, forwardangle - ANGLE_90, playerVisualRadius); + y2 = mobj->y + mobj->momy + P_ReturnThrustY(mobj, forwardangle - ANGLE_90, playerVisualRadius); + x2 = x2 + P_ReturnThrustX(mobj, forwardangle, playerVisualRadius); + y2 = y2 + P_ReturnThrustY(mobj, forwardangle, playerVisualRadius); + + // Left + // underlay + water = P_SpawnMobj(x1, y1, + ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, mobj->scale) : mobj->watertop), MT_WATERTRAILUNDERLAY); + P_InitAngle(water, forwardangle - ANGLE_180 - ANGLE_22h); + water->destscale = trailScale; + water->momx = mobj->momx; + water->momy = mobj->momy; + water->momz = mobj->momz; + P_SetScale(water, trailScale); + P_SetMobjState(water, curUnderlayFrame); + + // overlay + water = P_SpawnMobj(x1, y1, + ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, mobj->scale) : mobj->watertop), MT_WATERTRAIL); + P_InitAngle(water, forwardangle - ANGLE_180 - ANGLE_22h); + water->destscale = trailScale; + water->momx = mobj->momx; + water->momy = mobj->momy; + water->momz = mobj->momz; + P_SetScale(water, trailScale); + P_SetMobjState(water, curOverlayFrame); + + // Right + // Underlay + water = P_SpawnMobj(x2, y2, + ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, mobj->scale) : mobj->watertop), MT_WATERTRAILUNDERLAY); + P_InitAngle(water, forwardangle - ANGLE_180 + ANGLE_22h); + water->destscale = trailScale; + water->momx = mobj->momx; + water->momy = mobj->momy; + water->momz = mobj->momz; + P_SetScale(water, trailScale); + P_SetMobjState(water, curUnderlayFrame); + + // Overlay + water = P_SpawnMobj(x2, y2, + ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, mobj->scale) : mobj->watertop), MT_WATERTRAIL); + P_InitAngle(water, forwardangle - ANGLE_180 + ANGLE_22h); + water->destscale = trailScale; + water->momx = mobj->momx; + water->momy = mobj->momy; + water->momz = mobj->momz; + P_SetScale(water, trailScale); + P_SetMobjState(water, curOverlayFrame); + + if (!S_SoundPlaying(mobj, sfx_s3kdbs)) + { + const INT32 volume = (min(trailScale, FRACUNIT) * 255) / FRACUNIT; + S_StartSoundAtVolume(mobj, sfx_s3kdbs, volume); + } + } + + // Little water sound while touching water - just a nicety. + if ((mobj->eflags & MFE_TOUCHWATER) && !(mobj->eflags & MFE_UNDERWATER)) + { + if (P_RandomChance(PR_BUBBLE, FRACUNIT/2) && leveltime % TICRATE == 0) + { + S_StartSound(mobj, sfx_floush); + } + } + } +} + static fixed_t K_FlameShieldDashVar(INT32 val) { // 1 second = 75% + 50% top speed diff --git a/src/k_kart.h b/src/k_kart.h index 71169fec0..117422ffe 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -145,6 +145,7 @@ boolean K_TripwirePass(player_t *player); boolean K_MovingHorizontally(mobj_t *mobj); boolean K_WaterRun(mobj_t *mobj); boolean K_WaterSkip(mobj_t *mobj); +void K_SpawnWaterRunParticles(mobj_t *mobj); void K_ApplyTripWire(player_t *player, tripwirestate_t state); INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index ca77a8f14..3ab7b2c3b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3284,10 +3284,23 @@ void P_MobjCheckWater(mobj_t *mobj) } } - // Spectators and dead players don't get to do any of the things after this. - if (p && (p->spectator || p->playerstate != PST_LIVE)) + if (P_IsObjectOnGround(mobj) == true) { - return; + mobj->waterskip = 0; + } + + if (p != NULL) + { + // Spectators and dead players don't get to do any of the things after this. + if (p->spectator || p->playerstate != PST_LIVE) + { + return; + } + } + + if (mobj->flags & MF_APPLYTERRAIN) + { + K_SpawnWaterRunParticles(mobj); } // The rest of this code only executes on a water state change. @@ -3296,11 +3309,6 @@ void P_MobjCheckWater(mobj_t *mobj) return; } - if (P_IsObjectOnGround(mobj) == true) - { - mobj->waterskip = 0; - } - if (p != NULL && p->curshield != KSHIELD_BUBBLE && mobj->waterskip == 0 @@ -6795,11 +6803,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_ORBINAUT: { Obj_OrbinautThink(mobj); + P_MobjCheckWater(mobj); break; } case MT_JAWZ: { Obj_JawzThink(mobj); + P_MobjCheckWater(mobj); break; } case MT_EGGMANITEM: @@ -6863,6 +6873,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->threshold > 0) mobj->threshold--; + + P_MobjCheckWater(mobj); } break; case MT_SINK: diff --git a/src/p_user.c b/src/p_user.c index 3c3f67449..ca8b10c62 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2292,100 +2292,6 @@ void P_MovePlayer(player_t *player) //GAMEPLAY STUFF// ////////////////// - if (((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height >= player->mo->watertop && player->mo->z <= player->mo->watertop) - || (player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height >= player->mo->waterbottom && player->mo->z <= player->mo->waterbottom)) - && (player->speed > runspd) - && player->mo->momz == 0 && player->carry != CR_SLIDING && !player->spectator) - { - fixed_t playerTopSpeed = K_GetKartSpeed(player, false, false); - fixed_t trailScale = FixedMul(FixedDiv(player->speed - runspd, playerTopSpeed - runspd), mapobjectscale); - - if (playerTopSpeed > runspd) - trailScale = FixedMul(FixedDiv(player->speed - runspd, playerTopSpeed - runspd), mapobjectscale); - else - trailScale = mapobjectscale; // Scaling is based off difference between runspeed and top speed - - if (trailScale > 0) - { - const angle_t forwardangle = K_MomentumAngle(player->mo); - const fixed_t playerVisualRadius = player->mo->radius + (8 * player->mo->scale); - const size_t numFrames = S_WATERTRAIL8 - S_WATERTRAIL1; - const statenum_t curOverlayFrame = S_WATERTRAIL1 + (leveltime % numFrames); - const statenum_t curUnderlayFrame = S_WATERTRAILUNDERLAY1 + (leveltime % numFrames); - fixed_t x1, x2, y1, y2; - mobj_t *water; - - x1 = player->mo->x + player->mo->momx + P_ReturnThrustX(player->mo, forwardangle + ANGLE_90, playerVisualRadius); - y1 = player->mo->y + player->mo->momy + P_ReturnThrustY(player->mo, forwardangle + ANGLE_90, playerVisualRadius); - x1 = x1 + P_ReturnThrustX(player->mo, forwardangle, playerVisualRadius); - y1 = y1 + P_ReturnThrustY(player->mo, forwardangle, playerVisualRadius); - - x2 = player->mo->x + player->mo->momx + P_ReturnThrustX(player->mo, forwardangle - ANGLE_90, playerVisualRadius); - y2 = player->mo->y + player->mo->momy + P_ReturnThrustY(player->mo, forwardangle - ANGLE_90, playerVisualRadius); - x2 = x2 + P_ReturnThrustX(player->mo, forwardangle, playerVisualRadius); - y2 = y2 + P_ReturnThrustY(player->mo, forwardangle, playerVisualRadius); - - // Left - // underlay - water = P_SpawnMobj(x1, y1, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAILUNDERLAY); - P_InitAngle(water, forwardangle - ANGLE_180 - ANGLE_22h); - water->destscale = trailScale; - water->momx = player->mo->momx; - water->momy = player->mo->momy; - water->momz = player->mo->momz; - P_SetScale(water, trailScale); - P_SetMobjState(water, curUnderlayFrame); - - // overlay - water = P_SpawnMobj(x1, y1, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAIL); - P_InitAngle(water, forwardangle - ANGLE_180 - ANGLE_22h); - water->destscale = trailScale; - water->momx = player->mo->momx; - water->momy = player->mo->momy; - water->momz = player->mo->momz; - P_SetScale(water, trailScale); - P_SetMobjState(water, curOverlayFrame); - - // Right - // Underlay - water = P_SpawnMobj(x2, y2, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAILUNDERLAY); - P_InitAngle(water, forwardangle - ANGLE_180 + ANGLE_22h); - water->destscale = trailScale; - water->momx = player->mo->momx; - water->momy = player->mo->momy; - water->momz = player->mo->momz; - P_SetScale(water, trailScale); - P_SetMobjState(water, curUnderlayFrame); - - // Overlay - water = P_SpawnMobj(x2, y2, - ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAIL); - P_InitAngle(water, forwardangle - ANGLE_180 + ANGLE_22h); - water->destscale = trailScale; - water->momx = player->mo->momx; - water->momy = player->mo->momy; - water->momz = player->mo->momz; - P_SetScale(water, trailScale); - P_SetMobjState(water, curOverlayFrame); - - if (!S_SoundPlaying(player->mo, sfx_s3kdbs)) - { - const INT32 volume = (min(trailScale, FRACUNIT) * 255) / FRACUNIT; - S_StartSoundAtVolume(player->mo, sfx_s3kdbs, volume); - } - } - } - - // Little water sound while touching water - just a nicety. - if ((player->mo->eflags & MFE_TOUCHWATER) && !(player->mo->eflags & MFE_UNDERWATER) && !player->spectator) - { - if (P_RandomChance(PR_BUBBLE, FRACUNIT/2) && leveltime % TICRATE == 0) - S_StartSound(player->mo, sfx_floush); - } - //////////////////////////// //SPINNING AND SPINDASHING// //////////////////////////// From e34ec94721d3d9e57333fd7f49f8b9e153e1088e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 18:14:44 -0400 Subject: [PATCH 6/7] Smoothly adjust underwater turn nerf The actual issue was that turning was nerfed by a flat x0.5 when strafing was enabled, but the strafe amount was speed based. This meant that you got way less turning at low speed, and no strafe to make up for it. --- src/k_kart.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 43e14fbdd..bf7200b8a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8974,6 +8974,16 @@ INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering) return outputSteering; } +static fixed_t K_GetUnderwaterStrafeMul(player_t *player) +{ + const fixed_t minSpeed = 11 * player->mo->scale; + fixed_t baseline = INT32_MAX; + + baseline = 2 * K_GetKartSpeed(player, false, true) / 3; + + return max(0, FixedDiv(player->speed - minSpeed, baseline - minSpeed)); +} + INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) { fixed_t turnfixed = turnvalue * FRACUNIT; @@ -9051,10 +9061,10 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnfixed = FixedMul(turnfixed, FRACUNIT + player->handleboost); } - if ((player->mo->eflags & MFE_UNDERWATER) && - player->speed > 11 * player->mo->scale) + if (player->mo->eflags & MFE_UNDERWATER) { - turnfixed /= 2; + fixed_t div = min(FRACUNIT + K_GetUnderwaterStrafeMul(player), 2*FRACUNIT); + turnfixed = FixedDiv(turnfixed, div); } // Weight has a small effect on turning @@ -9065,18 +9075,15 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) INT32 K_GetUnderwaterTurnAdjust(player_t *player) { - if ((player->mo->eflags & MFE_UNDERWATER) && - player->speed > 11 * player->mo->scale) + if (player->mo->eflags & MFE_UNDERWATER) { INT32 steer = (K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE); - fixed_t minimum = INT32_MAX; if (!player->drift) steer = 9 * steer / 5; - minimum = 2 * K_GetKartSpeed(player, false, true) / 3; - return FixedMul(steer, 8 * FixedDiv(max(player->speed, minimum), minimum)); + return FixedMul(steer, 8 * K_GetUnderwaterStrafeMul(player)); } else return 0; From 66da84f1f7398640d1cfe8a3327b5f9f468b1741 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 19:18:06 -0400 Subject: [PATCH 7/7] Fixes for various maps - Don't skip on sloped water. Prevents water skipping on the top of the waterfall and then continuing the skip onto the water at the bottom in Aqueduct Crystal. - Fix Nova Shore regression in this branch by prevents water running if you can step down onto real ground. --- src/p_mobj.c | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 3ab7b2c3b..b7814d0db 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3097,8 +3097,12 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) player_t *player = mobj->player; fixed_t surfaceheight = INT32_MAX; - fixed_t mobjbottom = INT32_MAX; fixed_t surfDiff = INT32_MAX; + + fixed_t floorheight = INT32_MAX; + fixed_t floorDiff = INT32_MAX; + + fixed_t mobjbottom = INT32_MAX; fixed_t maxStep = INT32_MAX; boolean doifit = false; @@ -3142,38 +3146,48 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) { ourZAng = mobj->standingslope->zangle; } - + waterSlope = (flip ? *rover->b_slope : *rover->t_slope); if (waterSlope != NULL) { waterZAng = waterSlope->zangle; } - + if (ourZAng != waterZAng) { // The surface slopes are different. return false; } - + surfaceheight = flip ? P_GetFFloorBottomZAt(rover, mobj->x, mobj->y) : P_GetFFloorTopZAt(rover, mobj->x, mobj->y); mobjbottom = flip ? (mobj->z + mobj->height) : mobj->z; - + doifit = flip ? (surfaceheight - mobj->floorz >= mobj->height) : (mobj->ceilingz - surfaceheight >= mobj->height); - + if (!doifit) { // Object can't fit in this space. return false; } - - surfDiff = flip ? (surfaceheight - mobjbottom) : (mobjbottom - surfaceheight); + maxStep = P_GetThingStepUp(mobj); + + surfDiff = flip ? (surfaceheight - mobjbottom) : (mobjbottom - surfaceheight); if (surfDiff <= maxStep && surfDiff >= 0) { // We start water run IF we can step-down! + floorheight = flip ? P_GetSectorCeilingZAt(mobj->subsector->sector, mobj->x, mobj->y) : P_GetSectorFloorZAt(mobj->subsector->sector, mobj->x, mobj->y); + floorDiff = flip ? (floorheight - mobjbottom) : (mobjbottom - floorheight); + if (floorDiff <= maxStep && floorDiff >= 0) + { + // ... but NOT if real floor is in range. + // FIXME: Count solid FOFs in this check + return false; + } + return true; } - + return false; } @@ -3202,6 +3216,8 @@ void P_MobjCheckWater(mobj_t *mobj) boolean wasgroundpounding = false; fixed_t top2 = P_GetSectorCeilingZAt(sector, mobj->x, mobj->y); fixed_t bot2 = P_GetSectorFloorZAt(sector, mobj->x, mobj->y); + pslope_t *topslope = NULL; + pslope_t *bottomslope = NULL; // Default if no water exists. mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT; @@ -3244,6 +3260,9 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->watertop = topheight; mobj->waterbottom = bottomheight; + topslope = *rover->t_slope; + bottomslope = *rover->b_slope; + // Just touching the water? if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - height < bottomheight) || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + height > topheight)) @@ -3281,6 +3300,8 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->watertop = mobj->z; mobj->waterbottom = mobj->z - height; } + + topslope = bottomslope = NULL; } } @@ -3323,6 +3344,7 @@ void P_MobjCheckWater(mobj_t *mobj) fixed_t waterZ = INT32_MAX; fixed_t solidZ = INT32_MAX; fixed_t diff = INT32_MAX; + INT32 waterDelta = 0; fixed_t thingZ = INT32_MAX; boolean splashValid = false; @@ -3331,11 +3353,19 @@ void P_MobjCheckWater(mobj_t *mobj) { waterZ = mobj->waterbottom; solidZ = mobj->ceilingz; + if (bottomslope) + { + waterDelta = bottomslope->zdelta; + } } else { waterZ = mobj->watertop; solidZ = mobj->floorz; + if (topslope) + { + waterDelta = topslope->zdelta; + } } diff = waterZ - solidZ; @@ -3406,7 +3436,8 @@ void P_MobjCheckWater(mobj_t *mobj) P_SetScale(splish, mobj->scale); // skipping stone! - if (K_WaterSkip(mobj) == true) + if (K_WaterSkip(mobj) == true + && abs(waterDelta) < FRACUNIT/21) // Only on flat water { const fixed_t hop = 5 * mapobjectscale;