WIP: Speed Assist

This commit is contained in:
Antonio Martinez 2025-08-21 23:56:04 -04:00 committed by AJ Martinez
parent 6a54e2c5c2
commit aab374e9ef
6 changed files with 167 additions and 29 deletions

View file

@ -874,6 +874,8 @@ struct player_t
UINT16 invincibilitytimer; // Invincibility timer UINT16 invincibilitytimer; // Invincibility timer
UINT16 invincibilityextensions; // Used to control invinc time gains when it's already been extended. UINT16 invincibilityextensions; // Used to control invinc time gains when it's already been extended.
fixed_t loneliness; // How long has a player been too far to interact? Do they need speed assist?
UINT8 eggmanexplode; // Fake item recieved, explode in a few seconds UINT8 eggmanexplode; // Fake item recieved, explode in a few seconds
SINT8 eggmanblame; // (-1 to 15) - Fake item recieved, who set this fake SINT8 eggmanblame; // (-1 to 15) - Fake item recieved, who set this fake

View file

@ -3950,6 +3950,25 @@ fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed)
return finalspeed; return finalspeed;
} }
// Speed Assist pt.2: If we need assistance, how much?
static fixed_t K_GetKartSpeedAssist(const player_t *player)
{
if (modeattacking)
return FRACUNIT;
if (gametype && GTR_BUMPERS)
return FRACUNIT;
if (specialstageinfo.valid)
return FRACUNIT;
if (K_PlayerUsesBotMovement(player))
return FRACUNIT;
if (player->loneliness < 0)
return FRACUNIT;
fixed_t MAX_SPEED_ASSIST = FRACUNIT;
return FRACUNIT + FixedMul(player->loneliness, MAX_SPEED_ASSIST);
}
fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dorubberband) fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dorubberband)
{ {
const boolean mobjValid = (player->mo != NULL && P_MobjWasRemoved(player->mo) == false); const boolean mobjValid = (player->mo != NULL && P_MobjWasRemoved(player->mo) == false);
@ -4016,6 +4035,8 @@ fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dor
finalspeed += FixedMul(player->outrun, physicsScale); finalspeed += FixedMul(player->outrun, physicsScale);
} }
finalspeed = FixedMul(finalspeed, K_GetKartSpeedAssist(player));
return finalspeed; return finalspeed;
} }
@ -9956,6 +9977,98 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
} }
} }
if (!K_PlayerUsesBotMovement(player))
{
UINT32 toDefender = 0;
UINT32 toFirst = 0;
for (UINT8 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] == false || players[i].spectator == true || players[i].exiting)
continue;
if (players[i].position == player->position - 1)
toDefender = K_UndoMapScaling(player->distancetofinish - players[i].distancetofinish);
if (players[i].position == 1)
toFirst = K_UndoMapScaling(player->distancetofinish - players[i].distancetofinish);
}
UINT32 average = 0;
UINT8 counted = 0;
UINT32 firstRaw = 0;
for (UINT8 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] == false || players[i].spectator == true || players[i].exiting)
continue;
if (players[i].position != 1)
{
counted++;
average += K_UndoMapScaling(players[i].distancetofinish);
}
else
{
firstRaw = K_UndoMapScaling(players[i].distancetofinish);
}
}
average /= max(counted, 1);
if (D_NumPlayersInRace() == 2)
{
average = firstRaw;
}
UINT32 REALLY_FAR = average + 3000; // This far back, get max gain
UINT32 TOO_CLOSE = average + 1000; // Start gaining here, lose if closer
UINT32 WAY_TOO_CLOSE = average; // Lose at max rate here
fixed_t MAX_GAIN_PER_SEC = FRACUNIT/10; // % assist to gain per sec when REALLY_FAR
fixed_t MAX_LOSS_PER_SEC = FRACUNIT/10; // % assist to lose per sec when WAY_TOO_CLOSE
UINT32 gaingap = REALLY_FAR - TOO_CLOSE;
UINT32 lossgap = TOO_CLOSE - WAY_TOO_CLOSE;
CONS_Printf("Mine %d - %d / %d / %d\n", player->distancetofinish, WAY_TOO_CLOSE, TOO_CLOSE, REALLY_FAR);
UINT32 mydist = K_UndoMapScaling(player->distancetofinish);
if (mydist >= TOO_CLOSE)
{
fixed_t gain = MAX_GAIN_PER_SEC / TICRATE;
fixed_t gainrate = FRACUNIT * (mydist - TOO_CLOSE) / gaingap;
gainrate = clamp(gainrate, 0, FRACUNIT);
gainrate = Easing_InCubic(gainrate, 0, FRACUNIT);
gain = FixedMul(gain, gainrate);
player->loneliness += gain;
CONS_Printf("gaining @ %d - %d\n", gainrate, player->loneliness);
}
else
{
fixed_t loss = MAX_LOSS_PER_SEC / TICRATE;
fixed_t lossrate = FRACUNIT * (mydist - WAY_TOO_CLOSE) / lossgap;
lossrate = FRACUNIT - clamp(lossrate, 0, FRACUNIT);
lossrate = Easing_InCubic(lossrate, 0, FRACUNIT);
loss = FixedMul(loss, lossrate);
player->loneliness -= loss;
CONS_Printf("LOSING @ %d - %d\n", lossrate, player->loneliness);
}
player->loneliness = clamp(player->loneliness, 0, FRACUNIT);
}
else
{
player->loneliness = 0;
}
if (player->spheres > 40) if (player->spheres > 40)
player->spheres = 40; player->spheres = 40;
// where's the < 0 check? see below the following block! // where's the < 0 check? see below the following block!

View file

@ -436,7 +436,7 @@ fixed_t K_ItemOddsScale(UINT8 playerCount)
} }
/*-------------------------------------------------- /*--------------------------------------------------
static UINT32 K_UndoMapScaling(UINT32 distance) UINT32 K_UndoMapScaling(UINT32 distance)
Takes a raw map distance and adjusts it to Takes a raw map distance and adjusts it to
be in x1 scale. be in x1 scale.
@ -447,7 +447,7 @@ fixed_t K_ItemOddsScale(UINT8 playerCount)
Return:- Return:-
Distance unscaled by mapobjectscale. Distance unscaled by mapobjectscale.
--------------------------------------------------*/ --------------------------------------------------*/
static UINT32 K_UndoMapScaling(UINT32 distance) UINT32 K_UndoMapScaling(UINT32 distance)
{ {
if (mapobjectscale != FRACUNIT) if (mapobjectscale != FRACUNIT)
{ {

View file

@ -108,6 +108,21 @@ fixed_t K_ItemOddsScale(UINT8 playerCount);
UINT32 K_ScaleItemDistance(INT32 distance, UINT8 numPlayers); UINT32 K_ScaleItemDistance(INT32 distance, UINT8 numPlayers);
/*--------------------------------------------------
UINT32 K_UndoMapScaling(UINT32 distance)
Takes a raw map distance and adjusts it to
be in x1 scale.
Input Arguments:-
distance - Original distance.
Return:-
Distance unscaled by mapobjectscale.
--------------------------------------------------*/
UINT32 K_UndoMapScaling(UINT32 distance);
/*-------------------------------------------------- /*--------------------------------------------------
void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item) void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item)

View file

@ -515,6 +515,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->invincibilitytimer); lua_pushinteger(L, plr->invincibilitytimer);
else if (fastcmp(field,"invincibilityextensions")) else if (fastcmp(field,"invincibilityextensions"))
lua_pushinteger(L, plr->invincibilityextensions); lua_pushinteger(L, plr->invincibilityextensions);
else if (fastcmp(field,"loneliness"))
lua_pushinteger(L, plr->loneliness);
else if (fastcmp(field,"eggmanexplode")) else if (fastcmp(field,"eggmanexplode"))
lua_pushinteger(L, plr->eggmanexplode); lua_pushinteger(L, plr->eggmanexplode);
else if (fastcmp(field,"eggmanblame")) else if (fastcmp(field,"eggmanblame"))
@ -1166,6 +1168,8 @@ static int player_set(lua_State *L)
plr->invincibilitytimer = luaL_checkinteger(L, 3); plr->invincibilitytimer = luaL_checkinteger(L, 3);
else if (fastcmp(field,"invincibilityextensions")) else if (fastcmp(field,"invincibilityextensions"))
plr->invincibilityextensions = luaL_checkinteger(L, 3); plr->invincibilityextensions = luaL_checkinteger(L, 3);
else if (fastcmp(field,"loneliness"))
plr->loneliness = luaL_checkinteger(L, 3);
else if (fastcmp(field,"eggmanexplode")) else if (fastcmp(field,"eggmanexplode"))
plr->eggmanexplode = luaL_checkinteger(L, 3); plr->eggmanexplode = luaL_checkinteger(L, 3);
else if (fastcmp(field,"eggmanblame")) else if (fastcmp(field,"eggmanblame"))

View file

@ -585,6 +585,8 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT16(save->p, players[i].invincibilitytimer); WRITEUINT16(save->p, players[i].invincibilitytimer);
WRITEUINT16(save->p, players[i].invincibilityextensions); WRITEUINT16(save->p, players[i].invincibilityextensions);
WRITEFIXED(save->p, players[i].loneliness);
WRITEUINT8(save->p, players[i].eggmanexplode); WRITEUINT8(save->p, players[i].eggmanexplode);
WRITESINT8(save->p, players[i].eggmanblame); WRITESINT8(save->p, players[i].eggmanblame);
@ -1256,6 +1258,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].invincibilitytimer = READUINT16(save->p); players[i].invincibilitytimer = READUINT16(save->p);
players[i].invincibilityextensions = READUINT16(save->p); players[i].invincibilityextensions = READUINT16(save->p);
players[i].loneliness = READFIXED(save->p);
players[i].eggmanexplode = READUINT8(save->p); players[i].eggmanexplode = READUINT8(save->p);
players[i].eggmanblame = READSINT8(save->p); players[i].eggmanblame = READSINT8(save->p);