mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Cleanup lots of the older roulette code
- Most of it now requires a reference to itemroulette_t, rather than copying all of the variables over. - Increased the effect of Frantic Items, as the old scaling was made extremely low because item distance was exponential back then. - A lot of variables are pre-calculated in itemroulette_t instead of redoing the calculations every time (player count, first place's dist, etc) - Make most of these functions only accessible by k_roulette.c - Even when single items get forced into your roulette, the Super Ring Debt effect can happen - Make the game support setting single items from other gametypes (Pogo Spring-only races work now) - Fix some item distances not accounting for scale - Prevent multiple of certain items from rolling at once; Shrinks (not a big deal) and SPBs (OH GOD NO)
This commit is contained in:
parent
8d43acccb7
commit
f7e53ec811
6 changed files with 266 additions and 243 deletions
|
|
@ -334,7 +334,7 @@ struct skybox_t {
|
|||
|
||||
// Doing this the right way is causing problems.
|
||||
// so FINE, it's a static length now.
|
||||
#define ITEM_LIST_SIZE (NUMKARTRESULTS << 2)
|
||||
#define ITEM_LIST_SIZE (NUMKARTRESULTS << 3)
|
||||
|
||||
struct itemroulette_t
|
||||
{
|
||||
|
|
@ -350,6 +350,11 @@ struct itemroulette_t
|
|||
#endif
|
||||
|
||||
UINT8 useOdds;
|
||||
UINT8 playing, exiting;
|
||||
UINT32 dist, baseDist;
|
||||
UINT32 firstDist, secondDist;
|
||||
UINT32 secondToFirst;
|
||||
|
||||
size_t index;
|
||||
UINT8 sound;
|
||||
|
||||
|
|
|
|||
|
|
@ -4589,6 +4589,13 @@ static void K_drawDistributionDebugger(void)
|
|||
V_DrawString((x >> FRACBITS) + 20, 2, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("useOdds[%u]", rouletteData.useOdds));
|
||||
V_DrawString((x >> FRACBITS) + 20, 10, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("speed = %u", rouletteData.speed));
|
||||
|
||||
V_DrawString((x >> FRACBITS) + 20, 22, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("baseDist = %u", rouletteData.baseDist));
|
||||
V_DrawString((x >> FRACBITS) + 20, 30, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("dist = %u", rouletteData.dist));
|
||||
|
||||
V_DrawString((x >> FRACBITS) + 20, 42, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("firstDist = %u", rouletteData.firstDist));
|
||||
V_DrawString((x >> FRACBITS) + 20, 50, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("secondDist = %u", rouletteData.secondDist));
|
||||
V_DrawString((x >> FRACBITS) + 20, 58, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("secondToFirst = %u", rouletteData.secondToFirst));
|
||||
|
||||
#ifndef ITEM_LIST_SIZE
|
||||
Z_Free(rouletteData.itemList);
|
||||
#endif
|
||||
|
|
|
|||
12
src/k_kart.c
12
src/k_kart.c
|
|
@ -6053,6 +6053,7 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
|
||||
if (type == 0)
|
||||
{
|
||||
itemroulette_t rouletteData = {0};
|
||||
UINT8 useodds = 0;
|
||||
INT32 spawnchance[NUMKARTRESULTS];
|
||||
INT32 totalspawnchance = 0;
|
||||
|
|
@ -6062,12 +6063,12 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
|
||||
useodds = amount;
|
||||
|
||||
K_StartItemRoulette(stplyr, &rouletteData);
|
||||
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(
|
||||
useodds, i,
|
||||
UINT32_MAX,
|
||||
false, false)
|
||||
spawnchance[i] = (
|
||||
totalspawnchance += K_KartGetItemOdds(NULL, &rouletteData, useodds, i)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -10498,8 +10499,7 @@ 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)
|
||||
if (K_ItemSingularity(player->itemtype) == true)
|
||||
{
|
||||
K_SetItemCooldown(player->itemtype, 20*TICRATE);
|
||||
}
|
||||
|
|
|
|||
471
src/k_roulette.c
471
src/k_roulette.c
|
|
@ -59,17 +59,19 @@
|
|||
#define SPBSTARTDIST (8*DISTVAR)
|
||||
|
||||
// Distance when SPB is forced onto the next person who rolls an item
|
||||
#define SPBFORCEDIST (14*DISTVAR)
|
||||
#define SPBFORCEDIST (16*DISTVAR)
|
||||
|
||||
// Distance when the game stops giving you bananas
|
||||
#define ENDDIST (18*DISTVAR)
|
||||
#define ENDDIST (14*DISTVAR)
|
||||
|
||||
// Consistent seed used for item reels
|
||||
#define ITEM_REEL_SEED (0x22D5FAA8)
|
||||
|
||||
#define FRANTIC_ITEM_SCALE (FRACUNIT*6/5)
|
||||
|
||||
#define ROULETTE_SPEED_SLOWEST (20)
|
||||
#define ROULETTE_SPEED_FASTEST (2)
|
||||
#define ROULETTE_SPEED_DIST (224*DISTVAR)
|
||||
#define ROULETTE_SPEED_DIST (150*DISTVAR)
|
||||
#define ROULETTE_SPEED_TIMEATTACK (9)
|
||||
|
||||
static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
|
||||
|
|
@ -176,7 +178,23 @@ boolean K_ItemEnabled(SINT8 item)
|
|||
return cv_items[item - 1].value;
|
||||
}
|
||||
|
||||
fixed_t K_ItemOddsScale(UINT8 playerCount)
|
||||
boolean K_ItemSingularity(kartitems_t item)
|
||||
{
|
||||
switch (item)
|
||||
{
|
||||
case KITEM_SPB:
|
||||
case KITEM_SHRINK:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static fixed_t K_ItemOddsScale(UINT8 playerCount)
|
||||
{
|
||||
const UINT8 basePlayer = 8; // The player count we design most of the game around.
|
||||
fixed_t playerScaling = 0;
|
||||
|
|
@ -205,18 +223,23 @@ fixed_t K_ItemOddsScale(UINT8 playerCount)
|
|||
return playerScaling;
|
||||
}
|
||||
|
||||
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers)
|
||||
static UINT32 K_UndoMapScaling(UINT32 distance)
|
||||
{
|
||||
if (mapobjectscale != FRACUNIT)
|
||||
{
|
||||
// Bring back to normal scale.
|
||||
distance = FixedDiv(distance, mapobjectscale);
|
||||
return FixedDiv(distance, mapobjectscale);
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
static UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers)
|
||||
{
|
||||
if (franticitems == true)
|
||||
{
|
||||
// Frantic items pretends everyone's farther apart, for crazier items.
|
||||
distance = (15 * distance) / 14;
|
||||
distance = FixedMul(distance, FRANTIC_ITEM_SCALE);
|
||||
}
|
||||
|
||||
// Items get crazier with the fewer players that you have.
|
||||
|
|
@ -228,7 +251,7 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers)
|
|||
return distance;
|
||||
}
|
||||
|
||||
UINT32 K_GetItemRouletteDistance(player_t *const player, UINT8 pingame)
|
||||
static UINT32 K_GetItemRouletteDistance(player_t *const player, UINT8 numPlayers)
|
||||
{
|
||||
UINT32 pdis = 0;
|
||||
|
||||
|
|
@ -274,12 +297,13 @@ UINT32 K_GetItemRouletteDistance(player_t *const player, UINT8 pingame)
|
|||
}
|
||||
}
|
||||
|
||||
pdis = K_ScaleItemDistance(pdis, pingame);
|
||||
pdis = K_UndoMapScaling(pdis);
|
||||
pdis = K_ScaleItemDistance(pdis, numPlayers);
|
||||
|
||||
if (player->bot && player->botvars.rival)
|
||||
{
|
||||
// Rival has better odds :)
|
||||
pdis = (15 * pdis) / 14;
|
||||
pdis = FixedMul(pdis, FRANTIC_ITEM_SCALE);
|
||||
}
|
||||
|
||||
return pdis;
|
||||
|
|
@ -292,30 +316,33 @@ UINT32 K_GetItemRouletteDistance(player_t *const player, UINT8 pingame)
|
|||
\return void
|
||||
*/
|
||||
|
||||
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, boolean rival)
|
||||
INT32 K_KartGetItemOdds(player_t *const player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item)
|
||||
{
|
||||
fixed_t newOdds;
|
||||
INT32 i;
|
||||
boolean bot = false;
|
||||
boolean rival = false;
|
||||
UINT8 position = 0;
|
||||
|
||||
UINT8 pingame = 0, pexiting = 0;
|
||||
|
||||
player_t *first = NULL;
|
||||
player_t *second = NULL;
|
||||
|
||||
UINT32 firstDist = UINT32_MAX;
|
||||
UINT32 secondDist = UINT32_MAX;
|
||||
UINT32 secondToFirst = 0;
|
||||
boolean isFirst = false;
|
||||
INT32 shieldType = KSHIELD_NONE;
|
||||
|
||||
boolean powerItem = false;
|
||||
boolean cooldownOnStart = false;
|
||||
boolean notNearEnd = false;
|
||||
|
||||
INT32 shieldType = KSHIELD_NONE;
|
||||
fixed_t newOdds = 0;
|
||||
size_t i, j;
|
||||
|
||||
I_Assert(roulette != NULL);
|
||||
|
||||
I_Assert(item > KITEM_NONE); // too many off by one scenarioes.
|
||||
I_Assert(item < NUMKARTRESULTS);
|
||||
|
||||
if (player != NULL)
|
||||
{
|
||||
bot = player->bot;
|
||||
rival = (bot == true && player->botvars.rival == true);
|
||||
position = player->position;
|
||||
}
|
||||
|
||||
if (K_ItemEnabled(item) == false)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -345,6 +372,58 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, bool
|
|||
*/
|
||||
(void)bot;
|
||||
|
||||
shieldType = K_GetShieldFromItem(item);
|
||||
switch (shieldType)
|
||||
{
|
||||
case KSHIELD_NONE:
|
||||
/* Marble Garden Top is not REALLY
|
||||
a Sonic 3 shield */
|
||||
case KSHIELD_TOP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] == false || players[i].spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shieldType == K_GetShieldFromItem(players[i].itemtype))
|
||||
{
|
||||
// Don't allow more than one of each shield type at a time
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (K_ItemSingularity(item) == true)
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] == false || players[i].spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (players[i].itemRoulette.active == true)
|
||||
{
|
||||
for (j = 0; j < players[i].itemRoulette.itemListLen; j++)
|
||||
{
|
||||
if (players[i].itemRoulette.itemList[j] == item)
|
||||
{
|
||||
// Don't add if someone is already rolling for it.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
{
|
||||
I_Assert(pos < 2); // DO NOT allow positions past the bounds of the table
|
||||
|
|
@ -358,73 +437,6 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, bool
|
|||
|
||||
newOdds <<= FRACBITS;
|
||||
|
||||
shieldType = K_GetShieldFromItem(item);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS) || players[i].bumpers)
|
||||
{
|
||||
pingame++;
|
||||
}
|
||||
|
||||
if (players[i].exiting)
|
||||
{
|
||||
pexiting++;
|
||||
}
|
||||
|
||||
switch (shieldType)
|
||||
{
|
||||
case KSHIELD_NONE:
|
||||
/* Marble Garden Top is not REALLY
|
||||
a Sonic 3 shield */
|
||||
case KSHIELD_TOP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if (shieldType == K_GetShieldFromItem(players[i].itemtype))
|
||||
{
|
||||
// Don't allow more than one of each shield type at a time
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (players[i].position == 1)
|
||||
{
|
||||
first = &players[i];
|
||||
}
|
||||
|
||||
if (players[i].position == 2)
|
||||
{
|
||||
second = &players[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (first != NULL) // calculate 2nd's distance from 1st, for SPB
|
||||
{
|
||||
firstDist = first->distancetofinish;
|
||||
isFirst = (ourDist <= firstDist);
|
||||
}
|
||||
|
||||
if (second != NULL)
|
||||
{
|
||||
secondDist = second->distancetofinish;
|
||||
}
|
||||
|
||||
if (first != NULL && second != NULL)
|
||||
{
|
||||
secondToFirst = secondDist - firstDist;
|
||||
secondToFirst = K_ScaleItemDistance(secondToFirst, 16 - pingame); // Reversed scaling, so 16P is like 1v1, and 1v1 is like 16P
|
||||
}
|
||||
|
||||
switch (item)
|
||||
{
|
||||
case KITEM_BANANA:
|
||||
|
|
@ -440,7 +452,6 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, bool
|
|||
case KITEM_LANDMINE:
|
||||
case KITEM_DROPTARGET:
|
||||
case KITEM_BALLHOG:
|
||||
case KITEM_HYUDORO:
|
||||
case KRITEM_TRIPLESNEAKER:
|
||||
case KRITEM_TRIPLEORBINAUT:
|
||||
case KRITEM_QUADORBINAUT:
|
||||
|
|
@ -450,6 +461,7 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, bool
|
|||
break;
|
||||
}
|
||||
|
||||
case KITEM_HYUDORO:
|
||||
case KRITEM_TRIPLEBANANA:
|
||||
{
|
||||
powerItem = true;
|
||||
|
|
@ -473,17 +485,23 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, bool
|
|||
cooldownOnStart = true;
|
||||
notNearEnd = true;
|
||||
|
||||
if (firstDist < ENDDIST*2 // No SPB when 1st is almost done
|
||||
|| isFirst == true) // No SPB for 1st ever
|
||||
if ((gametyperules & GTR_CIRCUIT) == 0)
|
||||
{
|
||||
newOdds = 0;
|
||||
// Needs to be a race.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (roulette->firstDist < ENDDIST*2 // No SPB when 1st is almost done
|
||||
|| position == 1) // No SPB for 1st ever
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const UINT32 dist = max(0, ((signed)secondToFirst) - SPBSTARTDIST);
|
||||
const UINT32 dist = max(0, ((signed)roulette->secondToFirst) - SPBSTARTDIST);
|
||||
const UINT32 distRange = SPBFORCEDIST - SPBSTARTDIST;
|
||||
const UINT8 maxOdds = 20;
|
||||
fixed_t multiplier = (dist * FRACUNIT) / distRange;
|
||||
const fixed_t maxOdds = 20 << FRACBITS;
|
||||
fixed_t multiplier = FixedDiv(dist, distRange);
|
||||
|
||||
if (multiplier < 0)
|
||||
{
|
||||
|
|
@ -495,34 +513,40 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, bool
|
|||
multiplier = FRACUNIT;
|
||||
}
|
||||
|
||||
newOdds = FixedMul(maxOdds << FRACBITS, multiplier);
|
||||
newOdds = FixedMul(maxOdds, multiplier);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KITEM_SHRINK:
|
||||
{
|
||||
cooldownOnStart = true;
|
||||
powerItem = true;
|
||||
notNearEnd = true;
|
||||
|
||||
if (pingame-1 <= pexiting)
|
||||
if (roulette->playing - 1 <= roulette->exiting)
|
||||
{
|
||||
newOdds = 0;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KITEM_LIGHTNINGSHIELD:
|
||||
{
|
||||
cooldownOnStart = true;
|
||||
powerItem = true;
|
||||
|
||||
if (spbplace != -1)
|
||||
{
|
||||
newOdds = 0;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newOdds == 0)
|
||||
|
|
@ -536,7 +560,7 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, bool
|
|||
// 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 ((notNearEnd == true) && (roulette->baseDist < ENDDIST))
|
||||
{
|
||||
// This item should not appear at the end of a race. (Usually trap items that lose their effectiveness)
|
||||
newOdds = 0;
|
||||
|
|
@ -556,16 +580,14 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, bool
|
|||
newOdds *= 2;
|
||||
}
|
||||
|
||||
newOdds = FixedMul(newOdds, FRACUNIT + K_ItemOddsScale(pingame));
|
||||
newOdds = FixedMul(newOdds, FRACUNIT + K_ItemOddsScale(roulette->playing));
|
||||
}
|
||||
|
||||
newOdds = FixedInt(FixedRound(newOdds));
|
||||
return newOdds;
|
||||
}
|
||||
|
||||
//{ SRB2kart Roulette Code - Distance Based, yes waypoints
|
||||
|
||||
UINT8 K_FindUseodds(player_t *const player, UINT32 playerDist)
|
||||
static UINT8 K_FindUseodds(player_t *const player, itemroulette_t *const roulette)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT8 useOdds = 0;
|
||||
|
|
@ -586,11 +608,7 @@ UINT8 K_FindUseodds(player_t *const player, UINT32 playerDist)
|
|||
|
||||
for (j = 1; j < NUMKARTRESULTS; j++)
|
||||
{
|
||||
if (K_KartGetItemOdds(
|
||||
i, j,
|
||||
player->distancetofinish,
|
||||
player->bot, (player->bot && player->botvars.rival)
|
||||
) > 0)
|
||||
if (K_KartGetItemOdds(player, roulette, i, j) > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -636,7 +654,7 @@ UINT8 K_FindUseodds(player_t *const player, UINT32 playerDist)
|
|||
dist = FixedMul(DISTVAR << FRACBITS, pos) >> FRACBITS;
|
||||
index = FixedInt(FixedRound(pos));
|
||||
|
||||
if (playerDist <= (unsigned)dist)
|
||||
if (roulette->dist <= (unsigned)dist)
|
||||
{
|
||||
useOdds = distTable[index];
|
||||
break;
|
||||
|
|
@ -649,14 +667,8 @@ UINT8 K_FindUseodds(player_t *const player, UINT32 playerDist)
|
|||
return useOdds;
|
||||
}
|
||||
|
||||
boolean K_ForcedSPB(player_t *const player)
|
||||
static boolean K_ForcedSPB(player_t *const player, itemroulette_t *const roulette)
|
||||
{
|
||||
player_t *first = NULL;
|
||||
player_t *second = NULL;
|
||||
UINT32 secondToFirst = UINT32_MAX;
|
||||
UINT8 pingame = 0;
|
||||
UINT8 i;
|
||||
|
||||
if (K_ItemEnabled(KITEM_SPB) == false)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -682,49 +694,20 @@ boolean K_ForcedSPB(player_t *const player)
|
|||
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)
|
||||
if (roulette->playing <= 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (first != NULL && second != NULL)
|
||||
{
|
||||
secondToFirst = second->distancetofinish - first->distancetofinish;
|
||||
secondToFirst = K_ScaleItemDistance(secondToFirst, 16 - pingame);
|
||||
}
|
||||
|
||||
return (secondToFirst >= SPBFORCEDIST);
|
||||
return (roulette->secondToFirst >= SPBFORCEDIST);
|
||||
}
|
||||
|
||||
static void K_InitRoulette(itemroulette_t *const roulette)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
#ifndef ITEM_LIST_SIZE
|
||||
if (roulette->itemList == NULL)
|
||||
{
|
||||
|
|
@ -744,13 +727,50 @@ static void K_InitRoulette(itemroulette_t *const roulette)
|
|||
|
||||
roulette->itemListLen = 0;
|
||||
roulette->index = 0;
|
||||
|
||||
roulette->useOdds = UINT8_MAX;
|
||||
roulette->baseDist = roulette->dist = 0;
|
||||
roulette->playing = roulette->exiting = 0;
|
||||
roulette->firstDist = roulette->secondDist = UINT32_MAX;
|
||||
roulette->secondToFirst = 0;
|
||||
|
||||
roulette->elapsed = 0;
|
||||
roulette->tics = roulette->speed = ROULETTE_SPEED_FASTEST; // Some default speed
|
||||
|
||||
roulette->active = true;
|
||||
roulette->eggman = false;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] == false || players[i].spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
roulette->playing++;
|
||||
|
||||
if (players[i].exiting)
|
||||
{
|
||||
roulette->exiting++;
|
||||
}
|
||||
|
||||
if (players[i].position == 1)
|
||||
{
|
||||
roulette->firstDist = K_UndoMapScaling(players[i].distancetofinish);
|
||||
}
|
||||
|
||||
if (players[i].position == 2)
|
||||
{
|
||||
roulette->secondDist = K_UndoMapScaling(players[i].distancetofinish);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate 2nd's distance from 1st, for SPB
|
||||
if (roulette->firstDist != UINT32_MAX && roulette->secondDist != UINT32_MAX)
|
||||
{
|
||||
roulette->secondToFirst = roulette->secondDist - roulette->firstDist;
|
||||
roulette->secondToFirst = K_ScaleItemDistance(roulette->secondToFirst, 16 - roulette->playing); // Reversed scaling
|
||||
}
|
||||
}
|
||||
|
||||
static void K_PushToRouletteItemList(itemroulette_t *const roulette, kartitems_t item)
|
||||
|
|
@ -785,58 +805,47 @@ static void K_PushToRouletteItemList(itemroulette_t *const roulette, kartitems_t
|
|||
roulette->itemListLen++;
|
||||
}
|
||||
|
||||
static void K_AddItemToReel(player_t *const player, itemroulette_t *const roulette, kartitems_t item)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, item);
|
||||
|
||||
// If we're in ring debt, pad out the reel with
|
||||
// a BUNCH of Super Rings.
|
||||
if (K_ItemEnabled(KITEM_SUPERRING) == true
|
||||
&& player->rings <= 0
|
||||
&& (gametyperules & GTR_SPHERES) == 0)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, KITEM_SUPERRING);
|
||||
}
|
||||
}
|
||||
|
||||
static void K_CalculateRouletteSpeed(player_t *const player, itemroulette_t *const roulette)
|
||||
{
|
||||
fixed_t frontRun = 0;
|
||||
fixed_t progress = 0;
|
||||
fixed_t total = 0;
|
||||
|
||||
UINT8 playing = 0;
|
||||
|
||||
UINT32 firstDist = UINT32_MAX;
|
||||
UINT32 ourDist = UINT32_MAX;
|
||||
|
||||
size_t i;
|
||||
|
||||
// Make them select their item after a little while.
|
||||
// One of the few instances of bot RNG, would be nice to remove it.
|
||||
player->botvars.itemdelay = P_RandomRange(PR_UNDEFINED, TICRATE, TICRATE*3);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] == false || players[i].spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
playing++;
|
||||
|
||||
if (players[i].position == 1)
|
||||
{
|
||||
firstDist = players[i].distancetofinish;
|
||||
}
|
||||
}
|
||||
|
||||
if (modeattacking || playing <= 1)
|
||||
if (modeattacking || roulette->playing <= 1)
|
||||
{
|
||||
// Time Attack rules; use a consistent speed.
|
||||
roulette->tics = roulette->speed = ROULETTE_SPEED_TIMEATTACK;
|
||||
return;
|
||||
}
|
||||
|
||||
ourDist = K_ScaleItemDistance(player->distancetofinish, playing);
|
||||
firstDist = K_ScaleItemDistance(firstDist, playing);
|
||||
|
||||
if (ourDist > ENDDIST)
|
||||
if (roulette->baseDist > ENDDIST)
|
||||
{
|
||||
// Being farther in the course makes your roulette faster.
|
||||
progress = min(FRACUNIT, FixedDiv(ourDist - ENDDIST, ROULETTE_SPEED_DIST));
|
||||
progress = min(FRACUNIT, FixedDiv(roulette->baseDist - ENDDIST, ROULETTE_SPEED_DIST));
|
||||
}
|
||||
|
||||
if (ourDist > firstDist)
|
||||
if (roulette->baseDist > roulette->firstDist)
|
||||
{
|
||||
// Frontrunning makes your roulette faster.
|
||||
frontRun = min(FRACUNIT, FixedDiv(ourDist - firstDist, ENDDIST));
|
||||
frontRun = min(FRACUNIT, FixedDiv(roulette->baseDist - roulette->firstDist, ENDDIST));
|
||||
}
|
||||
|
||||
// Combine our two factors together.
|
||||
|
|
@ -862,16 +871,19 @@ static void K_CalculateRouletteSpeed(player_t *const player, itemroulette_t *con
|
|||
|
||||
void K_StartItemRoulette(player_t *const player, itemroulette_t *const roulette)
|
||||
{
|
||||
UINT8 playing = 0;
|
||||
UINT32 playerDist = UINT32_MAX;
|
||||
|
||||
UINT32 spawnChance[NUMKARTRESULTS] = {0};
|
||||
UINT32 totalSpawnChance = 0;
|
||||
size_t rngRoll = 0;
|
||||
|
||||
UINT8 numItems = 0;
|
||||
kartitems_t singleItem = KITEM_SAD;
|
||||
|
||||
size_t i;
|
||||
|
||||
K_InitRoulette(roulette);
|
||||
|
||||
roulette->baseDist = K_UndoMapScaling(player->distancetofinish);
|
||||
|
||||
K_CalculateRouletteSpeed(player, roulette);
|
||||
|
||||
// SPECIAL CASE No. 1:
|
||||
|
|
@ -884,16 +896,6 @@ void K_StartItemRoulette(player_t *const player, itemroulette_t *const roulette)
|
|||
|
||||
// SPECIAL CASE No. 2:
|
||||
// Use a special, pre-determined item reel for Time Attack / Free Play
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] == false || players[i].spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
playing++;
|
||||
}
|
||||
|
||||
if (bossinfo.boss == true)
|
||||
{
|
||||
for (i = 0; K_KartItemReelBoss[i] != KITEM_NONE; i++)
|
||||
|
|
@ -903,7 +905,7 @@ void K_StartItemRoulette(player_t *const player, itemroulette_t *const roulette)
|
|||
|
||||
return;
|
||||
}
|
||||
else if (modeattacking || playing <= 1)
|
||||
else if (modeattacking || roulette->playing <= 1)
|
||||
{
|
||||
switch (gametype)
|
||||
{
|
||||
|
|
@ -931,36 +933,58 @@ void K_StartItemRoulette(player_t *const player, itemroulette_t *const roulette)
|
|||
|
||||
// SPECIAL CASE No. 3:
|
||||
// Only give the SPB if conditions are right
|
||||
if (K_ForcedSPB(player) == true)
|
||||
if (K_ForcedSPB(player, roulette) == true)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, KITEM_SPB);
|
||||
K_AddItemToReel(player, roulette, KITEM_SPB);
|
||||
return;
|
||||
}
|
||||
|
||||
playerDist = K_GetItemRouletteDistance(player, playing);
|
||||
|
||||
roulette->useOdds = K_FindUseodds(player, playerDist);
|
||||
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
INT32 thisItemsOdds = K_KartGetItemOdds(
|
||||
roulette->useOdds, i,
|
||||
player->distancetofinish,
|
||||
player->bot, (player->bot && player->botvars.rival)
|
||||
);
|
||||
|
||||
spawnChance[i] = (totalSpawnChance += thisItemsOdds);
|
||||
}
|
||||
|
||||
// SPECIAL CASE No. 4:
|
||||
// All items are off, so give a placeholder item
|
||||
if (totalSpawnChance == 0)
|
||||
// If only one item is enabled, always use it
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, KITEM_SAD);
|
||||
if (K_ItemEnabled(i) == true)
|
||||
{
|
||||
numItems++;
|
||||
if (numItems > 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
singleItem = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (numItems < 2)
|
||||
{
|
||||
// singleItem = KITEM_SAD by default,
|
||||
// so it will be used when all items are turned off.
|
||||
K_AddItemToReel(player, roulette, singleItem);
|
||||
return;
|
||||
}
|
||||
|
||||
// We always want the same result when making the same item reel.
|
||||
// Special cases are all handled, we can now
|
||||
// actually calculate actual item reels.
|
||||
roulette->dist = K_GetItemRouletteDistance(player, roulette->playing);
|
||||
roulette->useOdds = K_FindUseodds(player, roulette);
|
||||
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
spawnChance[i] = (
|
||||
totalSpawnChance += K_KartGetItemOdds(player, roulette, roulette->useOdds, i)
|
||||
);
|
||||
}
|
||||
|
||||
if (totalSpawnChance == 0)
|
||||
{
|
||||
// This shouldn't happen, but if it does, early exit.
|
||||
// Maybe can happen if you enable multiple items for
|
||||
// another gametype, so we give the singleItem as a fallback.
|
||||
K_AddItemToReel(player, roulette, singleItem);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the same item reel given the same inputs.
|
||||
P_SetRandSeed(PR_ITEM_ROULETTE, ITEM_REEL_SEED);
|
||||
|
||||
while (totalSpawnChance > 0)
|
||||
|
|
@ -971,16 +995,7 @@ void K_StartItemRoulette(player_t *const player, itemroulette_t *const roulette)
|
|||
continue;
|
||||
}
|
||||
|
||||
K_PushToRouletteItemList(roulette, i);
|
||||
|
||||
// If we're in ring debt, pad out the reel with
|
||||
// a BUNCH of Super Rings.
|
||||
if (K_ItemEnabled(KITEM_SUPERRING) == true
|
||||
&& player->rings <= 0
|
||||
&& (gametyperules & GTR_SPHERES) == 0)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, KITEM_SUPERRING);
|
||||
}
|
||||
K_AddItemToReel(player, roulette, i);
|
||||
|
||||
for (; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
|
|
@ -1011,7 +1026,7 @@ void K_StartEggmanRoulette(player_t *const player)
|
|||
*/
|
||||
static void K_KartGetItemResult(player_t *const player, kartitems_t getitem)
|
||||
{
|
||||
if (getitem == KITEM_SPB || getitem == KITEM_SHRINK)
|
||||
if (K_ItemSingularity(getitem) == true)
|
||||
{
|
||||
K_SetItemCooldown(getitem, 20*TICRATE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,15 +17,9 @@
|
|||
#include "d_player.h"
|
||||
|
||||
boolean K_ItemEnabled(SINT8 item);
|
||||
boolean K_ItemSingularity(kartitems_t item);
|
||||
|
||||
fixed_t K_ItemOddsScale(UINT8 playerCount);
|
||||
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers);
|
||||
UINT32 K_GetItemRouletteDistance(player_t *const player, UINT8 pingame);
|
||||
|
||||
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, boolean bot, boolean rival);
|
||||
UINT8 K_FindUseodds(player_t *const player, UINT32 playerDist);
|
||||
|
||||
boolean K_ForcedSPB(player_t *const player);
|
||||
INT32 K_KartGetItemOdds(player_t *const player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item);
|
||||
|
||||
void K_StartItemRoulette(player_t *const player, itemroulette_t *const roulette);
|
||||
void K_StartEggmanRoulette(player_t *const player);
|
||||
|
|
|
|||
|
|
@ -444,6 +444,7 @@ static void P_NetArchivePlayers(void)
|
|||
#endif
|
||||
|
||||
WRITEUINT8(save_p, players[i].itemRoulette.useOdds);
|
||||
WRITEUINT32(save_p, players[i].itemRoulette.dist);
|
||||
WRITEUINT32(save_p, players[i].itemRoulette.index);
|
||||
WRITEUINT8(save_p, players[i].itemRoulette.sound);
|
||||
WRITEUINT32(save_p, players[i].itemRoulette.speed);
|
||||
|
|
@ -798,6 +799,7 @@ static void P_NetUnArchivePlayers(void)
|
|||
#endif
|
||||
|
||||
players[i].itemRoulette.useOdds = READUINT8(save_p);
|
||||
players[i].itemRoulette.dist = READUINT32(save_p);
|
||||
players[i].itemRoulette.index = (size_t)READUINT32(save_p);
|
||||
players[i].itemRoulette.sound = READUINT8(save_p);
|
||||
players[i].itemRoulette.speed = (tic_t)READUINT32(save_p);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue