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.
This commit is contained in:
Sally Coolatta 2022-09-27 12:31:33 -04:00
parent 81926947d5
commit 841bcf3619
12 changed files with 158 additions and 73 deletions

View file

@ -438,7 +438,6 @@ typedef struct player_s
INT32 underwatertilt; INT32 underwatertilt;
fixed_t offroad; // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed 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 tiregrease; // Reduced friction timer after hitting a spring
UINT16 springstars; // Spawn stars around a player when they hit a spring UINT16 springstars; // Spawn stars around a player when they hit a spring

View file

@ -3255,35 +3255,90 @@ boolean K_MovingHorizontally(mobj_t *mobj)
return (P_AproxDistance(mobj->momx, mobj->momy) / 5 > abs(mobj->momz)); return (P_AproxDistance(mobj->momx, mobj->momy) / 5 > abs(mobj->momz));
} }
boolean K_WaterRun(player_t *player) boolean K_WaterRun(mobj_t *mobj)
{ {
if ( switch (mobj->type)
player->invincibilitytimer || {
player->sneakertimer || case MT_JAWZ:
player->tiregrease || {
player->flamedash || if (mobj->tracer != NULL && P_MobjWasRemoved(mobj->tracer) == false)
player->speed > 2 * K_GetKartSpeed(player, false, false) {
) fixed_t jawzFeet = P_GetMobjFeet(mobj);
return true; fixed_t chaseFeet = P_GetMobjFeet(mobj->tracer);
return false; 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. // Already finished waterskipping.
return false; 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. // Already waterskipping.
// Simply make sure you haven't slowed down drastically. // 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) 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) if (player->instashield)
player->instashield--; player->instashield--;

View file

@ -143,8 +143,8 @@ boolean K_SlopeResistance(player_t *player);
tripwirepass_t K_TripwirePassConditions(player_t *player); tripwirepass_t K_TripwirePassConditions(player_t *player);
boolean K_TripwirePass(player_t *player); boolean K_TripwirePass(player_t *player);
boolean K_MovingHorizontally(mobj_t *mobj); boolean K_MovingHorizontally(mobj_t *mobj);
boolean K_WaterRun(player_t *player); boolean K_WaterRun(mobj_t *mobj);
boolean K_WaterSkip(player_t *player); boolean K_WaterSkip(mobj_t *mobj);
void K_ApplyTripWire(player_t *player, tripwirestate_t state); void K_ApplyTripWire(player_t *player, tripwirestate_t state);
INT16 K_GetSpindashChargeTime(player_t *player); INT16 K_GetSpindashChargeTime(player_t *player);
fixed_t K_GetSpindashChargeSpeed(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player);

View file

@ -954,12 +954,15 @@ static int lib_pCheckDeathPitCollide(lua_State *L)
static int lib_pCheckSolidLava(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)); ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
//HUDSAFE //HUDSAFE
INLEVEL INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
if (!rover) if (!rover)
return LUA_ErrInvalid(L, "ffloor_t"); return LUA_ErrInvalid(L, "ffloor_t");
lua_pushboolean(L, P_CheckSolidLava(rover)); lua_pushboolean(L, P_CheckSolidLava(mo, rover));
return 1; return 1;
} }

View file

@ -100,6 +100,7 @@ enum mobj_e {
mobj_spryoff, mobj_spryoff,
mobj_sprzoff, mobj_sprzoff,
mobj_hitlag, mobj_hitlag,
mobj_waterskip,
mobj_dispoffset mobj_dispoffset
}; };
@ -181,6 +182,7 @@ static const char *const mobj_opt[] = {
"spryoff", "spryoff",
"sprzoff", "sprzoff",
"hitlag", "hitlag",
"waterskip",
"dispoffset", "dispoffset",
NULL}; NULL};
@ -460,6 +462,9 @@ static int mobj_get(lua_State *L)
case mobj_hitlag: case mobj_hitlag:
lua_pushinteger(L, mo->hitlag); lua_pushinteger(L, mo->hitlag);
break; break;
case mobj_waterskip:
lua_pushinteger(L, mo->waterskip);
break;
case mobj_dispoffset: case mobj_dispoffset:
lua_pushinteger(L, mo->dispoffset); lua_pushinteger(L, mo->dispoffset);
break; break;
@ -835,6 +840,9 @@ static int mobj_set(lua_State *L)
case mobj_hitlag: case mobj_hitlag:
mo->hitlag = luaL_checkinteger(L, 3); mo->hitlag = luaL_checkinteger(L, 3);
break; break;
case mobj_waterskip:
mo->waterskip = (UINT8)luaL_checkinteger(L, 3);
break;
case mobj_dispoffset: case mobj_dispoffset:
mo->dispoffset = luaL_checkinteger(L, 3); mo->dispoffset = luaL_checkinteger(L, 3);
break; break;

View file

@ -264,8 +264,6 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->aizdriftturn); lua_pushinteger(L, plr->aizdriftturn);
else if (fastcmp(field,"offroad")) else if (fastcmp(field,"offroad"))
lua_pushinteger(L, plr->offroad); lua_pushinteger(L, plr->offroad);
else if (fastcmp(field,"waterskip"))
lua_pushinteger(L, plr->waterskip);
else if (fastcmp(field,"tiregrease")) else if (fastcmp(field,"tiregrease"))
lua_pushinteger(L, plr->tiregrease); lua_pushinteger(L, plr->tiregrease);
else if (fastcmp(field,"springstars")) else if (fastcmp(field,"springstars"))
@ -634,8 +632,6 @@ static int player_set(lua_State *L)
plr->aizdriftturn = luaL_checkinteger(L, 3); plr->aizdriftturn = luaL_checkinteger(L, 3);
else if (fastcmp(field,"offroad")) else if (fastcmp(field,"offroad"))
plr->offroad = luaL_checkinteger(L, 3); plr->offroad = luaL_checkinteger(L, 3);
else if (fastcmp(field,"waterskip"))
plr->waterskip = luaL_checkinteger(L, 3);
else if (fastcmp(field,"tiregrease")) else if (fastcmp(field,"tiregrease"))
plr->tiregrease = luaL_checkinteger(L, 3); plr->tiregrease = luaL_checkinteger(L, 3);
else if (fastcmp(field,"springstars")) else if (fastcmp(field,"springstars"))

View file

@ -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_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover);
boolean P_CheckDeathPitCollide(mobj_t *mo); 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); 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); 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); void P_Attract(mobj_t *source, mobj_t *enemy, boolean nightsgrab);
mobj_t *P_GetClosestAxis(mobj_t *source); mobj_t *P_GetClosestAxis(mobj_t *source);
boolean P_CanRunOnWater(player_t *player, ffloor_t *rover); boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover);
boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover); boolean P_CheckSolidFFloorSurface(mobj_t *mobj, ffloor_t *rover);
void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot); void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot);

View file

@ -1940,7 +1940,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
continue; continue;
} }
if (thing->player && P_CheckSolidFFloorSurface(thing->player, rover)) if (P_CheckSolidFFloorSurface(thing, rover))
; ;
else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE)) 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) static boolean P_WaterStepUp(mobj_t *thing)
{ {
player_t *player = thing->player; return (thing->waterskip > 0 || P_WaterRunning(thing));
return (player && player->waterskip) ||
P_WaterRunning(thing);
} }
fixed_t P_BaseStepUp(void) fixed_t P_BaseStepUp(void)

View file

@ -777,7 +777,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
if (!(rover->flags & FF_EXISTS)) if (!(rover->flags & FF_EXISTS))
continue; continue;
if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover)) if (P_CheckSolidFFloorSurface(mobj, rover))
; ;
else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
|| (rover->flags & FF_BLOCKOTHERS && !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)) if (!(rover->flags & FF_EXISTS))
continue; continue;
if (mobj->player && P_CheckSolidFFloorSurface(mobj->player, rover)) if (P_CheckSolidFFloorSurface(mobj, rover))
; ;
else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player) else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
|| (rover->flags & FF_BLOCKOTHERS && !mobj->player))) || (rover->flags & FF_BLOCKOTHERS && !mobj->player)))

View file

@ -1105,6 +1105,11 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
} }
} }
if (mo->waterskip > 0)
{
gravityadd = (4*gravityadd)/3;
}
if (mo->player) if (mo->player)
{ {
if (mo->flags2 & MF2_OBJECTFLIP) if (mo->flags2 & MF2_OBJECTFLIP)
@ -1118,11 +1123,6 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
P_PlayerFlip(mo); P_PlayerFlip(mo);
} }
if (mo->player->waterskip)
{
gravityadd = (4*gravityadd)/3;
}
if (mo->player->trickpanel >= 2) if (mo->player->trickpanel >= 2)
{ {
gravityadd = (5*gravityadd)/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); topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL);
bottomheight = P_GetFOFBottomZ(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 else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only
continue; continue;
@ -2097,11 +2097,18 @@ boolean P_CheckDeathPitCollide(mobj_t *mo)
return false; 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 if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
&& !(rover->master->flags & ML_BLOCKPLAYERS)) && !(rover->master->flags & ML_BLOCKPLAYERS))
return true; {
return true;
}
return false; return false;
} }
@ -3084,11 +3091,13 @@ boolean P_SceneryZMovement(mobj_t *mo)
// //
// Returns true if player can water run on a 3D floor // 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 surfaceheight = INT32_MAX;
fixed_t playerbottom = INT32_MAX; fixed_t mobjbottom = INT32_MAX;
fixed_t surfDiff = INT32_MAX; fixed_t surfDiff = INT32_MAX;
fixed_t maxStep = INT32_MAX; fixed_t maxStep = INT32_MAX;
boolean doifit = false; boolean doifit = false;
@ -3109,28 +3118,29 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover)
return false; return false;
} }
if (player->carry != CR_NONE) // Special carry state. if (player != NULL
&& player->carry != CR_NONE) // Special carry state.
{ {
// No good player state. // No good player state.
return false; return false;
} }
if (P_IsObjectOnGround(player->mo) == false) if (P_IsObjectOnGround(mobj) == false)
{ {
// Don't allow jumping onto water to start a water run. // Don't allow jumping onto water to start a water run.
// (Already water running still counts as being on the ground.) // (Already water running still counts as being on the ground.)
return false; return false;
} }
if (K_WaterRun(player) == false) if (K_WaterRun(mobj) == false)
{ {
// Basic conditions for enabling water run. // Basic conditions for enabling water run.
return false; 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); waterSlope = (flip ? *rover->b_slope : *rover->t_slope);
@ -3145,19 +3155,19 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover)
return false; return false;
} }
surfaceheight = flip ? P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y) : P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); surfaceheight = flip ? P_GetFFloorBottomZAt(rover, mobj->x, mobj->y) : P_GetFFloorTopZAt(rover, mobj->x, mobj->y);
playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z; 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) if (!doifit)
{ {
// Player can't fit in this space. // Object can't fit in this space.
return false; return false;
} }
surfDiff = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); surfDiff = flip ? (surfaceheight - mobjbottom) : (mobjbottom - surfaceheight);
maxStep = P_GetThingStepUp(player->mo); maxStep = P_GetThingStepUp(mobj);
if (surfDiff <= maxStep && surfDiff >= 0) if (surfDiff <= maxStep && surfDiff >= 0)
{ {
// We start water run IF we can step-down! // We start water run IF we can step-down!
@ -3167,10 +3177,10 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover)
return false; return false;
} }
boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover) boolean P_CheckSolidFFloorSurface(mobj_t *mobj, ffloor_t *rover)
{ {
return P_CheckSolidLava(rover) || return P_CheckSolidLava(mobj, rover) ||
P_CanRunOnWater(player, rover); P_CanRunOnWater(mobj, rover);
} }
// //
@ -3286,16 +3296,24 @@ void P_MobjCheckWater(mobj_t *mobj)
return; return;
} }
if (p && !p->waterskip && if (P_IsObjectOnGround(mobj) == true)
p->curshield != KSHIELD_BUBBLE && wasinwater)
{ {
S_StartSound(mobj, sfx_s3k38); mobj->waterskip = 0;
} }
if ((p) // Players if (mobj->waterskip == 0 && wasinwater)
|| (mobj->flags & MF_PUSHABLE) // Pushables {
|| ((mobj->info->flags & MF_PUSHABLE) && mobj->fuse) // Previously pushable, might be moving still if (p && p->curshield == KSHIELD_BUBBLE)
) {
;
}
else
{
S_StartSound(mobj, sfx_s3k38);
}
}
if (mobj->flags & MF_APPLYTERRAIN)
{ {
fixed_t waterZ = INT32_MAX; fixed_t waterZ = INT32_MAX;
fixed_t solidZ = INT32_MAX; fixed_t solidZ = INT32_MAX;
@ -3383,7 +3401,7 @@ void P_MobjCheckWater(mobj_t *mobj)
P_SetScale(splish, mobj->scale); P_SetScale(splish, mobj->scale);
// skipping stone! // skipping stone!
if (K_WaterSkip(p) == true) if (K_WaterSkip(mobj) == true)
{ {
const fixed_t hop = 5 * mapobjectscale; const fixed_t hop = 5 * mapobjectscale;
@ -3391,11 +3409,11 @@ void P_MobjCheckWater(mobj_t *mobj)
mobj->momy = (4*mobj->momy)/5; mobj->momy = (4*mobj->momy)/5;
mobj->momz = hop * P_MobjFlip(mobj); 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 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->colorized = false;
mobj->hitlag = 0; mobj->hitlag = 0;
mobj->waterskip = 0;
// Set shadowscale here, before spawn hook so that Lua can change it // Set shadowscale here, before spawn hook so that Lua can change it
P_DefaultMobjShadowScale(mobj); P_DefaultMobjShadowScale(mobj);

View file

@ -409,6 +409,7 @@ typedef struct mobj_s
struct mobj_s *terrainOverlay; // Overlay sprite object for terrain struct mobj_s *terrainOverlay; // Overlay sprite object for terrain
INT32 hitlag; // Sal-style hit lag, straight from Captain Fetch's jowls INT32 hitlag; // Sal-style hit lag, straight from Captain Fetch's jowls
UINT8 waterskip; // Water skipping counter
INT32 dispoffset; INT32 dispoffset;

View file

@ -280,7 +280,6 @@ static void P_NetArchivePlayers(void)
WRITEINT32(save_p, players[i].underwatertilt); WRITEINT32(save_p, players[i].underwatertilt);
WRITEFIXED(save_p, players[i].offroad); WRITEFIXED(save_p, players[i].offroad);
WRITEUINT8(save_p, players[i].waterskip);
WRITEUINT16(save_p, players[i].tiregrease); WRITEUINT16(save_p, players[i].tiregrease);
WRITEUINT16(save_p, players[i].springstars); WRITEUINT16(save_p, players[i].springstars);
@ -577,7 +576,6 @@ static void P_NetUnArchivePlayers(void)
players[i].underwatertilt = READINT32(save_p); players[i].underwatertilt = READINT32(save_p);
players[i].offroad = READFIXED(save_p); players[i].offroad = READFIXED(save_p);
players[i].waterskip = READUINT8(save_p);
players[i].tiregrease = READUINT16(save_p); players[i].tiregrease = READUINT16(save_p);
players[i].springstars = READUINT16(save_p); players[i].springstars = READUINT16(save_p);
@ -1638,6 +1636,7 @@ typedef enum
MD2_ITNEXT = 1<<27, MD2_ITNEXT = 1<<27,
MD2_LASTMOMZ = 1<<28, MD2_LASTMOMZ = 1<<28,
MD2_TERRAIN = 1<<29, MD2_TERRAIN = 1<<29,
MD2_WATERSKIP = 1<<30,
} mobj_diff2_t; } mobj_diff2_t;
typedef enum typedef enum
@ -1872,6 +1871,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
} }
if (mobj->hitlag) if (mobj->hitlag)
diff2 |= MD2_HITLAG; diff2 |= MD2_HITLAG;
if (mobj->waterskip)
diff2 |= MD2_WATERSKIP;
if (mobj->dispoffset) if (mobj->dispoffset)
diff2 |= MD2_DISPOFFSET; diff2 |= MD2_DISPOFFSET;
if (mobj == waypointcap) if (mobj == waypointcap)
@ -2082,6 +2083,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
{ {
WRITEINT32(save_p, mobj->hitlag); WRITEINT32(save_p, mobj->hitlag);
} }
if (diff2 & MD2_WATERSKIP)
{
WRITEUINT8(save_p, mobj->waterskip);
}
if (diff2 & MD2_DISPOFFSET) if (diff2 & MD2_DISPOFFSET)
{ {
WRITEINT32(save_p, mobj->dispoffset); WRITEINT32(save_p, mobj->dispoffset);
@ -3191,6 +3196,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
{ {
mobj->hitlag = READINT32(save_p); mobj->hitlag = READINT32(save_p);
} }
if (diff2 & MD2_WATERSKIP)
{
mobj->waterskip = READUINT8(save_p);
}
if (diff2 & MD2_DISPOFFSET) if (diff2 & MD2_DISPOFFSET)
{ {
mobj->dispoffset = READINT32(save_p); mobj->dispoffset = READINT32(save_p);