From 27ea5021b469324130c534c80580d8c222ee2c89 Mon Sep 17 00:00:00 2001 From: Anonimus Date: Sat, 31 May 2025 05:10:46 -0400 Subject: [PATCH] Add Flipover damage, change Invincibility interactions --- src/d_player.h | 6 ++++ src/deh_tables.c | 1 + src/info/sounds.h | 3 ++ src/k_collide.c | 4 +-- src/k_kart.c | 90 +++++++++++++++++++++++++++++++++++++++++++---- src/k_kart.h | 27 ++++++++++++++ src/k_stats.c | 4 ++- src/p_enemy.c | 6 ++-- src/p_inter.c | 12 +++++-- src/p_local.h | 13 +++---- src/p_map.c | 10 +++++- src/p_mobj.c | 2 +- src/p_saveg.c | 4 +++ src/p_user.c | 14 +++++--- 14 files changed, 167 insertions(+), 29 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index df70e2dd1..548138cc1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -110,6 +110,8 @@ typedef enum PF_SHRINKME = 1<<25, // "Shrink me" cheat preference PF_SHRINKACTIVE = 1<<26, // "Shrink me" cheat is in effect. (Can't be disabled mid-race) + PF_JUSTFLIPPED = 1<<27, // Just got flipped over, handle the bump interaction. + // up to 1<<29 is free PF_ATTACKDOWN = 1<<30, // For lua compat, don't use! PF_SLIDING = 1<<31, // For lua compat, don't use! @@ -619,6 +621,10 @@ struct player_t UINT16 flashing; UINT16 spinouttimer; // Spin-out from a banana peel or oil slick (was "pw_bananacam") UINT8 spinouttype; // Determines the mode of spinout/wipeout, see kartspinoutflags_t + + UINT16 flipovertimer; // Flipped over by a player using Invincibility. + angle_t flipoverangle; // Movement angle for a flipped-over player. + UINT8 instashield; // Instashield no-damage animation timer UINT8 wipeoutslow; // Timer before you slowdown when getting wiped out UINT8 justbumped; // Prevent players from endlessly bumping into each other diff --git a/src/deh_tables.c b/src/deh_tables.c index d7f3deeee..1d94c60e0 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1039,6 +1039,7 @@ struct int_const_s const INT_CONST[] = { {"DMG_SQUISH",DMG_SQUISH}, {"DMG_VOLTAGE",DMG_VOLTAGE}, {"DMG_KARMA",DMG_KARMA}, + {"DMG_FLIPOVER",DMG_FLIPOVER}, //// Death types {"DMG_INSTAKILL",DMG_INSTAKILL}, {"DMG_DEATHPIT",DMG_DEATHPIT}, diff --git a/src/info/sounds.h b/src/info/sounds.h index 25d8694aa..97f198731 100644 --- a/src/info/sounds.h +++ b/src/info/sounds.h @@ -786,6 +786,9 @@ _(kc6c) _(kc6d) _(kc6e) +// MKDS sounds +_(mdse8) + // SRB2kart _(slip) _(screec) diff --git a/src/k_collide.c b/src/k_collide.c index 0298c0dff..a8552a9f1 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -706,12 +706,12 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) } else if (t1Condition == true && t2Condition == false) { - P_DamageMobj(t2, t1, t1, 1, DMG_WIPEOUT); + P_DamageMobj(t2, t1, t1, 1, DMG_FLIPOVER); return true; } else if (t1Condition == false && t2Condition == true) { - P_DamageMobj(t1, t2, t2, 1, DMG_WIPEOUT); + P_DamageMobj(t1, t2, t2, 1, DMG_FLIPOVER); return true; } diff --git a/src/k_kart.c b/src/k_kart.c index 27dcb174d..0dd245d74 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1896,6 +1896,13 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) return weight; } +// Checks if the bump interaction was a flip-over. +static boolean K_CheckMobjFlippedOver(mobj_t* mobj1, mobj_t* mobj2) +{ + return ((mobj1->player && (mobj1->player->pflags & PF_JUSTFLIPPED)) || + (mobj2->player && (mobj2->player->pflags & PF_JUSTFLIPPED))); +} + boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) { mobj_t *fx; @@ -1954,6 +1961,19 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol return false; } + // Don't bump if you're flipping over + if (mobj1->player && mobj1->player->flipovertimer && (!(mobj1->player->pflags & PF_JUSTFLIPPED))) + { + mobj1->player->justbumped = bumptime; + return false; + } + + if (mobj2->player && mobj2->player->flipovertimer && (!(mobj2->player->pflags & PF_JUSTFLIPPED))) + { + mobj2->player->justbumped = bumptime; + return false; + } + mass1 = K_GetMobjWeight(mobj1, mobj2); if (solid == true && mass1 > 0) @@ -2040,7 +2060,7 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol // Do the bump fx when we've CONFIRMED we can bump. if ((mobj1->player && mobj1->player->itemtype == KITEM_BUBBLESHIELD) || (mobj2->player && mobj2->player->itemtype == KITEM_BUBBLESHIELD)) S_StartSound(mobj1, sfx_s3k44); - else + else if (!K_CheckMobjFlippedOver(mobj1, mobj2)) S_StartSound(mobj1, sfx_s3k49); fx = P_SpawnMobj(mobj1->x/2 + mobj2->x/2, mobj1->y/2 + mobj2->y/2, mobj1->z/2 + mobj2->z/2, MT_BUMP); @@ -2065,6 +2085,15 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol P_PlayerRingBurst(mobj1->player, 1); } + if (mobj1->player->pflags & PF_JUSTFLIPPED) + { + S_StartSound(mobj2, sfx_mdse8); + mobj1->player->flipoverangle = R_PointToAngle2(0,0,mobj1->player->rmomx,mobj1->player->rmomy); + P_InstaThrust(mobj1, mobj1->player->flipoverangle, FixedMul(FLIPOVERSPEED, mobj1->scale)); + mobj1->momz = FixedMul(FlipOverZMomentum(gravity), mobj1->scale); + mobj1->player->pflags &= ~PF_JUSTFLIPPED; + } + if (mobj1->player->spinouttimer) { mobj1->player->wipeoutslow = wipeoutslowtime+1; @@ -2091,6 +2120,15 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol mobj2->player->spinouttimer = max(wipeoutslowtime+1, mobj2->player->spinouttimer); //mobj2->player->spinouttype = KSPIN_WIPEOUT; // Enforce type } + + if (mobj2->player->pflags & PF_JUSTFLIPPED) + { + S_StartSound(mobj1, sfx_mdse8); + mobj2->player->flipoverangle = R_PointToAngle2(0,0,mobj2->player->rmomx,mobj2->player->rmomy); + P_InstaThrust(mobj2, mobj2->player->flipoverangle, FixedMul(FLIPOVERSPEED, mobj2->scale)); + mobj2->momz = FixedMul(FlipOverZMomentum(gravity), mobj2->scale); + mobj2->player->pflags &= ~PF_JUSTFLIPPED; + } } return true; @@ -3878,7 +3916,10 @@ SINT8 K_GetForwardMove(player_t *player) } } - if ((player->exiting || mapreset) || player->pflags & PF_STASIS || player->spinouttimer) // pw_introcam? + if ((player->exiting || mapreset) || + player->pflags & PF_STASIS || + player->spinouttimer || + player->flipovertimer) // pw_introcam? { forwardmove = 0; if (player->sneakertimer) @@ -4088,6 +4129,19 @@ void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 typ P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); } +void K_FlipPlayer(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + (void)inflictor; + (void)source; + + K_DirectorFollowAttack(player, inflictor, source); + + K_StatPlayerHit(player, source ? source->player : NULL); + player->flipovertimer = 1; + player->pflags |= PF_JUSTFLIPPED; + P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); +} + static void K_RemoveGrowShrink(player_t *player) { if (player->mo && !P_MobjWasRemoved(player->mo)) @@ -4194,6 +4248,11 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A return ringburst; } +boolean K_IsPlayerDamaged(player_t *player) +{ + return ((player->spinouttimer > 0) || (player->flipovertimer > 0)); +} + void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers) { if (!(gametyperules & GTR_BUMPERS)) @@ -7398,7 +7457,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_UpdateEngineSounds(player); // Thanks, VAda! // update boost angle if not spun out - if (!player->spinouttimer && !player->wipeoutslow) + if (!K_IsPlayerDamaged(player) && !player->wipeoutslow) player->boostangle = player->mo->angle; K_GetKartBoostPower(player); @@ -7473,7 +7532,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) // Make ABSOLUTELY SURE that your flashing tics don't get set WHILE you're still in hit animations. if (player->spinouttimer != 0 || player->wipeoutslow != 0 - || player->squishedtimer != 0) + || player->squishedtimer != 0 + || player->flipovertimer != 0) { player->flashing = K_GetKartFlashing(player); } @@ -7482,6 +7542,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->flashing--; } + if (player->flipovertimer) + { + player->flipovertimer++; + + // Kill off any extra damage values. + player->spinouttimer = 0; + player->wipeoutslow = 0; + + if (P_IsObjectOnGround(player->mo) && + ((INT32)(player->flipovertimer - 1) > 2)) + { + player->flipovertimer = 0; + player->mo->rollangle = 0; + } + } + if (player->spinouttimer) { if ((P_IsObjectOnGround(player->mo) @@ -10009,12 +10085,12 @@ static void K_AdjustPlayerFriction(player_t *player) player->mo->movefactor = 32; } - // Wipeout slowdown - if (player->speed > 0 && player->spinouttimer && player->wipeoutslow) + // Wipeout slowdown, or getting flipped over + if ((player->speed > 0 && player->spinouttimer && player->wipeoutslow) || (player->flipovertimer)) { if (player->offroad) player->mo->friction -= 4912; - if (player->wipeoutslow == 1) + if ((player->wipeoutslow == 1) || (player->flipovertimer)) player->mo->friction -= 9824; } } diff --git a/src/k_kart.h b/src/k_kart.h index f3d42d726..095cbd7d7 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -37,6 +37,31 @@ Make sure this matches the actual number of states #define FLAMESTOREMAX TICRATE*2 +// Fixed distance of a flipover. +#define FLIPOVERDIST (112<>1) + +#define FLIPOVER_90DEGTIME ((FLIPOVERTICS>>2)+1) // 0.1666 * FRACUNIT + +// Angle movement for a flipover +// ANGLE_90 / FLIPOVER_90DEGTIME +// Precalculating it here for some slight optimization. +#define FLIPOVERANG 0x0CCCCCCC + +#define FLIPOVERSPEED (FLIPOVERDIST / FLIPOVERTICS) + +#define FLIPOVERHEIGHT (32 << FRACBITS) + +// By the middle of a jump arc, you'll reach the apex. +#define FlipOverZMomentum(grav) \ + ((FLIPOVERHEIGHT + \ + ((grav >> 1) * (FLIPOVERHALFTICS * FLIPOVERHALFTICS))) / \ + FLIPOVERHALFTICS) + // Precalculated constants for stacked boost diminishing // *Somewhat* matches old calc but doesn't use arrays, which makes it faster and more memory efficent #define DIMINISHPARAM K_RAGuard(cv_kartstacking_diminishparam) @@ -153,7 +178,9 @@ void K_AwardPlayerRings(player_t *player, UINT16 rings, boolean overload); 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_FlipPlayer(player_t *player, mobj_t *inflictor, mobj_t *source); INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); +boolean K_IsPlayerDamaged(player_t *player); void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers); void K_DestroyBumpers(player_t *player, UINT8 amount); void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount); diff --git a/src/k_stats.c b/src/k_stats.c index 8ddcffa6a..bfa177167 100644 --- a/src/k_stats.c +++ b/src/k_stats.c @@ -31,7 +31,9 @@ void K_StatTicker(void) if (p->position == spbplace) kartstats.spbtargettime++; - if (max(p->spinouttimer, p->wipeoutslow) > 0) + if (p->flipovertimer > 0) + kartstats.spinouttime++; + else if (max(p->spinouttimer, p->wipeoutslow) > 0) kartstats.spinouttime++; } } diff --git a/src/p_enemy.c b/src/p_enemy.c index 9f4fa86c6..532eba9c1 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -11324,7 +11324,7 @@ void A_RandomShadowFrame(mobj_t *actor) if (actor->target && !actor->target->player->flashing && !actor->target->player->invincibilitytimer && !actor->target->player->growshrinktimer - && !actor->target->player->spinouttimer + && !K_IsPlayerDamaged(actor->target->player) && P_IsObjectOnGround(actor->target) && actor->z == actor->target->z) { @@ -11369,7 +11369,7 @@ void A_RoamingShadowThinker(mobj_t *actor) if (actor->target && !actor->target->player->flashing && !actor->target->player->invincibilitytimer && !actor->target->player->growshrinktimer - && !actor->target->player->spinouttimer) + && !K_IsPlayerDamaged(actor->target->player)) { // send them flying and spawn the WIND! P_InstaThrust(actor->target, 0, 0); @@ -11611,7 +11611,7 @@ void A_ReaperThinker(mobj_t *actor) if (!(actor->target == targetplayermo && actor->target && !actor->target->player->flashing && !actor->target->player->invincibilitytimer && !actor->target->player->growshrinktimer - && !actor->target->player->spinouttimer)) + && !K_IsPlayerDamaged(actor->target->player))) P_SetTarget(&actor->target, actor->hnext); // if the above isn't correct, then we should go back to targetting waypoints or something. } diff --git a/src/p_inter.c b/src/p_inter.c index 4e2af4a9c..347b54887 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -127,7 +127,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) { // Invulnerable if (player->flashing > 0 - || player->spinouttimer > 0 + || K_IsPlayerDamaged(player) || player->squishedtimer > 0 || player->invincibilitytimer > 0 || player->growshrinktimer > 0 @@ -2055,7 +2055,7 @@ static UINT8 P_ShouldHookDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sourc status = shouldDamage; - if (shouldSpin > 0 && ((type == DMG_NORMAL) || (type == DMG_WIPEOUT))) + if (shouldSpin > 0 && ((type == DMG_NORMAL) || (type == DMG_WIPEOUT) || (type == DMG_FLIPOVER))) status = shouldSpin; else if (shouldExplode > 0 && ((type == DMG_EXPLODE) || (type == DMG_KARMA))) status = shouldExplode; @@ -2266,7 +2266,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da K_DestroyBumpers(player, 1); } - if (!(type == DMG_NORMAL || type == DMG_WIPEOUT || type == DMG_VOLTAGE)) + if (!(type == DMG_NORMAL || type == DMG_WIPEOUT || type == DMG_VOLTAGE || type == DMG_FLIPOVER)) { player->sneakertimer = 0; player->mo->flags2 &= ~MF2_WATERRUN; @@ -2345,6 +2345,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da K_SquishPlayer(player, inflictor, source); LUA_HookPlayerSquish(target, inflictor, source, damage, damagetype); break; + case DMG_FLIPOVER: + if (P_IsDisplayPlayer(player)) + P_StartQuake(32<flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) return BMIT_CONTINUE; + // Get rid of the "just flipped" flag. + // We only use that to confirm flipover hits. + if (thing->player) + thing->player->pflags &= ~PF_JUSTFLIPPED; + + if (g_tm.thing->player) + g_tm.thing->player->pflags &= ~PF_JUSTFLIPPED; + blockdist = thing->radius + g_tm.thing->radius; if (abs(thing->x - g_tm.x) >= blockdist || abs(thing->y - g_tm.y) >= blockdist) @@ -1267,7 +1275,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } // no interaction - if (g_tm.thing->player->flashing > 0 || g_tm.thing->player->hyudorotimer > 0 || g_tm.thing->player->spinouttimer > 0) + if (g_tm.thing->player->flashing > 0 || g_tm.thing->player->hyudorotimer > 0 || K_IsPlayerDamaged(g_tm.thing->player)) return BMIT_CONTINUE; // collide diff --git a/src/p_mobj.c b/src/p_mobj.c index e5053ac82..35f31fe0c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2765,7 +2765,7 @@ void P_PlayerZMovement(mobj_t *mo) K_UpdateMobjTerrain(mo, (mo->eflags & MFE_VERTICALFLIP ? g_tm.ceilingpic : g_tm.floorpic)); // Get up if you fell. - if (mo->player->panim == PA_HURT && mo->player->spinouttimer == 0 && mo->player->squishedtimer == 0) + if (mo->player->panim == PA_HURT && !K_IsPlayerDamaged(mo->player) && mo->player->squishedtimer == 0) { P_SetPlayerMobjState(mo, S_KART_STILL); } diff --git a/src/p_saveg.c b/src/p_saveg.c index 3db594de2..e9758af49 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -256,6 +256,8 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT16(save->p, players[i].flashing); WRITEUINT16(save->p, players[i].spinouttimer); WRITEUINT8(save->p, players[i].spinouttype); + WRITEUINT16(save->p, players[i].flipovertimer); + WRITEANGLE(save->p, players[i].flipoverangle); WRITEINT16(save->p, players[i].squishedtimer); WRITEUINT8(save->p, players[i].instashield); WRITEUINT8(save->p, players[i].wipeoutslow); @@ -595,6 +597,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].flashing = READUINT16(save->p); players[i].spinouttimer = READUINT16(save->p); players[i].spinouttype = READUINT8(save->p); + players[i].flipoverangle = READUINT16(save->p); + players[i].flipovertimer = READANGLE(save->p); players[i].squishedtimer = READINT16(save->p); players[i].instashield = READUINT8(save->p); players[i].wipeoutslow = READUINT8(save->p); diff --git a/src/p_user.c b/src/p_user.c index dc9b55e50..eb9d5207f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -464,7 +464,7 @@ UINT8 P_FindHighestLap(void) // boolean P_PlayerInPain(player_t *player) { - if (player->spinouttimer || player->squishedtimer) + if (K_IsPlayerDamaged(player) || player->squishedtimer) return true; return false; @@ -1374,7 +1374,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir) // Cut momentum in half when you hit the ground and // aren't pressing any controls. if (!(player->cmd.forwardmove || player->cmd.sidemove) && !player->cmomx && !player->cmomy - && !(player->spinouttimer)) + && !K_IsPlayerDamaged(player)) { player->mo->momx = player->mo->momx/2; player->mo->momy = player->mo->momy/2; @@ -1806,7 +1806,7 @@ static void P_3dMovement(player_t *player) { movepushangle = player->mo->angle - (ANGLE_45/5) * player->drift; } - else if (player->spinouttimer || player->wipeoutslow) // if spun out, use the boost angle + else if (K_IsPlayerDamaged(player) || player->wipeoutslow) // if spun out, use the boost angle { movepushangle = (angle_t)player->boostangle; } @@ -1896,13 +1896,13 @@ static void P_3dMovement(player_t *player) totalthrust.x += P_ReturnThrustX(player->mo, movepushangle, movepushforward); totalthrust.y += P_ReturnThrustY(player->mo, movepushangle, movepushforward); } - else if (!(player->spinouttimer)) + else if (!K_IsPlayerDamaged(player)) { K_MomentumToFacing(player); } // Sideways movement - if (cmd->sidemove != 0 && !((player->exiting || mapreset) || player->spinouttimer)) + if (cmd->sidemove != 0 && !((player->exiting || mapreset) || K_IsPlayerDamaged(player))) { if (cmd->sidemove > 0) movepushside = (cmd->sidemove * FRACUNIT/128) + FixedDiv(player->speed, K_GetKartSpeed(player, true, true)); @@ -2169,6 +2169,10 @@ void P_MovePlayer(player_t *player) player->glanceDir = 0; player->pflags &= ~PF_GAINAX; } + else if (player->flipovertimer > 0) + { + player->mo->rollangle = (angle_t)(player->flipovertimer - 1) * FLIPOVERANG; + } else if ((player->spinouttimer > 0)) { UINT16 speed = player->spinouttimer/8;