mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'retune-weak-bots' into 'master'
Foes Closes #1582 See merge request kart-krew-dev/ring-racers-internal!2713
This commit is contained in:
commit
ad9501203f
11 changed files with 223 additions and 115 deletions
|
|
@ -418,6 +418,7 @@ struct botvars_t
|
||||||
UINT8 difficulty; // Bot's difficulty setting
|
UINT8 difficulty; // Bot's difficulty setting
|
||||||
INT16 diffincrease; // In GP: bot difficulty will increase this much next round
|
INT16 diffincrease; // In GP: bot difficulty will increase this much next round
|
||||||
boolean rival; // If true, they're the GP rival
|
boolean rival; // If true, they're the GP rival
|
||||||
|
boolean foe; // If true, in contention for top X
|
||||||
|
|
||||||
// All entries above persist between rounds and must be recorded in demos
|
// All entries above persist between rounds and must be recorded in demos
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,7 @@ void G_ReadDemoExtraData(void)
|
||||||
players[p].botvars.difficulty = READUINT8(demobuf.p);
|
players[p].botvars.difficulty = READUINT8(demobuf.p);
|
||||||
players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic
|
players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic
|
||||||
players[p].botvars.rival = (boolean)READUINT8(demobuf.p);
|
players[p].botvars.rival = (boolean)READUINT8(demobuf.p);
|
||||||
|
players[p].botvars.foe = (boolean)READUINT8(demobuf.p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (extradata & DXD_PLAYSTATE)
|
if (extradata & DXD_PLAYSTATE)
|
||||||
|
|
@ -497,6 +498,7 @@ void G_WriteDemoExtraData(void)
|
||||||
WRITEUINT8(demobuf.p, players[i].botvars.difficulty);
|
WRITEUINT8(demobuf.p, players[i].botvars.difficulty);
|
||||||
WRITEINT16(demobuf.p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic
|
WRITEINT16(demobuf.p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic
|
||||||
WRITEUINT8(demobuf.p, (UINT8)players[i].botvars.rival);
|
WRITEUINT8(demobuf.p, (UINT8)players[i].botvars.rival);
|
||||||
|
WRITEUINT8(demobuf.p, (UINT8)players[i].botvars.foe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (demo_extradata[i] & DXD_PLAYSTATE)
|
if (demo_extradata[i] & DXD_PLAYSTATE)
|
||||||
|
|
@ -2111,6 +2113,7 @@ void G_BeginRecording(void)
|
||||||
WRITEUINT8(demobuf.p, player->botvars.difficulty);
|
WRITEUINT8(demobuf.p, player->botvars.difficulty);
|
||||||
WRITEINT16(demobuf.p, player->botvars.diffincrease); // needed to avoid having to duplicate logic
|
WRITEINT16(demobuf.p, player->botvars.diffincrease); // needed to avoid having to duplicate logic
|
||||||
WRITEUINT8(demobuf.p, (UINT8)player->botvars.rival);
|
WRITEUINT8(demobuf.p, (UINT8)player->botvars.rival);
|
||||||
|
WRITEUINT8(demobuf.p, (UINT8)player->botvars.foe);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
|
|
@ -3222,6 +3225,7 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
|
||||||
players[p].botvars.difficulty = READUINT8(demobuf.p);
|
players[p].botvars.difficulty = READUINT8(demobuf.p);
|
||||||
players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic
|
players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic
|
||||||
players[p].botvars.rival = (boolean)READUINT8(demobuf.p);
|
players[p].botvars.rival = (boolean)READUINT8(demobuf.p);
|
||||||
|
players[p].botvars.foe = (boolean)READUINT8(demobuf.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
K_UpdateShrinkCheat(&players[p]);
|
K_UpdateShrinkCheat(&players[p]);
|
||||||
|
|
|
||||||
|
|
@ -2271,6 +2271,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
|
|
||||||
INT16 botdiffincrease;
|
INT16 botdiffincrease;
|
||||||
boolean botrival;
|
boolean botrival;
|
||||||
|
boolean botfoe;
|
||||||
|
|
||||||
boolean cangrabitems;
|
boolean cangrabitems;
|
||||||
|
|
||||||
|
|
@ -2381,6 +2382,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
|
|
||||||
botdiffincrease = players[player].botvars.diffincrease;
|
botdiffincrease = players[player].botvars.diffincrease;
|
||||||
botrival = players[player].botvars.rival;
|
botrival = players[player].botvars.rival;
|
||||||
|
botfoe = players[player].botvars.foe;
|
||||||
|
|
||||||
totalring = players[player].totalring;
|
totalring = players[player].totalring;
|
||||||
xtralife = players[player].xtralife;
|
xtralife = players[player].xtralife;
|
||||||
|
|
@ -2641,6 +2643,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
||||||
p->spheres = spheres;
|
p->spheres = spheres;
|
||||||
p->botvars.diffincrease = botdiffincrease;
|
p->botvars.diffincrease = botdiffincrease;
|
||||||
p->botvars.rival = botrival;
|
p->botvars.rival = botrival;
|
||||||
|
p->botvars.foe = botfoe;
|
||||||
p->xtralife = xtralife;
|
p->xtralife = xtralife;
|
||||||
|
|
||||||
// SRB2kart
|
// SRB2kart
|
||||||
|
|
|
||||||
|
|
@ -408,6 +408,8 @@ void K_UpdateMatchRaceBots(void)
|
||||||
clear_bots(wantedbots);
|
clear_bots(wantedbots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
K_AssignFoes();
|
||||||
|
|
||||||
// We should have enough bots now :)
|
// We should have enough bots now :)
|
||||||
|
|
||||||
#ifdef HAVE_DISCORDRPC
|
#ifdef HAVE_DISCORDRPC
|
||||||
|
|
@ -615,7 +617,7 @@ fixed_t K_BotMapModifier(void)
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
static UINT32 K_BotRubberbandDistance(const player_t *player)
|
static UINT32 K_BotRubberbandDistance(const player_t *player)
|
||||||
{
|
{
|
||||||
const UINT32 spacing = FixedDiv(640 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT;
|
UINT32 spacing = FixedDiv(640 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT;
|
||||||
const UINT8 portpriority = player - players;
|
const UINT8 portpriority = player - players;
|
||||||
UINT8 pos = 1;
|
UINT8 pos = 1;
|
||||||
UINT8 i;
|
UINT8 i;
|
||||||
|
|
@ -626,6 +628,11 @@ static UINT32 K_BotRubberbandDistance(const player_t *player)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (player->botvars.foe)
|
||||||
|
spacing /= 2;
|
||||||
|
*/
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if (i == portpriority)
|
if (i == portpriority)
|
||||||
|
|
@ -649,6 +656,11 @@ static UINT32 K_BotRubberbandDistance(const player_t *player)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (player->botvars.foe && !players[i].botvars.foe)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// First check difficulty levels, then score, then settle it with port priority!
|
// First check difficulty levels, then score, then settle it with port priority!
|
||||||
if (player->botvars.difficulty < players[i].botvars.difficulty)
|
if (player->botvars.difficulty < players[i].botvars.difficulty)
|
||||||
{
|
{
|
||||||
|
|
@ -694,6 +706,8 @@ fixed_t K_BotRubberband(const player_t *player)
|
||||||
{
|
{
|
||||||
UINT8 levelreduce = std::min<UINT8>(3, player->botvars.difficulty/4); // How much to drop the "effective level" of bots that are consistently behind
|
UINT8 levelreduce = std::min<UINT8>(3, player->botvars.difficulty/4); // How much to drop the "effective level" of bots that are consistently behind
|
||||||
expreduce = Easing_Linear((K_EffectiveGradingFactor(player) - MINGRADINGFACTOR) * 2, levelreduce*FRACUNIT, 0);
|
expreduce = Easing_Linear((K_EffectiveGradingFactor(player) - MINGRADINGFACTOR) * 2, levelreduce*FRACUNIT, 0);
|
||||||
|
if (player->botvars.foe)
|
||||||
|
expreduce /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed_t difficultyEase = (((player->botvars.difficulty - 1) * FRACUNIT) - expreduce) / (MAXBOTDIFFICULTY - 1);
|
fixed_t difficultyEase = (((player->botvars.difficulty - 1) * FRACUNIT) - expreduce) / (MAXBOTDIFFICULTY - 1);
|
||||||
|
|
@ -805,7 +819,13 @@ fixed_t K_BotRubberband(const player_t *player)
|
||||||
scaled_dist = FixedDiv(scaled_dist, mapobjectscale);
|
scaled_dist = FixedDiv(scaled_dist, mapobjectscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr UINT32 END_DIST = 2048 * 14;
|
UINT32 END_DIST = 2048 * 14;
|
||||||
|
|
||||||
|
if (K_EffectiveGradingFactor(player) <= FRACUNIT)
|
||||||
|
{
|
||||||
|
END_DIST = Easing_Linear((K_EffectiveGradingFactor(player) - MINGRADINGFACTOR) * 2, END_DIST * 2, END_DIST);
|
||||||
|
}
|
||||||
|
|
||||||
if (scaled_dist < END_DIST)
|
if (scaled_dist < END_DIST)
|
||||||
{
|
{
|
||||||
// At the end of tracks, start slowing down.
|
// At the end of tracks, start slowing down.
|
||||||
|
|
@ -823,7 +843,7 @@ fixed_t K_BotRubberband(const player_t *player)
|
||||||
fixed_t K_UpdateRubberband(player_t *player)
|
fixed_t K_UpdateRubberband(player_t *player)
|
||||||
{
|
{
|
||||||
fixed_t dest = K_BotRubberband(player);
|
fixed_t dest = K_BotRubberband(player);
|
||||||
|
|
||||||
fixed_t deflect = player->botvars.recentDeflection;
|
fixed_t deflect = player->botvars.recentDeflection;
|
||||||
if (deflect > BOTMAXDEFLECTION)
|
if (deflect > BOTMAXDEFLECTION)
|
||||||
deflect = BOTMAXDEFLECTION;
|
deflect = BOTMAXDEFLECTION;
|
||||||
|
|
@ -2146,7 +2166,7 @@ void K_UpdateBotGameplayVars(player_t *player)
|
||||||
UINT32 smo = BOTANGLESAMPLES - 1;
|
UINT32 smo = BOTANGLESAMPLES - 1;
|
||||||
|
|
||||||
player->botvars.recentDeflection = (smo * player->botvars.recentDeflection / BOTANGLESAMPLES) + (dangle / BOTANGLESAMPLES);
|
player->botvars.recentDeflection = (smo * player->botvars.recentDeflection / BOTANGLESAMPLES) + (dangle / BOTANGLESAMPLES);
|
||||||
|
|
||||||
player->botvars.lastAngle = mangle;
|
player->botvars.lastAngle = mangle;
|
||||||
|
|
||||||
const botcontroller_t *botController = K_GetBotController(player->mo);
|
const botcontroller_t *botController = K_GetBotController(player->mo);
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ static boolean K_RivalBotAggression(const player_t *bot, const player_t *target)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bot->botvars.rival == false && !cv_levelskull.value)
|
if (!(bot->botvars.rival || bot->botvars.foe) && !cv_levelskull.value)
|
||||||
{
|
{
|
||||||
// Not the rival, we aren't self-aware.
|
// Not the rival, we aren't self-aware.
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,113 @@ static UINT8 K_GetOffsetStartingDifficulty(const UINT8 startingdifficulty, UINT8
|
||||||
return startingdifficulty - offset;
|
return startingdifficulty - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
static INT16 K_RivalScore(player_t *bot)
|
||||||
|
|
||||||
|
Creates a "rival score" for a bot, used to determine which bot is the
|
||||||
|
most deserving of the rival status.
|
||||||
|
|
||||||
|
Input Arguments:-
|
||||||
|
bot - Player to check.
|
||||||
|
|
||||||
|
Return:-
|
||||||
|
"Rival score" value.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
static INT16 K_RivalScore(player_t *bot)
|
||||||
|
{
|
||||||
|
const UINT16 difficulty = bot->botvars.difficulty;
|
||||||
|
const UINT16 score = bot->score;
|
||||||
|
SINT8 roundnum = 1, roundsleft = 1;
|
||||||
|
UINT16 lowestscore = UINT16_MAX;
|
||||||
|
UINT8 lowestdifficulty = MAXBOTDIFFICULTY;
|
||||||
|
UINT8 i;
|
||||||
|
|
||||||
|
if (grandprixinfo.cup != NULL && roundqueue.size > 0)
|
||||||
|
{
|
||||||
|
roundnum = roundqueue.roundnum;
|
||||||
|
roundsleft = grandprixinfo.cup->numlevels - roundnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (!playeringame[i] || players[i].spectator)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (players[i].score < lowestscore)
|
||||||
|
{
|
||||||
|
lowestscore = players[i].score;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (players[i].bot == true && players[i].botvars.difficulty < lowestdifficulty)
|
||||||
|
{
|
||||||
|
lowestdifficulty = players[i].botvars.difficulty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the early game, difficulty is more important.
|
||||||
|
// This will try to influence the higher difficulty bots to get rival more often & get even more points.
|
||||||
|
// However, when we're running low on matches left, we need to focus more on raw score!
|
||||||
|
|
||||||
|
return ((difficulty - lowestdifficulty) * roundsleft) + ((score - lowestscore) * roundnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean CompareRivals(player_t *a, player_t *b)
|
||||||
|
{
|
||||||
|
if (a == NULL)
|
||||||
|
return false;
|
||||||
|
if (b == NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (K_RivalScore(a) != K_RivalScore(b))
|
||||||
|
{
|
||||||
|
// Rival Score is HIGH when bots are strong. Sort them first!
|
||||||
|
return (K_RivalScore(a) > K_RivalScore(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fuck it
|
||||||
|
return a > b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void K_AssignFoes(void)
|
||||||
|
{
|
||||||
|
std::vector<player_t *> bots;
|
||||||
|
boolean addedplayer = false;
|
||||||
|
|
||||||
|
for (UINT8 i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (playeringame[i] == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
player_t *player = &players[i];
|
||||||
|
|
||||||
|
if (!player->spectator && player->bot)
|
||||||
|
{
|
||||||
|
addedplayer = true;
|
||||||
|
bots.push_back(player);
|
||||||
|
player->botvars.foe = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Why the fuck is this blowing up sometimes
|
||||||
|
if (!addedplayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::stable_sort(bots.begin(), bots.end(), CompareRivals);
|
||||||
|
|
||||||
|
UINT8 i = 0;
|
||||||
|
for (auto &bot : bots)
|
||||||
|
{
|
||||||
|
if (bot != NULL)
|
||||||
|
bot->botvars.foe = true;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (i > 2)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_InitGrandPrixBots(void)
|
void K_InitGrandPrixBots(void)
|
||||||
|
|
||||||
|
|
@ -254,6 +361,8 @@ void K_InitGrandPrixBots(void)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (i <= 2)
|
||||||
|
players[newplayernum-1].botvars.foe = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,64 +398,13 @@ void K_LoadGrandPrixSaveGame(void)
|
||||||
K_SetBot(i, savedata.bots[i].skin, savedata.bots[i].difficulty, BOT_STYLE_NORMAL);
|
K_SetBot(i, savedata.bots[i].skin, savedata.bots[i].difficulty, BOT_STYLE_NORMAL);
|
||||||
|
|
||||||
players[i].botvars.rival = savedata.bots[i].rival;
|
players[i].botvars.rival = savedata.bots[i].rival;
|
||||||
|
players[i].botvars.foe = savedata.bots[i].foe;
|
||||||
players[i].score = savedata.bots[i].score;
|
players[i].score = savedata.bots[i].score;
|
||||||
|
|
||||||
players[i].spectator = K_BotDefaultSpectator();
|
players[i].spectator = K_BotDefaultSpectator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
|
||||||
static INT16 K_RivalScore(player_t *bot)
|
|
||||||
|
|
||||||
Creates a "rival score" for a bot, used to determine which bot is the
|
|
||||||
most deserving of the rival status.
|
|
||||||
|
|
||||||
Input Arguments:-
|
|
||||||
bot - Player to check.
|
|
||||||
|
|
||||||
Return:-
|
|
||||||
"Rival score" value.
|
|
||||||
--------------------------------------------------*/
|
|
||||||
static INT16 K_RivalScore(player_t *bot)
|
|
||||||
{
|
|
||||||
const UINT16 difficulty = bot->botvars.difficulty;
|
|
||||||
const UINT16 score = bot->score;
|
|
||||||
SINT8 roundnum = 1, roundsleft = 1;
|
|
||||||
UINT16 lowestscore = UINT16_MAX;
|
|
||||||
UINT8 lowestdifficulty = MAXBOTDIFFICULTY;
|
|
||||||
UINT8 i;
|
|
||||||
|
|
||||||
if (grandprixinfo.cup != NULL && roundqueue.size > 0)
|
|
||||||
{
|
|
||||||
roundnum = roundqueue.roundnum;
|
|
||||||
roundsleft = grandprixinfo.cup->numlevels - roundnum;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
|
||||||
{
|
|
||||||
if (!playeringame[i] || players[i].spectator)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (players[i].score < lowestscore)
|
|
||||||
{
|
|
||||||
lowestscore = players[i].score;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (players[i].bot == true && players[i].botvars.difficulty < lowestdifficulty)
|
|
||||||
{
|
|
||||||
lowestdifficulty = players[i].botvars.difficulty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the early game, difficulty is more important.
|
|
||||||
// This will try to influence the higher difficulty bots to get rival more often & get even more points.
|
|
||||||
// However, when we're running low on matches left, we need to focus more on raw score!
|
|
||||||
|
|
||||||
return ((difficulty - lowestdifficulty) * roundsleft) + ((score - lowestscore) * roundnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_UpdateGrandPrixBots(void)
|
void K_UpdateGrandPrixBots(void)
|
||||||
|
|
||||||
|
|
@ -379,6 +437,8 @@ void K_UpdateGrandPrixBots(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
K_AssignFoes();
|
||||||
|
|
||||||
// Find the rival.
|
// Find the rival.
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -639,7 +699,7 @@ void K_IncreaseBotDifficulty(player_t *bot)
|
||||||
// RELAXED MODE:
|
// RELAXED MODE:
|
||||||
// Continues don't drop bot difficulty, because we always advance.
|
// Continues don't drop bot difficulty, because we always advance.
|
||||||
// Bots will still level up from standard advancement; we need a
|
// Bots will still level up from standard advancement; we need a
|
||||||
// much steeper rank nudge to keep difficulty at the right level.
|
// much steeper rank nudge to keep difficulty at the right level.
|
||||||
if (grandprixinfo.gamespeed == KARTSPEED_EASY)
|
if (grandprixinfo.gamespeed == KARTSPEED_EASY)
|
||||||
{
|
{
|
||||||
switch(averageRank)
|
switch(averageRank)
|
||||||
|
|
@ -689,8 +749,8 @@ static boolean CompareJoiners(player_t *a, player_t *b)
|
||||||
return (a->spectatewait < b->spectatewait);
|
return (a->spectatewait < b->spectatewait);
|
||||||
}
|
}
|
||||||
|
|
||||||
// They are equals, so just randomize
|
// Fuck it
|
||||||
return (P_Random(PR_BOTS) & 1);
|
return a > b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean CompareReplacements(player_t *a, player_t *b)
|
static boolean CompareReplacements(player_t *a, player_t *b)
|
||||||
|
|
@ -707,8 +767,8 @@ static boolean CompareReplacements(player_t *a, player_t *b)
|
||||||
return (a->position < b->position);
|
return (a->position < b->position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// They are equals, so just randomize
|
// Fuck it
|
||||||
return (P_Random(PR_BOTS) & 1);
|
return a > b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,8 @@ boolean K_CanChangeRules(boolean allowdemos);
|
||||||
|
|
||||||
boolean K_BotDefaultSpectator(void);
|
boolean K_BotDefaultSpectator(void);
|
||||||
|
|
||||||
|
void K_AssignFoes(void);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
||||||
|
|
@ -525,7 +525,7 @@ void K_LoadKartHUDGraphics(void)
|
||||||
buffer[7] = '0'+((i) % 10);
|
buffer[7] = '0'+((i) % 10);
|
||||||
HU_UpdatePatch(&kp_overdrive[0][i], "%s", buffer);
|
HU_UpdatePatch(&kp_overdrive[0][i], "%s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buffer, "bsOVRDxx");
|
sprintf(buffer, "bsOVRDxx");
|
||||||
for (i = 0; i < 32; i++)
|
for (i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -2000,7 +2000,7 @@ static void K_drawKartItem(void)
|
||||||
static void K_drawBackupItem(void)
|
static void K_drawBackupItem(void)
|
||||||
{
|
{
|
||||||
bool tiny = r_splitscreen > 1;
|
bool tiny = r_splitscreen > 1;
|
||||||
patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw };
|
patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw };
|
||||||
patch_t *localbg = (kp_itembg[2]);
|
patch_t *localbg = (kp_itembg[2]);
|
||||||
patch_t *localinv = kp_invincibility[((leveltime % (6*3)) / 3) + 7 + tiny];
|
patch_t *localinv = kp_invincibility[((leveltime % (6*3)) / 3) + 7 + tiny];
|
||||||
INT32 fx = 0, fy = 0, fflags = 0, tx = 0, ty = 0; // final coords for hud and flags...
|
INT32 fx = 0, fy = 0, fflags = 0, tx = 0, ty = 0; // final coords for hud and flags...
|
||||||
|
|
@ -3406,7 +3406,7 @@ static void K_drawKartDuelScores(void)
|
||||||
{
|
{
|
||||||
flags |= V_SNAPTOBOTTOM;
|
flags |= V_SNAPTOBOTTOM;
|
||||||
flags &= ~V_SNAPTOTOP;
|
flags &= ~V_SNAPTOTOP;
|
||||||
basey = BASEVIDHEIGHT - 40;
|
basey = BASEVIDHEIGHT - 40;
|
||||||
}
|
}
|
||||||
basex = BASEVIDWIDTH - 80;
|
basex = BASEVIDWIDTH - 80;
|
||||||
}
|
}
|
||||||
|
|
@ -3493,7 +3493,7 @@ static void K_drawKartDuelScores(void)
|
||||||
V_DrawScaledPatch(basex-barheight+foeheight, basey, flags, kp_duel_4over);
|
V_DrawScaledPatch(basex-barheight+foeheight, basey, flags, kp_duel_4over);
|
||||||
else
|
else
|
||||||
V_DrawScaledPatch(basex, basey-barheight+foeheight, flags, kp_duel_over);
|
V_DrawScaledPatch(basex, basey-barheight+foeheight, flags, kp_duel_over);
|
||||||
|
|
||||||
if (!use4p)
|
if (!use4p)
|
||||||
{
|
{
|
||||||
V_DrawScaledPatch(basex, basey, flags, kp_duel_foe);
|
V_DrawScaledPatch(basex, basey, flags, kp_duel_foe);
|
||||||
|
|
@ -3512,7 +3512,7 @@ static void K_drawKartDuelScores(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
foenum.text("{}", foe->duelscore);
|
foenum.text("{}", foe->duelscore);
|
||||||
younum.text("{}", stplyr->duelscore);
|
younum.text("{}", stplyr->duelscore);
|
||||||
|
|
||||||
// minirankings shamelessly copypasted because i know that shit works already
|
// minirankings shamelessly copypasted because i know that shit works already
|
||||||
// and SURELY we will never need to use this somewhere else, right?
|
// and SURELY we will never need to use this somewhere else, right?
|
||||||
|
|
@ -3526,7 +3526,7 @@ static void K_drawKartDuelScores(void)
|
||||||
UINT8 drawme = draw ? (stplyr - players) : (foe - players);
|
UINT8 drawme = draw ? (stplyr - players) : (foe - players);
|
||||||
UINT16 drawx = basex + (draw ? youx : foex);
|
UINT16 drawx = basex + (draw ? youx : foex);
|
||||||
UINT16 drawy = basey + (draw ? youy : foey);
|
UINT16 drawy = basey + (draw ? youy : foey);
|
||||||
|
|
||||||
if (!playeringame[drawme] || players[drawme].spectator)
|
if (!playeringame[drawme] || players[drawme].spectator)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -3790,8 +3790,8 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
|
||||||
if (R_GetViewNumber() == 1)
|
if (R_GetViewNumber() == 1)
|
||||||
{
|
{
|
||||||
flags |= V_SNAPTOBOTTOM;
|
flags |= V_SNAPTOBOTTOM;
|
||||||
flags &= ~V_SNAPTOTOP;
|
flags &= ~V_SNAPTOTOP;
|
||||||
basey = 170;
|
basey = 170;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3817,7 +3817,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using srb2::Draw;
|
using srb2::Draw;
|
||||||
srb2::Draw::Font scorefont = Draw::Font::kTimer;
|
srb2::Draw::Font scorefont = Draw::Font::kTimer;
|
||||||
|
|
||||||
if (totalscore > 99)
|
if (totalscore > 99)
|
||||||
{
|
{
|
||||||
|
|
@ -3834,7 +3834,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
scorefont = Draw::Font::kZVote;
|
scorefont = Draw::Font::kZVote;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT32 youscore = stplyr->teamimportance;
|
UINT32 youscore = stplyr->teamimportance;
|
||||||
|
|
@ -3870,7 +3870,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
|
||||||
if (teams_lastleveltime[vn] != leveltime) // Timing consistency
|
if (teams_lastleveltime[vn] != leveltime) // Timing consistency
|
||||||
{
|
{
|
||||||
INT32 delta = abs(easedallyscore[vn] - allyscore); // how wrong is display score?
|
INT32 delta = abs(easedallyscore[vn] - allyscore); // how wrong is display score?
|
||||||
|
|
||||||
if (scorechangecooldown[vn] == 0 && delta)
|
if (scorechangecooldown[vn] == 0 && delta)
|
||||||
{
|
{
|
||||||
if (allyscore > easedallyscore[vn])
|
if (allyscore > easedallyscore[vn])
|
||||||
|
|
@ -3886,9 +3886,9 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
|
||||||
enemycolor = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_WHITE, GTC_CACHE);
|
enemycolor = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_WHITE, GTC_CACHE);
|
||||||
}
|
}
|
||||||
scorechangecooldown[vn] = TICRATE/delta;
|
scorechangecooldown[vn] = TICRATE/delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromintermission)
|
if (!fromintermission)
|
||||||
{
|
{
|
||||||
// replace scores with eased scores
|
// replace scores with eased scores
|
||||||
|
|
@ -4009,7 +4009,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset)
|
||||||
if (totalscore > 99)
|
if (totalscore > 99)
|
||||||
{
|
{
|
||||||
enemynum.text("{:03}", enemyscore);
|
enemynum.text("{:03}", enemyscore);
|
||||||
allynum.text("{:03}", allyscore);
|
allynum.text("{:03}", allyscore);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -5346,8 +5346,10 @@ static void K_DrawCPUTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT32 flag
|
||||||
K_DrawNameTagItemSpy(barx, bary, p, flags);
|
K_DrawNameTagItemSpy(barx, bary, p, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT8 *foecol = R_GetTranslationColormap(TC_RAINBOW, static_cast<skincolornum_t>(SKINCOLOR_RED), GTC_CACHE);
|
||||||
|
|
||||||
UINT8 blink = ((leveltime / 7) & 1);
|
UINT8 blink = ((leveltime / 7) & 1);
|
||||||
V_DrawFixedPatch(x, y, FRACUNIT, flags, kp_cpu[blink], NULL);
|
V_DrawFixedPatch(x, y, FRACUNIT, flags, kp_cpu[blink], (p->botvars.foe) ? foecol : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT32 flags)
|
static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT32 flags)
|
||||||
|
|
@ -5856,13 +5858,13 @@ INT32 K_GetMinimapSplitFlags(const boolean usingProgressBar)
|
||||||
#define ICON_DOT_RADIUS (10)
|
#define ICON_DOT_RADIUS (10)
|
||||||
|
|
||||||
// modified pick from blondedradio/RadioRacers (but there are like 57 things we don't want in the commit)
|
// modified pick from blondedradio/RadioRacers (but there are like 57 things we don't want in the commit)
|
||||||
// (so gogo gadget copypaste, thanks for a good feature and saving me work i was supposed to do anyway)
|
// (so gogo gadget copypaste, thanks for a good feature and saving me work i was supposed to do anyway)
|
||||||
static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags)
|
static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags)
|
||||||
{
|
{
|
||||||
fixed_t amnumxpos, amnumypos;
|
fixed_t amnumxpos, amnumypos;
|
||||||
INT32 amxpos, amypos;
|
INT32 amxpos, amypos;
|
||||||
|
|
||||||
if (exitcountdown || leveltime > g_battleufo.due || battleprisons)
|
if (exitcountdown || leveltime > g_battleufo.due || battleprisons)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tic_t raw = g_battleufo.due - leveltime;
|
tic_t raw = g_battleufo.due - leveltime;
|
||||||
|
|
@ -5872,7 +5874,7 @@ static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hud
|
||||||
{
|
{
|
||||||
flags |= (raw / (TICRATE/2) % 2) ? V_YELLOWMAP : 0;
|
flags |= (raw / (TICRATE/2) % 2) ? V_YELLOWMAP : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (countdown <= 10)
|
if (countdown <= 10)
|
||||||
{
|
{
|
||||||
flags &= ~(V_HUDTRANS|V_HUDTRANSHALF);
|
flags &= ~(V_HUDTRANS|V_HUDTRANSHALF);
|
||||||
|
|
@ -7314,7 +7316,7 @@ static void K_DrawBotDebugger(void)
|
||||||
|
|
||||||
V_DrawSmallString(8, 14, 0, va("Difficulty: %d / %d", bot->botvars.difficulty, MAXBOTDIFFICULTY));
|
V_DrawSmallString(8, 14, 0, va("Difficulty: %d / %d", bot->botvars.difficulty, MAXBOTDIFFICULTY));
|
||||||
V_DrawSmallString(8, 18, 0, va("Difficulty increase: %d", bot->botvars.diffincrease));
|
V_DrawSmallString(8, 18, 0, va("Difficulty increase: %d", bot->botvars.diffincrease));
|
||||||
V_DrawSmallString(8, 22, 0, va("Rival: %d", (UINT8)(bot->botvars.rival == true)));
|
V_DrawSmallString(8, 22, 0, va("Rival / Foe: %d / %d", (UINT8)(bot->botvars.rival == true), (UINT8)(bot->botvars.foe == true)));
|
||||||
V_DrawSmallString(8, 26, 0, va("Rubberbanding: %.02f", FIXED_TO_FLOAT(bot->botvars.rubberband) * 100.0f));
|
V_DrawSmallString(8, 26, 0, va("Rubberbanding: %.02f", FIXED_TO_FLOAT(bot->botvars.rubberband) * 100.0f));
|
||||||
|
|
||||||
V_DrawSmallString(8, 32, 0, va("Item delay: %d", bot->botvars.itemdelay));
|
V_DrawSmallString(8, 32, 0, va("Item delay: %d", bot->botvars.itemdelay));
|
||||||
|
|
|
||||||
79
src/k_kart.c
79
src/k_kart.c
|
|
@ -135,7 +135,7 @@ boolean K_DuelItemAlwaysSpawns(mapthing_t *mt)
|
||||||
boolean K_InRaceDuel(void)
|
boolean K_InRaceDuel(void)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
inDuel &&
|
inDuel &&
|
||||||
(gametyperules & GTR_CIRCUIT) &&
|
(gametyperules & GTR_CIRCUIT) &&
|
||||||
!(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE) &&
|
!(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE) &&
|
||||||
!specialstageinfo.valid &&
|
!specialstageinfo.valid &&
|
||||||
|
|
@ -1624,6 +1624,8 @@ static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed
|
||||||
// Double speed for the rival!
|
// Double speed for the rival!
|
||||||
if (player->botvars.rival || cv_levelskull.value)
|
if (player->botvars.rival || cv_levelskull.value)
|
||||||
player->draftpower += add;
|
player->draftpower += add;
|
||||||
|
else if (player->botvars.foe)
|
||||||
|
player->draftpower += add/2;
|
||||||
else if (dest->player->bot) // Reduce bot gluts.
|
else if (dest->player->bot) // Reduce bot gluts.
|
||||||
player->draftpower -= 3*add/4;
|
player->draftpower -= 3*add/4;
|
||||||
}
|
}
|
||||||
|
|
@ -3557,6 +3559,10 @@ static fixed_t K_RingDurationBoost(const player_t *player)
|
||||||
// x2.0 for Rival
|
// x2.0 for Rival
|
||||||
ret *= 2;
|
ret *= 2;
|
||||||
}
|
}
|
||||||
|
else if (player->botvars.foe)
|
||||||
|
{
|
||||||
|
ret = 3 * ret / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -3773,7 +3779,7 @@ static void K_GetKartBoostPower(player_t *player)
|
||||||
// This one's a little special: we add extra top speed per tic of ringboost stored up, to allow for Ring Box to really rocket away.
|
// This one's a little special: we add extra top speed per tic of ringboost stored up, to allow for Ring Box to really rocket away.
|
||||||
// (We compensate when decrementing ringboost to avoid runaway exponential scaling hell.)
|
// (We compensate when decrementing ringboost to avoid runaway exponential scaling hell.)
|
||||||
fixed_t rb = FixedDiv(player->ringboost * FRACUNIT, max(FRACUNIT, K_RingDurationBoost(player)));
|
fixed_t rb = FixedDiv(player->ringboost * FRACUNIT, max(FRACUNIT, K_RingDurationBoost(player)));
|
||||||
fixed_t rp = ((9 - player->kartspeed) + (9 - player->kartweight)) * ((3*FRACUNIT/20)/16);
|
fixed_t rp = ((9 - player->kartspeed) + (9 - player->kartweight)) * ((3*FRACUNIT/20)/16);
|
||||||
ADDBOOST(
|
ADDBOOST(
|
||||||
ringboost_base + FixedMul(FRACUNIT / 1750, rb) + rp,
|
ringboost_base + FixedMul(FRACUNIT / 1750, rb) + rp,
|
||||||
4*FRACUNIT,
|
4*FRACUNIT,
|
||||||
|
|
@ -3801,7 +3807,7 @@ static void K_GetKartBoostPower(player_t *player)
|
||||||
// Even when not inputting a turn, drift prediction is hard.
|
// Even when not inputting a turn, drift prediction is hard.
|
||||||
// Turn solver will sometimes need to slightly turn to stay "aligned".
|
// Turn solver will sometimes need to slightly turn to stay "aligned".
|
||||||
// Award full boost even if turn solver creates a fractional miniturn.
|
// Award full boost even if turn solver creates a fractional miniturn.
|
||||||
const INT16 inner_deadzone = KART_FULLTURN / 100;
|
const INT16 inner_deadzone = KART_FULLTURN / 100;
|
||||||
|
|
||||||
INT16 steer_threshold = FixedMul((FRACUNIT * player->kartweight) / 9, max_steer_threshold)>>FRACBITS;
|
INT16 steer_threshold = FixedMul((FRACUNIT * player->kartweight) / 9, max_steer_threshold)>>FRACBITS;
|
||||||
|
|
||||||
|
|
@ -3979,6 +3985,11 @@ fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dor
|
||||||
// +10% top speed for the rival
|
// +10% top speed for the rival
|
||||||
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
|
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
|
||||||
}
|
}
|
||||||
|
else if (player->bot && player->botvars.foe)
|
||||||
|
{
|
||||||
|
// +5% for foes
|
||||||
|
finalspeed = FixedMul(finalspeed, 21*FRACUNIT/20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4302,8 +4313,8 @@ void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact)
|
||||||
UINT16 scaledamps = min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10);
|
UINT16 scaledamps = min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10);
|
||||||
// Debug print for scaledamps calculation
|
// Debug print for scaledamps calculation
|
||||||
// CONS_Printf("K_SpawnAmps: player=%s, amps=%d, kartspeed=%d, kartweight=%d, itemdistance=%d, itemdistmult=%0.2f, statscaledamps=%d, distscaledamps=%d\n",
|
// CONS_Printf("K_SpawnAmps: player=%s, amps=%d, kartspeed=%d, kartweight=%d, itemdistance=%d, itemdistmult=%0.2f, statscaledamps=%d, distscaledamps=%d\n",
|
||||||
// player_names[player-players], amps, player->kartspeed, player->kartweight,
|
// player_names[player-players], amps, player->kartspeed, player->kartweight,
|
||||||
// itemdistance, FixedToFloat(itemdistmult),
|
// itemdistance, FixedToFloat(itemdistmult),
|
||||||
// min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10),
|
// min(amps, amps * (10 + (9-player->kartspeed) - (9-player->kartweight)) / 10),
|
||||||
// FixedMul(scaledamps<<FRACBITS, itemdistmult)>>FRACBITS);
|
// FixedMul(scaledamps<<FRACBITS, itemdistmult)>>FRACBITS);
|
||||||
scaledamps = FixedMul(scaledamps<<FRACBITS, itemdistmult)>>FRACBITS;
|
scaledamps = FixedMul(scaledamps<<FRACBITS, itemdistmult)>>FRACBITS;
|
||||||
|
|
@ -4362,8 +4373,8 @@ void K_AwardPlayerAmps(player_t *player, UINT8 amps)
|
||||||
if (oldamps/AMPLEVEL != player->amps/AMPLEVEL)
|
if (oldamps/AMPLEVEL != player->amps/AMPLEVEL)
|
||||||
{
|
{
|
||||||
UINT8 amplevel = player->amps / AMPLEVEL;
|
UINT8 amplevel = player->amps / AMPLEVEL;
|
||||||
static sfxenum_t bwips[7] = {sfx_mbs4c,
|
static sfxenum_t bwips[7] = {sfx_mbs4c,
|
||||||
sfx_mbs4d, sfx_mbs4e, sfx_mbs4f, sfx_mbs50,
|
sfx_mbs4d, sfx_mbs4e, sfx_mbs4f, sfx_mbs50,
|
||||||
sfx_mbs51, sfx_mbs52};
|
sfx_mbs51, sfx_mbs52};
|
||||||
amplevel = min(amplevel, 6);
|
amplevel = min(amplevel, 6);
|
||||||
|
|
||||||
|
|
@ -4427,7 +4438,7 @@ void K_CheckpointCrossAward(player_t *player)
|
||||||
//CONS_Printf("player: %s factor: %.2f exp: %d\n", player_names[player-players], FIXED_TO_FLOAT(player->gradingfactor), player->exp);
|
//CONS_Printf("player: %s factor: %.2f exp: %d\n", player_names[player-players], FIXED_TO_FLOAT(player->gradingfactor), player->exp);
|
||||||
if (!player->cangrabitems)
|
if (!player->cangrabitems)
|
||||||
player->cangrabitems = 1;
|
player->cangrabitems = 1;
|
||||||
|
|
||||||
K_AwardPlayerRings(player, (player->bot ? 20 : 10), true);
|
K_AwardPlayerRings(player, (player->bot ? 20 : 10), true);
|
||||||
|
|
||||||
// Update Duel scoring.
|
// Update Duel scoring.
|
||||||
|
|
@ -6672,7 +6683,7 @@ void K_SpawnFireworkTrail(mobj_t *mo)
|
||||||
|
|
||||||
if (mo->player)
|
if (mo->player)
|
||||||
dust->color = mo->player->skincolor;
|
dust->color = mo->player->skincolor;
|
||||||
else
|
else
|
||||||
dust->color = mo->color;
|
dust->color = mo->color;
|
||||||
dust->colorized = true;
|
dust->colorized = true;
|
||||||
|
|
||||||
|
|
@ -9358,7 +9369,7 @@ static void K_UpdateTripwire(player_t *player)
|
||||||
else
|
else
|
||||||
CONS_Printf("airtime: %d, twLen: %d, twAirLen: %d\n", player->airtime, player->tripwireLeniency, player->tripwireAirLeniency);
|
CONS_Printf("airtime: %d, twLen: %d, twAirLen: %d\n", player->airtime, player->tripwireLeniency, player->tripwireAirLeniency);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (boostExists)
|
if (boostExists)
|
||||||
{
|
{
|
||||||
// If player is MOSTLY on the ground.
|
// If player is MOSTLY on the ground.
|
||||||
|
|
@ -9549,13 +9560,13 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
||||||
for (doubler = 0; doubler < 2; doubler++)
|
for (doubler = 0; doubler < 2; doubler++)
|
||||||
{
|
{
|
||||||
fixed_t heightOffset = player->mo->height + (24*player->mo->scale);
|
fixed_t heightOffset = player->mo->height + (24*player->mo->scale);
|
||||||
if (P_IsObjectFlipped(player->mo))
|
if (P_IsObjectFlipped(player->mo))
|
||||||
{
|
{
|
||||||
// This counteracts the offset added by K_FlipFromObject so it looks seamless from non-flipped.
|
// This counteracts the offset added by K_FlipFromObject so it looks seamless from non-flipped.
|
||||||
heightOffset += player->mo->height - FixedMul(player->mo->scale, player->mo->height);
|
heightOffset += player->mo->height - FixedMul(player->mo->scale, player->mo->height);
|
||||||
heightOffset *= P_MobjFlip(player->mo); // Fleep.
|
heightOffset *= P_MobjFlip(player->mo); // Fleep.
|
||||||
}
|
}
|
||||||
|
|
||||||
mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy,
|
mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy,
|
||||||
player->mo->z + P_GetMobjZMovement(player->mo) + heightOffset, MT_THOK);
|
player->mo->z + P_GetMobjZMovement(player->mo) + heightOffset, MT_THOK);
|
||||||
|
|
||||||
|
|
@ -9667,7 +9678,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
||||||
sub = diff * (sub > 0 ? 1 : -1);
|
sub = diff * (sub > 0 ? 1 : -1);
|
||||||
player->mo->momz -= sub;
|
player->mo->momz -= sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -10093,7 +10104,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
||||||
player->invincibilitytimer--;
|
player->invincibilitytimer--;
|
||||||
if (player->invincibilitytimer && K_PlayerScamPercentage(player, 1))
|
if (player->invincibilitytimer && K_PlayerScamPercentage(player, 1))
|
||||||
player->invincibilitytimer--;
|
player->invincibilitytimer--;
|
||||||
|
|
||||||
// Extra tripwire leniency for the end of invincibility
|
// Extra tripwire leniency for the end of invincibility
|
||||||
if (player->invincibilitytimer <= 0) {
|
if (player->invincibilitytimer <= 0) {
|
||||||
player->tripwireLeniency = max( player->tripwireLeniency, TICRATE );
|
player->tripwireLeniency = max( player->tripwireLeniency, TICRATE );
|
||||||
|
|
@ -10104,7 +10115,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
// freeze the stunned timer while baildrop is active
|
// freeze the stunned timer while baildrop is active
|
||||||
// while retaining the value that was initially set
|
// while retaining the value that was initially set
|
||||||
player->stunned++;
|
player->stunned++;
|
||||||
|
|
||||||
mobj_t *pmo = player->mo;
|
mobj_t *pmo = player->mo;
|
||||||
// particle spawn
|
// particle spawn
|
||||||
|
|
@ -10174,7 +10185,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
||||||
if (player->amps > 0)
|
if (player->amps > 0)
|
||||||
K_DefensiveOverdrive(player);
|
K_DefensiveOverdrive(player);
|
||||||
|
|
||||||
P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo);
|
P_StartQuakeFromMobj(7, 50 * player->mo->scale, 2048 * player->mo->scale, player->mo);
|
||||||
player->bailhitlag = false;
|
player->bailhitlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -13728,7 +13739,7 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original)
|
||||||
{
|
{
|
||||||
INT16 myradius = FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale) / FRACUNIT;
|
INT16 myradius = FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale) / FRACUNIT;
|
||||||
INT16 SMALL_WAYPOINT = 450;
|
INT16 SMALL_WAYPOINT = 450;
|
||||||
|
|
||||||
if (myradius < SMALL_WAYPOINT)
|
if (myradius < SMALL_WAYPOINT)
|
||||||
errorfrict *= 2;
|
errorfrict *= 2;
|
||||||
}
|
}
|
||||||
|
|
@ -14037,7 +14048,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
// ...which nullifies a lot of designed advantages for accel types and high-weight racers.
|
// ...which nullifies a lot of designed advantages for accel types and high-weight racers.
|
||||||
//
|
//
|
||||||
// In addition, it's at Gear 3 Thunderdome speed, which can make it hard for heavies to
|
// In addition, it's at Gear 3 Thunderdome speed, which can make it hard for heavies to
|
||||||
// take strong lines without brakedrifting.
|
// take strong lines without brakedrifting.
|
||||||
//
|
//
|
||||||
// To try and help close this gap, we fudge Ring Box payouts to allow weaker characters
|
// To try and help close this gap, we fudge Ring Box payouts to allow weaker characters
|
||||||
// better access to things that make them go fast, without changing core handling.
|
// better access to things that make them go fast, without changing core handling.
|
||||||
|
|
@ -14057,7 +14068,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
// Scale from base payout at 9/1 to max payout at 1/9.
|
// Scale from base payout at 9/1 to max payout at 1/9.
|
||||||
award = Easing_InCubic(FRACUNIT*total/maxtotal, 13*award/10, 18*award/10);
|
award = Easing_InCubic(FRACUNIT*total/maxtotal, 13*award/10, 18*award/10);
|
||||||
|
|
||||||
// And, because we don't have to give a damn about sandbagging, up the stakes the longer we progress!
|
// And, because we don't have to give a damn about sandbagging, up the stakes the longer we progress!
|
||||||
if (gametyperules & GTR_CIRCUIT)
|
if (gametyperules & GTR_CIRCUIT)
|
||||||
{
|
{
|
||||||
UINT8 maxgrade = 10;
|
UINT8 maxgrade = 10;
|
||||||
|
|
@ -14197,7 +14208,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
else if (!(player->instaWhipCharge >= INSTAWHIP_CHARGETIME && P_PlayerInPain(player))) // Allow reversal whip
|
else if (!(player->instaWhipCharge >= INSTAWHIP_CHARGETIME && P_PlayerInPain(player))) // Allow reversal whip
|
||||||
player->instaWhipCharge = 0;
|
player->instaWhipCharge = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player->cmd.buttons & BT_BAIL && (player->cmd.buttons & BT_RESPAWNMASK) != BT_RESPAWNMASK)
|
if (player->cmd.buttons & BT_BAIL && (player->cmd.buttons & BT_RESPAWNMASK) != BT_RESPAWNMASK)
|
||||||
{
|
{
|
||||||
if (leveltime < introtime || (gametyperules & GTR_SPHERES))
|
if (leveltime < introtime || (gametyperules & GTR_SPHERES))
|
||||||
|
|
@ -14831,7 +14842,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
mobj_t *at1 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
|
mobj_t *at1 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
|
||||||
mobj_t *at2 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
|
mobj_t *at2 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
|
||||||
mobj_t *at3 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
|
mobj_t *at3 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
|
||||||
|
|
||||||
P_SetMobjState(at1, S_THNG);
|
P_SetMobjState(at1, S_THNG);
|
||||||
P_SetMobjState(at2, S_THND);
|
P_SetMobjState(at2, S_THND);
|
||||||
P_SetMobjState(at3, S_THNH);
|
P_SetMobjState(at3, S_THNH);
|
||||||
|
|
@ -14842,7 +14853,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
P_SetTarget(&at1->target, player->mo);
|
P_SetTarget(&at1->target, player->mo);
|
||||||
P_SetTarget(&at2->target, player->mo);
|
P_SetTarget(&at2->target, player->mo);
|
||||||
P_SetTarget(&at3->target, player->mo);
|
P_SetTarget(&at3->target, player->mo);
|
||||||
|
|
||||||
S_StartSound(player->mo, LIGHTNING_SOUND);
|
S_StartSound(player->mo, LIGHTNING_SOUND);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -14898,7 +14909,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
if (player->curshield != KSHIELD_BUBBLE)
|
if (player->curshield != KSHIELD_BUBBLE)
|
||||||
{
|
{
|
||||||
mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BUBBLESHIELD);
|
mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BUBBLESHIELD);
|
||||||
// MT_BUBBLESHIELD doesn't have MF_NOBLOCKMAP so we need to remove this manually.
|
// MT_BUBBLESHIELD doesn't have MF_NOBLOCKMAP so we need to remove this manually.
|
||||||
// Otherwise if you roll a bubble shield while flipped, the visuals look too mismatched.
|
// Otherwise if you roll a bubble shield while flipped, the visuals look too mismatched.
|
||||||
shield->eflags &= ~MFE_VERTICALFLIP;
|
shield->eflags &= ~MFE_VERTICALFLIP;
|
||||||
P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2));
|
P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2));
|
||||||
|
|
@ -15082,14 +15093,14 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
||||||
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
|
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
|
||||||
{
|
{
|
||||||
S_StartSound(player->mo, sfx_gsha7);
|
S_StartSound(player->mo, sfx_gsha7);
|
||||||
if (P_IsObjectOnGround(player->mo)) // facing angle blends w/ momentum angle for game-feel
|
if (P_IsObjectOnGround(player->mo)) // facing angle blends w/ momentum angle for game-feel
|
||||||
{
|
{
|
||||||
P_Thrust(player->mo, player->mo->angle, 25*player->mo->scale);
|
P_Thrust(player->mo, player->mo->angle, 25*player->mo->scale);
|
||||||
P_Thrust(player->mo, K_MomentumAngle(player->mo), 25*player->mo->scale);
|
P_Thrust(player->mo, K_MomentumAngle(player->mo), 25*player->mo->scale);
|
||||||
}
|
}
|
||||||
else // air version is momentum angle only, reduces cheese, is twice as strong to compensate
|
else // air version is momentum angle only, reduces cheese, is twice as strong to compensate
|
||||||
{
|
{
|
||||||
P_Thrust(player->mo, K_MomentumAngle(player->mo), 50*player->mo->scale);
|
P_Thrust(player->mo, K_MomentumAngle(player->mo), 50*player->mo->scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 numsparks = 8;
|
UINT8 numsparks = 8;
|
||||||
|
|
@ -16358,7 +16369,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===
|
// ===
|
||||||
// THE EXP ZONE
|
// THE EXP ZONE
|
||||||
// ===
|
// ===
|
||||||
|
|
||||||
|
|
@ -16372,7 +16383,7 @@ static boolean K_IsValidOpponent(player_t *me, player_t *them)
|
||||||
return false;
|
return false;
|
||||||
if (G_SameTeam(me, them))
|
if (G_SameTeam(me, them))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -16464,7 +16475,7 @@ UINT16 K_GetEXP(player_t *player)
|
||||||
|
|
||||||
UINT16 exp = FixedRescale(player->gradingfactor, factormin, factormax, Easing_Linear, targetminexp, targetmaxexp)>>FRACBITS;
|
UINT16 exp = FixedRescale(player->gradingfactor, factormin, factormax, Easing_Linear, targetminexp, targetmaxexp)>>FRACBITS;
|
||||||
|
|
||||||
// CONS_Printf("Player %s numgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n",
|
// CONS_Printf("Player %s numgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n",
|
||||||
// player_names[player - players], numgradingpoints, player->gradingpointnum, targetminexp, targetmaxexp, FIXED_TO_FLOAT(player->gradingfactor), FIXED_TO_FLOAT(factormin), FIXED_TO_FLOAT(factormax), exp);
|
// player_names[player - players], numgradingpoints, player->gradingpointnum, targetminexp, targetmaxexp, FIXED_TO_FLOAT(player->gradingfactor), FIXED_TO_FLOAT(factormin), FIXED_TO_FLOAT(factormax), exp);
|
||||||
|
|
||||||
return exp;
|
return exp;
|
||||||
|
|
@ -16478,7 +16489,7 @@ UINT32 K_GetNumGradingPoints(void)
|
||||||
return numlaps * (1 + Obj_GetCheckpointCount());
|
return numlaps * (1 + Obj_GetCheckpointCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===
|
// ===
|
||||||
// END EXP ZONE
|
// END EXP ZONE
|
||||||
// ===
|
// ===
|
||||||
|
|
||||||
|
|
@ -16497,7 +16508,7 @@ boolean K_IsPickMeUpItem(mobjtype_t type)
|
||||||
extern consvar_t cv_debugpickmeup;
|
extern consvar_t cv_debugpickmeup;
|
||||||
if (cv_debugpickmeup.value)
|
if (cv_debugpickmeup.value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case MT_JAWZ:
|
case MT_JAWZ:
|
||||||
|
|
@ -16676,7 +16687,7 @@ boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2, boolean allowHostile)
|
||||||
if (!K_PickUp(victim->player, inflictor))
|
if (!K_PickUp(victim->player, inflictor))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
K_AddHitLag(victim, 3, false);
|
K_AddHitLag(victim, 3, false);
|
||||||
|
|
||||||
P_RemoveMobj(inflictor);
|
P_RemoveMobj(inflictor);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -16703,7 +16714,7 @@ fixed_t K_TeamComebackMultiplier(player_t *player)
|
||||||
else
|
else
|
||||||
theirdistance += K_GetItemRouletteDistance(&players[i], players[i].itemRoulette.playing);
|
theirdistance += K_GetItemRouletteDistance(&players[i], players[i].itemRoulette.playing);
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed_t multiplier = FixedDiv(ourdistance, theirdistance);
|
fixed_t multiplier = FixedDiv(ourdistance, theirdistance);
|
||||||
multiplier = min(multiplier, 3*FRACUNIT);
|
multiplier = min(multiplier, 3*FRACUNIT);
|
||||||
multiplier = max(multiplier, FRACUNIT);
|
multiplier = max(multiplier, FRACUNIT);
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||||
|
|
||||||
WRITEUINT8(save->p, players[i].botvars.difficulty);
|
WRITEUINT8(save->p, players[i].botvars.difficulty);
|
||||||
WRITEUINT8(save->p, (UINT8)players[i].botvars.rival);
|
WRITEUINT8(save->p, (UINT8)players[i].botvars.rival);
|
||||||
|
WRITEUINT8(save->p, (UINT8)players[i].botvars.foe);
|
||||||
|
|
||||||
WRITEUINT32(save->p, players[i].score);
|
WRITEUINT32(save->p, players[i].score);
|
||||||
}
|
}
|
||||||
|
|
@ -195,6 +196,7 @@ static boolean P_UnArchivePlayer(savebuffer_t *save)
|
||||||
|
|
||||||
savedata.bots[pid].difficulty = READUINT8(save->p);
|
savedata.bots[pid].difficulty = READUINT8(save->p);
|
||||||
savedata.bots[pid].rival = (boolean)READUINT8(save->p);
|
savedata.bots[pid].rival = (boolean)READUINT8(save->p);
|
||||||
|
savedata.bots[pid].foe = (boolean)READUINT8(save->p);
|
||||||
savedata.bots[pid].score = READUINT32(save->p);
|
savedata.bots[pid].score = READUINT32(save->p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -765,6 +767,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
||||||
WRITEUINT8(save->p, players[i].botvars.difficulty);
|
WRITEUINT8(save->p, players[i].botvars.difficulty);
|
||||||
WRITEUINT8(save->p, players[i].botvars.diffincrease);
|
WRITEUINT8(save->p, players[i].botvars.diffincrease);
|
||||||
WRITEUINT8(save->p, players[i].botvars.rival);
|
WRITEUINT8(save->p, players[i].botvars.rival);
|
||||||
|
WRITEUINT8(save->p, players[i].botvars.foe);
|
||||||
WRITEFIXED(save->p, players[i].botvars.rubberband);
|
WRITEFIXED(save->p, players[i].botvars.rubberband);
|
||||||
WRITEUINT8(save->p, players[i].botvars.bumpslow);
|
WRITEUINT8(save->p, players[i].botvars.bumpslow);
|
||||||
WRITEUINT32(save->p, players[i].botvars.itemdelay);
|
WRITEUINT32(save->p, players[i].botvars.itemdelay);
|
||||||
|
|
@ -1430,6 +1433,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
||||||
players[i].botvars.difficulty = READUINT8(save->p);
|
players[i].botvars.difficulty = READUINT8(save->p);
|
||||||
players[i].botvars.diffincrease = READUINT8(save->p);
|
players[i].botvars.diffincrease = READUINT8(save->p);
|
||||||
players[i].botvars.rival = (boolean)READUINT8(save->p);
|
players[i].botvars.rival = (boolean)READUINT8(save->p);
|
||||||
|
players[i].botvars.foe = (boolean)READUINT8(save->p);
|
||||||
players[i].botvars.rubberband = READFIXED(save->p);
|
players[i].botvars.rubberband = READFIXED(save->p);
|
||||||
players[i].botvars.bumpslow = READUINT8(save->p);
|
players[i].botvars.bumpslow = READUINT8(save->p);
|
||||||
players[i].botvars.itemdelay = READUINT32(save->p);
|
players[i].botvars.itemdelay = READUINT32(save->p);
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ struct savedata_bot_s
|
||||||
UINT8 skin;
|
UINT8 skin;
|
||||||
UINT8 difficulty;
|
UINT8 difficulty;
|
||||||
boolean rival;
|
boolean rival;
|
||||||
|
boolean foe;
|
||||||
UINT32 score;
|
UINT32 score;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue