diff --git a/src/d_player.h b/src/d_player.h index 7d0f20058..ad7b75b86 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -590,6 +590,8 @@ typedef struct player_s UINT8 shrinkLaserDelay; + mobj_t *stumbleIndicator; + #ifdef HWRENDER fixed_t fovadd; // adjust FOV for hw rendering #endif diff --git a/src/deh_tables.c b/src/deh_tables.c index 37ec83b7f..7f293daa3 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3837,6 +3837,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_TRIPWIREBOOST_BLAST_TOP", "S_TRIPWIREBOOST_BLAST_BOTTOM", + "S_SMOOTHLANDING", + // DEZ respawn laser "S_DEZLASER", "S_DEZLASER_TRAIL1", @@ -5383,6 +5385,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_TRIPWIREBOOST", + "MT_SMOOTHLANDING", + "MT_DEZLASER", "MT_WAYPOINT", diff --git a/src/info.c b/src/info.c index 6fac31311..c14582b98 100644 --- a/src/info.c +++ b/src/info.c @@ -588,6 +588,7 @@ char sprnames[NUMSPRITES + 1][5] = "BEXB", // Battle Bumper Explosion: Blast "TWBS", // Tripwire Boost "TWBT", // Tripwire BLASTER + "SMLD", // Smooth landing "DEZL", // DEZ Laser respawn // Additional Kart Objects @@ -4397,6 +4398,8 @@ state_t states[NUMSTATES] = {SPR_TWBT, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 6, 2, S_NULL}, // S_TRIPWIREBOOST_BLAST_TOP {SPR_TWBT, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE|FF_VERTICALFLIP|FF_HORIZONTALFLIP, -1, {NULL}, 6, 2, S_NULL}, // S_TRIPWIREBOOST_BLAST_BOTTOM + {SPR_SMLD, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_SMOOTHLANDING + {SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER {SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL2}, // S_DEZLASER_TRAIL1 {SPR_DEZL, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL3}, // S_DEZLASER_TRAIL2 @@ -24470,6 +24473,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SMOOTHLANDING + -1, // doomednum + S_SMOOTHLANDING, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + -1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_DEZLASER -1, // doomednum S_DEZLASER, // spawnstate diff --git a/src/info.h b/src/info.h index c5ed74daa..2999ed52b 100644 --- a/src/info.h +++ b/src/info.h @@ -1136,6 +1136,7 @@ typedef enum sprite SPR_BEXB, // Battle Bumper Explosion: Blast SPR_TWBS, // Tripwire Boost SPR_TWBT, // Tripwire BLASTER + SPR_SMLD, // Smooth landing SPR_DEZL, // DEZ Laser respawn // Additional Kart Objects @@ -4833,6 +4834,8 @@ typedef enum state S_TRIPWIREBOOST_BLAST_TOP, S_TRIPWIREBOOST_BLAST_BOTTOM, + S_SMOOTHLANDING, + // DEZ Laser respawn S_DEZLASER, S_DEZLASER_TRAIL1, @@ -6416,6 +6419,8 @@ typedef enum mobj_type MT_TRIPWIREBOOST, + MT_SMOOTHLANDING, + MT_DEZLASER, MT_WAYPOINT, diff --git a/src/k_bot.c b/src/k_bot.c index 968ba8632..1b5a183b0 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -952,6 +952,55 @@ static void K_BotTrick(player_t *player, ticcmd_t *cmd, line_t *botController) } } +/*-------------------------------------------------- + static angle_t K_BotSmoothLanding(player_t *player, angle_t destangle) + + Calculates a new destination angle while in the air, + to be able to successfully smooth land. + + Input Arguments:- + player - Bot player to check. + destangle - Previous destination angle. + + Return:- + New destination angle. +--------------------------------------------------*/ +static angle_t K_BotSmoothLanding(player_t *player, angle_t destangle) +{ + angle_t newAngle = destangle; + boolean air = !P_IsObjectOnGround(player->mo); + angle_t steepVal = air ? STUMBLE_STEEP_VAL_AIR : STUMBLE_STEEP_VAL; + angle_t slopeSteep = max(AngleDelta(player->mo->pitch, 0), AngleDelta(player->mo->roll, 0)); + + if (slopeSteep > steepVal) + { + fixed_t pitchMul = -FINESINE(destangle >> ANGLETOFINESHIFT); + fixed_t rollMul = FINECOSINE(destangle >> ANGLETOFINESHIFT); + angle_t testAngles[2]; + angle_t testDeltas[2]; + UINT8 i; + + testAngles[0] = R_PointToAngle2(0, 0, rollMul, pitchMul); + testAngles[1] = R_PointToAngle2(0, 0, -rollMul, -pitchMul); + + for (i = 0; i < 2; i++) + { + testDeltas[i] = AngleDelta(testAngles[i], destangle); + } + + if (testDeltas[1] < testDeltas[0]) + { + return testAngles[1]; + } + else + { + return testAngles[0]; + } + } + + return newAngle; +} + /*-------------------------------------------------- static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *predict) @@ -975,6 +1024,8 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * I_Assert(predict != NULL); + destangle = K_BotSmoothLanding(player, destangle); + moveangle = player->mo->angle; anglediff = AngleDeltaSigned(moveangle, destangle); @@ -1105,6 +1156,8 @@ static INT32 K_HandleBotReverse(player_t *player, ticcmd_t *cmd, botprediction_t } } + destangle = K_BotSmoothLanding(player, destangle); + // Calculate turn direction first. moveangle = player->mo->angle; angle = (moveangle - destangle); diff --git a/src/k_kart.c b/src/k_kart.c index e14995d05..2b1eb3aa1 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -19,6 +19,7 @@ #include "p_setup.h" #include "r_draw.h" #include "r_local.h" +#include "r_things.c" #include "s_sound.h" #include "st_stuff.h" #include "v_video.h" @@ -3797,6 +3798,234 @@ void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) P_StartQuake(64<> ANGLETOFINESHIFT); + fixed_t rollMul = FINECOSINE(angle >> ANGLETOFINESHIFT); + + angle_t slope = FixedMul(pitch, pitchMul) + FixedMul(roll, rollMul); + + if (slope > ANGLE_180) + { + slope = InvAngle(slope); + } + + return slope; +} + +boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir) +{ + angle_t steepVal = ANGLE_MAX; + fixed_t gravityadjust; + angle_t oldSlope, newSlope; + angle_t slopeDelta; + + // If you don't land upright on a slope, then you tumble, + // kinda like Kirby Air Ride + + if (player->tumbleBounces) + { + // Already tumbling. + return false; + } + + if ((player->mo->pitch == oldPitch) + && (player->mo->roll == oldRoll)) + { + // No change. + return false; + } + + if (fromAir == true) + { + steepVal = STUMBLE_STEEP_VAL_AIR; + } + else + { + steepVal = STUMBLE_STEEP_VAL; + } + + oldSlope = K_StumbleSlope(player->mo->angle, oldPitch, oldRoll); + + if (oldSlope <= steepVal) + { + // Transferring from flat ground to a steep slope + // is a free action. (The other way around isn't, though.) + return false; + } + + newSlope = K_StumbleSlope(player->mo->angle, player->mo->pitch, player->mo->roll); + slopeDelta = AngleDelta(oldSlope, newSlope); + + if (slopeDelta <= steepVal) + { + // Needs to be VERY steep before we'll punish this. + return false; + } + + // Oh jeez, you landed on your side. + // You get to tumble. + + P_ResetPlayer(player); + +#if 0 + // Single, medium bounce + player->tumbleBounces = TUMBLEBOUNCES; + player->tumbleHeight = 30; +#else + // Two small bounces + player->tumbleBounces = TUMBLEBOUNCES-1; + player->tumbleHeight = 20; +#endif + + player->pflags &= ~PF_TUMBLESOUND; + S_StartSound(player->mo, sfx_s3k9b); + + gravityadjust = P_GetMobjGravity(player->mo)/2; // so we'll halve it for our calculations. + + if (player->mo->eflags & MFE_UNDERWATER) + gravityadjust /= 2; // halve "gravity" underwater + + // and then modulate momz like that... + player->mo->momz = -gravityadjust * player->tumbleHeight; + + P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); + + if (P_IsDisplayPlayer(player)) + P_StartQuake(64<mo->pitch = player->mo->roll = 0; + return true; +} + +void K_InitStumbleIndicator(player_t *player) +{ + mobj_t *new = NULL; + + if (player == NULL) + { + return; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + return; + } + + if (player->stumbleIndicator != NULL && P_MobjWasRemoved(player->stumbleIndicator) == false) + { + P_RemoveMobj(player->stumbleIndicator); + } + + new = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_SMOOTHLANDING); + + P_SetTarget(&player->stumbleIndicator, new); + P_SetTarget(&new->target, player->mo); +} + +void K_UpdateStumbleIndicator(player_t *player) +{ + const angle_t fudge = ANG15; + mobj_t *mobj = NULL; + + boolean air = false; + angle_t steepVal = STUMBLE_STEEP_VAL; + angle_t slopeSteep = 0; + angle_t steepRange = ANGLE_90; + + INT32 delta = 0; + INT32 trans = 0; + + if (player == NULL) + { + return; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + return; + } + + if (player->stumbleIndicator == NULL || P_MobjWasRemoved(player->stumbleIndicator) == true) + { + K_InitStumbleIndicator(player); + return; + } + + mobj = player->stumbleIndicator; + + P_MoveOrigin(mobj, player->mo->x, player->mo->y, player->mo->z + (player->mo->height / 2)); + + air = !P_IsObjectOnGround(player->mo); + steepVal = (air ? STUMBLE_STEEP_VAL_AIR : STUMBLE_STEEP_VAL) - fudge; + slopeSteep = max(AngleDelta(player->mo->pitch, 0), AngleDelta(player->mo->roll, 0)); + + delta = 0; + + if (slopeSteep > steepVal) + { + angle_t testAngles[2]; + INT32 testDeltas[2]; + UINT8 i; + + testAngles[0] = R_PointToAngle2(0, 0, player->mo->pitch, player->mo->roll); + testAngles[1] = R_PointToAngle2(0, 0, -player->mo->pitch, -player->mo->roll); + + for (i = 0; i < 2; i++) + { + testDeltas[i] = AngleDeltaSigned(player->mo->angle, testAngles[i]); + } + + if (abs(testDeltas[1]) < abs(testDeltas[0])) + { + delta = testDeltas[1]; + } + else + { + delta = testDeltas[0]; + } + } + + if (delta < 0) + { + mobj->renderflags |= RF_HORIZONTALFLIP; + } + else + { + mobj->renderflags &= ~RF_HORIZONTALFLIP; + } + + steepRange = ANGLE_90 - steepVal; + delta = max(0, abs(delta) - ((signed)steepVal)); + trans = ((FixedDiv(AngleFixed(delta), AngleFixed(steepRange)) * (NUMTRANSMAPS - 2)) + (FRACUNIT/2)) / FRACUNIT; + + if (trans < 0) + { + trans = 0; + } + + if (trans > (NUMTRANSMAPS - 2)) + { + trans = (NUMTRANSMAPS - 2); + } + + // invert + trans = (NUMTRANSMAPS - 2) - trans; + + mobj->renderflags |= RF_DONTDRAW; + + if (trans < (NUMTRANSMAPS - 2)) + { + mobj->renderflags &= ~(RF_TRANSMASK | K_GetPlayerDontDrawFlag(player)); + + if (trans != 0) + { + mobj->renderflags |= (trans << RF_TRANSSHIFT); + } + } +} + static boolean K_LastTumbleBounceCondition(player_t *player) { return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 60); @@ -3831,6 +4060,7 @@ static void K_HandleTumbleBounce(player_t *player) player->tumbleHeight = 10; player->pflags |= PF_TUMBLELASTBOUNCE; player->mo->rollangle = 0; // p_user.c will stop rotating the player automatically + player->mo->pitch = player->mo->roll = 0; // Prevent Kodachrome Void infinite } } @@ -7899,6 +8129,8 @@ void K_KartPlayerAfterThink(player_t *player) { K_KartResetPlayerColor(player); + K_UpdateStumbleIndicator(player); + // Move held objects (Bananas, Orbinaut, etc) K_MoveHeldObjects(player); @@ -9340,31 +9572,7 @@ static void K_KartSpindash(player_t *player) } else if (player->fastfall != 0) { - // Handle fastfall bounce. - const fixed_t maxBounce = player->mo->scale * 10; - const fixed_t minBounce = player->mo->scale; - fixed_t bounce = 2 * abs(player->fastfall) / 3; - - if (bounce > maxBounce) - { - bounce = maxBounce; - } - else - { - // Lose speed on bad bounce. - player->mo->momx /= 2; - player->mo->momy /= 2; - - if (bounce < minBounce) - { - bounce = minBounce; - } - } - - S_StartSound(player->mo, sfx_ffbonc); - player->mo->momz = bounce * P_MobjFlip(player->mo); - - player->fastfall = 0; + // Still handling fast-fall bounce. return; } @@ -9431,6 +9639,41 @@ static void K_KartSpindash(player_t *player) #undef SPINDASHTHRUSTTIME +boolean K_FastFallBounce(player_t *player) +{ + // Handle fastfall bounce. + if (player->fastfall != 0) + { + const fixed_t maxBounce = player->mo->scale * 10; + const fixed_t minBounce = player->mo->scale; + fixed_t bounce = 2 * abs(player->fastfall) / 3; + + if (bounce > maxBounce) + { + bounce = maxBounce; + } + else + { + // Lose speed on bad bounce. + player->mo->momx /= 2; + player->mo->momy /= 2; + + if (bounce < minBounce) + { + bounce = minBounce; + } + } + + S_StartSound(player->mo, sfx_ffbonc); + player->mo->momz = bounce * P_MobjFlip(player->mo); + + player->fastfall = 0; + return true; + } + + return false; +} + static void K_AirFailsafe(player_t *player) { const fixed_t maxSpeed = 6*player->mo->scale; diff --git a/src/k_kart.h b/src/k_kart.h index 7b1e0f6ae..46f97a3f5 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -28,6 +28,9 @@ Make sure this matches the actual number of states #define GROW_PHYSICS_SCALE (3*FRACUNIT/2) #define SHRINK_PHYSICS_SCALE (3*FRACUNIT/4) +#define STUMBLE_STEEP_VAL ANG60 +#define STUMBLE_STEEP_VAL_AIR (ANG30 + ANG10) + player_t *K_GetItemBoxPlayer(mobj_t *mobj); angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t yourspeed); @@ -75,6 +78,10 @@ void K_RemoveGrowShrink(player_t *player); void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type); void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_TumbleInterrupt(player_t *player); +angle_t K_StumbleSlope(angle_t angle, angle_t pitch, angle_t roll); +boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir); +void K_InitStumbleIndicator(player_t *player); +void K_UpdateStumbleIndicator(player_t *player); INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_DebtStingPlayer(player_t *player, mobj_t *source); void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers); @@ -142,6 +149,7 @@ fixed_t K_GetNewSpeed(player_t *player); fixed_t K_3dKartMovement(player_t *player); boolean K_PlayerEBrake(player_t *player); SINT8 K_Sliptiding(player_t *player); +boolean K_FastFallBounce(player_t *player); void K_AdjustPlayerFriction(player_t *player); void K_MoveKartPlayer(player_t *player, boolean onground); void K_CheckSpectateStatus(void); diff --git a/src/p_local.h b/src/p_local.h index 6c885191c..5fc73f1a2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -172,7 +172,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec); boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec); // SRB2Kart #define P_IsObjectFlipped(o) ((o)->eflags & MFE_VERTICALFLIP) boolean P_InQuicksand(mobj_t *mo); -boolean P_PlayerHitFloor(player_t *player, boolean fromAir); +boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, angle_t oldRoll); void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_RestoreMusic(player_t *player); diff --git a/src/p_map.c b/src/p_map.c index e00cbea1c..5b1827988 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2801,12 +2801,15 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->momz <= 0) { + angle_t oldPitch = thing->pitch; + angle_t oldRoll = thing->roll; + thing->standingslope = tmfloorslope; P_SetPitchRollFromSlope(thing, thing->standingslope); - if (thing->momz == 0 && thing->player && !startingonground) + if (thing->player) { - P_PlayerHitFloor(thing->player, true); + P_PlayerHitFloor(thing->player, !startingonground, oldPitch, oldRoll); } } } @@ -2821,12 +2824,15 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->momz >= 0) { + angle_t oldPitch = thing->pitch; + angle_t oldRoll = thing->roll; + thing->standingslope = tmceilingslope; P_SetPitchRollFromSlope(thing, thing->standingslope); - if (thing->momz == 0 && thing->player && !startingonground) + if (thing->player) { - P_PlayerHitFloor(thing->player, true); + P_PlayerHitFloor(thing->player, !startingonground, oldPitch, oldRoll); } } } @@ -3117,7 +3123,7 @@ static boolean P_ThingHeightClip(mobj_t *thing) } if ((P_MobjFlip(thing)*(thing->z - oldz) > 0 || hitfloor) && thing->player) - P_PlayerHitFloor(thing->player, !onfloor); + P_PlayerHitFloor(thing->player, !onfloor, thing->pitch, thing->roll); // debug: be sure it falls to the floor thing->eflags &= ~MFE_ONGROUND; diff --git a/src/p_mobj.c b/src/p_mobj.c index d3fa4eac1..28b596e2e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1534,12 +1534,18 @@ void P_XYMovement(mobj_t *mo) } // adjust various things based on slope - if (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8) { - if (!P_IsObjectOnGround(mo)) { // We fell off at some point? Do the twisty thing! + if (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8) + { + if (!P_IsObjectOnGround(mo)) + { + // We fell off at some point? Do the twisty thing! P_SlopeLaunch(mo); xmove = mo->momx; ymove = mo->momy; - } else { // Still on the ground. + } + else + { + // Still on the ground. slopemom.x = xmove; slopemom.y = ymove; slopemom.z = 0; @@ -1771,7 +1777,9 @@ void P_XYMovement(mobj_t *mo) if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;; return; - if (moved && oldslope && !(mo->flags & MF_NOCLIPHEIGHT)) { // Check to see if we ran off + if (moved && oldslope && !(mo->flags & MF_NOCLIPHEIGHT)) + { + // Check to see if we ran off if (oldslope != mo->standingslope) { @@ -2727,6 +2735,7 @@ static boolean P_PlayerPolyObjectZMovement(mobj_t *mo) void P_PlayerZMovement(mobj_t *mo) { boolean onground; + angle_t oldPitch, oldRoll; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -2734,6 +2743,9 @@ void P_PlayerZMovement(mobj_t *mo) if (!mo->player) return; + oldPitch = mo->pitch; + oldRoll = mo->roll; + // Intercept the stupid 'fall through 3dfloors' bug if (mo->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0); @@ -2810,7 +2822,7 @@ void P_PlayerZMovement(mobj_t *mo) mo->pmomz = 0; // We're on a new floor, don't keep doing platform movement. mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack - clipmomz = P_PlayerHitFloor(mo->player, true); + clipmomz = P_PlayerHitFloor(mo->player, true, oldPitch, oldRoll); P_PlayerPolyObjectZMovement(mo); if (clipmomz) @@ -2846,6 +2858,47 @@ void P_PlayerZMovement(mobj_t *mo) mo->eflags &= ~MFE_JUSTHITFLOOR; P_CheckGravity(mo, true); } + + // Even out pitch & roll slowly over time when respawning. + if (mo->player->respawn.state != RESPAWNST_NONE) + { + const angle_t speed = ANG2; //FixedMul(ANG2, abs(mo->momz) / 8); + angle_t dest = 0; + INT32 pitchDelta = AngleDeltaSigned(mo->pitch, 0); + INT32 rollDelta = AngleDeltaSigned(mo->roll, 0); + + if (abs(pitchDelta) <= speed && dest == 0) + { + mo->pitch = 0; + } + else if (abs(pitchDelta) > dest) + { + if (pitchDelta > 0) + { + mo->pitch -= speed; + } + else + { + mo->pitch += speed; + } + } + + if (abs(rollDelta) <= speed && dest == 0) + { + mo->roll = 0; + } + else if (abs(rollDelta) > dest) + { + if (rollDelta > 0) + { + mo->roll -= speed; + } + else + { + mo->roll += speed; + } + } + } } if (((mo->eflags & MFE_VERTICALFLIP && mo->z < mo->floorz) || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z + mo->height > mo->ceilingz)) @@ -11333,6 +11386,8 @@ void P_SpawnPlayer(INT32 playernum) P_SetScale(mobj, mobj->destscale); P_FlashPal(p, 0, 0); // Resets + K_InitStumbleIndicator(p); + if (gametyperules & GTR_BUMPERS) { mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW); diff --git a/src/p_saveg.c b/src/p_saveg.c index da85dac77..f1e51d3fb 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -64,6 +64,7 @@ typedef enum SKYBOXVIEW = 0x08, SKYBOXCENTER = 0x10, HOVERHYUDORO = 0x20, + STUMBLE = 0x40, } player_saveflags; static inline void P_ArchivePlayer(void) @@ -202,6 +203,9 @@ static void P_NetArchivePlayers(void) if (players[i].hoverhyudoro) flags |= HOVERHYUDORO; + if (players[i].stumbleIndicator) + flags |= STUMBLE; + WRITEUINT16(save_p, flags); if (flags & SKYBOXVIEW) @@ -219,6 +223,9 @@ static void P_NetArchivePlayers(void) if (flags & HOVERHYUDORO) WRITEUINT32(save_p, players[i].hoverhyudoro->mobjnum); + if (flags & STUMBLE) + WRITEUINT32(save_p, players[i].stumbleIndicator->mobjnum); + WRITEUINT32(save_p, (UINT32)players[i].followitem); WRITEUINT32(save_p, players[i].charflags); @@ -509,6 +516,9 @@ static void P_NetUnArchivePlayers(void) if (flags & HOVERHYUDORO) players[i].hoverhyudoro = (mobj_t *)(size_t)READUINT32(save_p); + if (flags & STUMBLE) + players[i].stumbleIndicator = (mobj_t *)(size_t)READUINT32(save_p); + players[i].followitem = (mobjtype_t)READUINT32(save_p); //SetPlayerSkinByNum(i, players[i].skin); @@ -4289,6 +4299,13 @@ static void P_RelinkPointers(void) if (!P_SetTarget(&mobj->player->hoverhyudoro, P_FindNewPosition(temp))) CONS_Debug(DBG_GAMELOGIC, "hoverhyudoro not found on %d\n", mobj->type); } + if (mobj->player->stumbleIndicator) + { + temp = (UINT32)(size_t)mobj->player->stumbleIndicator; + mobj->player->stumbleIndicator = NULL; + if (!P_SetTarget(&mobj->player->stumbleIndicator, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "stumbleIndicator not found on %d\n", mobj->type); + } } } } diff --git a/src/p_user.c b/src/p_user.c index 1e1cfcbcb..f733bad28 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1339,7 +1339,7 @@ void P_DoPlayerExit(player_t *player) // // Handles player hitting floor surface. // Returns whether to clip momz. -boolean P_PlayerHitFloor(player_t *player, boolean fromAir) +boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, angle_t oldRoll) { boolean clipmomz; @@ -1347,9 +1347,32 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir) clipmomz = !(P_CheckDeathPitCollide(player->mo)); - if (fromAir == true && clipmomz == true) + if (clipmomz == true) { - K_SpawnSplashForMobj(player->mo, abs(player->mo->momz)); + if (fromAir == true) + { + K_SpawnSplashForMobj(player->mo, abs(player->mo->momz)); + } + + if (player->mo->health > 0) + { + boolean air = fromAir; + + if (P_IsObjectOnGround(player->mo) && (player->mo->eflags & MFE_JUSTHITFLOOR)) + { + air = true; + } + + if (K_CheckStumble(player, oldPitch, oldRoll, air) == true) + { + return false; + } + + if (air == false && K_FastFallBounce(player) == true) + { + return false; + } + } } return clipmomz; @@ -1662,7 +1685,7 @@ static void P_CheckQuicksand(player_t *player) player->mo->z = ceilingheight - player->mo->height; if (player->mo->momz <= 0) - P_PlayerHitFloor(player, false); + P_PlayerHitFloor(player, false, player->mo->roll, player->mo->pitch); } else { @@ -1674,7 +1697,7 @@ static void P_CheckQuicksand(player_t *player) player->mo->z = floorheight; if (player->mo->momz >= 0) - P_PlayerHitFloor(player, false); + P_PlayerHitFloor(player, false, player->mo->roll, player->mo->pitch); } friction = abs(rover->master->v1->y - rover->master->v2->y)>>6;