From 78fb3c0cddabdbad40c4be453f100f292634a75b Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 15 Jul 2025 16:40:27 -0400 Subject: [PATCH 01/11] No lives in Relaxed --- src/g_game.c | 6 +-- src/k_grandprix.cpp | 36 +++++++++++++--- src/k_rank.cpp | 3 ++ src/k_tally.cpp | 60 ++++++++++++++------------ src/menus/play-local-race-difficulty.c | 4 +- 5 files changed, 71 insertions(+), 38 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index bd3acb7f0..d9c8c1551 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3257,7 +3257,7 @@ void G_BeginLevelExit(void) g_exit.losing = true; g_exit.retry = false; - if (!G_GametypeAllowsRetrying() || skipstats != 0) + if (!G_GametypeAllowsRetrying() || skipstats != 0 || (grandprixinfo.gp && grandprixinfo.gamespeed == KARTSPEED_EASY)) { g_exit.losing = false; // never force a retry } @@ -3618,7 +3618,7 @@ boolean G_GametypeUsesLives(void) if (modeattacking) // NOT in Record Attack return false; - if (grandprixinfo.gp == true) // In Grand Prix + if (grandprixinfo.gp == true && grandprixinfo.gamespeed != KARTSPEED_EASY) // In Grand Prix return true; return false; @@ -4738,7 +4738,7 @@ static void G_DoCompleted(void) } } - if (grandprixinfo.gp == true && grandprixinfo.wonround == true && player->exiting && !retrying) + if (grandprixinfo.gp == true && grandprixinfo.wonround == true && player->exiting && (!retrying || grandprixinfo.gamespeed == KARTSPEED_EASY)) { if (player->bot == true) { diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index 004ae6013..1dac5a69a 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -389,8 +389,9 @@ void K_UpdateGrandPrixBots(void) if (players[i].botvars.diffincrease) { + // CONS_Printf("in %d inc %d", players[i].botvars.difficulty, players[i].botvars.diffincrease); if (players[i].botvars.diffincrease < 0) - players[i].botvars.difficulty = std::max(1, players[i].botvars.difficulty - players[i].botvars.diffincrease); + players[i].botvars.difficulty = std::max(1, players[i].botvars.difficulty + players[i].botvars.diffincrease); else players[i].botvars.difficulty += players[i].botvars.diffincrease; @@ -400,6 +401,7 @@ void K_UpdateGrandPrixBots(void) } players[i].botvars.diffincrease = 0; + // CONS_Printf("out %d\n", players[i].botvars.difficulty); } if (players[i].botvars.rival) @@ -630,13 +632,37 @@ void K_IncreaseBotDifficulty(player_t *bot) rankNudge = 0; break; case GRADE_A: - if (grandprixinfo.gp && grandprixinfo.gamespeed == KARTSPEED_EASY) - rankNudge = 0; - else - rankNudge = 1; + rankNudge = 1; break; } + // RELAXED MODE: + // Continues don't drop bot difficulty, because we always advance. + // Bots will still level up from standard advancement; we need a + // much steeper rank nudge to keep difficulty at the right level. + if (grandprixinfo.gamespeed == KARTSPEED_EASY) + { + switch(averageRank) + { + case GRADE_E: + rankNudge = -4; + break; + case GRADE_D: + rankNudge = -3; + break; + case GRADE_C: + rankNudge = -2; + break; + case GRADE_B: + rankNudge = -1; + break; + case GRADE_A: + rankNudge = 0; + break; + } + } + + increase += rankNudge; if (increase <= 0) diff --git a/src/k_rank.cpp b/src/k_rank.cpp index f36e4f40a..9cafd98a8 100644 --- a/src/k_rank.cpp +++ b/src/k_rank.cpp @@ -646,6 +646,9 @@ fixed_t K_CalculateGPPercent(gpRank_t *rankData) rankData->scoreRings + rankData->scoreContinues; + if (rankData->scoreTotal < 0) + rankData->scoreTotal = 0; + const fixed_t percent = FixedDiv(rankData->scoreTotal, total); return percent; diff --git a/src/k_tally.cpp b/src/k_tally.cpp index aaf96de61..bfbc64dbb 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -618,7 +618,8 @@ boolean level_tally_t::IncrementLine(void) value = &displayStat[i]; lives_check = ( - stats[i] == TALLY_STAT_TOTALRINGS // Rings also shows the Lives. + grandprixinfo.gamespeed != KARTSPEED_EASY + && stats[i] == TALLY_STAT_TOTALRINGS // Rings also shows the Lives. && livesAdded < owner->xtralife // Don't check if we've maxxed out! ); @@ -1294,41 +1295,44 @@ void level_tally_t::Draw(void) case TALLY_STAT_TOTALRINGS: { drawer_text - .x(184.0 * frac) + .x((G_GametypeUsesLives() ? 184.0 : 200.0) * frac) .align(srb2::Draw::Align::kCenter) .text(va("%d", displayStat[i])); - srb2::Draw lives_drawer = drawer_text - .xy(221.0 * frac, -1.0 * frac); - - const skincolornum_t color = static_cast(owner->skincolor); - lives_drawer - .x(r_splitscreen ? -7.0 : -2.0) - .colormap(owner->skin, color) - .patch(faceprefix[owner->skin][r_splitscreen ? FACE_MINIMAP : FACE_RANK]); - - UINT8 lives_num = std::min(owner->lives + livesAdded, 10); - if (xtraBlink > 0 && (xtraBlink & 1) == 0 && livesAdded > 0) + if (G_GametypeUsesLives()) { - lives_num = 0; - } + srb2::Draw lives_drawer = drawer_text + .xy(221.0 * frac, -1.0 * frac); - if (lives_num > 0) - { - if (r_splitscreen) + const skincolornum_t color = static_cast(owner->skincolor); + lives_drawer + .x(r_splitscreen ? -7.0 : -2.0) + .colormap(owner->skin, color) + .patch(faceprefix[owner->skin][r_splitscreen ? FACE_MINIMAP : FACE_RANK]); + + UINT8 lives_num = std::min(owner->lives + livesAdded, 10); + if (xtraBlink > 0 && (xtraBlink & 1) == 0 && livesAdded > 0) { - lives_drawer = lives_drawer - .xy(6.0, 2.0) - .align(srb2::Draw::Align::kLeft); - } - else - { - lives_drawer = lives_drawer - .xy(17.0, 1.0) - .font(srb2::Draw::Font::kThinTimer); + lives_num = 0; } - lives_drawer.text("{}", lives_num); + if (lives_num > 0) + { + if (r_splitscreen) + { + lives_drawer = lives_drawer + .xy(6.0, 2.0) + .align(srb2::Draw::Align::kLeft); + } + else + { + lives_drawer = lives_drawer + .xy(17.0, 1.0) + .font(srb2::Draw::Font::kThinTimer); + } + + lives_drawer.text("{}", lives_num); + } } break; diff --git a/src/menus/play-local-race-difficulty.c b/src/menus/play-local-race-difficulty.c index 5793e76c4..e2f0a13fc 100644 --- a/src/menus/play-local-race-difficulty.c +++ b/src/menus/play-local-race-difficulty.c @@ -188,10 +188,10 @@ void Dummygpdifficulty_OnChange(void) switch (cv_dummygpdifficulty.value) { case KARTSPEED_EASY: - tooltip = "Low-stakes racing at \x83Gear 1""\x80"". Take a drive and \x83""enjoy the sights!"; + tooltip = "Low-stakes racing at \x83Gear 1""\x80"". \x83No placement requirements\x80."; break; case KARTSPEED_NORMAL: - tooltip = "Aim for the prize at\x82 Gear 2\x80. Can you \x82surpass your limits?"; + tooltip = "Aim for the prize at\x82 Gear 2\x80. Place \x82""4th or better\x80 to advance!"; break; case KARTSPEED_HARD: tooltip = "Challenge fierce competition at\x87 Gear 3\x80. For\x87 thrill-seekers!"; From eba0f22e46d79008de12c20aa238c59cd3688981 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 16 Jul 2025 05:05:20 -0400 Subject: [PATCH 02/11] Increase minimum-level bot strength, reduce bot EXP leveldown when they are already low level --- src/k_bot.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 5855e52a8..bb4cb3e5c 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -692,7 +692,7 @@ fixed_t K_BotRubberband(const player_t *player) // mechanics adjustments, not from items, so kill some bot speed if they've got bad EXP. if (player->gradingfactor < FRACUNIT && !(player->botvars.rival) && player->botvars.difficulty > 1) { - UINT8 levelreduce = std::min(3, player->botvars.difficulty); // How much to drop the "effective level" of bots that are consistently behind + UINT8 levelreduce = std::min(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); } @@ -704,11 +704,11 @@ fixed_t K_BotRubberband(const player_t *player) if (cv_levelskull.value) difficultyEase = FRACUNIT; - // Lv. 1: x0.65 avg + // Lv. 1: x0.75 avg // Lv. MAX: x1.05 avg const fixed_t rubberBase = Easing_OutSine( difficultyEase, - FRACUNIT * 65 / 100, + FRACUNIT * 75 / 100, FRACUNIT * 105 / 100 ); From e7b4ce1994759eb08561a70d5c4ee93710b1f794 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 16 Jul 2025 16:04:23 -0400 Subject: [PATCH 03/11] 90cc G1 --- src/k_kart.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index d88128a40..2d9c8cffc 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -533,6 +533,14 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value) fixed_t base = ((13 + (3*value)) << FRACBITS) / 16; fixed_t duel = overtimecheckpoints*(1<kartweight) * maxmetabolismincrease / 8); + fixed_t metabolism = FRACUNIT - ((9-player->kartweight) * maxmetabolismincrease / 8); + + if (gamespeed == KARTSPEED_EASY && gametype != GT_TUTORIAL) + metabolism *= 2; + fixed_t boostpower = FRACUNIT; fixed_t speedboost = 0, accelboost = 0, handleboost = 0; From af054d47861e68848f82f302fe81a2d6ff8f812b Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 16 Jul 2025 16:19:25 -0400 Subject: [PATCH 04/11] Crazier Relaxed ranknudge --- src/k_grandprix.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index 1dac5a69a..58a42dde2 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -648,17 +648,17 @@ void K_IncreaseBotDifficulty(player_t *bot) rankNudge = -4; break; case GRADE_D: - rankNudge = -3; - break; - case GRADE_C: rankNudge = -2; break; - case GRADE_B: + case GRADE_C: rankNudge = -1; break; - case GRADE_A: + case GRADE_B: rankNudge = 0; break; + case GRADE_A: + rankNudge = 1; + break; } } From ee1d571c08bb0a01a5c3336eacc9fd64ed5d1fff Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 04:23:35 -0400 Subject: [PATCH 05/11] Fix life tally notifications in Relaxed --- src/k_tally.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_tally.cpp b/src/k_tally.cpp index bfbc64dbb..1a8a19087 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -618,7 +618,7 @@ boolean level_tally_t::IncrementLine(void) value = &displayStat[i]; lives_check = ( - grandprixinfo.gamespeed != KARTSPEED_EASY + G_GametypeUsesLives() && stats[i] == TALLY_STAT_TOTALRINGS // Rings also shows the Lives. && livesAdded < owner->xtralife // Don't check if we've maxxed out! ); @@ -850,6 +850,7 @@ void level_tally_t::Tick(void) if (IncrementLine() == true) { if (grandprixinfo.gp == true // In GP + && G_GametypeUsesLives() && lines >= lineCount // Finished the bonuses && livesAdded < owner->xtralife // Didn't max out by other causes ) From efeee381f8d5c00b84bf2df9a6d917dee531fa83 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 04:32:01 -0400 Subject: [PATCH 06/11] Slightly reduce high strength boosts in G1 race --- src/k_kart.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 2d9c8cffc..f35071fb2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3558,10 +3558,14 @@ static void K_GetKartBoostPower(player_t *player) // Light weights have stronger boost stacking -- aka, better metabolism than heavies XD const fixed_t maxmetabolismincrease = FRACUNIT/2; fixed_t metabolism = FRACUNIT - ((9-player->kartweight) * maxmetabolismincrease / 8); + fixed_t softboostcap = 0; + fixed_t boostcapfactor = 3*FRACUNIT/4; if (gamespeed == KARTSPEED_EASY && gametype != GT_TUTORIAL) + { metabolism *= 2; - + softboostcap = FRACUNIT/2; + } fixed_t boostpower = FRACUNIT; fixed_t speedboost = 0, accelboost = 0, handleboost = 0; @@ -3870,6 +3874,13 @@ static void K_GetKartBoostPower(player_t *player) player->boostpower = boostpower; + // G1 race: Reduce high boosts + if (softboostcap && speedboost > softboostcap) + { + fixed_t leftover = speedboost - softboostcap; + speedboost = softboostcap + FixedMul(leftover, boostcapfactor); + } + // value smoothing if (speedboost > player->speedboost) { From 3bb5fe092df376729015160d59038de858ba6ca6 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 04:41:01 -0400 Subject: [PATCH 07/11] Half bot amp rewards and startboost duration in GP --- src/k_kart.c | 3 +++ src/p_spec.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index f35071fb2..388fcfedb 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4270,6 +4270,9 @@ boolean K_PvPAmpReward(UINT32 award, player_t *attacker, player_t *defender) award -= (delta * award / range / 2); } + if (!K_PlayerUsesBotMovement(attacker) && K_PlayerUsesBotMovement(defender)) + award /= 2; + return award; } diff --git a/src/p_spec.c b/src/p_spec.c index e4f3285b6..7e2300653 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -55,6 +55,7 @@ #include "k_battle.h" // battleprisons #include "k_endcam.h" // K_EndCameraIsFreezing() #include "k_race.h" // K_SpawnFinishEXP +#include "k_grandprix.h" // grandprixinfo // Not sure if this is necessary, but it was in w_wad.c, so I'm putting it here too -Shadow Hog #include @@ -2075,7 +2076,7 @@ static void K_HandleLapIncrement(player_t *player) else { S_StartSound(player->mo, sfx_s23c); - player->startboost = 125; + player->startboost = (grandprixinfo.gp ? 60 : 125); K_SpawnDriftBoostExplosion(player, 4); K_SpawnDriftElectricSparks(player, SKINCOLOR_SILVER, false); From 61663ec89edb09bd7aee227aa1e51f2fd0e55b58 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 04:43:33 -0400 Subject: [PATCH 08/11] Only apply nerfed startboost to players --- src/p_spec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_spec.c b/src/p_spec.c index 7e2300653..930b374b9 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2076,7 +2076,9 @@ static void K_HandleLapIncrement(player_t *player) else { S_StartSound(player->mo, sfx_s23c); - player->startboost = (grandprixinfo.gp ? 60 : 125); + player->startboost = 125; + if (!K_PlayerUsesBotMovement(player) && grandprixinfo.gp) + player->startboost /= 2; K_SpawnDriftBoostExplosion(player, 4); K_SpawnDriftElectricSparks(player, SKINCOLOR_SILVER, false); From a0cd78eb7af0b2acd6e0f82da2e26304481e2755 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 15:40:24 -0400 Subject: [PATCH 09/11] Disable instant last place explode in Relaxed --- src/p_inter.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p_inter.c b/src/p_inter.c index 8b3e6e25a..fd874f23a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1612,6 +1612,10 @@ boolean P_CheckRacers(void) const boolean griefed = (spectateGriefed > 0); boolean eliminateLast = (!K_CanChangeRules(true) || (cv_karteliminatelast.value != 0)); + + if (grandprixinfo.gp && grandprixinfo.gamespeed == KARTSPEED_EASY) + eliminateLast = false; + boolean allHumansDone = true; //boolean allBotsDone = true; From c95add2f55f6febf2d66fd9a8a93e0700e5426cc Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 16:02:28 -0400 Subject: [PATCH 10/11] Fix intermission music when not skipping tally under Relaxed --- src/p_user.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index bf8baf3df..e0fdb270c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -716,7 +716,8 @@ void P_EndingMusic(void) { jingle = "_lose"; - if (G_GametypeAllowsRetrying() == true) + // Sort of ugly, this composite check is effictively "does gametype force retry": Relaxed allows you to place low. + if (G_GametypeAllowsRetrying() == true && !(grandprixinfo.gp && grandprixinfo.gamespeed == KARTSPEED_EASY && gametyperules & GTR_CIRCUIT)) { // A retry will be happening nointer = true; From 043969015bc079fc21d001568eaf7542ca0444de Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 18 Jul 2025 20:08:55 -0400 Subject: [PATCH 11/11] Don't roll expert items in G1 --- src/k_roulette.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/k_roulette.c b/src/k_roulette.c index 88eaec7d4..5834519e2 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1152,6 +1152,10 @@ static boolean K_ShouldPlayerAllowItem(kartitems_t item, const player_t *player) if (K_EffectiveGradingFactor(player) < K_RequiredXPForItem(item)) return false; + // Expert items are G2+ only, no Top in Relaxed! + if (K_RequiredXPForItem(item) >= FRACUNIT && gamespeed == KARTSPEED_EASY) + return false; + return !K_IsItemFirstOnly(item); } }