From 219f8d74a0259efc4c2b3538edb0d749902b69ae Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Thu, 22 May 2025 16:35:53 -0400 Subject: [PATCH 1/9] Bot grip experiment --- src/d_player.h | 2 ++ src/k_bot.cpp | 8 ++++++-- src/k_hud.cpp | 2 ++ src/k_kart.c | 9 +++++++-- src/p_user.c | 3 +++ 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index d22f6f734..f056ca978 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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 diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 041a0be38..bc086c649 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -1427,10 +1427,11 @@ 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); + cmd->angle = std::min(destangle - moveangle, moveangle - destangle) >> TICCMD_REDUCE; + if (anglediff < 0) { turnsign = 1; @@ -1712,7 +1713,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 +1725,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 prediction error 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 diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 616861b37..1aae11443 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -6689,6 +6689,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) diff --git a/src/k_kart.c b/src/k_kart.c index 0371c1134..9c0264568 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13022,14 +13022,19 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) // A bit extra friction to help them without drifting. // Remove this line once they can drift. - frict -= extraFriction; + // frict -= extraFriction; + + angle_t MAXERROR = 45*ANG1; + fixed_t errorfrict = Easing_Linear(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, FRACUNIT>>2); + + 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) { const fixed_t traction_mul = traction_value - FRACUNIT; - frict -= FixedMul(extraFriction, traction_mul); + // frict -= FixedMul(extraFriction, traction_mul); } } } diff --git a/src/p_user.c b/src/p_user.c index 9e811dc01..c487f8ea3 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2321,6 +2321,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))) { From 9c7061aa0c12d2cf1dadc5ac9aa9809eaa5a21b3 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Thu, 22 May 2025 19:09:08 -0400 Subject: [PATCH 2/9] More corrective bot friction on tighter waypoints --- src/k_bot.cpp | 3 ++- src/k_kart.c | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index bc086c649..0e28e6f5e 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -1430,6 +1430,7 @@ static INT32 K_HandleBotTrack(const player_t *player, ticcmd_t *cmd, botpredicti 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) @@ -1725,7 +1726,7 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) UINT8 spindash = 0; INT32 turnamt = 0; - cmd->angle = 0; // For bots, this is used to transmit prediction error to gamelogic. + 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 diff --git a/src/k_kart.c b/src/k_kart.c index 9c0264568..97c9c4025 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13017,8 +13017,8 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) } else if (K_PlayerUsesBotMovement(player) == true) { - const fixed_t speedPercent = min(FRACUNIT, FixedDiv(player->speed, K_GetKartSpeed(player, false, false))); - const fixed_t extraFriction = FixedMul(FixedMul(FRACUNIT >> 5, factor), speedPercent); + // const fixed_t speedPercent = min(FRACUNIT, FixedDiv(player->speed, K_GetKartSpeed(player, false, false))); + // const fixed_t extraFriction = FixedMul(FixedMul(FRACUNIT >> 5, factor), speedPercent); // A bit extra friction to help them without drifting. // Remove this line once they can drift. @@ -13027,13 +13027,23 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) angle_t MAXERROR = 45*ANG1; fixed_t errorfrict = Easing_Linear(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, FRACUNIT>>2); + if (player->currentwaypoint && player->currentwaypoint->mobj) + { + fixed_t myradius = FixedInt(FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale)); + + if (myradius < 400) + errorfrict += errorfrict/100 * (300 - myradius); + } + + 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) { - const fixed_t traction_mul = traction_value - FRACUNIT; + //const fixed_t traction_mul = traction_value - FRACUNIT; // frict -= FixedMul(extraFriction, traction_mul); } } From 926a95f11795b6e54bf2cf7edb9c32c6422e5913 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 3 Jun 2025 12:48:45 -0400 Subject: [PATCH 3/9] Faster turn updates for bots going fast --- src/k_bot.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 0e28e6f5e..299a0f42b 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -1944,6 +1944,9 @@ static void K_BuildBotTiccmdNormal(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) @@ -1960,7 +1963,7 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) // Count up if (player->botvars.turnconfirm < BOTTURNCONFIRM) { - cmd->bot.turnconfirm++; + cmd->bot.turnconfirm += turndelta; } } else if (turnamt < 0) @@ -1968,7 +1971,7 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) // Count down if (player->botvars.turnconfirm > -BOTTURNCONFIRM) { - cmd->bot.turnconfirm--; + cmd->bot.turnconfirm -= turndelta; } } else From 0cb1f7bc414a483df69d547184d96fdca7e1d462 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 3 Jun 2025 13:00:47 -0400 Subject: [PATCH 4/9] Add back rubberband friction and speed friction --- src/k_kart.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 97c9c4025..7322e941b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13017,13 +13017,14 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) } else if (K_PlayerUsesBotMovement(player) == true) { - // const fixed_t speedPercent = min(FRACUNIT, FixedDiv(player->speed, K_GetKartSpeed(player, false, false))); - // const fixed_t extraFriction = FixedMul(FixedMul(FRACUNIT >> 5, factor), speedPercent); + const fixed_t speedPercent = min(FRACUNIT, FixedDiv(player->speed, K_GetKartSpeed(player, false, false))); + const fixed_t extraFriction = FixedMul(FixedMul(FRACUNIT >> 5, factor), speedPercent); // A bit extra friction to help them without drifting. // Remove this line once they can drift. - // frict -= extraFriction; + frict -= extraFriction; + // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. angle_t MAXERROR = 45*ANG1; fixed_t errorfrict = Easing_Linear(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, FRACUNIT>>2); @@ -13036,15 +13037,14 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) } 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) { - //const fixed_t traction_mul = traction_value - FRACUNIT; - // frict -= FixedMul(extraFriction, traction_mul); + const fixed_t traction_mul = traction_value - FRACUNIT; + frict -= FixedMul(extraFriction, traction_mul); } } } From 55d63fb40286e7a477d4ab45cf167a35533e03db Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 3 Jun 2025 13:02:04 -0400 Subject: [PATCH 5/9] Allow complexity to drop a little lower --- src/k_bot.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 299a0f42b..8e4f2f597 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -581,7 +581,9 @@ 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 = 4 * FRACUNIT / 10; + modifier_min -= FRACUNIT; const fixed_t complexity_value = std::clamp( FixedDiv(K_GetTrackComplexity(), complexity_scale), From 93b62bf8239dad1fbf86b3bce05c39ab026d4dbc Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 3 Jun 2025 18:42:35 -0400 Subject: [PATCH 6/9] Low EXP reduces rubberbanding, fix minimum complexity modifier --- src/k_bot.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 20107a159..86c9e7d77 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -587,7 +587,7 @@ fixed_t K_BotMapModifier(void) const fixed_t complexity_value = std::clamp( FixedDiv(K_GetTrackComplexity(), complexity_scale), - -FixedDiv(FRACUNIT, modifier_max), + modifier_min, modifier_max ); @@ -679,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) + { + UINT8 levelreduce = 2; // 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 * 2 - FRACUNIT, 0, levelreduce*FRACUNIT); + } + + fixed_t difficultyEase = (((player->botvars.difficulty - 1) * FRACUNIT) - expreduce) / (MAXBOTDIFFICULTY - 1); + + if (difficultyEase < 0) + difficultyEase = 0; if (cv_levelskull.value) difficultyEase = FRACUNIT; From 77ecab8464a0586609fe76a117edd4406539ec9c Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 4 Jun 2025 01:43:10 -0400 Subject: [PATCH 7/9] Review fixups --- src/k_kart.c | 9 +++++---- src/p_user.c | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index d8148f510..1f1487e41 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13216,15 +13216,16 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) frict -= extraFriction; // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. - angle_t MAXERROR = 45*ANG1; + 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) { - fixed_t myradius = FixedInt(FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale)); + INT16 myradius = FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale) / FRACUNIT; + INT16 SMALL_WAYPOINT = 450; - if (myradius < 400) - errorfrict += errorfrict/100 * (300 - myradius); + if (myradius < SMALL_WAYPOINT) + errorfrict *= 2; } errorfrict = min(errorfrict, frict/4); diff --git a/src/p_user.c b/src/p_user.c index 2bd2192ac..2907db999 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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; From 786dbe46e2df0164012d8ed749811ea2a835cc63 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 4 Jun 2025 14:58:04 -0400 Subject: [PATCH 8/9] Soften bot bumps, lower minimum complexity --- src/k_bot.cpp | 2 +- src/k_kart.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 86c9e7d77..2daaf3cce 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -582,7 +582,7 @@ fixed_t K_BotMapModifier(void) { constexpr INT32 complexity_scale = 10000; fixed_t modifier_max = FRACUNIT * 2; - fixed_t modifier_min = 4 * FRACUNIT / 10; + fixed_t modifier_min = 3 * FRACUNIT / 10; modifier_min -= FRACUNIT; const fixed_t complexity_value = std::clamp( diff --git a/src/k_kart.c b/src/k_kart.c index 1f1487e41..c42ddc416 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -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; From 13f17180d3342d8e0c472df08a85d864d995c740 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 4 Jun 2025 15:18:26 -0400 Subject: [PATCH 9/9] Fix krangled expreduce math, add maxbot shield error --- src/k_bot.cpp | 6 +++--- src/k_botitem.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 2daaf3cce..d9d91a134 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -683,11 +683,11 @@ fixed_t K_BotRubberband(const player_t *player) // 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) + if (player->gradingfactor < FRACUNIT && !(player->botvars.rival)) { - UINT8 levelreduce = 2; // How much to drop the "effective level" of bots that are consistently behind + 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 * 2 - FRACUNIT, 0, levelreduce*FRACUNIT); + expreduce = Easing_Linear((effgradingfactor - FRACUNIT/2) * 2, levelreduce*FRACUNIT, 0); } fixed_t difficultyEase = (((player->botvars.difficulty - 1) * FRACUNIT) - expreduce) / (MAXBOTDIFFICULTY - 1); diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index e3bb56c33..578c343eb 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -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++) {