Attempts to salvage Alt. Invin

What do people see in this thing...

* A player's invincibility is now permanently active until they get past the cluster player
* Speed boost has been buffed
* Cluster calculations now use an average-distance between players
* The odds system now uses a binary "force or not" format, instead of the gradienting system used prior.
  This should ensure that the item is rolled only when players need it the most.
This commit is contained in:
yamamama 2026-02-15 19:12:58 -05:00
parent 3ed99e27ef
commit b568e040ec
7 changed files with 106 additions and 419 deletions

View file

@ -506,9 +506,9 @@ consvar_t cv_kartstacking_invincibility_classicspeedboost = CVAR_INIT ("vanillab
consvar_t cv_kartstacking_invincibility_classicaccelboost = CVAR_INIT ("vanillaboost_invincibility_classicaccelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_invincibility_classichandleboost = CVAR_INIT ("vanillaboost_invincibility_classichandleboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
// Alternate boosts
consvar_t cv_kartstacking_invincibility_alternatespeedboost = CVAR_INIT ("vanillaboost_invincibility_alternatespeedboost", "0.67", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_invincibility_alternatespeedboost = CVAR_INIT ("vanillaboost_invincibility_alternatespeedboost", "0.75", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_invincibility_alternateaccelboost = CVAR_INIT ("vanillaboost_invincibility_alternateaccelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_invincibility_alternatehandleboost = CVAR_INIT ("vanillaboost_invincibility_alternatehandleboost", "0.45", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_invincibility_alternatehandleboost = CVAR_INIT ("vanillaboost_invincibility_alternatehandleboost", "0.48", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_invincibility_stackable = CVAR_INIT ("vanillaboost_invincibility_stackable", "On", CV_NETVAR|CV_GUARD, CV_OnOff, NULL);
consvar_t cv_kartstacking_grow_speedboost = CVAR_INIT ("vanillaboost_grow_speedboost", "0.2", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
@ -672,7 +672,7 @@ consvar_t cv_kartinvintheme = CVAR_INIT ("kartinvintheme", "Standard", CV_SAVE,
// How far the player must be from the cluster to begin frequently rolling Invincibility.
static CV_PossibleValue_t invindist_cons_t[] = {{1, "MIN"}, {32000, "MAX"}, {0, NULL}};
consvar_t cv_kartinvindist = CVAR_INIT ("kartinvindist", "8600", CV_NETVAR|CV_CHEAT|CV_GUARD, invindist_cons_t, NULL);
consvar_t cv_kartinvindist = CVAR_INIT ("kartinvindist", "17000", CV_NETVAR|CV_CHEAT|CV_GUARD, invindist_cons_t, NULL);
consvar_t cv_kartinvindistmul = CVAR_INIT ("kartinvindistmul", "0.54", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);

View file

@ -257,6 +257,8 @@ void K_DisplayItemTimers(void)
stplyr->invincibilitytimer,
{qche("K_TIINV1"), qche("K_TIINV2"), qche("K_TIINV3"), qche("K_TIINV4"), qche("K_TIINV5"), qche("K_TIINV6")},
3,
// Hide the timer until it's necessary
((stplyr->invincibilitytimer >= MININVINTIME) && K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? TIMER_NONUMBER : 0,
},
{ // grow
"grow",

View file

@ -1389,7 +1389,8 @@ static void K_drawKartItem(void)
}
else if ((stplyr->invincibilitytimer) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY)))
{
itembar = FixedDiv(stplyr->invincibilitytimer, max(1, stplyr->maxinvincibilitytime));
if (stplyr->invincibilitytimer < MININVINTIME)
itembar = FixedDiv(stplyr->invincibilitytimer, max(1, stplyr->maxinvincibilitytime));
if (stplyr->invincibilitycancel > 0)
flamebar = FixedDiv(stplyr->invincibilitycancel, 26);
@ -4498,8 +4499,6 @@ static void K_drawKartMinimap(void)
FRACUNIT - (V_GetHudTrans() * FRACUNIT / 10);
}
transmul *= 2;
invintrans =
max(0,
min(9,

View file

@ -504,41 +504,20 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush)
// Odds value for Alt. Invin. to force itself on trailing players.
#define INVFORCEODDS (MAXINVODDS / 2)
#define FRAC_95pct (95 * FRACUNIT / 100)
static INT32 K_KartGetInvincibilityOdds(UINT32 dist)
{
UINT32 invindist = INVINDIST/2;
// I'm tired; use floating-point distances for this fuckshit.
INT32 invdist = INVINDIST;
if (dist < invindist)
float fac_f = (float)(dist) / ((float)(invdist));
if (fac_f < 1.0f)
return 0;
INT32 finodds = 0;
fixed_t fac = (min(32000, (fixed_t)dist) * FRACUNIT) / (INVINDIST);
if (fac > FRACUNIT)
{
// Desperation! Climb exponentially until Invincibility is practically guaranteed.
fac = (((min(32000, (fixed_t)dist) * FRACUNIT) / (INVINDIST)) - FRACUNIT) >> 1;
finodds = Easing_InCubic(fac, INVODDS, MAXINVODDS);
}
else
{
if (fac <= FRAC_95pct)
{
// Invincibility is practically useless at lower distances.
// Only let it appear at or above 95%.
return 0;
}
// Basic linear climb to "reasonable" odds.
finodds = FixedMul(INVODDS, fac);
}
return min(MAXINVODDS, finodds);
// If you're far enough for this to be in your item slot, you're far enough to SERIOUSLY need this.
return MAXINVODDS;
}
#undef FRAC_95pct
// updates all result cooldown timers, and sets cooldowns for "unique" items
void K_UpdateItemCooldown(void)
{

View file

@ -1013,7 +1013,7 @@ static fixed_t K_CheckOffroadCollide(mobj_t *mo)
static fixed_t K_OffroadGradient(player_t *player, fixed_t offroad)
{
// At 50% or lower Invincibility, offroad creeps up on you.
fixed_t invinoffroad = (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? ((player->invincibilitytimer) ? FRACUNIT : 0) : min(FRACUNIT, K_InvincibilityGradient(player->invincibilitytimer) << 1);
fixed_t invinoffroad = (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? ((player->invincibilitytimer) ? FRACUNIT : 0) : min(FRACUNIT, K_InvincibilityGradient(player->invincibilitytimer));
fixed_t fac = CLAMP(FRACUNIT - invinoffroad, 0, FRACUNIT);
return FixedMul(offroad, fac);
@ -2564,71 +2564,12 @@ static inline fixed_t K_GetSneakerBoostSpeed(void)
// Used to determine the speed and power of Invincibility.
fixed_t K_InvincibilityGradient(UINT16 time)
{
return (min(936, (fixed_t)time) * FRACUNIT / BASEINVINTIME);
}
static fixed_t K_InvincibilityEasing(fixed_t x)
{
fixed_t u = max(FRACUNIT / 4, (min(32000, x) * FRACUNIT) / INVINDIST);
if (x < INVINDIST)
return u;
u = max(0, (u - FRACUNIT));
if (u < FRACUNIT)
return Easing_InCubic(u, FRACUNIT, (INVINMIDTIME/10));
return Easing_OutCubic(
min(FRACUNIT, FixedMul(u - FRACUNIT, FRACUNIT/4)), (INVINMIDTIME/10), (INVINMAXTIME/10));
return (min(936, (fixed_t)time) * FRACUNIT / (6 * TICRATE));
}
UINT16 K_GetInvincibilityTime(player_t *player)
{
UINT32 i, pingame;
fixed_t distmul = FRACUNIT;
if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
return BASEINVINTIME;
pingame = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (!(gametyperules & GTR_BUMPERS) || players[i].bumper)
pingame++;
if (pingame > 1) // We only want to see if one player is playing.
continue;
}
if (pingame <= 1)
{
return BASEINVINTIME;
}
if (K_LegacyOddsMode())
{
// Legacy waypointing is janky and finicky, so tack on a safety-net multiplier.
// If an invincible player gets ahead of the cluster player, bottlenecking activates
// regardless.
distmul = LEGACYALTINVINMUL;
}
UINT32 cdist = player->distancefromcluster;
if ((grandprixinfo.gp == true) && (grandprixinfo.lunaticmode))
{
// I'm tired, boss.
cdist = (9 * cdist / 5);
}
fixed_t clustermul = K_InvincibilityEasing(FixedMul(cdist,distmul));
UINT16 invintics = FixedMul(BASEINVINTIME, clustermul);
return max(MININVINTIME, invintics);
return (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? BASEINVINTIME : MININVINTIME;
}
fixed_t K_GetInvincibilitySpeed(UINT16 time)
@ -5165,13 +5106,8 @@ void K_DoInvincibility(player_t *player, tic_t time)
}
player->maxinvincibilitytime = player->invincibilitytimer;
if (player->maxinvincibilitytime <= MININVINTIME && isalt)
{
// Merritt suggestion: Kill bottlenecking if you get a short Invincibility.
// Anti-bottleneck code 2: Signify to play the warning signal later than usual!
player->invincibilitybottleneck = (UINT16)(-2);
}
player->invincibilitybottleneck = 0;
player->invincibilitywarning = 0;
if (P_IsLocalPlayer(player) == true)
{
@ -6457,7 +6393,7 @@ static void K_UpdateInvincibilitySounds(player_t *player)
{
if (player->growshrinktimer > 0 && (!localplayer || cv_growmusic.value == 2)) // Prioritize Grow
sfxnum = cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow;
else if (player->invincibilitytimer > 0 && (!localplayer || cv_supermusic.value == 2))
else if ((player->invincibilitytimer > 0) && (!player->invincibilitywarning) && (!localplayer || cv_supermusic.value == 2))
sfxnum = cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc;
// FIXME: Does Alt. Shrink need an alarm?
}
@ -7502,53 +7438,36 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) &&
(player->invincibilitytimer > 2))
{
UINT32 invindist = INVINDIST >> 2;
// Value to subtract from the Invincibility timer during bottlenecking.
INT16 invin_subtrahend = 1;
if ((INT16)(player->invincibilitybottleneck) >= 0)
INT16 pingame = 0;
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (player->distancefromcluster < invindist)
{
player->invincibilitybottleneck =
min(256, player->invincibilitybottleneck + 4);
invinfac = FixedMul(
8,
max(min(FRACUNIT,
FRACUNIT - (player->distancefromcluster /
(INVINDIST >> 2))),
0));
}
else
{
player->invincibilitybottleneck =
max(0, (INT32)(player->invincibilitybottleneck) - 2);
}
if (!playeringame[i] || players[i].spectator)
continue;
invin_subtrahend =
max(1,
FixedMul((UINT16)invinfac,
max(0, player->invincibilitybottleneck) << 8));
if (!(gametyperules & GTR_BUMPERS) || players[i].bumper)
pingame++;
if (pingame > 1) // We only want to see if one player is playing.
continue;
}
// Value to subtract from the Invincibility timer.
INT16 invin_subtrahend = (pingame > 1) ? 2 : 1;
if ((player->distancefromcluster > 0) && (!player->invincibilitybottleneck) && (pingame > 1))
{
// Don't subtract shit until we get past the cluster player.
invin_subtrahend = 0;
}
player->invincibilitytimer = (UINT16)(max(
2, (INT32)(player->invincibilitytimer) - invin_subtrahend));
const boolean warning_cond_standard =
((K_InvincibilityGradient(player->invincibilitytimer) <
(FRACHALF * invin_subtrahend)) &&
(player->maxinvincibilitytime >= (BASEINVINTIME - TICRATE)));
(K_InvincibilityGradient(player->invincibilitytimer) < INVINWARNINGTIME);
const boolean warning_cond_nobottleneck =
((K_InvincibilityGradient(player->invincibilitytimer) <
SecsToFixedTens(MININVINTIME / 2)) &&
(player->maxinvincibilitytime >= (MININVINTIME - TICRATE)));
const boolean warning_cond =
((INT16)(player->invincibilitybottleneck) == -2)
? warning_cond_nobottleneck
: warning_cond_standard;
const boolean warning_cond = warning_cond_standard;
if (warning_cond)
{
@ -7556,26 +7475,13 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
{
S_StartSound(player->mo, sfx_cdfm71);
player->invincibilitywarning = 1;
player->invincibilitybottleneck = 1;
}
}
if (((INT16)(player->invincibilitybottleneck) > 127) &&
(!S_SoundPlaying(player->mo, sfx_s3kbes)))
{
S_StartSound(player->mo, sfx_s3kbes);
}
}
else
{
player->invincibilitytimer--;
if (S_SoundPlaying(player->mo, sfx_s3kbes) &&
K_IsKartItemAlternate(KITEM_INVINCIBILITY))
{
// Shut off the bottlenecker sound.
S_StopSoundByID(player->mo, sfx_s3kbes);
}
player->invincibilitybottleneck = 0;
player->invincibilitywarning = 0;
}
@ -10081,20 +9987,13 @@ static fixed_t K_PlayerDistance3D(player_t *source, player_t *destination)
static boolean K_CheckBestRankForCluster(player_t *player, UINT32 pingame)
{
if (pingame > 17)
if (pingame > 6)
{
if (!K_IsPlayerLosing(player))
{
return false; // Ignore winning players to prevent sandbagging.
}
}
else if (pingame > 6)
{
if (player->position <= 3)
{
return false; // Ignore podium players to prevent sandbagging.
}
}
else if (pingame > 4)
{
if (player->position <= 1)
@ -10167,7 +10066,6 @@ static UINT32 K_UpdateDistanceFromCluster(player_t* player)
if (pingame <= 1)
{
// There's only us around.
player->invincibilitybottleneck = (UINT16)(-1); // No bottlenecking!
return 0;
}
else if (pingame == 3)
@ -10504,30 +10402,48 @@ static UINT32 K_UndoMapScaling(UINT32 distance)
return distance;
}
UINT32 clusterid = 0;
#define FARTHESTCLUSDIS (4096)
// Brute-force finds the area on the course with the highest player density in a given radius.
// Based on DBSCAN, so it "chain-scans" neighboring players as well for a more accurate result.
static vector3_t* K_FindPlayerCluster(
fixed_t eps,
INT32 (*func)(player_t*, fixed_t, playerfilter_f*, UINT32, vector3_t*),
vector3_t* out)
// Uses distance averaging to find a player cluster.
static vector3_t* K_FindPlayerCluster(vector3_t* out)
{
INT32 density[2] = {0, 0};
INT32 bestdensity = 0; // Cluster counter
vector3_t tempclusterpoint;
vector3_t c1 = {0}, c2 = {0};
player_t* findme;
player_t* player;
INT32 i;
player_t *player, *leader;
INT32 i, j;
INT32 nump = 0;
INT64 distavg = 0;
boolean doublecluster = false;
out->x = 0;
out->y = 0;
out->z = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
player = &players[i];
if (player->spectator)
continue; // spectator
if (!player->mo)
continue;
if (player->position <= 1)
{
// Leader
leader = player;
}
}
// No leader? No point.
if (!leader)
{
return out;
}
for (i = 0; i < MAXPLAYERS; i++)
{
@ -10543,75 +10459,28 @@ static vector3_t* K_FindPlayerCluster(
continue;
nump++;
}
if ((nump > 6) && (nump < 18))
{
// Start double-clustering.
doublecluster = true;
}
player_t* generalclusterp;
if (doublecluster)
{
// Get the second (general) cluster first.
for (i = 0; i < MAXPLAYERS; i++)
if (K_LegacyOddsMode())
{
// NESTED LOOP to clear clusterplayer flags. GOD.
for (j = 0; j < MAXPLAYERS; j++)
{
clusterplayer[j] = false;
}
if (!playeringame[i])
continue;
player = &players[i];
if (player->spectator)
continue; // spectator
if (!player->mo)
continue;
// Find neighbors
INT32 N2 =
func(player, eps, &K_ClusterFilter_NoFilter, 0, &tempclusterpoint);
// Double-remove the clusterplayer flag. Bad hack, I know...
clusterplayer[i] = false;
// 10/22/2025: Pairs don't count anymore
if (N2 < 2)
{
continue;
}
// Density check
if (N2 > density[1])
{
density[1] = N2;
generalclusterp = closesttocluster;
c2.x = tempclusterpoint.x;
c2.y = tempclusterpoint.y;
c2.z = tempclusterpoint.z;
continue;
}
distavg += (INT64)(K_GetCongaLineDistance(player, 1));
}
else
{
distavg += max(0, (INT64)(player->distancetofinish) - (INT64)(leader->distancetofinish));
}
}
// First (losing) cluster.
if (nump)
{
distavg /= nump;
}
INT64 distsample = 0;
INT64 bestsample = INT64_MAX;
// Find the player closest to the sample.
for (i = 0; i < MAXPLAYERS; i++)
{
// NESTED LOOP to clear clusterplayer flags. GOD.
for (j = 0; j < MAXPLAYERS; j++)
{
clusterplayer[j] = false;
}
if (!playeringame[i])
continue;
@ -10623,171 +10492,23 @@ static vector3_t* K_FindPlayerCluster(
if (!player->mo)
continue;
// Find neighbors
INT32 N = func(player, eps, &K_ClusterFilter_BaseFilter, nump, &tempclusterpoint);
// Double-remove the clusterplayer flag. Bad hack, I know...
clusterplayer[i] = false;
// 10/22/2025: Pairs don't count anymore
if (N < 2)
if (K_LegacyOddsMode())
{
continue;
}
// Density check
if (N > density[0])
{
density[0] = N;
findme = closesttocluster;
c1.x = tempclusterpoint.x;
c1.y = tempclusterpoint.y;
c1.z = tempclusterpoint.z;
continue;
}
}
bestdensity = density[0] + density[1];
if (bestdensity)
{
if (doublecluster && (density[1] > 0))
{
// If the general cluster is populated, the output vector is the average
// point between the two cluster points. Be biased TOWARDS the general
// cluster! If the losing player is too far away from the general player,
// use the general player.
if (generalclusterp && (density[0] > 0) && findme)
{
UINT32 clusdis = 0;
if ((generalclusterp != findme) &&
(findme->position != generalclusterp->position))
{
if (K_LegacyOddsMode())
{
clusdis =
FixedMul(K_GetCongaLineDistance(
(findme->position >
generalclusterp->position)
? findme
: generalclusterp,
(findme->position >
generalclusterp->position)
? generalclusterp->position
: findme->position),
LEGACYALTINVINMUL);
}
else
{
clusdis =
K_GetDTFDifference(findme, generalclusterp);
}
if (clusdis > FARTHESTCLUSDIS)
{
// The distance between clusters is too far!
// Use the general cluster.
findme = generalclusterp;
out->x = c2.x;
out->y = c2.y;
out->z = c2.z;
}
else
{
// Get the average position between the two
// clusters.
if (K_LegacyOddsMode())
{
out->x =
(fixed_t)(((INT64)c1.x + c2.x) / 2);
out->y =
(fixed_t)(((INT64)c1.y + c2.y) / 2);
out->z =
(fixed_t)(((INT64)c1.z + c2.z) / 2);
}
else
{
// Only need to do this for the x position;
// that's where the DtF is
out->x = (fixed_t)(((INT64)((UINT32)c1.x) +
(INT64)((UINT32)c2.x)) /
2);
}
// Finally, get the closest player to the average
// position.
fixed_t best_pdis = INT32_MAX;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (players[i].spectator)
continue; // spectator
if (!players[i].mo)
continue;
if (players[i].position >= nump)
continue; // Ignore last place.
// Last place should
// *never* be a cluster
// player.
fixed_t pdist;
if (K_LegacyOddsMode())
{
pdist =
K_Distance3D(players[i].mo->x,
players[i].mo->y,
players[i].mo->z,
out->x,
out->y,
out->z);
}
else
{
pdist = (fixed_t)(abs(
(INT32)((INT64)((UINT32)players[i]
.distancetofinish) -
(INT64)((UINT32)
out->x))));
}
if (pdist < best_pdis)
{
best_pdis = pdist;
findme = &players[i];
}
}
}
}
}
else if (generalclusterp)
{
// Findme doesn't exist, but the general player does.
// Use the general player.
findme = generalclusterp;
out->x = c2.x;
out->y = c2.y;
out->z = c2.z;
}
distsample = (INT64)(K_GetCongaLineDistance(player, 1)) - distavg;
}
else
{
out->x = c1.x;
out->y = c1.y;
out->z = c1.z;
distsample = max(0, (INT64)(player->distancetofinish) - (INT64)(leader->distancetofinish)) - distavg;
}
// Only find the cluster player if a cluster's populated.
if (findme)
if ((distsample < bestsample))
{
clusterid = (UINT32)(findme - players);
bestsample = distsample;
clusterid = i;
out->x = player->mo->x;
out->y = player->mo->y;
out->z = player->mo->z;
}
}
@ -10802,25 +10523,10 @@ static vector3_t* K_FindPlayerCluster(
#define CLUSTER_ACTIVE_EPSILON (K_LegacyOddsMode() ? CLUSTER_EPSILON : CLUSTER_EPSILON_PATHFIND)
#define USECLUSEPS (FixedMul(FixedMul(CLUSTER_ACTIVE_EPSILON, K_GetKartGameSpeedScalar(gamespeed)), mapobjectscale))
#define K_FindPlayerClusterLegacy() (K_FindPlayerCluster(USECLUSEPS, K_CountNeighboringPlayers, &clusterpoint))
#define K_FindPlayerClusterDTF() (K_FindPlayerCluster((USECLUSEPS / FRACUNIT), K_CountNeighboringPlayersByDTF, &clusterdtf))
void K_UpdateClusterPoints(void)
{
// Get the player cluster.
if (K_LegacyOddsMode())
{
K_FindPlayerClusterLegacy();
}
else
{
/*if (cv_kartdebugcluster.value)
{
K_FindPlayerClusterLegacy();
}*/
K_FindPlayerClusterDTF();
}
K_FindPlayerCluster(&clusterpoint);
}
void K_UpdateAllPlayerPositions(void)

View file

@ -276,6 +276,7 @@ void K_ResetPogoSpring(player_t *player);
extern boolean forcefullinvintheme;
boolean K_PlayFullInvinTheme(void);
void K_DoInvincibility(player_t *player, tic_t time);
#define INVINWARNINGTIME (fixed_t)(0.833333333f * (float)(FRACUNIT))
fixed_t K_InvincibilityGradient(UINT16 time);
UINT16 K_GetInvincibilityTime(player_t *player);
fixed_t K_GetInvincibilitySpeed(UINT16 time);

View file

@ -833,7 +833,7 @@ void P_RestoreMusic(player_t *player)
{ \
if (players[p].growshrinktimer > bestlocaltimer) \
{ wantedmus = 1; bestlocaltimer = players[p].growshrinktimer; } \
else if (players[p].invincibilitytimer > bestlocaltimer) \
else if ((players[p].invincibilitytimer > bestlocaltimer) && (!players[p].invincibilitywarning))\
{ wantedmus = 2; bestlocaltimer = players[p].invincibilitytimer; } \
else if ((K_IsKartItemAlternate(KITEM_SHRINK)) && \
(K_GetShrinkTime(&players[p]) > bestlocaltimer)) \
@ -853,7 +853,7 @@ void P_RestoreMusic(player_t *player)
{
if (player->growshrinktimer > 1)
wantedmus = 1;
else if (player->invincibilitytimer > 1)
else if ((player->invincibilitytimer > 1) && (!player->invincibilitywarning))
wantedmus = 2;
else if ((K_IsKartItemAlternate(KITEM_SHRINK)) &&
(K_GetShrinkTime(player) > 1))