mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge remote-tracking branch 'origin/race-checkpoint'
This commit is contained in:
commit
3670695df6
22 changed files with 1009 additions and 607 deletions
|
|
@ -819,7 +819,7 @@ consvar_t cv_fuzz = OnlineCheat("fuzz", "Off").on_off().description("Human playe
|
||||||
|
|
||||||
consvar_t cv_kartdebugamount = OnlineCheat("debugitemamount", "1").min_max(1, 255).description("If debugitem, give multiple copies of an item");
|
consvar_t cv_kartdebugamount = OnlineCheat("debugitemamount", "1").min_max(1, 255).description("If debugitem, give multiple copies of an item");
|
||||||
consvar_t cv_kartdebugbots = OnlineCheat("debugbots", "Off").on_off().description("Bot AI debugger");
|
consvar_t cv_kartdebugbots = OnlineCheat("debugbots", "Off").on_off().description("Bot AI debugger");
|
||||||
consvar_t cv_kartdebugdistribution = OnlineCheat("debugitemodds", "Off").on_off().description("Show items that the roulette can roll");
|
consvar_t cv_kartdebugdistribution = OnlineCheat("debugitemodds", "0").min_max(0, 2).description("Show items that the roulette can roll");
|
||||||
consvar_t cv_kartdebughuddrop = OnlineCheat("debugitemdrop", "Off").on_off().description("Players drop paper items when damaged in any way");
|
consvar_t cv_kartdebughuddrop = OnlineCheat("debugitemdrop", "Off").on_off().description("Players drop paper items when damaged in any way");
|
||||||
|
|
||||||
consvar_t cv_kartdebugbotwhip = OnlineCheat("debugbotwhip", "Off").on_off().description("Disable bot ring and item pickups");
|
consvar_t cv_kartdebugbotwhip = OnlineCheat("debugbotwhip", "Off").on_off().description("Disable bot ring and item pickups");
|
||||||
|
|
|
||||||
|
|
@ -6805,6 +6805,22 @@ INT32 D_NumPlayers(void)
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the number of players racing, not spectating and includes bots
|
||||||
|
* \return Number of players. Can be zero if we're running a ::dedicated
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
INT32 D_NumPlayersInRace(void)
|
||||||
|
{
|
||||||
|
INT32 numPlayers = 0;
|
||||||
|
INT32 i;
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (playeringame[i] && !players[i].spectator)
|
||||||
|
numPlayers++;
|
||||||
|
}
|
||||||
|
return numPlayers;
|
||||||
|
}
|
||||||
|
|
||||||
/** Return whether a player is a real person (not a CPU) and not spectating.
|
/** Return whether a player is a real person (not a CPU) and not spectating.
|
||||||
*/
|
*/
|
||||||
boolean D_IsPlayerHumanAndGaming (INT32 player_number)
|
boolean D_IsPlayerHumanAndGaming (INT32 player_number)
|
||||||
|
|
|
||||||
|
|
@ -657,6 +657,7 @@ extern UINT8 playernode[MAXPLAYERS];
|
||||||
extern UINT8 playerconsole[MAXPLAYERS];
|
extern UINT8 playerconsole[MAXPLAYERS];
|
||||||
|
|
||||||
INT32 D_NumPlayers(void);
|
INT32 D_NumPlayers(void);
|
||||||
|
INT32 D_NumPlayersInRace(void);
|
||||||
boolean D_IsPlayerHumanAndGaming(INT32 player_number);
|
boolean D_IsPlayerHumanAndGaming(INT32 player_number);
|
||||||
|
|
||||||
void D_ResetTiccmds(void);
|
void D_ResetTiccmds(void);
|
||||||
|
|
|
||||||
|
|
@ -495,9 +495,8 @@ struct itemroulette_t
|
||||||
SINT8 *itemList;
|
SINT8 *itemList;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UINT8 useOdds;
|
|
||||||
UINT8 playing, exiting;
|
UINT8 playing, exiting;
|
||||||
UINT32 dist, baseDist;
|
UINT32 preexpdist, dist, baseDist;
|
||||||
UINT32 firstDist, secondDist;
|
UINT32 firstDist, secondDist;
|
||||||
UINT32 secondToFirst;
|
UINT32 secondToFirst;
|
||||||
|
|
||||||
|
|
@ -914,6 +913,7 @@ struct player_t
|
||||||
UINT8 laps; // Number of laps (optional)
|
UINT8 laps; // Number of laps (optional)
|
||||||
UINT8 latestlap;
|
UINT8 latestlap;
|
||||||
UINT32 lapPoints; // Points given from laps
|
UINT32 lapPoints; // Points given from laps
|
||||||
|
INT32 exp;
|
||||||
INT32 cheatchecknum; // The number of the last cheatcheck you hit
|
INT32 cheatchecknum; // The number of the last cheatcheck you hit
|
||||||
INT32 checkpointId; // Players respawn here, objects/checkpoint.cpp
|
INT32 checkpointId; // Players respawn here, objects/checkpoint.cpp
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2131,6 +2131,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
UINT8 laps;
|
UINT8 laps;
|
||||||
UINT8 latestlap;
|
UINT8 latestlap;
|
||||||
UINT32 lapPoints;
|
UINT32 lapPoints;
|
||||||
|
INT32 exp;
|
||||||
UINT16 skincolor;
|
UINT16 skincolor;
|
||||||
INT32 skin;
|
INT32 skin;
|
||||||
UINT8 availabilities[MAXAVAILABILITY];
|
UINT8 availabilities[MAXAVAILABILITY];
|
||||||
|
|
@ -2319,6 +2320,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
laps = 0;
|
laps = 0;
|
||||||
latestlap = 0;
|
latestlap = 0;
|
||||||
lapPoints = 0;
|
lapPoints = 0;
|
||||||
|
exp = FRACUNIT;
|
||||||
roundscore = 0;
|
roundscore = 0;
|
||||||
exiting = 0;
|
exiting = 0;
|
||||||
khudfinish = 0;
|
khudfinish = 0;
|
||||||
|
|
@ -2356,6 +2358,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
laps = players[player].laps;
|
laps = players[player].laps;
|
||||||
latestlap = players[player].latestlap;
|
latestlap = players[player].latestlap;
|
||||||
lapPoints = players[player].lapPoints;
|
lapPoints = players[player].lapPoints;
|
||||||
|
exp = players[player].exp;
|
||||||
|
|
||||||
roundscore = players[player].roundscore;
|
roundscore = players[player].roundscore;
|
||||||
|
|
||||||
|
|
@ -2470,6 +2473,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
p->laps = laps;
|
p->laps = laps;
|
||||||
p->latestlap = latestlap;
|
p->latestlap = latestlap;
|
||||||
p->lapPoints = lapPoints;
|
p->lapPoints = lapPoints;
|
||||||
|
p->exp = exp;
|
||||||
p->totalring = totalring;
|
p->totalring = totalring;
|
||||||
|
|
||||||
for (i = 0; i < LAP__MAX; i++)
|
for (i = 0; i < LAP__MAX; i++)
|
||||||
|
|
@ -5248,7 +5252,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
|
||||||
players[i].score = 0;
|
players[i].score = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetplayer || map != gamemap)
|
if (resetplayer || !(gametyperules & GTR_CHECKPOINTS && map == gamemap))
|
||||||
{
|
{
|
||||||
players[i].checkpointId = 0;
|
players[i].checkpointId = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1061,7 +1061,7 @@ static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static patch_t *K_GetSmallStaticCachedItemPatch(kartitems_t item)
|
patch_t *K_GetSmallStaticCachedItemPatch(kartitems_t item)
|
||||||
{
|
{
|
||||||
UINT8 offset;
|
UINT8 offset;
|
||||||
|
|
||||||
|
|
@ -5736,60 +5736,28 @@ static void K_drawDistributionDebugger(void)
|
||||||
itemroulette_t rouletteData = {0};
|
itemroulette_t rouletteData = {0};
|
||||||
|
|
||||||
const fixed_t scale = (FRACUNIT >> 1);
|
const fixed_t scale = (FRACUNIT >> 1);
|
||||||
const fixed_t space = 24 * scale;
|
|
||||||
const fixed_t pad = 9 * scale;
|
const fixed_t pad = 9 * scale;
|
||||||
|
|
||||||
fixed_t x = -pad;
|
fixed_t x = -pad;
|
||||||
fixed_t y = -pad;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (R_GetViewNumber() != 0) // only for p1
|
if (R_GetViewNumber() != 0) // only for p1
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
K_FillItemRouletteData(stplyr, &rouletteData, false);
|
K_FillItemRouletteData(stplyr, &rouletteData, false, true);
|
||||||
|
|
||||||
for (i = 0; i < rouletteData.itemListLen; i++)
|
if (cv_kartdebugdistribution.value <= 1)
|
||||||
{
|
return;
|
||||||
const kartitems_t item = static_cast<kartitems_t>(rouletteData.itemList[i]);
|
|
||||||
UINT8 amount = 1;
|
|
||||||
|
|
||||||
if (y > (BASEVIDHEIGHT << FRACBITS) - space - pad)
|
V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+10, V_SNAPTOTOP|V_SNAPTORIGHT, va("speed = %u", rouletteData.speed));
|
||||||
{
|
|
||||||
x += space;
|
|
||||||
y = -pad;
|
|
||||||
}
|
|
||||||
|
|
||||||
V_DrawFixedPatch(x, y, scale, V_SNAPTOTOP,
|
V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+22, V_SNAPTOTOP|V_SNAPTORIGHT, va("baseDist = %u", rouletteData.baseDist));
|
||||||
K_GetSmallStaticCachedItemPatch(item), NULL);
|
V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+30, V_SNAPTOTOP|V_SNAPTORIGHT, va("dist = %u", rouletteData.dist));
|
||||||
|
|
||||||
// Display amount for multi-items
|
V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+42, V_SNAPTOTOP|V_SNAPTORIGHT, va("firstDist = %u", rouletteData.firstDist));
|
||||||
amount = K_ItemResultToAmount(item);
|
V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+50, V_SNAPTOTOP|V_SNAPTORIGHT, va("secondDist = %u", rouletteData.secondDist));
|
||||||
if (amount > 1)
|
V_DrawRightAlignedThinString(320-(x >> FRACBITS), 100+58, V_SNAPTOTOP|V_SNAPTORIGHT, va("secondToFirst = %u", rouletteData.secondToFirst));
|
||||||
{
|
|
||||||
V_DrawStringScaled(
|
|
||||||
x + (18 * scale),
|
|
||||||
y + (23 * scale),
|
|
||||||
scale, FRACUNIT, FRACUNIT,
|
|
||||||
V_SNAPTOTOP,
|
|
||||||
NULL, HU_FONT,
|
|
||||||
va("x%d", amount)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
y += space;
|
|
||||||
}
|
|
||||||
|
|
||||||
V_DrawString((x >> FRACBITS) + 20, 2, V_SNAPTOTOP, va("useOdds[%u]", rouletteData.useOdds));
|
|
||||||
V_DrawString((x >> FRACBITS) + 20, 10, V_SNAPTOTOP, va("speed = %u", rouletteData.speed));
|
|
||||||
|
|
||||||
V_DrawString((x >> FRACBITS) + 20, 22, V_SNAPTOTOP, va("baseDist = %u", rouletteData.baseDist));
|
|
||||||
V_DrawString((x >> FRACBITS) + 20, 30, V_SNAPTOTOP, va("dist = %u", rouletteData.dist));
|
|
||||||
|
|
||||||
V_DrawString((x >> FRACBITS) + 20, 42, V_SNAPTOTOP, va("firstDist = %u", rouletteData.firstDist));
|
|
||||||
V_DrawString((x >> FRACBITS) + 20, 50, V_SNAPTOTOP, va("secondDist = %u", rouletteData.secondDist));
|
|
||||||
V_DrawString((x >> FRACBITS) + 20, 58, V_SNAPTOTOP, va("secondToFirst = %u", rouletteData.secondToFirst));
|
|
||||||
|
|
||||||
#ifndef ITEM_LIST_SIZE
|
#ifndef ITEM_LIST_SIZE
|
||||||
Z_Free(rouletteData.itemList);
|
Z_Free(rouletteData.itemList);
|
||||||
|
|
@ -6096,7 +6064,7 @@ void K_ClearPersistentMessages()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return value can be used for "paired" splitscreen messages, true = was displayed
|
// Return value can be used for "paired" splitscreen messages, true = was displayed
|
||||||
void K_AddMessageForPlayer(player_t *player, const char *msg, boolean interrupt, boolean persist)
|
void K_AddMessageForPlayer(const player_t *player, const char *msg, boolean interrupt, boolean persist)
|
||||||
{
|
{
|
||||||
if (!player)
|
if (!player)
|
||||||
return;
|
return;
|
||||||
|
|
@ -6564,6 +6532,10 @@ void K_drawKartHUD(void)
|
||||||
if (cv_kartdebugdistribution.value)
|
if (cv_kartdebugdistribution.value)
|
||||||
K_drawDistributionDebugger();
|
K_drawDistributionDebugger();
|
||||||
|
|
||||||
|
// temp debug
|
||||||
|
V_DrawSmallString(8, 2, V_SNAPTOTOP, va("Exp/Dist mult: %.2f", FixedToFloat(stplyr->exp)));
|
||||||
|
// V_DrawSmallString(8, 4, V_SNAPTOTOP, va("Exp/Dist mult: %.2f", FixedToFloat(stplyr->exp)));
|
||||||
|
|
||||||
if (cv_kartdebugnodes.value)
|
if (cv_kartdebugnodes.value)
|
||||||
{
|
{
|
||||||
UINT8 p;
|
UINT8 p;
|
||||||
|
|
|
||||||
|
|
@ -108,11 +108,13 @@ extern patch_t *kp_facenum[MAXPLAYERS+1];
|
||||||
extern patch_t *kp_unknownminimap;
|
extern patch_t *kp_unknownminimap;
|
||||||
|
|
||||||
void K_AddMessage(const char *msg, boolean interrupt, boolean persist);
|
void K_AddMessage(const char *msg, boolean interrupt, boolean persist);
|
||||||
void K_AddMessageForPlayer(player_t *player, const char *msg, boolean interrupt, boolean persist);
|
void K_AddMessageForPlayer(const player_t *player, const char *msg, boolean interrupt, boolean persist);
|
||||||
void K_ClearPersistentMessages(void);
|
void K_ClearPersistentMessages(void);
|
||||||
void K_ClearPersistentMessageForPlayer(player_t *player);
|
void K_ClearPersistentMessageForPlayer(player_t *player);
|
||||||
void K_TickMessages(void);
|
void K_TickMessages(void);
|
||||||
|
|
||||||
|
patch_t *K_GetSmallStaticCachedItemPatch(kartitems_t item);
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
PLAYERTAG_NONE,
|
PLAYERTAG_NONE,
|
||||||
|
|
|
||||||
62
src/k_kart.c
62
src/k_kart.c
|
|
@ -4007,8 +4007,10 @@ void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact)
|
||||||
if (gametyperules & GTR_SPHERES)
|
if (gametyperules & GTR_SPHERES)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Give that Sonic guy some help.
|
UINT16 scaledamps = min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10);
|
||||||
UINT16 scaledamps = min(amps, amps * (10 + player->kartspeed - player->kartweight) / 10);
|
|
||||||
|
if (player->position <= 1)
|
||||||
|
scaledamps /= 2;
|
||||||
|
|
||||||
for (int i = 0; i < (scaledamps/2); i++)
|
for (int i = 0; i < (scaledamps/2); i++)
|
||||||
{
|
{
|
||||||
|
|
@ -4052,6 +4054,13 @@ void K_AwardPlayerAmps(player_t *player, UINT8 amps)
|
||||||
|
|
||||||
if (player->rings <= 0 && player->ampspending == 0)
|
if (player->rings <= 0 && player->ampspending == 0)
|
||||||
{
|
{
|
||||||
|
// Auto Overdrive!
|
||||||
|
// If this is a fresh OD, give 'em some extra juice to make up for lack of flexibility.
|
||||||
|
if (!player->overdrive && player->mo && !P_MobjWasRemoved(player->mo))
|
||||||
|
{
|
||||||
|
S_StartSound(player->mo, sfx_gshac);
|
||||||
|
player->amps *= 2;
|
||||||
|
}
|
||||||
K_Overdrive(player);
|
K_Overdrive(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4091,7 +4100,7 @@ boolean K_Overdrive(player_t *player)
|
||||||
S_StartSound(player->mo, sfx_cdfm35);
|
S_StartSound(player->mo, sfx_cdfm35);
|
||||||
S_StartSound(player->mo, sfx_cdfm13);
|
S_StartSound(player->mo, sfx_cdfm13);
|
||||||
|
|
||||||
player->overdrive += (player->amps)*6;
|
player->overdrive += (player->amps)*5;
|
||||||
player->overshield += (player->amps)*2;
|
player->overshield += (player->amps)*2;
|
||||||
player->overdrivepower = FRACUNIT;
|
player->overdrivepower = FRACUNIT;
|
||||||
|
|
||||||
|
|
@ -4112,7 +4121,7 @@ boolean K_DefensiveOverdrive(player_t *player)
|
||||||
S_StartSound(player->mo, sfx_cdfm35);
|
S_StartSound(player->mo, sfx_cdfm35);
|
||||||
S_StartSound(player->mo, sfx_cdfm13);
|
S_StartSound(player->mo, sfx_cdfm13);
|
||||||
|
|
||||||
player->overdrive += (player->amps)*4;
|
player->overdrive += (player->amps)*3;
|
||||||
player->overshield += (player->amps)*2 + TICRATE*2;
|
player->overshield += (player->amps)*2 + TICRATE*2;
|
||||||
player->overdrivepower = FRACUNIT;
|
player->overdrivepower = FRACUNIT;
|
||||||
|
|
||||||
|
|
@ -7424,7 +7433,7 @@ SINT8 K_GetTotallyRandomResult(UINT8 useodds)
|
||||||
// Avoid calling K_FillItemRouletteData since that
|
// Avoid calling K_FillItemRouletteData since that
|
||||||
// function resets PR_ITEM_ROULETTE.
|
// function resets PR_ITEM_ROULETTE.
|
||||||
spawnchance[i] = (
|
spawnchance[i] = (
|
||||||
totalspawnchance += K_KartGetItemOdds(NULL, NULL, useodds, i)
|
totalspawnchance += K_KartGetBattleOdds(NULL, useodds, i)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -12712,6 +12721,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UINT32 behind = K_GetItemRouletteDistance(player, player->itemRoulette.playing);
|
UINT32 behind = K_GetItemRouletteDistance(player, player->itemRoulette.playing);
|
||||||
|
behind = FixedMul(behind, max(player->exp, FRACUNIT/2));
|
||||||
UINT32 behindMulti = behind / 500;
|
UINT32 behindMulti = behind / 500;
|
||||||
behindMulti = min(behindMulti, 60);
|
behindMulti = min(behindMulti, 60);
|
||||||
award = award * (behindMulti + 10) / 10;
|
award = award * (behindMulti + 10) / 10;
|
||||||
|
|
@ -12982,6 +12992,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
else
|
else
|
||||||
player->rocketsneakertimer -= 3*TICRATE;
|
player->rocketsneakertimer -= 3*TICRATE;
|
||||||
player->botvars.itemconfirm = 2*TICRATE;
|
player->botvars.itemconfirm = 2*TICRATE;
|
||||||
|
player->overshield += TICRATE/2; // TEMP prototype
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (player->itemamount == 0)
|
else if (player->itemamount == 0)
|
||||||
|
|
@ -12997,6 +13008,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
{
|
{
|
||||||
K_DoSneaker(player, 1);
|
K_DoSneaker(player, 1);
|
||||||
K_PlayBoostTaunt(player->mo);
|
K_PlayBoostTaunt(player->mo);
|
||||||
|
player->overshield += TICRATE/2; // TEMP prototype
|
||||||
|
player->sneakertimer += TICRATE; // TEMP prototype
|
||||||
player->itemamount--;
|
player->itemamount--;
|
||||||
player->botvars.itemconfirm = 0;
|
player->botvars.itemconfirm = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -14780,4 +14793,43 @@ boolean K_PlayerCanUseItem(player_t *player)
|
||||||
return (player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime);
|
return (player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fixed_t K_GetExpAdjustment(player_t *player)
|
||||||
|
{
|
||||||
|
fixed_t exp_power = 3*FRACUNIT/100; // adjust to change overall xp volatility
|
||||||
|
fixed_t exp_stablerate = 3*FRACUNIT/10; // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain
|
||||||
|
fixed_t result = 0;
|
||||||
|
|
||||||
|
INT32 live_players = 0;
|
||||||
|
|
||||||
|
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (!playeringame[i] || players[i].spectator || player == players+i)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
live_players++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (live_players < 8)
|
||||||
|
{
|
||||||
|
exp_power += (8 - live_players) * exp_power/4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase XP for each player you're beating...
|
||||||
|
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (!playeringame[i] || players[i].spectator || player == players+i)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (player->position < players[i].position)
|
||||||
|
result += exp_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...then take all of the XP you could possibly have earned,
|
||||||
|
// and lose it proportional to the stable rate. If you're below
|
||||||
|
// the stable threshold, this results in you losing XP.
|
||||||
|
result -= FixedMul(exp_power, FixedMul(live_players*FRACUNIT, FRACUNIT - exp_stablerate));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,8 @@ boolean K_ThunderDome(void);
|
||||||
|
|
||||||
boolean K_PlayerCanUseItem(player_t *player);
|
boolean K_PlayerCanUseItem(player_t *player);
|
||||||
|
|
||||||
|
fixed_t K_GetExpAdjustment(player_t *player);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -263,6 +263,9 @@ mobj_t *Obj_FindCheckpoint(INT32 id);
|
||||||
boolean Obj_GetCheckpointRespawnPosition(const mobj_t *checkpoint, vector3_t *return_pos);
|
boolean Obj_GetCheckpointRespawnPosition(const mobj_t *checkpoint, vector3_t *return_pos);
|
||||||
angle_t Obj_GetCheckpointRespawnAngle(const mobj_t *checkpoint);
|
angle_t Obj_GetCheckpointRespawnAngle(const mobj_t *checkpoint);
|
||||||
void Obj_ActivateCheckpointInstantly(mobj_t* mobj);
|
void Obj_ActivateCheckpointInstantly(mobj_t* mobj);
|
||||||
|
UINT32 Obj_GetCheckpointCount();
|
||||||
|
void Obj_ClearCheckpoints();
|
||||||
|
void Obj_DeactivateCheckpoints();
|
||||||
|
|
||||||
/* Rideroid / Rideroid Node */
|
/* Rideroid / Rideroid Node */
|
||||||
void Obj_RideroidThink(mobj_t *mo);
|
void Obj_RideroidThink(mobj_t *mo);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "byteptr.h"
|
#include "byteptr.h"
|
||||||
#include "k_race.h"
|
#include "k_race.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "k_objects.h"
|
||||||
|
|
||||||
// I was ALMOST tempted to start tearing apart all
|
// I was ALMOST tempted to start tearing apart all
|
||||||
// of the map loading code and turning it into C++
|
// of the map loading code and turning it into C++
|
||||||
|
|
@ -510,7 +511,8 @@ void gpRank_t::Update(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
lvl->time = UINT32_MAX;
|
lvl->time = UINT32_MAX;
|
||||||
lvl->totalLapPoints = K_RaceLapCount(gamemap - 1) * 2;
|
|
||||||
|
lvl->totalLapPoints = ( K_RaceLapCount(gamemap - 1) + Obj_GetCheckpointCount() )* 2;
|
||||||
lvl->totalPrisons = maptargets;
|
lvl->totalPrisons = maptargets;
|
||||||
|
|
||||||
UINT8 i;
|
UINT8 i;
|
||||||
|
|
|
||||||
1078
src/k_roulette.c
1078
src/k_roulette.c
File diff suppressed because it is too large
Load diff
|
|
@ -78,17 +78,14 @@ botItemPriority_e K_GetBotItemPriority(kartitems_t result);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item);
|
INT32 K_KartGetBattleOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item);
|
||||||
|
|
||||||
Gets the frequency an item should show up in
|
Gets legacy item priority.
|
||||||
an item bracket, and adjusted for special
|
Currently used only for Battle monitors/spawners.
|
||||||
factors (such as Frantic Items).
|
|
||||||
|
|
||||||
Input Arguments:-
|
Input Arguments:-
|
||||||
player - The player we intend to give the item to later.
|
player - The player we intend to give the item to later.
|
||||||
Can be NULL for generic use.
|
Can be NULL for generic use.
|
||||||
roulette - The roulette data that we intend to
|
|
||||||
insert this item into.
|
|
||||||
pos - The item bracket we are in.
|
pos - The item bracket we are in.
|
||||||
item - The item to give.
|
item - The item to give.
|
||||||
|
|
||||||
|
|
@ -97,11 +94,11 @@ botItemPriority_e K_GetBotItemPriority(kartitems_t result);
|
||||||
into the roulette.
|
into the roulette.
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
|
|
||||||
INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item);
|
INT32 K_KartGetBattleOdds(const player_t *player, UINT8 pos, kartitems_t item);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox);
|
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun);
|
||||||
|
|
||||||
Fills out the item roulette struct when it is
|
Fills out the item roulette struct when it is
|
||||||
initially created. This function needs to be
|
initially created. This function needs to be
|
||||||
|
|
@ -113,12 +110,13 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
||||||
Can be NULL for generic use.
|
Can be NULL for generic use.
|
||||||
roulette - The roulette data struct to fill out.
|
roulette - The roulette data struct to fill out.
|
||||||
ringbox - Is this roulette fill triggered by a just-respawned Ring Box?
|
ringbox - Is this roulette fill triggered by a just-respawned Ring Box?
|
||||||
|
dryrun - Are we calling this from the distribution debugger? Don't call RNG or write roulette data!
|
||||||
|
|
||||||
Return:-
|
Return:-
|
||||||
N/A
|
N/A
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
|
|
||||||
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox);
|
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette, boolean ringbox, boolean dryrun);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include "r_fps.h"
|
#include "r_fps.h"
|
||||||
#include "g_party.h"
|
#include "g_party.h"
|
||||||
#include "g_input.h"
|
#include "g_input.h"
|
||||||
|
#include "k_objects.h"
|
||||||
|
|
||||||
boolean level_tally_t::UseBonuses(void)
|
boolean level_tally_t::UseBonuses(void)
|
||||||
{
|
{
|
||||||
|
|
@ -343,7 +344,7 @@ void level_tally_t::Init(player_t *player)
|
||||||
if ((gametypes[gt]->rules & GTR_CIRCUIT) == GTR_CIRCUIT)
|
if ((gametypes[gt]->rules & GTR_CIRCUIT) == GTR_CIRCUIT)
|
||||||
{
|
{
|
||||||
laps = player->lapPoints;
|
laps = player->lapPoints;
|
||||||
totalLaps = numlaps;
|
totalLaps = numlaps + numlaps * Obj_GetCheckpointCount();
|
||||||
|
|
||||||
if (inDuel == false)
|
if (inDuel == false)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ struct MobjList
|
||||||
{
|
{
|
||||||
ptr->next(front());
|
ptr->next(front());
|
||||||
front(ptr);
|
front(ptr);
|
||||||
|
count_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(T* node)
|
void erase(T* node)
|
||||||
|
|
@ -45,6 +46,7 @@ struct MobjList
|
||||||
{
|
{
|
||||||
front(node->next());
|
front(node->next());
|
||||||
node->next(nullptr);
|
node->next(nullptr);
|
||||||
|
count_--;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,6 +71,7 @@ struct MobjList
|
||||||
{
|
{
|
||||||
prev->next(node->next());
|
prev->next(node->next());
|
||||||
node->next(nullptr);
|
node->next(nullptr);
|
||||||
|
count_--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -77,9 +80,12 @@ struct MobjList
|
||||||
auto begin() const { return view().begin(); }
|
auto begin() const { return view().begin(); }
|
||||||
auto end() const { return view().end(); }
|
auto end() const { return view().end(); }
|
||||||
|
|
||||||
|
auto count() { return count_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void front(T* ptr) { Mobj::ManagedPtr {Head} = ptr; }
|
void front(T* ptr) { Mobj::ManagedPtr {Head} = ptr; }
|
||||||
auto view() const { return MobjListView(front(), [](T* node) { return node->next(); }); }
|
auto view() const { return MobjListView(front(), [](T* node) { return node->next(); }); }
|
||||||
|
UINT32 count_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace srb2
|
}; // namespace srb2
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ void Obj_AmpsThink (mobj_t *amps)
|
||||||
|
|
||||||
amps->extravalue2++;
|
amps->extravalue2++;
|
||||||
|
|
||||||
speed += amps->extravalue1 * amps->scale/2;
|
speed += amps->extravalue2 * amps->scale/2;
|
||||||
|
|
||||||
fakez = mo->z + (vert * amps->extravalue1 / AMP_ARCTIME);
|
fakez = mo->z + (vert * amps->extravalue1 / AMP_ARCTIME);
|
||||||
damper = 1;
|
damper = 1;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include "../doomdef.h"
|
#include "../doomdef.h"
|
||||||
#include "../doomtype.h"
|
#include "../doomtype.h"
|
||||||
#include "../info.h"
|
#include "../info.h"
|
||||||
|
#include "../g_game.h"
|
||||||
#include "../k_color.h"
|
#include "../k_color.h"
|
||||||
#include "../k_kart.h"
|
#include "../k_kart.h"
|
||||||
#include "../k_objects.h"
|
#include "../k_objects.h"
|
||||||
|
|
@ -34,9 +35,17 @@
|
||||||
#include "../sounds.h"
|
#include "../sounds.h"
|
||||||
#include "../tables.h"
|
#include "../tables.h"
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
using std::pair;
|
||||||
|
using std::min;
|
||||||
|
using std::max;
|
||||||
|
using std::clamp;
|
||||||
|
|
||||||
extern mobj_t* svg_checkpoints;
|
extern mobj_t* svg_checkpoints;
|
||||||
|
|
||||||
#define checkpoint_id(o) ((o)->thing_args[0])
|
#define checkpoint_id(o) ((o)->thing_args[0])
|
||||||
|
#define checkpoint_linetag(o) ((o)->thing_args[1])
|
||||||
|
#define checkpoint_extralength(o) ((o)->thing_args[2])
|
||||||
#define checkpoint_other(o) ((o)->target)
|
#define checkpoint_other(o) ((o)->target)
|
||||||
#define checkpoint_orb(o) ((o)->tracer)
|
#define checkpoint_orb(o) ((o)->tracer)
|
||||||
#define checkpoint_arm(o) ((o)->hnext)
|
#define checkpoint_arm(o) ((o)->hnext)
|
||||||
|
|
@ -51,12 +60,14 @@ namespace
|
||||||
|
|
||||||
struct LineOnDemand : line_t
|
struct LineOnDemand : line_t
|
||||||
{
|
{
|
||||||
|
LineOnDemand(const line_t* line) {}
|
||||||
|
|
||||||
LineOnDemand(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) :
|
LineOnDemand(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) :
|
||||||
line_t {
|
line_t {
|
||||||
.v1 = &v1_data_,
|
.v1 = &v1_data_,
|
||||||
.dx = x2 - x1,
|
.dx = x2 - x1,
|
||||||
.dy = y2 - y1,
|
.dy = y2 - y1,
|
||||||
.bbox = {std::max(y1, y2), std::min(y1, y2), std::min(x1, x2), std::max(x1, x2)},
|
.bbox = {max(y1, y2), min(y1, y2), min(x1, x2), max(x1, x2)},
|
||||||
},
|
},
|
||||||
v1_data_ {.x = x1, .y = y1}
|
v1_data_ {.x = x1, .y = y1}
|
||||||
{
|
{
|
||||||
|
|
@ -76,6 +87,12 @@ struct LineOnDemand : line_t
|
||||||
bbox[BOXLEFT] <= other.bbox[BOXRIGHT] && bbox[BOXRIGHT] >= other.bbox[BOXLEFT];
|
bbox[BOXLEFT] <= other.bbox[BOXRIGHT] && bbox[BOXRIGHT] >= other.bbox[BOXLEFT];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool overlaps(const line_t& other) const
|
||||||
|
{
|
||||||
|
return bbox[BOXTOP] >= other.bbox[BOXBOTTOM] && bbox[BOXBOTTOM] <= other.bbox[BOXTOP] &&
|
||||||
|
bbox[BOXLEFT] <= other.bbox[BOXRIGHT] && bbox[BOXRIGHT] >= other.bbox[BOXLEFT];
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vertex_t v1_data_;
|
vertex_t v1_data_;
|
||||||
};
|
};
|
||||||
|
|
@ -170,6 +187,30 @@ struct Checkpoint : mobj_t
|
||||||
deactivate();
|
deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// will not work properly after a player enters intoa new lap
|
||||||
|
INT32 players_passed()
|
||||||
|
{
|
||||||
|
INT32 pcount = 0;
|
||||||
|
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (playeringame[i] && !players[i].spectator && players[i].checkpointId >= id())
|
||||||
|
pcount++;
|
||||||
|
}
|
||||||
|
return pcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean top_half_has_passed()
|
||||||
|
{
|
||||||
|
INT32 pcount = 0;
|
||||||
|
INT32 winningpos = 1;
|
||||||
|
|
||||||
|
INT32 nump = D_NumPlayersInRace();
|
||||||
|
winningpos = nump / 2;
|
||||||
|
winningpos += nump % 2;
|
||||||
|
|
||||||
|
return players_passed() >= winningpos;
|
||||||
|
}
|
||||||
|
|
||||||
void animate()
|
void animate()
|
||||||
{
|
{
|
||||||
orient();
|
orient();
|
||||||
|
|
@ -181,10 +222,11 @@ struct Checkpoint : mobj_t
|
||||||
|
|
||||||
if (!clip_var())
|
if (!clip_var())
|
||||||
{
|
{
|
||||||
speed(speed() - FixedDiv(speed() / 50, std::max<fixed_t>(speed_multiplier(), 1)));
|
speed(speed() - FixedDiv(speed() / 50, max<fixed_t>(speed_multiplier(), 1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!activated())
|
|
||||||
|
if (!top_half_has_passed())
|
||||||
{
|
{
|
||||||
sparkle_between(0);
|
sparkle_between(0);
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +235,7 @@ struct Checkpoint : mobj_t
|
||||||
void twirl(angle_t dir, fixed_t multiplier)
|
void twirl(angle_t dir, fixed_t multiplier)
|
||||||
{
|
{
|
||||||
var(0);
|
var(0);
|
||||||
speed_multiplier(std::clamp(multiplier, kMinSpeedMultiplier, kMaxSpeedMultiplier));
|
speed_multiplier(clamp(multiplier, kMinSpeedMultiplier, kMaxSpeedMultiplier));
|
||||||
speed(FixedDiv(kBaseSpeed, speed_multiplier()));
|
speed(FixedDiv(kBaseSpeed, speed_multiplier()));
|
||||||
reverse(AngleDeltaSigned(angle_to_other(), dir) > 0);
|
reverse(AngleDeltaSigned(angle_to_other(), dir) > 0);
|
||||||
|
|
||||||
|
|
@ -266,7 +308,7 @@ private:
|
||||||
kMinPivotDelay
|
kMinPivotDelay
|
||||||
);
|
);
|
||||||
|
|
||||||
return to_angle(FixedDiv(std::max(var(), pos) - pos, FRACUNIT - pos)) / 4;
|
return to_angle(FixedDiv(max(var(), pos) - pos, FRACUNIT - pos)) / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void orient()
|
void orient()
|
||||||
|
|
@ -304,7 +346,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void spawn_sparkle(const vector3_t& pos, fixed_t xy_momentum, fixed_t z_momentum, angle_t dir)
|
void spawn_sparkle(const vector3_t& pos, fixed_t xy_momentum, fixed_t z_momentum, angle_t dir, skincolornum_t color = SKINCOLOR_ULTRAMARINE)
|
||||||
{
|
{
|
||||||
auto rng = [=](int units) { return P_RandomRange(PR_DECORATION, -(units) * scale, +(units) * scale); };
|
auto rng = [=](int units) { return P_RandomRange(PR_DECORATION, -(units) * scale, +(units) * scale); };
|
||||||
|
|
||||||
|
|
@ -324,10 +366,10 @@ private:
|
||||||
if (xy_momentum)
|
if (xy_momentum)
|
||||||
{
|
{
|
||||||
P_Thrust(p, dir, xy_momentum);
|
P_Thrust(p, dir, xy_momentum);
|
||||||
p->momz = P_RandomKey(PR_DECORATION, std::max<fixed_t>(z_momentum, 1));
|
p->momz = P_RandomKey(PR_DECORATION, max<fixed_t>(z_momentum, 1));
|
||||||
p->destscale = 0;
|
p->destscale = 0;
|
||||||
p->scalespeed = p->scale / 35;
|
p->scalespeed = p->scale / 35;
|
||||||
p->color = SKINCOLOR_ULTRAMARINE;
|
p->color = color;
|
||||||
p->fuse = 0;
|
p->fuse = 0;
|
||||||
|
|
||||||
// Something lags at the start of the level. The
|
// Something lags at the start of the level. The
|
||||||
|
|
@ -342,7 +384,7 @@ private:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p->color = K_RainbowColor(leveltime);
|
p->color = color;
|
||||||
p->fuse = 2;
|
p->fuse = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -369,7 +411,8 @@ private:
|
||||||
{x + FixedMul(ofs, FCOS(a)), y + FixedMul(ofs, FSIN(a)), z + (kSparkleZ * scale)},
|
{x + FixedMul(ofs, FCOS(a)), y + FixedMul(ofs, FSIN(a)), z + (kSparkleZ * scale)},
|
||||||
momentum,
|
momentum,
|
||||||
momentum / 2,
|
momentum / 2,
|
||||||
dir
|
dir,
|
||||||
|
activated() ? SKINCOLOR_GREEN : SKINCOLOR_ULTRAMARINE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -402,25 +445,41 @@ struct CheckpointManager
|
||||||
auto begin() { return list_.begin(); }
|
auto begin() { return list_.begin(); }
|
||||||
auto end() { return list_.end(); }
|
auto end() { return list_.end(); }
|
||||||
|
|
||||||
auto find(INT32 id) { return std::find_if(begin(), end(), [id](Checkpoint* chk) { return chk->id() == id; }); }
|
auto find_checkpoint(INT32 id) {
|
||||||
|
auto it = find_if(list_.begin(), list_.end(), [id](auto pair) { return pair.first->id() == id; });
|
||||||
|
if (it != list_.end())
|
||||||
|
{
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
return static_cast<Checkpoint*>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void push_front(Checkpoint* chk) { list_.push_front(chk); }
|
// auto find_pair(Checkpoint* chk) {
|
||||||
|
// pair<Checkpoint*, vector<line_t*>> retpair;
|
||||||
|
// auto it = find_if(list_.begin(), list_.end(), [chk](auto pair) { return pair.first == chk; });
|
||||||
|
// if (it != list_.end())
|
||||||
|
// {
|
||||||
|
// retpair = *it;
|
||||||
|
// return retpair;
|
||||||
|
// }
|
||||||
|
// return static_cast<pair<Checkpoint*, vector<line_t*>>>(nullptr);
|
||||||
|
// }
|
||||||
|
|
||||||
void erase(Checkpoint* chk) { list_.erase(chk); }
|
void remove_checkpoint(mobj_t* end)
|
||||||
|
{
|
||||||
private:
|
|
||||||
srb2::MobjList<Checkpoint, svg_checkpoints> list_;
|
|
||||||
};
|
|
||||||
|
|
||||||
CheckpointManager g_checkpoints;
|
|
||||||
|
|
||||||
}; // namespace
|
|
||||||
|
|
||||||
void Obj_LinkCheckpoint(mobj_t* end)
|
|
||||||
{
|
|
||||||
auto chk = static_cast<Checkpoint*>(end);
|
auto chk = static_cast<Checkpoint*>(end);
|
||||||
|
auto it = find_if(list_.begin(), list_.end(), [&](auto pair) { return pair.first == chk; });
|
||||||
|
if (it != list_.end())
|
||||||
|
{
|
||||||
|
list_.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (chk->spawnpoint && chk->id() == 0)
|
void link_checkpoint(mobj_t* end)
|
||||||
|
{
|
||||||
|
auto chk = static_cast<Checkpoint*>(end);
|
||||||
|
auto id = chk->id();
|
||||||
|
if (chk->spawnpoint && id == 0)
|
||||||
{
|
{
|
||||||
auto msg = fmt::format(
|
auto msg = fmt::format(
|
||||||
"Checkpoint thing (index #{}, thing type {}) has an invalid ID! ID must not be 0.\n",
|
"Checkpoint thing (index #{}, thing type {}) has an invalid ID! ID must not be 0.\n",
|
||||||
|
|
@ -431,10 +490,8 @@ void Obj_LinkCheckpoint(mobj_t* end)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto it = g_checkpoints.find(chk->id()); it != g_checkpoints.end())
|
if (auto other = find_checkpoint(id))
|
||||||
{
|
{
|
||||||
Checkpoint* other = *it;
|
|
||||||
|
|
||||||
if (chk->spawnpoint && other->spawnpoint && chk->spawnpoint->angle != other->spawnpoint->angle)
|
if (chk->spawnpoint && other->spawnpoint && chk->spawnpoint->angle != other->spawnpoint->angle)
|
||||||
{
|
{
|
||||||
auto msg = fmt::format(
|
auto msg = fmt::format(
|
||||||
|
|
@ -447,25 +504,51 @@ void Obj_LinkCheckpoint(mobj_t* end)
|
||||||
CONS_Alert(CONS_WARNING, "%s", msg.c_str());
|
CONS_Alert(CONS_WARNING, "%s", msg.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
other->other(chk);
|
other->other(chk);
|
||||||
chk->other(other);
|
chk->other(other);
|
||||||
}
|
}
|
||||||
else
|
else // Checkpoint isn't in the list, find any associated tagged lines and make the pair
|
||||||
{
|
{
|
||||||
g_checkpoints.push_front(chk);
|
vector<line_t*> checklines;
|
||||||
|
if (checkpoint_linetag(chk))
|
||||||
|
{
|
||||||
|
INT32 li;
|
||||||
|
INT32 tag = checkpoint_linetag(chk);
|
||||||
|
TAG_ITER_LINES(tag, li)
|
||||||
|
{
|
||||||
|
line_t* line = lines + li;
|
||||||
|
checklines.push_back(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_.emplace_back(chk, move(checklines));
|
||||||
}
|
}
|
||||||
|
|
||||||
chk->gingerbread();
|
chk->gingerbread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() { list_.clear(); }
|
||||||
|
|
||||||
|
auto count() { return list_.size(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<pair<Checkpoint*, vector<line_t*>>> list_;
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckpointManager g_checkpoints;
|
||||||
|
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
void Obj_LinkCheckpoint(mobj_t* end)
|
||||||
|
{
|
||||||
|
g_checkpoints.link_checkpoint(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Obj_UnlinkCheckpoint(mobj_t* end)
|
void Obj_UnlinkCheckpoint(mobj_t* end)
|
||||||
{
|
{
|
||||||
auto chk = static_cast<Checkpoint*>(end);
|
auto chk = static_cast<Checkpoint*>(end);
|
||||||
|
g_checkpoints.remove_checkpoint(end);
|
||||||
g_checkpoints.erase(chk);
|
|
||||||
|
|
||||||
P_RemoveMobj(chk->orb());
|
P_RemoveMobj(chk->orb());
|
||||||
|
P_RemoveMobj(chk->arm());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Obj_CheckpointThink(mobj_t* end)
|
void Obj_CheckpointThink(mobj_t* end)
|
||||||
|
|
@ -480,39 +563,64 @@ void Obj_CheckpointThink(mobj_t* end)
|
||||||
chk->animate();
|
chk->animate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y)
|
void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y)
|
||||||
{
|
{
|
||||||
LineOnDemand ray(old_x, old_y, player->mo->x, player->mo->y, player->mo->radius);
|
LineOnDemand ray(old_x, old_y, player->mo->x, player->mo->y, player->mo->radius);
|
||||||
|
|
||||||
auto it = std::find_if(
|
auto it = find_if(
|
||||||
g_checkpoints.begin(),
|
g_checkpoints.begin(),
|
||||||
g_checkpoints.end(),
|
g_checkpoints.end(),
|
||||||
[&](const Checkpoint* chk)
|
[&](auto chkpair)
|
||||||
{
|
{
|
||||||
|
Checkpoint* chk = chkpair.first;
|
||||||
if (!chk->valid())
|
if (!chk->valid())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LineOnDemand gate = chk->crossing_line();
|
LineOnDemand* gate;
|
||||||
|
|
||||||
|
if (chkpair.second.empty())
|
||||||
|
{
|
||||||
|
LineOnDemand dyngate = chk->crossing_line();
|
||||||
|
if (!ray.overlaps(dyngate))
|
||||||
|
return false;
|
||||||
|
gate = &dyngate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto it = find_if(
|
||||||
|
chkpair.second.begin(),
|
||||||
|
chkpair.second.end(),
|
||||||
|
[&](const line_t* line)
|
||||||
|
{
|
||||||
|
return ray.overlaps(*line);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (it == chkpair.second.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_t* line = *it;
|
||||||
|
gate = static_cast<LineOnDemand*>(line);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the bounding boxes of the two lines
|
// Check if the bounding boxes of the two lines
|
||||||
// overlap. This relies on the player movement not
|
// overlap. This relies on the player movement not
|
||||||
// being so large that it creates an oversized box,
|
// being so large that it creates an oversized box,
|
||||||
// but thankfully that doesn't seem to happen, under
|
// but thankfully that doesn't seem to happen, under
|
||||||
// normal circumstances.
|
// normal circumstances.
|
||||||
if (!ray.overlaps(gate))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
INT32 side = P_PointOnLineSide(player->mo->x, player->mo->y, &gate);
|
INT32 side = P_PointOnLineSide(player->mo->x, player->mo->y, gate);
|
||||||
INT32 oldside = P_PointOnLineSide(old_x, old_y, &gate);
|
INT32 oldside = P_PointOnLineSide(old_x, old_y, gate);
|
||||||
|
|
||||||
if (side == oldside)
|
if (side == oldside)
|
||||||
{
|
{
|
||||||
// Did not cross.
|
// Did not cross.
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -524,41 +632,58 @@ void Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Checkpoint* chk = *it;
|
Checkpoint* chk = it->first;
|
||||||
|
|
||||||
if (chk->activated())
|
if (player->checkpointId == chk->id())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Checkpoint* chk : g_checkpoints)
|
if (player->position <= 1)
|
||||||
{
|
{
|
||||||
|
angle_t direction = R_PointToAngle2(old_x, old_y, player->mo->x, player->mo->y);
|
||||||
|
fixed_t speed_multiplier = FixedDiv(player->speed, K_GetKartSpeed(player, false, false));
|
||||||
|
chk->twirl(direction, speed_multiplier);
|
||||||
|
chk->other()->twirl(direction, speed_multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gametyperules & GTR_CHECKPOINTS)
|
||||||
|
{
|
||||||
|
for (auto chkpair : g_checkpoints)
|
||||||
|
{
|
||||||
|
Checkpoint* chk = chkpair.first;
|
||||||
if (chk->valid())
|
if (chk->valid())
|
||||||
{
|
{
|
||||||
// Swing down any previously passed checkpoints.
|
|
||||||
// TODO: this could look weird in multiplayer if
|
|
||||||
// other players cross different checkpoints.
|
|
||||||
chk->untwirl();
|
chk->untwirl();
|
||||||
chk->other()->untwirl();
|
chk->other()->untwirl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
angle_t direction = R_PointToAngle2(old_x, old_y, player->mo->x, player->mo->y);
|
|
||||||
fixed_t speed_multiplier = FixedDiv(player->speed, K_GetKartSpeed(player, false, false));
|
|
||||||
|
|
||||||
chk->twirl(direction, speed_multiplier);
|
|
||||||
chk->other()->twirl(direction, speed_multiplier);
|
|
||||||
|
|
||||||
S_StartSound(player->mo, sfx_s3k63);
|
S_StartSound(player->mo, sfx_s3k63);
|
||||||
|
|
||||||
player->checkpointId = chk->id();
|
player->checkpointId = chk->id();
|
||||||
|
|
||||||
|
if (D_NumPlayersInRace() > 1 && !K_IsPlayerLosing(player))
|
||||||
|
{
|
||||||
|
if (player->position == 1)
|
||||||
|
{
|
||||||
|
player->lapPoints += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player->lapPoints += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player->exp += K_GetExpAdjustment(player);
|
||||||
|
|
||||||
|
K_UpdatePowerLevels(player, player->laps, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
mobj_t *Obj_FindCheckpoint(INT32 id)
|
mobj_t* Obj_FindCheckpoint(INT32 id)
|
||||||
{
|
{
|
||||||
auto it = g_checkpoints.find(id);
|
return g_checkpoints.find_checkpoint(id);
|
||||||
|
|
||||||
return it != g_checkpoints.end() ? *it : nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean Obj_GetCheckpointRespawnPosition(const mobj_t* mobj, vector3_t* return_pos)
|
boolean Obj_GetCheckpointRespawnPosition(const mobj_t* mobj, vector3_t* return_pos)
|
||||||
|
|
@ -593,3 +718,27 @@ void Obj_ActivateCheckpointInstantly(mobj_t* mobj)
|
||||||
chk->other()->activate();
|
chk->other()->activate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a count of checkpoint gates, not objects
|
||||||
|
UINT32 Obj_GetCheckpointCount()
|
||||||
|
{
|
||||||
|
return g_checkpoints.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Obj_ClearCheckpoints()
|
||||||
|
{
|
||||||
|
g_checkpoints.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Obj_DeactivateCheckpoints()
|
||||||
|
{
|
||||||
|
for (auto chkpair : g_checkpoints)
|
||||||
|
{
|
||||||
|
Checkpoint* chk = chkpair.first;
|
||||||
|
if (chk->valid())
|
||||||
|
{
|
||||||
|
chk->untwirl();
|
||||||
|
chk->other()->untwirl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3092,11 +3092,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
||||||
{
|
{
|
||||||
K_DoPowerClash(target, inflictor);
|
K_DoPowerClash(target, inflictor);
|
||||||
|
|
||||||
if (inflictor->type != MT_PLAYER)
|
|
||||||
{
|
|
||||||
K_SpawnAmps(player, 5, inflictor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inflictor->type == MT_SUPER_FLICKY)
|
if (inflictor->type == MT_SUPER_FLICKY)
|
||||||
{
|
{
|
||||||
Obj_BlockSuperFlicky(inflictor);
|
Obj_BlockSuperFlicky(inflictor);
|
||||||
|
|
@ -3565,4 +3560,6 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
|
||||||
{
|
{
|
||||||
P_FlingBurst(player, fa, MT_DEBTSPIKE, 0, 3 * FRACUNIT / 2, i++);
|
P_FlingBurst(player, fa, MT_DEBTSPIKE, 0, 3 * FRACUNIT / 2, i++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
K_DefensiveOverdrive(player);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12572,8 +12572,6 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case MT_CHECKPOINT_END:
|
case MT_CHECKPOINT_END:
|
||||||
if (!(gametyperules & GTR_CHECKPOINTS))
|
|
||||||
return false;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
||||||
WRITEUINT8(save->p, players[i].laps);
|
WRITEUINT8(save->p, players[i].laps);
|
||||||
WRITEUINT8(save->p, players[i].latestlap);
|
WRITEUINT8(save->p, players[i].latestlap);
|
||||||
WRITEUINT32(save->p, players[i].lapPoints);
|
WRITEUINT32(save->p, players[i].lapPoints);
|
||||||
|
WRITEINT32(save->p, players[i].exp);
|
||||||
WRITEINT32(save->p, players[i].cheatchecknum);
|
WRITEINT32(save->p, players[i].cheatchecknum);
|
||||||
WRITEINT32(save->p, players[i].checkpointId);
|
WRITEINT32(save->p, players[i].checkpointId);
|
||||||
|
|
||||||
|
|
@ -743,7 +744,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WRITEUINT8(save->p, players[i].itemRoulette.useOdds);
|
WRITEUINT32(save->p, players[i].itemRoulette.preexpdist);
|
||||||
WRITEUINT32(save->p, players[i].itemRoulette.dist);
|
WRITEUINT32(save->p, players[i].itemRoulette.dist);
|
||||||
WRITEUINT32(save->p, players[i].itemRoulette.index);
|
WRITEUINT32(save->p, players[i].itemRoulette.index);
|
||||||
WRITEUINT8(save->p, players[i].itemRoulette.sound);
|
WRITEUINT8(save->p, players[i].itemRoulette.sound);
|
||||||
|
|
@ -937,6 +938,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
||||||
players[i].laps = READUINT8(save->p); // Number of laps (optional)
|
players[i].laps = READUINT8(save->p); // Number of laps (optional)
|
||||||
players[i].latestlap = READUINT8(save->p);
|
players[i].latestlap = READUINT8(save->p);
|
||||||
players[i].lapPoints = READUINT32(save->p);
|
players[i].lapPoints = READUINT32(save->p);
|
||||||
|
players[i].exp = READINT32(save->p);
|
||||||
players[i].cheatchecknum = READINT32(save->p);
|
players[i].cheatchecknum = READINT32(save->p);
|
||||||
players[i].checkpointId = READINT32(save->p);
|
players[i].checkpointId = READINT32(save->p);
|
||||||
|
|
||||||
|
|
@ -1366,7 +1368,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
players[i].itemRoulette.useOdds = READUINT8(save->p);
|
players[i].itemRoulette.preexpdist = READUINT32(save->p);
|
||||||
players[i].itemRoulette.dist = READUINT32(save->p);
|
players[i].itemRoulette.dist = READUINT32(save->p);
|
||||||
players[i].itemRoulette.index = (size_t)READUINT32(save->p);
|
players[i].itemRoulette.index = (size_t)READUINT32(save->p);
|
||||||
players[i].itemRoulette.sound = READUINT8(save->p);
|
players[i].itemRoulette.sound = READUINT8(save->p);
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@
|
||||||
#include "k_hud.h" // K_ClearPersistentMessages
|
#include "k_hud.h" // K_ClearPersistentMessages
|
||||||
#include "k_endcam.h"
|
#include "k_endcam.h"
|
||||||
#include "k_credits.h"
|
#include "k_credits.h"
|
||||||
|
#include "k_objects.h"
|
||||||
|
|
||||||
// Replay names have time
|
// Replay names have time
|
||||||
#if !defined (UNDER_CE)
|
#if !defined (UNDER_CE)
|
||||||
|
|
@ -8586,6 +8587,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
||||||
|
|
||||||
LUA_InvalidateLevel();
|
LUA_InvalidateLevel();
|
||||||
|
|
||||||
|
Obj_ClearCheckpoints();
|
||||||
|
|
||||||
for (ss = sectors; sectors+numsectors != ss; ss++)
|
for (ss = sectors; sectors+numsectors != ss; ss++)
|
||||||
{
|
{
|
||||||
Z_Free(ss->attached);
|
Z_Free(ss->attached);
|
||||||
|
|
|
||||||
|
|
@ -2117,6 +2117,14 @@ static void K_HandleLapIncrement(player_t *player)
|
||||||
player->lapPoints++;
|
player->lapPoints++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
player->exp += K_GetExpAdjustment(player);
|
||||||
|
|
||||||
|
if (player->position == 1 && !(gametyperules & GTR_CHECKPOINTS))
|
||||||
|
{
|
||||||
|
Obj_DeactivateCheckpoints();
|
||||||
|
}
|
||||||
|
player->checkpointId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up lap animation vars
|
// Set up lap animation vars
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue