diff --git a/src/k_kart.c b/src/k_kart.c index 73661c018..a66f34d32 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2700,6 +2700,19 @@ boolean K_TripwirePass(player_t *player) return false; } +boolean K_WaterRun(player_t *player) +{ + if ( + player->invincibilitytimer || + player->sneakertimer || + player->tiregrease || + player->flamedash || + player->speed > 2 * K_GetKartSpeed(player, false) + ) + return true; + return false; +} + 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 8b0f755d6..0b60d521a 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -108,6 +108,7 @@ void K_MomentumToFacing(player_t *player); boolean K_ApplyOffroad(player_t *player); boolean K_SlopeResistance(player_t *player); boolean K_TripwirePass(player_t *player); +boolean K_WaterRun(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_local.h b/src/p_local.h index 61a8cf3a0..db9e9e6dd 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -333,6 +333,7 @@ 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); void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot); diff --git a/src/p_map.c b/src/p_map.c index d0716790b..bcecb1dfa 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1848,7 +1848,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) continue; } - if (thing->player && P_CheckSolidLava(rover)) + if (thing->player && P_CheckSolidFFloorSurface(thing->player, rover)) ; else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE)) ; @@ -2414,6 +2414,20 @@ boolean PIT_PushableMoved(mobj_t *thing) return true; } +static boolean P_WaterRunning(mobj_t *thing) +{ + ffloor_t *rover = thing->floorrover; + return rover && (rover->flags & FF_SWIMMABLE) && + P_IsObjectOnGround(thing); +} + +static boolean P_WaterStepUp(mobj_t *thing) +{ + player_t *player = thing->player; + return (player && player->waterskip) || + P_WaterRunning(thing); +} + // // P_TryMove // Attempt to move to a new position. @@ -2478,7 +2492,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale); fixed_t maxstep = maxstepmove; - if (thing->player && thing->player->waterskip) + if (thing->player && P_WaterStepUp(thing)) maxstep += maxstepmove; // Add some extra stepmove when waterskipping // If using type Section1:13, double the maxstep. diff --git a/src/p_maputl.c b/src/p_maputl.c index 2e21f5ee3..5acddf09c 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -730,7 +730,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (!(rover->flags & FF_EXISTS)) continue; - if (mobj->player && P_CheckSolidLava(rover)) + if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover)) ; else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) || (rover->flags & FF_BLOCKOTHERS && !mobj->player))) @@ -772,7 +772,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if (!(rover->flags & FF_EXISTS)) continue; - if (mobj->player && P_CheckSolidLava(rover)) + if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, 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 b066e2a1c..5a9f0925e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1879,7 +1879,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_CheckSolidLava(rover)) // only the player should stand on lava + if (mo->player && P_CheckSolidFFloorSurface(mo->player, rover)) // only the player should stand on lava or run on water ; else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only continue; @@ -2940,6 +2940,33 @@ boolean P_SceneryZMovement(mobj_t *mo) return true; } +// P_CanRunOnWater +// +// Returns true if player can waterrun on the 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; + + return + clip > -(player->mo->height / 2) && + span > player->mo->height && + player->speed / 5 > abs(player->mo->momz) && + player->speed > K_GetKartSpeed(player, false) && + K_WaterRun(player) && + (rover->flags & FF_SWIMMABLE); +} + +boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover) +{ + return P_CheckSolidLava(rover) || + P_CanRunOnWater(player, rover); +} + // // P_MobjCheckWater // @@ -2955,7 +2982,10 @@ void P_MobjCheckWater(mobj_t *mobj) ffloor_t *rover; player_t *p = mobj->player; // Will just be null if not a player. fixed_t height = mobj->height; + fixed_t halfheight = height / 2; boolean wasgroundpounding = false; + fixed_t top2 = P_GetSectorCeilingZAt(sector, mobj->x, mobj->y); + fixed_t bot2 = P_GetSectorFloorZAt(sector, mobj->x, mobj->y); // Default if no water exists. mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT; @@ -2966,24 +2996,31 @@ void P_MobjCheckWater(mobj_t *mobj) for (rover = sector->ffloors; rover; rover = rover->next) { fixed_t topheight, bottomheight; - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) - || (((rover->flags & FF_BLOCKPLAYER) && mobj->player) - || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player))) - continue; topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y); bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y); + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) + || (((rover->flags & FF_BLOCKPLAYER) && mobj->player) + || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player))) + { + if (topheight < top2 && topheight > thingtop) + top2 = topheight; + if (bottomheight > bot2 && bottomheight < mobj->z) + bot2 = bottomheight; + continue; + } + if (mobj->eflags & MFE_VERTICALFLIP) { - if (topheight < (thingtop - (height>>1)) - || bottomheight > thingtop) + if (topheight < (thingtop - halfheight) + || bottomheight > (thingtop + halfheight)) continue; } else { - if (topheight < mobj->z - || bottomheight > (mobj->z + (height>>1))) + if (topheight < (mobj->z - halfheight) + || bottomheight > (mobj->z + halfheight)) continue; } @@ -3011,6 +3048,12 @@ void P_MobjCheckWater(mobj_t *mobj) } } + if (mobj->watertop > top2) + mobj->watertop = top2; + + if (mobj->waterbottom < bot2) + mobj->waterbottom = bot2; + // Spectators and dead players don't get to do any of the things after this. if (p && (p->spectator || p->playerstate != PST_LIVE)) return;