diff --git a/src/g_game.c b/src/g_game.c index 6bf730f24..079b7bbab 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1813,14 +1813,20 @@ void G_Ticker(boolean run) { if (playeringame[i]) { - if (players[i].bot == true && grandprixinfo.gp == true && grandprixinfo.masterbots == false) + if (players[i].bot == true + && grandprixinfo.gp == true + && grandprixinfo.masterbots == false) { - UINT8 bot_level_decrease = 2; + UINT8 bot_level_decrease = 3; if (grandprixinfo.gamespeed == KARTSPEED_EASY) - bot_level_decrease = 3; + { + bot_level_decrease++; + } else if (grandprixinfo.gamespeed == KARTSPEED_HARD) - bot_level_decrease = 1; + { + bot_level_decrease--; + } if (players[i].botvars.difficulty <= bot_level_decrease) { diff --git a/src/k_bot.cpp b/src/k_bot.cpp index be054fa15..6ee701c62 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -649,6 +649,18 @@ static UINT32 K_BotRubberbandDistance(const player_t *player) --------------------------------------------------*/ fixed_t K_BotRubberband(const player_t *player) { + if (player->exiting) + { + // You're done, we don't need to rubberband anymore. + return FRACUNIT; + } + + const botcontroller_t *botController = K_GetBotController(player->mo); + if (botController != nullptr && (botController->flags & TMBOT_NORUBBERBAND) == TMBOT_NORUBBERBAND) // Disable rubberbanding + { + return FRACUNIT; + } + const fixed_t difficultyEase = ((player->botvars.difficulty - 1) * FRACUNIT) / (MAXBOTDIFFICULTY - 1); // Lv. 1: x0.65 avg @@ -682,18 +694,6 @@ fixed_t K_BotRubberband(const player_t *player) player_t *firstplace = nullptr; size_t i = SIZE_MAX; - if (player->exiting) - { - // You're done, we don't need to rubberband anymore. - return FRACUNIT; - } - - const botcontroller_t *botController = K_GetBotController(player->mo); - if (botController != nullptr && (botController->flags & TMBOT_NORUBBERBAND) == TMBOT_NORUBBERBAND) // Disable rubberbanding - { - return FRACUNIT; - } - for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) @@ -751,6 +751,20 @@ fixed_t K_BotRubberband(const player_t *player) } } + UINT32 scaled_dist = player->distancetofinish; + if (mapobjectscale != FRACUNIT) + { + // Bring back to normal scale. + scaled_dist = FixedDiv(scaled_dist, mapobjectscale); + } + + constexpr UINT32 END_DIST = 2048 * 14; + if (scaled_dist < END_DIST) + { + // At the end of tracks, start slowing down. + rubberband = FixedMul(rubberband, FixedDiv(scaled_dist, END_DIST)); + } + return Easing_Linear(rubberband, rubberSlow, rubberFast); } diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index 4c2c14837..056c0d4aa 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -1497,6 +1497,13 @@ static void K_BotItemInstashield(const player_t *player, ticcmd_t *cmd) return; } + if (player->botvars.difficulty <= 7) + { + // Weak players don't whip. + // Weak bots don't either. + return; + } + // Find players within the instashield's range. for (i = 0; i < MAXPLAYERS; i++) { diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 297d5d3ed..8991a9606 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -542,9 +542,9 @@ void K_IncreaseBotDifficulty(player_t *bot) bot->botvars.diffincrease = 0; - if (bot->botvars.difficulty >= MAXBOTDIFFICULTY) + if (grandprixinfo.masterbots == true) { - // Already at max difficulty, don't need to increase + // Master bot difficulty is not dynamic. return; } @@ -642,7 +642,11 @@ void K_IncreaseBotDifficulty(player_t *bot) rankNudge = 0; break; case GRADE_A: - rankNudge = 1; + if (grandprixinfo.gp && grandprixinfo.gamespeed == KARTSPEED_EASY) + rankNudge = 0; + else + rankNudge = 1; + break; } increase += rankNudge; diff --git a/src/k_kart.c b/src/k_kart.c index 147a0d381..7f15057ae 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2967,10 +2967,32 @@ boolean K_SlopeResistance(const player_t *player) return false; } +fixed_t K_PlayerTripwireSpeedThreshold(const player_t *player) +{ + fixed_t required_speed = 2 * K_GetKartSpeed(player, false, false); // 200% + + if (player->offroad && K_ApplyOffroad(player)) + { + // Increase to 300% if you're lawnmowering. + required_speed = (required_speed * 3) / 2; + } + + if (player->botvars.rubberband > FRACUNIT && K_PlayerUsesBotMovement(player) == true) + { + // Make it harder for bots to do this when rubberbanding. + + // This is actually biased really hard against the bot, + // because the bot rubberbanding speed increase is + // decreased with other boosts. + + required_speed = FixedMul(required_speed, player->botvars.rubberband); + } + + return required_speed; +} + tripwirepass_t K_TripwirePassConditions(const player_t *player) { - UINT8 tripwirereq = player->offroad ? 3 : 2; - if ( player->invincibilitytimer || player->sneakertimer @@ -2979,7 +3001,7 @@ tripwirepass_t K_TripwirePassConditions(const player_t *player) if ( player->flamedash || - (player->speed > (tripwirereq * K_GetKartSpeed(player, false, false)) && player->tripwireReboundDelay == 0) + ((player->speed > K_PlayerTripwireSpeedThreshold(player)) && player->tripwireReboundDelay == 0) ) return TRIPWIRE_BOOST; @@ -3053,7 +3075,7 @@ boolean K_WaterRun(mobj_t *mobj) return K_IsHoldingDownTop(mobj->player) == false; } - minspeed = 2 * K_GetKartSpeed(mobj->player, false, false); // 200% + minspeed = K_PlayerTripwireSpeedThreshold(mobj->player); if (mobj->player->speed < minspeed / 5) // 40% { @@ -4851,7 +4873,7 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state) } if (state == TRIPSTATE_PASSED && player->spinouttimer && - player->speed > 2 * K_GetKartSpeed(player, false, true)) + player->speed > K_PlayerTripwireSpeedThreshold(player)) { K_TumblePlayer(player, NULL, NULL); } @@ -10257,12 +10279,7 @@ static void K_UpdatePlayerWaypoints(player_t *const player) INT32 K_GetKartRingPower(const player_t *player, boolean boosted) { fixed_t ringPower = ((9 - player->kartspeed) + (9 - player->kartweight)) * (FRACUNIT/2); - fixed_t basePower = ringPower; - // FIXME: Bot ringboost adjustments can award negative ringboost per ring, which seems bad. - // Revisit these values if bot ringboost needs to respond to low-complexity maps better, - // but for now we're just lazily making sure that bots never have their ringboost "boosted" - // below the value that a player would have when playing the same stat combo. if (boosted == true && K_PlayerUsesBotMovement(player)) { // x2.0 for Lv. 9 @@ -10277,7 +10294,7 @@ INT32 K_GetKartRingPower(const player_t *player, boolean boosted) } } - return max(ringPower, basePower) / FRACUNIT; + return max(ringPower / FRACUNIT, 1); } // Returns false if this player being placed here causes them to collide with any other player @@ -14192,7 +14209,7 @@ boolean K_PlayerCanPunt(player_t *player) return true; } - if (player->tripwirePass >= TRIPWIRE_BLASTER && player->speed >= 2 * K_GetKartSpeed(player, false, false)) + if (player->tripwirePass >= TRIPWIRE_BLASTER && player->speed >= K_PlayerTripwireSpeedThreshold(player)) { return true; } diff --git a/src/k_kart.h b/src/k_kart.h index eec786f93..09c2d46d4 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -201,6 +201,7 @@ void K_StripOther(player_t *player); void K_MomentumToFacing(player_t *player); boolean K_ApplyOffroad(const player_t *player); boolean K_SlopeResistance(const player_t *player); +fixed_t K_PlayerTripwireSpeedThreshold(const player_t *player); tripwirepass_t K_TripwirePassConditions(const player_t *player); boolean K_TripwirePass(const player_t *player); boolean K_MovingHorizontally(mobj_t *mobj);