From 5767315787d8fc7a14c4dc87d3c36fcaf284828b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Sep 2022 01:07:46 -0400 Subject: [PATCH 01/51] SPB in its own file + better waypoint movement --- src/deh_tables.c | 1 - src/info.c | 40 +-- src/info.h | 2 - src/k_objects.h | 3 + src/objects/Sourcefile | 1 + src/objects/spb.c | 777 +++++++++++++++++++++++++++++++++++++++++ src/p_enemy.c | 511 --------------------------- src/p_mobj.c | 6 +- 8 files changed, 805 insertions(+), 536 deletions(-) create mode 100644 src/objects/spb.c diff --git a/src/deh_tables.c b/src/deh_tables.c index 5fe950e9e..8ea363fd9 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -322,7 +322,6 @@ actionpointer_t actionpointers[] = {{A_ItemPop}, "A_ITEMPOP"}, {{A_JawzChase}, "A_JAWZCHASE"}, {{A_JawzExplode}, "A_JAWZEXPLODE"}, - {{A_SPBChase}, "A_SPBCHASE"}, {{A_SSMineSearch}, "A_SSMINESEARCH"}, {{A_SSMineExplode}, "A_SSMINEEXPLODE"}, {{A_LandMineExplode}, "A_LANDMINEEXPLODE"}, diff --git a/src/info.c b/src/info.c index 186f04022..9e8108f76 100644 --- a/src/info.c +++ b/src/info.c @@ -4191,26 +4191,26 @@ state_t states[NUMSTATES] = {SPR_BHBM, FF_FULLBRIGHT|14, 1, {NULL}, 0, 0, S_BALLHOGBOOM16}, // S_BALLHOGBOOM15 {SPR_BHBM, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_NULL}, // S_BALLHOGBOOM16 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB2}, // S_SPB1 - {SPR_SPBM, 1, 1, {A_SPBChase}, 0, 0, S_SPB3}, // S_SPB2 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB4}, // S_SPB3 - {SPR_SPBM, 2, 1, {A_SPBChase}, 0, 0, S_SPB5}, // S_SPB4 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB6}, // S_SPB5 - {SPR_SPBM, 3, 1, {A_SPBChase}, 0, 0, S_SPB7}, // S_SPB6 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB8}, // S_SPB7 - {SPR_SPBM, 4, 1, {A_SPBChase}, 0, 0, S_SPB9}, // S_SPB8 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB10}, // S_SPB9 - {SPR_SPBM, 5, 1, {A_SPBChase}, 0, 0, S_SPB11}, // S_SPB10 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB12}, // S_SPB11 - {SPR_SPBM, 6, 1, {A_SPBChase}, 0, 0, S_SPB13}, // S_SPB12 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB14}, // S_SPB13 - {SPR_SPBM, 7, 1, {A_SPBChase}, 0, 0, S_SPB15}, // S_SPB14 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB16}, // S_SPB15 - {SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB17}, // S_SPB16 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB18}, // S_SPB17 - {SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB19}, // S_SPB18 - {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB20}, // S_SPB19 - {SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB1}, // S_SPB20 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB2}, // S_SPB1 + {SPR_SPBM, 1, 1, {NULL}, 0, 0, S_SPB3}, // S_SPB2 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB4}, // S_SPB3 + {SPR_SPBM, 2, 1, {NULL}, 0, 0, S_SPB5}, // S_SPB4 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB6}, // S_SPB5 + {SPR_SPBM, 3, 1, {NULL}, 0, 0, S_SPB7}, // S_SPB6 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB8}, // S_SPB7 + {SPR_SPBM, 4, 1, {NULL}, 0, 0, S_SPB9}, // S_SPB8 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB10}, // S_SPB9 + {SPR_SPBM, 5, 1, {NULL}, 0, 0, S_SPB11}, // S_SPB10 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB12}, // S_SPB11 + {SPR_SPBM, 6, 1, {NULL}, 0, 0, S_SPB13}, // S_SPB12 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB14}, // S_SPB13 + {SPR_SPBM, 7, 1, {NULL}, 0, 0, S_SPB15}, // S_SPB14 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB16}, // S_SPB15 + {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB17}, // S_SPB16 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB18}, // S_SPB17 + {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB19}, // S_SPB18 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB20}, // S_SPB19 + {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB1}, // S_SPB20 {SPR_SPBM, 8, 175, {NULL}, 0, 0, S_NULL}, // S_SPB_DEAD {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD2}, // S_LIGHTNINGSHIELD1 diff --git a/src/info.h b/src/info.h index 8acf73ba8..383dfd29f 100644 --- a/src/info.h +++ b/src/info.h @@ -275,7 +275,6 @@ enum actionnum A_ITEMPOP, A_JAWZCHASE, A_JAWZEXPLODE, - A_SPBCHASE, A_SSMINESEARCH, A_SSMINEEXPLODE, A_LANDMINEEXPLODE, @@ -547,7 +546,6 @@ void A_ChangeHeight(); void A_ItemPop(); void A_JawzChase(); void A_JawzExplode(); -void A_SPBChase(); void A_SSMineSearch(); void A_SSMineExplode(); void A_LandMineExplode(); diff --git a/src/k_objects.h b/src/k_objects.h index cc80d2555..7561c5d6e 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -15,4 +15,7 @@ void Obj_ShrinkGunRemoved(mobj_t *gun); boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim); void Obj_CreateShrinkPohbees(player_t *owner); +/* SPB */ +void Obj_SPBThink(mobj_t *spb); + #endif/*k_objects_H*/ diff --git a/src/objects/Sourcefile b/src/objects/Sourcefile index 94f7dd25b..4f0dacad7 100644 --- a/src/objects/Sourcefile +++ b/src/objects/Sourcefile @@ -1,2 +1,3 @@ hyudoro.c shrink.c +spb.c diff --git a/src/objects/spb.c b/src/objects/spb.c new file mode 100644 index 000000000..c5ae94efe --- /dev/null +++ b/src/objects/spb.c @@ -0,0 +1,777 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2022 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file shrink.c +/// \brief Shrink laser item code. + +#include "../doomdef.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../m_random.h" +#include "../p_local.h" +#include "../r_main.h" +#include "../s_sound.h" +#include "../g_game.h" +#include "../z_zone.h" +#include "../k_waypoint.h" +#include "../k_respawn.h" + +//#define SPB_SEEKTEST + +#define SPB_SLIPTIDEDELTA (ANG1 * 3) +#define SPB_STEERDELTA (ANGLE_90 - ANG10) +#define SPB_DEFAULTSPEED (FixedMul(mapobjectscale, K_GetKartSpeedFromStat(5) * 2)) + +enum +{ + SPB_MODE_SEEK, + SPB_MODE_CHASE, + SPB_MODE_WAIT, +}; + +#define spb_mode(o) ((o)->extravalue1) +#define spb_modetimer(o) ((o)->extravalue2) + +#define spb_nothink(o) ((o)->threshold) +#define spb_lastplayer(o) ((o)->lastlook) +#define spb_speed(o) ((o)->movefactor) +#define spb_pitch(o) ((o)->movedir) + +#define spb_curwaypoint(o) ((o)->cusval) + +#define spb_owner(o) ((o)->target) +#define spb_chase(o) ((o)->tracer) + +static void SpawnSPBTrailRings(mobj_t *spb) +{ + if (leveltime % (spb_mode(spb) != SPB_MODE_SEEK ? 6 : 3) == 0) + { + mobj_t *ring = P_SpawnMobjFromMobj(spb, + -FixedDiv(spb->momx, spb->scale), + -FixedDiv(spb->momy, spb->scale), + -FixedDiv(spb->momz, spb->scale) + (24*FRACUNIT), + MT_RING + ); + + ring->threshold = 10; + ring->fuse = 35*TICRATE; + + ring->colorized = true; + ring->color = SKINCOLOR_RED; + } +} + +static void SpawnSPBDust(mobj_t *spb) +{ + // The easiest way to spawn a V shaped cone of dust from the SPB is simply to spawn 2 particles, and to both move them to the sides in opposite direction. + mobj_t *dust; + fixed_t sx; + fixed_t sy; + fixed_t sz = spb->floorz; + angle_t sa = spb->angle - ANG1*60; + INT32 i; + + if (spb->eflags & MFE_VERTICALFLIP) + { + sz = spb->ceilingz; + } + + if ((leveltime & 1) && abs(spb->z - sz) < FRACUNIT*64) // Only every other frame. Also don't spawn it if we're way above the ground. + { + // Determine spawning position next to the SPB: + for (i = 0; i < 2; i++) + { + sx = 96 * FINECOSINE(sa >> ANGLETOFINESHIFT); + sy = 96 * FINESINE(sa >> ANGLETOFINESHIFT); + + dust = P_SpawnMobjFromMobj(spb, sx, sy, 0, MT_SPBDUST); + dust->z = sz; + + dust->momx = spb->momx/2; + dust->momy = spb->momy/2; + dust->momz = spb->momz/2; // Give some of the momentum to the dust + + P_SetScale(dust, spb->scale * 2); + + dust->color = SKINCOLOR_RED; + dust->colorized = true; + + dust->angle = spb->angle - FixedAngle(FRACUNIT*90 - FRACUNIT*180*i); // The first one will spawn to the right of the spb, the second one to the left. + P_Thrust(dust, dust->angle, 6*dust->scale); + + K_MatchGenericExtraFlags(dust, spb); + + sa += ANG1*120; // Add 120 degrees to get to mo->angle + ANG1*60 + } + } +} + +// Spawns SPB slip tide. To be used when the SPB is turning. +// Modified version of K_SpawnAIZDust. Maybe we could merge those to be cleaner? + +// dir should be either 1 or -1 to determine where to spawn the dust. + +static void SpawnSPBSliptide(mobj_t *spb, INT32 dir) +{ + fixed_t newx; + fixed_t newy; + mobj_t *spark; + angle_t travelangle; + fixed_t sz = spb->floorz; + + if (spb->eflags & MFE_VERTICALFLIP) + { + sz = spb->ceilingz; + } + + travelangle = K_MomentumAngle(spb); + + if ((leveltime & 1) && abs(spb->z - sz) < FRACUNIT*64) + { + newx = P_ReturnThrustX(spb, travelangle - (dir*ANGLE_45), 24*FRACUNIT); + newy = P_ReturnThrustY(spb, travelangle - (dir*ANGLE_45), 24*FRACUNIT); + + spark = P_SpawnMobjFromMobj(spb, newx, newy, 0, MT_SPBDUST); + spark->z = sz; + + spark->colorized = true; + spark->color = SKINCOLOR_RED; + + spark->flags = MF_NOGRAVITY|MF_PAIN; + P_SetTarget(&spark->target, spb); + + spark->angle = travelangle + (dir * ANGLE_90); + P_SetScale(spark, (spark->destscale = spb->scale*3/2)); + + spark->momx = (6*spb->momx)/5; + spark->momy = (6*spb->momy)/5; + + K_MatchGenericExtraFlags(spark, spb); + } +} + +// Used for seeking and when SPB is trailing its target from way too close! +static void SpawnSPBSpeedLines(mobj_t *spb) +{ + mobj_t *fast = P_SpawnMobjFromMobj(spb, + P_RandomRange(-24, 24) * FRACUNIT, + P_RandomRange(-24, 24) * FRACUNIT, + (spb->info->height / 2) + (P_RandomRange(-24, 24) * FRACUNIT), + MT_FASTLINE + ); + + P_SetTarget(&fast->target, spb); + fast->angle = K_MomentumAngle(spb); + + fast->color = SKINCOLOR_RED; + fast->colorized = true; + + K_MatchGenericExtraFlags(fast, spb); +} + +static fixed_t SPBDist(mobj_t *a, mobj_t *b) +{ + return P_AproxDistance(P_AproxDistance( + a->x - b->x, + a->y - b->y), + a->z - b->z + ); +} + +static void SPBTurn( + fixed_t destSpeed, angle_t destAngle, + fixed_t *editSpeed, angle_t *editAngle, + fixed_t lerp, SINT8 *returnSliptide) +{ + INT32 delta = destAngle - *editAngle; + fixed_t dampen = FRACUNIT; + + // Slow down when turning; it looks better and makes U-turns not unfair + dampen = FixedDiv((180 * FRACUNIT) - AngleFixed(abs(delta)), 180 * FRACUNIT); + + *editSpeed = FixedMul(destSpeed, dampen); + + delta = FixedMul(delta, lerp); + + // Calculate sliptide effect during seeking. + if (returnSliptide != NULL) + { + INT32 sliptide = (abs(delta) > SPB_SLIPTIDEDELTA); + + if (delta < 0) + { + sliptide = -sliptide; + } + + *returnSliptide = sliptide; + } + + *editAngle += delta; +} + +static void SetSPBSpeed(mobj_t *spb, fixed_t xySpeed, fixed_t zSpeed) +{ + spb->momx = FixedMul(FixedMul( + xySpeed, + FINECOSINE(spb->angle >> ANGLETOFINESHIFT)), + FINECOSINE(spb_pitch(spb) >> ANGLETOFINESHIFT) + ); + + spb->momy = FixedMul(FixedMul( + xySpeed, + FINESINE(spb->angle >> ANGLETOFINESHIFT)), + FINECOSINE(spb_pitch(spb) >> ANGLETOFINESHIFT) + ); + + spb->momz = FixedMul( + zSpeed, + FINESINE(spb_pitch(spb) >> ANGLETOFINESHIFT) + ); +} + +static void SPBSeek(mobj_t *spb, player_t *bestPlayer) +{ + const fixed_t desiredSpeed = SPB_DEFAULTSPEED; + + waypoint_t *curWaypoint = NULL; + waypoint_t *destWaypoint = NULL; + + fixed_t dist = INT32_MAX; + + fixed_t destX = spb->x; + fixed_t destY = spb->y; + fixed_t destZ = spb->z; + angle_t destAngle = spb->angle; + angle_t destPitch = 0U; + + fixed_t xySpeed = desiredSpeed; + fixed_t zSpeed = desiredSpeed; + SINT8 sliptide = 0; + + fixed_t steerDist = INT32_MAX; + mobj_t *steerMobj = NULL; + + size_t i; + + spb_lastplayer(spb) = -1; // Just make sure this is reset + + if (bestPlayer == NULL + || bestPlayer->mo == NULL + || P_MobjWasRemoved(bestPlayer->mo) == true + || bestPlayer->mo->health <= 0 + || (bestPlayer->respawn.state != RESPAWNST_NONE)) + { + // No one there? Completely STOP. + spb->momx = spb->momy = spb->momz = 0; + + if (bestPlayer == NULL) + { + spbplace = -1; + } + + return; + } + + // Found someone, now get close enough to initiate the slaughter... + P_SetTarget(&spb_chase(spb), bestPlayer->mo); + spbplace = bestPlayer->position; + + dist = SPBDist(spb, spb_chase(spb)); + +#ifdef SPB_SEEKTEST // Easy debug switch + (void)dist; +#else + if (dist <= (1024 * spb_chase(spb)->scale)) + { + S_StartSound(spb, spb->info->attacksound); + spb_mode(spb) = SPB_MODE_CHASE; // TARGET ACQUIRED + spb_modetimer(spb) = 7*TICRATE; + spb_speed(spb) = desiredSpeed; + return; + } +#endif + + // Move along the waypoints until you get close enough + if (spb_curwaypoint(spb) == -1) + { + // Determine first waypoint. + curWaypoint = K_GetBestWaypointForMobj(spb); + spb_curwaypoint(spb) = (INT32)K_GetWaypointHeapIndex(curWaypoint); + } + else + { + curWaypoint = K_GetWaypointFromIndex( (size_t)spb_curwaypoint(spb) ); + } + + destWaypoint = bestPlayer->nextwaypoint; + + if (curWaypoint != NULL) + { + fixed_t waypointDist = INT32_MAX; + fixed_t waypointRad = INT32_MAX; + + CONS_Printf("Moving towards waypoint... (%d)\n", K_GetWaypointID(curWaypoint)); + destX = curWaypoint->mobj->x; + destY = curWaypoint->mobj->y; + destZ = curWaypoint->mobj->z; + + waypointDist = R_PointToDist2(spb->x, spb->y, destX, destY) / mapobjectscale; + waypointRad = max(curWaypoint->mobj->radius / mapobjectscale, DEFAULT_WAYPOINT_RADIUS); + + if (waypointDist <= waypointRad) + { + boolean pathfindsuccess = false; + + if (destWaypoint != NULL) + { + // Go to next waypoint. + const boolean huntbackwards = false; + const boolean useshortcuts = K_GetWaypointIsShortcut(destWaypoint); // If the player is on a shortcut, use shortcuts. No escape. + + path_t pathtoplayer = {0}; + + pathfindsuccess = K_PathfindToWaypoint( + curWaypoint, destWaypoint, + &pathtoplayer, + useshortcuts, huntbackwards + ); + + if (pathfindsuccess == true) + { + if (pathtoplayer.numnodes > 1) + { + curWaypoint = (waypoint_t *)pathtoplayer.array[1].nodedata; + CONS_Printf("NEW: Proper next waypoint (%d)\n", K_GetWaypointID(curWaypoint)); + } + else if (destWaypoint->numnextwaypoints > 0) + { + curWaypoint = destWaypoint->nextwaypoints[0]; + CONS_Printf("NEW: Forcing next waypoint (%d)\n", K_GetWaypointID(curWaypoint)); + } + else + { + curWaypoint = destWaypoint; + CONS_Printf("NEW: Forcing destination (%d)\n", K_GetWaypointID(curWaypoint)); + } + + Z_Free(pathtoplayer.array); + } + } + + if (pathfindsuccess == true && curWaypoint != NULL) + { + // Update again + spb_curwaypoint(spb) = (INT32)K_GetWaypointHeapIndex(curWaypoint); + destX = curWaypoint->mobj->x; + destY = curWaypoint->mobj->y; + destZ = curWaypoint->mobj->z; + } + else + { + CONS_Printf("FAILURE, no waypoint (pathfind unsuccessful)\n"); + spb_curwaypoint(spb) = -1; + destX = spb_chase(spb)->x; + destY = spb_chase(spb)->y; + destZ = spb_chase(spb)->z; + } + } + } + else + { + CONS_Printf("FAILURE, no waypoint (no initial waypoint)\n"); + spb_curwaypoint(spb) = -1; + destX = spb_chase(spb)->x; + destY = spb_chase(spb)->y; + destZ = spb_chase(spb)->z; + } + + destAngle = R_PointToAngle2(spb->x, spb->y, destX, destY); + destPitch = R_PointToAngle2(0, spb->z, P_AproxDistance(spb->x - destX, spb->y - destY), destZ); + + SPBTurn(desiredSpeed, destAngle, &xySpeed, &spb->angle, FRACUNIT/8, &sliptide); + SPBTurn(desiredSpeed, destPitch, &zSpeed, &spb_pitch(spb), FRACUNIT/8, NULL); + + SetSPBSpeed(spb, xySpeed, zSpeed); + + // see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh! + steerDist = 1536 * mapobjectscale; + + for (i = 0; i < MAXPLAYERS; i++) + { + fixed_t ourDist = INT32_MAX; + INT32 ourDelta = INT32_MAX; + + if (playeringame[i] == false || players[i].spectator == true) + { + // Not in-game + continue; + } + + if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true) + { + // Invalid mobj + continue; + } + + ourDelta = AngleDelta(spb->angle, R_PointToAngle2(spb->x, spb->y, players[i].mo->x, players[i].mo->y)); + if (ourDelta > SPB_STEERDELTA) + { + // Check if the angle wouldn't make us LOSE speed. + continue; + } + + ourDist = R_PointToDist2(spb->x, spb->y, players[i].mo->x, players[i].mo->y); + if (ourDist < steerDist) + { + steerDist = ourDist; + steerMobj = players[i].mo; // it doesn't matter if we override this guy now. + } + } + + // different player from our main target, try and ram into em~! + if (steerMobj != NULL && steerMobj != spb_chase(spb)) + { + P_Thrust(spb, R_PointToAngle2(spb->x, spb->y, steerMobj->x, steerMobj->y), spb_speed(spb) / 4); + } + + if (sliptide != 0) + { + // 1 if turning left, -1 if turning right. + // Angles work counterclockwise, remember! + SpawnSPBSliptide(spb, sliptide); + } + else + { + // if we're mostly going straight, then spawn the V dust cone! + SpawnSPBDust(spb); + } + + // Always spawn speed lines while seeking + SpawnSPBSpeedLines(spb); + + // Spawn a trail of rings behind the SPB! + SpawnSPBTrailRings(spb); +} + +static void SPBChase(mobj_t *spb, player_t *bestPlayer) +{ + fixed_t baseSpeed = 0; + fixed_t maxSpeed = 0; + fixed_t desiredSpeed = 0; + + fixed_t range = INT32_MAX; + fixed_t cx = 0, cy = 0; + + fixed_t dist = INT32_MAX; + angle_t destAngle = spb->angle; + angle_t destPitch = 0U; + fixed_t xySpeed = 0; + fixed_t zSpeed = 0; + + mobj_t *chase = NULL; + player_t *chasePlayer = NULL; + + spb_curwaypoint(spb) = -1; // Reset waypoint + + chase = spb_chase(spb); + + if (chase == NULL || P_MobjWasRemoved(chase) == true || chase->health <= 0) + { + P_SetTarget(&spb_chase(spb), NULL); + spb_mode(spb) = SPB_MODE_WAIT; + spb_modetimer(spb) = 55; // Slightly over the respawn timer length + return; + } + + if (chase->hitlag) + { + // If the player is frozen, the SPB should be too. + spb->hitlag = max(spb->hitlag, chase->hitlag); + return; + } + + baseSpeed = SPB_DEFAULTSPEED; + range = (160 * chase->scale); + + // Play the intimidating gurgle + if (S_SoundPlaying(spb, spb->info->activesound) == false) + { + S_StartSound(spb, spb->info->activesound); + } + + // Maybe we want SPB to target an object later? IDK lol + chasePlayer = chase->player; + if (chasePlayer != NULL) + { + UINT8 fracmax = 32; + UINT8 spark = ((10 - chasePlayer->kartspeed) + chasePlayer->kartweight) / 2; + fixed_t easiness = ((chasePlayer->kartspeed + (10 - spark)) << FRACBITS) / 2; + + spb_lastplayer(spb) = chasePlayer - players; // Save the player num for death scumming... + spbplace = chasePlayer->position; + + chasePlayer->pflags |= PF_RINGLOCK; // set ring lock + + if (P_IsObjectOnGround(chase) == false) + { + // In the air you have no control; basically don't hit unless you make a near complete stop + baseSpeed = (7 * chasePlayer->speed) / 8; + } + else + { + // 7/8ths max speed for Knuckles, 3/4ths max speed for min accel, exactly max speed for max accel + baseSpeed = FixedMul( + ((fracmax+1) << FRACBITS) - easiness, + K_GetKartSpeed(chasePlayer, false, false) + ) / fracmax; + } + + if (chasePlayer->carry == CR_SLIDING) + { + baseSpeed = chasePlayer->speed/2; + } + + // Be fairer on conveyors + cx = chasePlayer->cmomx; + cy = chasePlayer->cmomy; + + // Switch targets if you're no longer 1st for long enough + if (bestPlayer != NULL && chasePlayer->position <= bestPlayer->position) + { + spb_modetimer(spb) = 7*TICRATE; + } + else + { + if (spb_modetimer(spb) > 0) + { + spb_modetimer(spb)--; + } + + if (spb_modetimer(spb) <= 0) + { + spb_mode(spb) = SPB_MODE_SEEK; // back to SEEKING + } + } + } + + dist = P_AproxDistance(P_AproxDistance(spb->x - chase->x, spb->y - chase->y), spb->z - chase->z); + + desiredSpeed = FixedMul(baseSpeed, FRACUNIT + FixedDiv(dist - range, range)); + + if (desiredSpeed < baseSpeed) + { + desiredSpeed = baseSpeed; + } + + maxSpeed = (baseSpeed * 3) / 2; + if (desiredSpeed > maxSpeed) + { + desiredSpeed = maxSpeed; + } + + if (desiredSpeed < 20 * chase->scale) + { + desiredSpeed = 20 * chase->scale; + } + + if (chasePlayer != NULL && chasePlayer->carry == CR_SLIDING) + { + // Hack for current sections to make them fair. + desiredSpeed = min(desiredSpeed, chasePlayer->speed / 2); + } + + destAngle = R_PointToAngle2(spb->x, spb->y, chase->x, chase->y); + destPitch = R_PointToAngle2(0, spb->z, P_AproxDistance(spb->x - chase->x, spb->y - chase->y), chase->z); + + // Modify stored speed + if (desiredSpeed > spb_speed(spb)) + { + spb_speed(spb) += (desiredSpeed - spb_speed(spb)) / TICRATE; + } + else + { + spb_speed(spb) = desiredSpeed; + } + + SPBTurn(spb_speed(spb), destAngle, &xySpeed, &spb->angle, FRACUNIT, NULL); + SPBTurn(spb_speed(spb), destPitch, &zSpeed, &spb_pitch(spb), FRACUNIT, NULL); + + SetSPBSpeed(spb, xySpeed, zSpeed); + spb->momx += cx; + spb->momy += cy; + + // Spawn a trail of rings behind the SPB! + SpawnSPBTrailRings(spb); + + // Red speed lines for when it's gaining on its target. A tell for when you're starting to lose too much speed! + if (R_PointToDist2(0, 0, spb->momx, spb->momy) > (16 * R_PointToDist2(0, 0, chase->momx, chase->momy)) / 15 // Going faster than the target + && xySpeed > 20 * mapobjectscale) // Don't display speedup lines at pitifully low speeds + { + SpawnSPBSpeedLines(spb); + } +} + +static void SPBWait(mobj_t *spb) +{ + player_t *oldPlayer = NULL; + + spb->momx = spb->momy = spb->momz = 0; // Stoooop + spb_curwaypoint(spb) = -1; // Reset waypoint + + if (spb_lastplayer(spb) != -1 + && playeringame[spb_lastplayer(spb)] == true) + { + oldPlayer = &players[spb_lastplayer(spb)]; + } + + if (oldPlayer != NULL + && oldPlayer->spectator == false + && oldPlayer->exiting > 0) + { + spbplace = oldPlayer->position; + oldPlayer->pflags |= PF_RINGLOCK; + } + + if (spb_modetimer(spb) > 0) + { + spb_modetimer(spb)--; + } + + if (spb_modetimer(spb) <= 0) + { + if (oldPlayer != NULL) + { + if (oldPlayer->mo != NULL && P_MobjWasRemoved(oldPlayer->mo) == false) + { + P_SetTarget(&spb_chase(spb), oldPlayer->mo); + spb_mode(spb) = SPB_MODE_CHASE; + spb_modetimer(spb) = 7*TICRATE; + spb_speed(spb) = SPB_DEFAULTSPEED; + } + } + else + { + spb_mode(spb) = SPB_MODE_SEEK; + spb_modetimer(spb) = 0; + spbplace = -1; + } + } +} + +void Obj_SPBThink(mobj_t *spb) +{ + mobj_t *ghost = NULL; + player_t *bestPlayer = NULL; + UINT8 bestRank = UINT8_MAX; + size_t i; + + if (spb->health <= 0) + { + return; + } + + indirectitemcooldown = 20*TICRATE; + + ghost = P_SpawnGhostMobj(spb); + ghost->fuse = 3; + + if (spb_owner(spb) != NULL && P_MobjWasRemoved(spb_owner(spb)) == false && spb_owner(spb)->player != NULL) + { + ghost->color = spb_owner(spb)->player->skincolor; + ghost->colorized = true; + } + + if (spb_nothink(spb) > 0) + { + // Doesn't think yet, when it initially spawns. + spb_lastplayer(spb) = -1; + spb_curwaypoint(spb) = -1; + spbplace = -1; + + P_InstaThrust(spb, spb->angle, SPB_DEFAULTSPEED); + + spb_nothink(spb)--; + } + else + { + // Find the player with the best rank + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *player = NULL; + + if (playeringame[i] == false) + { + // Not valid + continue; + } + + player = &players[i]; + + if (player->spectator == true || player->exiting > 0) + { + // Not playing + continue; + } + + /* + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + // No mobj + continue; + } + + if (player->mo <= 0) + { + // Dead + continue; + } + + if (player->respawn.state != RESPAWNST_NONE) + { + // Respawning + continue; + } + */ + + if (player->position < bestRank) + { + bestRank = player->position; + bestPlayer = player; + } + } + + switch (spb_mode(spb)) + { + case SPB_MODE_SEEK: + default: + SPBSeek(spb, bestPlayer); + break; + + case SPB_MODE_CHASE: + SPBChase(spb, bestPlayer); + break; + + case SPB_MODE_WAIT: + SPBWait(spb); + break; + } + } + + // Clamp within level boundaries. + if (spb->z < spb->floorz) + { + spb->z = spb->floorz; + } + else if (spb->z > spb->ceilingz - spb->height) + { + spb->z = spb->ceilingz - spb->height; + } +} diff --git a/src/p_enemy.c b/src/p_enemy.c index d5f999624..6fbbab61a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -311,7 +311,6 @@ void A_ChangeHeight(mobj_t *actor); void A_ItemPop(mobj_t *actor); void A_JawzChase(mobj_t *actor); void A_JawzExplode(mobj_t *actor); -void A_SPBChase(mobj_t *actor); void A_SSMineSearch(mobj_t *actor); void A_SSMineExplode(mobj_t *actor); void A_LandMineExplode(mobj_t *actor); @@ -13408,516 +13407,6 @@ void A_JawzExplode(mobj_t *actor) return; } -static void SpawnSPBTrailRings(mobj_t *actor) -{ - I_Assert(actor != NULL); - - if (leveltime % 6 == 0) - { - if (leveltime % (actor->extravalue1 == 2 ? 6 : 3) == 0) // Extravalue1 == 2 is seeking mode. Because the SPB is about twice as fast as normal in that mode, also spawn the rings twice as often to make up for it! - { - mobj_t *ring = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momy, - actor->z - actor->momz + (24*mapobjectscale), MT_RING); - ring->threshold = 10; - ring->fuse = 35*TICRATE; - ring->colorized = true; - ring->color = SKINCOLOR_RED; - } - } -} - -// Spawns the V shaped dust. To be used when the SPB is going mostly forward. -static void SpawnSPBDust(mobj_t *mo) -{ - // The easiest way to spawn a V shaped cone of dust from the SPB is simply to spawn 2 particles, and to both move them to the sides in opposite direction. - mobj_t *dust; - fixed_t sx; - fixed_t sy; - fixed_t sz = mo->floorz; - angle_t sa = mo->angle - ANG1*60; - INT32 i; - - if (mo->eflags & MFE_VERTICALFLIP) - sz = mo->ceilingz; - - if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64) // Only ever other frame. Also don't spawn it if we're way above the ground. - { - // Determine spawning position next to the SPB: - for (i=0; i < 2; i++) - { - sx = mo->x + FixedMul((mo->scale*96), FINECOSINE((sa)>>ANGLETOFINESHIFT)); - sy = mo->y + FixedMul((mo->scale*96), FINESINE((sa)>>ANGLETOFINESHIFT)); - - dust = P_SpawnMobj(sx, sy, sz, MT_SPBDUST); - dust->momx = mo->momx/2; - dust->momy = mo->momy/2; - dust->momz = mo->momz/2; // Give some of the momentum to the dust - P_SetScale(dust, mo->scale*2); - dust->colorized = true; - dust->color = SKINCOLOR_RED; - P_InitAngle(dust, mo->angle - FixedAngle(FRACUNIT*90 - FRACUNIT*180*i)); // The first one will spawn to the right of the spb, the second one to the left. - P_Thrust(dust, dust->angle, 6*dust->scale); - - K_MatchGenericExtraFlags(dust, mo); - - sa += ANG1*120; // Add 120 degrees to get to mo->angle + ANG1*60 - } - } -} - -// Spawns SPB slip tide. To be used when the SPB is turning. -// Modified version of K_SpawnAIZDust. Maybe we could merge those to be cleaner? - -// dir should be either 1 or -1 to determine where to spawn the dust. - -static void SpawnSPBAIZDust(mobj_t *mo, INT32 dir) -{ - fixed_t newx; - fixed_t newy; - mobj_t *spark; - angle_t travelangle; - fixed_t sz = mo->floorz; - - if (mo->eflags & MFE_VERTICALFLIP) - sz = mo->ceilingz; - - travelangle = K_MomentumAngle(mo); - if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64) - { - newx = mo->x + P_ReturnThrustX(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale)); - newy = mo->y + P_ReturnThrustY(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale)); - spark = P_SpawnMobj(newx, newy, sz, MT_AIZDRIFTSTRAT); - spark->colorized = true; - spark->color = SKINCOLOR_RED; - spark->flags = MF_NOGRAVITY|MF_PAIN; - P_SetTarget(&spark->target, mo); - - P_InitAngle(spark, travelangle+(dir*ANGLE_90)); - P_SetScale(spark, (spark->destscale = mo->scale*3/2)); - - spark->momx = (6*mo->momx)/5; - spark->momy = (6*mo->momy)/5; - - K_MatchGenericExtraFlags(spark, mo); - } -} - -// Used for seeking and when SPB is trailing its target from way too close! -static void SpawnSPBSpeedLines(mobj_t *actor) -{ - mobj_t *fast = P_SpawnMobj(actor->x + (P_RandomRange(-24,24) * actor->scale), - actor->y + (P_RandomRange(-24,24) * actor->scale), - actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale), - MT_FASTLINE); - - P_SetTarget(&fast->target, actor); - P_InitAngle(fast, K_MomentumAngle(actor)); - fast->color = SKINCOLOR_RED; - fast->colorized = true; - K_MatchGenericExtraFlags(fast, actor); -} - - -void A_SPBChase(mobj_t *actor) -{ - player_t *player = NULL; - player_t *scplayer = NULL; // secondary target for seeking - UINT8 i; - UINT8 bestrank = UINT8_MAX; - fixed_t dist; - angle_t hang, vang; - fixed_t wspeed, xyspeed, zspeed; - fixed_t pdist = 1536<threshold) // Just fired, go straight. - { - actor->lastlook = -1; - actor->cusval = -1; - spbplace = -1; - P_InstaThrust(actor, actor->angle, wspeed); - return; - } - - // Find the player with the best rank - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator || players[i].exiting) - continue; // not in-game - - /*if (!players[i].mo) - continue; // no mobj - - if (players[i].mo->health <= 0) - continue; // dead - - if (players[i].respawn.state != RESPAWNST_NONE) - continue;*/ // respawning - - if (players[i].position < bestrank) - { - bestrank = players[i].position; - player = &players[i]; - } - } - - // lastlook = last player num targetted - // cvmem = stored speed - // cusval = next waypoint heap index - // extravalue1 = SPB movement mode - // extravalue2 = mode misc option - - if (actor->extravalue1 == 1) // MODE: TARGETING - { - actor->cusval = -1; // Reset waypoint - - if (actor->tracer && actor->tracer->health) - { - fixed_t defspeed = wspeed; - fixed_t range = (160*actor->tracer->scale); - fixed_t cx = 0, cy =0; - - // Play the intimidating gurgle - if (!S_SoundPlaying(actor, actor->info->activesound)) - S_StartSound(actor, actor->info->activesound); - - // Maybe we want SPB to target an object later? IDK lol - if (actor->tracer->player) - { - UINT8 fracmax = 32; - UINT8 spark = ((10-actor->tracer->player->kartspeed) + actor->tracer->player->kartweight) / 2; - fixed_t easiness = ((actor->tracer->player->kartspeed + (10-spark)) << FRACBITS) / 2; - - actor->lastlook = actor->tracer->player-players; // Save the player num for death scumming... - actor->tracer->player->pflags |= PF_RINGLOCK; // set ring lock - - if (actor->tracer->hitlag) - { - // If the player is frozen through no fault of their own, the SPB should be too. - actor->hitlag = actor->tracer->hitlag; - } - - if (!P_IsObjectOnGround(actor->tracer)) - { - // In the air you have no control; basically don't hit unless you make a near complete stop - defspeed = (7 * actor->tracer->player->speed) / 8; - } - else - { - // 7/8ths max speed for Knuckles, 3/4ths max speed for min accel, exactly max speed for max accel - defspeed = FixedMul(((fracmax+1)<tracer->player, false, false)) / fracmax; - } - - // Be fairer on conveyors - cx = actor->tracer->player->cmomx; - cy = actor->tracer->player->cmomy; - - // Switch targets if you're no longer 1st for long enough - if (actor->tracer->player->position <= bestrank) - actor->extravalue2 = 7*TICRATE; - else if (actor->extravalue2-- <= 0) - actor->extravalue1 = 0; // back to SEEKING - - spbplace = actor->tracer->player->position; - } - - dist = P_AproxDistance(P_AproxDistance(actor->x-actor->tracer->x, actor->y-actor->tracer->y), actor->z-actor->tracer->z); - - wspeed = FixedMul(defspeed, FRACUNIT + FixedDiv(dist-range, range)); - if (wspeed < defspeed) - wspeed = defspeed; - if (wspeed > (3*defspeed)/2) - wspeed = (3*defspeed)/2; - if (wspeed < 20*actor->tracer->scale) - wspeed = 20*actor->tracer->scale; - if (actor->tracer->player->carry == CR_SLIDING) - wspeed = actor->tracer->player->speed/2; - // ^^^^ current section: These are annoying, and grand metropolis in particular needs this. - - hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); - vang = R_PointToAngle2(0, actor->z, dist, actor->tracer->z); - - // Modify stored speed - if (wspeed > actor->cvmem) - actor->cvmem += (wspeed - actor->cvmem) / TICRATE; - else - actor->cvmem = wspeed; - - { - // Smoothly rotate horz angle - angle_t input = hang - actor->angle; - boolean invert = (input > ANGLE_180); - if (invert) - input = InvAngle(input); - - // Slow down when turning; it looks better and makes U-turns not unfair - xyspeed = FixedMul(actor->cvmem, max(0, (((180<angle += input; - - // Smoothly rotate vert angle - input = vang - actor->movedir; - invert = (input > ANGLE_180); - if (invert) - input = InvAngle(input); - - // Slow down when turning; might as well do it for momz, since we do it above too - zspeed = FixedMul(actor->cvmem, max(0, (((180<movedir += input; - } - - actor->momx = cx + FixedMul(FixedMul(xyspeed, FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); - actor->momy = cy + FixedMul(FixedMul(xyspeed, FINESINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); - actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT)); - - // Spawn a trail of rings behind the SPB! - SpawnSPBTrailRings(actor); - - // Red speed lines for when it's gaining on its target. A tell for when you're starting to lose too much speed! - if (R_PointToDist2(0, 0, actor->momx, actor->momy) > (actor->tracer->player ? (16*actor->tracer->player->speed)/15 - : (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target - && xyspeed > K_GetKartSpeed(actor->tracer->player, false, false) / 4) // Don't display speedup lines at pitifully low speeds - SpawnSPBSpeedLines(actor); - - return; - } - else // Target's gone, return to SEEKING - { - P_SetTarget(&actor->tracer, NULL); - actor->extravalue1 = 2; // WAIT... - actor->extravalue2 = 52; // Slightly over the respawn timer length - return; - } - } - else if (actor->extravalue1 == 2) // MODE: WAIT... - { - actor->momx = actor->momy = actor->momz = 0; // Stoooop - actor->cusval = -1; // Reset waypoint - - if (actor->lastlook != -1 - && playeringame[actor->lastlook] - && !players[actor->lastlook].spectator - && !players[actor->lastlook].exiting) - { - spbplace = players[actor->lastlook].position; - players[actor->lastlook].pflags |= PF_RINGLOCK; - if (actor->extravalue2-- <= 0 && players[actor->lastlook].mo) - { - P_SetTarget(&actor->tracer, players[actor->lastlook].mo); - actor->extravalue1 = 1; // TARGET ACQUIRED - actor->extravalue2 = 7*TICRATE; - actor->cvmem = wspeed; - } - } - else - { - actor->extravalue1 = 0; // SEEKING - actor->extravalue2 = 0; - spbplace = -1; - } - } - else // MODE: SEEKING - { - waypoint_t *lastwaypoint = NULL; - waypoint_t *bestwaypoint = NULL; - waypoint_t *nextwaypoint = NULL; - waypoint_t *tempwaypoint = NULL; - - actor->lastlook = -1; // Just make sure this is reset - - if (!player || !player->mo || player->mo->health <= 0 || (player->respawn.state != RESPAWNST_NONE)) - { - // No one there? Completely STOP. - actor->momx = actor->momy = actor->momz = 0; - if (!player) - spbplace = -1; - return; - } - - // Found someone, now get close enough to initiate the slaughter... - P_SetTarget(&actor->tracer, player->mo); - spbplace = bestrank; - dist = P_AproxDistance(P_AproxDistance(actor->x-actor->tracer->x, actor->y-actor->tracer->y), actor->z-actor->tracer->z); - - /* - K_GetBestWaypointForMobj returns the waypoint closest to the object that isn't its current waypoint. While this is usually good enough, - in cases where the track overlaps, this means that the SPB will sometimes target a waypoint on an earlier/later portion of the track instead of following along. - For this reason, we're going to try and make sure to avoid these situations. - */ - - // Move along the waypoints until you get close enough - if (actor->cusval > -1 && actor->extravalue2 > 0) - { - // Previously set nextwaypoint - lastwaypoint = K_GetWaypointFromIndex((size_t)actor->cusval); - tempwaypoint = K_GetBestWaypointForMobj(actor); - // check if the tempwaypoint corresponds to lastwaypoint's next ID at least; - // This is to avoid situations where the SPB decides to suicide jump down a bridge because it found a COMPLETELY unrelated waypoint down there. - - if (K_GetWaypointID(tempwaypoint) == K_GetWaypointNextID(lastwaypoint) || K_GetWaypointID(tempwaypoint) == K_GetWaypointID(lastwaypoint)) - // either our previous or curr waypoint ID, sure, take it - bestwaypoint = tempwaypoint; - else - bestwaypoint = K_GetWaypointFromIndex((size_t)actor->extravalue2); // keep going from the PREVIOUS wp. - } - else - bestwaypoint = K_GetBestWaypointForMobj(actor); - - if (bestwaypoint == NULL && lastwaypoint == NULL) - { - // We have invalid waypoints all around, so use closest to try and make it non-NULL. - bestwaypoint = K_GetClosestWaypointToMobj(actor); - } - - if (bestwaypoint != NULL) - { - const boolean huntbackwards = false; - boolean useshortcuts = false; - - // If the player is on a shortcut, use shortcuts. No escape. - if (K_GetWaypointIsShortcut(player->nextwaypoint)) - { - useshortcuts = true; - } - - nextwaypoint = K_GetNextWaypointToDestination( - bestwaypoint, player->nextwaypoint, useshortcuts, huntbackwards); - } - - if (nextwaypoint == NULL && lastwaypoint != NULL) - { - // Restore to the last nextwaypoint - nextwaypoint = lastwaypoint; - } - - if (nextwaypoint != NULL) - { - const fixed_t xywaypointdist = P_AproxDistance( - actor->x - nextwaypoint->mobj->x, actor->y - nextwaypoint->mobj->y); - - hang = R_PointToAngle2(actor->x, actor->y, nextwaypoint->mobj->x, nextwaypoint->mobj->y); - vang = R_PointToAngle2(0, actor->z, xywaypointdist, nextwaypoint->mobj->z); - - actor->cusval = (INT32)K_GetWaypointHeapIndex(nextwaypoint); - actor->extravalue2 = (INT32)K_GetWaypointHeapIndex(bestwaypoint); // save our last best, used above. - } - else - { - // continue straight ahead... Shouldn't happen. - hang = actor->angle; - vang = 0U; - } - - { - // Smoothly rotate horz angle - angle_t input = hang - actor->angle; - boolean invert = (input > ANGLE_180); - INT32 turnangle; - - if (invert) - input = InvAngle(input); - - input = FixedAngle(AngleFixed(input)/8); - - // Slow down when turning; it looks better and makes U-turns not unfair - xyspeed = FixedMul(wspeed, max(0, (((180<angle += input; - - // If input is small enough, spawn dust. Otherwise, spawn a slip tide! - turnangle = AngleFixed(input)/FRACUNIT; - - // The SPB is really turning if that value is >= 3 and <= 357. This looks pretty bad check-wise so feel free to change it for something that isn't as terrible. - if (turnangle >= 3 && turnangle <= 357) - SpawnSPBAIZDust(actor, turnangle < 180 ? 1 : -1); // 1 if turning left, -1 if turning right. Angles work counterclockwise, remember! - else - SpawnSPBDust(actor); // if we're mostly going straight, then spawn the V dust cone! - - SpawnSPBSpeedLines(actor); // Always spawn speed lines while seeking - - // Smoothly rotate vert angle - input = vang - actor->movedir; - invert = (input > ANGLE_180); - if (invert) - input = InvAngle(input); - - input = FixedAngle(AngleFixed(input)/8); - - // Slow down when turning; might as well do it for momz, since we do it above too - zspeed = FixedMul(wspeed, max(0, (((180<movedir += input; - } - - actor->momx = FixedMul(FixedMul(xyspeed, FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); - actor->momy = FixedMul(FixedMul(xyspeed, FINESINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); - actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT)); - - // see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh! - for (i=0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator || players[i].exiting) - continue; // not in-game - - if (R_PointToDist2(actor->x, actor->y, players[i].mo->x, players[i].mo->y) < pdist) - { - pdist = R_PointToDist2(actor->x, actor->y, players[i].mo->x, players[i].mo->y); - scplayer = &players[i]; // it doesn't matter if we override this guy now. - } - } - - // different player from our main target, try and ram into em~! - if (scplayer && scplayer != player) - { - pangle = actor->angle - R_PointToAngle2(actor->x, actor->y,scplayer->mo->x, scplayer->mo->y); - // check if the angle wouldn't make us LOSE speed... - if ((INT32)pangle/ANG1 >= -80 && (INT32)pangle/ANG1 <= 80) // allow for around 80 degrees - { - // Thrust us towards the guy, try to screw em up! - P_Thrust(actor, R_PointToAngle2(actor->x, actor->y, scplayer->mo->x, scplayer->mo->y), actor->movefactor/4); // not too fast though. - } - } - - // Spawn a trail of rings behind the SPB! - SpawnSPBTrailRings(actor); - - if (dist <= (1024*actor->tracer->scale) && !(actor->flags2 & MF2_AMBUSH)) // Close enough to target? Use Ambush flag to disable targetting so I can have an easier time testing stuff... - { - S_StartSound(actor, actor->info->attacksound); - actor->extravalue1 = 1; // TARGET ACQUIRED - actor->extravalue2 = 7*TICRATE; - actor->cvmem = wspeed; - } - } - - // Finally, no matter what, the spb should not be able to be under the ground, or above the ceiling; - if (actor->z < actor->floorz) - actor->z = actor->floorz; - else if (actor->z > actor->ceilingz - actor->height) - actor->z = actor->ceilingz - actor->height; - - return; -} - void A_SSMineSearch(mobj_t *actor) { fixed_t dis = INT32_MAX; diff --git a/src/p_mobj.c b/src/p_mobj.c index 0505d6bda..042cdad01 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6915,8 +6915,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->threshold--; break; case MT_SPB: - indirectitemcooldown = 20*TICRATE; - /* FALLTHRU */ + { + Obj_SPBThink(mobj); + break; + } case MT_BALLHOG: { mobj_t *ghost = P_SpawnGhostMobj(mobj); From 4fb1eef8f1cce4bacf2fc26a7b953255e1004306 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 07:53:58 -0700 Subject: [PATCH 02/51] command.c: refactor Setvalue, create CV_CompleteValue --- src/command.c | 147 +++++++++++++++++++++++++++----------------------- src/command.h | 6 +++ 2 files changed, 86 insertions(+), 67 deletions(-) diff --git a/src/command.c b/src/command.c index 0145687be..afa844906 100644 --- a/src/command.c +++ b/src/command.c @@ -1424,26 +1424,27 @@ const char *CV_CompleteVar(char *partial, INT32 skips) return NULL; } -/** Sets a value to a variable with less checking. Only for internal use. - * - * \param var Variable to set. - * \param valstr String value for the variable. - */ -static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) +boolean CV_CompleteValue(consvar_t *var, const char **valstrp, INT32 *intval) { - boolean override = false; + const char *valstr = *valstrp; + INT32 overrideval = 0; - // If we want messages informing us if cheats have been enabled or disabled, - // we need to rework the consvars a little bit. This call crashes the game - // on load because not all variables will be registered at that time. -/* boolean prevcheats = false; - if (var->flags & CV_CHEAT) - prevcheats = CV_CheatsEnabled(); */ + INT32 v; + + if (var == &cv_forceskin) + { + v = R_SkinAvailable(valstr); + + if (!R_SkinUsable(-1, v)) + v = -1; + + goto finish; + } if (var->PossibleValue) { - INT32 v; + INT32 i; if (var->flags & CV_FLOAT) { @@ -1464,7 +1465,6 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) { #define MINVAL 0 #define MAXVAL 1 - INT32 i; #ifdef PARANOIA if (!var->PossibleValue[MAXVAL].strvalue) I_Error("Bounded cvar \"%s\" without maximum!\n", var->name); @@ -1473,52 +1473,26 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) // search for other for (i = MAXVAL+1; var->PossibleValue[i].strvalue; i++) if (v == var->PossibleValue[i].value || !stricmp(var->PossibleValue[i].strvalue, valstr)) - { - if (client && execversion_enabled) - { - if (var->revert.allocated) - { - Z_Free(var->revert.v.string); - var->revert.allocated = false; // the below value is not allocated in zone memory, don't try to free it! - } - - var->revert.v.const_munge = var->PossibleValue[i].strvalue; - - return; - } - - // free the old value string - Z_Free(var->zstring); - var->zstring = NULL; - - var->value = var->PossibleValue[i].value; - var->string = var->PossibleValue[i].strvalue; - goto finish; - } + goto found; if ((v != INT32_MIN && v < var->PossibleValue[MINVAL].value) || !stricmp(valstr, "MIN")) { - v = var->PossibleValue[MINVAL].value; - valstr = var->PossibleValue[MINVAL].strvalue; - override = true; - overrideval = v; + i = MINVAL; + goto found; } else if ((v != INT32_MIN && v > var->PossibleValue[MAXVAL].value) || !stricmp(valstr, "MAX")) { - v = var->PossibleValue[MAXVAL].value; - valstr = var->PossibleValue[MAXVAL].strvalue; - override = true; - overrideval = v; + i = MAXVAL; + goto found; } if (v == INT32_MIN) goto badinput; + valstr = NULL; // not a preset value #undef MINVAL #undef MAXVAL } else { - INT32 i; - // check first strings for (i = 0; var->PossibleValue[i].strvalue; i++) if (!stricmp(var->PossibleValue[i].strvalue, valstr)) @@ -1550,27 +1524,69 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) // ...or not. goto badinput; found: - if (client && execversion_enabled) - { - var->revert.v.const_munge = var->PossibleValue[i].strvalue; - return; - } + v = var->PossibleValue[i].value; + valstr = var->PossibleValue[i].strvalue; + } - var->value = var->PossibleValue[i].value; - var->string = var->PossibleValue[i].strvalue; - goto finish; +finish: + if (intval) + *intval = v; + + *valstrp = valstr; + + return true; + } + +// landing point for possiblevalue failures +badinput: + return false; +} + +/** Sets a value to a variable with less checking. Only for internal use. + * + * \param var Variable to set. + * \param valstr String value for the variable. + */ +static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) +{ + boolean override = false; + INT32 overrideval = 0; + + // If we want messages informing us if cheats have been enabled or disabled, + // we need to rework the consvars a little bit. This call crashes the game + // on load because not all variables will be registered at that time. +/* boolean prevcheats = false; + if (var->flags & CV_CHEAT) + prevcheats = CV_CheatsEnabled(); */ + + const char *overridestr = valstr; + + if (CV_CompleteValue(var, &overridestr, &overrideval)) + { + if (overridestr) + { + valstr = overridestr; + override = true; } } + else if (var->PossibleValue) + goto badinput; if (client && execversion_enabled) { if (var->revert.allocated) { Z_Free(var->revert.v.string); + // Z_StrDup creates a new zone memory block, so we can keep the allocated flag on + if (override) + var->revert.allocated = false; // the below value is not allocated in zone memory, don't try to free it! } - var->revert.v.string = Z_StrDup(valstr); + if (override) + var->revert.v.const_munge = valstr; + else + var->revert.v.string = Z_StrDup(valstr); return; } @@ -1578,28 +1594,25 @@ found: // free the old value string Z_Free(var->zstring); - var->string = var->zstring = Z_StrDup(valstr); - if (override) - var->value = overrideval; - else if (var->flags & CV_FLOAT) { - double d = atof(var->string); - var->value = (INT32)(d * FRACUNIT); + var->zstring = NULL; + var->value = overrideval; + var->string = valstr; } else { - if (var == &cv_forceskin) + var->string = var->zstring = Z_StrDup(valstr); + + if (var->flags & CV_FLOAT) { - var->value = R_SkinAvailable(var->string); - if (!R_SkinUsable(-1, var->value)) - var->value = -1; + double d = atof(var->string); + var->value = (INT32)(d * FRACUNIT); } else var->value = atoi(var->string); } -finish: // See the note above. /* if (var->flags & CV_CHEAT) { diff --git a/src/command.h b/src/command.h index 876dce67f..31e372006 100644 --- a/src/command.h +++ b/src/command.h @@ -194,6 +194,12 @@ void CV_ClearChangedFlags(void); // returns the name of the nearest console variable name found const char *CV_CompleteVar(char *partial, INT32 skips); +// Returns true if valstrp is within the PossibleValues of +// var. If an exact string value exists, it is returned in +// valstrp. An integer value is returned in intval if it +// is not NULL. +boolean CV_CompleteValue(consvar_t *var, const char **valstrp, INT32 *intval); + // equivalent to " " typed at the console void CV_Set(consvar_t *var, const char *value); From 96c1c368216d409cb0a68c6e87c57510152d96cf Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 08:26:02 -0700 Subject: [PATCH 03/51] Add a mode to the toggle command, cycle a set of values toggle timescale 0.2 0.75 1 If timescale is 0.2, go to 0.75 If timescale is 0.75, go to 1 If timescale is 1 or any other value, go to 0.2 --- src/command.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/command.c b/src/command.c index afa844906..3c5cb9180 100644 --- a/src/command.c +++ b/src/command.c @@ -1024,15 +1024,17 @@ static void COM_Help_f(void) /** Toggles a console variable. Useful for on/off values. * - * This works on on/off, yes/no values only + * This works on on/off, yes/no values by default. Given + * a list of values, cycles between them. */ static void COM_Toggle_f(void) { consvar_t *cvar; - if (COM_Argc() != 2) + if (COM_Argc() == 1 || COM_Argc() == 3) { CONS_Printf(M_GetText("Toggle : Toggle the value of a cvar\n")); + CONS_Printf("Toggle ...: Cycle along a set of values\n"); return; } cvar = CV_FindVar(COM_Argv(1)); @@ -1042,15 +1044,44 @@ static void COM_Toggle_f(void) return; } - if (!(cvar->PossibleValue == CV_YesNo || cvar->PossibleValue == CV_OnOff)) + if (COM_Argc() == 2) { - CONS_Alert(CONS_NOTICE, M_GetText("%s is not a boolean value\n"), COM_Argv(1)); - return; + if (!(cvar->PossibleValue == CV_YesNo || cvar->PossibleValue == CV_OnOff)) + { + CONS_Alert(CONS_NOTICE, M_GetText("%s is not a boolean value\n"), COM_Argv(1)); + return; + } } // netcvar don't change imediately cvar->flags |= CV_SHOWMODIFONETIME; - CV_AddValue(cvar, +1); + + if (COM_Argc() == 2) + { + CV_AddValue(cvar, +1); + } + else + { + size_t i; + + for (i = 2; i < COM_Argc() - 1; ++i) + { + const char *str = COM_Argv(i); + INT32 val; + + if (CV_CompleteValue(cvar, &str, &val)) + { + if (str ? !stricmp(cvar->string, str) + : cvar->value == val) + { + CV_Set(cvar, COM_Argv(i + 1)); + return; + } + } + } + + CV_Set(cvar, COM_Argv(2)); + } } /** Command variant of CV_AddValue From 03effa44e57a97005b25d36f78ca684e236f84ec Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 02:13:57 -0400 Subject: [PATCH 04/51] Fix spb.c header --- src/objects/spb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index c5ae94efe..f968236d3 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -7,8 +7,8 @@ // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file shrink.c -/// \brief Shrink laser item code. +/// \file spb.c +/// \brief Self Propelled Bomb item code. #include "../doomdef.h" #include "../doomstat.h" From 7b77998523565e19167899c55273afd637cb5e77 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 02:27:34 -0400 Subject: [PATCH 05/51] Remove SPB 2nd place bonus odds Was a fun idea while it lasted, but we would like to give it more "tangible" buffs to players now, rather than trying to rig the casino. --- src/k_hud.c | 14 +++----------- src/k_kart.c | 37 ++++++++++++++----------------------- src/k_kart.h | 8 ++++---- 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 96635584e..e6ce9706b 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4556,7 +4556,6 @@ static void K_drawDistributionDebugger(void) UINT32 pdis = 0; INT32 i; INT32 x = -9, y = -9; - boolean spbrush = false; if (stplyr != &players[displayplayers[0]]) // only for p1 return; @@ -4583,14 +4582,7 @@ static void K_drawDistributionDebugger(void) } } - if (spbplace != -1 && stplyr->position == spbplace+1) - { - // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell - pdis = (3 * pdis) / 2; - spbrush = true; - } - - pdis = K_ScaleItemDistance(pdis, pingame, spbrush); + pdis = K_ScaleItemDistance(pdis, pingame); if (stplyr->bot && stplyr->botvars.rival) { @@ -4598,7 +4590,7 @@ static void K_drawDistributionDebugger(void) pdis = (15 * pdis) / 14; } - useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper, spbrush); + useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper); for (i = 1; i < NUMKARTRESULTS; i++) { @@ -4606,7 +4598,7 @@ static void K_drawDistributionDebugger(void) useodds, i, stplyr->distancetofinish, 0, - spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival) + stplyr->bot, (stplyr->bot && stplyr->botvars.rival) ); if (itemodds <= 0) diff --git a/src/k_kart.c b/src/k_kart.c index e14995d05..ca198d885 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -457,7 +457,9 @@ INT32 K_GetShieldFromItem(INT32 item) static void K_KartGetItemResult(player_t *player, SINT8 getitem) { if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) // Indirect items + { indirectitemcooldown = 20*TICRATE; + } player->botvars.itemdelay = TICRATE; player->botvars.itemconfirm = 0; @@ -511,15 +513,13 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem) } } -fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush) +fixed_t K_ItemOddsScale(UINT8 playerCount) { const UINT8 basePlayer = 8; // The player count we design most of the game around. - UINT8 playerCount = (spbrush ? 2 : numPlayers); fixed_t playerScaling = 0; // Then, it multiplies it further if the player count isn't equal to basePlayer. // This is done to make low player count races more interesting and high player count rates more fair. - // (If you're in SPB mode and in 2nd place, it acts like it's a 1v1, so the catch-up game is not weakened.) if (playerCount < basePlayer) { // Less than basePlayer: increase odds significantly. @@ -536,7 +536,7 @@ fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush) return playerScaling; } -UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush) +UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers) { if (mapobjectscale != FRACUNIT) { @@ -555,7 +555,7 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush) // Items get crazier with the fewer players that you have. distance = FixedMul( distance * FRACUNIT, - FRACUNIT + (K_ItemOddsScale(numPlayers, spbrush) / 2) + FRACUNIT + (K_ItemOddsScale(numPlayers) / 2) ) / FRACUNIT; } @@ -573,7 +573,7 @@ INT32 K_KartGetItemOdds( UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, - boolean spbrush, boolean bot, boolean rival) + boolean bot, boolean rival) { INT32 newodds; INT32 i; @@ -668,7 +668,7 @@ INT32 K_KartGetItemOdds( secondToFirst = K_ScaleItemDistance( players[second].distancetofinish - players[first].distancetofinish, - pingame, spbrush + pingame ); } @@ -787,7 +787,7 @@ INT32 K_KartGetItemOdds( fracOdds *= 2; } - fracOdds = FixedMul(fracOdds, FRACUNIT + K_ItemOddsScale(pingame, spbrush)); + fracOdds = FixedMul(fracOdds, FRACUNIT + K_ItemOddsScale(pingame)); if (mashed > 0) { @@ -803,7 +803,7 @@ INT32 K_KartGetItemOdds( //{ SRB2kart Roulette Code - Distance Based, yes waypoints -UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush) +UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper) { UINT8 i; UINT8 useodds = 0; @@ -831,7 +831,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum i, j, player->distancetofinish, mashed, - spbrush, player->bot, (player->bot && player->botvars.rival) + player->bot, (player->bot && player->botvars.rival) ) > 0) { available = true; @@ -910,7 +910,6 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) UINT8 bestbumper = 0; fixed_t mashed = 0; boolean dontforcespb = false; - boolean spbrush = false; // This makes the roulette cycle through items - if this is 0, you shouldn't be here. if (!player->itemroulette) @@ -983,14 +982,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } } - if (spbplace != -1 && player->position == spbplace+1) - { - // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell - pdis = (3 * pdis) / 2; - spbrush = true; - } - - pdis = K_ScaleItemDistance(pdis, pingame, spbrush); + pdis = K_ScaleItemDistance(pdis, pingame); if (player->bot && player->botvars.rival) { @@ -1125,7 +1117,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) spawnchance[i] = 0; // Split into another function for a debug function below - useodds = K_FindUseodds(player, mashed, pdis, bestbumper, spbrush); + useodds = K_FindUseodds(player, mashed, pdis, bestbumper); for (i = 1; i < NUMKARTRESULTS; i++) { @@ -1133,7 +1125,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) useodds, i, player->distancetofinish, mashed, - spbrush, player->bot, (player->bot && player->botvars.rival)) + player->bot, (player->bot && player->botvars.rival)) ); } @@ -6086,8 +6078,7 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 useodds, i, UINT32_MAX, 0, - false, false, false - ) + false, false) ); } diff --git a/src/k_kart.h b/src/k_kart.h index 7b1e0f6ae..6fc559929 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -41,10 +41,10 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value); extern consvar_t *KartItemCVars[NUMKARTRESULTS-1]; -UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush); -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); +UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper); +fixed_t K_ItemOddsScale(UINT8 numPlayers); +UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers); +INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean bot, boolean rival); INT32 K_GetShieldFromItem(INT32 item); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); From 986ca88f232f7b34a92575fb1c70cac22c676fae Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 02:44:24 -0400 Subject: [PATCH 06/51] Clean up SPB spawning conditions - Instead of basing it off of the item table, the extra chance is a raw bonus for the entire server. - Allow SPB to be forced onto the whoever happens to get an item the soonest, rather than only 2nd place. --- src/k_kart.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index ca198d885..f3c66be31 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -362,7 +362,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = /*Mine*/ { 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine /*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine /*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog - /*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb + /*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Self-Propelled Bomb /*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow /*Shrink*/ { 0, 0, 0, 0, 0, 1, 3, 2 }, // Shrink /*Lightning Shield*/ { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield @@ -416,8 +416,8 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] = }; #define DISTVAR (2048) // Magic number distance for use with item roulette tiers -#define SPBSTARTDIST (5*DISTVAR) // Distance when SPB is forced onto 2nd place -#define SPBFORCEDIST (15*DISTVAR) // Distance when SPB is forced onto 2nd place +#define SPBSTARTDIST (6*DISTVAR) // Distance when SPB is forced onto 2nd place +#define SPBFORCEDIST (12*DISTVAR) // Distance when SPB is forced onto 2nd place #define ENDDIST (12*DISTVAR) // Distance when the game stops giving you bananas // Array of states to pick the starting point of the animation, based on the actual time left for invincibility. @@ -456,7 +456,7 @@ INT32 K_GetShieldFromItem(INT32 item) */ static void K_KartGetItemResult(player_t *player, SINT8 getitem) { - if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) // Indirect items + if (getitem == KITEM_SPB) // Indirect items { indirectitemcooldown = 20*TICRATE; } @@ -581,8 +581,8 @@ INT32 K_KartGetItemOdds( UINT8 pingame = 0, pexiting = 0; SINT8 first = -1, second = -1; - UINT32 firstDist = UINT32_MAX; - UINT32 secondToFirst = UINT32_MAX; + UINT32 firstDist = 0; + UINT32 secondToFirst = 0; boolean powerItem = false; boolean cooldownOnStart = false; @@ -679,6 +679,7 @@ INT32 K_KartGetItemOdds( case KITEM_SUPERRING: notNearEnd = true; break; + case KITEM_ROCKETSNEAKER: case KITEM_JAWZ: case KITEM_LANDMINE: @@ -691,11 +692,13 @@ INT32 K_KartGetItemOdds( case KRITEM_DUALJAWZ: powerItem = true; break; + case KRITEM_TRIPLEBANANA: case KRITEM_TENFOLDBANANA: powerItem = true; notNearEnd = true; break; + case KITEM_INVINCIBILITY: case KITEM_MINE: case KITEM_GROW: @@ -704,40 +707,46 @@ INT32 K_KartGetItemOdds( cooldownOnStart = true; powerItem = true; break; + case KITEM_SPB: cooldownOnStart = true; indirectItem = true; notNearEnd = true; - if (firstDist < ENDDIST) // No SPB near the end of the race + if (firstDist < ENDDIST*2) // No SPB when 1st is almost done { newodds = 0; } else { - const INT32 distFromStart = max(0, (INT32)secondToFirst - SPBSTARTDIST); + const INT32 distFromStart = max(0, ((signed)secondToFirst) - SPBSTARTDIST); const INT32 distRange = SPBFORCEDIST - SPBSTARTDIST; - const INT32 mulMax = 3; - - INT32 multiplier = (distFromStart * mulMax) / distRange; + const UINT8 maxOdds = 10; + fixed_t multiplier = (distFromStart * FRACUNIT) / distRange; if (multiplier < 0) + { multiplier = 0; - if (multiplier > mulMax) - multiplier = mulMax; + } - newodds *= multiplier; + if (multiplier > FRACUNIT) + { + multiplier = FRACUNIT; + } + + newodds = FixedMul(maxOdds * 4 * FRACUNIT, multiplier) / FRACUNIT; } break; + case KITEM_SHRINK: cooldownOnStart = true; powerItem = true; - indirectItem = true; notNearEnd = true; if (pingame-1 <= pexiting) newodds = 0; break; + case KITEM_LIGHTNINGSHIELD: cooldownOnStart = true; powerItem = true; @@ -745,6 +754,7 @@ INT32 K_KartGetItemOdds( if (spbplace != -1) newodds = 0; break; + default: break; } @@ -1097,7 +1107,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // SPECIAL CASE No. 5: // Force SPB onto 2nd if they get too far behind - if ((gametyperules & GTR_CIRCUIT) && player->position == 2 && pdis > SPBFORCEDIST + if ((gametyperules & GTR_CIRCUIT) && pdis > SPBFORCEDIST && spbplace == -1 && !indirectitemcooldown && !dontforcespb && cv_selfpropelledbomb.value) { @@ -10342,10 +10352,10 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (spbplace == -1 || player->position != spbplace) player->pflags &= ~PF_RINGLOCK; // reset ring lock - if (player->itemtype == KITEM_SPB - || player->itemtype == KITEM_SHRINK - || player->growshrinktimer < 0) + if (player->itemtype == KITEM_SPB) + { indirectitemcooldown = 20*TICRATE; + } if (player->hyudorotimer > 0) { From 3c26a2f19b2f95cf7cffeeaf014d6e31e57f7ffb Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 02:49:37 -0400 Subject: [PATCH 07/51] Increase seeking speed --- src/objects/spb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index f968236d3..ff77649d8 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -28,7 +28,8 @@ #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) -#define SPB_DEFAULTSPEED (FixedMul(mapobjectscale, K_GetKartSpeedFromStat(5) * 2)) +#define SPB_DEFAULTSPEED (FixedMul(mapobjectscale, K_GetKartSpeedFromStat(9) * 2)) +#define SPB_ACTIVEDIST (1024 * FRACUNIT) enum { @@ -245,6 +246,7 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) waypoint_t *destWaypoint = NULL; fixed_t dist = INT32_MAX; + fixed_t activeDist = INT32_MAX; fixed_t destX = spb->x; fixed_t destY = spb->y; @@ -285,12 +287,14 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) spbplace = bestPlayer->position; dist = SPBDist(spb, spb_chase(spb)); + activeDist = FixedMul(SPB_ACTIVEDIST, spb_chase(spb)->scale); #ifdef SPB_SEEKTEST // Easy debug switch (void)dist; #else - if (dist <= (1024 * spb_chase(spb)->scale)) + if (dist <= activeDist) { + S_StopSound(spb); S_StartSound(spb, spb->info->attacksound); spb_mode(spb) = SPB_MODE_CHASE; // TARGET ACQUIRED spb_modetimer(spb) = 7*TICRATE; From dd94b1449e00d11dc43c3bffb29f1675aaa954c1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 07:05:26 -0400 Subject: [PATCH 08/51] Juicebox gates forward port for SPB --- src/d_player.h | 1 + src/deh_tables.c | 5 + src/info.c | 32 +++++ src/info.h | 7 + src/k_kart.c | 15 ++- src/k_objects.h | 4 + src/k_respawn.c | 1 + src/lua_playerlib.c | 6 + src/objects/Sourcefile | 1 + src/objects/manta-ring.c | 281 +++++++++++++++++++++++++++++++++++++++ src/objects/spb.c | 69 ++++++---- src/p_inter.c | 1 + src/p_mobj.c | 5 + src/p_saveg.c | 2 + src/sounds.c | 3 + src/sounds.h | 3 + 16 files changed, 410 insertions(+), 26 deletions(-) create mode 100644 src/objects/manta-ring.c diff --git a/src/d_player.h b/src/d_player.h index 7d0f20058..e467121a9 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -426,6 +426,7 @@ typedef struct player_s fixed_t driftcharge; // Charge your drift so you can release a burst of speed UINT8 driftboost; // (0 to 125) - Boost you get from drifting UINT8 strongdriftboost; // (0 to 125) - While active, boost from drifting gives a stronger speed increase + UINT16 gateBoost; // Juicebox Manta Ring boosts SINT8 aizdriftstrat; // (-1 to 1) - Let go of your drift while boosting? Helper for the SICK STRATZ (sliptiding!) you have just unlocked INT32 aizdrifttilt; diff --git a/src/deh_tables.c b/src/deh_tables.c index 2fb952890..99cbc8da0 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3651,6 +3651,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_SPB20", "S_SPB_DEAD", + // Juicebox for SPB + "S_MANTA1", + "S_MANTA2", + // Lightning Shield "S_LIGHTNINGSHIELD1", "S_LIGHTNINGSHIELD2", @@ -5353,6 +5357,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_SPB", // Self-Propelled Bomb "MT_SPBEXPLOSION", + "MT_MANTARING", // Juicebox for SPB "MT_LIGHTNINGSHIELD", // Shields "MT_BUBBLESHIELD", diff --git a/src/info.c b/src/info.c index 4a64fcb4a..e20340ee4 100644 --- a/src/info.c +++ b/src/info.c @@ -565,6 +565,8 @@ char sprnames[NUMSPRITES + 1][5] = "BHOG", // Ballhog "BHBM", // Ballhog BOOM "SPBM", // Self-Propelled Bomb + "TRIS", // SPB Manta Ring start + "TRNQ", // SPB Manta Ring loop "THNS", // Lightning Shield "BUBS", // Bubble Shield (not Bubs) "BWVE", // Bubble Shield waves @@ -4220,6 +4222,9 @@ state_t states[NUMSTATES] = {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB1}, // S_SPB20 {SPR_SPBM, 8, 175, {NULL}, 0, 0, S_NULL}, // S_SPB_DEAD + {SPR_TRIS, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_TRANS20|FF_ADD, 9, {NULL}, 2, 3, S_MANTA2}, // S_MANTA1 + {SPR_TRNQ, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_TRANS20|FF_ADD, -1, {NULL}, 11, 3, S_NULL}, // S_MANTA2 + {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD2}, // S_LIGHTNINGSHIELD1 {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD3}, // S_LIGHTNINGSHIELD2 {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD4}, // S_LIGHTNINGSHIELD3 @@ -23903,6 +23908,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_MANTARING + -1, // doomednum + S_MANTA1, // 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 + 64*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_LIGHTNINGSHIELD -1, // doomednum S_LIGHTNINGSHIELD1, // spawnstate diff --git a/src/info.h b/src/info.h index 6fe164c0e..ca3a4f298 100644 --- a/src/info.h +++ b/src/info.h @@ -1111,6 +1111,8 @@ typedef enum sprite SPR_BHOG, // Ballhog SPR_BHBM, // Ballhog BOOM SPR_SPBM, // Self-Propelled Bomb + SPR_TRIS, // SPB Manta Ring start + SPR_TRNQ, // SPB Manta Ring loop SPR_THNS, // Thunder Shield SPR_BUBS, // Bubble Shield (not Bubs) SPR_BWVE, // Bubble Shield waves @@ -4647,6 +4649,10 @@ typedef enum state S_SPB20, S_SPB_DEAD, + // Juicebox for SPB + S_MANTA1, + S_MANTA2, + // Thunder Shield S_LIGHTNINGSHIELD1, S_LIGHTNINGSHIELD2, @@ -6385,6 +6391,7 @@ typedef enum mobj_type MT_SPB, // SPB stuff MT_SPBEXPLOSION, + MT_MANTARING, // Juicebox for SPB MT_LIGHTNINGSHIELD, // Shields MT_BUBBLESHIELD, diff --git a/src/k_kart.c b/src/k_kart.c index f3c66be31..472da6130 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3186,7 +3186,7 @@ static void K_GetKartBoostPower(player_t *player) if (player->startboost) // Startup Boost { - ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling/2); // + 100% top speed, + 400% acceleration, +25% handling + ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling); // + 100% top speed, + 400% acceleration, +50% handling } if (player->driftboost) // Drift Boost @@ -3214,9 +3214,14 @@ static void K_GetKartBoostPower(player_t *player) ADDBOOST(player->trickboostpower, 5*FRACUNIT, 0); // % speed, 500% accel, 0% handling } + if (player->gateBoost) // SPB Juicebox boost + { + ADDBOOST(FRACUNIT/2, 4*FRACUNIT, sliptidehandling); // + 50% top speed, + 400% acceleration, +50% handling + } + if (player->ringboost) // Ring Boost { - ADDBOOST(FRACUNIT/5, 4*FRACUNIT, 0); // + 20% top speed, + 400% acceleration, +0% handling + ADDBOOST(FRACUNIT/4, 4*FRACUNIT, 0); // + 20% top speed, + 400% acceleration, +0% handling } if (player->eggmanexplode) // Ready-to-explode @@ -7329,7 +7334,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) // Speed lines if (player->sneakertimer || player->ringboost || player->driftboost || player->startboost - || player->eggmanexplode || player->trickboost) + || player->eggmanexplode || player->trickboost + || player->gateBoost) { #if 0 if (player->invincibilitytimer) @@ -7579,6 +7585,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->strongdriftboost) player->strongdriftboost--; + if (player->gateBoost) + player->gateBoost--; + if (player->startboost > 0 && onground == true) { player->startboost--; diff --git a/src/k_objects.h b/src/k_objects.h index 8936850f9..6ed87cbfe 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -23,4 +23,8 @@ fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz); /* SPB */ void Obj_SPBThink(mobj_t *spb); +/* SPB Juicebox Rings */ +void Obj_MantaRingThink(mobj_t *manta); +mobj_t *Obj_MantaRingCreate(mobj_t *spb, mobj_t *owner, mobj_t *chase); + #endif/*k_objects_H*/ diff --git a/src/k_respawn.c b/src/k_respawn.c index 9a8cc38e8..94bb04e18 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -151,6 +151,7 @@ void K_DoIngameRespawn(player_t *player) player->ringboost = 0; player->driftboost = player->strongdriftboost = 0; + player->gateBoost = 0; K_TumbleInterrupt(player); P_ResetPlayer(player); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index cfab3696e..07db592fb 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -250,6 +250,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->driftboost); else if (fastcmp(field,"strongdriftboost")) lua_pushinteger(L, plr->strongdriftboost); + else if (fastcmp(field,"gateBoost")) + lua_pushinteger(L, plr->gateBoost); else if (fastcmp(field,"aizdriftstraft")) lua_pushinteger(L, plr->aizdriftstrat); else if (fastcmp(field,"aizdrifttilt")) @@ -612,6 +614,10 @@ static int player_set(lua_State *L) plr->driftcharge = luaL_checkinteger(L, 3); else if (fastcmp(field,"driftboost")) plr->driftboost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"strongdriftboost")) + plr->strongdriftboost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"gateBoost")) + plr->gateBoost = luaL_checkinteger(L, 3); else if (fastcmp(field,"aizdriftstraft")) plr->aizdriftstrat = luaL_checkinteger(L, 3); else if (fastcmp(field,"aizdrifttilt")) diff --git a/src/objects/Sourcefile b/src/objects/Sourcefile index 7053e83cf..84e263f29 100644 --- a/src/objects/Sourcefile +++ b/src/objects/Sourcefile @@ -2,3 +2,4 @@ hyudoro.c shrink.c item-debris.c spb.c +manta-ring.c diff --git a/src/objects/manta-ring.c b/src/objects/manta-ring.c new file mode 100644 index 000000000..2a5ed538c --- /dev/null +++ b/src/objects/manta-ring.c @@ -0,0 +1,281 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2022 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file manta-ring.c +/// \brief SPB Juicebox rings. See spb.c for their spawning. + +#include "../doomdef.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../m_random.h" +#include "../p_local.h" +#include "../r_main.h" +#include "../s_sound.h" +#include "../g_game.h" +#include "../z_zone.h" +#include "../k_waypoint.h" +#include "../k_respawn.h" + +#define MANTA_RACETIME (90) +#define MANTA_MINTIME (15) +#define MANTA_SPRINTTIME (60) + +#define MANTA_ALIVEGATE (FF_TRANS40) +#define MANTA_DEADGATE (FF_TRANS80) + +#define MANTA_SIZE (2 * FRACUNIT) +#define MANTA_SIZEUP (10) +#define MANTA_SIZESTRENGTH (1500) +#define MANTA_MAXRAMP (80) + +#define MANTA_COLLIDE (80 * FRACUNIT) + +#define MANTA_TURBO (40) +#define MANTA_FASTRAMP (17) +#define MANTA_MINPWR (10) + +#define manta_delay(o) ((o)->fuse) +#define manta_timealive(o) ((o)->movecount) +#define manta_boostval(o) ((o)->extravalue1) +#define manta_laps(o) ((o)->extravalue2) +#define manta_touched(o) ((o)->cusval) + +#define manta_owner(o) ((o)->target) +#define manta_chase(o) ((o)->tracer) + +static boolean MantaAlreadyTouched(mobj_t *manta, player_t *player) +{ + INT32 touchFlag = 0; + + if (manta_chase(manta) != NULL && P_MobjWasRemoved(manta_chase(manta)) == false + && player->mo == manta_chase(manta)) + { + return true; + } + +#if 0 + if (manta_laps(manta) < player->laps) + { + return true; + } +#endif + + touchFlag = 1 << (player - players); + return (manta_touched(manta) & touchFlag); +} + +static void Obj_MantaCollide(mobj_t *manta, mobj_t *other) +{ + // Could hook this into actual mobj collide if desired. + fixed_t distance = INT32_MAX; + fixed_t size = INT32_MAX; + + INT32 addBoost = 0; + INT32 touchFlag = 0; + + distance = P_AproxDistance(P_AproxDistance( + other->x - manta->x, + other->y - manta->y), + other->z - manta->z) - other->radius - manta->radius; + + size = FixedMul(MANTA_COLLIDE, mapobjectscale); + + if (distance > size) + { + return; + } + + if (other->player != NULL) // Just in case other objects should be added? + { + if (MantaAlreadyTouched(manta, other->player)) + { + return; + } + + touchFlag = 1 << (other->player - players); + } + + addBoost = manta_boostval(manta); + + if (manta_timealive(manta) < MANTA_FASTRAMP) + { + // Ramp up to max power. + addBoost = FixedMul(addBoost * FRACUNIT, (manta_timealive(manta) * FRACUNIT) / MANTA_FASTRAMP); + + // Convert to integer + addBoost = (addBoost + (FRACUNIT/2)) / FRACUNIT; + + // Cap it + addBoost = max(MANTA_MINPWR, addBoost); + } + + S_StartSound(other, sfx_gatefx); + + if (other->player != NULL) + { + other->player->gateBoost += addBoost; + + if (P_IsDisplayPlayer(other->player) == true) + { + P_StartQuake(12 << FRACBITS, 6); + } + } + + if (touchFlag > 0) + { + manta_touched(manta) |= touchFlag; + } +} + +static void RunMantaCollide(mobj_t *manta) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *player = NULL; + + if (playeringame[i] == false) + { + // Invalid + continue; + } + + player = &players[i]; + if (player->spectator == true) + { + // Not playing. + continue; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + // Invalid object + continue; + } + + if (player->mo == manta_chase(manta)) + { + // Don't allow the person being chased to touch this. + continue; + } + + Obj_MantaCollide(manta, player->mo); + } +} + +static void RunMantaVisual(mobj_t *manta) +{ + INT32 i; + + if (manta->fuse < 5*TICRATE) + { + if (leveltime & 1) + { + manta->renderflags |= RF_DONTDRAW; + } + else + { + manta->renderflags &= ~RF_DONTDRAW; + } + } + + for (i = 0; i <= r_splitscreen; i++) + { + const UINT8 pID = displayplayers[i]; + player_t *player = &players[pID]; + + if (MantaAlreadyTouched(manta, player) == false) + { + break; + } + } + + if (i > r_splitscreen) + { + manta->frame = (manta->frame & ~FF_TRANSMASK) | MANTA_DEADGATE; + } + else + { + manta->frame = (manta->frame & ~FF_TRANSMASK) | MANTA_ALIVEGATE; + } +} + +void Obj_MantaRingThink(mobj_t *manta) +{ + RunMantaVisual(manta); + + if (manta_delay(manta) % MANTA_SIZEUP == 0) + { + manta->destscale += FixedMul(MANTA_SIZESTRENGTH, mapobjectscale); + manta_boostval(manta) = min(MANTA_MAXRAMP, manta_boostval(manta) + 1); + } + + manta_timealive(manta)++; + + RunMantaCollide(manta); +} + +mobj_t *Obj_MantaRingCreate(mobj_t *spb, mobj_t *owner, mobj_t *chase) +{ + mobj_t *manta = NULL; + INT32 delay = 0; + + manta = P_SpawnMobjFromMobj(spb, 0, 0, 0, MT_MANTARING); + + manta->color = SKINCOLOR_KETCHUP; + + manta->destscale = FixedMul(MANTA_SIZE, spb->scale); + P_SetScale(manta, manta->destscale); + + manta->angle = R_PointToAngle2(0, 0, spb->momx, spb->momy) + ANGLE_90; + + // Set boost value + manta_boostval(manta) = MANTA_TURBO; + + // Set despawn delay + delay = max(MANTA_MINTIME, MANTA_RACETIME / mapheaderinfo[gamemap - 1]->numlaps); + + if (mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) + { + delay = MANTA_SPRINTTIME; + } + + manta_delay(manta) = delay * TICRATE; + + // Default if neither object exists + manta_laps(manta) = INT32_MAX; + + // Set owner + if (owner != NULL && P_MobjWasRemoved(owner) == false) + { + P_SetTarget(&manta_owner(manta), owner); + + if (owner->player != NULL) + { + // Default if chaser doesn't exist + manta_laps(manta) = owner->player->laps; + } + } + + // Set chaser + if (chase != NULL && P_MobjWasRemoved(chase) == false) + { + P_SetTarget(&manta_chase(manta), chase); + + if (chase->player != NULL) + { + manta_laps(manta) = chase->player->laps; + } + } + + return manta; +} diff --git a/src/objects/spb.c b/src/objects/spb.c index ff77649d8..35d6f3aa5 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -24,13 +24,19 @@ #include "../k_waypoint.h" #include "../k_respawn.h" -//#define SPB_SEEKTEST +#define SPB_SEEKTEST #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) #define SPB_DEFAULTSPEED (FixedMul(mapobjectscale, K_GetKartSpeedFromStat(9) * 2)) #define SPB_ACTIVEDIST (1024 * FRACUNIT) +#define SPB_MANTA_SPACING (2750 * FRACUNIT) + +#define SPB_MANTA_VSTART (150) +#define SPB_MANTA_VRATE (60) +#define SPB_MANTA_VMAX (100) + enum { SPB_MODE_SEEK, @@ -48,25 +54,44 @@ enum #define spb_curwaypoint(o) ((o)->cusval) +#define spb_manta_vscale(o) ((o)->movecount) +#define spb_manta_totaldist(o) ((o)->reactiontime) + #define spb_owner(o) ((o)->target) #define spb_chase(o) ((o)->tracer) -static void SpawnSPBTrailRings(mobj_t *spb) +static void SPBMantaRings(mobj_t *spb) { - if (leveltime % (spb_mode(spb) != SPB_MODE_SEEK ? 6 : 3) == 0) + fixed_t vScale = INT32_MAX; + fixed_t spacing = INT32_MAX; + fixed_t finalDist = INT32_MAX; + + if (leveltime % SPB_MANTA_VRATE == 0) { - mobj_t *ring = P_SpawnMobjFromMobj(spb, - -FixedDiv(spb->momx, spb->scale), - -FixedDiv(spb->momy, spb->scale), - -FixedDiv(spb->momz, spb->scale) + (24*FRACUNIT), - MT_RING + spb_manta_vscale(spb) = max(spb_manta_vscale(spb) - 1, SPB_MANTA_VMAX); + } + + spacing = FixedMul(SPB_MANTA_SPACING, spb->scale); + spacing = FixedMul(spacing, K_GetKartGameSpeedScalar(gamespeed)); + + vScale = FixedDiv(spb_manta_vscale(spb) * FRACUNIT, 100 * FRACUNIT); + finalDist = FixedMul(spacing, vScale); + + spb_manta_totaldist(spb) += P_AproxDistance(spb->momx, spb->momy); + + if (spb_manta_totaldist(spb) > finalDist) + { + spb_manta_totaldist(spb) = 0; + + Obj_MantaRingCreate( + spb, + spb_owner(spb), +#ifdef SPB_SEEKTEST + NULL +#else + spb_chase(spb) +#endif ); - - ring->threshold = 10; - ring->fuse = 35*TICRATE; - - ring->colorized = true; - ring->color = SKINCOLOR_RED; } } @@ -291,6 +316,7 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) #ifdef SPB_SEEKTEST // Easy debug switch (void)dist; + (void)activeDist; #else if (dist <= activeDist) { @@ -322,7 +348,6 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) fixed_t waypointDist = INT32_MAX; fixed_t waypointRad = INT32_MAX; - CONS_Printf("Moving towards waypoint... (%d)\n", K_GetWaypointID(curWaypoint)); destX = curWaypoint->mobj->x; destY = curWaypoint->mobj->y; destZ = curWaypoint->mobj->z; @@ -353,17 +378,14 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) if (pathtoplayer.numnodes > 1) { curWaypoint = (waypoint_t *)pathtoplayer.array[1].nodedata; - CONS_Printf("NEW: Proper next waypoint (%d)\n", K_GetWaypointID(curWaypoint)); } else if (destWaypoint->numnextwaypoints > 0) { curWaypoint = destWaypoint->nextwaypoints[0]; - CONS_Printf("NEW: Forcing next waypoint (%d)\n", K_GetWaypointID(curWaypoint)); } else { curWaypoint = destWaypoint; - CONS_Printf("NEW: Forcing destination (%d)\n", K_GetWaypointID(curWaypoint)); } Z_Free(pathtoplayer.array); @@ -380,7 +402,6 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) } else { - CONS_Printf("FAILURE, no waypoint (pathfind unsuccessful)\n"); spb_curwaypoint(spb) = -1; destX = spb_chase(spb)->x; destY = spb_chase(spb)->y; @@ -390,7 +411,6 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) } else { - CONS_Printf("FAILURE, no waypoint (no initial waypoint)\n"); spb_curwaypoint(spb) = -1; destX = spb_chase(spb)->x; destY = spb_chase(spb)->y; @@ -462,7 +482,7 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) SpawnSPBSpeedLines(spb); // Spawn a trail of rings behind the SPB! - SpawnSPBTrailRings(spb); + SPBMantaRings(spb); } static void SPBChase(mobj_t *spb, player_t *bestPlayer) @@ -613,7 +633,7 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) spb->momy += cy; // Spawn a trail of rings behind the SPB! - SpawnSPBTrailRings(spb); + SPBMantaRings(spb); // Red speed lines for when it's gaining on its target. A tell for when you're starting to lose too much speed! if (R_PointToDist2(0, 0, spb->momx, spb->momy) > (16 * R_PointToDist2(0, 0, chase->momx, chase->momy)) / 15 // Going faster than the target @@ -695,11 +715,14 @@ void Obj_SPBThink(mobj_t *spb) if (spb_nothink(spb) > 0) { - // Doesn't think yet, when it initially spawns. + // Init values, don't think yet. spb_lastplayer(spb) = -1; spb_curwaypoint(spb) = -1; spbplace = -1; + spb_manta_totaldist(spb) = 0; // 30000? + spb_manta_vscale(spb) = SPB_MANTA_VSTART; + P_InstaThrust(spb, spb->angle, SPB_DEFAULTSPEED); spb_nothink(spb)--; diff --git a/src/p_inter.c b/src/p_inter.c index d21fb1195..38667b97b 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2060,6 +2060,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player->sneakertimer = player->numsneakers = 0; player->driftboost = player->strongdriftboost = 0; + player->gateBoost = 0; player->ringboost = 0; player->glanceDir = 0; player->pflags &= ~PF_LOOKDOWN; diff --git a/src/p_mobj.c b/src/p_mobj.c index 15a318c37..30c1ec0f2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6934,6 +6934,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_SPBThink(mobj); break; } + case MT_MANTARING: + { + Obj_MantaRingThink(mobj); + break; + } case MT_BALLHOG: { mobj_t *ghost = P_SpawnGhostMobj(mobj); diff --git a/src/p_saveg.c b/src/p_saveg.c index da85dac77..6640d7b51 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -261,6 +261,7 @@ static void P_NetArchivePlayers(void) WRITEFIXED(save_p, players[i].driftcharge); WRITEUINT8(save_p, players[i].driftboost); WRITEUINT8(save_p, players[i].strongdriftboost); + WRITEUINT16(save_p, players[i].gateBoost); WRITESINT8(save_p, players[i].aizdriftstrat); WRITEINT32(save_p, players[i].aizdrifttilt); @@ -552,6 +553,7 @@ static void P_NetUnArchivePlayers(void) players[i].driftcharge = READFIXED(save_p); players[i].driftboost = READUINT8(save_p); players[i].strongdriftboost = READUINT8(save_p); + players[i].gateBoost = READUINT16(save_p); players[i].aizdriftstrat = READSINT8(save_p); players[i].aizdrifttilt = READINT32(save_p); diff --git a/src/sounds.c b/src/sounds.c index 1cff40633..c7e3773c1 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1118,6 +1118,9 @@ sfxinfo_t S_sfx[NUMSFX] = // Shrink laser beam {"beam01", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // Juicebox for SPB + {"gatefx", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // SRB2Kart - Engine sounds // Engine class A {"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""}, diff --git a/src/sounds.h b/src/sounds.h index cb9d3b671..33de228b4 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1183,6 +1183,9 @@ typedef enum // Shrink laser sfx_beam01, + // Juicebox for SPB + sfx_gatefx, + // Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy... // Engine class A - Low Speed, Low Weight sfx_krta00, From eaf232302f695eae776253934651b0d604b5dd07 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 07:12:16 -0400 Subject: [PATCH 09/51] Turn off the seek test --- src/objects/spb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index 35d6f3aa5..31963b037 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -24,7 +24,7 @@ #include "../k_waypoint.h" #include "../k_respawn.h" -#define SPB_SEEKTEST +//#define SPB_SEEKTEST #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) From a790ffee79fafae7f554e87297dabe2dac16e492 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 11:51:16 -0400 Subject: [PATCH 10/51] The little SPB tweaks - Explosion strength scales with how long you've been outrunning it. 0 seconds is even more punishing than it was before, while surviving 60+ seconds converts the damage into minimal stumble. - When it starts properly chasing a new target, it will be intangible for 1 second - Hot potato takes 2 seconds instead of 7 - Too much hot potato will make it run ahead & explode (untested) --- src/k_kart.c | 93 ++++++++++++++++----------- src/k_objects.h | 2 + src/objects/spb.c | 158 ++++++++++++++++++++++++++++++++++++++++++---- src/p_inter.c | 35 +--------- src/p_mobj.c | 5 ++ 5 files changed, 213 insertions(+), 80 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 4602f1b21..ad8790573 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3820,10 +3820,38 @@ angle_t K_StumbleSlope(angle_t angle, angle_t pitch, angle_t roll) return slope; } +static void K_StumblePlayer(player_t *player) +{ + P_ResetPlayer(player); + +#if 0 + // Single, medium bounce + player->tumbleBounces = TUMBLEBOUNCES; + player->tumbleHeight = 30; +#else + // Two small bounces + player->tumbleBounces = TUMBLEBOUNCES-1; + player->tumbleHeight = 20; +#endif + + player->pflags &= ~PF_TUMBLESOUND; + S_StartSound(player->mo, sfx_s3k9b); + + // and then modulate momz like that... + player->mo->momz = K_TumbleZ(player->mo, player->tumbleHeight * FRACUNIT); + + P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); + + if (P_IsDisplayPlayer(player)) + P_StartQuake(64<mo->pitch = player->mo->roll = 0; +} + boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir) { angle_t steepVal = ANGLE_MAX; - fixed_t gravityadjust; angle_t oldSlope, newSlope; angle_t slopeDelta; @@ -3873,36 +3901,7 @@ 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; - 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; + K_StumblePlayer(player); return true; } @@ -4136,23 +4135,45 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state) INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer { INT32 ringburst = 10; + fixed_t spbMultiplier = FRACUNIT; (void)source; K_DirectorFollowAttack(player, inflictor, source); - player->mo->momz = 18*mapobjectscale*P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!! + if (inflictor != NULL && P_MobjWasRemoved(inflictor) == false) + { + if (inflictor->type == MT_SPBEXPLOSION && inflictor->movefactor) + { + spbMultiplier = inflictor->movefactor; + + if (spbMultiplier <= 0) + { + // Convert into stumble. + K_StumblePlayer(player); + return 0; + } + else if (spbMultiplier < FRACUNIT) + { + spbMultiplier = FRACUNIT; + } + } + } + + player->mo->momz = 18 * mapobjectscale * P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!! player->mo->momx = player->mo->momy = 0; player->spinouttype = KSPIN_EXPLOSION; player->spinouttimer = (3*TICRATE/2)+2; - if (inflictor && !P_MobjWasRemoved(inflictor)) + if (spbMultiplier != FRACUNIT) { - if (inflictor->type == MT_SPBEXPLOSION && inflictor->extravalue1) + player->mo->momz = FixedMul(player->mo->momz, spbMultiplier); + player->spinouttimer = FixedMul(player->spinouttimer, spbMultiplier + ((spbMultiplier - FRACUNIT) / 2)); + + ringburst = FixedMul(ringburst * FRACUNIT, spbMultiplier) / FRACUNIT; + if (ringburst > 20) { - player->spinouttimer = ((5*player->spinouttimer)/2)+1; - player->mo->momz *= 2; ringburst = 20; } } diff --git a/src/k_objects.h b/src/k_objects.h index 6ed87cbfe..d39da4247 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -22,6 +22,8 @@ fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz); /* SPB */ void Obj_SPBThink(mobj_t *spb); +void Obj_SPBExplode(mobj_t *spb); +void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher); /* SPB Juicebox Rings */ void Obj_MantaRingThink(mobj_t *manta); diff --git a/src/objects/spb.c b/src/objects/spb.c index 31963b037..49db1841c 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -24,13 +24,20 @@ #include "../k_waypoint.h" #include "../k_respawn.h" -//#define SPB_SEEKTEST +#define SPB_SEEKTEST #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) #define SPB_DEFAULTSPEED (FixedMul(mapobjectscale, K_GetKartSpeedFromStat(9) * 2)) #define SPB_ACTIVEDIST (1024 * FRACUNIT) +#define SPB_HOTPOTATO (2*TICRATE) +#define SPB_MAXSWAPS (2) +#define SPB_FLASHING (TICRATE) + +#define SPB_CHASETIMESCALE (60*TICRATE) +#define SPB_CHASETIMEMUL (3*FRACUNIT) + #define SPB_MANTA_SPACING (2750 * FRACUNIT) #define SPB_MANTA_VSTART (150) @@ -48,10 +55,15 @@ enum #define spb_modetimer(o) ((o)->extravalue2) #define spb_nothink(o) ((o)->threshold) +#define spb_intangible(o) ((o)->cvmem) + #define spb_lastplayer(o) ((o)->lastlook) #define spb_speed(o) ((o)->movefactor) #define spb_pitch(o) ((o)->movedir) +#define spb_chasetime(o) ((o)->watertop) // running out of variables here... +#define spb_swapcount(o) ((o)->health) + #define spb_curwaypoint(o) ((o)->cusval) #define spb_manta_vscale(o) ((o)->movecount) @@ -318,14 +330,31 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) (void)dist; (void)activeDist; #else - if (dist <= activeDist) + if (spb_swapcount(spb) > SPB_MAXSWAPS + 1) { - S_StopSound(spb); - S_StartSound(spb, spb->info->attacksound); - spb_mode(spb) = SPB_MODE_CHASE; // TARGET ACQUIRED - spb_modetimer(spb) = 7*TICRATE; - spb_speed(spb) = desiredSpeed; - return; + // Too much hot potato. + // Go past our target and explode instead. + if (spb->fuse == 0) + { + spb->fuse = 2*TICRATE; + } + } + else + { + if (dist <= activeDist) + { + S_StopSound(spb); + S_StartSound(spb, spb->info->attacksound); + + spb_mode(spb) = SPB_MODE_CHASE; // TARGET ACQUIRED + spb_swapcount(spb)++; + + spb_modetimer(spb) = SPB_HOTPOTATO; + spb_intangible(spb) = SPB_FLASHING; + + spb_speed(spb) = desiredSpeed; + return; + } } #endif @@ -379,10 +408,12 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) { curWaypoint = (waypoint_t *)pathtoplayer.array[1].nodedata; } - else if (destWaypoint->numnextwaypoints > 0) +#if 0 + else if (spb->fuse > 0 && destWaypoint->numnextwaypoints > 0) { curWaypoint = destWaypoint->nextwaypoints[0]; } +#endif else { curWaypoint = destWaypoint; @@ -522,6 +553,9 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) return; } + // Increment chase time + spb_chasetime(spb)++; + baseSpeed = SPB_DEFAULTSPEED; range = (160 * chase->scale); @@ -570,7 +604,7 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) // Switch targets if you're no longer 1st for long enough if (bestPlayer != NULL && chasePlayer->position <= bestPlayer->position) { - spb_modetimer(spb) = 7*TICRATE; + spb_modetimer(spb) = SPB_HOTPOTATO; } else { @@ -582,6 +616,7 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) if (spb_modetimer(spb) <= 0) { spb_mode(spb) = SPB_MODE_SEEK; // back to SEEKING + spb_intangible(spb) = SPB_FLASHING; } } } @@ -677,7 +712,8 @@ static void SPBWait(mobj_t *spb) { P_SetTarget(&spb_chase(spb), oldPlayer->mo); spb_mode(spb) = SPB_MODE_CHASE; - spb_modetimer(spb) = 7*TICRATE; + spb_modetimer(spb) = SPB_HOTPOTATO; + spb_intangible(spb) = SPB_FLASHING; spb_speed(spb) = SPB_DEFAULTSPEED; } } @@ -685,6 +721,7 @@ static void SPBWait(mobj_t *spb) { spb_mode(spb) = SPB_MODE_SEEK; spb_modetimer(spb) = 0; + spb_intangible(spb) = SPB_FLASHING; spbplace = -1; } } @@ -718,6 +755,7 @@ void Obj_SPBThink(mobj_t *spb) // Init values, don't think yet. spb_lastplayer(spb) = -1; spb_curwaypoint(spb) = -1; + spb_chasetime(spb) = 0; spbplace = -1; spb_manta_totaldist(spb) = 0; // 30000? @@ -792,6 +830,36 @@ void Obj_SPBThink(mobj_t *spb) } } + // Flash on/off when intangible. + if (spb_intangible(spb) > 0) + { + spb_intangible(spb)--; + + if (spb_intangible(spb) & 1) + { + spb->renderflags |= RF_DONTDRAW; + } + else + { + spb->renderflags &= ~RF_DONTDRAW; + } + } + + // Flash white when about to explode! + if (spb->fuse > 0) + { + if (spb->fuse & 1) + { + spb->color = SKINCOLOR_INVINCFLASH; + spb->colorized = true; + } + else + { + spb->color = SKINCOLOR_NONE; + spb->colorized = false; + } + } + // Clamp within level boundaries. if (spb->z < spb->floorz) { @@ -802,3 +870,71 @@ void Obj_SPBThink(mobj_t *spb) spb->z = spb->ceilingz - spb->height; } } + +void Obj_SPBExplode(mobj_t *spb) +{ + mobj_t *spbExplode = NULL; + + // Don't continue playing the gurgle or the siren + S_StopSound(spb); + + spbExplode = P_SpawnMobjFromMobj(spb, 0, 0, 0, MT_SPBEXPLOSION); + + if (spb_owner(spb) != NULL && P_MobjWasRemoved(spb_owner(spb)) == false) + { + P_SetTarget(&spbExplode->target, spb_owner(spb)); + } + + // Tell the explosion to use alternate knockback. + spbExplode->movefactor = ((SPB_CHASETIMESCALE - spb_chasetime(spb)) * SPB_CHASETIMEMUL) / SPB_CHASETIMESCALE; + + P_RemoveMobj(spb); +} + +void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher) +{ + player_t *player = toucher->player; + + if (spb_intangible(spb) > 0) + { + return; + } + + if ((spb_owner(spb) == toucher || spb_owner(spb) == toucher->target) + && (spb_nothink(spb) > 0)) + { + return; + } + + if (spb->health <= 0 || toucher->health <= 0) + { + return; + } + + if (player->spectator == true) + { + return; + } + + if (player->bubbleblowup > 0) + { + // Stun the SPB, and remove the shield. + K_DropHnextList(player, false); + spb_mode(spb) = SPB_MODE_WAIT; + spb_modetimer(spb) = 55; // Slightly over the respawn timer length + return; + } + + if (spb_chase(spb) != NULL && P_MobjWasRemoved(spb_chase(spb)) == false + && toucher == spb_chase(spb)) + { + // Cause the explosion. + Obj_SPBExplode(spb); + return; + } + else + { + // Regular spinout, please. + P_DamageMobj(toucher, spb, spb_owner(spb), 1, DMG_NORMAL); + } +} diff --git a/src/p_inter.c b/src/p_inter.c index 38667b97b..5513064f0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -352,41 +352,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } return; case MT_SPB: - if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0)) - return; - - if (special->health <= 0 || toucher->health <= 0) - return; - - if (player->spectator) - return; - - if (special->tracer && !P_MobjWasRemoved(special->tracer) && toucher == special->tracer) { - mobj_t *spbexplode; - - if (player->bubbleblowup > 0) - { - K_DropHnextList(player, false); - special->extravalue1 = 2; // WAIT... - special->extravalue2 = 52; // Slightly over the respawn timer length - return; - } - - S_StopSound(special); // Don't continue playing the gurgle or the siren - - spbexplode = P_SpawnMobj(toucher->x, toucher->y, toucher->z, MT_SPBEXPLOSION); - spbexplode->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback - if (special->target && !P_MobjWasRemoved(special->target)) - P_SetTarget(&spbexplode->target, special->target); - - P_RemoveMobj(special); + Obj_SPBTouch(special, toucher); + return; } - else - { - P_DamageMobj(player->mo, special, special->target, 1, DMG_NORMAL); - } - return; case MT_EMERALD: if (!P_CanPickupItem(player, 0)) return; diff --git a/src/p_mobj.c b/src/p_mobj.c index b9dd4a4cc..ab37b2e7c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6269,6 +6269,11 @@ static void P_MobjSceneryThink(mobj_t *mobj) case MT_DRIFTELECTRICSPARK: mobj->renderflags ^= RF_DONTDRAW; break; + case MT_SPB: + { + Obj_SPBExplode(mobj); + return; + } case MT_VWREF: case MT_VWREB: { From f4dddf0385b0895ab7c3dd326193afb93d00c403 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 11:59:59 -0400 Subject: [PATCH 11/51] Properly run ahead in fuse state --- src/objects/spb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index 49db1841c..b99f7c371 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -406,16 +406,17 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) { if (pathtoplayer.numnodes > 1) { + // Go to next. curWaypoint = (waypoint_t *)pathtoplayer.array[1].nodedata; } -#if 0 else if (spb->fuse > 0 && destWaypoint->numnextwaypoints > 0) { + // Run ahead. curWaypoint = destWaypoint->nextwaypoints[0]; } -#endif else { + // Sort of wait at the player's dest waypoint. curWaypoint = destWaypoint; } From d7ce973aaf596b22229cd42f506929b504d37c49 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 12:23:42 -0400 Subject: [PATCH 12/51] Only spawn gates when SPB is close to the ground --- src/objects/spb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index b99f7c371..4ac06b9ee 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -78,6 +78,9 @@ static void SPBMantaRings(mobj_t *spb) fixed_t spacing = INT32_MAX; fixed_t finalDist = INT32_MAX; + const fixed_t floatHeight = 24 * spb->scale; + fixed_t floorDist = INT32_MAX; + if (leveltime % SPB_MANTA_VRATE == 0) { spb_manta_vscale(spb) = max(spb_manta_vscale(spb) - 1, SPB_MANTA_VMAX); @@ -89,9 +92,12 @@ static void SPBMantaRings(mobj_t *spb) vScale = FixedDiv(spb_manta_vscale(spb) * FRACUNIT, 100 * FRACUNIT); finalDist = FixedMul(spacing, vScale); + floorDist = abs(P_GetMobjFeet(spb) - P_GetMobjGround(spb)); + spb_manta_totaldist(spb) += P_AproxDistance(spb->momx, spb->momy); - if (spb_manta_totaldist(spb) > finalDist) + if (spb_manta_totaldist(spb) > finalDist + && floorDist <= floatHeight) { spb_manta_totaldist(spb) = 0; From f02b67eae624bba61fa1ae9ebae021dc1ba830a5 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 14:57:33 -0400 Subject: [PATCH 13/51] Add seeking sounds --- src/objects/spb.c | 30 +++++++++++++++++++++++++----- src/sounds.c | 5 +++++ src/sounds.h | 5 +++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index 4ac06b9ee..39c33bdf7 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -281,6 +281,13 @@ static void SetSPBSpeed(mobj_t *spb, fixed_t xySpeed, fixed_t zSpeed) ); } +static boolean SPBSeekSoundPlaying(mobj_t *spb) +{ + return (S_SoundPlaying(spb, sfx_spbska) + || S_SoundPlaying(spb, sfx_spbskb) + || S_SoundPlaying(spb, sfx_spbskc)); +} + static void SPBSeek(mobj_t *spb, player_t *bestPlayer) { const fixed_t desiredSpeed = SPB_DEFAULTSPEED; @@ -332,10 +339,6 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) dist = SPBDist(spb, spb_chase(spb)); activeDist = FixedMul(SPB_ACTIVEDIST, spb_chase(spb)->scale); -#ifdef SPB_SEEKTEST // Easy debug switch - (void)dist; - (void)activeDist; -#else if (spb_swapcount(spb) > SPB_MAXSWAPS + 1) { // Too much hot potato. @@ -347,6 +350,7 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) } else { +#ifndef SPB_SEEKTEST // Easy debug switch if (dist <= activeDist) { S_StopSound(spb); @@ -361,8 +365,24 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) spb_speed(spb) = desiredSpeed; return; } - } #endif + } + + if (SPBSeekSoundPlaying(spb) == false) + { + if (dist <= activeDist * 3) + { + S_StartSound(spb, sfx_spbskc); + } + else if (dist <= activeDist * 6) + { + S_StartSound(spb, sfx_spbskb); + } + else + { + S_StartSound(spb, sfx_spbska); + } + } // Move along the waypoints until you get close enough if (spb_curwaypoint(spb) == -1) diff --git a/src/sounds.c b/src/sounds.c index c7e3773c1..6feb0b6ca 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1118,6 +1118,11 @@ sfxinfo_t S_sfx[NUMSFX] = // Shrink laser beam {"beam01", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // SPB seeking + {"spbska", false, 32, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"spbskb", false, 32, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"spbskc", false, 32, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // Juicebox for SPB {"gatefx", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, diff --git a/src/sounds.h b/src/sounds.h index 33de228b4..0f7fde60e 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1183,6 +1183,11 @@ typedef enum // Shrink laser sfx_beam01, + // SPB seeking + sfx_spbska, + sfx_spbskb, + sfx_spbskc, + // Juicebox for SPB sfx_gatefx, From 9fa46547760def0b13957357d6d2ccacb80ba667 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 17:23:55 -0400 Subject: [PATCH 14/51] Turn off seek test again --- src/objects/spb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index 39c33bdf7..d22dbe49c 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -24,7 +24,7 @@ #include "../k_waypoint.h" #include "../k_respawn.h" -#define SPB_SEEKTEST +//#define SPB_SEEKTEST #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) From f3742bad9d180527e8c3051343edb00ac3d978ef Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 19:02:38 -0400 Subject: [PATCH 15/51] Safe-guard SPB from 1st place --- src/k_kart.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 7024c8162..b4ce811e6 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -584,6 +584,7 @@ INT32 K_KartGetItemOdds( SINT8 first = -1, second = -1; UINT32 firstDist = 0; UINT32 secondToFirst = 0; + boolean isFirst = false; boolean powerItem = false; boolean cooldownOnStart = false; @@ -658,19 +659,24 @@ INT32 K_KartGetItemOdds( } } - if (first != -1 && second != -1) // calculate 2nd's distance from 1st, for SPB + if (first != -1) // calculate 2nd's distance from 1st, for SPB { firstDist = players[first].distancetofinish; + isFirst = (ourDist <= firstDist); + if (mapobjectscale != FRACUNIT) { firstDist = FixedDiv(firstDist * FRACUNIT, mapobjectscale) / FRACUNIT; } - secondToFirst = K_ScaleItemDistance( - players[second].distancetofinish - players[first].distancetofinish, - pingame - ); + if (second != -1) + { + secondToFirst = K_ScaleItemDistance( + players[second].distancetofinish - players[first].distancetofinish, + pingame + ); + } } switch (item) @@ -714,7 +720,8 @@ INT32 K_KartGetItemOdds( indirectItem = true; notNearEnd = true; - if (firstDist < ENDDIST*2) // No SPB when 1st is almost done + if (firstDist < ENDDIST*2 // No SPB when 1st is almost done + || isFirst == true) // No SPB for 1st ever { newodds = 0; } @@ -1108,8 +1115,12 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // SPECIAL CASE No. 5: // Force SPB onto 2nd if they get too far behind - if ((gametyperules & GTR_CIRCUIT) && pdis > SPBFORCEDIST - && spbplace == -1 && !indirectitemcooldown && !dontforcespb + if ((gametyperules & GTR_CIRCUIT) + && player->position > 1 + && pdis > SPBFORCEDIST + && spbplace == -1 + && !indirectitemcooldown + && !dontforcespb && cv_selfpropelledbomb.value) { K_KartGetItemResult(player, KITEM_SPB); From 34aa00ab0d2d234c5a3e595f075ce52de19d9045 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 19:48:57 -0400 Subject: [PATCH 16/51] Fix drop target cvars & debug distribution --- src/k_hud.c | 2 +- src/k_kart.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 27deb7211..a51f0fa1f 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4530,7 +4530,6 @@ static void K_drawDistributionDebugger(void) kp_jawz[1], kp_mine[1], kp_landmine[1], - kp_droptarget[1], kp_ballhog[1], kp_selfpropelledbomb[1], kp_grow[1], @@ -4542,6 +4541,7 @@ static void K_drawDistributionDebugger(void) kp_pogospring[1], kp_superring[1], kp_kitchensink[1], + kp_droptarget[1], kp_sneaker[1], kp_sneaker[1], diff --git a/src/k_kart.c b/src/k_kart.c index b4ce811e6..ed5434e46 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -326,7 +326,6 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = &cv_jawz, &cv_mine, &cv_landmine, - &cv_droptarget, &cv_ballhog, &cv_selfpropelledbomb, &cv_grow, @@ -338,6 +337,7 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = &cv_pogospring, &cv_superring, &cv_kitchensink, + &cv_droptarget, &cv_dualsneaker, &cv_triplesneaker, &cv_triplebanana, From 47293d1d9f0e6b258b4a5d5312574617a7b2e1a2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 21 Sep 2022 21:02:05 -0400 Subject: [PATCH 17/51] Improve debug distribution, rebalance SPB spawning Might be too far in the other direction, we'll see --- src/k_hud.c | 15 +++-- src/k_kart.c | 159 ++++++++++++++++++++++++++++++++++++--------------- src/k_kart.h | 1 + 3 files changed, 124 insertions(+), 51 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index a51f0fa1f..609ddaaf8 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4560,6 +4560,13 @@ static void K_drawDistributionDebugger(void) if (stplyr != &players[displayplayers[0]]) // only for p1 return; + if (K_ForcedSPB(stplyr) == true) + { + V_DrawScaledPatch(x, y, V_SNAPTOTOP, items[KITEM_SPB]); + V_DrawThinString(x+11, y+31, V_ALLOWLOWERCASE|V_SNAPTOTOP, "EX"); + return; + } + // The only code duplication from the Kart, just to avoid the actual item function from calculating pingame twice for (i = 0; i < MAXPLAYERS; i++) { @@ -4604,8 +4611,8 @@ static void K_drawDistributionDebugger(void) if (itemodds <= 0) continue; - V_DrawScaledPatch(x, y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, items[i]); - V_DrawThinString(x+11, y+31, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, va("%d", itemodds)); + V_DrawScaledPatch(x, y, V_SNAPTOTOP, items[i]); + V_DrawThinString(x+11, y+31, V_SNAPTOTOP, va("%d", itemodds)); // Display amount for multi-items if (i >= NUMKARTITEMS) @@ -4629,7 +4636,7 @@ static void K_drawDistributionDebugger(void) amount = 3; break; } - V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, va("x%d", amount)); + V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("x%d", amount)); } x += 32; @@ -4640,7 +4647,7 @@ static void K_drawDistributionDebugger(void) } } - V_DrawString(0, 0, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, va("USEODDS %d", useodds)); + V_DrawString(0, 0, V_SNAPTOTOP, va("USEODDS %d", useodds)); } static void K_drawCheckpointDebugger(void) diff --git a/src/k_kart.c b/src/k_kart.c index ed5434e46..5c9369387 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -417,8 +417,8 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] = }; #define DISTVAR (2048) // Magic number distance for use with item roulette tiers -#define SPBSTARTDIST (6*DISTVAR) // Distance when SPB is forced onto 2nd place -#define SPBFORCEDIST (12*DISTVAR) // Distance when SPB is forced onto 2nd place +#define SPBSTARTDIST (10*DISTVAR) // Distance when SPB can start appearing +#define SPBFORCEDIST (20*DISTVAR) // Distance when SPB is forced onto the next person who rolls an item #define ENDDIST (12*DISTVAR) // Distance when the game stops giving you bananas // Array of states to pick the starting point of the animation, based on the actual time left for invincibility. @@ -542,7 +542,7 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers) if (mapobjectscale != FRACUNIT) { // Bring back to normal scale. - distance = FixedDiv(distance * FRACUNIT, mapobjectscale) / FRACUNIT; + distance = FixedDiv(distance, mapobjectscale); } if (franticitems == true) @@ -555,9 +555,9 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers) { // Items get crazier with the fewer players that you have. distance = FixedMul( - distance * FRACUNIT, + distance, FRACUNIT + (K_ItemOddsScale(numPlayers) / 2) - ) / FRACUNIT; + ); } return distance; @@ -581,8 +581,11 @@ INT32 K_KartGetItemOdds( UINT8 pingame = 0, pexiting = 0; - SINT8 first = -1, second = -1; - UINT32 firstDist = 0; + player_t *first = NULL; + player_t *second = NULL; + + UINT32 firstDist = UINT32_MAX; + UINT32 secondDist = UINT32_MAX; UINT32 secondToFirst = 0; boolean isFirst = false; @@ -650,33 +653,32 @@ INT32 K_KartGetItemOdds( return 0; } - if (players[i].mo && gametype == GT_RACE) + if (players[i].position == 1) { - if (players[i].position == 1 && first == -1) - first = i; - if (players[i].position == 2 && second == -1) - second = i; + first = &players[i]; + } + + if (players[i].position == 2) + { + second = &players[i]; } } - if (first != -1) // calculate 2nd's distance from 1st, for SPB + if (first != NULL) // calculate 2nd's distance from 1st, for SPB { - firstDist = players[first].distancetofinish; - + firstDist = first->distancetofinish; isFirst = (ourDist <= firstDist); + } - if (mapobjectscale != FRACUNIT) - { - firstDist = FixedDiv(firstDist * FRACUNIT, mapobjectscale) / FRACUNIT; - } + if (second != NULL) + { + secondDist = second->distancetofinish; + } - if (second != -1) - { - secondToFirst = K_ScaleItemDistance( - players[second].distancetofinish - players[first].distancetofinish, - pingame - ); - } + if (first != NULL && second != NULL) + { + secondToFirst = secondDist - firstDist; + secondToFirst = K_ScaleItemDistance(secondToFirst, pingame); } switch (item) @@ -727,10 +729,10 @@ INT32 K_KartGetItemOdds( } else { - const INT32 distFromStart = max(0, ((signed)secondToFirst) - SPBSTARTDIST); - const INT32 distRange = SPBFORCEDIST - SPBSTARTDIST; - const UINT8 maxOdds = 10; - fixed_t multiplier = (distFromStart * FRACUNIT) / distRange; + const UINT32 dist = max(0, ((signed)secondToFirst) - SPBSTARTDIST); + const UINT32 distRange = SPBFORCEDIST - SPBSTARTDIST; + const UINT8 maxOdds = 20; + fixed_t multiplier = (dist * FRACUNIT) / distRange; if (multiplier < 0) { @@ -742,7 +744,7 @@ INT32 K_KartGetItemOdds( multiplier = FRACUNIT; } - newodds = FixedMul(maxOdds * 4 * FRACUNIT, multiplier) / FRACUNIT; + newodds = FixedMul(maxOdds * 4, multiplier); } break; @@ -916,6 +918,80 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum return useodds; } +boolean K_ForcedSPB(player_t *player) +{ + player_t *first = NULL; + player_t *second = NULL; + UINT32 secondToFirst = UINT32_MAX; + UINT8 pingame = 0; + UINT8 i; + + if (!cv_selfpropelledbomb.value) + { + return false; + } + + if (!(gametyperules & GTR_CIRCUIT)) + { + return false; + } + + if (player->position <= 1) + { + return false; + } + + if (spbplace != -1) + { + return false; + } + + if (indirectitemcooldown > 0) + { + return false; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + { + continue; + } + + if (players[i].exiting) + { + return false; + } + + pingame++; + + if (players[i].position == 1) + { + first = &players[i]; + } + + if (players[i].position == 2) + { + second = &players[i]; + } + } + +#if 0 + if (pingame <= 2) + { + return false; + } +#endif + + if (first != NULL && second != NULL) + { + secondToFirst = second->distancetofinish - first->distancetofinish; + secondToFirst = K_ScaleItemDistance(secondToFirst, pingame); + } + + return (secondToFirst >= SPBFORCEDIST); +} + static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) { INT32 i; @@ -927,7 +1003,6 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) INT32 totalspawnchance = 0; UINT8 bestbumper = 0; fixed_t mashed = 0; - boolean dontforcespb = false; // This makes the roulette cycle through items - if this is 0, you shouldn't be here. if (!player->itemroulette) @@ -939,17 +1014,13 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) { if (!playeringame[i] || players[i].spectator) continue; + pingame++; - if (players[i].exiting) - dontforcespb = true; + if (players[i].bumpers > bestbumper) bestbumper = players[i].bumpers; } - // No forced SPB in 1v1s, it has to be randomly rolled - if (pingame <= 2) - dontforcespb = true; - // This makes the roulette produce the random noises. if ((player->itemroulette % 3) == 1 && P_IsDisplayPlayer(player) && !demo.freecam) { @@ -1114,14 +1185,8 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } // SPECIAL CASE No. 5: - // Force SPB onto 2nd if they get too far behind - if ((gametyperules & GTR_CIRCUIT) - && player->position > 1 - && pdis > SPBFORCEDIST - && spbplace == -1 - && !indirectitemcooldown - && !dontforcespb - && cv_selfpropelledbomb.value) + // Force SPB if 2nd is way too far behind + if (K_ForcedSPB(player) == true) { K_KartGetItemResult(player, KITEM_SPB); player->karthud[khud_itemblink] = TICRATE; @@ -9324,7 +9389,7 @@ static INT32 K_FlameShieldMax(player_t *player) } disttofinish = player->distancetofinish - disttofinish; - distv = FixedMul(distv * FRACUNIT, mapobjectscale) / FRACUNIT; + distv = FixedMul(distv, mapobjectscale); return min(16, 1 + (disttofinish / distv)); } diff --git a/src/k_kart.h b/src/k_kart.h index 9138997c5..6655ec034 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); UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers); INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean bot, boolean rival); +boolean K_ForcedSPB(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); From b9ecb9ccc8c79988b0255e8fe734527bac7ec218 Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Wed, 21 Sep 2022 22:01:09 -0400 Subject: [PATCH 18/51] Reduced SPB distances again --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 5c9369387..c8847ff31 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -417,8 +417,8 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] = }; #define DISTVAR (2048) // Magic number distance for use with item roulette tiers -#define SPBSTARTDIST (10*DISTVAR) // Distance when SPB can start appearing -#define SPBFORCEDIST (20*DISTVAR) // Distance when SPB is forced onto the next person who rolls an item +#define SPBSTARTDIST (6*DISTVAR) // Distance when SPB can start appearing +#define SPBFORCEDIST (12*DISTVAR) // Distance when SPB is forced onto the next person who rolls an item #define ENDDIST (12*DISTVAR) // Distance when the game stops giving you bananas // Array of states to pick the starting point of the animation, based on the actual time left for invincibility. From 5cbaeb58357ae97b57b8460f20508a23abbdd451 Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Wed, 21 Sep 2022 23:14:12 -0400 Subject: [PATCH 19/51] Gateboost @ 100%+ speed instead of 50%+ --- 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 c8847ff31..b09bc740d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3293,7 +3293,7 @@ static void K_GetKartBoostPower(player_t *player) if (player->gateBoost) // SPB Juicebox boost { - ADDBOOST(FRACUNIT/2, 4*FRACUNIT, sliptidehandling); // + 50% top speed, + 400% acceleration, +50% handling + ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling); // + 100% top speed, + 400% acceleration, +50% handling } if (player->ringboost) // Ring Boost From d9beb0daa6574d9a26a9ed551447a7da094ed353 Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Thu, 22 Sep 2022 00:00:32 -0400 Subject: [PATCH 20/51] Rebalanced GATES gains and reduced boost timers Reduced top-speed from 100%+ to 75%+, reduced handling buff from 50%+ to 25%+, reduced boost-time on gates to half the time. --- src/k_kart.c | 2 +- src/objects/manta-ring.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index b09bc740d..ee7b0b62b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3293,7 +3293,7 @@ static void K_GetKartBoostPower(player_t *player) if (player->gateBoost) // SPB Juicebox boost { - ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling); // + 100% top speed, + 400% acceleration, +50% handling + ADDBOOST(3*FRACUNIT/4, 4*FRACUNIT, sliptidehandling/2); // + 75% top speed, + 400% acceleration, +25% handling } if (player->ringboost) // Ring Boost diff --git a/src/objects/manta-ring.c b/src/objects/manta-ring.c index 2a5ed538c..7a352cabc 100644 --- a/src/objects/manta-ring.c +++ b/src/objects/manta-ring.c @@ -121,7 +121,7 @@ static void Obj_MantaCollide(mobj_t *manta, mobj_t *other) if (other->player != NULL) { - other->player->gateBoost += addBoost; + other->player->gateBoost += addBoost/2; if (P_IsDisplayPlayer(other->player) == true) { From e4f51ada155c7a7a55607e6a5e3612c37fd860ad Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Thu, 22 Sep 2022 00:13:35 -0400 Subject: [PATCH 21/51] Set back to 100%+ top speed, but w/ everything else kept the same --- 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 ee7b0b62b..6a93a1b8a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3293,7 +3293,7 @@ static void K_GetKartBoostPower(player_t *player) if (player->gateBoost) // SPB Juicebox boost { - ADDBOOST(3*FRACUNIT/4, 4*FRACUNIT, sliptidehandling/2); // + 75% top speed, + 400% acceleration, +25% handling + ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling/2); // + 100% top speed, + 400% acceleration, +25% handling } if (player->ringboost) // Ring Boost From 3a21f60ce1a7637688908253c2d1993059f1e051 Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Thu, 22 Sep 2022 00:23:31 -0400 Subject: [PATCH 22/51] Revert "Set back to 100%+ top speed, but w/ everything else kept the same" This reverts commit e4f51ada155c7a7a55607e6a5e3612c37fd860ad. --- 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 6a93a1b8a..ee7b0b62b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3293,7 +3293,7 @@ static void K_GetKartBoostPower(player_t *player) if (player->gateBoost) // SPB Juicebox boost { - ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling/2); // + 100% top speed, + 400% acceleration, +25% handling + ADDBOOST(3*FRACUNIT/4, 4*FRACUNIT, sliptidehandling/2); // + 75% top speed, + 400% acceleration, +25% handling } if (player->ringboost) // Ring Boost From 713c21688eb3fa498e8c35afe1ffd2892b813c21 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 22 Sep 2022 06:38:01 -0700 Subject: [PATCH 23/51] Remove unnecessary setting of PF_ATTACKDOWN; use BT_ATTACK where equivalent --- src/k_kart.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 99f74b751..8fc6a0ab1 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -960,9 +960,6 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) else if (!(player->itemroulette >= (TICRATE*3))) return; - if (cmd->buttons & BT_ATTACK) - player->pflags |= PF_ATTACKDOWN; - for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && !players[i].spectator @@ -5853,7 +5850,6 @@ void K_DoSneaker(player_t *player, INT32 type) if (type != 0) { - player->pflags |= PF_ATTACKDOWN; K_PlayBoostTaunt(player->mo); } @@ -5868,7 +5864,6 @@ static void K_DoShrink(player_t *user) mobj_t *mobj, *next; S_StartSound(user->mo, sfx_kc46); // Sound the BANG! - user->pflags |= PF_ATTACKDOWN; Obj_CreateShrinkPohbees(user); @@ -9935,7 +9930,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) // Ring boosting if (player->pflags & PF_USERINGS) { - if ((player->pflags & PF_ATTACKDOWN) && !player->ringdelay && player->rings > 0) + if ((cmd->buttons & BT_ATTACK) && !player->ringdelay && player->rings > 0) { mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); P_SetMobjState(ring, S_FASTRING1); From c7928188877156b8996ed8a93a979b1287010a6f Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 22 Sep 2022 07:19:10 -0700 Subject: [PATCH 24/51] Rename PF_LOOKDOWN to PF_GAINAX --- src/d_player.h | 5 ++++- src/deh_tables.c | 5 ++++- src/k_kart.c | 10 +++++----- src/p_inter.c | 2 +- src/p_user.c | 4 +--- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index ad7b75b86..d817c4231 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -62,7 +62,10 @@ typedef enum PF_ATTACKDOWN = 1, PF_ACCELDOWN = 1<<1, PF_BRAKEDOWN = 1<<2, - PF_LOOKDOWN = 1<<3, + + // Look back VFX has been spawned + // TODO: Is there a better way to track this? + PF_GAINAX = 1<<3, // Accessibility and cheats PF_KICKSTARTACCEL = 1<<4, // Is accelerate in kickstart mode? diff --git a/src/deh_tables.c b/src/deh_tables.c index 7f293daa3..2cc9cdb09 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5729,7 +5729,10 @@ const char *const PLAYERFLAG_LIST[] = { "ATTACKDOWN", "ACCELDOWN", "BRAKEDOWN", - "LOOKDOWN", + + // Look back VFX has been spawned + // TODO: Is there a better way to track this? + "GAINAX", // Accessibility and cheats "KICKSTARTACCEL", // Is accelerate in kickstart mode? diff --git a/src/k_kart.c b/src/k_kart.c index 8fc6a0ab1..088eb834b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2489,7 +2489,7 @@ void K_KartMoveAnimation(player_t *player) if (!lookback) { - player->pflags &= ~PF_LOOKDOWN; + player->pflags &= ~PF_GAINAX; // Uses turning over steering -- it's important to show player feedback immediately. if (player->cmd.turning < -minturn) @@ -2513,7 +2513,7 @@ void K_KartMoveAnimation(player_t *player) destGlanceDir = -(2*intsign(player->aizdriftturn)); player->glanceDir = destGlanceDir; drift = turndir = 0; - player->pflags &= ~PF_LOOKDOWN; + player->pflags &= ~PF_GAINAX; } else if (player->aizdriftturn) { @@ -2559,14 +2559,14 @@ void K_KartMoveAnimation(player_t *player) gainaxstate = S_GAINAX_MID1; } - if (destGlanceDir && !(player->pflags & PF_LOOKDOWN)) + if (destGlanceDir && !(player->pflags & PF_GAINAX)) { mobj_t *gainax = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_GAINAX); gainax->movedir = (destGlanceDir < 0) ? (ANGLE_270-ANG10) : (ANGLE_90+ANG10); P_SetTarget(&gainax->target, player->mo); P_SetMobjState(gainax, gainaxstate); gainax->flags2 |= MF2_AMBUSH; - player->pflags |= PF_LOOKDOWN; + player->pflags |= PF_GAINAX; } } else if (K_GetForwardMove(player) < 0 && destGlanceDir == 0) @@ -2823,7 +2823,7 @@ void K_KartMoveAnimation(player_t *player) } if (!player->glanceDir) - player->pflags &= ~PF_LOOKDOWN; + player->pflags &= ~PF_GAINAX; // Update lastspeed value -- we use to display slow driving frames instead of fast driving when slowing down. player->lastspeed = player->speed; diff --git a/src/p_inter.c b/src/p_inter.c index d21fb1195..4b2b8381a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2062,7 +2062,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player->driftboost = player->strongdriftboost = 0; player->ringboost = 0; player->glanceDir = 0; - player->pflags &= ~PF_LOOKDOWN; + player->pflags &= ~PF_GAINAX; switch (type) { diff --git a/src/p_user.c b/src/p_user.c index f733bad28..22a1d38ba 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2218,7 +2218,7 @@ void P_MovePlayer(player_t *player) player->drawangle -= ANGLE_22h; player->mo->rollangle = 0; player->glanceDir = 0; - player->pflags &= ~PF_LOOKDOWN; + player->pflags &= ~PF_GAINAX; } else if ((player->pflags & PF_FAULT) || (player->spinouttimer > 0)) { @@ -4405,8 +4405,6 @@ void P_PlayerThink(player_t *player) else player->pflags &= ~PF_BRAKEDOWN; - // PF_LOOKDOWN handled in K_KartMoveAnimation - // Counters, time dependent power ups. // Time Bonus & Ring Bonus count settings From 7251ed5d9eb926754ea9a85760cfbfb20d61c730 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 22 Sep 2022 08:43:40 -0700 Subject: [PATCH 25/51] Add player.oldcmd -- ticcmd from previous tic --- src/d_player.h | 1 + src/lua_playerlib.c | 4 ++++ src/p_tick.c | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/src/d_player.h b/src/d_player.h index d817c4231..cb527bdc1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -333,6 +333,7 @@ typedef struct player_s // Caveat: ticcmd_t is ATTRPACK! Be careful what precedes it. ticcmd_t cmd; + ticcmd_t oldcmd; // from the previous tic playerstate_t playerstate; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index cfab3696e..ad1669373 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -192,6 +192,8 @@ static int player_get(lua_State *L) LUA_PushUserdata(L, plr->mo, META_MOBJ); else if (fastcmp(field,"cmd")) LUA_PushUserdata(L, &plr->cmd, META_TICCMD); + else if (fastcmp(field,"oldcmd")) + LUA_PushUserdata(L, &plr->oldcmd, META_TICCMD); else if (fastcmp(field,"respawn")) LUA_PushUserdata(L, &plr->respawn, META_RESPAWN); else if (fastcmp(field,"playerstate")) @@ -526,6 +528,8 @@ static int player_set(lua_State *L) } else if (fastcmp(field,"cmd")) return NOSET; + else if (fastcmp(field,"oldcmd")) + return NOSET; else if (fastcmp(field,"respawn")) return NOSET; else if (fastcmp(field,"playerstate")) diff --git a/src/p_tick.c b/src/p_tick.c index 58b11406f..1f396a5fd 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -768,6 +768,11 @@ void P_Ticker(boolean run) K_TimerInit(); } + for (i = 0; i < MAXPLAYERS; i++) + { + G_CopyTiccmd(&players[i].oldcmd, &players[i].cmd, 1); + } + // Z_CheckMemCleanup(); } From bcdf41ec640999543052960f5c3ec908cccdcf35 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 22 Sep 2022 08:49:44 -0700 Subject: [PATCH 26/51] Remove PF_ATTACKDOWN/PF_ACCELDOWN/PF_BRAKEDOWN, use oldcmd.buttons --- src/d_player.h | 5 +---- src/g_game.c | 5 ----- src/k_botitem.c | 29 +++++++++++++++++++++++------ src/k_kart.c | 7 +------ src/m_cheat.c | 10 +++++----- src/p_user.c | 13 +------------ 6 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index cb527bdc1..74ac5943f 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -58,10 +58,7 @@ typedef enum // typedef enum { - // True if button down last tic. - PF_ATTACKDOWN = 1, - PF_ACCELDOWN = 1<<1, - PF_BRAKEDOWN = 1<<2, + // free: 1<<0 to 1<<2 // Look back VFX has been spawned // TODO: Is there a better way to track this? diff --git a/src/g_game.c b/src/g_game.c index 4d98256f1..f47681e44 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2410,11 +2410,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) // ^ Not necessary anyway since it will be respawned regardless considering it doesn't exist anymore. - // Don't do anything immediately - p->pflags |= PF_BRAKEDOWN; - p->pflags |= PF_ATTACKDOWN; - p->pflags |= PF_ACCELDOWN; - p->playerstate = PST_LIVE; p->panim = PA_STILL; // standing animation diff --git a/src/k_botitem.c b/src/k_botitem.c index 865a18fdd..bb90ef736 100644 --- a/src/k_botitem.c +++ b/src/k_botitem.c @@ -27,6 +27,23 @@ #include "m_random.h" #include "r_things.h" // numskins +/*-------------------------------------------------- + static inline boolean K_ItemButtonWasDown(player_t *player) + + Looks for players around the bot, and presses the item button + if there is one in range. + + Input Arguments:- + player - Bot to check. + + Return:- + true if the item button was pressed last tic, otherwise false. +--------------------------------------------------*/ +static inline boolean K_ItemButtonWasDown(player_t *player) +{ + return (player->oldcmd.buttons & BT_ATTACK); +} + /*-------------------------------------------------- static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t radius) @@ -45,7 +62,7 @@ static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t r { UINT8 i; - if (player->pflags & PF_ATTACKDOWN) + if (K_ItemButtonWasDown(player) == true) { return false; } @@ -327,7 +344,7 @@ static void K_ItemConfirmForTarget(player_t *bot, player_t *target, UINT16 amoun --------------------------------------------------*/ static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir) { - if (player->pflags & PF_ATTACKDOWN) + if (K_ItemButtonWasDown(player) == true) { return false; } @@ -352,7 +369,7 @@ static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir) --------------------------------------------------*/ static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd) { - if (!(player->pflags & PF_ATTACKDOWN)) + if (K_ItemButtonWasDown(player) == false) { cmd->buttons |= BT_ATTACK; player->botvars.itemconfirm = 0; @@ -475,7 +492,7 @@ static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd) || player->speedboost > (FRACUNIT/8) // Have another type of boost (tethering) || player->botvars.itemconfirm > 4*TICRATE) // Held onto it for too long { - if (!player->sneakertimer && !(player->pflags & PF_ATTACKDOWN)) + if (player->sneakertimer == 0 && K_ItemButtonWasDown(player) == false) { cmd->buttons |= BT_ATTACK; player->botvars.itemconfirm = 2*TICRATE; @@ -503,7 +520,7 @@ static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd) { if (player->botvars.itemconfirm > TICRATE) { - if (!player->sneakertimer && !(player->pflags & PF_ATTACKDOWN)) + if (player->sneakertimer == 0 && K_ItemButtonWasDown(player) == false) { cmd->buttons |= BT_ATTACK; player->botvars.itemconfirm = 0; @@ -1193,7 +1210,7 @@ static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) { boolean mash = false; - if (player->pflags & PF_ATTACKDOWN) + if (K_ItemButtonWasDown(player) == true) { return; } diff --git a/src/k_kart.c b/src/k_kart.c index 088eb834b..5b4dbed76 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9883,7 +9883,7 @@ void K_UnsetItemOut(player_t *player) void K_MoveKartPlayer(player_t *player, boolean onground) { ticcmd_t *cmd = &player->cmd; - boolean ATTACK_IS_DOWN = ((cmd->buttons & BT_ATTACK) && !(player->pflags & PF_ATTACKDOWN)); + boolean ATTACK_IS_DOWN = ((cmd->buttons & BT_ATTACK) && !(player->oldcmd.buttons & BT_ATTACK)); boolean HOLDING_ITEM = (player->pflags & (PF_ITEMOUT|PF_EGGMANOUT)); boolean NO_HYUDORO = (player->stealingtimer == 0); @@ -9918,11 +9918,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->pflags &= ~PF_USERINGS; } - if ((player->pflags & PF_ATTACKDOWN) && !(cmd->buttons & BT_ATTACK)) - player->pflags &= ~PF_ATTACKDOWN; - else if (cmd->buttons & BT_ATTACK) - player->pflags |= PF_ATTACKDOWN; - if (player && player->mo && player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime) { // First, the really specific, finicky items that function without the item being directly in your item slot. diff --git a/src/m_cheat.c b/src/m_cheat.c index 5eddbce4a..fbf7e0bcb 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1053,11 +1053,11 @@ void OP_ObjectplaceMovement(player_t *player) } - if (player->pflags & PF_ATTACKDOWN) + if (player->pflags & PF_STASIS) { // Are ANY objectplace buttons pressed? If no, remove flag. if (!(cmd->buttons & (BT_ATTACK|BT_DRIFT))) - player->pflags &= ~PF_ATTACKDOWN; + player->pflags &= ~PF_STASIS; // Do nothing. return; @@ -1066,12 +1066,12 @@ void OP_ObjectplaceMovement(player_t *player) /*if (cmd->buttons & BT_FORWARD) { OP_CycleThings(-1); - player->pflags |= PF_ATTACKDOWN; + player->pflags |= PF_STASIS; } else*/ if (cmd->buttons & BT_DRIFT) { OP_CycleThings(1); - player->pflags |= PF_ATTACKDOWN; + player->pflags |= PF_STASIS; } // Place an object and add it to the maplist @@ -1082,7 +1082,7 @@ void OP_ObjectplaceMovement(player_t *player) mobjtype_t spawnthing = op_currentdoomednum; boolean ceiling; - player->pflags |= PF_ATTACKDOWN; + player->pflags |= PF_STASIS; if (cv_mapthingnum.value > 0 && cv_mapthingnum.value < 4096) { diff --git a/src/p_user.c b/src/p_user.c index 22a1d38ba..8d3a24bfe 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4186,7 +4186,7 @@ void P_PlayerThink(player_t *player) } else if (cmd->buttons & BT_ACCELERATE) { - if (!player->exiting && !(player->pflags & PF_ACCELDOWN)) + if (!player->exiting && !(player->oldcmd.buttons & BT_ACCELERATE)) { player->kickstartaccel = 0; } @@ -4394,17 +4394,6 @@ void P_PlayerThink(player_t *player) P_DoBubbleBreath(player); // Spawn Sonic's bubbles P_CheckInvincibilityTimer(player); // Spawn Invincibility Sparkles - // check for buttons - if (cmd->buttons & BT_ACCELERATE) - player->pflags |= PF_ACCELDOWN; - else - player->pflags &= ~PF_ACCELDOWN; - - if (cmd->buttons & BT_BRAKE) - player->pflags |= PF_BRAKEDOWN; - else - player->pflags &= ~PF_BRAKEDOWN; - // Counters, time dependent power ups. // Time Bonus & Ring Bonus count settings From 8b0a80996886b5031af2df9f6402028e17838a89 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 22 Sep 2022 08:52:34 -0700 Subject: [PATCH 27/51] Remove dehacked pflags Cont. bcdf41ec6 --- src/deh_tables.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 2cc9cdb09..e366cee9f 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5725,10 +5725,10 @@ const char *const MAPTHINGFLAG_LIST[4] = { }; const char *const PLAYERFLAG_LIST[] = { - // True if button down last tic. - "ATTACKDOWN", - "ACCELDOWN", - "BRAKEDOWN", + // free: 1<<0 to 1<<2 + "", + "", + "", // Look back VFX has been spawned // TODO: Is there a better way to track this? From a836893a980d8cfcb7c29ac49e54cc97002b9371 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 22 Sep 2022 09:03:36 -0700 Subject: [PATCH 28/51] Correct 8b0a80996 --- src/deh_tables.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index e366cee9f..d0d767412 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5725,10 +5725,10 @@ const char *const MAPTHINGFLAG_LIST[4] = { }; const char *const PLAYERFLAG_LIST[] = { - // free: 1<<0 to 1<<2 - "", - "", - "", + // free: 1<<0 to 1<<2 (name un-matchable) + "\x01", + "\x01", + "\x01", // Look back VFX has been spawned // TODO: Is there a better way to track this? From f89d8d15c2ac8b3ee32610700a10ed0cf0d5662c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 03:35:18 -0400 Subject: [PATCH 29/51] Properly separate SPB & Shrink cooldowns Also refactors some of the result -> type & amount code --- src/doomstat.h | 2 +- src/g_game.c | 2 +- src/k_hud.c | 23 +---- src/k_kart.c | 226 ++++++++++++++++++++++++------------------- src/k_kart.h | 5 + src/k_menudraw.c | 44 +-------- src/lua_script.c | 5 - src/objects/shrink.c | 2 + src/objects/spb.c | 2 +- src/p_mobj.c | 2 +- src/p_saveg.c | 6 +- src/p_setup.c | 7 +- src/p_tick.c | 3 +- src/p_user.c | 2 +- 14 files changed, 155 insertions(+), 176 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 95baf7ce4..30578d3e6 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -707,7 +707,7 @@ extern boolean comeback; extern SINT8 battlewanted[4]; extern tic_t wantedcalcdelay; -extern tic_t indirectitemcooldown; +extern tic_t itemCooldowns[NUMKARTITEMS - 1]; extern tic_t mapreset; extern boolean thwompsactive; extern UINT8 lastLowestLap; diff --git a/src/g_game.c b/src/g_game.c index 4d98256f1..790d04941 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -317,7 +317,7 @@ SINT8 pickedvote; // What vote the host rolls // Server-sided, synched variables SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points tic_t wantedcalcdelay; // Time before it recalculates WANTED -tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded +tic_t itemCooldowns[NUMKARTITEMS - 1]; // Cooldowns to prevent item spawning tic_t mapreset; // Map reset delay when enough players have joined an empty game boolean thwompsactive; // Thwomps activate on lap 2 UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors diff --git a/src/k_hud.c b/src/k_hud.c index 609ddaaf8..161795fef 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4607,6 +4607,7 @@ static void K_drawDistributionDebugger(void) 0, stplyr->bot, (stplyr->bot && stplyr->botvars.rival) ); + INT32 amount = 1; if (itemodds <= 0) continue; @@ -4615,27 +4616,9 @@ static void K_drawDistributionDebugger(void) V_DrawThinString(x+11, y+31, V_SNAPTOTOP, va("%d", itemodds)); // Display amount for multi-items - if (i >= NUMKARTITEMS) + amount = K_ItemResultToAmount(i); + if (amount > 1) { - INT32 amount; - switch (i) - { - case KRITEM_TENFOLDBANANA: - amount = 10; - break; - case KRITEM_QUADORBINAUT: - amount = 4; - break; - case KRITEM_DUALJAWZ: - amount = 2; - break; - case KRITEM_DUALSNEAKER: - amount = 2; - break; - default: - amount = 3; - break; - } V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("x%d", amount)); } diff --git a/src/k_kart.c b/src/k_kart.c index ee7b0b62b..91015d886 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -47,7 +47,6 @@ // encoremode is Encore Mode (duh), bool // comeback is Battle Mode's karma comeback, also bool // battlewanted is an array of the WANTED player nums, -1 for no player in that slot -// indirectitemcooldown is timer before anyone's allowed another Shrink/SPB // mapreset is set when enough players fill an empty server void K_TimerReset(void) @@ -448,6 +447,111 @@ INT32 K_GetShieldFromItem(INT32 item) } } +SINT8 K_ItemResultToType(SINT8 getitem) +{ + if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback) + { + if (getitem != 0) + { + CONS_Printf("ERROR: K_GetItemResultToItemType - Item roulette gave bad item (%d) :(\n", getitem); + } + + return KITEM_SAD; + } + + if (getitem >= NUMKARTITEMS) + { + switch (getitem) + { + case KRITEM_DUALSNEAKER: + case KRITEM_TRIPLESNEAKER: + return KITEM_SNEAKER; + + case KRITEM_TRIPLEBANANA: + case KRITEM_TENFOLDBANANA: + return KITEM_BANANA; + + case KRITEM_TRIPLEORBINAUT: + case KRITEM_QUADORBINAUT: + return KITEM_ORBINAUT; + + case KRITEM_DUALJAWZ: + return KITEM_JAWZ; + + default: + I_Error("Bad item cooldown redirect for result %d\n", getitem); + break; + } + } + + return getitem; +} + +UINT8 K_ItemResultToAmount(SINT8 getitem) +{ + switch (getitem) + { + case KRITEM_DUALSNEAKER: + case KRITEM_DUALJAWZ: + return 2; + + case KRITEM_TRIPLESNEAKER: + case KRITEM_TRIPLEBANANA: + case KRITEM_TRIPLEORBINAUT: + return 3; + + case KRITEM_QUADORBINAUT: + return 4; + + case KITEM_BALLHOG: // Not a special result, but has a special amount + return 5; + + case KRITEM_TENFOLDBANANA: + return 10; + + default: + return 1; + } +} + +tic_t K_GetItemCooldown(SINT8 itemResult) +{ + SINT8 itemType = K_ItemResultToType(itemResult); + + if (itemType < 1 || itemType >= NUMKARTITEMS) + { + return 0; + } + + return itemCooldowns[itemType - 1]; +} + +void K_SetItemCooldown(SINT8 itemResult, tic_t time) +{ + SINT8 itemType = K_ItemResultToType(itemResult); + + if (itemType < 1 || itemType >= NUMKARTITEMS) + { + return; + } + + itemCooldowns[itemType - 1] = max(itemCooldowns[itemType - 1], time); +} + +void K_RunItemCooldowns(void) +{ + size_t i; + + for (i = 0; i < NUMKARTITEMS-1; i++) + { + if (itemCooldowns[i] > 0) + { + itemCooldowns[i]--; + } + } +} + + /** \brief Item Roulette for Kart \param player player @@ -457,61 +561,16 @@ INT32 K_GetShieldFromItem(INT32 item) */ static void K_KartGetItemResult(player_t *player, SINT8 getitem) { - if (getitem == KITEM_SPB) // Indirect items + if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) { - indirectitemcooldown = 20*TICRATE; + K_SetItemCooldown(getitem, 20*TICRATE); } player->botvars.itemdelay = TICRATE; player->botvars.itemconfirm = 0; - switch (getitem) - { - // Special roulettes first, then the generic ones are handled by default - case KRITEM_DUALSNEAKER: // Sneaker x2 - player->itemtype = KITEM_SNEAKER; - player->itemamount = 2; - break; - case KRITEM_TRIPLESNEAKER: // Sneaker x3 - player->itemtype = KITEM_SNEAKER; - player->itemamount = 3; - break; - case KRITEM_TRIPLEBANANA: // Banana x3 - player->itemtype = KITEM_BANANA; - player->itemamount = 3; - break; - case KRITEM_TENFOLDBANANA: // Banana x10 - player->itemtype = KITEM_BANANA; - player->itemamount = 10; - break; - case KRITEM_TRIPLEORBINAUT: // Orbinaut x3 - player->itemtype = KITEM_ORBINAUT; - player->itemamount = 3; - break; - case KRITEM_QUADORBINAUT: // Orbinaut x4 - player->itemtype = KITEM_ORBINAUT; - player->itemamount = 4; - break; - case KRITEM_DUALJAWZ: // Jawz x2 - 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) - { - if (getitem != 0) - CONS_Printf("ERROR: P_KartGetItemResult - Item roulette gave bad item (%d) :(\n", getitem); - player->itemtype = KITEM_SAD; - } - else - player->itemtype = getitem; - player->itemamount = 1; - break; - } + player->itemtype = K_ItemResultToType(getitem); + player->itemamount = K_ItemResultToAmount(getitem); } fixed_t K_ItemOddsScale(UINT8 playerCount) @@ -591,7 +650,6 @@ INT32 K_KartGetItemOdds( boolean powerItem = false; boolean cooldownOnStart = false; - boolean indirectItem = false; boolean notNearEnd = false; INT32 shieldtype = KSHIELD_NONE; @@ -600,7 +658,15 @@ INT32 K_KartGetItemOdds( I_Assert(KartItemCVars[NUMKARTRESULTS-2] != NULL); // Make sure this exists if (!KartItemCVars[item-1]->value && !modeattacking) + { return 0; + } + + if (K_GetItemCooldown(item) > 0) + { + // Cooldown is still running, don't give another. + return 0; + } /* if (bot) @@ -719,7 +785,6 @@ INT32 K_KartGetItemOdds( case KITEM_SPB: cooldownOnStart = true; - indirectItem = true; notNearEnd = true; if (firstDist < ENDDIST*2 // No SPB when 1st is almost done @@ -775,12 +840,8 @@ INT32 K_KartGetItemOdds( return newodds; } - if ((indirectItem == true) && (indirectitemcooldown > 0)) - { - // Too many items that act indirectly in a match can feel kind of bad. - newodds = 0; - } - else if ((cooldownOnStart == true) && (leveltime < (30*TICRATE)+starttime)) + + if ((cooldownOnStart == true) && (leveltime < (30*TICRATE)+starttime)) { // This item should not appear at the beginning of a race. (Usually really powerful crowd-breaking items) newodds = 0; @@ -946,7 +1007,7 @@ boolean K_ForcedSPB(player_t *player) return false; } - if (indirectitemcooldown > 0) + if (itemCooldowns[KITEM_SPB - 1] > 0) { return false; } @@ -6436,46 +6497,8 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 // K_KartGetItemResult requires a player // but item roulette will need rewritten to change this - switch (i) - { - // Special roulettes first, then the generic ones are handled by default - case KRITEM_DUALSNEAKER: // Sneaker x2 - newType = KITEM_SNEAKER; - newAmount = 2; - break; - case KRITEM_TRIPLESNEAKER: // Sneaker x3 - newType = KITEM_SNEAKER; - newAmount = 3; - break; - case KRITEM_TRIPLEBANANA: // Banana x3 - newType = KITEM_BANANA; - newAmount = 3; - break; - case KRITEM_TENFOLDBANANA: // Banana x10 - newType = KITEM_BANANA; - newAmount = 10; - break; - case KRITEM_TRIPLEORBINAUT: // Orbinaut x3 - newType = KITEM_ORBINAUT; - newAmount = 3; - break; - case KRITEM_QUADORBINAUT: // Orbinaut x4 - newType = KITEM_ORBINAUT; - newAmount = 4; - break; - case KRITEM_DUALJAWZ: // Jawz x2 - newType = KITEM_JAWZ; - newAmount = 2; - break; - case KITEM_BALLHOG: // Ballhog x5 - newType = KITEM_BALLHOG; - newAmount = 5; - break; - default: - newType = i; - newAmount = 1; - break; - } + newType = K_ItemResultToType(i); + newAmount = K_ItemResultToAmount(i); if (newAmount > 1) { @@ -10701,9 +10724,10 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (spbplace == -1 || player->position != spbplace) player->pflags &= ~PF_RINGLOCK; // reset ring lock - if (player->itemtype == KITEM_SPB) + if (player->itemtype == KITEM_SPB + || player->itemtype == KITEM_SHRINK) { - indirectitemcooldown = 20*TICRATE; + K_SetItemCooldown(player->itemtype, 20*TICRATE); } if (player->hyudorotimer > 0) diff --git a/src/k_kart.h b/src/k_kart.h index 6655ec034..eda49b4c3 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -50,6 +50,11 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers); INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean bot, boolean rival); boolean K_ForcedSPB(player_t *player); INT32 K_GetShieldFromItem(INT32 item); +SINT8 K_ItemResultToType(SINT8 getitem); +UINT8 K_ItemResultToAmount(SINT8 getitem); +tic_t K_GetItemCooldown(SINT8 itemResult); +void K_SetItemCooldown(SINT8 itemResult, tic_t time); +void K_RunItemCooldowns(void); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 76a001544..2785f83ac 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -3366,34 +3366,14 @@ void M_DrawItemToggles(void) cv = KartItemCVars[currentMenu->menuitems[thisitem].mvar1-1]; translucent = (cv->value ? 0 : V_TRANSLUCENT); - switch (currentMenu->menuitems[thisitem].mvar1) - { - case KRITEM_DUALSNEAKER: - case KRITEM_DUALJAWZ: - drawnum = 2; - break; - case KRITEM_TRIPLESNEAKER: - case KRITEM_TRIPLEBANANA: - case KRITEM_TRIPLEORBINAUT: - drawnum = 3; - break; - case KRITEM_QUADORBINAUT: - drawnum = 4; - break; - case KRITEM_TENFOLDBANANA: - drawnum = 10; - break; - default: - drawnum = 0; - break; - } + drawnum = K_ItemResultToAmount(currentMenu->menuitems[thisitem].mvar1); if (cv->value) V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE)); else V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBGD", PU_CACHE)); - if (drawnum != 0) + if (drawnum > 1) { V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISMUL", PU_CACHE)); V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].mvar1, true), PU_CACHE)); @@ -3433,30 +3413,14 @@ void M_DrawItemToggles(void) cv = KartItemCVars[currentMenu->menuitems[itemOn].mvar1-1]; translucent = (cv->value ? 0 : V_TRANSLUCENT); - switch (currentMenu->menuitems[itemOn].mvar1) - { - case KRITEM_DUALSNEAKER: - case KRITEM_DUALJAWZ: - drawnum = 2; - break; - case KRITEM_TRIPLESNEAKER: - case KRITEM_TRIPLEBANANA: - drawnum = 3; - break; - case KRITEM_TENFOLDBANANA: - drawnum = 10; - break; - default: - drawnum = 0; - break; - } + drawnum = K_ItemResultToAmount(currentMenu->menuitems[itemOn].mvar1); if (cv->value) V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE)); else V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBGD", PU_CACHE)); - if (drawnum != 0) + if (drawnum > 1) { V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITMUL", PU_CACHE)); V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].mvar1, false), PU_CACHE)); diff --git a/src/lua_script.c b/src/lua_script.c index 8a1e307bb..051739976 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -375,9 +375,6 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"wantedcalcdelay")) { lua_pushinteger(L, wantedcalcdelay); return 1; - } else if (fastcmp(word,"indirectitemcooldown")) { - lua_pushinteger(L, indirectitemcooldown); - return 1; } else if (fastcmp(word,"thwompsactive")) { lua_pushboolean(L, thwompsactive); return 1; @@ -463,8 +460,6 @@ int LUA_WriteGlobals(lua_State *L, const char *word) racecountdown = (tic_t)luaL_checkinteger(L, 2); else if (fastcmp(word,"exitcountdown")) exitcountdown = (tic_t)luaL_checkinteger(L, 2); - else if (fastcmp(word,"indirectitemcooldown")) - indirectitemcooldown = (tic_t)luaL_checkinteger(L, 2); else return 0; diff --git a/src/objects/shrink.c b/src/objects/shrink.c index 241164aa7..9a520171b 100644 --- a/src/objects/shrink.c +++ b/src/objects/shrink.c @@ -439,6 +439,8 @@ void Obj_PohbeeThinker(mobj_t *pohbee) { mobj_t *gun = NULL; + K_SetItemCooldown(KITEM_SHRINK, 20*TICRATE); + pohbee->momx = pohbee->momy = pohbee->momz = 0; pohbee->spritexscale = pohbee->spriteyscale = 2*FRACUNIT; diff --git a/src/objects/spb.c b/src/objects/spb.c index d22dbe49c..ca3c5813a 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -766,7 +766,7 @@ void Obj_SPBThink(mobj_t *spb) return; } - indirectitemcooldown = 20*TICRATE; + K_SetItemCooldown(KITEM_SPB, 20*TICRATE); ghost = P_SpawnGhostMobj(spb); ghost->fuse = 3; diff --git a/src/p_mobj.c b/src/p_mobj.c index ab37b2e7c..01c6b649a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6743,7 +6743,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) break; case KITEM_SPB: case KITEM_SHRINK: - indirectitemcooldown = 20*TICRATE; + K_SetItemCooldown(mobj->threshold, 20*TICRATE); /* FALLTHRU */ default: mobj->sprite = SPR_ITEM; diff --git a/src/p_saveg.c b/src/p_saveg.c index fe11f0ee9..e04b4a3f4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4560,7 +4560,8 @@ static void P_NetArchiveMisc(boolean resending) WRITEFIXED(save_p, battleovertime.z); WRITEUINT32(save_p, wantedcalcdelay); - WRITEUINT32(save_p, indirectitemcooldown); + for (i = 0; i < NUMKARTITEMS-1; i++) + WRITEUINT32(save_p, itemCooldowns[i]); WRITEUINT32(save_p, mapreset); WRITEUINT8(save_p, spectateGriefed); @@ -4723,7 +4724,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) battleovertime.z = READFIXED(save_p); wantedcalcdelay = READUINT32(save_p); - indirectitemcooldown = READUINT32(save_p); + for (i = 0; i < NUMKARTITEMS-1; i++) + itemCooldowns[i] = READUINT32(save_p); mapreset = READUINT32(save_p); spectateGriefed = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 6815d1496..a75d830ec 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4022,6 +4022,8 @@ static void P_InitPlayers(void) static void P_InitGametype(void) { + size_t i; + spectateGriefed = 0; K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped @@ -4046,7 +4048,10 @@ static void P_InitGametype(void) } wantedcalcdelay = wantedfrequency*2; - indirectitemcooldown = 0; + + for (i = 0; i < NUMKARTITEMS-1; i++) + itemCooldowns[i] = 0; + mapreset = 0; thwompsactive = false; diff --git a/src/p_tick.c b/src/p_tick.c index 58b11406f..9da702289 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -683,8 +683,7 @@ void P_Ticker(boolean run) if (exitcountdown > 1) exitcountdown--; - if (indirectitemcooldown > 0) - indirectitemcooldown--; + K_RunItemCooldowns(); K_BossInfoTicker(); diff --git a/src/p_user.c b/src/p_user.c index f733bad28..c3b602195 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2592,7 +2592,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) if (mo->type == MT_SPB) // If you destroy a SPB, you don't get the luxury of a cooldown. { spbplace = -1; - indirectitemcooldown = 0; + itemCooldowns[KITEM_SPB - 1] = 0; } if (mo->flags & MF_BOSS) //don't OHKO bosses nor players! From 13caae7a0e22cabdb7f6d03b138c9b03e4c5c8c7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 03:41:27 -0400 Subject: [PATCH 30/51] Shrink does not remove SPB --- src/k_kart.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 91015d886..52e105d62 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6032,16 +6032,22 @@ static void K_DoShrink(player_t *user) { mobj_t *mobj, *next; - S_StartSound(user->mo, sfx_kc46); // Sound the BANG! + S_StartSound(NULL, sfx_kc46); // Sound the BANG! user->pflags |= PF_ATTACKDOWN; Obj_CreateShrinkPohbees(user); +#if 1 // kill everything in the kitem list while we're at it: for (mobj = kitemcap; mobj; mobj = next) { next = mobj->itnext; + if (mobj->type == MT_SPB) + { + continue; + } + // check if the item is being held by a player behind us before removing it. // check if the item is a "shield" first, bc i'm p sure thrown items keep the player that threw em as target anyway @@ -6060,10 +6066,8 @@ static void K_DoShrink(player_t *user) mobj->destscale = 0; mobj->flags &= ~(MF_SOLID|MF_SHOOTABLE|MF_SPECIAL); mobj->flags |= MF_NOCLIPTHING; // Just for safety - - if (mobj->type == MT_SPB) - spbplace = -1; } +#endif } void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) From fa63c67f04990309ee4b9a4807bf24a27c281715 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 03:46:56 -0400 Subject: [PATCH 31/51] Disable shrinking items into nothing No one feels strongly about it, it just feels weird --- 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 52e105d62..7403d1a18 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6037,7 +6037,7 @@ static void K_DoShrink(player_t *user) Obj_CreateShrinkPohbees(user); -#if 1 +#if 0 // kill everything in the kitem list while we're at it: for (mobj = kitemcap; mobj; mobj = next) { From 2786957feff33f9af1442c48d8ac87da762188c3 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 03:52:14 -0400 Subject: [PATCH 32/51] Move Obj_SPBExplode to correct place --- src/p_mobj.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 01c6b649a..e73babc0f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6269,11 +6269,6 @@ static void P_MobjSceneryThink(mobj_t *mobj) case MT_DRIFTELECTRICSPARK: mobj->renderflags ^= RF_DONTDRAW; break; - case MT_SPB: - { - Obj_SPBExplode(mobj); - return; - } case MT_VWREF: case MT_VWREB: { @@ -9358,6 +9353,11 @@ static boolean P_FuseThink(mobj_t *mobj) P_RemoveMobj(mobj); return false; } + case MT_SPB: + { + Obj_SPBExplode(mobj); + break; + } case MT_PLAYER: break; // don't remove default: From 21bd7bf041d4b936485f64ab0ba4560644e7ab52 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 04:04:05 -0400 Subject: [PATCH 33/51] Reverse SPB distance scaling --- src/k_kart.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 7403d1a18..e81253c72 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -578,6 +578,12 @@ fixed_t K_ItemOddsScale(UINT8 playerCount) const UINT8 basePlayer = 8; // The player count we design most of the game around. fixed_t playerScaling = 0; + if (playerCount < 2) + { + // Cap to 1v1 scaling + playerCount = 2; + } + // Then, it multiplies it further if the player count isn't equal to basePlayer. // This is done to make low player count races more interesting and high player count rates more fair. if (playerCount < basePlayer) @@ -610,14 +616,11 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers) distance = (15 * distance) / 14; } - if (numPlayers > 0) - { - // Items get crazier with the fewer players that you have. - distance = FixedMul( - distance, - FRACUNIT + (K_ItemOddsScale(numPlayers) / 2) - ); - } + // Items get crazier with the fewer players that you have. + distance = FixedMul( + distance, + FRACUNIT + (K_ItemOddsScale(numPlayers) / 2) + ); return distance; } @@ -744,7 +747,7 @@ INT32 K_KartGetItemOdds( if (first != NULL && second != NULL) { secondToFirst = secondDist - firstDist; - secondToFirst = K_ScaleItemDistance(secondToFirst, pingame); + secondToFirst = K_ScaleItemDistance(secondToFirst, 16 - pingame); // Reversed scaling, so 16P is like 1v1, and 1v1 is like 16P } switch (item) @@ -1047,7 +1050,7 @@ boolean K_ForcedSPB(player_t *player) if (first != NULL && second != NULL) { secondToFirst = second->distancetofinish - first->distancetofinish; - secondToFirst = K_ScaleItemDistance(secondToFirst, pingame); + secondToFirst = K_ScaleItemDistance(secondToFirst, 16 - pingame); } return (secondToFirst >= SPBFORCEDIST); From d43a5d05547138f21af594d6663584c0542c955c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 04:08:07 -0400 Subject: [PATCH 34/51] Fix unused variables --- src/k_kart.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index e81253c72..5fa89425a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6033,42 +6033,44 @@ void K_DoSneaker(player_t *player, INT32 type) static void K_DoShrink(player_t *user) { - mobj_t *mobj, *next; - S_StartSound(NULL, sfx_kc46); // Sound the BANG! user->pflags |= PF_ATTACKDOWN; Obj_CreateShrinkPohbees(user); #if 0 - // kill everything in the kitem list while we're at it: - for (mobj = kitemcap; mobj; mobj = next) { - next = mobj->itnext; + mobj_t *mobj, *next; - if (mobj->type == MT_SPB) + // kill everything in the kitem list while we're at it: + for (mobj = kitemcap; mobj; mobj = next) { - continue; - } + next = mobj->itnext; - // check if the item is being held by a player behind us before removing it. - // check if the item is a "shield" first, bc i'm p sure thrown items keep the player that threw em as target anyway - - if (mobj->type == MT_BANANA_SHIELD || mobj->type == MT_JAWZ_SHIELD || - mobj->type == MT_SSMINE_SHIELD || mobj->type == MT_EGGMANITEM_SHIELD || - mobj->type == MT_SINK_SHIELD || mobj->type == MT_ORBINAUT_SHIELD || - mobj->type == MT_DROPTARGET_SHIELD) - { - if (mobj->target && mobj->target->player) + if (mobj->type == MT_SPB) { - if (mobj->target->player->position > user->position) - continue; // this guy's behind us, don't take his stuff away! + continue; } - } - mobj->destscale = 0; - mobj->flags &= ~(MF_SOLID|MF_SHOOTABLE|MF_SPECIAL); - mobj->flags |= MF_NOCLIPTHING; // Just for safety + // check if the item is being held by a player behind us before removing it. + // check if the item is a "shield" first, bc i'm p sure thrown items keep the player that threw em as target anyway + + if (mobj->type == MT_BANANA_SHIELD || mobj->type == MT_JAWZ_SHIELD || + mobj->type == MT_SSMINE_SHIELD || mobj->type == MT_EGGMANITEM_SHIELD || + mobj->type == MT_SINK_SHIELD || mobj->type == MT_ORBINAUT_SHIELD || + mobj->type == MT_DROPTARGET_SHIELD) + { + if (mobj->target && mobj->target->player) + { + if (mobj->target->player->position > user->position) + continue; // this guy's behind us, don't take his stuff away! + } + } + + mobj->destscale = 0; + mobj->flags &= ~(MF_SOLID|MF_SHOOTABLE|MF_SPECIAL); + mobj->flags |= MF_NOCLIPTHING; // Just for safety + } } #endif } From 58f56de7ccf7a13dc96dfada788d92524c7a5c07 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 05:30:19 -0400 Subject: [PATCH 35/51] fuck you NULL targets? --- src/objects/shrink.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/objects/shrink.c b/src/objects/shrink.c index 9a520171b..bd68fa3d4 100644 --- a/src/objects/shrink.c +++ b/src/objects/shrink.c @@ -484,6 +484,8 @@ void Obj_PohbeeRemoved(mobj_t *pohbee) P_RemoveMobj(gun); gun = nextGun; } + + P_SetTarget(&pohbee_guns(pohbee), NULL); } void Obj_ShrinkGunRemoved(mobj_t *gun) @@ -495,6 +497,8 @@ void Obj_ShrinkGunRemoved(mobj_t *gun) P_RemoveMobj(gun_laser(gun)); } + P_SetTarget(&gun_laser(gun), NULL); + chain = gun_chains(gun); while (chain != NULL && P_MobjWasRemoved(chain) == false) { @@ -502,6 +506,8 @@ void Obj_ShrinkGunRemoved(mobj_t *gun) P_RemoveMobj(chain); chain = nextChain; } + + P_SetTarget(&gun_chains(gun), NULL); } boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim) From 31009264ca40036b8b04140b137b7064ebaf5194 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 05:51:14 -0400 Subject: [PATCH 36/51] NULL itnext in general on removal --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index e73babc0f..00e065984 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10794,6 +10794,8 @@ void P_RemoveMobj(mobj_t *mobj) } } + P_SetTarget(&mobj->itnext, NULL); + // DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error. #ifdef SCRAMBLE_REMOVED // Invalidate mobj_t data to cause crashes if accessed! From e340d9b701a3c4c02fcbc6ca09460a4111aaca6c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 05:54:02 -0400 Subject: [PATCH 37/51] Remove itnext at top of MobjThinker also --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 00e065984..37f76898c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9394,6 +9394,8 @@ void P_MobjThinker(mobj_t *mobj) P_SetTarget(&mobj->hnext, NULL); if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) P_SetTarget(&mobj->hprev, NULL); + if (mobj->itnext && P_MobjWasRemoved(mobj->itnext)) + P_SetTarget(&mobj->itnext, NULL); if (mobj->flags & MF_NOTHINK) return; From c6e4a93e296faeba96239c63ffe65e02fd73df02 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 06:15:19 -0700 Subject: [PATCH 38/51] Drop items being dragged behind you, like orbinaut shields, when failing a trick --- src/k_kart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 99f74b751..6e1a1df29 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10693,6 +10693,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->trickpanel = 0; K_trickPanelTimingVisual(player, momz); // fail trick visual P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); + if (player->pflags & (PF_ITEMOUT|PF_EGGMANOUT)) + K_DropHnextList(player, true); } else if (!(player->pflags & PF_TRICKDELAY)) // don't allow tricking at the same frame you tumble obv From e202f244b9404b600e4f27a5649931164ea58c3f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 15:25:42 -0400 Subject: [PATCH 39/51] Allow smaller flat sizes With mobj scale, smaller flats are pretty reasonable to want to use. Fixes a visual bug in Endless Mine. --- src/hardware/hw_draw.c | 44 ++++++------------------ src/hardware/hw_main.c | 57 ++++--------------------------- src/r_plane.h | 1 + src/r_textures.c | 77 +++++++++++++++++++++++++++++------------- src/v_video.c | 16 ++++++--- 5 files changed, 83 insertions(+), 112 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 570771fc3..b4917751b 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -31,6 +31,7 @@ #include "../p_local.h" // stplyr #include "../g_game.h" // players #include "../k_hud.h" +#include "../r_plane.h" // R_FlatDimensionsFromLumpSize #include #include "../i_video.h" // for rendermode != render_glide @@ -482,42 +483,17 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) // -------------------------------------------------------------------------- void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum) { - FOutVector v[4]; - double dflatsize; - INT32 flatflag; const size_t len = W_LumpLength(flatlumpnum); - switch (len) - { - case 4194304: // 2048x2048 lump - dflatsize = 2048.0f; - flatflag = 2047; - break; - case 1048576: // 1024x1024 lump - dflatsize = 1024.0f; - flatflag = 1023; - break; - case 262144:// 512x512 lump - dflatsize = 512.0f; - flatflag = 511; - break; - case 65536: // 256x256 lump - dflatsize = 256.0f; - flatflag = 255; - break; - case 16384: // 128x128 lump - dflatsize = 128.0f; - flatflag = 127; - break; - case 1024: // 32x32 lump - dflatsize = 32.0f; - flatflag = 31; - break; - default: // 64x64 lump - dflatsize = 64.0f; - flatflag = 63; - break; - } + size_t sflatsize; + double dflatsize; + INT32 flatflag; + + FOutVector v[4]; + + sflatsize = R_FlatDimensionsFromLumpSize(len); + dflatsize = (double)sflatsize; + flatflag = sflatsize - 1; // 3--2 // | /| diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3a4a0687f..91aa8b00e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -46,6 +46,7 @@ // SRB2Kart #include "../k_kart.h" // HITLAGJITTERS #include "../r_fps.h" +#include "../r_plane.h" // R_FlatDimensionsFromLumpSize #ifdef NEWCLIP #include "hw_clip.h" @@ -393,31 +394,9 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool if (levelflat->type == LEVELFLAT_FLAT) { size_t len = W_LumpLength(levelflat->u.flat.lumpnum); - switch (len) - { - case 4194304: // 2048x2048 lump - fflatwidth = fflatheight = 2048.0f; - break; - case 1048576: // 1024x1024 lump - fflatwidth = fflatheight = 1024.0f; - break; - case 262144:// 512x512 lump - fflatwidth = fflatheight = 512.0f; - break; - case 65536: // 256x256 lump - fflatwidth = fflatheight = 256.0f; - break; - case 16384: // 128x128 lump - fflatwidth = fflatheight = 128.0f; - break; - case 1024: // 32x32 lump - fflatwidth = fflatheight = 32.0f; - break; - default: // 64x64 lump - fflatwidth = fflatheight = 64.0f; - break; - } - flatflag = ((INT32)fflatwidth)-1; + size_t sflatsize = R_FlatDimensionsFromLumpSize(len); + fflatwidth = fflatheight = (double)sflatsize; + flatflag = sflatsize-1; } else { @@ -2756,31 +2735,9 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, if (levelflat->type == LEVELFLAT_FLAT) { size_t len = W_LumpLength(levelflat->u.flat.lumpnum); - switch (len) - { - case 4194304: // 2048x2048 lump - fflatwidth = fflatheight = 2048.0f; - break; - case 1048576: // 1024x1024 lump - fflatwidth = fflatheight = 1024.0f; - break; - case 262144:// 512x512 lump - fflatwidth = fflatheight = 512.0f; - break; - case 65536: // 256x256 lump - fflatwidth = fflatheight = 256.0f; - break; - case 16384: // 128x128 lump - fflatwidth = fflatheight = 128.0f; - break; - case 1024: // 32x32 lump - fflatwidth = fflatheight = 32.0f; - break; - default: // 64x64 lump - fflatwidth = fflatheight = 64.0f; - break; - } - flatflag = ((INT32)fflatwidth)-1; + size_t sflatsize = R_FlatDimensionsFromLumpSize(len); + fflatwidth = fflatheight = (double)sflatsize; + flatflag = sflatsize-1; } else { diff --git a/src/r_plane.h b/src/r_plane.h index 61bac1968..f0a32d969 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -89,6 +89,7 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_PlaneBounds(visplane_t *plane); +size_t R_FlatDimensionsFromLumpSize(size_t size); void R_CheckFlatLength(size_t size); boolean R_CheckPowersOfTwo(void); diff --git a/src/r_textures.c b/src/r_textures.c index 39976a3c8..35d79e872 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -656,6 +656,44 @@ boolean R_CheckPowersOfTwo(void) return ds_powersoftwo; } +// +// R_FlatDimensionsFromLumpSize +// +// Returns the flat's square size from its lump length. +// +size_t R_FlatDimensionsFromLumpSize(size_t size) +{ + switch (size) + { + case 4194304: // 2048x2048 lump + return 2048; + + case 1048576: // 1024x1024 lump + return 1024; + + case 262144:// 512x512 lump + return 512; + + case 65536: // 256x256 lump + return 256; + + case 16384: // 128x128 lump + return 128; + + case 1024: // 32x32 lump + return 32; + + case 256: // 16x16 lump + return 16; + + case 64: // 8x8 lump + return 8; + + default: // 64x64 lump + return 64; + } +} + // // R_CheckFlatLength // @@ -707,6 +745,20 @@ void R_CheckFlatLength(size_t size) nflatshiftup = 11; ds_flatwidth = ds_flatheight = 32; break; + case 256: // 16x16 lump + nflatmask = 0xF0; + nflatxshift = 28; + nflatyshift = 24; + nflatshiftup = 12; + ds_flatwidth = ds_flatheight = 16; + break; + case 64: // 8x8 lump + nflatmask = 0x38; + nflatxshift = 29; + nflatyshift = 26; + nflatshiftup = 13; + ds_flatwidth = ds_flatheight = 8; + break; default: // 64x64 lump nflatmask = 0xFC0; nflatxshift = 26; @@ -774,30 +826,7 @@ Rloadflats (INT32 i, INT32 w) W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0); lumplength = W_LumpLengthPwad(wadnum, lumpnum); - switch (lumplength) - { - case 4194304: // 2048x2048 lump - flatsize = 2048; - break; - case 1048576: // 1024x1024 lump - flatsize = 1024; - break; - case 262144:// 512x512 lump - flatsize = 512; - break; - case 65536: // 256x256 lump - flatsize = 256; - break; - case 16384: // 128x128 lump - flatsize = 128; - break; - case 1024: // 32x32 lump - flatsize = 32; - break; - default: // 64x64 lump - flatsize = 64; - break; - } + flatsize = R_FlatDimensionsFromLumpSize(lumplength); //CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize); texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); diff --git a/src/v_video.c b/src/v_video.c index 193339574..c2d3e3c4c 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1236,19 +1236,19 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum) { case 4194304: // 2048x2048 lump lflatsize = 2048; - flatshift = 10; + flatshift = 11; break; case 1048576: // 1024x1024 lump lflatsize = 1024; - flatshift = 9; + flatshift = 10; break; case 262144:// 512x512 lump lflatsize = 512; - flatshift = 8; + flatshift = 9; break; case 65536: // 256x256 lump lflatsize = 256; - flatshift = 7; + flatshift = 8; break; case 16384: // 128x128 lump lflatsize = 128; @@ -1258,6 +1258,14 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum) lflatsize = 32; flatshift = 5; break; + case 256: // 16x16 lump + lflatsize = 16; + flatshift = 4; + break; + case 64: // 8x8 lump + lflatsize = 8; + flatshift = 3; + break; default: // 64x64 lump lflatsize = 64; flatshift = 6; From 8b160a996b0868ed28221a7abeef466725199481 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 16:00:35 -0400 Subject: [PATCH 40/51] SPB circles in place if it goes past on accident --- src/objects/spb.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index ca3c5813a..354ee11a2 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -311,6 +311,8 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) fixed_t steerDist = INT32_MAX; mobj_t *steerMobj = NULL; + boolean circling = false; + size_t i; spb_lastplayer(spb) = -1; // Just make sure this is reset @@ -417,9 +419,8 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) if (destWaypoint != NULL) { // Go to next waypoint. - const boolean huntbackwards = false; const boolean useshortcuts = K_GetWaypointIsShortcut(destWaypoint); // If the player is on a shortcut, use shortcuts. No escape. - + boolean huntbackwards = false; path_t pathtoplayer = {0}; pathfindsuccess = K_PathfindToWaypoint( @@ -430,9 +431,27 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) if (pathfindsuccess == true) { - if (pathtoplayer.numnodes > 1) + path_t reversepath = {0}; + boolean reversesuccess = false; + + huntbackwards = true; + reversesuccess = K_PathfindToWaypoint( + curWaypoint, destWaypoint, + &reversepath, + useshortcuts, huntbackwards + ); + + if (reversesuccess == true + && reversepath.totaldist < pathtoplayer.totaldist) { - // Go to next. + // It's faster to go backwards than to chase forward. + // Keep curWaypoint the same, so the SPB waits around for them. + circling = true; + Z_Free(reversepath.array); + } + else if (pathtoplayer.numnodes > 1) + { + // Go to the next waypoint. curWaypoint = (waypoint_t *)pathtoplayer.array[1].nodedata; } else if (spb->fuse > 0 && destWaypoint->numnextwaypoints > 0) @@ -443,6 +462,7 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) else { // Sort of wait at the player's dest waypoint. + circling = true; curWaypoint = destWaypoint; } @@ -539,8 +559,12 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) // Always spawn speed lines while seeking SpawnSPBSpeedLines(spb); - // Spawn a trail of rings behind the SPB! - SPBMantaRings(spb); + // Don't run this while we're circling around one waypoint intentionally. + if (circling == false) + { + // Spawn a trail of rings behind the SPB! + SPBMantaRings(spb); + } } static void SPBChase(mobj_t *spb, player_t *bestPlayer) From 0bd280a29c5ec4e80eba26012a973bf1e935d50f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 16:44:21 -0400 Subject: [PATCH 41/51] Fix SPB dust - Fix sliptide not using sliptide states - Fix dust not dealing damage --- src/info.c | 6 +++--- src/objects/spb.c | 36 +++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/info.c b/src/info.c index 9b8e47626..87c0a28c1 100644 --- a/src/info.c +++ b/src/info.c @@ -28736,13 +28736,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16<z = sz; + P_SetMobjState(spark, S_KARTAIZDRIFTSTRAT); + P_SetTarget(&spark->target, spb); + spark->colorized = true; spark->color = SKINCOLOR_RED; - spark->flags = MF_NOGRAVITY|MF_PAIN; - P_SetTarget(&spark->target, spb); - spark->angle = travelangle + (dir * ANGLE_90); P_SetScale(spark, (spark->destscale = spb->scale*3/2)); @@ -235,12 +238,11 @@ static void SPBTurn( fixed_t *editSpeed, angle_t *editAngle, fixed_t lerp, SINT8 *returnSliptide) { - INT32 delta = destAngle - *editAngle; + INT32 delta = AngleDeltaSigned(destAngle, *editAngle); fixed_t dampen = FRACUNIT; // Slow down when turning; it looks better and makes U-turns not unfair dampen = FixedDiv((180 * FRACUNIT) - AngleFixed(abs(delta)), 180 * FRACUNIT); - *editSpeed = FixedMul(destSpeed, dampen); delta = FixedMul(delta, lerp); @@ -248,11 +250,19 @@ static void SPBTurn( // Calculate sliptide effect during seeking. if (returnSliptide != NULL) { - INT32 sliptide = (abs(delta) > SPB_SLIPTIDEDELTA); + const boolean isSliptiding = (abs(delta) >= SPB_SLIPTIDEDELTA); + SINT8 sliptide = 0; - if (delta < 0) + if (isSliptiding == true) { - sliptide = -sliptide; + if (delta < 0) + { + sliptide = -1; + } + else + { + sliptide = 1; + } } *returnSliptide = sliptide; @@ -498,8 +508,8 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) destAngle = R_PointToAngle2(spb->x, spb->y, destX, destY); destPitch = R_PointToAngle2(0, spb->z, P_AproxDistance(spb->x - destX, spb->y - destY), destZ); - SPBTurn(desiredSpeed, destAngle, &xySpeed, &spb->angle, FRACUNIT/8, &sliptide); - SPBTurn(desiredSpeed, destPitch, &zSpeed, &spb_pitch(spb), FRACUNIT/8, NULL); + SPBTurn(desiredSpeed, destAngle, &xySpeed, &spb->angle, SPB_SEEKTURN, &sliptide); + SPBTurn(desiredSpeed, destPitch, &zSpeed, &spb_pitch(spb), SPB_SEEKTURN, NULL); SetSPBSpeed(spb, xySpeed, zSpeed); @@ -711,8 +721,8 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) spb_speed(spb) = desiredSpeed; } - SPBTurn(spb_speed(spb), destAngle, &xySpeed, &spb->angle, FRACUNIT, NULL); - SPBTurn(spb_speed(spb), destPitch, &zSpeed, &spb_pitch(spb), FRACUNIT, NULL); + SPBTurn(spb_speed(spb), destAngle, &xySpeed, &spb->angle, SPB_CHASETURN, NULL); + SPBTurn(spb_speed(spb), destPitch, &zSpeed, &spb_pitch(spb), SPB_CHASETURN, NULL); SetSPBSpeed(spb, xySpeed, zSpeed); spb->momx += cx; From 362bef7b3a5c3eca9942d24dd0fadff64b9b17d5 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Sep 2022 17:19:15 -0400 Subject: [PATCH 42/51] Add new gate sounds --- src/d_player.h | 2 ++ src/lua_playerlib.c | 4 ++++ src/objects/manta-ring.c | 27 +++++++++++++++++++++++++-- src/objects/spb.c | 29 ++++++++++++++++++++++++++--- src/p_saveg.c | 4 ++++ src/sounds.c | 6 +++++- src/sounds.h | 6 +++++- 7 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 59b9aa921..81fda5c6f 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -426,7 +426,9 @@ typedef struct player_s fixed_t driftcharge; // Charge your drift so you can release a burst of speed UINT8 driftboost; // (0 to 125) - Boost you get from drifting UINT8 strongdriftboost; // (0 to 125) - While active, boost from drifting gives a stronger speed increase + UINT16 gateBoost; // Juicebox Manta Ring boosts + UINT8 gateSound; // Sound effect combo SINT8 aizdriftstrat; // (-1 to 1) - Let go of your drift while boosting? Helper for the SICK STRATZ (sliptiding!) you have just unlocked INT32 aizdrifttilt; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 07db592fb..f77bd95b7 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -252,6 +252,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->strongdriftboost); else if (fastcmp(field,"gateBoost")) lua_pushinteger(L, plr->gateBoost); + else if (fastcmp(field,"gateSound")) + lua_pushinteger(L, plr->gateSound); else if (fastcmp(field,"aizdriftstraft")) lua_pushinteger(L, plr->aizdriftstrat); else if (fastcmp(field,"aizdrifttilt")) @@ -618,6 +620,8 @@ static int player_set(lua_State *L) plr->strongdriftboost = luaL_checkinteger(L, 3); else if (fastcmp(field,"gateBoost")) plr->gateBoost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"gateSound")) + plr->gateSound = luaL_checkinteger(L, 3); else if (fastcmp(field,"aizdriftstraft")) plr->aizdriftstrat = luaL_checkinteger(L, 3); else if (fastcmp(field,"aizdrifttilt")) diff --git a/src/objects/manta-ring.c b/src/objects/manta-ring.c index 7a352cabc..639732af7 100644 --- a/src/objects/manta-ring.c +++ b/src/objects/manta-ring.c @@ -81,6 +81,8 @@ static void Obj_MantaCollide(mobj_t *manta, mobj_t *other) INT32 addBoost = 0; INT32 touchFlag = 0; + size_t i; + distance = P_AproxDistance(P_AproxDistance( other->x - manta->x, other->y - manta->y), @@ -117,10 +119,31 @@ static void Obj_MantaCollide(mobj_t *manta, mobj_t *other) addBoost = max(MANTA_MINPWR, addBoost); } - S_StartSound(other, sfx_gatefx); - if (other->player != NULL) { + UINT8 snd = 0; + + if (other->player->speedboost > FRACUNIT/4) + { + snd = other->player->gateSound; + other->player->gateSound++; + + if (other->player->gateSound > 4) + { + other->player->gateSound = 4; + } + } + else + { + other->player->gateSound = 0; + } + + for (i = 0; i < 5; i++) + { + S_StopSoundByID(other, sfx_gate01 + i); + } + + S_StartSound(other, sfx_gate01 + snd); other->player->gateBoost += addBoost/2; if (P_IsDisplayPlayer(other->player) == true) diff --git a/src/objects/spb.c b/src/objects/spb.c index 28dc2e2e3..2817fc7a7 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -360,9 +360,9 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) spb->fuse = 2*TICRATE; } } +#ifndef SPB_SEEKTEST // Easy debug switch else { -#ifndef SPB_SEEKTEST // Easy debug switch if (dist <= activeDist) { S_StopSound(spb); @@ -377,8 +377,8 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) spb_speed(spb) = desiredSpeed; return; } -#endif } +#endif if (SPBSeekSoundPlaying(spb) == false) { @@ -441,6 +441,24 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) if (pathfindsuccess == true) { +#ifdef SPB_SEEKTEST + if (pathtoplayer.numnodes > 1) + { + // Go to the next waypoint. + curWaypoint = (waypoint_t *)pathtoplayer.array[1].nodedata; + } + else if (destWaypoint->numnextwaypoints > 0) + { + // Run ahead. + curWaypoint = destWaypoint->nextwaypoints[0]; + } + else + { + // Sort of wait at the player's dest waypoint. + circling = true; + curWaypoint = destWaypoint; + } +#else path_t reversepath = {0}; boolean reversesuccess = false; @@ -457,7 +475,6 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) // It's faster to go backwards than to chase forward. // Keep curWaypoint the same, so the SPB waits around for them. circling = true; - Z_Free(reversepath.array); } else if (pathtoplayer.numnodes > 1) { @@ -476,6 +493,12 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) curWaypoint = destWaypoint; } + if (reversesuccess == true) + { + Z_Free(reversepath.array); + } +#endif + Z_Free(pathtoplayer.array); } } diff --git a/src/p_saveg.c b/src/p_saveg.c index e04b4a3f4..a70ac6257 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -268,7 +268,9 @@ static void P_NetArchivePlayers(void) WRITEFIXED(save_p, players[i].driftcharge); WRITEUINT8(save_p, players[i].driftboost); WRITEUINT8(save_p, players[i].strongdriftboost); + WRITEUINT16(save_p, players[i].gateBoost); + WRITEUINT8(save_p, players[i].gateSound); WRITESINT8(save_p, players[i].aizdriftstrat); WRITEINT32(save_p, players[i].aizdrifttilt); @@ -563,7 +565,9 @@ static void P_NetUnArchivePlayers(void) players[i].driftcharge = READFIXED(save_p); players[i].driftboost = READUINT8(save_p); players[i].strongdriftboost = READUINT8(save_p); + players[i].gateBoost = READUINT16(save_p); + players[i].gateSound = READUINT8(save_p); players[i].aizdriftstrat = READSINT8(save_p); players[i].aizdrifttilt = READINT32(save_p); diff --git a/src/sounds.c b/src/sounds.c index 6feb0b6ca..5abb9504b 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1124,7 +1124,11 @@ sfxinfo_t S_sfx[NUMSFX] = {"spbskc", false, 32, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Juicebox for SPB - {"gatefx", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"gate01", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"gate02", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"gate03", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"gate04", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"gate05", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SRB2Kart - Engine sounds // Engine class A diff --git a/src/sounds.h b/src/sounds.h index 0f7fde60e..5194d1114 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1189,7 +1189,11 @@ typedef enum sfx_spbskc, // Juicebox for SPB - sfx_gatefx, + sfx_gate01, + sfx_gate02, + sfx_gate03, + sfx_gate04, + sfx_gate05, // Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy... // Engine class A - Low Speed, Low Weight From 75c87499396f58cc613bd377ce23c41d4bf9f0a6 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 22:58:51 +0100 Subject: [PATCH 43/51] Menu jammin - Menu uses one of three songs (already in music.pk3) - Cycles between them every time you return to the title screen after starting a map - Console-accessible. Do what you want --- src/k_menu.h | 2 +- src/k_menufunc.c | 34 +++++++++++++++++++--------------- src/p_setup.c | 3 +++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 415c54284..caf21013b 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -536,7 +536,7 @@ extern struct menutransition_s { extern boolean menuwipe; extern consvar_t cv_showfocuslost; -extern consvar_t cv_chooseskin, cv_serversort; +extern consvar_t cv_chooseskin, cv_serversort, cv_menujam_update; void M_SetMenuDelay(UINT8 i); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 753a9b767..4ee347587 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -143,6 +143,10 @@ consvar_t cv_showfocuslost = CVAR_INIT ("showfocuslost", "Yes", CV_SAVE, CV_YesN static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}}; consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", DEFAULTSKIN, CV_HIDDEN, skins_cons_t, NULL); +consvar_t cv_menujam_update = CVAR_INIT ("menujam_update", "Off", CV_SAVE, CV_OnOff, NULL); +static CV_PossibleValue_t menujam_cons_t[] = {{0, "menu"}, {1, "menu2"}, {2, "menu3"}, {0, NULL}}; +static consvar_t cv_menujam = CVAR_INIT ("menujam", "0", CV_SAVE, menujam_cons_t, NULL); + // This gametype list is integral for many different reasons. // When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h! CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1]; @@ -945,7 +949,13 @@ void M_StartControlPanel(void) paused = false; CON_ToggleOff(); - S_ChangeMusicInternal("menu", true); + if (cv_menujam_update.value) + { + CV_AddValue(&cv_menujam, 1); + CV_SetValue(&cv_menujam_update, 0); + } + + S_ChangeMusicInternal(cv_menujam.string, true); } menuactive = true; @@ -1686,6 +1696,14 @@ void M_Init(void) CV_RegisterVar(&cv_chooseskin); CV_RegisterVar(&cv_autorecord); + // don't lose your position in the jam cycle + CV_RegisterVar(&cv_menujam_update); + CV_RegisterVar(&cv_menujam); + +#ifndef NONET + CV_RegisterVar(&cv_serversort); +#endif + if (dedicated) return; @@ -1712,20 +1730,6 @@ void M_Init(void) CV_RegisterVar(&cv_dummyaddonsearch); M_UpdateMenuBGImage(true); - -#if 0 -#ifdef HWRENDER - // Permanently hide some options based on render mode - if (rendermode == render_soft) - OP_VideoOptionsMenu[op_video_ogl].status = - OP_VideoOptionsMenu[op_video_kartman].status = - OP_VideoOptionsMenu[op_video_md2] .status = IT_DISABLED; -#endif -#endif - -#ifndef NONET - CV_RegisterVar(&cv_serversort); -#endif } // ================================================== diff --git a/src/p_setup.c b/src/p_setup.c index 6815d1496..762bf0b1b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4074,6 +4074,9 @@ static void P_InitGametype(void) G_RecordDemo(buf); } + + // Started a game? Move on to the next jam when you go back to the title screen + CV_SetValue(&cv_menujam_update, 1); } /** Loads a level from a lump or external wad. From 3501ca7976b621bb7fd7a99f42ed173e9079e31d Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 23 Sep 2022 17:44:22 -0700 Subject: [PATCH 44/51] Match gate animation to Chengi's new visuals --- src/info.c | 4 ++-- src/objects/manta-ring.c | 2 +- src/objects/spb.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/info.c b/src/info.c index 87c0a28c1..947b06701 100644 --- a/src/info.c +++ b/src/info.c @@ -4223,8 +4223,8 @@ state_t states[NUMSTATES] = {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB1}, // S_SPB20 {SPR_SPBM, 8, 175, {NULL}, 0, 0, S_NULL}, // S_SPB_DEAD - {SPR_TRIS, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_TRANS20|FF_ADD, 9, {NULL}, 2, 3, S_MANTA2}, // S_MANTA1 - {SPR_TRNQ, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_TRANS20|FF_ADD, -1, {NULL}, 11, 3, S_NULL}, // S_MANTA2 + {SPR_TRIS, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_ADD, 9, {NULL}, 2, 3, S_MANTA2}, // S_MANTA1 + {SPR_TRNQ, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_ADD, -1, {NULL}, 7, 1, S_NULL}, // S_MANTA2 {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD2}, // S_LIGHTNINGSHIELD1 {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD3}, // S_LIGHTNINGSHIELD2 diff --git a/src/objects/manta-ring.c b/src/objects/manta-ring.c index 639732af7..f136bf597 100644 --- a/src/objects/manta-ring.c +++ b/src/objects/manta-ring.c @@ -28,7 +28,7 @@ #define MANTA_MINTIME (15) #define MANTA_SPRINTTIME (60) -#define MANTA_ALIVEGATE (FF_TRANS40) +#define MANTA_ALIVEGATE (0) #define MANTA_DEADGATE (FF_TRANS80) #define MANTA_SIZE (2 * FRACUNIT) diff --git a/src/objects/spb.c b/src/objects/spb.c index 2817fc7a7..43e059a5e 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -24,7 +24,7 @@ #include "../k_waypoint.h" #include "../k_respawn.h" -//#define SPB_SEEKTEST +#define SPB_SEEKTEST #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) From 5f8901b0333094dd31b71b957304c24d244a55f6 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 20:09:25 -0700 Subject: [PATCH 45/51] Apply wall transfer to any object --- 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 42d8c8302..10978db11 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1671,7 +1671,7 @@ void P_XYMovement(mobj_t *mo) { boolean walltransferred = false; - if (player || mo->flags & MF_SLIDEME) + //if (player || mo->flags & MF_SLIDEME) { // try to slide along it // Wall transfer part 1. pslope_t *transferslope = NULL; From b6b7d7a93ea3b1c7beaf132e3048d8ddb8e15ec2 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 20:10:05 -0700 Subject: [PATCH 46/51] Don't thrust orbinauts while airborne Fixes bonking against a wall transfer. --- src/p_mobj.c | 59 ++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 10978db11..b9dfed581 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6739,40 +6739,45 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } else { - fixed_t finalspeed = mobj->movefactor; - const fixed_t currentspeed = R_PointToDist2(0, 0, mobj->momx, mobj->momy); - fixed_t thrustamount = 0; - fixed_t frictionsafety = (mobj->friction == 0) ? 1 : mobj->friction; mobj_t *ghost = P_SpawnGhostMobj(mobj); ghost->colorized = true; // already has color! - if (!grounded) - { - // No friction in the air - frictionsafety = FRACUNIT; - } - mobj->angle = K_MomentumAngle(mobj); - if (mobj->health <= 5) - { - INT32 i; - for (i = 5; i >= mobj->health; i--) - finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); - } - if (currentspeed >= finalspeed) + if (P_IsObjectOnGround(mobj)) { - // Thrust as if you were at top speed, slow down naturally - thrustamount = FixedDiv(finalspeed, frictionsafety) - finalspeed; - } - else - { - const fixed_t beatfriction = FixedDiv(currentspeed, frictionsafety) - currentspeed; - // Thrust to immediately get to top speed - thrustamount = beatfriction + FixedDiv(finalspeed - currentspeed, frictionsafety); - } + fixed_t finalspeed = mobj->movefactor; + const fixed_t currentspeed = R_PointToDist2(0, 0, mobj->momx, mobj->momy); + fixed_t thrustamount = 0; + fixed_t frictionsafety = (mobj->friction == 0) ? 1 : mobj->friction; - P_Thrust(mobj, mobj->angle, thrustamount); + if (!grounded) + { + // No friction in the air + frictionsafety = FRACUNIT; + } + + if (mobj->health <= 5) + { + INT32 i; + for (i = 5; i >= mobj->health; i--) + finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); + } + + if (currentspeed >= finalspeed) + { + // Thrust as if you were at top speed, slow down naturally + thrustamount = FixedDiv(finalspeed, frictionsafety) - finalspeed; + } + else + { + const fixed_t beatfriction = FixedDiv(currentspeed, frictionsafety) - currentspeed; + // Thrust to immediately get to top speed + thrustamount = beatfriction + FixedDiv(finalspeed - currentspeed, frictionsafety); + } + + P_Thrust(mobj, mobj->angle, thrustamount); + } if (P_MobjTouchingSectorSpecial(mobj, 3, 1, true)) K_DoPogoSpring(mobj, 0, 1); From 79f445401683ddf42d855e4a5e2f2f15c6f529dd Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 23 Sep 2022 21:06:33 -0700 Subject: [PATCH 47/51] Let jawz wall transfer; don't thrust in air --- src/p_enemy.c | 38 +++++++++++++++++------------------ src/p_mobj.c | 55 +++++++++++++++++++++++---------------------------- 2 files changed, 43 insertions(+), 50 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 527dcf0b6..90ab62e29 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -13210,7 +13210,6 @@ void A_ItemPop(mobj_t *actor) void A_JawzChase(mobj_t *actor) { - const fixed_t currentspeed = R_PointToDist2(0, 0, actor->momx, actor->momy); player_t *player; fixed_t thrustamount = 0; fixed_t frictionsafety = (actor->friction == 0) ? 1 : actor->friction; @@ -13295,30 +13294,29 @@ void A_JawzChase(mobj_t *actor) P_SetTarget(&actor->tracer, NULL); } - if (!P_IsObjectOnGround(actor)) - { - // No friction in the air - frictionsafety = FRACUNIT; - } - - if (currentspeed >= topspeed) - { - // Thrust as if you were at top speed, slow down naturally - thrustamount = FixedDiv(topspeed, frictionsafety) - topspeed; - } - else - { - const fixed_t beatfriction = FixedDiv(currentspeed, frictionsafety) - currentspeed; - // Thrust to immediately get to top speed - thrustamount = beatfriction + FixedDiv(topspeed - currentspeed, frictionsafety); - } - if (!actor->tracer) { actor->angle = K_MomentumAngle(actor); } - P_Thrust(actor, actor->angle, thrustamount); + if (P_IsObjectOnGround(actor)) + { + const fixed_t currentspeed = R_PointToDist2(0, 0, actor->momx, actor->momy); + + if (currentspeed >= topspeed) + { + // Thrust as if you were at top speed, slow down naturally + thrustamount = FixedDiv(topspeed, frictionsafety) - topspeed; + } + else + { + const fixed_t beatfriction = FixedDiv(currentspeed, frictionsafety) - currentspeed; + // Thrust to immediately get to top speed + thrustamount = beatfriction + FixedDiv(topspeed - currentspeed, frictionsafety); + } + + P_Thrust(actor, actor->angle, thrustamount); + } if ((actor->tracer != NULL) && (actor->tracer->health > 0)) return; diff --git a/src/p_mobj.c b/src/p_mobj.c index b9dfed581..16d07dfa1 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1594,21 +1594,7 @@ void P_XYMovement(mobj_t *mo) else if (P_MobjWasRemoved(mo)) return; - //{ SRB2kart - Jawz - if (mo->type == MT_JAWZ || mo->type == MT_JAWZ_DUD) - { - if (mo->health == 1) - { - // This Item Damage - S_StartSound(mo, mo->info->deathsound); - P_KillMobj(mo, NULL, NULL, DMG_NORMAL); - - P_SetObjectMomZ(mo, 8*FRACUNIT, false); - P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT); - } - } - //} - else if (mo->flags & MF_MISSILE) + if (mo->flags & MF_MISSILE) { // explode a missile if (P_CheckSkyHit(mo)) @@ -1745,23 +1731,32 @@ void P_XYMovement(mobj_t *mo) fx->scale = mo->scale; } - if (mo->type == MT_ORBINAUT) // Orbinaut speed decreasing + switch (mo->type) { - if (mo->health > 1) - { - S_StartSound(mo, mo->info->attacksound); - mo->health--; - mo->threshold = 0; - } - else if (mo->health == 1) - { - // This Item Damage - S_StartSound(mo, mo->info->deathsound); - P_KillMobj(mo, NULL, NULL, DMG_NORMAL); + case MT_ORBINAUT: // Orbinaut speed decreasing + if (mo->health > 1) + { + S_StartSound(mo, mo->info->attacksound); + mo->health--; + mo->threshold = 0; + } + /*FALLTHRU*/ - P_SetObjectMomZ(mo, 8*FRACUNIT, false); - P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT); - } + case MT_JAWZ: + case MT_JAWZ_DUD: + if (mo->health == 1) + { + // This Item Damage + S_StartSound(mo, mo->info->deathsound); + P_KillMobj(mo, NULL, NULL, DMG_NORMAL); + + P_SetObjectMomZ(mo, 8*FRACUNIT, false); + P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT); + } + break; + + default: + break; } // Bubble bounce From 9ecd5b9c4b050872b03a58a33fed1004a42b2a7b Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 23 Sep 2022 22:14:10 -0700 Subject: [PATCH 48/51] Add shockwave support to K_SpawnDriftElectricSparks --- src/k_kart.c | 20 +++++++++++--------- src/k_kart.h | 2 +- src/objects/manta-ring.c | 3 +++ src/objects/spb.c | 2 +- src/p_spec.c | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 789567583..b607def10 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4931,9 +4931,10 @@ static void K_SpawnDriftElectricity(player_t *player) } } -void K_SpawnDriftElectricSparks(player_t *player) +void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave) { SINT8 hdir, vdir, i; + int shockscale = shockwave ? 2 : 1; mobj_t *mo = player->mo; angle_t momangle = K_MomentumAngle(mo) + ANGLE_180; @@ -4943,12 +4944,7 @@ void K_SpawnDriftElectricSparks(player_t *player) fixed_t z = FixedDiv(mo->height, 2 * mo->scale); // P_SpawnMobjFromMobj will rescale fixed_t sparkspeed = mobjinfo[MT_DRIFTELECTRICSPARK].speed; - fixed_t sparkradius = 2 * mobjinfo[MT_DRIFTELECTRICSPARK].radius; - UINT16 color = K_DriftSparkColor(player, player->driftcharge); - - // if the sparks are spawned from first blood rather than drift boost, color will be SKINCOLOR_NONE. ew! - if (color == SKINCOLOR_NONE) - color = SKINCOLOR_SILVER; + fixed_t sparkradius = 2 * shockscale * mobjinfo[MT_DRIFTELECTRICSPARK].radius; for (hdir = -1; hdir <= 1; hdir += 2) { @@ -4971,6 +4967,12 @@ void K_SpawnDriftElectricSparks(player_t *player) spark->momx += mo->momx; // copy player speed spark->momy += mo->momy; spark->momz += P_GetMobjZMovement(mo); + spark->destscale = shockscale * spark->scale; + P_SetScale(spark, shockscale * spark->scale); + spark->radius = shockscale * spark->radius; + + if (shockwave) + spark->frame |= FF_ADD; sparkangle += ANGLE_90; } @@ -9097,7 +9099,7 @@ static void K_KartDrift(player_t *player, boolean onground) player->strongdriftboost = 85; K_SpawnDriftBoostExplosion(player, 3); - K_SpawnDriftElectricSparks(player); + K_SpawnDriftElectricSparks(player, K_DriftSparkColor(player, player->driftcharge), false); } else if (player->driftcharge >= dsfour) { @@ -9111,7 +9113,7 @@ static void K_KartDrift(player_t *player, boolean onground) player->strongdriftboost = 125; K_SpawnDriftBoostExplosion(player, 4); - K_SpawnDriftElectricSparks(player); + K_SpawnDriftElectricSparks(player, K_DriftSparkColor(player, player->driftcharge), false); } } diff --git a/src/k_kart.h b/src/k_kart.h index 3db28a9f2..a3f7dae0c 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -125,7 +125,7 @@ INT32 K_GetKartDriftSparkValue(player_t *player); INT32 K_StairJankFlip(INT32 value); INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage); void K_SpawnDriftBoostExplosion(player_t *player, int stage); -void K_SpawnDriftElectricSparks(player_t *player); +void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave); void K_KartUpdatePosition(player_t *player); mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount); void K_DropItems(player_t *player); diff --git a/src/objects/manta-ring.c b/src/objects/manta-ring.c index f136bf597..69f98fc06 100644 --- a/src/objects/manta-ring.c +++ b/src/objects/manta-ring.c @@ -138,6 +138,9 @@ static void Obj_MantaCollide(mobj_t *manta, mobj_t *other) other->player->gateSound = 0; } + K_SpawnDriftBoostExplosion(other->player, 3); + K_SpawnDriftElectricSparks(other->player, SKINCOLOR_CRIMSON, true); + for (i = 0; i < 5; i++) { S_StopSoundByID(other, sfx_gate01 + i); diff --git a/src/objects/spb.c b/src/objects/spb.c index 43e059a5e..e939b1b31 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -24,7 +24,7 @@ #include "../k_waypoint.h" #include "../k_respawn.h" -#define SPB_SEEKTEST +// #define SPB_SEEKTEST #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) diff --git a/src/p_spec.c b/src/p_spec.c index 681e5e8e9..3e8edb2b4 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1925,7 +1925,7 @@ static void K_HandleLapIncrement(player_t *player) player->startboost = 125; K_SpawnDriftBoostExplosion(player, 4); - K_SpawnDriftElectricSparks(player); + K_SpawnDriftElectricSparks(player, SKINCOLOR_SILVER, false); rainbowstartavailable = false; } From fdffed06223b881aafcf2d43478f5212da5acdbb Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 23 Sep 2022 23:39:35 -0700 Subject: [PATCH 49/51] Remove redundant radius set --- src/k_kart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 1a32586bc..5d9faf36f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4966,7 +4966,6 @@ void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave) spark->momz += P_GetMobjZMovement(mo); spark->destscale = shockscale * spark->scale; P_SetScale(spark, shockscale * spark->scale); - spark->radius = shockscale * spark->radius; if (shockwave) spark->frame |= FF_ADD; From 42c6f4fe92e60bda2f1d274cf81fd4b80652b009 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 24 Sep 2022 02:47:52 -0700 Subject: [PATCH 50/51] Fix HUD drawing crash if 1 or more KITEM_NONE blame 375fb72de --- src/k_hud.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 86d37c62a..9f14d882a 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -695,7 +695,7 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) } } -static patch_t **K_GetItemPatchTable(INT32 item) +static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset) { patch_t **kp[1 + NUMKARTITEMS] = { kp_sadface, @@ -723,8 +723,8 @@ static patch_t **K_GetItemPatchTable(INT32 item) kp_droptarget, }; - if (item >= KITEM_SAD && item < NUMKARTITEMS) - return kp[item - KITEM_SAD]; + if (item == KITEM_SAD || (item > KITEM_NONE && item < NUMKARTITEMS)) + return kp[item - KITEM_SAD][offset]; else return NULL; } @@ -1146,7 +1146,7 @@ static void K_drawKartItem(void) break; default: - localpatch = K_GetItemPatchTable(item)[offset]; + localpatch = K_GetCachedItemPatch(item, offset); } } else @@ -1224,7 +1224,7 @@ static void K_drawKartItem(void) /*FALLTHRU*/ default: - localpatch = K_GetItemPatchTable(stplyr->itemtype)[offset]; + localpatch = K_GetCachedItemPatch(stplyr->itemtype, offset); if (localpatch == NULL) localpatch = kp_nodraw; // diagnose underflows From e5d7b3467c5b114b274bafcfe3e25d016e5b0e17 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sat, 24 Sep 2022 15:56:42 +0000 Subject: [PATCH 51/51] Let stop building a NONET build of Kart --- .circleci/config.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d8ac4b995..a9e773ea5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -49,15 +49,15 @@ jobs: paths: - /var/cache/apt/archives - checkout - - run: - name: Compile without network support - command: make -C src LINUX=1 ERRORMODE=1 -k NONET=1 - - run: - name: wipe build - command: make -C src LINUX=1 cleandep - - run: - name: rebuild depend - command: make -C src LINUX=1 clean + #- run: + # name: Compile without network support + # command: make -C src LINUX=1 ERRORMODE=1 -k NONET=1 + #- run: + # name: wipe build + # command: make -C src LINUX=1 cleandep + #- run: + # name: rebuild depend + # command: make -C src LINUX=1 clean - restore_cache: keys: - v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}