Refactor legacy odds code to generate pdis instead of duping multiple legacy functions

Why did I ever do it like that before when it was this easy....
This commit is contained in:
NepDisk 2025-09-24 22:50:36 -04:00
parent dcc5b41075
commit 87300944fa
3 changed files with 185 additions and 707 deletions

View file

@ -5422,137 +5422,7 @@ static void K_drawDistributionDebugger(void)
bestbumper = players[i].bumper;
}
if (!K_UsingLegacyCheckpoints())
{
// lovely double loop......
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator
&& players[i].position == 1)
{
// This player is first! Yay!
pdis = stplyr->distancetofinish - players[i].distancetofinish;
break;
}
}
}
else
{
// Pain and fucking suffering.
SINT8 sortedPlayers[MAXPLAYERS];
UINT8 sortLength = 0;
memset(sortedPlayers, -1, sizeof(sortedPlayers));
if (stplyr->mo != NULL && P_MobjWasRemoved(stplyr->mo) == false)
{
// Sort all of the players ahead of you.
// Then tally up their distances in a conga line.
// This will create a much more consistent item
// distance algorithm than the "spider web" thing
// that it was doing before.
// Add yourself to the list.
// You'll always be the end of the list,
// so we can also calculate the length here.
sortedPlayers[ stplyr->position - 1 ] = stplyr - players;
sortLength = stplyr->position;
// Will only need to do this if there's goint to be
// more than yourself in the list.
if (sortLength > 1)
{
SINT8 firstIndex = -1;
SINT8 secondIndex = -1;
INT32 startFrom = INT32_MAX;
// Add all of the other players.
for (i = 0; i < MAXPLAYERS; i++)
{
INT32 pos = INT32_MAX;
if (!playeringame[i] || players[i].spectator)
{
continue;
}
if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true)
{
continue;
}
pos = players[i].position;
if (pos <= 0 || pos > MAXPLAYERS)
{
// Invalid position.
continue;
}
if (pos >= stplyr->position)
{
// Tied / behind us.
// Also handles ourselves, obviously.
continue;
}
// Ties are done with port priority, if there are any.
if (sortedPlayers[ pos - 1 ] == -1)
{
sortedPlayers[ pos - 1 ] = i;
}
}
// The chance of this list having gaps is improbable,
// but not impossible. So we need to spend some extra time
// to prevent the gaps from mattering.
for (i = 0; i < sortLength-1; i++)
{
if (sortedPlayers[i] >= 0 && sortedPlayers[i] < MAXPLAYERS)
{
// First valid index in the list found.
firstIndex = sortedPlayers[i];
// Start the next loop after this player.
startFrom = i + 1;
break;
}
}
if (firstIndex >= 0 && firstIndex < MAXPLAYERS
&& startFrom < sortLength)
{
// First index is valid, so we can
// start comparing the players.
player_t *firstPlayer = NULL;
player_t *secondPlayer = NULL;
for (i = startFrom; i < sortLength; i++)
{
if (sortedPlayers[i] >= 0 && sortedPlayers[i] < MAXPLAYERS)
{
secondIndex = sortedPlayers[i];
firstPlayer = &players[firstIndex];
secondPlayer = &players[secondIndex];
// Add the distance to the player behind you.
pdis += P_AproxDistance(P_AproxDistance(
firstPlayer->mo->x - secondPlayer->mo->x,
firstPlayer->mo->y - secondPlayer->mo->y),
firstPlayer->mo->z - secondPlayer->mo->z) / FRACUNIT;
// Advance to next index.
firstIndex = secondIndex;
}
}
}
}
}
}
pdis = K_CalculateInitalPDIS(stplyr);
if (spbplace != -1 && stplyr->position == spbplace+1)
{
@ -5570,10 +5440,7 @@ static void K_drawDistributionDebugger(void)
pdis = (15 * pdis) / 14;
}
if (K_UsingLegacyCheckpoints())
useodds = K_FindLegacyUseodds(stplyr, 0, pingame, bestbumper, spbrush, dontforcespb);
else
useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper, spbrush);
useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper, spbrush);
if (pingame == 1)
{
@ -5583,30 +5450,20 @@ static void K_drawDistributionDebugger(void)
V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SNEAKER));
V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", 200));
}
else if (useodds == 69)
{
V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SPB));
V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", 200));
}
else
{
for (item = 1; item < NUMKARTRESULTS; item++)
{
INT32 itemodds;
INT32 amount;
if (K_UsingLegacyCheckpoints())
itemodds = K_KartGetLegacyItemOdds(useodds, item, stplyr->distancefromcluster, 0, spbrush);
else
itemodds = K_KartGetItemOdds(
useodds, item,
stplyr->distancetofinish,
stplyr->distancefromcluster,
0,
spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival)
);
itemodds = K_KartGetItemOdds(
useodds, item,
stplyr->distancetofinish,
stplyr->distancefromcluster,
0,
spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival)
);
if (itemodds <= 0)
continue;
@ -5633,8 +5490,6 @@ static void K_drawDistributionDebugger(void)
if (pingame == 1)
V_DrawString(0, 0, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, "TA MODE");
else if (useodds == 69)
V_DrawString(0, 0, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, "FORCED SPB");
else
V_DrawString(0, 0, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("USEODDS %d", useodds));

View file

@ -591,7 +591,7 @@ INT32 K_KartGetItemOdds(
// This item should not appear at the beginning of a race. (Usually really powerful crowd-breaking items)
newodds = 0;
}
else if ((notNearEnd == true) && (ourDist < ENDDIST))
else if (!K_UsingLegacyCheckpoints() && (notNearEnd == true) && (ourDist < ENDDIST))
{
// This item should not appear at the end of a race. (Usually trap items that lose their effectiveness)
newodds = 0;
@ -627,203 +627,6 @@ INT32 K_KartGetItemOdds(
return newodds;
}
INT32 K_KartGetLegacyItemOdds(UINT8 pos, SINT8 item, fixed_t clusterDist, fixed_t mashed, boolean spbrush)
{
INT32 newodds;
INT32 i;
UINT8 pingame = 0, pexiting = 0;
SINT8 first = -1, second = -1;
UINT32 secondToFirst = 0;
INT32 shieldtype = KSHIELD_NONE;
boolean powerItem = false;
boolean cooldownOnStart = false;
boolean indirectItem = false;
I_Assert(item > KITEM_NONE); // too many off by one scenarioes.
if (!KartItemCVars[item-1]->value && !modeattacking)
return 0;
INT32 oddsmul = BASEODDSMUL;
if (gametyperules & GTR_BATTLEODDS)
{
newodds = K_KartItemOddsBattle[item-1][pos];
oddsmul = BATTLEODDSMUL;
}
else if (gametyperules & GTR_RACEODDS)
newodds = K_KartItemOddsRace[item-1][pos];
else
newodds = 0;
// Blow up the odds with a multiplier.
newodds *= oddsmul;
shieldtype = K_GetShieldFromItem(item);
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (!(gametyperules & GTR_BUMPERS) || players[i].bumper)
pingame++;
if (players[i].exiting)
pexiting++;
if (shieldtype != KSHIELD_NONE && ((shieldtype == K_GetShieldFromItem(players[i].itemtype))
|| (shieldtype == K_GetShieldFromPlayer(&players[i]))))
{
// Don't allow more than one of each shield type at a time
return 0;
}
if (players[i].mo && gametype == GT_RACE)
{
if (players[i].position == 1 && first == -1)
first = i;
if (players[i].position == 2 && second == -1)
second = i;
}
}
if (first != -1 && second != -1) // calculate 2nd's distance from 1st, for SPB
{
secondToFirst = P_AproxDistance(P_AproxDistance(players[first].mo->x - players[second].mo->x,
players[first].mo->y - players[second].mo->y),
players[first].mo->z - players[second].mo->z) / FRACUNIT;
secondToFirst = K_ScaleItemDistance(secondToFirst, pingame, spbrush);
}
switch (item)
{
case KITEM_ROCKETSNEAKER:
case KITEM_JAWZ:
case KITEM_BALLHOG:
case KITEM_LANDMINE:
case KRITEM_TRIPLESNEAKER:
case KRITEM_TRIPLEBANANA:
case KRITEM_TENFOLDBANANA:
case KRITEM_TRIPLEORBINAUT:
case KRITEM_QUADORBINAUT:
case KRITEM_DUALJAWZ:
powerItem = true;
break;
case KITEM_INVINCIBILITY:
if ((K_GetKartInvinType() == KARTINVIN_ALTERN) && (gametyperules & GTR_RACEODDS))
{
// It's a power item, yes, but we don't want mashing to lessen
// its chances, so we lie to the game's face.
// Nonetheless, apply the start cooldown.
cooldownOnStart = true;
// Unique odds for Invincibility. In legacy waypointing,
// its odds are doubled.
newodds = K_KartGetInvincibilityOdds(clusterDist) * 2;
newodds *= BASEODDSMUL;
break;
}
/*FALLTHRU*/
case KITEM_MINE:
case KITEM_GROW:
case KITEM_BUBBLESHIELD:
case KITEM_FLAMESHIELD:
cooldownOnStart = true;
powerItem = true;
break;
case KITEM_SPB:
cooldownOnStart = true;
indirectItem = true;
//powerItem = true;
if (pexiting > 0)
{
newodds = 0;
}
else if (pos != 9) // Force SPB
{
const INT32 distFromStart = max(secondToFirst - SPBSTARTDIST , 0);
const INT32 distRange = SPBFORCEDIST - SPBSTARTDIST;
const fixed_t mulMax = 3*FRACUNIT;
fixed_t multiplier = (distFromStart * mulMax) / distRange;
if (multiplier < 0)
multiplier = 0;
if (multiplier > mulMax)
multiplier = mulMax;
newodds = FixedMul(newodds * FRACUNIT, multiplier) / FRACUNIT;
}
break;
case KITEM_SHRINK:
cooldownOnStart = true;
powerItem = true;
indirectItem = true;
if (pingame-1 <= pexiting)
newodds = 0;
break;
case KITEM_THUNDERSHIELD:
cooldownOnStart = true;
powerItem = true;
break;
case KITEM_HYUDORO:
cooldownOnStart = true;
if (hyubgone > 0)
newodds = 0;
break;
default:
break;
}
if (newodds == 0)
{
// Nothing else we want to do with odds matters at this point :p
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))
{
// This item should not appear at the beginning of a race. (Usually really powerful crowd-breaking items)
newodds = 0;
}
else if (powerItem == true)
{
// This item is a "power item". This activates "frantic item" toggle related functionality.
fixed_t fracOdds = newodds * FRACUNIT;
if (franticitems == true)
{
// First, power items multiply their odds by 2 if frantic items are on; easy-peasy.
fracOdds *= 2;
}
fracOdds = FixedMul(fracOdds, FRACUNIT + K_ItemOddsScale(pingame, spbrush));
if (mashed > 0)
{
// Lastly, it *divides* it based on your mashed value, so that power items are less likely when you mash.
fracOdds = FixedDiv(fracOdds, FRACUNIT + mashed);
}
newodds = fracOdds / FRACUNIT;
}
return newodds;
}
//{ SRB2kart Roulette Code - Distance Based, yes waypoints
UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush)
@ -959,278 +762,6 @@ UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 b
return useodds;
}
INT32 K_FindLegacyUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 bestbumper, boolean spbrush, boolean dontforcespb)
{
fixed_t oddsfac = max(FRACUNIT, (MAXODDS * FRACUNIT) / 8);
INT32 oddsdiv = (MAXODDS - 1) * 2;
SINT8 sortedPlayers[MAXPLAYERS];
UINT8 sortLength = 0;
UINT32 pdis = 0;
UINT8 disttable[oddsdiv];
UINT8 distlen = 0;
boolean oddsvalid[MAXODDS];
INT32 useodds = 0;
INT32 i, j;
// Unused now, oops :V
(void)bestbumper;
for (i = 0; i < MAXODDS; i++)
{
boolean available = false;
if ((gametyperules & GTR_BATTLEODDS) && i > 1)
{
oddsvalid[i] = false;
break;
}
for (j = 1; j < NUMKARTRESULTS; j++)
{
if (K_KartGetLegacyItemOdds(i, j, player->distancefromcluster, mashed, spbrush) > 0)
{
available = true;
break;
}
}
oddsvalid[i] = available;
}
memset(sortedPlayers, -1, sizeof(sortedPlayers));
if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false)
{
// Sort all of the players ahead of you.
// Then tally up their distances in a conga line.
// This will create a much more consistent item
// distance algorithm than the "spider web" thing
// that it was doing before.
// Add yourself to the list.
// You'll always be the end of the list,
// so we can also calculate the length here.
sortedPlayers[ player->position - 1 ] = player - players;
sortLength = player->position;
// Will only need to do this if there's goint to be
// more than yourself in the list.
if (sortLength > 1)
{
SINT8 firstIndex = -1;
SINT8 secondIndex = -1;
INT32 startFrom = INT32_MAX;
// Add all of the other players.
for (i = 0; i < MAXPLAYERS; i++)
{
INT32 pos = INT32_MAX;
if (!playeringame[i] || players[i].spectator)
{
continue;
}
if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true)
{
continue;
}
pos = players[i].position;
if (pos <= 0 || pos > MAXPLAYERS)
{
// Invalid position.
continue;
}
if (pos >= player->position)
{
// Tied / behind us.
// Also handles ourselves, obviously.
continue;
}
// Ties are done with port priority, if there are any.
if (sortedPlayers[ pos - 1 ] == -1)
{
sortedPlayers[ pos - 1 ] = i;
}
}
// The chance of this list having gaps is improbable,
// but not impossible. So we need to spend some extra time
// to prevent the gaps from mattering.
for (i = 0; i < sortLength-1; i++)
{
if (sortedPlayers[i] >= 0 && sortedPlayers[i] < MAXPLAYERS)
{
// First valid index in the list found.
firstIndex = sortedPlayers[i];
// Start the next loop after this player.
startFrom = i + 1;
break;
}
}
if (firstIndex >= 0 && firstIndex < MAXPLAYERS
&& startFrom < sortLength)
{
// First index is valid, so we can
// start comparing the players.
player_t *firstPlayer = NULL;
player_t *secondPlayer = NULL;
for (i = startFrom; i < sortLength; i++)
{
if (sortedPlayers[i] >= 0 && sortedPlayers[i] < MAXPLAYERS)
{
secondIndex = sortedPlayers[i];
firstPlayer = &players[firstIndex];
secondPlayer = &players[secondIndex];
// Add the distance to the player behind you.
pdis += P_AproxDistance(P_AproxDistance(
firstPlayer->mo->x - secondPlayer->mo->x,
firstPlayer->mo->y - secondPlayer->mo->y),
firstPlayer->mo->z - secondPlayer->mo->z) / FRACUNIT;
// Advance to next index.
firstIndex = secondIndex;
}
}
}
}
}
#define SETUPDISTTABLE(odds, num) \
if (oddsvalid[odds]) \
for (i = num; i; --i) \
{ \
disttable[distlen++] = odds; \
distlen = min(oddsdiv - 1, distlen); \
}
if (gametyperules & GTR_BATTLEODDS) // Battle Mode
{
if (player->roulettetype == KROULETTETYPE_KARMA && oddsvalid[1] == true)
{
// 1 is the extreme odds of player-controlled "Karma" items
useodds = 1;
}
else
{
useodds = 0;
if (oddsvalid[0] == false && oddsvalid[1] == true)
{
// try to use karma odds as a fallback
useodds = 1;
}
}
}
else
{
INT32 tablediv = FixedMul(2, oddsfac);
INT32 jj;
// "Why j instead of i"?
// Using i causes an infinite loop due to SETUPDISTTABLE. Yep.
for (j = 0; j < MAXODDS; j++)
{
if (j == (MAXODDS - 1))
{
// Attempt to replicate vanilla behavior; Useodds 8 is set up like this.
SETUPDISTTABLE(j,1);
}
else
{
jj = max(1, ((j - 3) / tablediv) + 1);
if (jj < 1)
{
jj = 1;
}
//CONS_Printf("SETUPDISTTABLE(%d, %d)\n", j, jj);
SETUPDISTTABLE(j,jj);
}
}
/*SETUPDISTTABLE(0,1);
SETUPDISTTABLE(1,1);
SETUPDISTTABLE(2,1);
SETUPDISTTABLE(3,2);
SETUPDISTTABLE(4,2);
SETUPDISTTABLE(5,3);
SETUPDISTTABLE(6,3);
SETUPDISTTABLE(7,1);*/
pdis = K_ScaleItemDistance(pdis, pingame, spbrush);
const INT32 usedistvar = FixedDiv(DISTVAR, oddsfac);
if (player->bot && player->botvars.rival)
{
// Rival has better odds :)
pdis = (15 * pdis) / 14;
}
if (pingame == 1 && oddsvalid[0])
{
// Record Attack / FREE PLAY
useodds = 0;
}
else if (pdis <= 0)
{
// 1st place
useodds = disttable[0];
}
else if (player->position == 2 && pdis > SPBFORCEDIST
&& spbplace == -1 && !indirectitemcooldown && !dontforcespb)
{
// Force SPB in 2nd
useodds = 69;
}
else if (pdis > (UINT32)DISTVAR * ((12 * distlen) / oddsdiv))
{
// Back of the pack
useodds = disttable[distlen-1];
}
else
{
for (i = 1; i < (oddsdiv - 1); i++)
{
INT32 distcalc = min(distlen-1, (i * distlen) / oddsdiv);
if (pdis <= (unsigned)(usedistvar * distcalc))
{
useodds = disttable[distcalc];
break;
}
}
}
}
#undef SETUPDISTTABLE
//CONS_Printf("Got useodds %d. (position: %d, distance: %u)\n", useodds, player->position, pdis);
return useodds;
}
INT32 K_GetRollingRouletteItem(player_t *player)
{
static UINT8 translation[NUMKARTITEMS-1];
@ -1279,6 +810,153 @@ INT32 K_GetRollingRouletteItem(player_t *player)
return translation[(player->itemroulette % roulette_size) / 3];
}
UINT32 K_CalculateInitalPDIS(const player_t *player)
{
UINT8 i;
UINT32 pdis = 0;
if (!K_UsingLegacyCheckpoints())
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator
&& players[i].position == 1)
{
// This player is first! Yay!
if (player->distancetofinish <= players[i].distancetofinish)
{
// Guess you're in first / tied for first?
pdis = 0;
}
else
{
// Subtract 1st's distance from your distance, to get your distance from 1st!
pdis = player->distancetofinish - players[i].distancetofinish;
}
break;
}
}
}
else
{
SINT8 sortedPlayers[MAXPLAYERS];
UINT8 sortLength = 0;
memset(sortedPlayers, -1, sizeof(sortedPlayers));
if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false)
{
// Sort all of the players ahead of you.
// Then tally up their distances in a conga line.
// This will create a much more consistent item
// distance algorithm than the "spider web" thing
// that it was doing before.
// Add yourself to the list.
// You'll always be the end of the list,
// so we can also calculate the length here.
sortedPlayers[ player->position - 1 ] = player - players;
sortLength = player->position;
// Will only need to do this if there's goint to be
// more than yourself in the list.
if (sortLength > 1)
{
SINT8 firstIndex = -1;
SINT8 secondIndex = -1;
INT32 startFrom = INT32_MAX;
// Add all of the other players.
for (i = 0; i < MAXPLAYERS; i++)
{
INT32 pos = INT32_MAX;
if (!playeringame[i] || players[i].spectator)
{
continue;
}
if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true)
{
continue;
}
pos = players[i].position;
if (pos <= 0 || pos > MAXPLAYERS)
{
// Invalid position.
continue;
}
if (pos >= player->position)
{
// Tied / behind us.
// Also handles ourselves, obviously.
continue;
}
// Ties are done with port priority, if there are any.
if (sortedPlayers[ pos - 1 ] == -1)
{
sortedPlayers[ pos - 1 ] = i;
}
}
// The chance of this list having gaps is improbable,
// but not impossible. So we need to spend some extra time
// to prevent the gaps from mattering.
for (i = 0; i < sortLength-1; i++)
{
if (sortedPlayers[i] >= 0 && sortedPlayers[i] < MAXPLAYERS)
{
// First valid index in the list found.
firstIndex = sortedPlayers[i];
// Start the next loop after this player.
startFrom = i + 1;
break;
}
}
if (firstIndex >= 0 && firstIndex < MAXPLAYERS
&& startFrom < sortLength)
{
// First index is valid, so we can
// start comparing the players.
player_t *firstPlayer = NULL;
player_t *secondPlayer = NULL;
for (i = startFrom; i < sortLength; i++)
{
if (sortedPlayers[i] >= 0 && sortedPlayers[i] < MAXPLAYERS)
{
secondIndex = sortedPlayers[i];
firstPlayer = &players[firstIndex];
secondPlayer = &players[secondIndex];
// Add the distance to the player behind you.
pdis += P_AproxDistance(P_AproxDistance(
firstPlayer->mo->x - secondPlayer->mo->x,
firstPlayer->mo->y - secondPlayer->mo->y),
firstPlayer->mo->z - secondPlayer->mo->z) / FRACUNIT;
// Advance to next index.
firstIndex = secondIndex;
}
}
}
}
}
}
return pdis;
}
void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
{
INT32 i;
@ -1341,50 +1019,23 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
else if (!(player->itemroulette >= (TICRATE*3)))
return;
if (!(K_UsingLegacyCheckpoints()))
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator
&& players[i].position == 1)
{
// This player is first! Yay!
if (player->distancetofinish <= players[i].distancetofinish)
{
// Guess you're in first / tied for first?
pdis = 0;
}
else
{
// Subtract 1st's distance from your distance, to get your distance from 1st!
pdis = player->distancetofinish - players[i].distancetofinish;
}
break;
}
}
}
pdis = K_CalculateInitalPDIS(player);
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
if (!(K_UsingLegacyCheckpoints()))
pdis = (3 * pdis) / 2;
pdis = (3 * pdis) / 2;
spbrush = true;
}
if (!(K_UsingLegacyCheckpoints()))
pdis = K_ScaleItemDistance(pdis, pingame, spbrush);
if (player->bot && player->botvars.rival)
{
pdis = K_ScaleItemDistance(pdis, pingame, spbrush);
if (player->bot && player->botvars.rival)
{
// Rival has better odds :)
pdis = (15 * pdis) / 14;
}
// Rival has better odds :)
pdis = (15 * pdis) / 14;
}
// SPECIAL CASE No. 1:
// Fake Eggman items
if (player->roulettetype == KROULETTETYPE_EGGMAN)
@ -1502,38 +1153,11 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
}
}
if (!(K_UsingLegacyCheckpoints()))
{
// SPECIAL CASE No. 6:
// Force SPB onto 2nd if they get too far behind
if ((gametyperules & GTR_CIRCUIT) && player->position == 2 && pdis > SPBFORCEDIST
&& spbplace == -1 && !indirectitemcooldown && !dontforcespb
&& cv_selfpropelledbomb.value)
{
K_KartGetItemResult(player, KITEM_SPB);
player->itemblink = TICRATE;
player->itemblinkmode = KITEMBLINKMODE_KARMA;
player->itemroulette = KROULETTE_DISABLED;
player->roulettetype = KROULETTETYPE_NORMAL;
if (P_IsDisplayPlayer(player))
S_StartSound(NULL, sfx_itrolk);
return;
}
}
// NOW that we're done with all of those specialized cases, we can move onto the REAL item roulette tables.
// Initializes existing spawnchance values
for (i = 0; i < NUMKARTRESULTS; i++)
spawnchance[i] = 0;
// Split into another function for a debug function below
// Use a legacy version for maps not using waypoints.
if (K_UsingLegacyCheckpoints())
useodds = K_FindLegacyUseodds(player, mashed, pingame, bestbumper, spbrush, dontforcespb);
else
useodds = K_FindUseodds(player, mashed, pdis, bestbumper, spbrush);
if (useodds == 69)
// SPECIAL CASE No. 6:
// Force SPB onto 2nd if they get too far behind
if ((gametyperules & GTR_CIRCUIT) && player->position == 2 && pdis > SPBFORCEDIST
&& spbplace == -1 && !indirectitemcooldown && !dontforcespb
&& cv_selfpropelledbomb.value)
{
K_KartGetItemResult(player, KITEM_SPB);
player->itemblink = TICRATE;
@ -1545,23 +1169,24 @@ void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
return;
}
// NOW that we're done with all of those specialized cases, we can move onto the REAL item roulette tables.
// Initializes existing spawnchance values
for (i = 0; i < NUMKARTRESULTS; i++)
spawnchance[i] = 0;
// Split into another function for a debug function below
useodds = K_FindUseodds(player, mashed, pdis, bestbumper, spbrush);
for (i = 1; i < NUMKARTRESULTS; i++)
{
if (K_UsingLegacyCheckpoints())
{
spawnchance[i] = (totalspawnchance += K_KartGetLegacyItemOdds(useodds, i, player->distancefromcluster, mashed, spbrush));
}
else
{
spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(
useodds, i,
player->distancetofinish,
player->distancefromcluster,
mashed,
spbrush, player->bot, (player->bot && player->botvars.rival))
);
}
spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(
useodds, i,
player->distancetofinish,
player->distancefromcluster,
mashed,
spbrush, player->bot, (player->bot && player->botvars.rival))
);
}
// Award the player whatever power is rolled

View file

@ -30,12 +30,10 @@ extern "C" {
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
UINT32 K_CalculateInitalPDIS(const player_t *player);
UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
INT32 K_FindLegacyUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 bestbumper, boolean spbrush, boolean dontforcespb);
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, UINT32 clusterDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival);
INT32 K_KartGetLegacyItemOdds(UINT8 pos, SINT8 item, fixed_t clusterDist, fixed_t mashed, boolean spbrush);
INT32 K_GetRollingRouletteItem(player_t *player);
SINT8 K_ItemResultToType(SINT8 getitem);
UINT8 K_ItemResultToAmount(SINT8 getitem);