Red FOE nametags, try not to sort empty lists of bots

This commit is contained in:
Antonio Martinez 2025-08-03 23:36:38 -04:00
parent 6a2568e7a7
commit d78afd9de3
3 changed files with 67 additions and 63 deletions

View file

@ -170,6 +170,8 @@ static boolean CompareRivals(player_t *a, player_t *b)
void K_AssignFoes(void)
{
std::vector<player_t *> bots;
boolean addedplayer = false;
for (UINT8 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] == false)
@ -179,16 +181,21 @@ void K_AssignFoes(void)
if (!player->spectator && player->bot)
{
addedplayer = true;
bots.push_back(player);
player->botvars.foe = false;
}
}
// Why the fuck is this blowing up sometimes
if (!addedplayer)
return;
std::stable_sort(bots.begin(), bots.end(), CompareRivals);
UINT8 i = 0;
for (auto &bot : bots)
{
{
if (bot != NULL)
bot->botvars.foe = true;
@ -425,13 +432,13 @@ void K_UpdateGrandPrixBots(void)
players[i].spectator = K_BotDefaultSpectator();
}
K_AssignFoes();
if (grandprixinfo.wonround == false)
{
return;
}
K_AssignFoes();
// Find the rival.
for (i = 0; i < MAXPLAYERS; i++)
{
@ -692,7 +699,7 @@ void K_IncreaseBotDifficulty(player_t *bot)
// RELAXED MODE:
// Continues don't drop bot difficulty, because we always advance.
// Bots will still level up from standard advancement; we need a
// much steeper rank nudge to keep difficulty at the right level.
// much steeper rank nudge to keep difficulty at the right level.
if (grandprixinfo.gamespeed == KARTSPEED_EASY)
{
switch(averageRank)

View file

@ -525,7 +525,7 @@ void K_LoadKartHUDGraphics(void)
buffer[7] = '0'+((i) % 10);
HU_UpdatePatch(&kp_overdrive[0][i], "%s", buffer);
}
sprintf(buffer, "bsOVRDxx");
for (i = 0; i < 32; i++)
{
@ -2000,7 +2000,7 @@ static void K_drawKartItem(void)
static void K_drawBackupItem(void)
{
bool tiny = r_splitscreen > 1;
patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw };
patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw };
patch_t *localbg = (kp_itembg[2]);
patch_t *localinv = kp_invincibility[((leveltime % (6*3)) / 3) + 7 + tiny];
INT32 fx = 0, fy = 0, fflags = 0, tx = 0, ty = 0; // final coords for hud and flags...
@ -3406,7 +3406,7 @@ static void K_drawKartDuelScores(void)
{
flags |= V_SNAPTOBOTTOM;
flags &= ~V_SNAPTOTOP;
basey = BASEVIDHEIGHT - 40;
basey = BASEVIDHEIGHT - 40;
}
basex = BASEVIDWIDTH - 80;
}
@ -3493,7 +3493,7 @@ static void K_drawKartDuelScores(void)
V_DrawScaledPatch(basex-barheight+foeheight, basey, flags, kp_duel_4over);
else
V_DrawScaledPatch(basex, basey-barheight+foeheight, flags, kp_duel_over);
if (!use4p)
{
V_DrawScaledPatch(basex, basey, flags, kp_duel_foe);
@ -3512,7 +3512,7 @@ static void K_drawKartDuelScores(void)
}
foenum.text("{}", foe->duelscore);
younum.text("{}", stplyr->duelscore);
younum.text("{}", stplyr->duelscore);
// minirankings shamelessly copypasted because i know that shit works already
// and SURELY we will never need to use this somewhere else, right?
@ -3526,7 +3526,7 @@ static void K_drawKartDuelScores(void)
UINT8 drawme = draw ? (stplyr - players) : (foe - players);
UINT16 drawx = basex + (draw ? youx : foex);
UINT16 drawy = basey + (draw ? youy : foey);
if (!playeringame[drawme] || players[drawme].spectator)
continue;
@ -3790,8 +3790,8 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
if (R_GetViewNumber() == 1)
{
flags |= V_SNAPTOBOTTOM;
flags &= ~V_SNAPTOTOP;
basey = 170;
flags &= ~V_SNAPTOTOP;
basey = 170;
}
}
}
@ -3817,7 +3817,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
return;
using srb2::Draw;
srb2::Draw::Font scorefont = Draw::Font::kTimer;
srb2::Draw::Font scorefont = Draw::Font::kTimer;
if (totalscore > 99)
{
@ -3834,7 +3834,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
else
{
scorefont = Draw::Font::kZVote;
}
}
}
UINT32 youscore = stplyr->teamimportance;
@ -3870,7 +3870,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
if (teams_lastleveltime[vn] != leveltime) // Timing consistency
{
INT32 delta = abs(easedallyscore[vn] - allyscore); // how wrong is display score?
if (scorechangecooldown[vn] == 0 && delta)
{
if (allyscore > easedallyscore[vn])
@ -3886,9 +3886,9 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
enemycolor = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_WHITE, GTC_CACHE);
}
scorechangecooldown[vn] = TICRATE/delta;
}
}
}
if (!fromintermission)
{
// replace scores with eased scores
@ -4009,7 +4009,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
if (totalscore > 99)
{
enemynum.text("{:03}", enemyscore);
allynum.text("{:03}", allyscore);
allynum.text("{:03}", allyscore);
}
else
{
@ -5346,8 +5346,10 @@ static void K_DrawCPUTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT32 flag
K_DrawNameTagItemSpy(barx, bary, p, flags);
}
UINT8 *foecol = R_GetTranslationColormap(TC_RAINBOW, static_cast<skincolornum_t>(SKINCOLOR_RED), GTC_CACHE);
UINT8 blink = ((leveltime / 7) & 1);
V_DrawFixedPatch(x, y, FRACUNIT, flags, kp_cpu[blink], NULL);
V_DrawFixedPatch(x, y, FRACUNIT, flags, kp_cpu[blink], (p->botvars.foe) ? foecol : NULL);
}
static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT32 flags)
@ -5856,13 +5858,13 @@ INT32 K_GetMinimapSplitFlags(const boolean usingProgressBar)
#define ICON_DOT_RADIUS (10)
// modified pick from blondedradio/RadioRacers (but there are like 57 things we don't want in the commit)
// (so gogo gadget copypaste, thanks for a good feature and saving me work i was supposed to do anyway)
// (so gogo gadget copypaste, thanks for a good feature and saving me work i was supposed to do anyway)
static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags)
{
fixed_t amnumxpos, amnumypos;
INT32 amxpos, amypos;
if (exitcountdown || leveltime > g_battleufo.due || battleprisons)
if (exitcountdown || leveltime > g_battleufo.due || battleprisons)
return;
tic_t raw = g_battleufo.due - leveltime;
@ -5872,7 +5874,7 @@ static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hud
{
flags |= (raw / (TICRATE/2) % 2) ? V_YELLOWMAP : 0;
}
if (countdown <= 10)
{
flags &= ~(V_HUDTRANS|V_HUDTRANSHALF);

View file

@ -135,7 +135,7 @@ boolean K_DuelItemAlwaysSpawns(mapthing_t *mt)
boolean K_InRaceDuel(void)
{
return (
inDuel &&
inDuel &&
(gametyperules & GTR_CIRCUIT) &&
!(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE) &&
!specialstageinfo.valid &&
@ -3776,7 +3776,7 @@ static void K_GetKartBoostPower(player_t *player)
// This one's a little special: we add extra top speed per tic of ringboost stored up, to allow for Ring Box to really rocket away.
// (We compensate when decrementing ringboost to avoid runaway exponential scaling hell.)
fixed_t rb = FixedDiv(player->ringboost * FRACUNIT, max(FRACUNIT, K_RingDurationBoost(player)));
fixed_t rp = ((9 - player->kartspeed) + (9 - player->kartweight)) * ((3*FRACUNIT/20)/16);
fixed_t rp = ((9 - player->kartspeed) + (9 - player->kartweight)) * ((3*FRACUNIT/20)/16);
ADDBOOST(
ringboost_base + FixedMul(FRACUNIT / 1750, rb) + rp,
4*FRACUNIT,
@ -3804,7 +3804,7 @@ static void K_GetKartBoostPower(player_t *player)
// Even when not inputting a turn, drift prediction is hard.
// Turn solver will sometimes need to slightly turn to stay "aligned".
// Award full boost even if turn solver creates a fractional miniturn.
const INT16 inner_deadzone = KART_FULLTURN / 100;
const INT16 inner_deadzone = KART_FULLTURN / 100;
INT16 steer_threshold = FixedMul((FRACUNIT * player->kartweight) / 9, max_steer_threshold)>>FRACBITS;
@ -4310,8 +4310,8 @@ void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact)
UINT16 scaledamps = min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10);
// Debug print for scaledamps calculation
// CONS_Printf("K_SpawnAmps: player=%s, amps=%d, kartspeed=%d, kartweight=%d, itemdistance=%d, itemdistmult=%0.2f, statscaledamps=%d, distscaledamps=%d\n",
// player_names[player-players], amps, player->kartspeed, player->kartweight,
// itemdistance, FixedToFloat(itemdistmult),
// player_names[player-players], amps, player->kartspeed, player->kartweight,
// itemdistance, FixedToFloat(itemdistmult),
// min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10),
// FixedMul(scaledamps<<FRACBITS, itemdistmult)>>FRACBITS);
scaledamps = FixedMul(scaledamps<<FRACBITS, itemdistmult)>>FRACBITS;
@ -4370,8 +4370,8 @@ void K_AwardPlayerAmps(player_t *player, UINT8 amps)
if (oldamps/AMPLEVEL != player->amps/AMPLEVEL)
{
UINT8 amplevel = player->amps / AMPLEVEL;
static sfxenum_t bwips[7] = {sfx_mbs4c,
sfx_mbs4d, sfx_mbs4e, sfx_mbs4f, sfx_mbs50,
static sfxenum_t bwips[7] = {sfx_mbs4c,
sfx_mbs4d, sfx_mbs4e, sfx_mbs4f, sfx_mbs50,
sfx_mbs51, sfx_mbs52};
amplevel = min(amplevel, 6);
@ -4435,7 +4435,7 @@ void K_CheckpointCrossAward(player_t *player)
//CONS_Printf("player: %s factor: %.2f exp: %d\n", player_names[player-players], FIXED_TO_FLOAT(player->gradingfactor), player->exp);
if (!player->cangrabitems)
player->cangrabitems = 1;
K_AwardPlayerRings(player, (player->bot ? 20 : 10), true);
// Update Duel scoring.
@ -6680,7 +6680,7 @@ void K_SpawnFireworkTrail(mobj_t *mo)
if (mo->player)
dust->color = mo->player->skincolor;
else
else
dust->color = mo->color;
dust->colorized = true;
@ -9366,7 +9366,7 @@ static void K_UpdateTripwire(player_t *player)
else
CONS_Printf("airtime: %d, twLen: %d, twAirLen: %d\n", player->airtime, player->tripwireLeniency, player->tripwireAirLeniency);
*/
if (boostExists)
{
// If player is MOSTLY on the ground.
@ -9557,13 +9557,13 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
for (doubler = 0; doubler < 2; doubler++)
{
fixed_t heightOffset = player->mo->height + (24*player->mo->scale);
if (P_IsObjectFlipped(player->mo))
if (P_IsObjectFlipped(player->mo))
{
// This counteracts the offset added by K_FlipFromObject so it looks seamless from non-flipped.
heightOffset += player->mo->height - FixedMul(player->mo->scale, player->mo->height);
heightOffset *= P_MobjFlip(player->mo); // Fleep.
}
mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy,
player->mo->z + P_GetMobjZMovement(player->mo) + heightOffset, MT_THOK);
@ -9675,7 +9675,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
sub = diff * (sub > 0 ? 1 : -1);
player->mo->momz -= sub;
}
}
else
{
@ -10101,7 +10101,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->invincibilitytimer--;
if (player->invincibilitytimer && K_PlayerScamPercentage(player, 1))
player->invincibilitytimer--;
// Extra tripwire leniency for the end of invincibility
if (player->invincibilitytimer <= 0) {
player->tripwireLeniency = max( player->tripwireLeniency, TICRATE );
@ -10112,7 +10112,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
{
// freeze the stunned timer while baildrop is active
// while retaining the value that was initially set
player->stunned++;
player->stunned++;
mobj_t *pmo = player->mo;
// particle spawn
@ -10182,7 +10182,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->amps > 0)
K_DefensiveOverdrive(player);
P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo);
P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo);
player->bailhitlag = false;
}
@ -10232,6 +10232,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
S_StartSound(player->mo, sfx_kc33);
P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo);
player->bailquake = false;
}
// The precise ordering of start-of-level made me want to cut my head off,
@ -10976,13 +10978,6 @@ void K_KartResetPlayerColor(player_t *player)
goto base;
}
if (player->botvars.foe)
{
player->mo->colorized = true;
player->mo->color = SKINCOLOR_BLACK;
goto finalise;
}
if (player->eggmanexplode) // You're gonna diiiiie
{
const INT32 flashtime = 4<<(player->eggmanexplode/TICRATE);
@ -13743,7 +13738,7 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original)
{
INT16 myradius = FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale) / FRACUNIT;
INT16 SMALL_WAYPOINT = 450;
if (myradius < SMALL_WAYPOINT)
errorfrict *= 2;
}
@ -14052,7 +14047,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
// ...which nullifies a lot of designed advantages for accel types and high-weight racers.
//
// In addition, it's at Gear 3 Thunderdome speed, which can make it hard for heavies to
// take strong lines without brakedrifting.
// take strong lines without brakedrifting.
//
// To try and help close this gap, we fudge Ring Box payouts to allow weaker characters
// better access to things that make them go fast, without changing core handling.
@ -14072,7 +14067,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
// Scale from base payout at 9/1 to max payout at 1/9.
award = Easing_InCubic(FRACUNIT*total/maxtotal, 13*award/10, 18*award/10);
// And, because we don't have to give a damn about sandbagging, up the stakes the longer we progress!
// And, because we don't have to give a damn about sandbagging, up the stakes the longer we progress!
if (gametyperules & GTR_CIRCUIT)
{
UINT8 maxgrade = 10;
@ -14212,7 +14207,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
else if (!(player->instaWhipCharge >= INSTAWHIP_CHARGETIME && P_PlayerInPain(player))) // Allow reversal whip
player->instaWhipCharge = 0;
}
if (player->cmd.buttons & BT_BAIL && (player->cmd.buttons & BT_RESPAWNMASK) != BT_RESPAWNMASK)
{
if (leveltime < introtime || (gametyperules & GTR_SPHERES))
@ -14846,7 +14841,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
mobj_t *at1 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
mobj_t *at2 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
mobj_t *at3 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
P_SetMobjState(at1, S_THNG);
P_SetMobjState(at2, S_THND);
P_SetMobjState(at3, S_THNH);
@ -14857,7 +14852,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
P_SetTarget(&at1->target, player->mo);
P_SetTarget(&at2->target, player->mo);
P_SetTarget(&at3->target, player->mo);
S_StartSound(player->mo, LIGHTNING_SOUND);
}
break;
@ -14913,7 +14908,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (player->curshield != KSHIELD_BUBBLE)
{
mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BUBBLESHIELD);
// MT_BUBBLESHIELD doesn't have MF_NOBLOCKMAP so we need to remove this manually.
// MT_BUBBLESHIELD doesn't have MF_NOBLOCKMAP so we need to remove this manually.
// Otherwise if you roll a bubble shield while flipped, the visuals look too mismatched.
shield->eflags &= ~MFE_VERTICALFLIP;
P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2));
@ -15097,14 +15092,14 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
S_StartSound(player->mo, sfx_gsha7);
if (P_IsObjectOnGround(player->mo)) // facing angle blends w/ momentum angle for game-feel
if (P_IsObjectOnGround(player->mo)) // facing angle blends w/ momentum angle for game-feel
{
P_Thrust(player->mo, player->mo->angle, 25*player->mo->scale);
P_Thrust(player->mo, K_MomentumAngle(player->mo), 25*player->mo->scale);
P_Thrust(player->mo, player->mo->angle, 25*player->mo->scale);
P_Thrust(player->mo, K_MomentumAngle(player->mo), 25*player->mo->scale);
}
else // air version is momentum angle only, reduces cheese, is twice as strong to compensate
{
P_Thrust(player->mo, K_MomentumAngle(player->mo), 50*player->mo->scale);
P_Thrust(player->mo, K_MomentumAngle(player->mo), 50*player->mo->scale);
}
UINT8 numsparks = 8;
@ -16373,7 +16368,7 @@ boolean K_PlayerCanUseItem(player_t *player)
return (player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime);
}
// ===
// ===
// THE EXP ZONE
// ===
@ -16387,7 +16382,7 @@ static boolean K_IsValidOpponent(player_t *me, player_t *them)
return false;
if (G_SameTeam(me, them))
return false;
return true;
}
@ -16479,7 +16474,7 @@ UINT16 K_GetEXP(player_t *player)
UINT16 exp = FixedRescale(player->gradingfactor, factormin, factormax, Easing_Linear, targetminexp, targetmaxexp)>>FRACBITS;
// CONS_Printf("Player %s numgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n",
// CONS_Printf("Player %s numgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n",
// player_names[player - players], numgradingpoints, player->gradingpointnum, targetminexp, targetmaxexp, FIXED_TO_FLOAT(player->gradingfactor), FIXED_TO_FLOAT(factormin), FIXED_TO_FLOAT(factormax), exp);
return exp;
@ -16493,7 +16488,7 @@ UINT32 K_GetNumGradingPoints(void)
return numlaps * (1 + Obj_GetCheckpointCount());
}
// ===
// ===
// END EXP ZONE
// ===
@ -16512,7 +16507,7 @@ boolean K_IsPickMeUpItem(mobjtype_t type)
extern consvar_t cv_debugpickmeup;
if (cv_debugpickmeup.value)
return false;
switch (type)
{
case MT_JAWZ:
@ -16691,7 +16686,7 @@ boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2, boolean allowHostile)
if (!K_PickUp(victim->player, inflictor))
return false;
K_AddHitLag(victim, 3, false);
K_AddHitLag(victim, 3, false);
P_RemoveMobj(inflictor);
return true;
@ -16718,7 +16713,7 @@ fixed_t K_TeamComebackMultiplier(player_t *player)
else
theirdistance += K_GetItemRouletteDistance(&players[i], players[i].itemRoulette.playing);
}
fixed_t multiplier = FixedDiv(ourdistance, theirdistance);
multiplier = min(multiplier, 3*FRACUNIT);
multiplier = max(multiplier, FRACUNIT);