Merge branch 'item-jumbler' into 'master'

Gameplay prototyping lightning round

See merge request KartKrew/Kart!2439
This commit is contained in:
Oni 2024-08-28 05:10:15 +00:00
commit cb5dcea80d
17 changed files with 215 additions and 23 deletions

View file

@ -511,6 +511,8 @@ struct itemroulette_t
boolean ringbox;
boolean autoroulette;
UINT8 reserved;
UINT8 popcorn;
};
// enum for bot item priorities
@ -766,6 +768,9 @@ struct player_t
UINT16 ringboost; // Ring boost timer
UINT8 sparkleanim; // (0 to 19) - Angle offset for ring sparkle animation
UINT16 superring; // You were awarded rings, and have this many of them left to spawn on yourself.
UINT16 superringdisplay; // For HUD countup when awarded superring
UINT16 superringpeak; // Display award when getting awarded
UINT8 superringalert; // Timer for displaying award instead of countdown
UINT8 nextringaward; // When should we spawn our next superring ring?
UINT8 ringvolume; // When consuming lots of rings, lower the sound a little.
UINT8 ringtransparency; // When consuming lots of rings, fade out the rings again.

View file

@ -1571,6 +1571,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_AMPRING",
"S_AMPBODY",
"S_AMPAURA",
"S_AMPBURST",
"S_CHARGEAURA",
"S_CHARGEFALL",
@ -3514,6 +3515,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_AMPRING",
"MT_AMPBODY",
"MT_AMPAURA",
"MT_AMPBURST",
"MT_CHARGEAURA",
"MT_CHARGEFALL",

View file

@ -2130,6 +2130,7 @@ state_t states[NUMSTATES] =
{SPR_AMPB, FF_FULLBRIGHT|FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_AMPRING
{SPR_AMPC, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_AMPBODY
{SPR_AMPD, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_AMPAURA
{SPR_AMPB, FF_FULLBRIGHT|FF_ADD|FF_PAPERSPRITE|2, -1, {NULL}, 4, 2, S_NULL}, // S_AMPBURST
{SPR_TRC1, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_CHARGEAURA
{SPR_TRC2, FF_FULLBRIGHT|FF_ANIMATE|0, 20, {NULL}, 19, 1, S_NULL}, // S_CHARGEFALL
@ -13721,6 +13722,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_AMPBURST
-1, // doomednum
S_AMPBURST, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // 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
67*FRACUNIT, // radius
67*FRACUNIT, // height
1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate
},
{ // MT_CHARGEAURA
-1, // doomednum
S_CHARGEAURA, // spawnstate

View file

@ -2598,6 +2598,7 @@ typedef enum state
S_AMPRING,
S_AMPBODY,
S_AMPAURA,
S_AMPBURST,
S_CHARGEAURA,
S_CHARGEFALL,
@ -4568,6 +4569,7 @@ typedef enum mobj_type
MT_AMPRING,
MT_AMPBODY,
MT_AMPAURA,
MT_AMPBURST,
MT_CHARGEAURA,
MT_CHARGEFALL,

View file

@ -1457,7 +1457,7 @@ static void K_drawKartItem(void)
const SINT8 result = stplyr->itemRoulette.itemList[index];
const SINT8 item = K_ItemResultToType(result);
const boolean usingDebugItemAmount = cv_kartdebugitem.value != KITEM_NONE && cv_kartdebugitem.value == item && cv_kartdebugamount.value > 1;
const UINT8 amt = usingDebugItemAmount ? cv_kartdebugamount.value : K_ItemResultToAmount(result);
const UINT8 amt = usingDebugItemAmount ? cv_kartdebugamount.value : K_ItemResultToAmount(result, &stplyr->itemRoulette);
switch (item)
{
@ -1640,7 +1640,12 @@ static void K_drawKartItem(void)
fy -= 5;
}
V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|fflags, localbg);
UINT8 *boxmap = NULL;
if (stplyr->itemRoulette.active && (stplyr->itemRoulette.speed - stplyr->itemRoulette.tics < 3) && stplyr->itemRoulette.index == 0)
{
boxmap = R_GetTranslationColormap(TC_ALLWHITE, SKINCOLOR_WHITE, GTC_CACHE);
}
V_DrawMappedPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|fflags, localbg, boxmap);
// Need to draw these in a particular order, for sorting.
V_SetClipRect(
@ -3250,13 +3255,29 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
if (stplyr->pflags & PF_RINGLOCK)
V_DrawScaledPatch(fr-12, fy-13, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringspblocksmall[stplyr->karthud[khud_ringspblock]]);
UINT32 greyout = V_HUDTRANS;
SINT8 superoffset = 5;
if (stplyr->superringdisplay)
{
greyout = V_HUDTRANSHALF;
if (flipflag && !uselives)
superoffset = -25 - (stplyr->superringdisplay >= 10 ? 3 : 0) - (stplyr->superringdisplay >= 100 ? 3 : 0);
}
// Lives
if (uselives)
{
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, static_cast<skincolornum_t>(stplyr->skincolor), GTC_CACHE);
V_DrawMappedPatch(fr+21, fy-3, V_HUDTRANS|V_SLIDEIN|splitflags, faceprefix[stplyr->skin][FACE_MINIMAP], colormap);
V_DrawMappedPatch(fr+21, fy-3, V_SLIDEIN|splitflags|greyout, faceprefix[stplyr->skin][FACE_MINIMAP], colormap);
if (stplyr->lives >= 0)
K_DrawLivesDigits(fr+34, fy, 4, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font);
K_DrawLivesDigits(fr+34, fy, 4, V_SLIDEIN|splitflags|greyout, fontv[PINGNUM_FONT].font);
}
if (stplyr->superringdisplay && !(stplyr->superringalert % 2))
{
using srb2::Draw;
Draw row = Draw(fr+19+superoffset, fy).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kPing).colorize(SKINCOLOR_SAPPHIRE);
row.text("+{:01}", abs(stplyr->superringdisplay));
}
}
else
@ -3303,8 +3324,6 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
}
}
// "Why fy-4? Why LAPS_X+29+1?"
// "use magic numbers" - jartha 2024-03-05
if (stplyr->hudrings < 0) // Draw the minus for ring debt
@ -3329,11 +3348,18 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
if (stplyr->pflags & PF_RINGLOCK)
V_DrawScaledPatch(LAPS_X-5, fy-17, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringspblock[stplyr->karthud[khud_ringspblock]]);
UINT32 greyout = V_HUDTRANS;
if (stplyr->superringdisplay)
{
greyout = V_HUDTRANSHALF;
}
// Lives
if (uselives)
{
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, static_cast<skincolornum_t>(stplyr->skincolor), GTC_CACHE);
V_DrawMappedPatch(LAPS_X+46, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags, faceprefix[stplyr->skin][FACE_RANK], colormap);
V_DrawMappedPatch(LAPS_X+46, fy-5, V_SLIDEIN|splitflags|greyout, faceprefix[stplyr->skin][FACE_RANK], colormap);
SINT8 livescount = 0;
if (stplyr->lives > 0)
{
@ -3342,9 +3368,16 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
livescount = 10;
}
using srb2::Draw;
Draw row = Draw(LAPS_X+65, fy-4).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kThinTimer);
Draw row = Draw(LAPS_X+65, fy-4).flags(V_SLIDEIN|splitflags|greyout).font(Draw::Font::kThinTimer);
row.text("{}", livescount);
}
if (stplyr->superringdisplay && !(stplyr->superringalert % 2))
{
using srb2::Draw;
Draw row = Draw(LAPS_X+23+3+15, fy-4).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kThinTimer).colorize(SKINCOLOR_SAPPHIRE);
row.text("+{:01}", abs(stplyr->superringdisplay));
}
}
}
@ -6455,7 +6488,8 @@ void K_drawKartHUD(void)
}
}
K_drawKartTimestamp(realtime, TIME_X, TIME_Y + (ta ? 2 : 0), flags, 0);
if (modeattacking || (gametyperules & GTR_TIMELIMIT))
K_drawKartTimestamp(realtime, TIME_X, TIME_Y + (ta ? 2 : 0), flags, 0);
if (modeattacking)
{

View file

@ -538,7 +538,7 @@ SINT8 K_ItemResultToType(SINT8 getitem)
return getitem;
}
UINT8 K_ItemResultToAmount(SINT8 getitem)
UINT8 K_ItemResultToAmount(SINT8 getitem, const itemroulette_t *roulette)
{
switch (getitem)
{
@ -558,6 +558,12 @@ UINT8 K_ItemResultToAmount(SINT8 getitem)
case KITEM_BALLHOG: // Not a special result, but has a special amount
return 5;
case KITEM_SUPERRING:
if (roulette && roulette->popcorn)
return roulette->popcorn;
else
return 1;
default:
return 1;
}
@ -4128,7 +4134,11 @@ void K_AwardPlayerRings(player_t *player, UINT16 rings, boolean overload)
/* check if not overflow */
if (superring > player->superring)
{
player->superring = superring;
player->superringpeak = superring;
player->superringalert = TICRATE/2;
}
}
boolean K_Overdrive(player_t *player)
@ -6986,7 +6996,7 @@ void K_DoSneaker(player_t *player, INT32 type)
player->overshield += TICRATE/2; // TEMP prototype
break;
case 2:
player->sneakertimer = sneakertime + TICRATE/2;
player->sneakertimer = 3*sneakertime/4;
player->overshield += TICRATE/2; // TEMP prototype
break;
}
@ -7582,7 +7592,7 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
// but item roulette will need rewritten to change this
const SINT8 newType = K_ItemResultToType(i);
const UINT8 newAmount = K_ItemResultToAmount(i);
const UINT8 newAmount = K_ItemResultToAmount(i, NULL);
if (newAmount > 1)
{
@ -9402,6 +9412,24 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->freeRingShooterCooldown && !player->mo->hitlag)
player->freeRingShooterCooldown--;
if (player->superringalert)
{
player->superringdisplay = player->superringpeak;
player->superringalert--;
}
else
{
if (player->superringdisplay != player->superring)
{
INT16 delta = player->superring - player->superringdisplay;
if (player->superring > player->superringdisplay)
delta = max(delta/8, 1);
else
delta = min(delta/8, -1);
player->superringdisplay += delta;
}
}
if (player->superring)
{
player->nextringaward++;
@ -13788,8 +13816,36 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
case KITEM_SUPERRING:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
K_AwardPlayerRings(player, 20, true);
player->itemamount--;
S_StartSound(player->mo, sfx_gsha7);
P_Thrust(player->mo, K_MomentumAngle(player->mo), 25*player->mo->scale);
P_Thrust(player->mo, player->mo->angle, 25*player->mo->scale);
UINT8 numsparks = 8;
for (UINT8 i = 0; i < numsparks; i++)
{
mobj_t *sparkle = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RINGSPARKS);
P_InstaScale(sparkle, player->mo->scale*2);
P_SetTarget(&sparkle->target, player->mo);
sparkle->angle = player->mo->angle + FixedAngle((360*i/numsparks)<<FRACBITS);
player->sparkleanim = (player->sparkleanim+1) % 20;
P_SetTarget(&sparkle->owner, player->mo);
sparkle->renderflags |= RF_REDUCEVFX;
}
mobj_t *burst = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height/2, MT_AMPBURST);
burst->momx = player->mo->momx/2;
burst->momy = player->mo->momy/2;
burst->momz = player->mo->momz/2;
burst->angle = player->mo->angle + ANGLE_90;
burst->scalespeed = burst->scale;
burst->destscale = burst->scale*8;
burst->color = SKINCOLOR_GOLD;
burst->fuse = 8;
// player->strongdriftboost += TICRATE;
// player->driftboost += TICRATE;
K_AwardPlayerRings(player, 20*player->itemamount, true);
player->itemamount = 0;
player->botvars.itemconfirm = 0;
}
break;

View file

@ -105,7 +105,7 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value);
INT32 K_GetShieldFromItem(INT32 item);
SINT8 K_ItemResultToType(SINT8 getitem);
UINT8 K_ItemResultToAmount(SINT8 getitem);
UINT8 K_ItemResultToAmount(SINT8 getitem, const itemroulette_t *roulette);
tic_t K_GetItemCooldown(SINT8 itemResult);
void K_SetItemCooldown(SINT8 itemResult, tic_t time);
void K_RunItemCooldowns(void);

View file

@ -5533,7 +5533,7 @@ void M_DrawItemToggles(void)
cv = &cv_items[currentMenu->menuitems[thisitem].mvar1-1];
drawnum = K_ItemResultToAmount(currentMenu->menuitems[thisitem].mvar1);
drawnum = K_ItemResultToAmount(currentMenu->menuitems[thisitem].mvar1, NULL);
V_DrawScaledPatch(x, y, 0, cv->value ? isbg : isbgd);
@ -5588,7 +5588,7 @@ void M_DrawItemToggles(void)
{
cv = &cv_items[currentMenu->menuitems[itemOn].mvar1-1];
drawnum = K_ItemResultToAmount(currentMenu->menuitems[itemOn].mvar1);
drawnum = K_ItemResultToAmount(currentMenu->menuitems[itemOn].mvar1, NULL);
if (cv->value)
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE));

View file

@ -142,6 +142,7 @@ void Obj_GuardBreakThink(mobj_t *fx);
void Obj_AmpRingThink(mobj_t *amp);
void Obj_AmpBodyThink(mobj_t *amp);
void Obj_AmpAuraThink(mobj_t *amp);
void Obj_AmpBurstThink(mobj_t *amp);
void Obj_AmpsThink(mobj_t *amps);

View file

@ -98,7 +98,7 @@ static UINT32 K_DynamicItemOddsRace[NUMKARTRESULTS-1][2] =
{66, 9}, // flameshield
{1, 3}, // hyudoro
{0, 0}, // pogospring
{7, 4}, // superring
{30, 8}, // superring (SPECIAL! distance value specifies when this can NO LONGER appear)
{0, 0}, // kitchensink
{1, 3}, // droptarget
{43, 5}, // gardentop
@ -796,6 +796,8 @@ static void K_InitRoulette(itemroulette_t *const roulette)
roulette->ringbox = false;
roulette->autoroulette = false;
roulette->popcorn = 1;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] == false || players[i].spectator == true)
@ -1497,6 +1499,26 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
deltas[i] = min(targetpower - powers[i], powers[i] - targetpower);
}
// == "POPCORN" Super Ring in Race.
// This can appear anywhere from 0 to its specified distance, to pad the
// reels with non-disruptive catchup (since we have a ton of offensive items
// and not many front/mid speed items).
boolean canfiltersuperring = true;
if ((gametyperules & GTR_CIRCUIT) && (specialstageinfo.valid == false))
{
if (targetpower > powers[KITEM_SUPERRING])
{
permit[KITEM_SUPERRING] = false;
}
else
{
permit[KITEM_SUPERRING] = true;
deltas[KITEM_SUPERRING] = 0;
canfiltersuperring = false;
roulette->popcorn = (player->position > 1) ? max(1, targetpower/humanscaler/3) : 1;
}
}
// == LONELINESS DETECTION
// A lot of items suck if no players are nearby to interact with them.
// Should we bias towards items that get us back to the action?
@ -1612,7 +1634,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
V_DrawThinString(BASE_X + 65, BASE_Y, FLAGS, va("D%d", deltas[bestitem]/humanscaler));
V_DrawThinString(BASE_X + 20, BASE_Y, FLAGS, va("%d", dupetolerance[bestitem]));
V_DrawFixedPatch(BASE_X*FRACUNIT, (BASE_Y-7)*FRACUNIT, (FRACUNIT >> 1), FLAGS, K_GetSmallStaticCachedItemPatch(bestitem), NULL);
UINT8 amount = K_ItemResultToAmount(bestitem);
UINT8 amount = K_ItemResultToAmount(bestitem, roulette);
if (amount > 1)
V_DrawThinString(BASE_X, BASE_Y, FLAGS, va("x%d", amount));
}
@ -1654,6 +1676,10 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
// feels exciting, low-rolling feels punishing!
boolean reject = (filterweakitems) && (powers[i] + DISTVAR < meanreelpower);
// Popcorn Super Ring is always strong enough, we put it there on purpose.
if (i == KITEM_SUPERRING && !canfiltersuperring)
reject = false;
// Before we actually apply that rejection, draw the simple odds debugger.
// This one is just to watch the distribution for vibes as you drive around.
if (cv_kartdebugdistribution.value && candidates[i])
@ -1667,7 +1693,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
V_DrawThinString(BASE_X - 12, 5+36, FLAGS, va("%d", loneliness));
for(UINT8 k = 0; k < candidates[i]; k++)
V_DrawFixedPatch((BASE_X + 3*k)*FRACUNIT, (BASE_Y-7)*FRACUNIT, (FRACUNIT >> 1), FLAGS, K_GetSmallStaticCachedItemPatch(i), NULL);
UINT8 amount = K_ItemResultToAmount(i);
UINT8 amount = K_ItemResultToAmount(i, roulette);
if (amount > 1)
V_DrawThinString(BASE_X, BASE_Y, FLAGS, va("x%d", amount));
if (reject)
@ -1835,7 +1861,7 @@ static void K_KartGetItemResult(player_t *const player, kartitems_t getitem)
player->botvars.itemconfirm = 0;
player->itemtype = K_ItemResultToType(getitem);
UINT8 itemamount = K_ItemResultToAmount(getitem);
UINT8 itemamount = K_ItemResultToAmount(getitem, &player->itemRoulette);
if (cv_kartdebugitem.value != KITEM_NONE && cv_kartdebugitem.value == player->itemtype && cv_kartdebugamount.value > 1)
itemamount = cv_kartdebugamount.value;
player->itemamount = itemamount;
@ -2001,6 +2027,13 @@ void K_KartItemRoulette(player_t *const player, ticcmd_t *const cmd)
S_StartSound(NULL, sfx_s240);
else
S_StartSound(NULL, sfx_itrol1 + roulette->sound);
if (roulette->index == 0)
{
S_StartSound(NULL, sfx_kc50);
S_StartSound(NULL, sfx_kc50);
}
}
}
else

View file

@ -432,6 +432,12 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->sparkleanim);
else if (fastcmp(field,"superring"))
lua_pushinteger(L, plr->superring);
else if (fastcmp(field,"superringdisplay"))
lua_pushinteger(L, plr->superringdisplay);
else if (fastcmp(field,"superringpeak"))
lua_pushinteger(L, plr->superringpeak);
else if (fastcmp(field,"superringalert"))
lua_pushinteger(L, plr->superringalert);
else if (fastcmp(field,"nextringaward"))
lua_pushinteger(L, plr->nextringaward);
else if (fastcmp(field,"ringvolume"))
@ -1010,6 +1016,12 @@ static int player_set(lua_State *L)
plr->sparkleanim = luaL_checkinteger(L, 3);
else if (fastcmp(field,"superring"))
plr->superring = luaL_checkinteger(L, 3);
else if (fastcmp(field,"superringdisplay"))
plr->superringdisplay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"superringpeak"))
plr->superringpeak = luaL_checkinteger(L, 3);
else if (fastcmp(field,"superringalert"))
plr->superringalert = luaL_checkinteger(L, 3);
else if (fastcmp(field,"nextringaward"))
plr->nextringaward = luaL_checkinteger(L, 3);
else if (fastcmp(field,"ringvolume"))

View file

@ -195,3 +195,9 @@ void Obj_AmpAuraThink (mobj_t *amps)
amps->renderflags &= ~RF_DONTDRAW;
}
}
void Obj_AmpBurstThink (mobj_t *amps)
{
amps->renderflags &= ~RF_TRANSMASK;
amps->renderflags |= (NUMTRANSMAPS - amps->fuse) << RF_TRANSSHIFT;
}

View file

@ -677,6 +677,7 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe
}
player->exp += K_GetExpAdjustment(player);
K_AwardPlayerRings(player, 10, true);
player->gradingpointnum++;
K_UpdatePowerLevels(player, player->laps, false);

View file

@ -408,7 +408,7 @@ project_icon (mobj_t *part)
K_UpdateMobjItemOverlay(part,
K_ItemResultToType(result),
K_ItemResultToAmount(result));
K_ItemResultToAmount(result, NULL));
center_item_sprite(part, 5*FRACUNIT/4);
}
@ -703,7 +703,7 @@ Obj_MonitorOnDeath
monitor->x, monitor->y, monitor->z + (128 * mapobjectscale * flip),
i * ang, flip,
K_ItemResultToType(result),
K_ItemResultToAmount(result)));
K_ItemResultToAmount(result, NULL)));
drop->momz /= 2; // This is player-locked, so no need to throw it high

View file

@ -8641,6 +8641,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
Obj_AmpAuraThink(mobj);
break;
}
case MT_AMPBURST:
{
Obj_AmpBurstThink(mobj);
break;
}
case MT_CHARGEAURA:
{
Obj_ChargeAuraThink(mobj);

View file

@ -501,6 +501,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT16(save->p, players[i].ringboost);
WRITEUINT8(save->p, players[i].sparkleanim);
WRITEUINT16(save->p, players[i].superring);
WRITEUINT16(save->p, players[i].superringdisplay);
WRITEUINT16(save->p, players[i].superringpeak);
WRITEUINT8(save->p, players[i].superringalert);
WRITEUINT8(save->p, players[i].nextringaward);
WRITEUINT8(save->p, players[i].ringvolume);
WRITEUINT8(save->p, players[i].ringtransparency);
@ -1119,6 +1122,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].ringboost = READUINT16(save->p);
players[i].sparkleanim = READUINT8(save->p);
players[i].superring = READUINT16(save->p);
players[i].superringdisplay = READUINT16(save->p);
players[i].superringpeak = READUINT16(save->p);
players[i].superringalert = READUINT8(save->p);
players[i].nextringaward = READUINT8(save->p);
players[i].ringvolume = READUINT8(save->p);
players[i].ringtransparency = READUINT8(save->p);

View file

@ -2119,6 +2119,7 @@ static void K_HandleLapIncrement(player_t *player)
}
player->exp += K_GetExpAdjustment(player);
K_AwardPlayerRings(player, 10, true);
player->gradingpointnum++;
if (player->position == 1 && !(gametyperules & GTR_CHECKPOINTS))