diff --git a/src/k_kart.c b/src/k_kart.c index 58cb6fe31..7bd45c029 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3407,6 +3407,89 @@ void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) P_StartQuake(64<angle >> ANGLETOFINESHIFT); + fixed_t rollMul = FINECOSINE(mobj->angle >> ANGLETOFINESHIFT); + + return FixedMul(pitch, pitchMul) + FixedMul(roll, rollMul); +} + +#define STEEP_VAL (ANG60) + +void K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll) +{ + fixed_t gravityadjust; + angle_t oldSlope, newSlope; + angle_t slopeDelta; + angle_t oldSteepness; + + // If you don't land upright on a slope, then you tumble, + // kinda like Kirby Air Ride + + if (player->tumbleBounces) + { + // Already tumbling. + return; + } + + oldSlope = K_TumbleSlope(player->mo, oldPitch, oldRoll); + + oldSteepness = oldSlope; + if (oldSteepness > ANGLE_180) + { + oldSteepness = InvAngle(oldSteepness); + } + + if (oldSteepness <= STEEP_VAL) + { + // Transferring from flat ground to a steep slope + // is a free action. (The other way around isn't, though.) + return; + } + + newSlope = K_TumbleSlope(player->mo, player->mo->pitch, player->mo->roll); + slopeDelta = AngleDelta(oldSlope, newSlope); + + if (slopeDelta <= STEEP_VAL) + { + // Needs to be VERY steep before we'll punish this. + return; + } + + // Oh jeez, you landed on your side. + // You get to tumble. + +#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; +} + static boolean K_LastTumbleBounceCondition(player_t *player) { return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 60); diff --git a/src/k_kart.h b/src/k_kart.h index 91024488f..605e0f410 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -70,6 +70,7 @@ void K_DoInstashield(player_t *player); void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved); 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_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll); 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); diff --git a/src/p_local.h b/src/p_local.h index 4940daf81..1bcc2f6d8 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -169,7 +169,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 6954d6e11..996d1c2db 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2667,12 +2667,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->momz == 0 && thing->player) { - P_PlayerHitFloor(thing->player, true); + P_PlayerHitFloor(thing->player, !startingonground, oldPitch, oldRoll); } } } @@ -2687,12 +2690,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->momz == 0 && thing->player) { - P_PlayerHitFloor(thing->player, true); + P_PlayerHitFloor(thing->player, !startingonground, oldPitch, oldRoll); } } } @@ -2983,7 +2989,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 3a4cd1751..953d641c0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2685,6 +2685,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)); @@ -2692,6 +2693,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); @@ -2768,7 +2772,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) diff --git a/src/p_user.c b/src/p_user.c index 8cc74c837..af0aff8b1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1316,7 +1316,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; @@ -1329,6 +1329,11 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir) K_SpawnSplashForMobj(player->mo, abs(player->mo->momz)); } + if (player->mo->health) + { + K_CheckSlopeTumble(player, oldPitch, oldRoll); + } + return clipmomz; } @@ -1639,7 +1644,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 { @@ -1651,7 +1656,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;