Merge branch 'bot-grip' into 'master'

Bot grip

See merge request kart-krew-dev/ring-racers-internal!2568
This commit is contained in:
Oni VelocitOni 2025-06-06 04:08:20 +00:00
commit eaffcb2492
6 changed files with 63 additions and 10 deletions

View file

@ -420,6 +420,8 @@ struct botvars_t
UINT8 roulettePriority; // What items to go for on the roulette
tic_t rouletteTimeout; // If it takes too long to decide, try lowering priority until we find something valid.
angle_t predictionError; // How bad is our momentum angle relative to where we're trying to go?
};
// player_t struct for round-specific condition tracking

View file

@ -581,11 +581,13 @@ const botcontroller_t *K_GetBotController(const mobj_t *mobj)
fixed_t K_BotMapModifier(void)
{
constexpr INT32 complexity_scale = 10000;
constexpr fixed_t modifier_max = FRACUNIT * 2;
fixed_t modifier_max = FRACUNIT * 2;
fixed_t modifier_min = 3 * FRACUNIT / 10;
modifier_min -= FRACUNIT;
const fixed_t complexity_value = std::clamp<fixed_t>(
FixedDiv(K_GetTrackComplexity(), complexity_scale),
-FixedDiv(FRACUNIT, modifier_max),
modifier_min,
modifier_max
);
@ -677,7 +679,21 @@ fixed_t K_BotRubberband(const player_t *player)
return FRACUNIT;
}
fixed_t difficultyEase = ((player->botvars.difficulty - 1) * FRACUNIT) / (MAXBOTDIFFICULTY - 1);
fixed_t expreduce = 0;
// Allow the status quo to assert itself a bit. Bots get most of their speed from their
// mechanics adjustments, not from items, so kill some bot speed if they've got bad EXP.
if (player->gradingfactor < FRACUNIT && !(player->botvars.rival))
{
UINT8 levelreduce = 3; // How much to drop the "effective level" of bots that are consistently behind
fixed_t effgradingfactor = std::max(FRACUNIT/2, player->gradingfactor);
expreduce = Easing_Linear((effgradingfactor - FRACUNIT/2) * 2, levelreduce*FRACUNIT, 0);
}
fixed_t difficultyEase = (((player->botvars.difficulty - 1) * FRACUNIT) - expreduce) / (MAXBOTDIFFICULTY - 1);
if (difficultyEase < 0)
difficultyEase = 0;
if (cv_levelskull.value)
difficultyEase = FRACUNIT;
@ -1427,10 +1443,12 @@ static INT32 K_HandleBotTrack(const player_t *player, ticcmd_t *cmd, botpredicti
I_Assert(predict != nullptr);
destangle = K_BotSmoothLanding(player, destangle);
moveangle = player->mo->angle + K_GetUnderwaterTurnAdjust(player);
anglediff = AngleDeltaSigned(moveangle, destangle);
// predictionerror
cmd->angle = std::min(destangle - moveangle, moveangle - destangle) >> TICCMD_REDUCE;
if (anglediff < 0)
{
turnsign = 1;
@ -1712,7 +1730,7 @@ static void K_BuildBotPodiumTiccmd(const player_t *player, ticcmd_t *cmd)
Build ticcmd for bots with a style of BOT_STYLE_NORMAL
--------------------------------------------------*/
static void K_BuildBotTiccmdNormal(const player_t *player, ticcmd_t *cmd)
static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd)
{
precise_t t = 0;
@ -1724,6 +1742,9 @@ static void K_BuildBotTiccmdNormal(const player_t *player, ticcmd_t *cmd)
UINT8 spindash = 0;
INT32 turnamt = 0;
cmd->angle = 0; // For bots, this is used to transmit predictionerror to gamelogic.
// Will be overwritten by K_HandleBotTrack if we have a destination.
if (!(gametyperules & GTR_BOTS) // No bot behaviors
|| K_GetNumWaypoints() == 0 // No waypoints
|| leveltime <= introtime // During intro camera
@ -1939,6 +1960,9 @@ static void K_BuildBotTiccmdNormal(const player_t *player, ticcmd_t *cmd)
ps_bots[player - players].item = I_GetPreciseTime() - t;
}
// Update turning quicker if we're moving at high speeds.
UINT8 turndelta = (player->speed > (7 * K_GetKartSpeed(player, false, false) / 4)) ? 2 : 1;
if (turnamt != 0)
{
if (turnamt > KART_FULLTURN)
@ -1955,7 +1979,7 @@ static void K_BuildBotTiccmdNormal(const player_t *player, ticcmd_t *cmd)
// Count up
if (player->botvars.turnconfirm < BOTTURNCONFIRM)
{
cmd->bot.turnconfirm++;
cmd->bot.turnconfirm += turndelta;
}
}
else if (turnamt < 0)
@ -1963,7 +1987,7 @@ static void K_BuildBotTiccmdNormal(const player_t *player, ticcmd_t *cmd)
// Count down
if (player->botvars.turnconfirm > -BOTTURNCONFIRM)
{
cmd->bot.turnconfirm--;
cmd->bot.turnconfirm -= turndelta;
}
}
else

View file

@ -1201,7 +1201,7 @@ static void K_BotItemLightning(const player_t *player, ticcmd_t *cmd)
ZoneScoped;
fixed_t radius = 192 * player->mo->scale;
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, radius);
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, 4*radius/3);
if (K_BotUseItemNearPlayer(player, cmd, radius) == false)
{
@ -1243,7 +1243,7 @@ static void K_BotItemBubble(const player_t *player, ticcmd_t *cmd)
if (player->bubblecool <= 0)
{
fixed_t radius = 192 * player->mo->scale;
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, radius);
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, 4*radius/3);
for (i = 0; i < MAXPLAYERS; i++)
{

View file

@ -7079,6 +7079,8 @@ static void K_DrawBotDebugger(void)
V_DrawSmallString(8, 66, 0, va("Complexity: %d", K_GetTrackComplexity()));
V_DrawSmallString(8, 70, 0, va("Bot modifier: %.2f", FixedToFloat(K_BotMapModifier())));
V_DrawSmallString(8, 76, 0, va("Prediction error: %d", bot->botvars.predictionError));
}
static void K_DrawGPRankDebugger(void)

View file

@ -741,6 +741,7 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against)
// Applies rubberbanding, to prevent rubberbanding bots
// from causing super crazy bumps.
fixed_t spd = K_GetKartSpeed(mobj->player, false, true);
fixed_t unmodifiedspd = K_GetKartSpeed(mobj->player, false, false);
fixed_t speedfactor = 8 * mapobjectscale;
@ -757,7 +758,10 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against)
}
if (mobj->player->speed > spd)
weight += FixedDiv((mobj->player->speed - spd), speedfactor);
weight += FixedDiv(
FixedDiv((mobj->player->speed - spd), speedfactor),
FixedDiv(spd, unmodifiedspd)
);
}
return weight;
@ -13232,6 +13236,22 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original)
// Remove this line once they can drift.
frict -= extraFriction;
// If bots are moving in the wrong direction relative to where they want to look, add some extra grip.
angle_t MAXERROR = ANGLE_45;
fixed_t errorfrict = Easing_Linear(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, FRACUNIT>>2);
if (player->currentwaypoint && player->currentwaypoint->mobj)
{
INT16 myradius = FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale) / FRACUNIT;
INT16 SMALL_WAYPOINT = 450;
if (myradius < SMALL_WAYPOINT)
errorfrict *= 2;
}
errorfrict = min(errorfrict, frict/4);
frict -= errorfrict;
// Bots gain more traction as they rubberband.
const fixed_t traction_value = FixedMul(player->botvars.rubberband, max(FRACUNIT, K_BotMapModifier()));
if (traction_value > FRACUNIT)

View file

@ -2313,6 +2313,8 @@ static void P_UpdatePlayerAngle(player_t *player)
}
}
player->botvars.predictionError = 0;
// Don't apply steering just yet. If we make a correction, we'll need to adjust it.
INT16 targetsteering = K_UpdateSteeringValue(player->steering, player->cmd.turning);
angleChange = K_GetKartTurnValue(player, targetsteering) << TICCMD_REDUCE;
@ -2321,6 +2323,9 @@ static void P_UpdatePlayerAngle(player_t *player)
{
// You're a bot. Go where you're supposed to go
player->steering = targetsteering;
// But the "angle" field of this ticcmd stores your prediction error,
// which we use to apply friction. Transfer it!
player->botvars.predictionError = player->cmd.angle << TICCMD_REDUCE;
}
else if ((!(player->cmd.flags & TICCMD_RECEIVED)) && (!!(player->oldcmd.flags && TICCMD_RECEIVED)))
{