From 2459affaa37084a114a2add7cd33cfd87ac36747 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sat, 7 Jun 2025 15:21:58 -0400 Subject: [PATCH 01/19] GP refinements --- src/g_game.c | 11 ++++++++++- src/k_grandprix.cpp | 4 +--- src/k_podium.cpp | 15 +++++++++++---- src/k_rank.h | 1 + src/p_saveg.cpp | 2 ++ 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 850bdace5..b8f4d7725 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1905,17 +1905,22 @@ void G_Ticker(boolean run) && grandprixinfo.gp == true && grandprixinfo.masterbots == false) { - UINT8 bot_level_decrease = 3; + UINT8 bot_level_decrease = 2; + UINT8 min_lvl = 5; if (grandprixinfo.gamespeed == KARTSPEED_EASY) { bot_level_decrease++; + min_lvl = 1; } else if (grandprixinfo.gamespeed == KARTSPEED_HARD) { bot_level_decrease--; + min_lvl = 9; } + boolean already_min_lvl = (players[i].botvars.difficulty >= min_lvl); + if (players[i].botvars.difficulty <= bot_level_decrease) { players[i].botvars.difficulty = 1; @@ -1924,6 +1929,9 @@ void G_Ticker(boolean run) { players[i].botvars.difficulty -= bot_level_decrease; } + + if (already_min_lvl) + players[i].botvars.difficulty = max(players[i].botvars.difficulty, min_lvl); } else { @@ -5852,6 +5860,7 @@ void G_SetRetryFlag(void) if (retrying == false && grandprixinfo.gp) { grandprixinfo.rank.continuesUsed++; + grandprixinfo.rank.levels[grandprixinfo.rank.numLevels].continues++; } retrying = true; diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index 24a197f39..a636b5896 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -611,12 +611,10 @@ void K_IncreaseBotDifficulty(player_t *bot) switch(averageRank) { case GRADE_E: - rankNudge = -2; - break; case GRADE_D: + case GRADE_C: rankNudge = -1; break; - case GRADE_C: case GRADE_B: rankNudge = 0; break; diff --git a/src/k_podium.cpp b/src/k_podium.cpp index 9797f58ba..603de82dc 100644 --- a/src/k_podium.cpp +++ b/src/k_podium.cpp @@ -188,6 +188,10 @@ void podiumData_s::Init(void) lvl->time = M_RandomRange(50*TICRATE, 210*TICRATE); + lvl->continues = 0; + if (!M_RandomRange(0, 2)) + lvl->continues = M_RandomRange(1, 3); + for (INT32 j = 0; j < rank.numPlayers; j++) { gpRank_level_perplayer_t *const dta = &lvl->perPlayer[j]; @@ -633,10 +637,13 @@ void podiumData_s::Draw(void) if (lvl->event != GPEVENT_SPECIAL && dta->grade != GRADE_INVALID) { - drawer_rank - .xy(0, -1) - .colormap( static_cast(K_GetGradeColor(dta->grade)) ) - .patch(va("R_CUPRN%c", K_GetGradeChar(dta->grade))); + if (lvl->continues) + drawer_rank.xy(2, 1).font(srb2::Draw::Font::kPing).colorize(SKINCOLOR_RED).text(va("-%d", lvl->continues)); + else + drawer_rank + .xy(0, -1) + .colormap( static_cast(K_GetGradeColor(dta->grade)) ) + .patch(va("R_CUPRN%c", K_GetGradeChar(dta->grade))); } // Do not draw any stats for GAME OVERed player diff --git a/src/k_rank.h b/src/k_rank.h index 4f36d12df..e801da037 100644 --- a/src/k_rank.h +++ b/src/k_rank.h @@ -34,6 +34,7 @@ struct gpRank_level_t UINT32 time; UINT16 totalExp; UINT16 totalPrisons; + UINT16 continues; gpRank_level_perplayer_t perPlayer[MAXSPLITSCREENPLAYERS]; }; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 5bdd0e338..f00daaac8 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -6416,6 +6416,7 @@ static inline void P_ArchiveMisc(savebuffer_t *save) WRITEUINT32(save->p, lvl->time); WRITEUINT16(save->p, lvl->totalExp); WRITEUINT16(save->p, lvl->totalPrisons); + WRITEUINT16(save->p, lvl->continues); UINT8 j; for (j = 0; j < rank->numPlayers; j++) @@ -6704,6 +6705,7 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save) lvl->time = READUINT32(save->p); lvl->totalExp = READUINT16(save->p); lvl->totalPrisons = READUINT16(save->p); + lvl->continues = READUINT16(save->p); for (j = 0; j < rank->numPlayers; j++) { From cd439be74c02470457df53e904825827b1b64dbb Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sat, 7 Jun 2025 17:49:11 -0400 Subject: [PATCH 02/19] Bot difficulty and grading tweaks --- src/d_player.h | 2 +- src/g_demo.cpp | 8 ++++---- src/g_game.c | 2 +- src/k_bot.cpp | 2 ++ src/k_grandprix.cpp | 50 ++++++++++++++++++++++++++++++--------------- src/k_rank.h | 4 ++-- src/k_tally.cpp | 2 +- 7 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 96af19f80..f968ae6ec 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -402,7 +402,7 @@ struct botvars_t botStyle_e style; // Training mode-style CPU mode UINT8 difficulty; // Bot's difficulty setting - UINT8 diffincrease; // In GP: bot difficulty will increase this much next round + INT16 diffincrease; // In GP: bot difficulty will increase this much next round boolean rival; // If true, they're the GP rival // All entries above persist between rounds and must be recorded in demos diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 05a881ace..172309016 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -319,7 +319,7 @@ void G_ReadDemoExtraData(void) if (players[p].bot) { players[p].botvars.difficulty = READUINT8(demobuf.p); - players[p].botvars.diffincrease = READUINT8(demobuf.p); // needed to avoid having to duplicate logic + players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic players[p].botvars.rival = (boolean)READUINT8(demobuf.p); } } @@ -495,7 +495,7 @@ void G_WriteDemoExtraData(void) if (players[i].bot) { WRITEUINT8(demobuf.p, players[i].botvars.difficulty); - WRITEUINT8(demobuf.p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic + WRITEINT16(demobuf.p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic WRITEUINT8(demobuf.p, (UINT8)players[i].botvars.rival); } } @@ -2109,7 +2109,7 @@ void G_BeginRecording(void) if (i & DEMO_BOT) { WRITEUINT8(demobuf.p, player->botvars.difficulty); - WRITEUINT8(demobuf.p, player->botvars.diffincrease); // needed to avoid having to duplicate logic + WRITEINT16(demobuf.p, player->botvars.diffincrease); // needed to avoid having to duplicate logic WRITEUINT8(demobuf.p, (UINT8)player->botvars.rival); } @@ -3220,7 +3220,7 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum) if ((players[p].bot = bot) == true) { players[p].botvars.difficulty = READUINT8(demobuf.p); - players[p].botvars.diffincrease = READUINT8(demobuf.p); // needed to avoid having to duplicate logic + players[p].botvars.diffincrease = READINT16(demobuf.p); // needed to avoid having to duplicate logic players[p].botvars.rival = (boolean)READUINT8(demobuf.p); } diff --git a/src/g_game.c b/src/g_game.c index b8f4d7725..67bea359a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2265,7 +2265,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT16 steering; angle_t playerangleturn; - UINT8 botdiffincrease; + INT16 botdiffincrease; boolean botrival; boolean cangrabitems; diff --git a/src/k_bot.cpp b/src/k_bot.cpp index d9d91a134..516021966 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -117,6 +117,8 @@ void K_SetBot(UINT8 newplayernum, UINT8 skinnum, UINT8 difficulty, botStyle_e st playernode[newplayernum] = servernode; + CONS_Printf("addbot diff %d\n", difficulty); + // this will permit unlocks memcpy(&players[newplayernum].availabilities, R_GetSkinAvailabilities(false, skinnum), MAXAVAILABILITY*sizeof(UINT8)); diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index a636b5896..a96f7b977 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -90,6 +90,14 @@ UINT8 K_GetGPPlayerCount(UINT8 humans) return std::clamp(humans * 4, 8, MAXPLAYERS); } +// Kind of hate unsigned types +static UINT8 K_GetOffsetStartingDifficulty(const UINT8 startingdifficulty, UINT8 offset) +{ + if (offset >= startingdifficulty) + return 1; + return startingdifficulty - offset; +} + /*-------------------------------------------------- void K_InitGrandPrixBots(void) @@ -139,22 +147,22 @@ void K_InitGrandPrixBots(void) else { // init difficulty levels list - difficultylevels[ 0] = std::max(1, startingdifficulty); - difficultylevels[ 1] = std::max(1, startingdifficulty-1); - difficultylevels[ 2] = std::max(1, startingdifficulty-2); - difficultylevels[ 3] = std::max(1, startingdifficulty-3); - difficultylevels[ 4] = std::max(1, startingdifficulty-3); - difficultylevels[ 5] = std::max(1, startingdifficulty-4); - difficultylevels[ 6] = std::max(1, startingdifficulty-4); - difficultylevels[ 7] = std::max(1, startingdifficulty-4); - difficultylevels[ 8] = std::max(1, startingdifficulty-5); - difficultylevels[ 9] = std::max(1, startingdifficulty-5); - difficultylevels[10] = std::max(1, startingdifficulty-5); - difficultylevels[11] = std::max(1, startingdifficulty-6); - difficultylevels[12] = std::max(1, startingdifficulty-6); - difficultylevels[13] = std::max(1, startingdifficulty-7); - difficultylevels[14] = std::max(1, startingdifficulty-7); - difficultylevels[15] = std::max(1, startingdifficulty-8); + difficultylevels[ 0] = startingdifficulty; + difficultylevels[ 1] = K_GetOffsetStartingDifficulty(startingdifficulty, 1); + difficultylevels[ 2] = K_GetOffsetStartingDifficulty(startingdifficulty, 2); + difficultylevels[ 3] = K_GetOffsetStartingDifficulty(startingdifficulty, 3); + difficultylevels[ 4] = K_GetOffsetStartingDifficulty(startingdifficulty, 3); + difficultylevels[ 5] = K_GetOffsetStartingDifficulty(startingdifficulty, 4); + difficultylevels[ 6] = K_GetOffsetStartingDifficulty(startingdifficulty, 4); + difficultylevels[ 7] = K_GetOffsetStartingDifficulty(startingdifficulty, 4); + difficultylevels[ 8] = K_GetOffsetStartingDifficulty(startingdifficulty, 5); + difficultylevels[ 9] = K_GetOffsetStartingDifficulty(startingdifficulty, 5); + difficultylevels[10] = K_GetOffsetStartingDifficulty(startingdifficulty, 5); + difficultylevels[11] = K_GetOffsetStartingDifficulty(startingdifficulty, 6); + difficultylevels[12] = K_GetOffsetStartingDifficulty(startingdifficulty, 6); + difficultylevels[13] = K_GetOffsetStartingDifficulty(startingdifficulty, 7); + difficultylevels[14] = K_GetOffsetStartingDifficulty(startingdifficulty, 7); + difficultylevels[15] = K_GetOffsetStartingDifficulty(startingdifficulty, 8); } for (i = 0; i < MAXPLAYERS; i++) @@ -381,13 +389,19 @@ void K_UpdateGrandPrixBots(void) if (players[i].botvars.diffincrease) { - players[i].botvars.difficulty += 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); + else + players[i].botvars.difficulty += players[i].botvars.diffincrease; if (players[i].botvars.difficulty > MAXBOTDIFFICULTY) { players[i].botvars.difficulty = MAXBOTDIFFICULTY; } + CONS_Printf(" out %d\n", players[i].botvars.difficulty); + players[i].botvars.diffincrease = 0; } @@ -628,6 +642,8 @@ void K_IncreaseBotDifficulty(player_t *bot) increase += rankNudge; + CONS_Printf("raising %d by %d - %d\n", bot->botvars.difficulty, increase, bot->botvars.difficulty + increase); + if (increase <= 0) { // TYRON: We want to allow SMALL bot rank downs if a player gets rolled but still squeaks by. diff --git a/src/k_rank.h b/src/k_rank.h index e801da037..aa28727e3 100644 --- a/src/k_rank.h +++ b/src/k_rank.h @@ -96,8 +96,8 @@ extern "C" { #define RANK_WEIGHT_PRISONS (100) #define RANK_WEIGHT_RINGS (50) -#define RANK_CONTINUE_PENALTY_DIV (20) // 5% of the total grade -#define RANK_CONTINUE_PENALTY_START (2) +#define RANK_CONTINUE_PENALTY_DIV (10) // 10% of the total grade +#define RANK_CONTINUE_PENALTY_START (0) /*-------------------------------------------------- void K_InitGrandPrixRank(gpRank_t *rankData); diff --git a/src/k_tally.cpp b/src/k_tally.cpp index fd407e360..e23b0ee31 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -247,7 +247,7 @@ INT32 level_tally_t::CalculateGrade(void) case TALLY_BONUS_EXP: { const fixed_t frac = std::min(FRACUNIT, ((exp-15) * FRACUNIT) / std::max(1, static_cast(totalExp))); - ours += Easing_Linear(frac, 0, bonusWeights[i]); + ours += Easing_InQuint(frac, 0, bonusWeights[i]); break; } case TALLY_BONUS_PRISON: From 0f500ac0c6fba3f840cd3082fd8ec672aec25b73 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sat, 7 Jun 2025 17:52:51 -0400 Subject: [PATCH 03/19] Remove debug print --- src/k_bot.cpp | 2 -- src/k_grandprix.cpp | 5 ----- 2 files changed, 7 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 516021966..d9d91a134 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -117,8 +117,6 @@ void K_SetBot(UINT8 newplayernum, UINT8 skinnum, UINT8 difficulty, botStyle_e st playernode[newplayernum] = servernode; - CONS_Printf("addbot diff %d\n", difficulty); - // this will permit unlocks memcpy(&players[newplayernum].availabilities, R_GetSkinAvailabilities(false, skinnum), MAXAVAILABILITY*sizeof(UINT8)); diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index a96f7b977..004ae6013 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -389,7 +389,6 @@ 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); else @@ -400,8 +399,6 @@ void K_UpdateGrandPrixBots(void) players[i].botvars.difficulty = MAXBOTDIFFICULTY; } - CONS_Printf(" out %d\n", players[i].botvars.difficulty); - players[i].botvars.diffincrease = 0; } @@ -642,8 +639,6 @@ void K_IncreaseBotDifficulty(player_t *bot) increase += rankNudge; - CONS_Printf("raising %d by %d - %d\n", bot->botvars.difficulty, increase, bot->botvars.difficulty + increase); - if (increase <= 0) { // TYRON: We want to allow SMALL bot rank downs if a player gets rolled but still squeaks by. From 33a24accda56e24e0e8fae0acfbe9b73785d338b Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sat, 7 Jun 2025 21:27:00 -0400 Subject: [PATCH 04/19] Softer EXP easing curve, cap bot modifier because Darkvile 1 is beating my ass --- src/k_bot.cpp | 5 ++--- src/k_tally.cpp | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index d9d91a134..cb037dfd8 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -581,9 +581,8 @@ const botcontroller_t *K_GetBotController(const mobj_t *mobj) fixed_t K_BotMapModifier(void) { constexpr INT32 complexity_scale = 10000; - fixed_t modifier_max = FRACUNIT * 2; - fixed_t modifier_min = 3 * FRACUNIT / 10; - modifier_min -= FRACUNIT; + fixed_t modifier_max = (9 * FRACUNIT / 10) - FRACUNIT; + fixed_t modifier_min = (3 * FRACUNIT / 10) - FRACUNIT; const fixed_t complexity_value = std::clamp( FixedDiv(K_GetTrackComplexity(), complexity_scale), diff --git a/src/k_tally.cpp b/src/k_tally.cpp index e23b0ee31..b6f339989 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -246,8 +246,8 @@ INT32 level_tally_t::CalculateGrade(void) } case TALLY_BONUS_EXP: { - const fixed_t frac = std::min(FRACUNIT, ((exp-15) * FRACUNIT) / std::max(1, static_cast(totalExp))); - ours += Easing_InQuint(frac, 0, bonusWeights[i]); + const fixed_t frac = std::min(FRACUNIT, ((exp) * FRACUNIT) / std::max(1, static_cast(totalExp))); + ours += Easing_InCubic(frac, 0, bonusWeights[i]); break; } case TALLY_BONUS_PRISON: From a3c387abc52b2c1f33a769da183ca77b85f062e0 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 8 Jun 2025 00:41:45 -0400 Subject: [PATCH 05/19] Back to quint, weeee --- src/k_tally.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_tally.cpp b/src/k_tally.cpp index b6f339989..8a855f909 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -247,7 +247,7 @@ INT32 level_tally_t::CalculateGrade(void) case TALLY_BONUS_EXP: { const fixed_t frac = std::min(FRACUNIT, ((exp) * FRACUNIT) / std::max(1, static_cast(totalExp))); - ours += Easing_InCubic(frac, 0, bonusWeights[i]); + ours += Easing_InQuint(frac, 0, bonusWeights[i]); break; } case TALLY_BONUS_PRISON: From 7c1df623ae201c464fd66407a3846f238c13f2fb Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 10 Jun 2025 13:29:55 -0400 Subject: [PATCH 06/19] Podium: display continues on special, transparent grade icon below continues --- src/k_podium.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/k_podium.cpp b/src/k_podium.cpp index 603de82dc..7ce1eaef0 100644 --- a/src/k_podium.cpp +++ b/src/k_podium.cpp @@ -637,15 +637,15 @@ void podiumData_s::Draw(void) if (lvl->event != GPEVENT_SPECIAL && dta->grade != GRADE_INVALID) { - if (lvl->continues) - drawer_rank.xy(2, 1).font(srb2::Draw::Font::kPing).colorize(SKINCOLOR_RED).text(va("-%d", lvl->continues)); - else drawer_rank - .xy(0, -1) + .xy(0, -1).flags(lvl->continues ? V_TRANSLUCENT : 0) .colormap( static_cast(K_GetGradeColor(dta->grade)) ) .patch(va("R_CUPRN%c", K_GetGradeChar(dta->grade))); } + if (lvl->continues) + drawer_rank.xy(7, 1).align(srb2::Draw::Align::kCenter).font(srb2::Draw::Font::kPing).colorize(SKINCOLOR_RED).text(va("-%d", lvl->continues)); + // Do not draw any stats for GAME OVERed player if (dta->grade != GRADE_INVALID || lvl->event == GPEVENT_SPECIAL) { From 2a36838b540844d15c05409b643978efaf9bce65 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Thu, 12 Jun 2025 00:09:44 -0400 Subject: [PATCH 07/19] grading refinements attempt --- src/doomdef.h | 6 ++++-- src/k_kart.c | 4 ++-- src/k_podium.cpp | 52 +++++++++++++++++++++++++++++++++++++++++------- src/k_tally.cpp | 8 ++++---- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index b62f44472..3ff5c274b 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -745,9 +745,11 @@ extern int #define MAXAMPSCALINGDIST 18000 // Exp +#define EXP_STABLERATE 3*FRACUNIT/10 // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain +#define EXP_POWER 3*FRACUNIT/100 // adjust to change overall xp volatility #define MINEXP 25 // The min value target -#define TARGETEXP 100 // The target value needed for A rank -#define MAXEXP 125 // The max value displayed by the hud and in the tally screen and GP results screen +#define TARGETEXP 120 // Used for grading ... +#define MAXEXP 120 // The max value displayed by the hud and in the tally screen and GP results screen #ifdef __cplusplus } // extern "C" diff --git a/src/k_kart.c b/src/k_kart.c index 8a1a6869a..afe184910 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -15739,8 +15739,8 @@ boolean K_PlayerCanUseItem(player_t *player) fixed_t K_GetGradingFactorAdjustment(player_t *player) { - fixed_t power = 3*FRACUNIT/100; // adjust to change overall xp volatility - fixed_t stablerate = 3*FRACUNIT/10; // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain + fixed_t power = EXP_POWER; // adjust to change overall xp volatility + const fixed_t stablerate = EXP_STABLERATE; // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain fixed_t result = 0; if (g_teamplay) diff --git a/src/k_podium.cpp b/src/k_podium.cpp index 7ce1eaef0..d3ee64205 100644 --- a/src/k_podium.cpp +++ b/src/k_podium.cpp @@ -723,10 +723,28 @@ void podiumData_s::Draw(void) .xy(0, 1) .colorize(static_cast(SKINCOLOR_MUSTARD)) .patch("K_SPTEXP"); + // Colorize the crystal, just like we do for hud - fixed_t factor = FixedDiv(dta->exp*FRACUNIT, lvl->totalExp*FRACUNIT); - skincolornum_t overlaycolor = factor < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE; - if (factor >= FRACUNIT) {factor += factor-FRACUNIT;} // exaggerate the positive side, since reverse engineering the factor like this results in half the translucency range + skincolornum_t overlaycolor = SKINCOLOR_MUSTARD; + fixed_t stablerateinverse = FRACUNIT - EXP_STABLERATE; + INT16 exp_range = MAXEXP-MINEXP; + INT16 exp_offset = dta->exp-MINEXP; + fixed_t factor = (exp_offset*FRACUNIT) / exp_range; // 0.0 to 1.0 in fixed + // amount of blue is how much factor is above EXP_STABLERATE, and amount of red is how much factor is below + // assume that EXP_STABLERATE is within 0.0 to 1.0 in fixed + if (factor <= stablerateinverse) + { + overlaycolor = SKINCOLOR_RUBY; + factor = FixedDiv(factor, stablerateinverse); + } + else + { + overlaycolor = SKINCOLOR_ULTRAMARINE; + fixed_t bluemaxoffset = EXP_STABLERATE; + factor = factor - stablerateinverse; + factor = FRACUNIT - FixedDiv(factor, bluemaxoffset); + } + auto transflag = K_GetTransFlagFromFixed(factor); drawer_gametype .xy(0, 1) @@ -872,12 +890,32 @@ void podiumData_s::Draw(void) drawer_totals_right .colorize(static_cast(SKINCOLOR_MUSTARD)) .patch("K_STEXP"); + // Colorize the crystal for the totals, just like we do for in race hud - fixed_t factor = FixedDiv((rank.exp+(35*rank.numPlayers-1))*FRACUNIT, rank.totalExp*FRACUNIT); // bump the calc a bit, because its probably not possible for every human to get 125 on every race - skincolornum_t overlaycolor = factor < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE; - if (factor >= FRACUNIT) {factor += factor-FRACUNIT;} // exaggerate the positive side, since reverse engineering the factor like this results in half the translucency range + fixed_t extraexpfactor = (MAXEXP*FRACUNIT) / TARGETEXP; + INT16 totalExpMax = FixedMul(rank.totalExp*FRACUNIT, extraexpfactor) / FRACUNIT; // im just going to calculate it from target lol + INT16 totalExpMin = rank.numPlayers*MINEXP; + skincolornum_t overlaycolor = SKINCOLOR_MUSTARD; + fixed_t stablerateinverse = FRACUNIT - EXP_STABLERATE; + INT16 exp_range = totalExpMax-totalExpMin; + INT16 exp_offset = rank.exp-totalExpMin; + fixed_t factor = (exp_offset*FRACUNIT) / exp_range; // 0.0 to 1.0 in fixed + // amount of blue is how much factor is above EXP_STABLERATE, and amount of red is how much factor is below + // assume that EXP_STABLERATE is within 0.0 to 1.0 in fixed + if (factor <= stablerateinverse) + { + overlaycolor = SKINCOLOR_RUBY; + factor = FixedDiv(factor, stablerateinverse); + } + else + { + overlaycolor = SKINCOLOR_ULTRAMARINE; + fixed_t bluemaxoffset = EXP_STABLERATE; + factor = factor - stablerateinverse; + factor = FRACUNIT - FixedDiv(factor, bluemaxoffset); + } + auto transflag = K_GetTransFlagFromFixed(factor); - drawer_totals_right .colorize(static_cast(overlaycolor)) .flags(transflag) diff --git a/src/k_tally.cpp b/src/k_tally.cpp index 8a855f909..379986c92 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -204,14 +204,14 @@ INT32 level_tally_t::CalculateGrade(void) } case TALLY_BONUS_SCORE: { - bonusWeights[i] = ((pointLimit != 0) ? 100 : 0); + bonusWeights[i] = ((pointLimit != 0) ? 200 : 0); break; } case TALLY_BONUS_EXP: case TALLY_BONUS_PRISON: case TALLY_BONUS_POWERSTONES: { - bonusWeights[i] = 150; + bonusWeights[i] = 300; break; } default: @@ -222,7 +222,7 @@ INT32 level_tally_t::CalculateGrade(void) } } - const INT32 positionWeight = (position > 0 && numPlayers > 2) ? 20 : 0; + const INT32 positionWeight = (position > 0 && numPlayers > 2) ? 50 : 0; const INT32 total = positionWeight + bonusWeights[0] + bonusWeights[1]; INT32 ours = 0; @@ -247,7 +247,7 @@ INT32 level_tally_t::CalculateGrade(void) case TALLY_BONUS_EXP: { const fixed_t frac = std::min(FRACUNIT, ((exp) * FRACUNIT) / std::max(1, static_cast(totalExp))); - ours += Easing_InQuint(frac, 0, bonusWeights[i]); + ours += Easing_Linear(frac, 0, bonusWeights[i]); break; } case TALLY_BONUS_PRISON: From f418b5841a9495bf8bad59e1e21f9d502a36ce4e Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 16 Jun 2025 15:50:34 -0400 Subject: [PATCH 08/19] Minimum gradingfactor in Master --- src/k_bot.cpp | 5 ++--- src/k_hud.cpp | 8 ++++---- src/k_kart.c | 9 ++++++++- src/k_kart.h | 3 +++ src/k_roulette.c | 4 ++-- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index cb037dfd8..c775efbfb 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 = (9 * FRACUNIT / 10) - FRACUNIT; - fixed_t modifier_min = (3 * FRACUNIT / 10) - FRACUNIT; + fixed_t modifier_min = (5 * FRACUNIT / 10) - FRACUNIT; const fixed_t complexity_value = std::clamp( FixedDiv(K_GetTrackComplexity(), complexity_scale), @@ -685,8 +685,7 @@ fixed_t K_BotRubberband(const player_t *player) 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); + expreduce = Easing_Linear((K_EffectiveGradingFactor(player) - MINGRADINGFACTOR) * 2, levelreduce*FRACUNIT, 0); } fixed_t difficultyEase = (((player->botvars.difficulty - 1) * FRACUNIT) - expreduce) / (MAXBOTDIFFICULTY - 1); diff --git a/src/k_hud.cpp b/src/k_hud.cpp index d36d74169..3362e8d26 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -4037,8 +4037,8 @@ static boolean K_drawKartLaps(void) // WHAT IS THIS? // WHAT ARE YOU FUCKING TALKING ABOUT? V_DrawMappedPatch(fr, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[1], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MUSTARD, GTC_CACHE)); - auto transflag = K_GetTransFlagFromFixed(stplyr->gradingfactor); - skincolornum_t overlaycolor = stplyr->gradingfactor < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ; + auto transflag = K_GetTransFlagFromFixed(K_EffectiveGradingFactor(stplyr)); + skincolornum_t overlaycolor = K_EffectiveGradingFactor(stplyr) < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ; auto colormap = R_GetTranslationColormap(TC_RAINBOW, overlaycolor, GTC_CACHE); V_DrawMappedPatch(fr, fy, transflag|V_SLIDEIN|splitflags, kp_exp[1], colormap); @@ -4054,8 +4054,8 @@ static boolean K_drawKartLaps(void) V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[0], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MUSTARD, GTC_CACHE)); - auto transflag = K_GetTransFlagFromFixed(stplyr->gradingfactor); - skincolornum_t overlaycolor = stplyr->gradingfactor < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ; + auto transflag = K_GetTransFlagFromFixed(K_EffectiveGradingFactor(stplyr)); + skincolornum_t overlaycolor = K_EffectiveGradingFactor(stplyr) < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ; auto colormap = R_GetTranslationColormap(TC_RAINBOW, overlaycolor, GTC_CACHE); V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, transflag|V_SLIDEIN|splitflags, kp_exp[0], colormap); diff --git a/src/k_kart.c b/src/k_kart.c index afe184910..d516f8c07 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -124,6 +124,13 @@ boolean K_InRaceDuel(void) return (inDuel && (gametyperules & GTR_CIRCUIT) && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE)) && !specialstageinfo.valid; } +fixed_t K_EffectiveGradingFactor(const player_t *player) +{ + if (grandprixinfo.gp && grandprixinfo.masterbots && !K_PlayerUsesBotMovement(player)) + return MINGRADINGFACTOR; + return max(MINGRADINGFACTOR, player->gradingfactor); +} + player_t *K_DuelOpponent(player_t *player) { if (!K_InRaceDuel()) @@ -13567,7 +13574,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else { UINT32 behind = K_GetItemRouletteDistance(player, player->itemRoulette.playing); - behind = FixedMul(behind, max(player->gradingfactor, FRACUNIT/2)); + behind = FixedMul(behind, K_EffectiveGradingFactor(player)); UINT32 behindMulti = behind / 500; behindMulti = min(behindMulti, 60); award = award * (behindMulti + 10) / 10; diff --git a/src/k_kart.h b/src/k_kart.h index 738513358..99f551c98 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -114,6 +114,9 @@ boolean K_DuelItemAlwaysSpawns(mapthing_t *mt); boolean K_InRaceDuel(void); player_t *K_DuelOpponent(player_t *player); +fixed_t K_EffectiveGradingFactor(const player_t *player); +#define MINGRADINGFACTOR (FRACUNIT/2) + void K_TimerReset(void); void K_TimerInit(void); diff --git a/src/k_roulette.c b/src/k_roulette.c index bba953a64..c5348d108 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -1132,7 +1132,7 @@ static boolean K_ShouldPlayerAllowItem(kartitems_t item, const player_t *player) return false; // GIGA power items reserved only for players who were doing great and died. - if (player->gradingfactor < K_RequiredXPForItem(item)) + if (K_EffectiveGradingFactor(player) < K_RequiredXPForItem(item)) return false; return !K_IsItemFirstOnly(item); @@ -1399,7 +1399,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet if ((gametyperules & GTR_CIRCUIT) && !K_Cooperative()) { - roulette->dist = FixedMul(roulette->preexpdist, max(player->gradingfactor, FRACUNIT/2)); + roulette->dist = FixedMul(roulette->preexpdist, K_EffectiveGradingFactor(player)); } // =============================================================================== From e2122fa3516ad8235854585223fc2baec1af3540 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 16 Jun 2025 17:07:27 -0400 Subject: [PATCH 09/19] Update level continues when restoring GP save --- src/p_saveg.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index f00daaac8..a785fc1b9 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -6431,6 +6431,9 @@ static inline void P_ArchiveMisc(savebuffer_t *save) WRITESINT8(save->p, (SINT8)plr->grade); } } + + const gpRank_level_t *lvl = &rank->levels[rank->numLevels]; + WRITEUINT16(save->p, lvl->continues + 1); } // Marathon information @@ -6719,6 +6722,9 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save) plr->grade = (gp_rank_e)READSINT8(save->p); } } + + gpRank_level_t *const lvl = &rank->levels[rank->numLevels]; + lvl->continues = READUINT16(save->p); } // Marathon information From c5c413e2fe6a6f8f6f48f7885a162099d21596f6 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 16 Jun 2025 18:19:45 -0400 Subject: [PATCH 10/19] Bot WTF --- src/k_bot.cpp | 3 +++ src/k_kart.c | 9 ++++++++- src/p_user.c | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index c775efbfb..44ea1b448 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -580,6 +580,9 @@ const botcontroller_t *K_GetBotController(const mobj_t *mobj) --------------------------------------------------*/ fixed_t K_BotMapModifier(void) { + // fuck it we ball + return 60*FRACUNIT/100; + constexpr INT32 complexity_scale = 10000; fixed_t modifier_max = (9 * FRACUNIT / 10) - FRACUNIT; fixed_t modifier_min = (5 * FRACUNIT / 10) - FRACUNIT; diff --git a/src/k_kart.c b/src/k_kart.c index d516f8c07..606677c1f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13257,10 +13257,17 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) } errorfrict = min(errorfrict, frict/4); + + if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->movefactor < FRACUNIT) + { + // Reduce error friction on low-friction surfaces + errorfrict = FixedMul(errorfrict, player->mo->movefactor); + } + frict -= errorfrict; // Bots gain more traction as they rubberband. - const fixed_t traction_value = FixedMul(player->botvars.rubberband, max(FRACUNIT, K_BotMapModifier())); + const fixed_t traction_value = FixedMul(player->botvars.rubberband, K_BotMapModifier()); if (traction_value > FRACUNIT) { const fixed_t traction_mul = traction_value - FRACUNIT; diff --git a/src/p_user.c b/src/p_user.c index 5859aa916..cea834a94 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2326,6 +2326,11 @@ static void P_UpdatePlayerAngle(player_t *player) // 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; + if (player->botvars.predictionError >= ANGLE_45) + { + // Also slow bots down if they're about to do a weird 90. + player->botvars.bumpslow = TICRATE/2; + } } else if ((!(player->cmd.flags & TICCMD_RECEIVED)) && (!!(player->oldcmd.flags && TICCMD_RECEIVED))) { From a623526ebd1736b5b7866a008a50e002bd890b3c Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 16 Jun 2025 23:56:03 -0400 Subject: [PATCH 11/19] Don't multiapply bumpslow rubberband penalty --- src/k_kart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 606677c1f..cd0744e85 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -15871,7 +15871,8 @@ void K_BotHitPenalty(player_t *player) { if (K_PlayerUsesBotMovement(player)) { - player->botvars.rubberband = max(player->botvars.rubberband/2, FRACUNIT/2); + if (!player->botvars.bumpslow) + player->botvars.rubberband = max(3*player->botvars.rubberband/4, FRACUNIT/2); player->botvars.bumpslow = TICRATE*2; } } From 212ec92e52fc6c8838918040006ed37a61dea838 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 17 Jun 2025 01:35:55 -0400 Subject: [PATCH 12/19] That's not how this fucking works --- src/p_user.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index cea834a94..5859aa916 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2326,11 +2326,6 @@ static void P_UpdatePlayerAngle(player_t *player) // 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; - if (player->botvars.predictionError >= ANGLE_45) - { - // Also slow bots down if they're about to do a weird 90. - player->botvars.bumpslow = TICRATE/2; - } } else if ((!(player->cmd.flags & TICCMD_RECEIVED)) && (!!(player->oldcmd.flags && TICCMD_RECEIVED))) { From ab58b27873e6cd632e6c62c85101f7c9bc4b1d96 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 17 Jun 2025 02:41:29 -0400 Subject: [PATCH 13/19] Go to church friction code --- src/k_bot.cpp | 2 +- src/k_kart.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 44ea1b448..f2e1ad981 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -581,7 +581,7 @@ const botcontroller_t *K_GetBotController(const mobj_t *mobj) fixed_t K_BotMapModifier(void) { // fuck it we ball - return 60*FRACUNIT/100; + return 5*FRACUNIT/10; constexpr INT32 complexity_scale = 10000; fixed_t modifier_max = (9 * FRACUNIT / 10) - FRACUNIT; diff --git a/src/k_kart.c b/src/k_kart.c index cd0744e85..dbd4f05e0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4091,10 +4091,11 @@ fixed_t K_GetNewSpeed(const player_t *player) p_speed = 15 * p_speed / 10; } - if (K_PlayerUsesBotMovement(player) == true && player->botvars.rubberband > 0) + if (K_PlayerUsesBotMovement(player) == true && player->botvars.rubberband > FRACUNIT) { // Acceleration is tied to top speed... // so if we want JUST a top speed boost, we have to do this... + // (But only do it if we're actually boosting from rubberbanding!) p_accel = FixedDiv(p_accel, player->botvars.rubberband); } @@ -13245,6 +13246,7 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. angle_t MAXERROR = ANGLE_45; + angle_t MINERROR = ANGLE_45; fixed_t errorfrict = Easing_Linear(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, FRACUNIT>>2); if (player->currentwaypoint && player->currentwaypoint->mobj) @@ -13264,7 +13266,12 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) errorfrict = FixedMul(errorfrict, player->mo->movefactor); } - frict -= errorfrict; + if (player->botvars.predictionError >= MINERROR) + { + // CONS_Printf("%d: friction was %d, is ", leveltime, frict); + frict -= errorfrict; + // CONS_Printf("%d\n", frict); + } // Bots gain more traction as they rubberband. const fixed_t traction_value = FixedMul(player->botvars.rubberband, K_BotMapModifier()); From a8f326a08e72f3a65ed1afdebb4864bdbddb3840 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 17 Jun 2025 17:01:48 -0400 Subject: [PATCH 14/19] WIP: do bot error friction as friction adjustment instead of base friction --- src/k_bot.cpp | 2 +- src/k_kart.c | 70 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index f2e1ad981..38b481f28 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -581,7 +581,7 @@ const botcontroller_t *K_GetBotController(const mobj_t *mobj) fixed_t K_BotMapModifier(void) { // fuck it we ball - return 5*FRACUNIT/10; + return 10*FRACUNIT/10; constexpr INT32 complexity_scale = 10000; fixed_t modifier_max = (9 * FRACUNIT / 10) - FRACUNIT; diff --git a/src/k_kart.c b/src/k_kart.c index dbd4f05e0..78a6bdd58 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13244,35 +13244,6 @@ 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; - angle_t MINERROR = 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); - - if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->movefactor < FRACUNIT) - { - // Reduce error friction on low-friction surfaces - errorfrict = FixedMul(errorfrict, player->mo->movefactor); - } - - if (player->botvars.predictionError >= MINERROR) - { - // CONS_Printf("%d: friction was %d, is ", leveltime, frict); - frict -= errorfrict; - // CONS_Printf("%d\n", frict); - } - // Bots gain more traction as they rubberband. const fixed_t traction_value = FixedMul(player->botvars.rubberband, K_BotMapModifier()); if (traction_value > FRACUNIT) @@ -13354,6 +13325,47 @@ void K_AdjustPlayerFriction(player_t *player) player->mo->friction = FRACUNIT; } + if (K_PlayerUsesBotMovement(player)) + { + fixed_t frict = 0; + + // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. + angle_t MAXERROR = ANGLE_45; + angle_t MINERROR = 0; + fixed_t errorfrict = Easing_InCubic(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, FRACUNIT>>4); + + 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); + + if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->movefactor < FRACUNIT) + { + // Reduce error friction on low-friction surfaces + errorfrict = FixedMul(errorfrict, player->mo->movefactor); + } + + if (player->botvars.predictionError >= MINERROR) + { + // CONS_Printf("%d: friction was %d, is ", leveltime, frict); + frict -= errorfrict; + // CONS_Printf("%d\n", frict); + } + + player->mo->friction += frict; + } + + /* + if (player->cmd.buttons & BT_ATTACK) + player->mo->friction -= FRACUNIT/2; + */ + // Cap between intended values if (player->mo->friction > FRACUNIT) player->mo->friction = FRACUNIT; From af99764a468f8ac4f223aa96e6ee29a9346e6fc3 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 17 Jun 2025 17:57:06 -0400 Subject: [PATCH 15/19] WIP: Adjust speed caps when base friction is high --- src/k_kart.c | 79 +++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 78a6bdd58..8275507ea 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4099,10 +4099,17 @@ fixed_t K_GetNewSpeed(const player_t *player) p_accel = FixedDiv(p_accel, player->botvars.rubberband); } + // WEIRD! Adjust speed cap when base friction is grippy (bots only), to make sure + // they don't drive really, really fast when we try to give them extra grip. + fixed_t frictiondelta = FRACUNIT + K_PlayerBaseFriction(player, ORIG_FRICTION) - ORIG_FRICTION; + fixed_t p_speed_cap = p_speed; + if (frictiondelta < FRACUNIT) + p_speed_cap = FixedMul(frictiondelta, p_speed); + oldspeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); // Don't calculate the acceleration as ever being above top speed - if (oldspeed > p_speed) - oldspeed = p_speed; + if (oldspeed > p_speed_cap) + oldspeed = p_speed_cap; newspeed = FixedDiv(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), K_PlayerBaseFriction(player, ORIG_FRICTION)); finalspeed = newspeed - oldspeed; @@ -13254,6 +13261,38 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) } } + // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. + angle_t MAXERROR = ANGLE_45; + angle_t MINERROR = 0; + fixed_t errorfrict = Easing_InCubic(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); + + if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->movefactor < FRACUNIT) + { + // Reduce error friction on low-friction surfaces + errorfrict = FixedMul(errorfrict, player->mo->movefactor); + } + + if (player->botvars.predictionError >= MINERROR) + { + // CONS_Printf("%d: friction was %d, is ", leveltime, frict); + frict -= errorfrict; + // CONS_Printf("%d\n", frict); + } + + if (player->cmd.buttons & BT_VOTE && false) + frict -= FRACUNIT/2; + if (frict > FRACUNIT) { frict = FRACUNIT; } if (frict < 0) { frict = 0; } @@ -13325,42 +13364,6 @@ void K_AdjustPlayerFriction(player_t *player) player->mo->friction = FRACUNIT; } - if (K_PlayerUsesBotMovement(player)) - { - fixed_t frict = 0; - - // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. - angle_t MAXERROR = ANGLE_45; - angle_t MINERROR = 0; - fixed_t errorfrict = Easing_InCubic(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, FRACUNIT>>4); - - 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); - - if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->movefactor < FRACUNIT) - { - // Reduce error friction on low-friction surfaces - errorfrict = FixedMul(errorfrict, player->mo->movefactor); - } - - if (player->botvars.predictionError >= MINERROR) - { - // CONS_Printf("%d: friction was %d, is ", leveltime, frict); - frict -= errorfrict; - // CONS_Printf("%d\n", frict); - } - - player->mo->friction += frict; - } - /* if (player->cmd.buttons & BT_ATTACK) player->mo->friction -= FRACUNIT/2; From 734e34e1bafff7e0306d393bd41122b277c795c1 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 17 Jun 2025 20:52:52 -0400 Subject: [PATCH 16/19] Gate error friction behind bot movement, restore map complexity with limited range --- src/k_bot.cpp | 4 +-- src/k_kart.c | 79 +++++++++++++++++++++++++++------------------------ 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 38b481f28..66e5ee2f3 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -581,10 +581,10 @@ const botcontroller_t *K_GetBotController(const mobj_t *mobj) fixed_t K_BotMapModifier(void) { // fuck it we ball - return 10*FRACUNIT/10; + // return 10*FRACUNIT/10; constexpr INT32 complexity_scale = 10000; - fixed_t modifier_max = (9 * FRACUNIT / 10) - FRACUNIT; + fixed_t modifier_max = (10 * FRACUNIT / 10) - FRACUNIT; fixed_t modifier_min = (5 * FRACUNIT / 10) - FRACUNIT; const fixed_t complexity_value = std::clamp( diff --git a/src/k_kart.c b/src/k_kart.c index 8275507ea..18e5164b6 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -750,6 +750,14 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against) fixed_t spd = K_GetKartSpeed(mobj->player, false, true); fixed_t unmodifiedspd = K_GetKartSpeed(mobj->player, false, false); + fixed_t bumpfactor = FRACUNIT; + if (K_PlayerUsesBotMovement(mobj->player)) + { + // Bot bumps are just a hard problem: lots going on. + // Treat bots as moving slower than they really are. + bumpfactor = max(bumpfactor, FixedDiv(spd, unmodifiedspd) * 2); + } + fixed_t speedfactor = 8 * mapobjectscale; weight = (mobj->player->kartweight) * FRACUNIT; @@ -767,7 +775,7 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against) if (mobj->player->speed > spd) weight += FixedDiv( FixedDiv((mobj->player->speed - spd), speedfactor), - FixedDiv(spd, unmodifiedspd) + bumpfactor ); } @@ -3892,9 +3900,9 @@ fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dor if (K_PlayerUsesBotMovement(player)) { - // Increase bot speed by 0-10% depending on difficulty + // Increase bot speed by 0-20% depending on difficulty const fixed_t modifier = K_BotMapModifier(); - fixed_t add = ((player->botvars.difficulty-1) * FixedMul(FRACUNIT / 10, modifier)) / (DIFFICULTBOT-1); + fixed_t add = ((player->botvars.difficulty-1) * FixedMul(FRACUNIT / 5, modifier)) / (DIFFICULTBOT-1); finalspeed = FixedMul(finalspeed, FRACUNIT + add); if (player->bot && (player->botvars.rival || cv_levelskull.value)) @@ -4091,11 +4099,10 @@ fixed_t K_GetNewSpeed(const player_t *player) p_speed = 15 * p_speed / 10; } - if (K_PlayerUsesBotMovement(player) == true && player->botvars.rubberband > FRACUNIT) + if (K_PlayerUsesBotMovement(player) == true && player->botvars.rubberband > 0) { // Acceleration is tied to top speed... // so if we want JUST a top speed boost, we have to do this... - // (But only do it if we're actually boosting from rubberbanding!) p_accel = FixedDiv(p_accel, player->botvars.rubberband); } @@ -13251,6 +13258,36 @@ 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; + angle_t MINERROR = 0; + fixed_t MAXERRORFRICTION = FRACUNIT>>3; + fixed_t errorfrict = Easing_InCubic(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, MAXERRORFRICTION); + + 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); + + if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->movefactor < FRACUNIT) + { + // Reduce error friction on low-friction surfaces + errorfrict = FixedMul(errorfrict, player->mo->movefactor); + } + + if (player->botvars.predictionError >= MINERROR) + { + // CONS_Printf("%d: friction was %d, is ", leveltime, frict); + frict -= min(errorfrict, MAXERRORFRICTION); + // CONS_Printf("%d\n", frict); + } + // Bots gain more traction as they rubberband. const fixed_t traction_value = FixedMul(player->botvars.rubberband, K_BotMapModifier()); if (traction_value > FRACUNIT) @@ -13261,38 +13298,6 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) } } - // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. - angle_t MAXERROR = ANGLE_45; - angle_t MINERROR = 0; - fixed_t errorfrict = Easing_InCubic(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); - - if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->movefactor < FRACUNIT) - { - // Reduce error friction on low-friction surfaces - errorfrict = FixedMul(errorfrict, player->mo->movefactor); - } - - if (player->botvars.predictionError >= MINERROR) - { - // CONS_Printf("%d: friction was %d, is ", leveltime, frict); - frict -= errorfrict; - // CONS_Printf("%d\n", frict); - } - - if (player->cmd.buttons & BT_VOTE && false) - frict -= FRACUNIT/2; - if (frict > FRACUNIT) { frict = FRACUNIT; } if (frict < 0) { frict = 0; } From 3591df606014350077279839639c5f2c395ef7ba Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 17 Jun 2025 21:15:43 -0400 Subject: [PATCH 17/19] Error friction responds to changes in friction --- src/k_kart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 18e5164b6..bd57b4079 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13261,7 +13261,7 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. angle_t MAXERROR = ANGLE_45; angle_t MINERROR = 0; - fixed_t MAXERRORFRICTION = FRACUNIT>>3; + fixed_t MAXERRORFRICTION = FixedMul(FRACUNIT >> 3, factor); fixed_t errorfrict = Easing_InCubic(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, MAXERRORFRICTION); if (player->currentwaypoint && player->currentwaypoint->mobj) @@ -13273,13 +13273,13 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) errorfrict *= 2; } - // errorfrict = min(errorfrict, frict/4); - + /* if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->movefactor < FRACUNIT) { // Reduce error friction on low-friction surfaces errorfrict = FixedMul(errorfrict, player->mo->movefactor); } + */ if (player->botvars.predictionError >= MINERROR) { From 153396d99cb43ea9bbb9c999204a3382413bb60c Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 18 Jun 2025 02:00:31 -0400 Subject: [PATCH 18/19] Disable error friction in no rubberband or angle too far --- src/k_kart.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index bd57b4079..eff9c5044 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13261,9 +13261,17 @@ fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original) // If bots are moving in the wrong direction relative to where they want to look, add some extra grip. angle_t MAXERROR = ANGLE_45; angle_t MINERROR = 0; + angle_t BLINDSPOT = ANGLE_135; fixed_t MAXERRORFRICTION = FixedMul(FRACUNIT >> 3, factor); + fixed_t errorfrict = Easing_InCubic(min(FRACUNIT, FixedDiv(player->botvars.predictionError, MAXERROR)), 0, MAXERRORFRICTION); + const botcontroller_t *botController = K_GetBotController(player->mo); + if (botController != NULL && (botController->flags & TMBOT_NORUBBERBAND) == TMBOT_NORUBBERBAND) + MAXERRORFRICTION = 0; // Don't grip to setpieces... + if (player->botvars.predictionError > BLINDSPOT) + MAXERRORFRICTION = 0; // ...or "tar pit" narrow waypoints. + if (player->currentwaypoint && player->currentwaypoint->mobj) { INT16 myradius = FixedDiv(player->currentwaypoint->mobj->radius, mapobjectscale) / FRACUNIT; From 08df01878efe0284a0400746b7e410b6862386f2 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Wed, 18 Jun 2025 23:42:41 -0400 Subject: [PATCH 19/19] Small Grade A threshold increase in tally --- src/k_tally.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_tally.cpp b/src/k_tally.cpp index 379986c92..f8e91b46c 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -188,7 +188,7 @@ INT32 level_tally_t::CalculateGrade(void) 7*FRACUNIT/20, // D: 35% or higher 10*FRACUNIT/20, // C: 50% or higher 14*FRACUNIT/20, // B: 70% or higher - 17*FRACUNIT/20 // A: 85% or higher + 18*FRACUNIT/20 // A: 90% or higher }; INT32 retGrade = GRADE_E; // gp_rank_e