From f3bb8833a1fb64698d6069d632047b39d8400106 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 28 Mar 2022 17:10:27 -0400 Subject: [PATCH 01/49] Tumble when not landing upright on slopes --- src/k_kart.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/k_kart.h | 1 + src/p_local.h | 2 +- src/p_map.c | 16 ++++++---- src/p_mobj.c | 6 +++- src/p_user.c | 11 +++++-- 6 files changed, 109 insertions(+), 10 deletions(-) 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; From c207de5d5d7783c452b0db43728f64fbb17c02a2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 28 Mar 2022 19:04:18 -0400 Subject: [PATCH 02/49] Tilt towards even while falling, make more strict as a result --- src/k_kart.c | 2 +- src/p_mobj.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 7bd45c029..082f4bf90 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3415,7 +3415,7 @@ static angle_t K_TumbleSlope(mobj_t *mobj, angle_t pitch, angle_t roll) return FixedMul(pitch, pitchMul) + FixedMul(roll, rollMul); } -#define STEEP_VAL (ANG60) +#define STEEP_VAL (ANGLE_45 - ANGLE_11hh) // (ANG60) void K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll) { diff --git a/src/p_mobj.c b/src/p_mobj.c index 953d641c0..e92a98639 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2808,6 +2808,47 @@ void P_PlayerZMovement(mobj_t *mo) mo->eflags &= ~MFE_JUSTHITFLOOR; P_CheckGravity(mo, true); } + + // Even out pitch & roll slowly over time when falling. + // Helps give OpenGL models a bit of the tumble tell. + if (P_MobjFlip(mo) * mo->momz < 0) + { + const angle_t evenSpeed = (ANG1 << 1) / 3; // 0.66 degrees + INT32 pitchDelta = AngleDeltaSigned(mo->pitch, 0); + INT32 rollDelta = AngleDeltaSigned(mo->roll, 0); + + if (abs(pitchDelta) <= evenSpeed) + { + mo->pitch = 0; + } + else + { + if (pitchDelta > 0) + { + mo->pitch -= evenSpeed; + } + else + { + mo->pitch += evenSpeed; + } + } + + if (abs(rollDelta) <= evenSpeed) + { + mo->roll = 0; + } + else + { + if (rollDelta > 0) + { + mo->roll -= evenSpeed; + } + else + { + mo->roll += evenSpeed; + } + } + } } if (((mo->eflags & MFE_VERTICALFLIP && mo->z < mo->floorz) || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z + mo->height > mo->ceilingz)) From 421d850a5b69054705934e3a3dc623667d986a51 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 28 Mar 2022 19:06:09 -0400 Subject: [PATCH 03/49] Use <= 0 so it happens while respawning. --- src/p_mobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index e92a98639..d8f8f025b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2811,7 +2811,7 @@ void P_PlayerZMovement(mobj_t *mo) // Even out pitch & roll slowly over time when falling. // Helps give OpenGL models a bit of the tumble tell. - if (P_MobjFlip(mo) * mo->momz < 0) + if (P_MobjFlip(mo) * mo->momz <= 0) { const angle_t evenSpeed = (ANG1 << 1) / 3; // 0.66 degrees INT32 pitchDelta = AngleDeltaSigned(mo->pitch, 0); From 60d72b5c202d37fd3e925a9ff380b765cd0042eb Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 28 Mar 2022 22:14:45 -0400 Subject: [PATCH 04/49] Make it flatten out faster & while rising, add a cap to the flattening, flatten out completely while respawning. --- src/k_kart.c | 2 +- src/p_mobj.c | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 082f4bf90..49f199932 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3415,7 +3415,7 @@ static angle_t K_TumbleSlope(mobj_t *mobj, angle_t pitch, angle_t roll) return FixedMul(pitch, pitchMul) + FixedMul(roll, rollMul); } -#define STEEP_VAL (ANGLE_45 - ANGLE_11hh) // (ANG60) +#define STEEP_VAL (ANGLE_45) void K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll) { diff --git a/src/p_mobj.c b/src/p_mobj.c index d8f8f025b..ad79f6353 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2811,41 +2811,46 @@ void P_PlayerZMovement(mobj_t *mo) // Even out pitch & roll slowly over time when falling. // Helps give OpenGL models a bit of the tumble tell. - if (P_MobjFlip(mo) * mo->momz <= 0) { - const angle_t evenSpeed = (ANG1 << 1) / 3; // 0.66 degrees + const angle_t speed = ANG1; + angle_t dest = ANGLE_45 + (ANG10 >> 1); INT32 pitchDelta = AngleDeltaSigned(mo->pitch, 0); INT32 rollDelta = AngleDeltaSigned(mo->roll, 0); - if (abs(pitchDelta) <= evenSpeed) + if (mo->player->respawn.state != RESPAWNST_NONE) + { + dest = 0; + } + + if (abs(pitchDelta) <= speed && dest == 0) { mo->pitch = 0; } - else + else if (abs(pitchDelta) > dest) { if (pitchDelta > 0) { - mo->pitch -= evenSpeed; + mo->pitch -= speed; } else { - mo->pitch += evenSpeed; + mo->pitch += speed; } } - if (abs(rollDelta) <= evenSpeed) + if (abs(rollDelta) <= speed && dest == 0) { mo->roll = 0; } - else + else if (abs(rollDelta) > dest) { if (rollDelta > 0) { - mo->roll -= evenSpeed; + mo->roll -= speed; } else { - mo->roll += evenSpeed; + mo->roll += speed; } } } From f06be5ce1d0a62be6c8c1ac6f35fb1b9c282f313 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 28 Mar 2022 22:37:43 -0400 Subject: [PATCH 05/49] Make it the tiniest bit more aggressive again - Do it while falling agaaainnn - Double even-out speed - Fix Mario Kart 64 --- src/k_kart.c | 20 ++++++++++---------- src/p_mobj.c | 5 +++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 49f199932..f019eef50 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3412,17 +3412,23 @@ static angle_t K_TumbleSlope(mobj_t *mobj, angle_t pitch, angle_t roll) fixed_t pitchMul = -FINESINE(mobj->angle >> ANGLETOFINESHIFT); fixed_t rollMul = FINECOSINE(mobj->angle >> ANGLETOFINESHIFT); - return FixedMul(pitch, pitchMul) + FixedMul(roll, rollMul); + angle_t slope = FixedMul(pitch, pitchMul) + FixedMul(roll, rollMul); + + if (slope > ANGLE_180) + { + slope = InvAngle(slope); + } + + return slope; } -#define STEEP_VAL (ANGLE_45) +#define STEEP_VAL (FixedAngle(40*FRACUNIT)) 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 @@ -3435,13 +3441,7 @@ void K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll) oldSlope = K_TumbleSlope(player->mo, oldPitch, oldRoll); - oldSteepness = oldSlope; - if (oldSteepness > ANGLE_180) - { - oldSteepness = InvAngle(oldSteepness); - } - - if (oldSteepness <= STEEP_VAL) + if (oldSlope <= STEEP_VAL) { // Transferring from flat ground to a steep slope // is a free action. (The other way around isn't, though.) diff --git a/src/p_mobj.c b/src/p_mobj.c index ad79f6353..428880478 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2811,9 +2811,10 @@ void P_PlayerZMovement(mobj_t *mo) // Even out pitch & roll slowly over time when falling. // Helps give OpenGL models a bit of the tumble tell. + if (P_MobjFlip(mo) * mo->momz <= 0) { - const angle_t speed = ANG1; - angle_t dest = ANGLE_45 + (ANG10 >> 1); + const angle_t speed = ANG2; + angle_t dest = FixedAngle(50*FRACUNIT); INT32 pitchDelta = AngleDeltaSigned(mo->pitch, 0); INT32 rollDelta = AngleDeltaSigned(mo->roll, 0); From 794090d026c8167dbf405aca17856f6d0b994ec9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 2 Apr 2022 01:20:23 -0400 Subject: [PATCH 06/49] Make more lenient on the ground --- src/k_kart.c | 35 ++++++++++++++++++++++++++++------- src/k_kart.h | 2 +- src/p_map.c | 6 +++--- src/p_mobj.c | 38 ++++++++++++++++++++++++++++---------- src/p_user.c | 21 +++++++++++++++------ 5 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index f019eef50..26c7c4811 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3422,10 +3422,13 @@ static angle_t K_TumbleSlope(mobj_t *mobj, angle_t pitch, angle_t roll) return slope; } -#define STEEP_VAL (FixedAngle(40*FRACUNIT)) -void K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll) +#define STEEP_VAL ANG60 +#define STEEP_VAL_AIR ANG30 + ANG10 + +boolean K_CheckSlopeTumble(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; @@ -3436,25 +3439,41 @@ void K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll) if (player->tumbleBounces) { // Already tumbling. - return; + return false; + } + + if ((player->mo->pitch == oldPitch) + && (player->mo->roll == oldRoll)) + { + // No change. + return false; + } + + if (fromAir == true) + { + steepVal = STEEP_VAL_AIR; + } + else + { + steepVal = STEEP_VAL; } oldSlope = K_TumbleSlope(player->mo, oldPitch, oldRoll); - if (oldSlope <= STEEP_VAL) + if (oldSlope <= steepVal) { // Transferring from flat ground to a steep slope // is a free action. (The other way around isn't, though.) - return; + return false; } newSlope = K_TumbleSlope(player->mo, player->mo->pitch, player->mo->roll); slopeDelta = AngleDelta(oldSlope, newSlope); - if (slopeDelta <= STEEP_VAL) + if (slopeDelta <= steepVal) { // Needs to be VERY steep before we'll punish this. - return; + return false; } // Oh jeez, you landed on your side. @@ -3488,6 +3507,7 @@ void K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll) // Reset slope. player->mo->pitch = player->mo->roll = 0; + return true; } static boolean K_LastTumbleBounceCondition(player_t *player) @@ -3525,6 +3545,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 } } diff --git a/src/k_kart.h b/src/k_kart.h index 605e0f410..8881729ad 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -70,7 +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); +boolean K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir); 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_map.c b/src/p_map.c index 996d1c2db..67f15102e 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2480,7 +2480,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) fixed_t oldy = tryy; fixed_t radius = thing->radius; fixed_t thingtop; - fixed_t startingonground = P_IsObjectOnGround(thing); + boolean startingonground = P_IsObjectOnGround(thing); fixed_t stairjank = 0; pslope_t *oldslope = thing->standingslope; floatok = false; @@ -2673,7 +2673,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->standingslope = tmfloorslope; P_SetPitchRollFromSlope(thing, thing->standingslope); - if (thing->momz == 0 && thing->player) + if (thing->player) { P_PlayerHitFloor(thing->player, !startingonground, oldPitch, oldRoll); } @@ -2696,7 +2696,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->standingslope = tmceilingslope; P_SetPitchRollFromSlope(thing, thing->standingslope); - if (thing->momz == 0 && thing->player) + if (thing->player) { P_PlayerHitFloor(thing->player, !startingonground, oldPitch, oldRoll); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 428880478..42652afdc 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1514,12 +1514,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; @@ -1748,9 +1754,13 @@ 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) { // First, compare different slopes + if (oldslope != mo->standingslope) + { + // First, compare different slopes angle_t oldangle, newangle; angle_t moveangle = K_MomentumAngle(mo); @@ -1762,7 +1772,9 @@ void P_XYMovement(mobj_t *mo) newangle = 0; // Now compare the Zs of the different quantizations - if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later + if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) + { + // Allow for a bit of sticking - this value can be adjusted later mo->standingslope = oldslope; P_SetPitchRollFromSlope(mo, mo->standingslope); P_SlopeLaunch(mo); @@ -1776,12 +1788,17 @@ void P_XYMovement(mobj_t *mo) FIXED_TO_FLOAT(AngleFixed(oldangle-newangle)) );*/ // Sryder 2018-11-26: Don't launch here if it's a slope without physics, we stick to those like glue anyway - } else if (predictedz-mo->z > abs(slopemom.z/2) - && !(mo->standingslope->flags & SL_NOPHYSICS)) { // Now check if we were supposed to stick to this slope + } + else if (predictedz-mo->z > abs(slopemom.z/2) + && !(mo->standingslope->flags & SL_NOPHYSICS)) + { + // Now check if we were supposed to stick to this slope //CONS_Printf("%d-%d > %d\n", (predictedz), (mo->z), (slopemom.z/2)); P_SlopeLaunch(mo); } - } else if (moved && mo->standingslope && predictedz) { + } + else if (moved && mo->standingslope && predictedz) + { angle_t moveangle = K_MomentumAngle(mo); angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT)); @@ -1789,7 +1806,8 @@ void P_XYMovement(mobj_t *mo) FIXED_TO_FLOAT(AngleFixed(ANGLE_MAX-newangle)), FIXED_TO_FLOAT(predictedz) );*/ - if (ANGLE_MAX-newangle > ANG30 && newangle > ANGLE_180) { + if (ANGLE_MAX-newangle > ANG30 && newangle > ANGLE_180) + { mo->momz = P_MobjFlip(mo)*FRACUNIT/2; mo->z = predictedz + P_MobjFlip(mo); mo->standingslope = NULL; diff --git a/src/p_user.c b/src/p_user.c index af0aff8b1..9eba0531e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1324,14 +1324,23 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, an 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) - { - K_CheckSlopeTumble(player, oldPitch, oldRoll); + if (player->mo->health) + { + boolean air = fromAir; + + if (P_IsObjectOnGround(player->mo) && (player->mo->eflags & MFE_JUSTHITFLOOR)) + air = true; + + if (K_CheckSlopeTumble(player, oldPitch, oldRoll, air)) + return false; + } } return clipmomz; From d6efbc143b8b429552a96b2e35045d6fc1073650 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 2 Apr 2022 01:40:40 -0400 Subject: [PATCH 07/49] Some code I didn't end up using but want here anyway --- src/p_mobj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 42652afdc..6820d7948 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2831,8 +2831,8 @@ void P_PlayerZMovement(mobj_t *mo) // Helps give OpenGL models a bit of the tumble tell. if (P_MobjFlip(mo) * mo->momz <= 0) { - const angle_t speed = ANG2; - angle_t dest = FixedAngle(50*FRACUNIT); + const angle_t speed = ANG2; //FixedMul(ANG2, abs(mo->momz) / 8); + angle_t dest = ANG60 - ANG10; INT32 pitchDelta = AngleDeltaSigned(mo->pitch, 0); INT32 rollDelta = AngleDeltaSigned(mo->roll, 0); From bb510a6a6708399c6ff7de7817399677dab07f4d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 2 Apr 2022 02:01:39 -0400 Subject: [PATCH 08/49] Rename to "stumble" :D --- src/k_kart.c | 16 ++++++---------- src/k_kart.h | 6 +++++- src/p_user.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 26c7c4811..d4d9ebcd7 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3407,7 +3407,7 @@ void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) P_StartQuake(64<angle >> ANGLETOFINESHIFT); fixed_t rollMul = FINECOSINE(mobj->angle >> ANGLETOFINESHIFT); @@ -3422,11 +3422,7 @@ static angle_t K_TumbleSlope(mobj_t *mobj, angle_t pitch, angle_t roll) return slope; } - -#define STEEP_VAL ANG60 -#define STEEP_VAL_AIR ANG30 + ANG10 - -boolean K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir) +boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir) { angle_t steepVal = ANGLE_MAX; fixed_t gravityadjust; @@ -3451,14 +3447,14 @@ boolean K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll, if (fromAir == true) { - steepVal = STEEP_VAL_AIR; + steepVal = STUMBLE_STEEP_VAL_AIR; } else { - steepVal = STEEP_VAL; + steepVal = STUMBLE_STEEP_VAL; } - oldSlope = K_TumbleSlope(player->mo, oldPitch, oldRoll); + oldSlope = K_StumbleSlope(player->mo, oldPitch, oldRoll); if (oldSlope <= steepVal) { @@ -3467,7 +3463,7 @@ boolean K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll, return false; } - newSlope = K_TumbleSlope(player->mo, player->mo->pitch, player->mo->roll); + newSlope = K_StumbleSlope(player->mo, player->mo->pitch, player->mo->roll); slopeDelta = AngleDelta(oldSlope, newSlope); if (slopeDelta <= steepVal) diff --git a/src/k_kart.h b/src/k_kart.h index 8881729ad..796392d85 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); @@ -70,7 +73,8 @@ 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); -boolean K_CheckSlopeTumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir); +angle_t K_StumbleSlope(mobj_t *mobj, angle_t pitch, angle_t roll); +boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir); 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_user.c b/src/p_user.c index 9eba0531e..7e6e1b1f9 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1338,7 +1338,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, an if (P_IsObjectOnGround(player->mo) && (player->mo->eflags & MFE_JUSTHITFLOOR)) air = true; - if (K_CheckSlopeTumble(player, oldPitch, oldRoll, air)) + if (K_CheckStumble(player, oldPitch, oldRoll, air)) return false; } } From 5ece4825c0949ce6c12373ffec01f17a3951cfb4 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 2 Apr 2022 02:25:25 -0400 Subject: [PATCH 09/49] Smooth landing support for bots --- src/k_bot.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/k_bot.c b/src/k_bot.c index b3f73b8ac..5d512f54c 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -1062,6 +1062,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) @@ -1085,6 +1134,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; angle = (moveangle - destangle); @@ -1227,6 +1278,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); From cf15c485c8e47b1990b3f57eb4a1d1b36bca781c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 2 Apr 2022 14:43:38 -0400 Subject: [PATCH 10/49] review --- src/k_bot.c | 25 +++++++------ src/k_grandprix.c | 94 +++++++++++++++++++++++++++++------------------ src/k_grandprix.h | 14 ++----- src/y_inter.c | 13 ++----- 4 files changed, 78 insertions(+), 68 deletions(-) diff --git a/src/k_bot.c b/src/k_bot.c index 5d512f54c..c8c2a232b 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -487,7 +487,7 @@ static UINT32 K_BotRubberbandDistance(player_t *player) fixed_t K_BotRubberband(player_t *player) { fixed_t rubberband = FRACUNIT; - fixed_t max, min; + fixed_t rubbermax, rubbermin; player_t *firstplace = NULL; line_t *botController = NULL; UINT8 i; @@ -551,21 +551,21 @@ fixed_t K_BotRubberband(player_t *player) // Lv. 5: x1.4 max // Lv. 9: x1.8 max // Lv. MAX: x2.2 max - max = FRACUNIT + ((FRACUNIT * (player->botvars.difficulty - 1)) / 10); + rubbermax = FRACUNIT + ((FRACUNIT * (player->botvars.difficulty - 1)) / 10); // Lv. 1: x0.75 min // Lv. 5: x0.875 min // Lv. 9: x1.0 min // Lv. MAX: x1.0 min - min = FRACUNIT - (((FRACUNIT/4) * (DIFFICULTBOT - min(DIFFICULTBOT, player->botvars.difficulty))) / (DIFFICULTBOT - 1)); + rubbermin = FRACUNIT - (((FRACUNIT/4) * (DIFFICULTBOT - min(DIFFICULTBOT, player->botvars.difficulty))) / (DIFFICULTBOT - 1)); - if (rubberband > max) + if (rubberband > rubbermax) { - rubberband = max; + rubberband = rubbermax; } - else if (rubberband < min) + else if (rubberband < rubbermin) { - rubberband = min; + rubberband = rubbermin; } return rubberband; @@ -1170,6 +1170,11 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * predict->x, predict->y ); + if (realrad < player->mo->radius) + { + realrad = player->mo->radius; + } + if (anglediff > 0) { // Become more precise based on how hard you need to turn @@ -1500,11 +1505,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) turnamt = bullyTurn; // If already spindashing, wait until we get a relatively OK charge first. - if (player->spindash > 0 && player->spindash <= TICRATE) - { - trySpindash = true; - } - else + if (player->spindash == 0 || player->spindash > TICRATE) { trySpindash = false; cmd->buttons |= BT_ACCELERATE; diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 332224479..bb14edac6 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -513,18 +513,16 @@ void K_IncreaseBotDifficulty(player_t *bot) } /*-------------------------------------------------- - void K_ReplaceBot(player_t *bot) + void K_RetireBots(void) See header file for description. --------------------------------------------------*/ -void K_ReplaceBot(player_t *bot) +void K_RetireBots(void) { const SINT8 defaultbotskin = K_BotDefaultSkin(); SINT8 newDifficulty; boolean skinusable[MAXSKINS]; - UINT8 skinnum; - UINT8 loops = 0; UINT8 i; @@ -555,32 +553,6 @@ void K_ReplaceBot(player_t *bot) } } - skinnum = P_RandomKey(numskins); - - while (!skinusable[skinnum]) - { - if (loops >= numskins) - { - // no more skins - break; - } - - skinnum++; - - if (skinnum >= numskins) - { - skinnum = 0; - } - - loops++; - } - - if (loops >= numskins) - { - // Use default skin - skinnum = defaultbotskin; - } - if (!grandprixinfo.gp) // Sure, let's let this happen all the time :) { newDifficulty = cv_kartbot.value; @@ -600,14 +572,64 @@ void K_ReplaceBot(player_t *bot) newDifficulty = 1; } - bot->botvars.difficulty = newDifficulty; - bot->botvars.diffincrease = 0; + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *bot = NULL; - SetPlayerSkinByNum(bot - players, skinnum); - bot->skincolor = skins[skinnum].prefcolor; - sprintf(player_names[bot - players], "%s", skins[skinnum].realname); + if (!playeringame[i] || !players[i].bot) + { + continue; + } - bot->score = 0; + bot = players[i]; + + if (bot->spectator) + { + continue; + } + + if (bot->pflags & PF_NOCONTEST) + { + UINT8 skinnum = P_RandomKey(numskins); + UINT8 loops = 0; + + while (!skinusable[skinnum]) + { + if (loops >= numskins) + { + // no more skins + break; + } + + skinnum++; + + if (skinnum >= numskins) + { + skinnum = 0; + } + + loops++; + } + + if (loops >= numskins) + { + // Use default skin + skinnum = defaultbotskin; + } + + skinusable[skinnum] = false; + + bot->botvars.difficulty = newDifficulty; + bot->botvars.diffincrease = 0; + + SetPlayerSkinByNum(bot - players, skinnum); + bot->skincolor = skins[skinnum].prefcolor; + sprintf(player_names[bot - players], "%s", skins[skinnum].realname); + + bot->score = 0; + bot->pflags &= ~PF_NOCONTEST; + } + } } /*-------------------------------------------------- diff --git a/src/k_grandprix.h b/src/k_grandprix.h index f951860d8..552f75450 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -106,19 +106,13 @@ void K_IncreaseBotDifficulty(player_t *bot); /*-------------------------------------------------- - void K_ReplaceBot(player_t *bot); + void K_RetireBots(player_t *bot); - "Replaces" a bot, by refreshing their difficulty + Replaces PF_NOCONTEST bots, by refreshing their difficulty and changing their skin. - - Input Arguments:- - bot - Player to do this for. - - Return:- - None --------------------------------------------------*/ -void K_ReplaceBot(player_t *bot); +void K_RetireBots(player_t *bot); /*-------------------------------------------------- @@ -162,7 +156,7 @@ void K_PlayerLoseLife(player_t *player); None Return:- - None + true if can change important gameplay rules, otherwise false. --------------------------------------------------*/ boolean K_CanChangeRules(void); diff --git a/src/y_inter.c b/src/y_inter.c index 69cbf2660..7f48f0798 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -584,7 +584,7 @@ void Y_IntermissionDrawer(void) V_DrawScaledPatch(x+16, y-4, 0, W_CachePatchName(va("K_CHILI%d", cursorframe+1), PU_CACHE)); } - if (!data.rankingsmode && (players[data.num[i]].pflags & PF_NOCONTEST) && players[data.num[i]].bot) + if ((players[data.num[i]].pflags & PF_NOCONTEST) && players[data.num[i]].bot) { // RETIRED!! V_DrawScaledPatch(x+12, y-7, 0, W_CachePatchName("K_NOBLNS", PU_CACHE)); @@ -811,15 +811,7 @@ void Y_Ticker(void) { if (!data.rankingsmode && sorttic != -1 && (intertic >= sorttic + 8)) { - UINT8 i; - for (i = 0; i < MAXPLAYERS; i++) - { - if ((players[i].pflags & PF_NOCONTEST) && players[i].bot) - { - K_ReplaceBot(&players[i]); - } - } - + K_RetireBots(); Y_CalculateMatchData(1, Y_CompareRank); } @@ -1170,6 +1162,7 @@ void Y_StartIntermission(void) // void Y_EndIntermission(void) { + K_RetireBots(); Y_UnloadData(); endtic = -1; From 33c79ea746a43206bc2419a9b86de6b946fa58f1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 2 Apr 2022 14:54:23 -0400 Subject: [PATCH 11/49] Bad function declaration --- src/k_grandprix.c | 2 +- src/k_grandprix.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_grandprix.c b/src/k_grandprix.c index bb14edac6..740730c6f 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -581,7 +581,7 @@ void K_RetireBots(void) continue; } - bot = players[i]; + bot = &players[i]; if (bot->spectator) { diff --git a/src/k_grandprix.h b/src/k_grandprix.h index 552f75450..bd20d3894 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -106,13 +106,13 @@ void K_IncreaseBotDifficulty(player_t *bot); /*-------------------------------------------------- - void K_RetireBots(player_t *bot); + void K_RetireBots(void); Replaces PF_NOCONTEST bots, by refreshing their difficulty and changing their skin. --------------------------------------------------*/ -void K_RetireBots(player_t *bot); +void K_RetireBots(void); /*-------------------------------------------------- From e2ac69824732ddef41c0c0aa33fe529f61b36ea4 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 27 May 2022 17:51:47 -0400 Subject: [PATCH 12/49] Make Ballhog more interesting - No more instant fuck you button. You charge up a meter instead by holding down attack, and let go to fire as many as you charged up. Tapping fires one out of five, holding for the entire duration shoots out all five like before, but anything inbetween is also possible. - Ballhog projectiles scale up over time (like Contra spread shot), to help make it stronger again after players started getting faster. --- src/d_player.h | 6 +- src/k_hud.c | 10 ++++ src/k_kart.c | 134 +++++++++++++++++++++++++++----------------- src/k_kart.h | 2 +- src/lua_playerlib.c | 4 ++ src/p_inter.c | 2 +- src/p_mobj.c | 3 + src/p_saveg.c | 4 ++ 8 files changed, 111 insertions(+), 54 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index c6328c3ca..9b5ba4cca 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -259,6 +259,8 @@ typedef enum #define TUMBLEBOUNCES 3 +#define BALLHOGINCREMENT (7) + //} // for kickstartaccel @@ -470,9 +472,11 @@ typedef struct player_s UINT16 flamemeter; // Flame Shield dash meter left UINT8 flamelength; // Flame Shield dash meter, number of segments + UINT16 ballhogcharge; // Ballhog charge up -- the higher this value, the more projectiles + UINT16 hyudorotimer; // Duration of the Hyudoro offroad effect itself SINT8 stealingtimer; // if >0 you are stealing, if <0 you are being stolen from - mobj_t *hoverhyudoro; // First hyudoro hovering next to player + mobj_t *hoverhyudoro; // First hyudoro hovering next to player UINT16 sneakertimer; // Duration of a Sneaker Boost (from Sneakers or level boosters) UINT8 numsneakers; // Number of stacked sneaker effects diff --git a/src/k_hud.c b/src/k_hud.c index 2f0a43b24..4e9a4544f 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1204,6 +1204,16 @@ static void K_drawKartItem(void) else localpatch = kp_nodraw; } + else if (stplyr->ballhogcharge > 0) + { + itembar = stplyr->ballhogcharge; + maxl = (((stplyr->itemamount-1) * BALLHOGINCREMENT) + 1); + + if (leveltime & 1) + localpatch = kp_ballhog[offset]; + else + localpatch = kp_nodraw; + } else if (stplyr->rocketsneakertimer > 1) { itembar = stplyr->rocketsneakertimer; diff --git a/src/k_kart.c b/src/k_kart.c index 170e5a361..f2b4cb21f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -493,6 +493,10 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem) player->itemtype = KITEM_JAWZ; player->itemamount = 2; break; + case KITEM_BALLHOG: // Ballhog x5 + player->itemtype = KITEM_BALLHOG; + player->itemamount = 5; + break; default: if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback) { @@ -4052,7 +4056,6 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I if (source->player != NULL) { - if (source->player->itemscale == ITEMSCALE_SHRINK) { // Nerf the base item speed a bit. @@ -4165,6 +4168,11 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I S_StartSound(th, sfx_s3kbfl); S_StartSound(th, sfx_cdfm35); break; + case MT_BALLHOG: + // Contra spread shot scale up + th->destscale = th->destscale << 1; + th->scalespeed = abs(th->destscale - th->scale) / (2*TICRATE); + break; default: break; } @@ -5000,7 +5008,7 @@ static mobj_t *K_FindLastTrailMobj(player_t *player) return trail; } -mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow) +mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset) { mobj_t *mo; INT32 dir; @@ -5066,46 +5074,21 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, if (missile) // Shootables { - if (mapthing == MT_BALLHOG) // Messy + if (dir == -1 && mapthing != MT_SPB) { - mo = NULL; // can't return multiple projectiles - if (dir == -1) - { - // Shoot backward - K_SpawnKartMissile(player->mo, mapthing, (player->mo->angle + ANGLE_180) - 0x06000000, 0, PROJSPEED/8); - K_SpawnKartMissile(player->mo, mapthing, (player->mo->angle + ANGLE_180) - 0x03000000, 0, PROJSPEED/8); - K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180, 0, PROJSPEED/8); - K_SpawnKartMissile(player->mo, mapthing, (player->mo->angle + ANGLE_180) + 0x03000000, 0, PROJSPEED/8); - K_SpawnKartMissile(player->mo, mapthing, (player->mo->angle + ANGLE_180) + 0x06000000, 0, PROJSPEED/8); - } - else - { - // Shoot forward - K_SpawnKartMissile(player->mo, mapthing, player->mo->angle - 0x06000000, 0, PROJSPEED); - K_SpawnKartMissile(player->mo, mapthing, player->mo->angle - 0x03000000, 0, PROJSPEED); - K_SpawnKartMissile(player->mo, mapthing, player->mo->angle, 0, PROJSPEED); - K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + 0x03000000, 0, PROJSPEED); - K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + 0x06000000, 0, PROJSPEED); - } + // Shoot backward + mo = K_SpawnKartMissile(player->mo, mapthing, (player->mo->angle + ANGLE_180) + angleOffset, 0, PROJSPEED/8); } else { - if (dir == -1 && mapthing != MT_SPB) - { - // Shoot backward - mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180, 0, PROJSPEED/8); - } - else - { - // Shoot forward - mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle, 0, PROJSPEED); - } + // Shoot forward + mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + angleOffset, 0, PROJSPEED); + } - if (mapthing == MT_DROPTARGET && mo) - { - mo->reactiontime = TICRATE/2; - P_SetMobjState(mo, mo->info->painstate); - } + if (mapthing == MT_DROPTARGET && mo) + { + mo->reactiontime = TICRATE/2; + P_SetMobjState(mo, mo->info->painstate); } } else @@ -6067,6 +6050,10 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 newType = KITEM_JAWZ; newAmount = 2; break; + case KITEM_BALLHOG: // Ballhog x5 + newType = KITEM_BALLHOG; + newAmount = 5; + break; default: newType = i; newAmount = 1; @@ -9573,7 +9560,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { if (ATTACK_IS_DOWN) { - K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0); + K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0, 0); K_PlayAttackTaunt(player->mo); player->pflags &= ~PF_EGGMANOUT; K_UpdateHnextList(player, true); @@ -9699,7 +9686,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else if (ATTACK_IS_DOWN && (player->pflags & PF_ITEMOUT)) // Banana x3 thrown { - K_ThrowKartItem(player, false, MT_BANANA, -1, 0); + K_ThrowKartItem(player, false, MT_BANANA, -1, 0, 0); K_PlayAttackTaunt(player->mo); player->itemamount--; K_UpdateHnextList(player, false); @@ -9762,7 +9749,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else if (ATTACK_IS_DOWN && (player->pflags & PF_ITEMOUT)) // Orbinaut x3 thrown { - K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0); + K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0, 0); K_PlayAttackTaunt(player->mo); player->itemamount--; K_UpdateHnextList(player, false); @@ -9804,9 +9791,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (ATTACK_IS_DOWN && HOLDING_ITEM && (player->pflags & PF_ITEMOUT)) // Jawz thrown { if (player->throwdir == 1 || player->throwdir == 0) - K_ThrowKartItem(player, true, MT_JAWZ, 1, 0); + K_ThrowKartItem(player, true, MT_JAWZ, 1, 0, 0); else if (player->throwdir == -1) // Throwing backward gives you a dud that doesn't home in - K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0); + K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0, 0); K_PlayAttackTaunt(player->mo); player->itemamount--; K_UpdateHnextList(player, false); @@ -9832,7 +9819,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else if (ATTACK_IS_DOWN && (player->pflags & PF_ITEMOUT)) { - K_ThrowKartItem(player, false, MT_SSMINE, 1, 1); + K_ThrowKartItem(player, false, MT_SSMINE, 1, 1, 0); K_PlayAttackTaunt(player->mo); player->itemamount--; player->pflags &= ~PF_ITEMOUT; @@ -9867,7 +9854,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else if (ATTACK_IS_DOWN && (player->pflags & PF_ITEMOUT)) { - K_ThrowKartItem(player, (player->throwdir > 0), MT_DROPTARGET, -1, 0); + K_ThrowKartItem(player, (player->throwdir > 0), MT_DROPTARGET, -1, 0, 0); K_PlayAttackTaunt(player->mo); player->itemamount--; player->pflags &= ~PF_ITEMOUT; @@ -9875,18 +9862,63 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } break; case KITEM_BALLHOG: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + if (!HOLDING_ITEM && NO_HYUDORO) { - player->itemamount--; - K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0); - K_PlayAttackTaunt(player->mo); + INT32 ballhogmax = ((player->itemamount-1) * BALLHOGINCREMENT) + 1; + + if ((cmd->buttons & BT_ATTACK) && (player->pflags & PF_HOLDREADY) + && (player->ballhogcharge < ballhogmax)) + { + player->ballhogcharge++; + } + else + { + if (cmd->buttons & BT_ATTACK) + { + player->pflags &= ~PF_HOLDREADY; + } + else + { + player->pflags |= PF_HOLDREADY; + } + + if (player->ballhogcharge > 0) + { + INT32 numhogs = min((player->ballhogcharge / BALLHOGINCREMENT) + 1, player->itemamount); + + if (numhogs <= 1) + { + player->itemamount--; + K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0, 0); + } + else + { + angle_t cone = 0x01800000 * (numhogs-1); + angle_t offsetAmt = (cone * 2) / (numhogs-1); + angle_t angleOffset = cone; + INT32 i; + + player->itemamount -= numhogs; + + for (i = 0; i < numhogs; i++) + { + K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0, angleOffset); + angleOffset -= offsetAmt; + } + } + + player->ballhogcharge = 0; + K_PlayAttackTaunt(player->mo); + player->pflags &= ~PF_HOLDREADY; + } + } } break; case KITEM_SPB: if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { player->itemamount--; - K_ThrowKartItem(player, true, MT_SPB, 1, 0); + K_ThrowKartItem(player, true, MT_SPB, 1, 0, 0); K_PlayAttackTaunt(player->mo); } break; @@ -9987,7 +10019,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->bubbleblowup > bubbletime*2) { - K_ThrowKartItem(player, (player->throwdir > 0), MT_BUBBLESHIELDTRAP, -1, 0); + K_ThrowKartItem(player, (player->throwdir > 0), MT_BUBBLESHIELDTRAP, -1, 0, 0); K_PlayAttackTaunt(player->mo); player->bubbleblowup = 0; player->bubblecool = 0; @@ -10131,7 +10163,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else if (ATTACK_IS_DOWN && HOLDING_ITEM && (player->pflags & PF_ITEMOUT)) // Sink thrown { - K_ThrowKartItem(player, false, MT_SINK, 1, 2); + K_ThrowKartItem(player, false, MT_SINK, 1, 2, 0); K_PlayAttackTaunt(player->mo); player->itemamount--; player->pflags &= ~PF_ITEMOUT; diff --git a/src/k_kart.h b/src/k_kart.h index 5a6555db0..275e345fe 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -87,7 +87,7 @@ void K_SpawnWipeoutTrail(mobj_t *mo); void K_SpawnDraftDust(mobj_t *mo); void K_DriftDustHandling(mobj_t *spawner); void K_Squish(mobj_t *mo); -mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow); +mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset); void K_PuntMine(mobj_t *mine, mobj_t *punter); void K_DoSneaker(player_t *player, INT32 type); void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 4b2bad33d..7984b053b 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -330,6 +330,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->flamemeter); else if (fastcmp(field,"flamelength")) lua_pushinteger(L, plr->flamelength); + else if (fastcmp(field,"ballhogcharge")) + lua_pushinteger(L, plr->ballhogcharge); else if (fastcmp(field,"hyudorotimer")) lua_pushinteger(L, plr->hyudorotimer); else if (fastcmp(field,"stealingtimer")) @@ -682,6 +684,8 @@ static int player_set(lua_State *L) plr->flamemeter = luaL_checkinteger(L, 3); else if (fastcmp(field,"flamelength")) plr->flamelength = luaL_checkinteger(L, 3); + else if (fastcmp(field,"ballhogcharge")) + plr->ballhogcharge = luaL_checkinteger(L, 3); else if (fastcmp(field,"hyudorotimer")) plr->hyudorotimer = luaL_checkinteger(L, 3); else if (fastcmp(field,"stealingtimer")) diff --git a/src/p_inter.c b/src/p_inter.c index 27455872d..689b91912 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1410,7 +1410,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget // special behavior for SPB capsules if (target->threshold == KITEM_SPB) { - K_ThrowKartItem(player, true, MT_SPB, 1, 0); + K_ThrowKartItem(player, true, MT_SPB, 1, 0, 0); break; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 5219fb707..a1ec033bc 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1548,7 +1548,10 @@ void P_XYMovement(mobj_t *mo) { mo->health--; if (mo->health == 0) + { + mo->scalespeed = mo->scale/12; mo->destscale = 0; + } } } //} diff --git a/src/p_saveg.c b/src/p_saveg.c index 0ae0ee72a..1eac84058 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -314,6 +314,8 @@ static void P_NetArchivePlayers(void) WRITEUINT16(save_p, players[i].flamemeter); WRITEUINT8(save_p, players[i].flamelength); + WRITEUINT16(save_p, players[i].ballhogcharge); + WRITEUINT16(save_p, players[i].hyudorotimer); WRITESINT8(save_p, players[i].stealingtimer); @@ -595,6 +597,8 @@ static void P_NetUnArchivePlayers(void) players[i].flamemeter = READUINT16(save_p); players[i].flamelength = READUINT8(save_p); + players[i].ballhogcharge = READUINT16(save_p); + players[i].hyudorotimer = READUINT16(save_p); players[i].stealingtimer = READSINT8(save_p); From c878c7725cf687a133a7c1c550d021c676321773 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 10 Sep 2022 15:03:42 -0400 Subject: [PATCH 13/49] Reduce tripwire leniency from 35 to 7 tics --- src/d_player.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_player.h b/src/d_player.h index 91989279c..2b47c89a1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -268,7 +268,7 @@ typedef enum #define TUMBLEBOUNCES 3 #define TUMBLEGRAVITY (4*FRACUNIT) -#define TRIPWIRETIME (TICRATE) +#define TRIPWIRETIME (7) //} From 16a12de4f4e2d9546f2d701abc4e2db58607c6bb Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 16 Sep 2022 06:57:28 -0400 Subject: [PATCH 14/49] Fix hyudoro ballhog bug --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index d91e26e18..e57b01991 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9011,7 +9011,7 @@ void K_StripItems(player_t *player) player->curshield = KSHIELD_NONE; player->bananadrag = 0; - + player->ballhogcharge = 0; player->sadtimer = 0; K_UpdateHnextList(player, true); From 4d67cc6324593b1905b9e385043399360e6bb8dd Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 17 Sep 2022 06:34:11 -0700 Subject: [PATCH 15/49] Replace shitty item box pop with flying debris and dust clouds Debris flies forward and outward from the player in the direction of momentum. Debris particles bounce once then disappear when they hit the ground for the second time. Clouds spawn on and trail behind the player for a short duration. --- src/deh_tables.c | 9 ++ src/info.c | 61 +++++++++++ src/info.h | 11 ++ src/k_collide.c | 4 +- src/k_objects.h | 6 ++ src/objects/Sourcefile | 1 + src/objects/item-debris.c | 207 ++++++++++++++++++++++++++++++++++++++ src/p_enemy.c | 131 +++++++++++++++--------- src/p_mobj.c | 17 ++++ 9 files changed, 396 insertions(+), 51 deletions(-) create mode 100644 src/objects/item-debris.c diff --git a/src/deh_tables.c b/src/deh_tables.c index 5fe950e9e..37d1e0cc0 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -337,6 +337,7 @@ actionpointer_t actionpointers[] = {{A_ReaperThinker}, "A_REAPERTHINKER"}, {{A_FlameShieldPaper}, "A_FLAMESHIELDPAPER"}, {{A_InvincSparkleRotate}, "A_INVINCSPARKLEROTATE"}, + {{A_SpawnItemDebrisCloud}, "A_SPAWNITEMDEBRISCLOUD"}, {{NULL}, "NONE"}, @@ -3277,6 +3278,12 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_RANDOMITEMPOP4", //} + "S_ITEM_DEBRIS", + "S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT", + "S_ITEM_DEBRIS_CLOUD_SPAWNER1", + "S_ITEM_DEBRIS_CLOUD_SPAWNER2", + "S_ITEM_DEBRIS_CLOUD_SPAWNER3", + "S_ITEMICON", // Item capsules @@ -5297,6 +5304,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BRAKEDRIFT", "MT_BRAKEDUST", "MT_DRIFTDUST", + "MT_ITEM_DEBRIS", + "MT_ITEM_DEBRIS_CLOUD_SPAWNER", "MT_DRIFTELECTRICITY", "MT_DRIFTELECTRICSPARK", "MT_JANKSPARK", diff --git a/src/info.c b/src/info.c index b0a3becef..e0df17fa6 100644 --- a/src/info.c +++ b/src/info.c @@ -530,6 +530,7 @@ char sprnames[NUMSPRITES + 1][5] = "RNDM", // Random Item Box "SBOX", // Sphere Box (for Battle) "RPOP", // Random Item Box Pop + "ITRI", // Item Box Debris "SGNS", // Signpost sparkle "FAST", // Speed boost trail "DSHR", // Speed boost dust release @@ -3867,6 +3868,12 @@ state_t states[NUMSTATES] = {SPR_RPOP, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_RANDOMITEMPOP4}, // S_RANDOMITEMPOP3 {SPR_RPOP, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL}, // S_RANDOMITEMPOP4 + {SPR_ITRI, FF_FULLBRIGHT, -1, {NULL}, 19, 1, S_NULL}, // S_ITEM_DEBRIS + {SPR_NULL, 0, 1, {NULL}, 0, 0, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT + {SPR_NULL, 0, 1, {A_Repeat}, 4, S_ITEM_DEBRIS_CLOUD_SPAWNER2, S_NULL}, // S_ITEM_DEBRIS_CLOUD_SPAWNER1 + {SPR_NULL, 4, 2, {A_SpawnItemDebrisCloud}, 1, 10, S_ITEM_DEBRIS_CLOUD_SPAWNER3}, // S_ITEM_DEBRIS_CLOUD_SPAWNER2 + {SPR_NULL, 4, 5, {A_SpawnItemDebrisCloud}, 0, 2, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER3 + {SPR_NULL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMICON {SPR_ICAP, FF_ADD|0, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE @@ -23128,6 +23135,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_ITEM_DEBRIS + -1, // doomednum + S_ITEM_DEBRIS, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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 + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_ITEM_DEBRIS_CLOUD_SPAWNER + -1, // doomednum + S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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 + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + { // MT_DRIFTELECTRICITY -1, // doomednum S_DRIFTELECTRICITY, // spawnstate diff --git a/src/info.h b/src/info.h index 8acf73ba8..62daffb42 100644 --- a/src/info.h +++ b/src/info.h @@ -290,6 +290,7 @@ enum actionnum A_REAPERTHINKER, A_FLAMESHIELDPAPER, A_INVINCSPARKLEROTATE, + A_SPAWNITEMDEBRISCLOUD, NUMACTIONS }; @@ -563,6 +564,7 @@ void A_ReaperThinker(); void A_MementosTPParticles(); void A_FlameShieldPaper(); void A_InvincSparkleRotate(); +void A_SpawnItemDebrisCloud(); extern boolean actionsoverridden[NUMACTIONS]; @@ -1076,6 +1078,7 @@ typedef enum sprite SPR_RNDM, // Random Item Box SPR_SBOX, // Sphere Box (for Battle) SPR_RPOP, // Random Item Box Pop + SPR_ITRI, // Item Box Debris SPR_SGNS, // Signpost sparkle SPR_FAST, // Speed boost trail SPR_DSHR, // Speed boost dust release @@ -4270,6 +4273,12 @@ typedef enum state S_RANDOMITEMPOP4, //} + S_ITEM_DEBRIS, + S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT, + S_ITEM_DEBRIS_CLOUD_SPAWNER1, + S_ITEM_DEBRIS_CLOUD_SPAWNER2, + S_ITEM_DEBRIS_CLOUD_SPAWNER3, + S_ITEMICON, // Item capsules @@ -6326,6 +6335,8 @@ typedef enum mobj_type MT_BRAKEDRIFT, MT_BRAKEDUST, MT_DRIFTDUST, + MT_ITEM_DEBRIS, + MT_ITEM_DEBRIS_CLOUD_SPAWNER, MT_DRIFTELECTRICITY, MT_DRIFTELECTRICSPARK, MT_JANKSPARK, diff --git a/src/k_collide.c b/src/k_collide.c index a23801ccc..9d582da59 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -11,6 +11,7 @@ #include "hu_stuff.h" // Sink snipe print #include "doomdef.h" // Sink snipe print #include "g_game.h" // Sink snipe print +#include "k_objects.h" angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2) { @@ -265,8 +266,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) } else { - mobj_t *poof = P_SpawnMobj(t1->x, t1->y, t1->z, MT_EXPLODE); - S_StartSound(poof, t1->info->deathsound); + Obj_SpawnItemDebrisEffects(t1, t2); #if 0 // Eggbox snipe! diff --git a/src/k_objects.h b/src/k_objects.h index cc80d2555..128c0f461 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -15,4 +15,10 @@ void Obj_ShrinkGunRemoved(mobj_t *gun); boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim); void Obj_CreateShrinkPohbees(player_t *owner); +/* Item Debris */ +fixed_t Obj_GetItemDebrisSpeed(mobj_t *collector, fixed_t min_speed); +void Obj_SpawnItemDebrisEffects(mobj_t *collectible, mobj_t *collector); +void Obj_ItemDebrisThink(mobj_t *debris); +fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz); + #endif/*k_objects_H*/ diff --git a/src/objects/Sourcefile b/src/objects/Sourcefile index 94f7dd25b..d1e801471 100644 --- a/src/objects/Sourcefile +++ b/src/objects/Sourcefile @@ -1,2 +1,3 @@ hyudoro.c shrink.c +item-debris.c diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c new file mode 100644 index 000000000..dcb1950d7 --- /dev/null +++ b/src/objects/item-debris.c @@ -0,0 +1,207 @@ +#include "../doomdef.h" +#include "../d_player.h" +#include "../m_random.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../p_local.h" +#include "../s_sound.h" + +// TODO: general function +static fixed_t K_GetPlayerSpeedRatio(player_t *player) +{ + return FixedDiv(player->speed, + K_GetKartSpeed(player, false, false)); +} + +#define debris_type(o) ((o)->extravalue1) +#define debris_bouncesleft(o) ((o)->threshold) + +enum { + DEBRIS_ALPHA, + DEBRIS_BETA, + + NUM_DEBRIS_TYPES +}; + +struct debris_config { + mobj_t * origin; + angle_t angle; + fixed_t speed; + fixed_t scale; + UINT8 type; +}; + +static fixed_t +get_speed_ratio (mobj_t *thing) +{ + return thing->player ? + K_GetPlayerSpeedRatio(thing->player) : FRACUNIT; +} + +static void +spawn_debris +( const struct debris_config * config, + INT32 angle) +{ + const fixed_t height_table[NUM_DEBRIS_TYPES] = { + 50*FRACUNIT, + 35*FRACUNIT, + }; + + mobj_t *debris = P_SpawnMobjFromMobj( + config->origin, 0, 0, 0, MT_ITEM_DEBRIS); + + const state_t *st = debris->state; + + debris_type(debris) = config->type; + debris_bouncesleft(debris) = 1; + + // Start at a random frame of animation + debris->frame = (debris->frame & ~(FF_FRAMEMASK)) | + P_RandomRange((st->frame & FF_FRAMEMASK), st->var1); + + P_InstaThrust(debris, + config->angle + angle, + config->speed); + + P_SetObjectMomZ(debris, + FixedMul(config->scale, + height_table[config->type]), + false); + + debris->destscale = + FixedMul(config->scale, 3 * debris->scale); + P_SetScale(debris, debris->destscale); + + // Pass down color to dust particles + debris->color = config->origin->color; +} + +static void +spawn_cloud +( mobj_t * collectible, + mobj_t * collector) +{ + mobj_t *spawner = P_SpawnMobjFromMobj(collectible, + 0, 0, 0, MT_ITEM_DEBRIS_CLOUD_SPAWNER); + + P_SetTarget(&spawner->target, collector); + + S_StartSound(spawner, sfx_kc2e); + S_StartSound(spawner, sfx_s1c9); +} + +static void +rotate3d (mobj_t *debris) +{ + const UINT8 steps = 30; + + debris->rollangle = + M_RandomKey(steps) * (ANGLE_MAX / steps); +} + +fixed_t +Obj_GetItemDebrisSpeed +( mobj_t * collector, + fixed_t min_speed) +{ + const fixed_t base_speed = FixedMul( + 75 * mapobjectscale, + get_speed_ratio(collector)); + + return max(base_speed, min_speed); +} + +void +Obj_SpawnItemDebrisEffects +( mobj_t * collectible, + mobj_t * collector) +{ + const fixed_t min_speed = 80 * collectible->scale; + + const fixed_t speed = + Obj_GetItemDebrisSpeed(collector, min_speed); + + struct debris_config config = { + .origin = collectible, + .angle = K_MomentumAngle(collector), + .speed = speed, + .scale = FixedDiv(speed, min_speed), + }; + + config.type = DEBRIS_ALPHA; + + spawn_debris(&config, ANGLE_11hh); + spawn_debris(&config, -(ANGLE_11hh)); + + config.type = DEBRIS_BETA; + + spawn_debris(&config, 3*ANGLE_22h/2); + spawn_debris(&config, 3*ANGLE_22h/4); + spawn_debris(&config, 0); + spawn_debris(&config, -(3*ANGLE_22h/4)); + spawn_debris(&config, -(3*ANGLE_22h/2)); + + spawn_cloud(collectible, collector); +} + +void +Obj_ItemDebrisThink (mobj_t *debris) +{ + const UINT8 frame = (debris->frame & FF_FRAMEMASK); + + if (debris->momz == 0) + { + P_KillMobj(debris, NULL, NULL, DMG_NORMAL); + return; + } + + rotate3d(debris); + + if (frame % 3 == 1) + { + mobj_t *ghost = P_SpawnGhostMobj(debris); + + ghost->fuse = 3; + } + + if (debris_type(debris) == DEBRIS_ALPHA) + { + mobj_t *dust = P_SpawnMobjFromMobj( + debris, 0, 0, 0, MT_SPINDASHDUST); + + P_SetScale(dust, (dust->destscale /= 3)); + + dust->color = debris->color; + dust->colorized = true; + + dust->momx = debris->momx / 4; + dust->momy = debris->momy / 4; + dust->momz = debris->momz / 4; + } +} + +fixed_t +Obj_ItemDebrisBounce +( mobj_t * debris, + fixed_t momz) +{ + if (debris_bouncesleft(debris) <= 0) + { + P_KillMobj(debris, NULL, NULL, DMG_NORMAL); + return 0; + } + + momz = -(momz); + + if (debris_type(debris) == DEBRIS_BETA) + { + momz /= 2; + } + + debris_bouncesleft(debris)--; + + S_StartSound(debris, sfx_cdfm47); + + return momz; +} diff --git a/src/p_enemy.c b/src/p_enemy.c index d5f999624..879d01350 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -32,6 +32,7 @@ #include "k_battle.h" #include "k_respawn.h" #include "k_collide.h" +#include "k_objects.h" #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -326,6 +327,7 @@ void A_ReaperThinker(mobj_t *actor); void A_MementosTPParticles(mobj_t *actor); void A_FlameShieldPaper(mobj_t *actor); void A_InvincSparkleRotate(mobj_t *actor); +void A_SpawnItemDebrisCloud(mobj_t *actor); //for p_enemy.c @@ -13166,9 +13168,6 @@ void A_ItemPop(mobj_t *actor) { INT32 locvar1 = var1; - mobj_t *remains; - mobjtype_t explode; - if (LUA_CallAction(A_ITEMPOP, actor)) return; @@ -13185,58 +13184,13 @@ void A_ItemPop(mobj_t *actor) actor->flags |= MF_NOCLIP; P_SetThingPosition(actor); - // item explosion - explode = mobjinfo[actor->info->damage].mass; - remains = P_SpawnMobj(actor->x, actor->y, - ((actor->eflags & MFE_VERTICALFLIP) ? (actor->z + 3*(actor->height/4) - FixedMul(mobjinfo[explode].height, actor->scale)) : (actor->z + actor->height/4)), explode); - if (actor->eflags & MFE_VERTICALFLIP) - { - remains->eflags |= MFE_VERTICALFLIP; - remains->flags2 |= MF2_OBJECTFLIP; - } - remains->destscale = actor->destscale; - P_SetScale(remains, actor->scale); - - remains = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->damage); - remains->type = actor->type; // Transfer type information - P_UnsetThingPosition(remains); - if (sector_list) - { - P_DelSeclist(sector_list); - sector_list = NULL; - } - P_SetThingPosition(remains); - remains->destscale = actor->destscale; - P_SetScale(remains, actor->scale); - remains->flags = actor->flags; // Transfer flags - remains->flags2 = actor->flags2; // Transfer flags2 - remains->fuse = actor->fuse; // Transfer respawn timer - remains->cvmem = leveltime; - remains->threshold = actor->threshold; - if (remains->threshold != 69 && remains->threshold != 70) - { - remains->threshold = 68; - } - // To insure this information doesn't have to be rediscovered every time you look at this function... - // A threshold of 0 is for a "living", ordinary random item. - // 68 means regular popped random item debris. - // 69 used to mean old Karma Item behaviour (now you can replicate this with MF2_DONTRESPAWN). - // 70 is a powered up Overtime item. - remains->skin = NULL; - remains->spawnpoint = actor->spawnpoint; - - P_SetTarget(&tmthing, remains); - - if (actor->info->deathsound) - S_StartSound(remains, actor->info->deathsound); + Obj_SpawnItemDebrisEffects(actor, actor->target); if (locvar1 == 1) P_GivePlayerSpheres(actor->target->player, actor->extravalue1); else if (locvar1 == 0) actor->target->player->itemroulette = 1; - remains->flags2 &= ~MF2_AMBUSH; - // Here at mapload in battle? if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP)) numgotboxes++; @@ -14525,3 +14479,82 @@ void A_InvincSparkleRotate(mobj_t *actor) ghost->fuse = 4; } } + +// Function: A_SpawnItemDebrisCloud +// +// Description: Spawns a particle effect relative to the location of the actor +// +// var1 = If 1, scale size and momentum by extravalue2 / frame. +// var2 = Number of particles to spawn. +// +void +A_SpawnItemDebrisCloud (mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + const fixed_t min_speed = 90 * actor->scale; + const INT16 spacing = (actor->radius / 2) / actor->scale; + + fixed_t fade = FRACUNIT; + fixed_t scale_fade = FRACUNIT; + + mobj_t *target = actor->target; + + fixed_t speed; + fixed_t scale; + + INT32 i; + + if (target == NULL) + { + return; + } + + if (locvar1) + { + const UINT8 frame = (actor->frame & FF_FRAMEMASK); + fixed_t frac; + + if (frame == 0) + { + return; // div by zero + } + + // extravalue2 from A_Repeat + frac = fade / frame; + fade = actor->extravalue2 * frac; + scale_fade = fade + frac; + } + + speed = Obj_GetItemDebrisSpeed(target, min_speed); + scale = 2 * FixedMul(FixedDiv(speed, min_speed), scale_fade); + + // Most of this code is from p_inter.c, MT_ITEMCAPSULE + + // dust effects + for (i = 0; i < locvar2; i++) + { + mobj_t *puff = P_SpawnMobjFromMobj( + target, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(0, 4 * spacing) * FRACUNIT, + MT_SPINDASHDUST + ); + + puff->color = target->color; + puff->colorized = true; + + puff->destscale = FixedMul(puff->destscale, scale); + P_SetScale(puff, puff->destscale); + + puff->momz = puff->scale * P_MobjFlip(puff); + + P_Thrust(puff, R_PointToAngle2(target->x, target->y, puff->x, puff->y), 3 * puff->scale); + + puff->momx += FixedMul(target->momx, fade); + puff->momy += FixedMul(target->momy, fade); + puff->momz += FixedMul(target->momz, fade); + } +} diff --git a/src/p_mobj.c b/src/p_mobj.c index 0505d6bda..ee005d960 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1209,6 +1209,9 @@ fixed_t P_GetMobjGravity(mobj_t *mo) case MT_KARMAFIREWORK: gravityadd /= 3; break; + case MT_ITEM_DEBRIS: + gravityadd *= 6; + break; default: break; } @@ -2339,6 +2342,15 @@ boolean P_ZMovement(mobj_t *mo) mom.z = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale); else if (mo->type == MT_SPINFIRE) // elemental shield fire is another exception here ; + else if (mo->type == MT_ITEM_DEBRIS) + { + mom.z = Obj_ItemDebrisBounce(mo, mom.z); + + if (mom.z == 0) + { + return false; + } + } else if (mo->type == MT_DRIFTCLIP) { mom.z = -mom.z/2; @@ -7845,6 +7857,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_PohbeeThinker(mobj); break; } + case MT_ITEM_DEBRIS: + { + Obj_ItemDebrisThink(mobj); + break; + } case MT_ROCKETSNEAKER: if (!mobj->target || !mobj->target->health) { From c7847fa32aaf98d08855bd0a2ac634be3cd0a99c Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 19 Sep 2022 14:21:37 -0700 Subject: [PATCH 16/49] Bump trip wire leniency tics from 7 to 15 --- src/d_player.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_player.h b/src/d_player.h index 7b14f57c6..259a66f70 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -268,7 +268,7 @@ typedef enum #define TUMBLEBOUNCES 3 #define TUMBLEGRAVITY (4*FRACUNIT) -#define TRIPWIRETIME (7) +#define TRIPWIRETIME (15) //} From a2db1673dc0be5a70d29a1e598ae17f9b9982b6f Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Mon, 19 Sep 2022 19:27:23 -0400 Subject: [PATCH 17/49] Made hitbox radius 26 instead of 16 --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 6774050b6..e80098499 100644 --- a/src/info.c +++ b/src/info.c @@ -23753,7 +23753,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_hogbom, // deathsound 80*FRACUNIT, // speed - 16*FRACUNIT, // radius + 26*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset 100, // mass From db25599647496d6e79c4b761719ffc6c7f3ec70e Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 02:34:53 -0700 Subject: [PATCH 18/49] Offline input delay cvar --- src/d_clisrv.c | 4 +++- src/d_clisrv.h | 1 + src/d_netcmd.c | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ebd58844e..aa4199fce 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -114,6 +114,8 @@ UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. static tic_t lowest_lag; boolean server_lagless; +static CV_PossibleValue_t mindelay_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; +consvar_t cv_mindelay = CVAR_INIT ("mindelay", "0", 0, mindelay_cons_t, NULL); SINT8 nodetoplayer[MAXNETNODES]; SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) @@ -5665,7 +5667,7 @@ static void UpdatePingTable(void) if (netgame && !(gametime % 35)) // update once per second. PingUpdate(); - fastest = 0; + fastest = cv_mindelay.value; // update node latency values so we can take an average later. for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 72ce18a5c..ca36ba26c 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -445,6 +445,7 @@ extern UINT32 playerpingtable[MAXPLAYERS]; extern tic_t servermaxping; extern boolean server_lagless; +extern consvar_t cv_mindelay; extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_maxconnections, cv_joindelay; extern consvar_t cv_resynchattempts, cv_blamecfail; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9dcc990a9..c0057896a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -972,6 +972,7 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_rollingdemos); CV_RegisterVar(&cv_netstat); CV_RegisterVar(&cv_netticbuffer); + CV_RegisterVar(&cv_mindelay); #ifdef NETGAME_DEVMODE CV_RegisterVar(&cv_fishcake); From c2b2cd9a43a1252983b7311d8f0f53a36338e267 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 19 Sep 2022 23:37:29 -0700 Subject: [PATCH 19/49] Reenable item box respawning Old code was shit so I removed it (4d67cc632). Turns out none of that bullshit actually mattered to make this box respawn and it just needs to go to an invisible state! Makes use of some nifty flickering code (that was already there but effectively disabled) shortly before it actually respawns. --- src/info.c | 2 +- src/p_enemy.c | 8 ++++++-- src/p_mobj.c | 4 ---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/info.c b/src/info.c index ce37b51ad..3c868d4c0 100644 --- a/src/info.c +++ b/src/info.c @@ -3849,7 +3849,7 @@ state_t states[NUMSTATES] = {SPR_RNDM, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_RANDOMITEM11}, // S_RANDOMITEM10 {SPR_RNDM, 20|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_RANDOMITEM12}, // S_RANDOMITEM11 {SPR_RNDM, 22|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_RANDOMITEM1}, // S_RANDOMITEM12 - {SPR_NULL, 0, 0, {A_ItemPop}, 0, 0, S_NULL}, // S_DEADRANDOMITEM + {SPR_NULL, 0, 0, {A_ItemPop}, 0, 0, S_RANDOMITEM1}, // S_DEADRANDOMITEM {SPR_SBOX, FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX2}, // S_SPHEREBOX1 {SPR_SBOX, 2|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX3}, // S_SPHEREBOX2 diff --git a/src/p_enemy.c b/src/p_enemy.c index 879d01350..901c2a2b2 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -13184,6 +13184,12 @@ void A_ItemPop(mobj_t *actor) actor->flags |= MF_NOCLIP; P_SetThingPosition(actor); + // RF_DONTDRAW will flicker as the object's fuse gets + // closer to running out (see P_FuseThink) + actor->renderflags |= RF_DONTDRAW|RF_TRANS50; + actor->color = SKINCOLOR_GREY; + actor->colorized = true; + Obj_SpawnItemDebrisEffects(actor, actor->target); if (locvar1 == 1) @@ -13194,8 +13200,6 @@ void A_ItemPop(mobj_t *actor) // Here at mapload in battle? if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP)) numgotboxes++; - - P_RemoveMobj(actor); } void A_JawzChase(mobj_t *actor) diff --git a/src/p_mobj.c b/src/p_mobj.c index ee005d960..1c34a1b1e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12683,10 +12683,6 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean P_SetThingPosition(mobj); } } - else - { - P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_EXPLODE); - } break; } case MT_ITEMCAPSULE: From f6ef29cf03bca2898824e5011cea8f7dcf487da5 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 05:24:48 -0700 Subject: [PATCH 20/49] Refactor item debris cloud - The "cloud" is stationary and spawned on the item box instead of the player. Still scales up with speed. - Single particles are spawned behind the player. No longer scales. Lasts longer but can end early if the player slows down. --- src/deh_tables.c | 2 - src/info.c | 10 ++--- src/info.h | 2 - src/k_objects.h | 1 - src/objects/item-debris.c | 90 +++++++++++++++++++++++++++------------ src/p_enemy.c | 69 +++++++++++++++--------------- 6 files changed, 101 insertions(+), 73 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 534b17db7..37ec83b7f 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3279,10 +3279,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi //} "S_ITEM_DEBRIS", - "S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT", "S_ITEM_DEBRIS_CLOUD_SPAWNER1", "S_ITEM_DEBRIS_CLOUD_SPAWNER2", - "S_ITEM_DEBRIS_CLOUD_SPAWNER3", "S_ITEMICON", diff --git a/src/info.c b/src/info.c index 3c868d4c0..84edb3900 100644 --- a/src/info.c +++ b/src/info.c @@ -3871,10 +3871,8 @@ state_t states[NUMSTATES] = {SPR_RPOP, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL}, // S_RANDOMITEMPOP4 {SPR_ITRI, FF_FULLBRIGHT, -1, {NULL}, 19, 1, S_NULL}, // S_ITEM_DEBRIS - {SPR_NULL, 0, 1, {NULL}, 0, 0, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT - {SPR_NULL, 0, 1, {A_Repeat}, 4, S_ITEM_DEBRIS_CLOUD_SPAWNER2, S_NULL}, // S_ITEM_DEBRIS_CLOUD_SPAWNER1 - {SPR_NULL, 4, 2, {A_SpawnItemDebrisCloud}, 1, 10, S_ITEM_DEBRIS_CLOUD_SPAWNER3}, // S_ITEM_DEBRIS_CLOUD_SPAWNER2 - {SPR_NULL, 4, 5, {A_SpawnItemDebrisCloud}, 0, 2, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER3 + {SPR_NULL, 0, 0, {A_Repeat}, 16, S_ITEM_DEBRIS_CLOUD_SPAWNER2, S_NULL}, // S_ITEM_DEBRIS_CLOUD_SPAWNER1 + {SPR_NULL, 0, 7, {A_SpawnItemDebrisCloud}, 20, 0, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER2 {SPR_NULL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMICON @@ -23178,7 +23176,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_ITEM_DEBRIS_CLOUD_SPAWNER -1, // doomednum - S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT, // spawnstate + S_ITEM_DEBRIS_CLOUD_SPAWNER1, // spawnstate 1, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -23199,7 +23197,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOSECTOR|MF_NOBLOCKMAP, // flags + MF_NOSECTOR|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, diff --git a/src/info.h b/src/info.h index dceec967d..c5ed74daa 100644 --- a/src/info.h +++ b/src/info.h @@ -4276,10 +4276,8 @@ typedef enum state //} S_ITEM_DEBRIS, - S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT, S_ITEM_DEBRIS_CLOUD_SPAWNER1, S_ITEM_DEBRIS_CLOUD_SPAWNER2, - S_ITEM_DEBRIS_CLOUD_SPAWNER3, S_ITEMICON, diff --git a/src/k_objects.h b/src/k_objects.h index 128c0f461..775710c1a 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -16,7 +16,6 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim); void Obj_CreateShrinkPohbees(player_t *owner); /* Item Debris */ -fixed_t Obj_GetItemDebrisSpeed(mobj_t *collector, fixed_t min_speed); void Obj_SpawnItemDebrisEffects(mobj_t *collectible, mobj_t *collector); void Obj_ItemDebrisThink(mobj_t *debris); fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz); diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c index dcb1950d7..841650527 100644 --- a/src/objects/item-debris.c +++ b/src/objects/item-debris.c @@ -4,6 +4,7 @@ #include "../k_kart.h" #include "../k_objects.h" #include "../p_local.h" +#include "../r_main.h" #include "../s_sound.h" // TODO: general function @@ -80,15 +81,52 @@ spawn_debris static void spawn_cloud ( mobj_t * collectible, - mobj_t * collector) + mobj_t * collector, + fixed_t base_speed) { - mobj_t *spawner = P_SpawnMobjFromMobj(collectible, - 0, 0, 0, MT_ITEM_DEBRIS_CLOUD_SPAWNER); + const fixed_t min_speed = 90 * collectible->scale; - P_SetTarget(&spawner->target, collector); + const fixed_t scale = FixedDiv( + max(base_speed, min_speed), min_speed); - S_StartSound(spawner, sfx_kc2e); - S_StartSound(spawner, sfx_s1c9); + const INT16 spacing = + (collectible->radius / 2) / collectible->scale; + + INT32 i; + + // Most of this code is from p_inter.c, MT_ITEMCAPSULE + + // dust effects + for (i = 0; i < 10; i++) + { + mobj_t *puff = P_SpawnMobjFromMobj( + collectible, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(0, 4 * spacing) * FRACUNIT, + MT_SPINDASHDUST + ); + + puff->color = collector->color; + puff->colorized = true; + + puff->destscale = FixedMul(puff->destscale, scale); + P_SetScale(puff, puff->destscale); + + puff->momz = puff->scale * P_MobjFlip(puff); + + P_InitAngle(puff, R_PointToAngle2( + collectible->x, + collectible->y, + puff->x, + puff->y)); + + P_Thrust(puff, puff->angle, 3 * puff->scale); + + puff->momx += collector->momx; + puff->momy += collector->momy; + puff->momz += collector->momz; + } } static void @@ -100,18 +138,6 @@ rotate3d (mobj_t *debris) M_RandomKey(steps) * (ANGLE_MAX / steps); } -fixed_t -Obj_GetItemDebrisSpeed -( mobj_t * collector, - fixed_t min_speed) -{ - const fixed_t base_speed = FixedMul( - 75 * mapobjectscale, - get_speed_ratio(collector)); - - return max(base_speed, min_speed); -} - void Obj_SpawnItemDebrisEffects ( mobj_t * collectible, @@ -119,15 +145,22 @@ Obj_SpawnItemDebrisEffects { const fixed_t min_speed = 80 * collectible->scale; - const fixed_t speed = - Obj_GetItemDebrisSpeed(collector, min_speed); + fixed_t base_speed = FixedMul(75 * mapobjectscale, + get_speed_ratio(collector)); - struct debris_config config = { - .origin = collectible, - .angle = K_MomentumAngle(collector), - .speed = speed, - .scale = FixedDiv(speed, min_speed), - }; + struct debris_config config; + + // Delayed effect for puffs of smoke that stick to and + // glide off of the player + mobj_t *spawner = P_SpawnMobjFromMobj(collectible, + 0, 0, 0, MT_ITEM_DEBRIS_CLOUD_SPAWNER); + + P_SetTarget(&spawner->target, collector); + + config.origin = collectible; + config.angle = K_MomentumAngle(collector); + config.speed = max(base_speed, min_speed); + config.scale = FixedDiv(config.speed, min_speed); config.type = DEBRIS_ALPHA; @@ -142,7 +175,10 @@ Obj_SpawnItemDebrisEffects spawn_debris(&config, -(3*ANGLE_22h/4)); spawn_debris(&config, -(3*ANGLE_22h/2)); - spawn_cloud(collectible, collector); + spawn_cloud(collectible, collector, base_speed); + + S_StartSound(collectible, sfx_kc2e); + S_StartSound(collectible, sfx_s1c9); } void diff --git a/src/p_enemy.c b/src/p_enemy.c index 901c2a2b2..1a0c31c4b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -14486,59 +14486,55 @@ void A_InvincSparkleRotate(mobj_t *actor) // Function: A_SpawnItemDebrisCloud // -// Description: Spawns a particle effect relative to the location of the actor +// Description: Spawns the poofs of an exploded item box. Target is a player to spawn the particles around. // -// var1 = If 1, scale size and momentum by extravalue2 / frame. -// var2 = Number of particles to spawn. +// var1 = Copy extravalue2 / var1 fraction of target's momentum. +// var2 = unused // void A_SpawnItemDebrisCloud (mobj_t *actor) { INT32 locvar1 = var1; - INT32 locvar2 = var2; - - const fixed_t min_speed = 90 * actor->scale; - const INT16 spacing = (actor->radius / 2) / actor->scale; - - fixed_t fade = FRACUNIT; - fixed_t scale_fade = FRACUNIT; mobj_t *target = actor->target; + player_t *player; - fixed_t speed; - fixed_t scale; + fixed_t kartspeed; + fixed_t fade; - INT32 i; - - if (target == NULL) + if (target == NULL || target->player == NULL) { return; } - if (locvar1) + player = target->player; + kartspeed = K_GetKartSpeed(player, false, false); + + // Scale around >50% top speed + fade = FixedMul(locvar1, (FixedDiv(player->speed, + kartspeed) - FRACUNIT/2) * 2); + + if (fade < 1) { - const UINT8 frame = (actor->frame & FF_FRAMEMASK); - fixed_t frac; - - if (frame == 0) - { - return; // div by zero - } - - // extravalue2 from A_Repeat - frac = fade / frame; - fade = actor->extravalue2 * frac; - scale_fade = fade + frac; + fade = 1; } - speed = Obj_GetItemDebrisSpeed(target, min_speed); - scale = 2 * FixedMul(FixedDiv(speed, min_speed), scale_fade); + if (actor->extravalue2 > fade) + { + actor->extravalue2 = fade; + } + + // MT_ITEM_DEBRIS_CLOUD_SPAWNER + // extravalue2 from A_Repeat + fade = actor->extravalue2 * FRACUNIT / locvar1; // Most of this code is from p_inter.c, MT_ITEMCAPSULE // dust effects - for (i = 0; i < locvar2; i++) { + const INT16 spacing = + (target->radius / 2) / target->scale; + mobj_t *puff = P_SpawnMobjFromMobj( target, P_RandomRange(-spacing, spacing) * FRACUNIT, @@ -14550,12 +14546,15 @@ A_SpawnItemDebrisCloud (mobj_t *actor) puff->color = target->color; puff->colorized = true; - puff->destscale = FixedMul(puff->destscale, scale); - P_SetScale(puff, puff->destscale); - puff->momz = puff->scale * P_MobjFlip(puff); - P_Thrust(puff, R_PointToAngle2(target->x, target->y, puff->x, puff->y), 3 * puff->scale); + P_InitAngle(puff, R_PointToAngle2( + target->x, + target->y, + puff->x, + puff->y)); + + P_Thrust(puff, puff->angle, 3 * puff->scale); puff->momx += FixedMul(target->momx, fade); puff->momy += FixedMul(target->momy, fade); From 7d87f2e1a2fbe467a52fe0d2b90092560857d68b Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 05:42:11 -0700 Subject: [PATCH 21/49] Fix item debris animation WHAT WERE THEY COOKING --- src/info.c | 2 +- src/objects/item-debris.c | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/info.c b/src/info.c index 84edb3900..861120d23 100644 --- a/src/info.c +++ b/src/info.c @@ -3870,7 +3870,7 @@ state_t states[NUMSTATES] = {SPR_RPOP, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_RANDOMITEMPOP4}, // S_RANDOMITEMPOP3 {SPR_RPOP, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL}, // S_RANDOMITEMPOP4 - {SPR_ITRI, FF_FULLBRIGHT, -1, {NULL}, 19, 1, S_NULL}, // S_ITEM_DEBRIS + {SPR_ITRI, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 19, 1, S_NULL}, // S_ITEM_DEBRIS {SPR_NULL, 0, 0, {A_Repeat}, 16, S_ITEM_DEBRIS_CLOUD_SPAWNER2, S_NULL}, // S_ITEM_DEBRIS_CLOUD_SPAWNER1 {SPR_NULL, 0, 7, {A_SpawnItemDebrisCloud}, 20, 0, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER2 diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c index 841650527..941cdc24c 100644 --- a/src/objects/item-debris.c +++ b/src/objects/item-debris.c @@ -52,15 +52,9 @@ spawn_debris mobj_t *debris = P_SpawnMobjFromMobj( config->origin, 0, 0, 0, MT_ITEM_DEBRIS); - const state_t *st = debris->state; - debris_type(debris) = config->type; debris_bouncesleft(debris) = 1; - // Start at a random frame of animation - debris->frame = (debris->frame & ~(FF_FRAMEMASK)) | - P_RandomRange((st->frame & FF_FRAMEMASK), st->var1); - P_InstaThrust(debris, config->angle + angle, config->speed); From 81eb513ef14a5e5b56b6836e9cdd64a371827a1d Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 06:08:00 -0700 Subject: [PATCH 22/49] Fix item pop sfx not playing for eggman boxes and playing TWICE for everything else The former is my bruh and the latter is probably not my brew. --- src/objects/item-debris.c | 4 ++-- src/p_inter.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c index 941cdc24c..a5ddd5842 100644 --- a/src/objects/item-debris.c +++ b/src/objects/item-debris.c @@ -171,8 +171,8 @@ Obj_SpawnItemDebrisEffects spawn_cloud(collectible, collector, base_speed); - S_StartSound(collectible, sfx_kc2e); - S_StartSound(collectible, sfx_s1c9); + S_StartSound(spawner, sfx_kc2e); + S_StartSound(spawner, sfx_s1c9); } void diff --git a/src/p_inter.c b/src/p_inter.c index 438909980..7898d0b8e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -275,7 +275,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->momx = special->momy = special->momz = 0; P_SetTarget(&special->target, toucher); P_KillMobj(special, toucher, toucher, DMG_NORMAL); - break; + return; case MT_SPHEREBOX: if (!P_CanPickupItem(player, 0)) return; @@ -283,7 +283,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->momx = special->momy = special->momz = 0; P_SetTarget(&special->target, toucher); P_KillMobj(special, toucher, toucher, DMG_NORMAL); - break; + return; case MT_ITEMCAPSULE: if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0) return; From f987d1b601b5f6e225c8d6f1190426e16f6c8e7c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 20 Sep 2022 10:33:24 -0400 Subject: [PATCH 23/49] Add smooth landing vfx --- src/d_player.h | 2 + src/deh_tables.c | 4 ++ src/info.c | 30 ++++++++++ src/info.h | 5 ++ src/k_bot.c | 2 +- src/k_kart.c | 140 +++++++++++++++++++++++++++++++++++++++++++++-- src/k_kart.h | 4 +- src/p_mobj.c | 14 ++--- src/p_saveg.c | 17 ++++++ 9 files changed, 202 insertions(+), 16 deletions(-) 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 7bb649d2b..9b8774f4c 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3832,6 +3832,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", @@ -5376,6 +5378,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 e80098499..110c1e906 100644 --- a/src/info.c +++ b/src/info.c @@ -587,6 +587,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 @@ -4392,6 +4393,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 @@ -24411,6 +24414,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 8305e1400..0d07f2775 100644 --- a/src/info.h +++ b/src/info.h @@ -1133,6 +1133,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 @@ -4826,6 +4827,8 @@ typedef enum state S_TRIPWIREBOOST_BLAST_TOP, S_TRIPWIREBOOST_BLAST_BOTTOM, + S_SMOOTHLANDING, + // DEZ Laser respawn S_DEZLASER, S_DEZLASER_TRAIL1, @@ -6407,6 +6410,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 f77cbe882..1b5a183b0 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -987,7 +987,7 @@ static angle_t K_BotSmoothLanding(player_t *player, angle_t destangle) { testDeltas[i] = AngleDelta(testAngles[i], destangle); } -' + if (testDeltas[1] < testDeltas[0]) { return testAngles[1]; diff --git a/src/k_kart.c b/src/k_kart.c index bad2c1da0..9d888cfbd 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3797,10 +3797,10 @@ void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) P_StartQuake(64<angle >> ANGLETOFINESHIFT); - fixed_t rollMul = FINECOSINE(mobj->angle >> ANGLETOFINESHIFT); + fixed_t pitchMul = -FINESINE(angle >> ANGLETOFINESHIFT); + fixed_t rollMul = FINECOSINE(angle >> ANGLETOFINESHIFT); angle_t slope = FixedMul(pitch, pitchMul) + FixedMul(roll, rollMul); @@ -3844,7 +3844,7 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool steepVal = STUMBLE_STEEP_VAL; } - oldSlope = K_StumbleSlope(player->mo, oldPitch, oldRoll); + oldSlope = K_StumbleSlope(player->mo->angle, oldPitch, oldRoll); if (oldSlope <= steepVal) { @@ -3853,7 +3853,7 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool return false; } - newSlope = K_StumbleSlope(player->mo, player->mo->pitch, player->mo->roll); + newSlope = K_StumbleSlope(player->mo->angle, player->mo->pitch, player->mo->roll); slopeDelta = AngleDelta(oldSlope, newSlope); if (slopeDelta <= steepVal) @@ -3896,6 +3896,134 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool 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) +{ + 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; + 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+1)) + (FRACUNIT/2)) / FRACUNIT; + + if (trans < 0) + { + trans = 0; + } + + if (trans > NUMTRANSMAPS) + { + trans = NUMTRANSMAPS; + } + + // invert + trans = NUMTRANSMAPS - trans; + + if (trans >= NUMTRANSMAPS) + { + mobj->renderflags |= RF_DONTDRAW; + } + else + { + mobj->renderflags &= ~(RF_TRANSMASK|RF_DONTDRAW); + + if (trans != 0) + { + mobj->renderflags |= (trans << RF_TRANSSHIFT); + } + } +} + static boolean K_LastTumbleBounceCondition(player_t *player) { return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 60); @@ -7999,6 +8127,8 @@ void K_KartPlayerAfterThink(player_t *player) { K_KartResetPlayerColor(player); + K_UpdateStumbleIndicator(player); + // Move held objects (Bananas, Orbinaut, etc) K_MoveHeldObjects(player); diff --git a/src/k_kart.h b/src/k_kart.h index 9d91ef240..b44258a9a 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -78,8 +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(mobj_t *mobj, angle_t pitch, angle_t roll); +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); diff --git a/src/p_mobj.c b/src/p_mobj.c index c71238928..3f0521b12 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2847,20 +2847,14 @@ void P_PlayerZMovement(mobj_t *mo) P_CheckGravity(mo, true); } - // Even out pitch & roll slowly over time when falling. - // Helps give OpenGL models a bit of the tumble tell. - if (P_MobjFlip(mo) * mo->momz <= 0) + // 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 = ANG60 - ANG10; + angle_t dest = 0; INT32 pitchDelta = AngleDeltaSigned(mo->pitch, 0); INT32 rollDelta = AngleDeltaSigned(mo->roll, 0); - if (mo->player->respawn.state != RESPAWNST_NONE) - { - dest = 0; - } - if (abs(pitchDelta) <= speed && dest == 0) { mo->pitch = 0; @@ -11389,6 +11383,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); + } } } } From 12475dc4340f86fa997da1b102feb012cdb74902 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 20 Sep 2022 10:35:13 -0400 Subject: [PATCH 24/49] Make smoothland client-sided --- src/k_kart.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 9d888cfbd..8b0f472a9 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4009,13 +4009,11 @@ void K_UpdateStumbleIndicator(player_t *player) // invert trans = NUMTRANSMAPS - trans; - if (trans >= NUMTRANSMAPS) + mobj->renderflags |= RF_DONTDRAW; + + if (trans < NUMTRANSMAPS) { - mobj->renderflags |= RF_DONTDRAW; - } - else - { - mobj->renderflags &= ~(RF_TRANSMASK|RF_DONTDRAW); + mobj->renderflags &= ~(RF_TRANSMASK | K_GetPlayerDontDrawFlag(player)); if (trans != 0) { From 7a56e5ade6bff53f2e0a2e7248c7089473c8c4ab Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 06:34:02 -0700 Subject: [PATCH 25/49] Move choose and chooseweighted commands to command.c Fixes disabled under dedicated and it's the appropriate place for these. Effectively cherry pick of 35b82b6dd9 --- src/command.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/console.c | 78 ------------------------------------------------- 2 files changed, 80 insertions(+), 78 deletions(-) diff --git a/src/command.c b/src/command.c index 1439463c1..0145687be 100644 --- a/src/command.c +++ b/src/command.c @@ -36,6 +36,7 @@ #include "d_netfil.h" // findfile #include "r_data.h" // Color_cons_t #include "r_skins.h" +#include "m_random.h" //======== // protos. @@ -53,6 +54,8 @@ static void COM_Wait_f(void); static void COM_Help_f(void); static void COM_Toggle_f(void); static void COM_Add_f(void); +static void COM_Choose_f(void); +static void COM_ChooseWeighted_f(void); static void CV_EnforceExecVersion(void); static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr); @@ -361,6 +364,8 @@ void COM_Init(void) COM_AddCommand("help", COM_Help_f); COM_AddCommand("toggle", COM_Toggle_f); COM_AddCommand("add", COM_Add_f); + COM_AddCommand("choose", COM_Choose_f); + COM_AddCommand("chooseweighted", COM_ChooseWeighted_f); RegisterNetXCmd(XD_NETVAR, Got_NetVar); } @@ -1075,6 +1080,81 @@ static void COM_Add_f(void) CV_AddValue(cvar, atoi(COM_Argv(2))); } +static void COM_Choose_f(void) +{ + size_t na = COM_Argc(); + + if (na < 2) + { + CONS_Printf(M_GetText("choose [] [] [...]: Picks a command at random\n")); + return; + } + + COM_BufAddText(COM_Argv(M_RandomKey(na - 1) + 1)); + COM_BufAddText("\n"); +} + +static void COM_ChooseWeighted_f(void) +{ + size_t na = COM_Argc(); + size_t i, cmd; + const char *commands[40]; + INT32 weights[40]; + INT32 totalWeight = 0; + INT32 roll; + + if (na < 3) + { + CONS_Printf(M_GetText("chooseweighted [ ] [ ] [...]: Picks a command with weighted randomization\n")); + return; + } + + memset(weights, 0, sizeof(weights)); + + i = 1; + cmd = 0; + while (i < na) + { + commands[cmd] = COM_Argv(i); + + i++; + if (i >= na) + { + break; + } + + weights[cmd] = atoi(COM_Argv(i)); + totalWeight += weights[cmd]; + + i++; + cmd++; + } + + if (cmd == 0 || totalWeight <= 0) + { + return; + } + + roll = M_RandomRange(1, totalWeight); + + for (i = 0; i < cmd; i++) + { + if (roll <= weights[i]) + { + if (commands[i] == NULL) + { + break; + } + + COM_BufAddText(commands[i]); + COM_BufAddText("\n"); + break; + } + + roll -= weights[i]; + } +} + // ========================================================================= // VARIABLE SIZE BUFFERS // ========================================================================= diff --git a/src/console.c b/src/console.c index 80174692e..7cbcb85a9 100644 --- a/src/console.c +++ b/src/console.c @@ -34,7 +34,6 @@ #include "k_menu.h" #include "filesrch.h" #include "m_misc.h" -#include "m_random.h" #ifdef _WINDOWS #include "win32/win_main.h" @@ -244,81 +243,6 @@ static void CONS_Bind_f(void) bindtable[key] = Z_StrDup(COM_Argv(2)); } -static void CONS_Choose_f(void) -{ - size_t na = COM_Argc(); - - if (na < 2) - { - CONS_Printf(M_GetText("choose [] [] [...]: Picks a command at random\n")); - return; - } - - COM_BufAddText(COM_Argv(M_RandomKey(na - 1) + 1)); - COM_BufAddText("\n"); -} - -static void CONS_ChooseWeighted_f(void) -{ - size_t na = COM_Argc(); - size_t i, cmd; - const char *commands[40]; - INT32 weights[40]; - INT32 totalWeight = 0; - INT32 roll; - - if (na < 3) - { - CONS_Printf(M_GetText("chooseweighted [ ] [ ] [...]: Picks a command with weighted randomization\n")); - return; - } - - memset(weights, 0, sizeof(weights)); - - i = 1; - cmd = 0; - while (i < na) - { - commands[cmd] = COM_Argv(i); - - i++; - if (i >= na) - { - break; - } - - weights[cmd] = atoi(COM_Argv(i)); - totalWeight += weights[cmd]; - - i++; - cmd++; - } - - if (cmd == 0 || totalWeight <= 0) - { - return; - } - - roll = M_RandomRange(1, totalWeight); - - for (i = 0; i < cmd; i++) - { - if (roll <= weights[i]) - { - if (commands[i] == NULL) - { - break; - } - - COM_BufAddText(commands[i]); - COM_BufAddText("\n"); - break; - } - - roll -= weights[i]; - } -} - //====================================================================== // CONSOLE SETUP //====================================================================== @@ -521,8 +445,6 @@ void CON_Init(void) CV_RegisterVar(&cons_backpic); CV_RegisterVar(&cons_backcolor); COM_AddCommand("bind", CONS_Bind_f); - COM_AddCommand("choose", CONS_Choose_f); - COM_AddCommand("chooseweighted", CONS_ChooseWeighted_f); } else { From e7b0e223e1862ad10edd0300c9f45ac4c98039e3 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 10:36:32 -0700 Subject: [PATCH 26/49] Fix respawning item boxes with P_RespawnBattlesBoxes --- src/info.c | 2 +- src/p_enemy.c | 6 ++++++ src/p_inter.c | 39 +++++++++++++++++++++++---------------- src/p_mobj.c | 24 +++++------------------- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/info.c b/src/info.c index 861120d23..c1136d43d 100644 --- a/src/info.c +++ b/src/info.c @@ -22550,7 +22550,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MT_RANDOMITEMPOP, // damage sfx_None, // activesound MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags - S_NULL // raisestate + S_RANDOMITEM1 // raisestate }, { // MT_SPHEREBOX diff --git a/src/p_enemy.c b/src/p_enemy.c index 1a0c31c4b..527dcf0b6 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -13199,7 +13199,13 @@ void A_ItemPop(mobj_t *actor) // Here at mapload in battle? if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP)) + { numgotboxes++; + + // do not flicker back in just yet, handled by + // P_RespawnBattleBoxes eventually + P_SetMobjState(actor, S_INVISIBLE); + } } void A_JawzChase(mobj_t *actor) diff --git a/src/p_inter.c b/src/p_inter.c index 7898d0b8e..1edf9fcb2 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1037,27 +1037,34 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { if (target->flags & MF_MONITOR || target->type == MT_RANDOMITEM) { - UINT8 i; - P_SetTarget(&target->target, source); - for (i = 0; i < MAXPLAYERS; i++) + if (gametyperules & GTR_BUMPERS) { - if (&players[i] == source->player) - { - continue; - } - - if (playeringame[i] && !players[i].spectator && players[i].lives != 0) - { - break; - } + target->fuse = 2; } - - if (i < MAXPLAYERS) + else { - // Respawn items in multiplayer, don't respawn them when alone - target->fuse = 2*TICRATE + 2; + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (&players[i] == source->player) + { + continue; + } + + if (playeringame[i] && !players[i].spectator && players[i].lives != 0) + { + break; + } + } + + if (i < MAXPLAYERS) + { + // Respawn items in multiplayer, don't respawn them when alone + target->fuse = 2*TICRATE + 2; + } } } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 1c34a1b1e..1d08d63e9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9229,7 +9229,7 @@ static boolean P_FuseThink(mobj_t *mobj) { ; } - else if ((gametyperules & GTR_BUMPERS) && (mobj->threshold != 70)) + else if ((gametyperules & GTR_BUMPERS) && (mobj->state == &states[S_INVISIBLE])) { break; } @@ -11072,7 +11072,6 @@ void P_RespawnBattleBoxes(void) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { mobj_t *box; - mobj_t *newmobj; if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; @@ -11081,25 +11080,12 @@ void P_RespawnBattleBoxes(void) if (box->type != MT_RANDOMITEM || (box->flags2 & MF2_DONTRESPAWN) - || box->threshold != 68 - || box->fuse - || ((tic_t)box->cvmem+1 >= leveltime)) + || box->health > 0 + || box->fuse) continue; // only popped items - // Respawn from mapthing if you have one! - if (box->spawnpoint) - { - P_SpawnMapThing(box->spawnpoint); - newmobj = box->spawnpoint->mobj; // this is set to the new mobj in P_SpawnMapThing - } - else - { - newmobj = P_SpawnMobj(box->x, box->y, box->z, box->type); - } - - // Transfer flags2 (strongbox, objectflip, bossnotrap) - newmobj->flags2 = box->flags2; - P_RemoveMobj(box); // make sure they disappear + box->fuse = TICRATE; // flicker back in (A_ItemPop preps this effect) + P_SetMobjState(box, box->info->raisestate); if (numgotboxes > 0) numgotboxes--; // you've restored a box, remove it from the count From ccff9a6ce2cefd967348a502dc1d8b6df98824a6 Mon Sep 17 00:00:00 2001 From: SteelT Date: Tue, 20 Sep 2022 15:04:37 -0400 Subject: [PATCH 27/49] Improve profile applying during startup This allow cases can route around the title screen, such as if the `-connect` command line param is used, to work properly --- src/d_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index d7092a901..d6dcfbcab 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1775,16 +1775,16 @@ void D_SRB2Main(void) } } + // Has to be done before anything else so skin, color, etc in command buffer has an affect. + // ttlprofilen used because it's roughly equivalent in functionality - a QoL aid for quickly getting from startup to action + PR_ApplyProfile(cv_ttlprofilen.value, 0); + if (autostart || netgame) { gameaction = ga_nothing; CV_ClearChangedFlags(); - // Has to be done before anything else so skin, color, etc in command buffer has an affect. - // ttlprofilen used because it's roughly equivalent in functionality - a QoL aid for quickly getting from startup to action - PR_ApplyProfile(cv_ttlprofilen.value, 0); - // Do this here so if you run SRB2 with eg +timelimit 5, the time limit counts // as having been modified for the first game. M_PushSpecialParameters(); // push all "+" parameter at the command buffer @@ -1887,9 +1887,13 @@ void D_SRB2Main(void) else if (M_CheckParm("-skipintro")) { F_StartTitleScreen(); + CV_StealthSetValue(&cv_currprofile, -1); } else + { F_StartIntro(); // Tails 03-03-2002 + CV_StealthSetValue(&cv_currprofile, -1); + } CON_ToggleOff(); From e242207d10c5edf7d12e7364eab0b2998861ebdd Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 19:01:54 -0700 Subject: [PATCH 28/49] Mindelay: Oni suggestions rollup --- src/d_clisrv.c | 10 +++++++--- src/hu_stuff.c | 37 +++++++++++++++++++++++++++++++++---- src/hu_stuff.h | 2 +- src/k_hud.c | 4 ++-- src/k_menudef.c | 6 ++++++ src/screen.c | 5 ++++- src/sdl/i_video.c | 2 ++ 7 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index aa4199fce..2f38f0aef 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -115,7 +115,7 @@ UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. static tic_t lowest_lag; boolean server_lagless; static CV_PossibleValue_t mindelay_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; -consvar_t cv_mindelay = CVAR_INIT ("mindelay", "0", 0, mindelay_cons_t, NULL); +consvar_t cv_mindelay = CVAR_INIT ("mindelay", "0", CV_SAVE, mindelay_cons_t, NULL); SINT8 nodetoplayer[MAXNETNODES]; SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) @@ -5650,7 +5650,7 @@ static inline void PingUpdate(void) if (nodeingame[i]) HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1)); - pingmeasurecount = 1; //Reset count + pingmeasurecount = 0; //Reset count } static tic_t gametime = 0; @@ -5667,7 +5667,7 @@ static void UpdatePingTable(void) if (netgame && !(gametime % 35)) // update once per second. PingUpdate(); - fastest = cv_mindelay.value; + fastest = 0; // update node latency values so we can take an average later. for (i = 0; i < MAXPLAYERS; i++) @@ -5690,6 +5690,10 @@ static void UpdatePingTable(void) } } + // Don't gentleman below your mindelay + if (fastest < (tic_t)cv_mindelay.value) + fastest = (tic_t)cv_mindelay.value; + pingmeasurecount++; if (server_lagless) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index fd57f4a36..2ffc80bc7 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -79,6 +79,7 @@ typedef enum patch_t *pinggfx[5]; // small ping graphic patch_t *mping[5]; // smaller ping graphic patch_t *pingmeasure[2]; // ping measurement graphic +patch_t *pinglocal[2]; // mindelay indecator patch_t *framecounter; patch_t *frameslash; // framerate stuff. Used in screen.c @@ -197,6 +198,9 @@ void HU_LoadGraphics(void) HU_UpdatePatch(&pingmeasure[0], "PINGD"); HU_UpdatePatch(&pingmeasure[1], "PINGMS"); + HU_UpdatePatch(&pinglocal[0], "PINGGFXL"); + HU_UpdatePatch(&pinglocal[1], "MPINGL"); + // fps stuff HU_UpdatePatch(&framecounter, "FRAMER"); HU_UpdatePatch(&frameslash, "FRAMESL"); @@ -2346,25 +2350,47 @@ Ping_gfx_num (int lag) return 4; } +static int +Ping_gfx_color (int lag) +{ + if (lag < 2) + return SKINCOLOR_JAWZ; + else if (lag < 4) + return SKINCOLOR_MINT; + else if (lag < 7) + return SKINCOLOR_GOLD; + else if (lag < 10) + return SKINCOLOR_RASPBERRY; + else + return SKINCOLOR_MAGENTA; +} + // // HU_drawPing // -void HU_drawPing(INT32 x, INT32 y, UINT32 lag, INT32 flags) +void HU_drawPing(INT32 x, INT32 y, UINT32 lag, INT32 flags, boolean offline) { UINT8 *colormap = NULL; INT32 measureid = cv_pingmeasurement.value ? 1 : 0; INT32 gfxnum; // gfx to draw + boolean drawlocal = (offline && cv_mindelay.value && lag <= (tic_t)cv_mindelay.value); gfxnum = Ping_gfx_num(lag); if (measureid == 1) V_DrawScaledPatch(x+11 - pingmeasure[measureid]->width, y+9, flags, pingmeasure[measureid]); - V_DrawScaledPatch(x+2, y, flags, pinggfx[gfxnum]); + + if (drawlocal) + V_DrawScaledPatch(x+2, y, flags, pinglocal[0]); + else + V_DrawScaledPatch(x+2, y, flags, pinggfx[gfxnum]); + + colormap = R_GetTranslationColormap(TC_RAINBOW, Ping_gfx_color(lag), GTC_CACHE); if (servermaxping && lag > servermaxping && hu_tick < 4) { // flash ping red if too high - colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE); + colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_WHITE, GTC_CACHE); } if (cv_pingmeasurement.value) @@ -2389,7 +2415,10 @@ HU_drawMiniPing (INT32 x, INT32 y, UINT32 lag, INT32 flags) w /= 2; } - patch = mping[Ping_gfx_num(lag)]; + if (cv_mindelay.value && (tic_t)cv_mindelay.value <= lag) + patch = pinglocal[1]; + else + patch = mping[Ping_gfx_num(lag)]; if (( flags & V_SNAPTORIGHT )) x += ( w - SHORT (patch->width) ); diff --git a/src/hu_stuff.h b/src/hu_stuff.h index cc9959467..9bcf45e09 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -138,7 +138,7 @@ void HU_Drawer(void); char HU_dequeueChatChar(void); void HU_Erase(void); void HU_clearChatChars(void); -void HU_drawPing(INT32 x, INT32 y, UINT32 ping, INT32 flags); // Lat': Ping drawer for scoreboard. +void HU_drawPing(INT32 x, INT32 y, UINT32 ping, INT32 flags, boolean offline); // Lat': Ping drawer for scoreboard. void HU_drawMiniPing(INT32 x, INT32 y, UINT32 ping, INT32 flags); INT32 HU_CreateTeamScoresTbl(playersort_t *tab, UINT32 dmtotals[]); diff --git a/src/k_hud.c b/src/k_hud.c index 96635584e..2496e5393 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2177,7 +2177,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN } else if (tab[i].num != serverplayer || !server_lagless) { - HU_drawPing(x + ((i < 8) ? -17 : rightoffset + 11), y-4, playerpingtable[tab[i].num], 0); + HU_drawPing(x + ((i < 8) ? -17 : rightoffset + 11), y-4, playerpingtable[tab[i].num], 0, false); } } @@ -4878,7 +4878,7 @@ void K_drawKartHUD(void) V_DrawCenteredString(BASEVIDWIDTH>>1, 176, V_REDMAP|V_SNAPTOBOTTOM, "WRONG WAY"); } - if (netgame && r_splitscreen) + if ((netgame || cv_mindelay.value) && r_splitscreen) { K_drawMiniPing(); } diff --git a/src/k_menudef.c b/src/k_menudef.c index d97083509..fe243c38c 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -1035,6 +1035,12 @@ menuitem_t OPTIONS_Gameplay[] = {IT_STRING | IT_CVAR, "Karma Comeback", "Enable Karma Comeback in Battle mode.", NULL, {.cvar = &cv_kartcomeback}, 0, 0}, + {IT_SPACE | IT_NOTHING, NULL, NULL, + NULL, {NULL}, 0, 0}, + + {IT_STRING | IT_CVAR, "Offline Input Delay", "Practice for online play in offline modes. Higher = more delay.", + NULL, {.cvar = &cv_mindelay}, 0, 0}, + {IT_SPACE | IT_NOTHING, NULL, NULL, NULL, {NULL}, 0, 0}, diff --git a/src/screen.c b/src/screen.c index 5d6b59ee8..f1b53a7f2 100644 --- a/src/screen.c +++ b/src/screen.c @@ -628,11 +628,14 @@ void SCR_DisplayTicRate(void) void SCR_DisplayLocalPing(void) { + boolean offline; + UINT32 ping = playerpingtable[consoleplayer]; // consoleplayer's ping is everyone's ping in a splitnetgame :P if (! r_splitscreen && ( cv_showping.value == 1 || (cv_showping.value == 2 && ping > servermaxping) )) // only show 2 (warning) if our ping is at a bad level { INT32 dispy = cv_ticrate.value ? 160 : 181; - HU_drawPing(307, dispy, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS); + offline = (consoleplayer == serverplayer); + HU_drawPing(307, dispy, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS, offline); } } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 2361a5349..09b2f6bbf 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1219,6 +1219,8 @@ void I_FinishUpdate(void) } } } + if (cv_mindelay.value && consoleplayer == serverplayer) + SCR_DisplayLocalPing(); } if (marathonmode) From 87b92a7127137bc78739c492543f4646d305900f Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 20:05:00 -0700 Subject: [PATCH 29/49] Bump ping tiers by 1 tic --- src/hu_stuff.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 2ffc80bc7..2fe1fb883 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2338,13 +2338,13 @@ void HU_Erase(void) static int Ping_gfx_num (int lag) { - if (lag < 2) + if (lag <= 2) return 0; - else if (lag < 4) + else if (lag <= 4) return 1; - else if (lag < 7) + else if (lag <= 7) return 2; - else if (lag < 10) + else if (lag <= 10) return 3; else return 4; @@ -2353,13 +2353,13 @@ Ping_gfx_num (int lag) static int Ping_gfx_color (int lag) { - if (lag < 2) + if (lag <= 2) return SKINCOLOR_JAWZ; - else if (lag < 4) + else if (lag <= 4) return SKINCOLOR_MINT; - else if (lag < 7) + else if (lag <= 7) return SKINCOLOR_GOLD; - else if (lag < 10) + else if (lag <= 10) return SKINCOLOR_RASPBERRY; else return SKINCOLOR_MAGENTA; From e1f72898f5543d2f0e66ff72baebafeddb8773d1 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 20:15:02 -0700 Subject: [PATCH 30/49] Mindelay: Update ping display even in local play --- src/d_clisrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 2f38f0aef..69eebe595 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5664,7 +5664,7 @@ static void UpdatePingTable(void) if (server) { - if (netgame && !(gametime % 35)) // update once per second. + if (!(gametime % 35)) // update once per second. PingUpdate(); fastest = 0; From ada40b421c1757025ff1a9369932813245a52b4c Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 20:29:34 -0700 Subject: [PATCH 31/49] Mindelay: Never draw ping outside of games --- src/k_hud.c | 2 +- src/sdl/i_video.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 2496e5393..fd4493a93 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4878,7 +4878,7 @@ void K_drawKartHUD(void) V_DrawCenteredString(BASEVIDWIDTH>>1, 176, V_REDMAP|V_SNAPTOBOTTOM, "WRONG WAY"); } - if ((netgame || cv_mindelay.value) && r_splitscreen) + if ((netgame || cv_mindelay.value) && r_splitscreen && Playing()) { K_drawMiniPing(); } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 09b2f6bbf..a1948f2f1 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1219,7 +1219,7 @@ void I_FinishUpdate(void) } } } - if (cv_mindelay.value && consoleplayer == serverplayer) + if (cv_mindelay.value && consoleplayer == serverplayer && Playing()) SCR_DisplayLocalPing(); } From bd83a9f3b198082b1aecfb2d02c41cbafb6ef447 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 20:33:30 -0700 Subject: [PATCH 32/49] Mindelay: Probably don't calculate ping outside of games period --- src/d_clisrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 69eebe595..1c3708b12 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5664,7 +5664,7 @@ static void UpdatePingTable(void) if (server) { - if (!(gametime % 35)) // update once per second. + if (Playing() && !(gametime % 35)) // update once per second. PingUpdate(); fastest = 0; From 8525dfb50273e4265bd470948f8298e25b9da630 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 21:21:51 -0700 Subject: [PATCH 33/49] Allow netgame clients to display and be affected by mindelay --- src/d_clisrv.c | 5 +++++ src/hu_stuff.c | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1c3708b12..f11215b60 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5725,6 +5725,11 @@ static void UpdatePingTable(void) } } } + else // We're a client, handle mindelay on the way out. + { + if ((neededtic - gametic) < (tic_t)cv_mindelay.value) + lowest_lag = cv_mindelay.value - (neededtic - gametic); + } } static void RenewHolePunch(void) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 2fe1fb883..bdcc158d4 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2375,6 +2375,12 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 lag, INT32 flags, boolean offline) INT32 gfxnum; // gfx to draw boolean drawlocal = (offline && cv_mindelay.value && lag <= (tic_t)cv_mindelay.value); + if (!server && lag <= (tic_t)cv_mindelay.value) + { + lag = cv_mindelay.value; + drawlocal = true; + } + gfxnum = Ping_gfx_num(lag); if (measureid == 1) @@ -2415,7 +2421,15 @@ HU_drawMiniPing (INT32 x, INT32 y, UINT32 lag, INT32 flags) w /= 2; } - if (cv_mindelay.value && (tic_t)cv_mindelay.value <= lag) + CONS_Printf("mindelay %d / lag %d\n", cv_mindelay.value, lag); + + // This looks kinda dumb, but basically: + // Servers with mindelay set modify the ping table. + // Clients with mindelay unset don't, because they can't. + // Both are affected by mindelay, but a client's lag value is pre-adjustment. + if (server && cv_mindelay.value && (tic_t)cv_mindelay.value <= lag) + patch = pinglocal[1]; + else if (!server && cv_mindelay.value && (tic_t)cv_mindelay.value >= lag) patch = pinglocal[1]; else patch = mping[Ping_gfx_num(lag)]; From aaf18fb1cf7f000526fa22f51999edecd370c30d Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 21:29:17 -0700 Subject: [PATCH 34/49] Offline Input Delay -> Minimum Input Delay, default 0 -> 2 --- src/d_clisrv.c | 2 +- src/k_menudef.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f11215b60..1e5787583 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -115,7 +115,7 @@ UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. static tic_t lowest_lag; boolean server_lagless; static CV_PossibleValue_t mindelay_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; -consvar_t cv_mindelay = CVAR_INIT ("mindelay", "0", CV_SAVE, mindelay_cons_t, NULL); +consvar_t cv_mindelay = CVAR_INIT ("mindelay", "2", CV_SAVE, mindelay_cons_t, NULL); SINT8 nodetoplayer[MAXNETNODES]; SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) diff --git a/src/k_menudef.c b/src/k_menudef.c index fe243c38c..97f77abd2 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -1038,7 +1038,7 @@ menuitem_t OPTIONS_Gameplay[] = {IT_SPACE | IT_NOTHING, NULL, NULL, NULL, {NULL}, 0, 0}, - {IT_STRING | IT_CVAR, "Offline Input Delay", "Practice for online play in offline modes. Higher = more delay.", + {IT_STRING | IT_CVAR, "Minimum Input Delay", "Practice for online play! Higher = more delay.", NULL, {.cvar = &cv_mindelay}, 0, 0}, {IT_SPACE | IT_NOTHING, NULL, NULL, From 51d46a2a8abd88a5a46ab6e6e5491abc5d90190f Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 20 Sep 2022 21:32:45 -0700 Subject: [PATCH 35/49] Remove debug print --- src/hu_stuff.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index bdcc158d4..1d7f23ac9 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2421,8 +2421,6 @@ HU_drawMiniPing (INT32 x, INT32 y, UINT32 lag, INT32 flags) w /= 2; } - CONS_Printf("mindelay %d / lag %d\n", cv_mindelay.value, lag); - // This looks kinda dumb, but basically: // Servers with mindelay set modify the ping table. // Clients with mindelay unset don't, because they can't. From 3f66a8e72f351f1008189cc450257c734cc41a23 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 01:38:21 -0400 Subject: [PATCH 36/49] Fix fast fall preventing stumble --- src/k_kart.c | 63 +++++++++++++++++++++++++++++++--------------------- src/k_kart.h | 1 + src/p_user.c | 13 +++++++++-- 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 8b0f472a9..00c99c8e1 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3865,6 +3865,8 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool // Oh jeez, you landed on your side. // You get to tumble. + P_ResetPlayer(player); + #if 0 // Single, medium bounce player->tumbleBounces = TUMBLEBOUNCES; @@ -9568,31 +9570,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; } @@ -9659,6 +9637,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 b44258a9a..46f97a3f5 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -149,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_user.c b/src/p_user.c index e7cc525cc..f733bad28 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1354,15 +1354,24 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, an K_SpawnSplashForMobj(player->mo, abs(player->mo->momz)); } - if (player->mo->health) + 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)) + if (K_CheckStumble(player, oldPitch, oldRoll, air) == true) + { return false; + } + + if (air == false && K_FastFallBounce(player) == true) + { + return false; + } } } From 1530c15db74ba11395e5feb4c564fed58e9f935c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 02:01:38 -0400 Subject: [PATCH 37/49] Fix visual not matching exact steep range --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 00c99c8e1..513fe6c7f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3996,7 +3996,7 @@ void K_UpdateStumbleIndicator(player_t *player) steepRange = ANGLE_90 - steepVal; delta = max(0, abs(delta) - ((signed)steepVal)); - trans = ((FixedDiv(AngleFixed(delta), AngleFixed(steepRange)) * (NUMTRANSMAPS+1)) + (FRACUNIT/2)) / FRACUNIT; + trans = ((FixedDiv(AngleFixed(delta), AngleFixed(steepRange)) * NUMTRANSMAPS) + (FRACUNIT/2)) / FRACUNIT; if (trans < 0) { From e347fadf0219c17c963f752c4d1470a21d5a8db9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 07:49:33 -0400 Subject: [PATCH 38/49] Add a fudge constant to the stumble indicator --- src/k_kart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 513fe6c7f..39366c64d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3925,6 +3925,7 @@ void K_InitStumbleIndicator(player_t *player) void K_UpdateStumbleIndicator(player_t *player) { + const angle_t fudge = ANG10; mobj_t *mobj = NULL; boolean air = false; @@ -3956,7 +3957,7 @@ void K_UpdateStumbleIndicator(player_t *player) 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; + steepVal = (air ? STUMBLE_STEEP_VAL_AIR : STUMBLE_STEEP_VAL) - fudge; slopeSteep = max(AngleDelta(player->mo->pitch, 0), AngleDelta(player->mo->roll, 0)); delta = 0; From 329aecd5e52c8e5da1dc8d0d70cafc9216b80cc0 Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Wed, 21 Sep 2022 10:12:10 -0400 Subject: [PATCH 39/49] Made the circle solid for longer Edited NUMTRANSMAPS to make it solid for 2 maps longer, adjusted fudge ANG to 15 from 10 (more visually lenient) --- src/k_kart.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 39366c64d..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" @@ -3925,7 +3926,7 @@ void K_InitStumbleIndicator(player_t *player) void K_UpdateStumbleIndicator(player_t *player) { - const angle_t fudge = ANG10; + const angle_t fudge = ANG15; mobj_t *mobj = NULL; boolean air = false; @@ -3997,24 +3998,24 @@ void K_UpdateStumbleIndicator(player_t *player) steepRange = ANGLE_90 - steepVal; delta = max(0, abs(delta) - ((signed)steepVal)); - trans = ((FixedDiv(AngleFixed(delta), AngleFixed(steepRange)) * NUMTRANSMAPS) + (FRACUNIT/2)) / FRACUNIT; + trans = ((FixedDiv(AngleFixed(delta), AngleFixed(steepRange)) * (NUMTRANSMAPS - 2)) + (FRACUNIT/2)) / FRACUNIT; if (trans < 0) { trans = 0; } - if (trans > NUMTRANSMAPS) + if (trans > (NUMTRANSMAPS - 2)) { - trans = NUMTRANSMAPS; + trans = (NUMTRANSMAPS - 2); } // invert - trans = NUMTRANSMAPS - trans; + trans = (NUMTRANSMAPS - 2) - trans; mobj->renderflags |= RF_DONTDRAW; - if (trans < NUMTRANSMAPS) + if (trans < (NUMTRANSMAPS - 2)) { mobj->renderflags &= ~(RF_TRANSMASK | K_GetPlayerDontDrawFlag(player)); From 44a742b1aa69e6f7c05768ca08a7cc0212bc41d4 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 11:51:43 -0400 Subject: [PATCH 40/49] r_things.c -> r_things.h --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 2b1eb3aa1..99f74b751 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -19,7 +19,7 @@ #include "p_setup.h" #include "r_draw.h" #include "r_local.h" -#include "r_things.c" +#include "r_things.h" #include "s_sound.h" #include "st_stuff.h" #include "v_video.h" From 499c61a9f2d0f73c8b34a4dd8878c30bb151ede3 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 21 Sep 2022 01:19:13 -0700 Subject: [PATCH 41/49] Kill SPRITE/SPRITEINFO, SPRITE2INFO SOC headers Kill it because maintaining three parsers for the same data is insane. --- src/deh_soc.c | 236 ------------------------------------------------- src/deh_soc.h | 1 - src/dehacked.c | 24 ----- 3 files changed, 261 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index dd0fbf5eb..c1197c3cb 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -640,242 +640,6 @@ void readlight(MYFILE *f, INT32 num) } #endif // HWRENDER -static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word, *word2; - char *tmp; - INT32 value; - char *lastline; - - do - { - lastline = f->curpos; - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Set / reset word - word = s; - while ((*word == '\t') || (*word == ' ')) - word++; - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - { - *(tmp-1) = '\0'; - // Now get the part after - word2 = tmp += 2; - } - else - { - // Get the part before the " " - tmp = strchr(s, ' '); - if (tmp) - { - *tmp = '\0'; - // Now get the part after - tmp++; - word2 = tmp; - } - else - break; - } - strupr(word); - value = atoi(word2); // used for numerical settings - - if (fastcmp(word, "XPIVOT")) - sprinfo->pivot[frame].x = value; - else if (fastcmp(word, "YPIVOT")) - sprinfo->pivot[frame].y = value; - else if (fastcmp(word, "ROTAXIS")) - sprinfo->pivot[frame].rotaxis = value; - else - { - f->curpos = lastline; - break; - } - } - } while (!myfeof(f)); // finish when the line is empty - Z_Free(s); -} - -void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word, *word2; - char *tmp; -#ifdef HWRENDER - INT32 value; -#endif - char *lastline; - INT32 skinnumbers[MAXSKINS]; - INT32 foundskins = 0; - - // allocate a spriteinfo - spriteinfo_t *info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL); - info->available = true; - - do - { - lastline = f->curpos; - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Set / reset word - word = s; - while ((*word == '\t') || (*word == ' ')) - word++; - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - { - *(tmp-1) = '\0'; - // Now get the part after - word2 = tmp += 2; - } - else - { - // Get the part before the " " - tmp = strchr(s, ' '); - if (tmp) - { - *tmp = '\0'; - // Now get the part after - tmp++; - word2 = tmp; - } - else - break; - } - strupr(word); -#ifdef HWRENDER - value = atoi(word2); // used for numerical settings - - if (fastcmp(word, "LIGHTTYPE")) - { - if (sprite2) - deh_warning("Sprite2 %s: invalid word '%s'", spr2names[num], word); - else - { - INT32 oldvar; - for (oldvar = 0; t_lspr[num] != &lspr[oldvar]; oldvar++) - ; - t_lspr[num] = &lspr[value]; - } - } - else -#endif - if (fastcmp(word, "SKIN")) - { - INT32 skinnum = -1; - if (!sprite2) - { - deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word); - continue; - } - - // make lowercase - strlwr(word2); - skinnum = R_SkinAvailable(word2); - if (skinnum == -1) - { - deh_warning("Sprite2 %s: unknown skin %s", spr2names[num], word2); - break; - } - - skinnumbers[foundskins] = skinnum; - foundskins++; - } - else if (fastcmp(word, "DEFAULT")) - { - if (!sprite2) - { - deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word); - continue; - } - if (num < (INT32)free_spr2 && num >= (INT32)SPR2_FIRSTFREESLOT) - spr2defaults[num] = get_number(word2); - else - { - deh_warning("Sprite2 %s: out of range (%d - %d), ignoring", spr2names[num], SPR2_FIRSTFREESLOT, free_spr2-1); - continue; - } - } - else if (fastcmp(word, "FRAME")) - { - UINT8 frame = R_Char2Frame(word2[0]); - // frame number too high - if (frame >= 64) - { - if (sprite2) - deh_warning("Sprite2 %s: invalid frame %s", spr2names[num], word2); - else - deh_warning("Sprite %s: invalid frame %s", sprnames[num], word2); - break; - } - - // read sprite frame and store it in the spriteinfo_t struct - readspriteframe(f, info, frame); - if (sprite2) - { - INT32 i; - if (!foundskins) - { - deh_warning("Sprite2 %s: no skins specified", spr2names[num]); - break; - } - for (i = 0; i < foundskins; i++) - { - size_t skinnum = skinnumbers[i]; - skin_t *skin = &skins[skinnum]; - spriteinfo_t *sprinfo = skin->sprinfo; - M_Memcpy(&sprinfo[num], info, sizeof(spriteinfo_t)); - } - } - else - M_Memcpy(&spriteinfo[num], info, sizeof(spriteinfo_t)); - } - else - { - //deh_warning("Sprite %s: unknown word '%s'", sprnames[num], word); - f->curpos = lastline; - break; - } - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); - Z_Free(info); -} - void readsprite2(MYFILE *f, INT32 num) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); diff --git a/src/deh_soc.h b/src/deh_soc.h index d19b67a1a..335260953 100644 --- a/src/deh_soc.h +++ b/src/deh_soc.h @@ -71,7 +71,6 @@ void readcutscene(MYFILE *f, INT32 num); void readlevelheader(MYFILE *f, INT32 num); void readgametype(MYFILE *f, char *gtname); void readsprite2(MYFILE *f, INT32 num); -void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2); #ifdef HWRENDER void readlight(MYFILE *f, INT32 num); #endif diff --git a/src/dehacked.c b/src/dehacked.c index d9a2084f1..4187a522b 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -356,30 +356,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) } } #endif - else if (fastcmp(word, "SPRITE") || fastcmp(word, "SPRITEINFO")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_sprite(word2); // find a sprite by name - if (i < NUMSPRITES && i > 0) - readspriteinfo(f, i, false); - else - { - deh_warning("Sprite number %d out of range (0 - %d)", i, NUMSPRITES-1); - ignorelines(f); - } - } - else if (fastcmp(word, "SPRITE2INFO")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_sprite2(word2); // find a sprite by name - if (i < NUMPLAYERSPRITES && i >= 0) - readspriteinfo(f, i, true); - else - { - deh_warning("Sprite2 number %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1); - ignorelines(f); - } - } else if (fastcmp(word, "LEVEL")) { // Support using the actual map name, From 58bc3294fabaa71ab777745acd707f5c8ca67777 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 21 Sep 2022 12:27:16 -0700 Subject: [PATCH 42/49] Refactor R_ParseSpriteInfo Splits up the function, thus makes me want to kill myself less. --- src/r_picformats.c | 145 +++++++++++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 58 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index de9bb4857..deb2bcfde 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1396,12 +1396,56 @@ boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *to #endif #endif -// -// R_ParseSpriteInfoFrame -// -// Parse a SPRTINFO frame. -// -static void R_ParseSpriteInfoFrame(spriteinfo_t *info) +struct ParseSpriteInfoState { + boolean spr2; + spriteinfo_t *info; + spritenum_t sprnum; + playersprite_t spr2num; + INT32 skinnumbers[MAXSKINS]; + INT32 foundskins; +}; + +static void R_ParseSpriteInfoSkin(struct ParseSpriteInfoState *parser) +{ + char *sprinfoToken; + size_t sprinfoTokenLength; + + INT32 skinnum; + char *skinName = NULL; + + // Skin name + sprinfoToken = M_GetToken(NULL); + if (sprinfoToken == NULL) + { + I_Error("Error parsing SPRTINFO lump: Unexpected end of file where skin frame should be"); + } + + // copy skin name yada yada + sprinfoTokenLength = strlen(sprinfoToken); + skinName = (char *)Z_Malloc((sprinfoTokenLength+1)*sizeof(char),PU_STATIC,NULL); + M_Memcpy(skinName,sprinfoToken,sprinfoTokenLength*sizeof(char)); + skinName[sprinfoTokenLength] = '\0'; + strlwr(skinName); + + skinnum = R_SkinAvailable(skinName); + if (skinnum == -1) + I_Error("Error parsing SPRTINFO lump: Unknown skin \"%s\"", skinName); + + parser->skinnumbers[parser->foundskins] = skinnum; + parser->foundskins++; + + Z_Free(sprinfoToken); +} + +static void copy_to_skin (struct ParseSpriteInfoState *parser, INT32 skinnum) +{ + skin_t *skin = &skins[skinnum]; + spriteinfo_t *sprinfo = skin->sprinfo; + + M_Memcpy(&sprinfo[parser->spr2num], parser->info, sizeof(spriteinfo_t)); +} + +static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser) { char *sprinfoToken; size_t sprinfoTokenLength; @@ -1480,9 +1524,26 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info) } // set fields - info->pivot[frameFrame].x = frameXPivot; - info->pivot[frameFrame].y = frameYPivot; - info->pivot[frameFrame].rotaxis = frameRotAxis; + parser->info->pivot[frameFrame].x = frameXPivot; + parser->info->pivot[frameFrame].y = frameYPivot; + parser->info->pivot[frameFrame].rotaxis = frameRotAxis; + + if (parser->spr2) + { + INT32 i; + + if (!parser->foundskins) + I_Error("Error parsing SPRTINFO lump: No skins specified in this sprite2 definition"); + + for (i = 0; i < parser->foundskins; i++) + { + copy_to_skin(parser, parser->skinnumbers[i]); + } + } + else + { + M_Memcpy(&spriteinfo[parser->sprnum], parser->info, sizeof(spriteinfo_t)); + } } // @@ -1492,15 +1553,18 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info) // static void R_ParseSpriteInfo(boolean spr2) { - spriteinfo_t *info; char *sprinfoToken; size_t sprinfoTokenLength; char newSpriteName[5]; // no longer dynamically allocated - spritenum_t sprnum = NUMSPRITES; - playersprite_t spr2num = NUMPLAYERSPRITES; + + struct ParseSpriteInfoState parser = { + .spr2 = spr2, + .sprnum = NUMSPRITES, + .spr2num = NUMPLAYERSPRITES, + .foundskins = 0, + }; + INT32 i; - INT32 skinnumbers[MAXSKINS]; - INT32 foundskins = 0; // Sprite name sprinfoToken = M_GetToken(NULL); @@ -1508,6 +1572,7 @@ static void R_ParseSpriteInfo(boolean spr2) { I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be"); } + sprinfoTokenLength = strlen(sprinfoToken); if (sprinfoTokenLength != 4) { @@ -1520,6 +1585,7 @@ static void R_ParseSpriteInfo(boolean spr2) // ^^ we've confirmed that the token is == 4 characters so it will never overflow a 5 byte char buffer strupr(newSpriteName); // Just do this now so we don't have to worry about it } + Z_Free(sprinfoToken); if (!spr2) @@ -1530,7 +1596,7 @@ static void R_ParseSpriteInfo(boolean spr2) I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName); if (!memcmp(newSpriteName,sprnames[i],4)) { - sprnum = i; + parser.sprnum = i; break; } } @@ -1543,15 +1609,15 @@ static void R_ParseSpriteInfo(boolean spr2) I_Error("Error parsing SPRTINFO lump: Unknown sprite2 name \"%s\"", newSpriteName); if (!memcmp(newSpriteName,spr2names[i],4)) { - spr2num = i; + parser.spr2num = i; break; } } } // allocate a spriteinfo - info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL); - info->available = true; + parser.info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL); + parser.info->available = true; // Left Curly Brace sprinfoToken = M_GetToken(NULL); @@ -1571,53 +1637,16 @@ static void R_ParseSpriteInfo(boolean spr2) { if (stricmp(sprinfoToken, "SKIN")==0) { - INT32 skinnum; - char *skinName = NULL; if (!spr2) I_Error("Error parsing SPRTINFO lump: \"SKIN\" token found outside of a sprite2 definition"); Z_Free(sprinfoToken); - - // Skin name - sprinfoToken = M_GetToken(NULL); - if (sprinfoToken == NULL) - { - I_Error("Error parsing SPRTINFO lump: Unexpected end of file where skin frame should be"); - } - - // copy skin name yada yada - sprinfoTokenLength = strlen(sprinfoToken); - skinName = (char *)Z_Malloc((sprinfoTokenLength+1)*sizeof(char),PU_STATIC,NULL); - M_Memcpy(skinName,sprinfoToken,sprinfoTokenLength*sizeof(char)); - skinName[sprinfoTokenLength] = '\0'; - strlwr(skinName); - Z_Free(sprinfoToken); - - skinnum = R_SkinAvailable(skinName); - if (skinnum == -1) - I_Error("Error parsing SPRTINFO lump: Unknown skin \"%s\"", skinName); - - skinnumbers[foundskins] = skinnum; - foundskins++; + R_ParseSpriteInfoSkin(&parser); } else if (stricmp(sprinfoToken, "FRAME")==0) { - R_ParseSpriteInfoFrame(info); Z_Free(sprinfoToken); - if (spr2) - { - if (!foundskins) - I_Error("Error parsing SPRTINFO lump: No skins specified in this sprite2 definition"); - for (i = 0; i < foundskins; i++) - { - size_t skinnum = skinnumbers[i]; - skin_t *skin = &skins[skinnum]; - spriteinfo_t *sprinfo = skin->sprinfo; - M_Memcpy(&sprinfo[spr2num], info, sizeof(spriteinfo_t)); - } - } - else - M_Memcpy(&spriteinfo[sprnum], info, sizeof(spriteinfo_t)); + R_ParseSpriteInfoFrame(&parser); } else { @@ -1636,7 +1665,7 @@ static void R_ParseSpriteInfo(boolean spr2) I_Error("Error parsing SPRTINFO lump: Expected \"{\" for sprite \"%s\", got \"%s\"",newSpriteName,sprinfoToken); } Z_Free(sprinfoToken); - Z_Free(info); + Z_Free(parser.info); } // From b0f84e99fcfcfec243d128ae3e08b8740495b931 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 21 Sep 2022 13:20:30 -0700 Subject: [PATCH 43/49] Refactor Lua spriteinfo Fixes available not being set when pivot list is updated on its own. --- src/lua_infolib.c | 48 +++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 1aaa207de..45dcf9977 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -242,6 +242,11 @@ static int lib_spr2namelen(lua_State *L) // SPRITE INFO // ///////////////// +struct PivotFrame { + spriteinfo_t *sprinfo; + UINT8 frame; +}; + // spriteinfo[] static int lib_getSpriteInfo(lua_State *L) { @@ -441,7 +446,7 @@ static int spriteinfo_get(lua_State *L) { // bypass LUA_PushUserdata void **userdata = lua_newuserdata(L, sizeof(void *)); - *userdata = &sprinfo->pivot; + *userdata = sprinfo; luaL_getmetatable(L, META_PIVOTLIST); lua_setmetatable(L, -2); @@ -480,9 +485,8 @@ static int spriteinfo_set(lua_State *L) // pivot[] is userdata else if (lua_isuserdata(L, 1)) { - spriteframepivot_t *pivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_PIVOTLIST)); - memcpy(&sprinfo->pivot, pivot, sizeof(spriteframepivot_t)); - sprinfo->available = true; // Just in case? + spriteinfo_t *copyinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_PIVOTLIST)); + memcpy(sprinfo, copyinfo, sizeof(spriteinfo_t)); } } else @@ -505,8 +509,8 @@ static int spriteinfo_num(lua_State *L) // framepivot_t static int pivotlist_get(lua_State *L) { - void **userdata; - spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_PIVOTLIST)); + struct PivotFrame *container; + spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_PIVOTLIST)); const char *field = luaL_checkstring(L, 2); UINT8 frame; @@ -517,8 +521,9 @@ static int pivotlist_get(lua_State *L) luaL_error(L, "invalid frame %s", field); // bypass LUA_PushUserdata - userdata = lua_newuserdata(L, sizeof(void *)); - *userdata = &framepivot[frame]; + container = lua_newuserdata(L, sizeof *container); + container->sprinfo = sprinfo; + container->frame = frame; luaL_getmetatable(L, META_FRAMEPIVOT); lua_setmetatable(L, -2); @@ -528,11 +533,10 @@ static int pivotlist_get(lua_State *L) static int pivotlist_set(lua_State *L) { - // Because I already know it's a spriteframepivot_t anyway - spriteframepivot_t *pivotlist = *((spriteframepivot_t **)lua_touserdata(L, 1)); - //spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT)); + spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_PIVOTLIST)); const char *field = luaL_checkstring(L, 2); UINT8 frame; + int okcool = 0; if (!lua_lumploading) return luaL_error(L, "Do not alter spriteframepivot_t from within a hook or coroutine!"); @@ -549,14 +553,18 @@ static int pivotlist_set(lua_State *L) // pivot[] is a table if (lua_istable(L, 3)) - return PopPivotSubTable(pivotlist, L, 3, frame); + okcool = PopPivotSubTable(sprinfo->pivot, L, 3, frame); // pivot[] is userdata else if (lua_isuserdata(L, 3)) { - spriteframepivot_t *copypivot = *((spriteframepivot_t **)luaL_checkudata(L, 3, META_FRAMEPIVOT)); - memcpy(&pivotlist[frame], copypivot, sizeof(spriteframepivot_t)); + struct PivotFrame *container = luaL_checkudata(L, 3, META_FRAMEPIVOT); + memcpy(&sprinfo->pivot[frame], &container->sprinfo->pivot[container->frame], sizeof(spriteframepivot_t)); + okcool = 1; } + if (okcool) + sprinfo->available = true; + return 0; } @@ -568,7 +576,8 @@ static int pivotlist_num(lua_State *L) static int framepivot_get(lua_State *L) { - spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT)); + struct PivotFrame *container = luaL_checkudata(L, 1, META_FRAMEPIVOT); + spriteframepivot_t *framepivot = &container->sprinfo->pivot[container->frame]; const char *field = luaL_checkstring(L, 2); I_Assert(framepivot != NULL); @@ -585,7 +594,8 @@ static int framepivot_get(lua_State *L) static int framepivot_set(lua_State *L) { - spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT)); + struct PivotFrame *container = luaL_checkudata(L, 1, META_FRAMEPIVOT); + spriteframepivot_t *framepivot = &container->sprinfo->pivot[container->frame]; const char *field = luaL_checkstring(L, 2); if (!lua_lumploading) @@ -598,9 +608,15 @@ static int framepivot_set(lua_State *L) I_Assert(framepivot != NULL); if (fastcmp("x", field)) + { framepivot->x = luaL_checkinteger(L, 3); + container->sprinfo->available = true; + } else if (fastcmp("y", field)) + { framepivot->y = luaL_checkinteger(L, 3); + container->sprinfo->available = true; + } else return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field)); From 5a631b302dcbc7ae405711cc4fc039d4d8db8b1a Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 21 Sep 2022 12:31:32 -0700 Subject: [PATCH 44/49] Add SPRINFO_DEFAULT_PIVOT, change spriteinfo_t.available to bit array Default is used if the bit is not set for a particular frame. --- src/r_patchrotation.c | 7 ++++++- src/r_picformats.h | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c index ab6c0de97..e2506baa5 100644 --- a/src/r_patchrotation.c +++ b/src/r_patchrotation.c @@ -141,11 +141,16 @@ patch_t *Patch_GetRotatedSprite( patch = W_CachePatchNum(lump, PU_SPRITE); - if (sprinfo->available) + if (in_bit_array(sprinfo->available, frame)) { xpivot = sprinfo->pivot[frame].x; ypivot = sprinfo->pivot[frame].y; } + else if (in_bit_array(sprinfo->available, SPRINFO_DEFAULT_PIVOT)) + { + xpivot = sprinfo->pivot[SPRINFO_DEFAULT_PIVOT].x; + ypivot = sprinfo->pivot[SPRINFO_DEFAULT_PIVOT].y; + } else { xpivot = patch->leftoffset; diff --git a/src/r_picformats.h b/src/r_picformats.h index 0a822cc48..700424814 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -100,8 +100,9 @@ typedef struct typedef struct { - spriteframepivot_t pivot[64]; - boolean available; + spriteframepivot_t pivot[64 + 1]; +#define SPRINFO_DEFAULT_PIVOT (64) + UINT8 available[BIT_ARRAY_SIZE(64 + 1)]; // 1 extra for default_pivot } spriteinfo_t; // Portable Network Graphics From 0912ebaaa3c5a05e7c554eebd3e3ebe016c28c7f Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 21 Sep 2022 12:32:06 -0700 Subject: [PATCH 45/49] Update and extend R_ParseSpriteInfo for default pivot - Set default pivot with DEFAULT block - Use wildcard star (*) with Sprite/Sprite2Info/Skin to iterate over all sprites and/or skins --- src/r_picformats.c | 144 +++++++++++++++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 38 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index deb2bcfde..1f39ae42c 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1401,10 +1401,14 @@ struct ParseSpriteInfoState { spriteinfo_t *info; spritenum_t sprnum; playersprite_t spr2num; + boolean any; INT32 skinnumbers[MAXSKINS]; INT32 foundskins; }; +#define PARSER_FRAME (false) +#define PARSER_DEFAULT (true) + static void R_ParseSpriteInfoSkin(struct ParseSpriteInfoState *parser) { char *sprinfoToken; @@ -1420,19 +1424,26 @@ static void R_ParseSpriteInfoSkin(struct ParseSpriteInfoState *parser) I_Error("Error parsing SPRTINFO lump: Unexpected end of file where skin frame should be"); } - // copy skin name yada yada - sprinfoTokenLength = strlen(sprinfoToken); - skinName = (char *)Z_Malloc((sprinfoTokenLength+1)*sizeof(char),PU_STATIC,NULL); - M_Memcpy(skinName,sprinfoToken,sprinfoTokenLength*sizeof(char)); - skinName[sprinfoTokenLength] = '\0'; - strlwr(skinName); + if (strcmp(sprinfoToken, "*")==0) // All skins + { + parser->foundskins = -1; + } + else + { + // copy skin name yada yada + sprinfoTokenLength = strlen(sprinfoToken); + skinName = (char *)Z_Malloc((sprinfoTokenLength+1)*sizeof(char),PU_STATIC,NULL); + M_Memcpy(skinName,sprinfoToken,sprinfoTokenLength*sizeof(char)); + skinName[sprinfoTokenLength] = '\0'; + strlwr(skinName); - skinnum = R_SkinAvailable(skinName); - if (skinnum == -1) - I_Error("Error parsing SPRTINFO lump: Unknown skin \"%s\"", skinName); + skinnum = R_SkinAvailable(skinName); + if (skinnum == -1) + I_Error("Error parsing SPRTINFO lump: Unknown skin \"%s\"", skinName); - parser->skinnumbers[parser->foundskins] = skinnum; - parser->foundskins++; + parser->skinnumbers[parser->foundskins] = skinnum; + parser->foundskins++; + } Z_Free(sprinfoToken); } @@ -1442,10 +1453,22 @@ static void copy_to_skin (struct ParseSpriteInfoState *parser, INT32 skinnum) skin_t *skin = &skins[skinnum]; spriteinfo_t *sprinfo = skin->sprinfo; - M_Memcpy(&sprinfo[parser->spr2num], parser->info, sizeof(spriteinfo_t)); + if (parser->any) + { + playersprite_t spr2num; + + for (spr2num = 0; spr2num < NUMPLAYERSPRITES; ++spr2num) + { + M_Memcpy(&sprinfo[spr2num], parser->info, sizeof(spriteinfo_t)); + } + } + else + { + M_Memcpy(&sprinfo[parser->spr2num], parser->info, sizeof(spriteinfo_t)); + } } -static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser) +static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser, boolean all) { char *sprinfoToken; size_t sprinfoTokenLength; @@ -1455,22 +1478,29 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser) INT16 frameYPivot = 0; rotaxis_t frameRotAxis = 0; - // Sprite identifier - sprinfoToken = M_GetToken(NULL); - if (sprinfoToken == NULL) + if (all) { - I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite frame should be"); - } - sprinfoTokenLength = strlen(sprinfoToken); - if (sprinfoTokenLength != 1) - { - I_Error("Error parsing SPRTINFO lump: Invalid frame \"%s\"",sprinfoToken); + frameFrame = SPRINFO_DEFAULT_PIVOT; } else - frameChar = sprinfoToken; + { + // Sprite identifier + sprinfoToken = M_GetToken(NULL); + if (sprinfoToken == NULL) + { + I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite frame should be"); + } + sprinfoTokenLength = strlen(sprinfoToken); + if (sprinfoTokenLength != 1) + { + I_Error("Error parsing SPRTINFO lump: Invalid frame \"%s\"",sprinfoToken); + } + else + frameChar = sprinfoToken; - frameFrame = R_Char2Frame(frameChar[0]); - Z_Free(sprinfoToken); + frameFrame = R_Char2Frame(frameChar[0]); + Z_Free(sprinfoToken); + } // Left Curly Brace sprinfoToken = M_GetToken(NULL); @@ -1528,6 +1558,8 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser) parser->info->pivot[frameFrame].y = frameYPivot; parser->info->pivot[frameFrame].rotaxis = frameRotAxis; + set_bit_array(parser->info->available, frameFrame); + if (parser->spr2) { INT32 i; @@ -1535,14 +1567,36 @@ static void R_ParseSpriteInfoFrame(struct ParseSpriteInfoState *parser) if (!parser->foundskins) I_Error("Error parsing SPRTINFO lump: No skins specified in this sprite2 definition"); - for (i = 0; i < parser->foundskins; i++) + if (parser->foundskins < 0) { - copy_to_skin(parser, parser->skinnumbers[i]); + for (i = 0; i < numskins; i++) + { + copy_to_skin(parser, i); + } + } + else + { + for (i = 0; i < parser->foundskins; i++) + { + copy_to_skin(parser, parser->skinnumbers[i]); + } } } else { - M_Memcpy(&spriteinfo[parser->sprnum], parser->info, sizeof(spriteinfo_t)); + if (parser->any) + { + spritenum_t sprnum; + + for (sprnum = 0; sprnum < NUMSPRITES; ++sprnum) + { + M_Memcpy(&spriteinfo[sprnum], parser->info, sizeof(spriteinfo_t)); + } + } + else + { + M_Memcpy(&spriteinfo[parser->sprnum], parser->info, sizeof(spriteinfo_t)); + } } } @@ -1561,6 +1615,7 @@ static void R_ParseSpriteInfo(boolean spr2) .spr2 = spr2, .sprnum = NUMSPRITES, .spr2num = NUMPLAYERSPRITES, + .any = false, .foundskins = 0, }; @@ -1573,22 +1628,31 @@ static void R_ParseSpriteInfo(boolean spr2) I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be"); } - sprinfoTokenLength = strlen(sprinfoToken); - if (sprinfoTokenLength != 4) + if (!strcmp(sprinfoToken, "*")) // All sprites { - I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" isn't 4 characters long",sprinfoToken); + parser.any = true; } else { - memset(&newSpriteName, 0, 5); - M_Memcpy(newSpriteName, sprinfoToken, sprinfoTokenLength); - // ^^ we've confirmed that the token is == 4 characters so it will never overflow a 5 byte char buffer - strupr(newSpriteName); // Just do this now so we don't have to worry about it + sprinfoTokenLength = strlen(sprinfoToken); + if (sprinfoTokenLength != 4) + { + I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" isn't 4 characters long",sprinfoToken); + } + else + { + memset(&newSpriteName, 0, 5); + M_Memcpy(newSpriteName, sprinfoToken, sprinfoTokenLength); + // ^^ we've confirmed that the token is == 4 characters so it will never overflow a 5 byte char buffer + strupr(newSpriteName); // Just do this now so we don't have to worry about it + } } Z_Free(sprinfoToken); - if (!spr2) + if (parser.any) + ; + else if (!spr2) { for (i = 0; i <= NUMSPRITES; i++) { @@ -1617,7 +1681,6 @@ static void R_ParseSpriteInfo(boolean spr2) // allocate a spriteinfo parser.info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL); - parser.info->available = true; // Left Curly Brace sprinfoToken = M_GetToken(NULL); @@ -1646,7 +1709,12 @@ static void R_ParseSpriteInfo(boolean spr2) else if (stricmp(sprinfoToken, "FRAME")==0) { Z_Free(sprinfoToken); - R_ParseSpriteInfoFrame(&parser); + R_ParseSpriteInfoFrame(&parser, PARSER_FRAME); + } + else if (stricmp(sprinfoToken, "DEFAULT")==0) + { + Z_Free(sprinfoToken); + R_ParseSpriteInfoFrame(&parser, PARSER_DEFAULT); } else { From 43984aebd456e7a19ec4b907c8df51643d6557e7 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 21 Sep 2022 14:14:39 -0700 Subject: [PATCH 46/49] Lua spriteinfo default pivot support --- src/lua_infolib.c | 49 +++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 45dcf9977..0b8359065 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -247,6 +247,25 @@ struct PivotFrame { UINT8 frame; }; +static UINT8 GetPivotFrame(lua_State *L, int idx) +{ + const char *field = luaL_checkstring(L, idx); + UINT8 frame; + + if (fastcmp("default", field)) + { + frame = SPRINFO_DEFAULT_PIVOT; + } + else + { + frame = R_Char2Frame(field[0]); + if (frame == 255) + luaL_error(L, "invalid frame %s", field); + } + + return frame; +} + // spriteinfo[] static int lib_getSpriteInfo(lua_State *L) { @@ -354,24 +373,23 @@ static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk) while (lua_next(L, stk)) { int idx = 0; - const char *framestr = NULL; switch (lua_type(L, stk+1)) { case LUA_TSTRING: - framestr = lua_tostring(L, stk+1); - idx = R_Char2Frame(framestr[0]); + idx = GetPivotFrame(L, stk+1); break; case LUA_TNUMBER: idx = lua_tonumber(L, stk+1); + + if ((idx < 0) || (idx >= 64)) + return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, 63); break; default: TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1)); } - if ((idx < 0) || (idx >= 64)) - return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, 63); // the values in pivot[] are also tables if (PopPivotSubTable(info->pivot, L, stk+2, idx)) - info->available = true; + set_bit_array(info->available, idx); lua_pop(L, 1); } @@ -511,15 +529,10 @@ static int pivotlist_get(lua_State *L) { struct PivotFrame *container; spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_PIVOTLIST)); - const char *field = luaL_checkstring(L, 2); - UINT8 frame; + UINT8 frame = GetPivotFrame(L, 2); I_Assert(framepivot != NULL); - frame = R_Char2Frame(field[0]); - if (frame == 255) - luaL_error(L, "invalid frame %s", field); - // bypass LUA_PushUserdata container = lua_newuserdata(L, sizeof *container); container->sprinfo = sprinfo; @@ -534,7 +547,6 @@ static int pivotlist_get(lua_State *L) static int pivotlist_set(lua_State *L) { spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_PIVOTLIST)); - const char *field = luaL_checkstring(L, 2); UINT8 frame; int okcool = 0; @@ -547,9 +559,7 @@ static int pivotlist_set(lua_State *L) I_Assert(pivotlist != NULL); - frame = R_Char2Frame(field[0]); - if (frame == 255) - luaL_error(L, "invalid frame %s", field); + frame = GetPivotFrame(L, 2); // pivot[] is a table if (lua_istable(L, 3)) @@ -563,7 +573,7 @@ static int pivotlist_set(lua_State *L) } if (okcool) - sprinfo->available = true; + set_bit_array(sprinfo->available, frame); return 0; } @@ -596,6 +606,7 @@ static int framepivot_set(lua_State *L) { struct PivotFrame *container = luaL_checkudata(L, 1, META_FRAMEPIVOT); spriteframepivot_t *framepivot = &container->sprinfo->pivot[container->frame]; + UINT8 *available = container->sprinfo->available; const char *field = luaL_checkstring(L, 2); if (!lua_lumploading) @@ -610,12 +621,12 @@ static int framepivot_set(lua_State *L) if (fastcmp("x", field)) { framepivot->x = luaL_checkinteger(L, 3); - container->sprinfo->available = true; + set_bit_array(available, container->frame); } else if (fastcmp("y", field)) { framepivot->y = luaL_checkinteger(L, 3); - container->sprinfo->available = true; + set_bit_array(available, container->frame); } else return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field)); From 966ccdd230f0a1b80161d9ea61e225de5de1741e Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 22 Sep 2022 06:39:45 -0700 Subject: [PATCH 47/49] Don't play boost taunt twice if meme voices are enabled --- src/k_kart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 99f74b751..c72ff59db 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -5854,7 +5854,6 @@ void K_DoSneaker(player_t *player, INT32 type) if (type != 0) { player->pflags |= PF_ATTACKDOWN; - K_PlayBoostTaunt(player->mo); } player->sneakertimer = sneakertime; From 375fb72de1548a776ecbec4909e6edd07b83a5c8 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 03:07:35 -0700 Subject: [PATCH 48/49] Add K_GetRollingRouletteItem, refactor item drawers Roulette now cycles through all single items (that have odds). Added missing shields and drop target. --- src/k_hud.c | 187 ++++++++++++++------------------------------------- src/k_kart.c | 35 +++++++++- src/k_kart.h | 1 + src/p_mobj.c | 74 +------------------- 4 files changed, 86 insertions(+), 211 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index fd4493a93..91c0abb88 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -695,6 +695,40 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) } } +static patch_t **K_GetItemPatchTable(INT32 item) +{ + patch_t **kp[1 + NUMKARTITEMS] = { + kp_sadface, + NULL, + kp_sneaker, + kp_rocketsneaker, + kp_invincibility, + kp_banana, + kp_eggman, + kp_orbinaut, + kp_jawz, + kp_mine, + kp_landmine, + kp_ballhog, + kp_selfpropelledbomb, + kp_grow, + kp_shrink, + kp_lightningshield, + kp_bubbleshield, + kp_flameshield, + kp_hyudoro, + kp_pogospring, + kp_superring, + kp_kitchensink, + kp_droptarget, + }; + + if (item >= KITEM_SAD && item < NUMKARTITEMS) + return kp[item - KITEM_SAD]; + else + return NULL; +} + //} INT32 ITEM_X, ITEM_Y; // Item Window @@ -1096,90 +1130,23 @@ static void K_drawKartItem(void) if (stplyr->itemroulette) { + const INT32 item = K_GetRollingRouletteItem(stplyr); + if (stplyr->skincolor) localcolor = stplyr->skincolor; - switch((stplyr->itemroulette % (16*3)) / 3) + switch (item) { - // Each case is handled in threes, to give three frames of in-game time to see the item on the roulette - case 0: // Sneaker - localpatch = kp_sneaker[offset]; - //localcolor = SKINCOLOR_RASPBERRY; - break; - case 1: // Banana - localpatch = kp_banana[offset]; - //localcolor = SKINCOLOR_YELLOW; - break; - case 2: // Orbinaut - localpatch = kp_orbinaut[3+offset]; - //localcolor = SKINCOLOR_STEEL; - break; - case 3: // Mine - localpatch = kp_mine[offset]; - //localcolor = SKINCOLOR_JET; - break; - case 4: // Grow - localpatch = kp_grow[offset]; - //localcolor = SKINCOLOR_TEAL; - break; - case 5: // Hyudoro - localpatch = kp_hyudoro[offset]; - //localcolor = SKINCOLOR_STEEL; - break; - case 6: // Rocket Sneaker - localpatch = kp_rocketsneaker[offset]; - //localcolor = SKINCOLOR_TANGERINE; - break; - case 7: // Jawz - localpatch = kp_jawz[offset]; - //localcolor = SKINCOLOR_JAWZ; - break; - case 8: // Self-Propelled Bomb - localpatch = kp_selfpropelledbomb[offset]; - //localcolor = SKINCOLOR_JET; - break; - case 9: // Shrink - localpatch = kp_shrink[offset]; - //localcolor = SKINCOLOR_ORANGE; - break; - case 10: // Invincibility + case KITEM_INVINCIBILITY: localpatch = localinv; - //localcolor = SKINCOLOR_GREY; break; - case 11: // Eggman Monitor - localpatch = kp_eggman[offset]; - //localcolor = SKINCOLOR_ROSE; + + case KITEM_ORBINAUT: + localpatch = kp_orbinaut[3 + offset]; break; - case 12: // Ballhog - localpatch = kp_ballhog[offset]; - //localcolor = SKINCOLOR_LILAC; - break; - case 13: // Lightning Shield - localpatch = kp_lightningshield[offset]; - //localcolor = SKINCOLOR_CYAN; - break; - case 14: // Super Ring - localpatch = kp_superring[offset]; - //localcolor = SKINCOLOR_GOLD; - break; - case 15: // Land Mine - localpatch = kp_landmine[offset]; - //localcolor = SKINCOLOR_JET; - break; - case 16: // Drop Target - localpatch = kp_droptarget[offset]; - //localcolor = SKINCOLOR_LIME; - break; - /*case 17: // Pogo Spring - localpatch = kp_pogospring[offset]; - localcolor = SKINCOLOR_TANGERINE; - break; - case 18: // Kitchen Sink - localpatch = kp_kitchensink[offset]; - localcolor = SKINCOLOR_STEEL; - break;*/ + default: - break; + localpatch = K_GetItemPatchTable(item)[offset]; } } else @@ -1240,79 +1207,27 @@ static void K_drawKartItem(void) switch(stplyr->itemtype) { - case KITEM_SNEAKER: - localpatch = kp_sneaker[offset]; - break; - case KITEM_ROCKETSNEAKER: - localpatch = kp_rocketsneaker[offset]; - break; case KITEM_INVINCIBILITY: localpatch = localinv; localbg = kp_itembg[offset+1]; break; - case KITEM_BANANA: - localpatch = kp_banana[offset]; - break; - case KITEM_EGGMAN: - localpatch = kp_eggman[offset]; - break; + case KITEM_ORBINAUT: localpatch = kp_orbinaut[(offset ? 4 : min(stplyr->itemamount-1, 3))]; break; - case KITEM_JAWZ: - localpatch = kp_jawz[offset]; - break; - case KITEM_MINE: - localpatch = kp_mine[offset]; - break; - case KITEM_LANDMINE: - localpatch = kp_landmine[offset]; - break; - case KITEM_DROPTARGET: - localpatch = kp_droptarget[offset]; - break; - case KITEM_BALLHOG: - localpatch = kp_ballhog[offset]; - break; + case KITEM_SPB: - localpatch = kp_selfpropelledbomb[offset]; - localbg = kp_itembg[offset+1]; - break; - case KITEM_GROW: - localpatch = kp_grow[offset]; - break; - case KITEM_SHRINK: - localpatch = kp_shrink[offset]; - break; case KITEM_LIGHTNINGSHIELD: - localpatch = kp_lightningshield[offset]; - localbg = kp_itembg[offset+1]; - break; case KITEM_BUBBLESHIELD: - localpatch = kp_bubbleshield[offset]; - localbg = kp_itembg[offset+1]; - break; case KITEM_FLAMESHIELD: - localpatch = kp_flameshield[offset]; localbg = kp_itembg[offset+1]; - break; - case KITEM_HYUDORO: - localpatch = kp_hyudoro[offset]; - break; - case KITEM_POGOSPRING: - localpatch = kp_pogospring[offset]; - break; - case KITEM_SUPERRING: - localpatch = kp_superring[offset]; - break; - case KITEM_KITCHENSINK: - localpatch = kp_kitchensink[offset]; - break; - case KITEM_SAD: - localpatch = kp_sadface[offset]; - break; + /*FALLTHRU*/ + default: - localpatch = kp_nodraw; // diagnose underflows + localpatch = K_GetItemPatchTable(stplyr->itemtype)[offset]; + + if (localpatch == NULL) + localpatch = kp_nodraw; // diagnose underflows break; } diff --git a/src/k_kart.c b/src/k_kart.c index 99f74b751..c645e8914 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -350,7 +350,7 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = #define NUMKARTODDS 80 // Less ugly 2D arrays -static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = +static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { //P-Odds 0 1 2 3 4 5 6 7 /*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker @@ -383,7 +383,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = /*Jawz x2*/ { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2 }; -static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] = +static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = { //P-Odds 0 1 /*Sneaker*/ { 2, 1 }, // Sneaker @@ -899,6 +899,37 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum return useodds; } +INT32 K_GetRollingRouletteItem(player_t *player) +{ + static UINT8 translation[NUMKARTITEMS-1]; + static UINT16 roulette_size; + + static boolean odds_uncached = true; + + const UINT8 EMPTYODDS[sizeof K_KartItemOddsRace[0]] = {0}; + + if (odds_uncached) + { + UINT8 i; + + roulette_size = 0; + + for (i = 1; i < NUMKARTITEMS; ++i) + { + if (memcmp(K_KartItemOddsRace[i - 1], EMPTYODDS, sizeof EMPTYODDS)) + { + translation[roulette_size] = i; + roulette_size++; + } + } + + roulette_size *= 3; + odds_uncached = false; + } + + return translation[(player->itemroulette % roulette_size) / 3]; +} + static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) { INT32 i; diff --git a/src/k_kart.h b/src/k_kart.h index 46f97a3f5..98a372188 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -48,6 +48,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush); UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush); INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival); +INT32 K_GetRollingRouletteItem(player_t *player); INT32 K_GetShieldFromItem(INT32 item); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); diff --git a/src/p_mobj.c b/src/p_mobj.c index 28b596e2e..42d8c8302 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5997,79 +5997,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) { P_SetMobjState(mobj, S_PLAYERARROW_BOX); mobj->tracer->sprite = SPR_ITEM; - switch((mobj->target->player->itemroulette % (16*3)) / 3) - { - // Each case is handled in threes, to give three frames of in-game time to see the item on the roulette - case 0: // Sneaker - mobj->tracer->frame = KITEM_SNEAKER; - //localcolor = SKINCOLOR_RASPBERRY; - break; - case 1: // Banana - mobj->tracer->frame = KITEM_BANANA; - //localcolor = SKINCOLOR_YELLOW; - break; - case 2: // Orbinaut - mobj->tracer->frame = KITEM_ORBINAUT; - //localcolor = SKINCOLOR_STEEL; - break; - case 3: // Mine - mobj->tracer->frame = KITEM_MINE; - //localcolor = SKINCOLOR_JET; - break; - case 4: // Grow - mobj->tracer->frame = KITEM_GROW; - //localcolor = SKINCOLOR_TEAL; - break; - case 5: // Hyudoro - mobj->tracer->frame = KITEM_HYUDORO; - //localcolor = SKINCOLOR_STEEL; - break; - case 6: // Rocket Sneaker - mobj->tracer->frame = KITEM_ROCKETSNEAKER; - //localcolor = SKINCOLOR_TANGERINE; - break; - case 7: // Jawz - mobj->tracer->frame = KITEM_JAWZ; - //localcolor = SKINCOLOR_JAWZ; - break; - case 8: // Self-Propelled Bomb - mobj->tracer->frame = KITEM_SPB; - //localcolor = SKINCOLOR_JET; - break; - case 9: // Shrink - mobj->tracer->frame = KITEM_SHRINK; - //localcolor = SKINCOLOR_ORANGE; - break; - case 10: // Invincibility - mobj->tracer->frame = KITEM_INVINCIBILITY; - //localcolor = SKINCOLOR_GREY; - break; - case 11: // Eggman Monitor - mobj->tracer->frame = KITEM_EGGMAN; - //localcolor = SKINCOLOR_ROSE; - break; - case 12: // Ballhog - mobj->tracer->frame = KITEM_BALLHOG; - //localcolor = SKINCOLOR_LILAC; - break; - case 13: // Lightning Shield - mobj->tracer->frame = KITEM_LIGHTNINGSHIELD; - //localcolor = SKINCOLOR_CYAN; - break; - case 14: // Super Ring - mobj->tracer->frame = KITEM_SUPERRING; - //localcolor = SKINCOLOR_GOLD; - break; - case 15: // Land Mine - mobj->tracer->frame = KITEM_LANDMINE; - //localcolor = SKINCOLOR_JET; - break; - case 16: // Drop Target - mobj->tracer->frame = KITEM_DROPTARGET; - //localcolor = SKINCOLOR_LIME; - break; - } - mobj->tracer->frame |= FF_FULLBRIGHT; + mobj->tracer->frame = K_GetRollingRouletteItem(mobj->target->player) | FF_FULLBRIGHT; mobj->tracer->renderflags &= ~RF_DONTDRAW; } else if (mobj->target->player->stealingtimer < 0) From 3d01fca41ba64eab35a00ca305ccdea94bd0961c Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 04:29:40 -0700 Subject: [PATCH 49/49] K_GetRollingRouletteItem: support Battle --- src/k_kart.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index c645e8914..fd260891d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -904,27 +904,44 @@ INT32 K_GetRollingRouletteItem(player_t *player) static UINT8 translation[NUMKARTITEMS-1]; static UINT16 roulette_size; - static boolean odds_uncached = true; + static INT16 odds_cached = -1; + // Race odds have more columns than Battle const UINT8 EMPTYODDS[sizeof K_KartItemOddsRace[0]] = {0}; - if (odds_uncached) + if (odds_cached != gametype) { + UINT8 *odds_row; + size_t odds_row_size; + UINT8 i; roulette_size = 0; + if (gametype == GT_BATTLE) + { + odds_row = K_KartItemOddsBattle[0]; + odds_row_size = sizeof K_KartItemOddsBattle[0]; + } + else + { + odds_row = K_KartItemOddsRace[0]; + odds_row_size = sizeof K_KartItemOddsRace[0]; + } + for (i = 1; i < NUMKARTITEMS; ++i) { - if (memcmp(K_KartItemOddsRace[i - 1], EMPTYODDS, sizeof EMPTYODDS)) + if (memcmp(odds_row, EMPTYODDS, odds_row_size)) { translation[roulette_size] = i; roulette_size++; } + + odds_row += odds_row_size; } roulette_size *= 3; - odds_uncached = false; + odds_cached = gametype; } return translation[(player->itemroulette % roulette_size) / 3];