From 2898c5d60c02689388d48a1affb705b9330cc556 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sun, 25 May 2025 17:04:05 -0400 Subject: [PATCH 1/7] Warnings for checkpoints missing associated lines --- src/objects/checkpoint.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/objects/checkpoint.cpp b/src/objects/checkpoint.cpp index 36e1eec84..1ab035865 100644 --- a/src/objects/checkpoint.cpp +++ b/src/objects/checkpoint.cpp @@ -495,7 +495,21 @@ struct CheckpointManager else // Checkpoint isn't in the list, find any associated tagged lines and make the pair { if (chk->linetag()) - lines_.try_emplace(chk->linetag(), tagged_lines(chk->linetag())); + { + auto lines = tagged_lines(chk->linetag()); + if (lines.empty()) + { + CONS_Alert(CONS_WARNING, "Checkpoint thing %d, has linetag %d, but no lines found. Please ensure all checkpoints have associated lines.\n", chk->spawnpoint - mapthings, chk->linetag()); + } + else + { + lines_.try_emplace(chk->linetag(), lines); + } + } + else + { + CONS_Alert(CONS_WARNING, "Checkpoint thing %d, has no linetag. Please ensure all checkpoint things have a linetag.\n", chk->spawnpoint - mapthings, chk->spawnpoint->type); + } list_.push_front(chk); count_ += 1; // Mobjlist can't have a count on it, so we keep it here } From 0cdd4d1b07daaf0fcdb638abb333c59450dbb675 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sun, 25 May 2025 17:08:22 -0400 Subject: [PATCH 2/7] Increase intermission tally speed --- src/y_inter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 4c4956551..095484090 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -2175,7 +2175,7 @@ void Y_Ticker(void) // Basic bitch points if (data.increase[data.num[q]]) { - if (--data.increase[data.num[q]]) + if (std::max(0,data.increase[data.num[q]]-3)) kaching = false; } } From 9c61edbeec1b726d31df4135259e3681e514dbff Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sun, 25 May 2025 17:09:16 -0400 Subject: [PATCH 3/7] End of round grade adjustments, reduces weight of position on grade --- src/k_tally.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/k_tally.cpp b/src/k_tally.cpp index 877e39dd1..a73319f95 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -218,7 +218,7 @@ INT32 level_tally_t::CalculateGrade(void) } } - const INT32 positionWeight = (position > 0 && numPlayers > 2) ? 50 : 0; + const INT32 positionWeight = (position > 0 && numPlayers > 2) ? 20 : 0; const INT32 total = positionWeight + bonusWeights[0] + bonusWeights[1]; INT32 ours = 0; @@ -242,10 +242,7 @@ INT32 level_tally_t::CalculateGrade(void) } case TALLY_BONUS_EXP: { - // Use a special curve for this. - // Low Exp amounts are guaranteed, higher than half is where skill expression starts - // Magic numbers here are to reduce the range from 50-125 to 0-75 and compare with a max of 58, 85% of which is 49.3, which should put an even 100 or higher exp at A rank - const fixed_t frac = std::min(FRACUNIT, ((exp-50) * FRACUNIT) / std::max(1, static_cast(totalExp-42))); + const fixed_t frac = std::min(FRACUNIT, ((exp-15) * FRACUNIT) / std::max(1, static_cast(totalExp))); ours += Easing_Linear(frac, 0, bonusWeights[i]); break; } From 083cc4a44f878cd4ac792e0b0ba2b63482c8b1f1 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sun, 25 May 2025 17:12:54 -0400 Subject: [PATCH 4/7] Exp rework. Uses the entire valid range of gradingfactor to map to exp instead of clamping some range off. --- src/doomdef.h | 2 +- src/k_grandprix.cpp | 25 -------------------- src/k_hud.cpp | 4 +--- src/k_kart.c | 56 ++++++++++++++++++++++++++++++++++++++++----- src/k_kart.h | 4 ++-- 5 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index cef04507f..b62f44472 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -745,7 +745,7 @@ extern int #define MAXAMPSCALINGDIST 18000 // Exp -#define MINEXP 50 // The min value target +#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 diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index d4b96a257..24a197f39 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -67,31 +67,6 @@ INT16 K_CalculateGPRankPoints(UINT16 exp, UINT8 position, UINT8 numplayers) points = exp; - // Give bonus to high-ranking players, depending on player count - // This rounds out the point gain when you get 1st every race, - // and gives bots able to catch up in points if a player gets an early lead. - // The maximum points you can get in a cup is: ((number of players - 1) + (max extra points)) * (number of races) - // 8P: (7 + 5) * 5 = 60 maximum points - // 12P: (11 + 5) * 5 = 80 maximum points - // 16P: (15 + 5) * 5 = 100 maximum points - switch (numplayers) - { - case 0: case 1: case 2: // 1v1 - break; // No bonus needed. - case 3: case 4: // 3-4P - if (position == 1) { points += 5; } // 1st gets +1 extra point - break; - case 5: case 6: // 5-6P - if (position == 1) { points += 10; } // 1st gets +3 extra points - // else if (position == 2) { points += 4; } // 2nd gets +1 extra point - break; - default: // Normal matches - if (position == 1) { points += 10; } // 1st gets +5 extra points - // else if (position == 2) { points += 5; } // 2nd gets +3 extra points - // else if (position == 3) { points += 2; } // 3rd gets +1 extra point - break; - } - // somehow underflowed? if (points < 0) { diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 616861b37..b4120c199 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -6715,10 +6715,8 @@ static void K_DrawGPRankDebugger(void) V_DrawThinString(0, 0, V_SNAPTOTOP|V_SNAPTOLEFT, va("POS: %d / %d", grandprixinfo.rank.position, RANK_NEUTRAL_POSITION)); - V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT, - va("PTS: %d / %d", grandprixinfo.rank.winPoints, grandprixinfo.rank.totalPoints)); V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT, - va("LAPS: %d / %d", grandprixinfo.rank.exp, grandprixinfo.rank.totalExp)); + va("EXP: %d / %d", grandprixinfo.rank.exp, grandprixinfo.rank.totalExp)); V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT, va("CONTINUES: %d", grandprixinfo.rank.continuesUsed)); V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT, diff --git a/src/k_kart.c b/src/k_kart.c index 4e2f0ef35..855214220 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4242,7 +4242,7 @@ void K_CheckpointCrossAward(player_t *player) if (gametype != GT_RACE) return; - player->gradingfactor += K_GetGradingMultAdjustment(player); + player->gradingfactor += K_GetGradingFactorAdjustment(player); player->gradingpointnum++; player->exp = K_GetEXP(player); //CONS_Printf("player: %s factor: %.2f exp: %d\n", player_names[player-players], FIXED_TO_FLOAT(player->gradingfactor), player->exp); @@ -15527,7 +15527,7 @@ boolean K_PlayerCanUseItem(player_t *player) return (player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime); } -fixed_t K_GetGradingMultAdjustment(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 @@ -15581,13 +15581,57 @@ fixed_t K_GetGradingMultAdjustment(player_t *player) return result; } +fixed_t K_GetGradingFactorMinMax(UINT32 gradingpointnum, boolean max) +{ + // Create a dummy player structure for the theoretical last-place player + player_t dummy_player; + memset(&dummy_player, 0, sizeof(player_t)); + dummy_player.gradingfactor = FRACUNIT; // Start at 1.0 + + if (G_GametypeHasTeams()) + { + const UINT8 orange_count = G_CountTeam(TEAM_ORANGE); + const UINT8 blue_count = G_CountTeam(TEAM_BLUE); + if (orange_count <= blue_count) + { + dummy_player.team = TEAM_ORANGE; + } + else + { + dummy_player.team = TEAM_BLUE; + } + dummy_player.position = max ? 0 : D_NumPlayersInRace() + 1; // Ensures that all enemy players are counted, and our dummy won't overlap + } + else + { + dummy_player.position = max ? 1 : D_NumPlayersInRace(); + } + + // Apply the adjustment for each grading point + for (UINT32 i = 0; i < gradingpointnum; i++) + { + dummy_player.gradingfactor += K_GetGradingFactorAdjustment(&dummy_player); + } + return dummy_player.gradingfactor; +} + UINT16 K_GetEXP(player_t *player) { UINT32 numgradingpoints = K_GetNumGradingPoints(); - // target is where you should be if you're doing good and at a 1.0 mult - fixed_t clampedmult = max(FRACUNIT/2, min(FRACUNIT*5/4, player->gradingfactor)); // clamp between 0.5 and 1.25 - fixed_t targetexp = (TARGETEXP*player->gradingpointnum/max(1,numgradingpoints))<>FRACBITS; + UINT16 targetminexp = (MINEXP*player->gradingpointnum/max(1,numgradingpoints)); // about what a last place player should be at this stage of the race + UINT16 targetexp = (MAXEXP*player->gradingpointnum/max(1,numgradingpoints)); // about what a 1.0 factor should be at this stage of the race + fixed_t factormin = K_GetGradingFactorMinMax(player->gradingpointnum, false); + fixed_t factormax = K_GetGradingFactorMinMax(player->gradingpointnum, true); + fixed_t clampedfactor = max(factormin, min(factormax, player->gradingfactor)); + fixed_t range = factormax - factormin; + fixed_t normalizedfactor = FixedDiv(clampedfactor - factormin, range); + fixed_t easedexp = Easing_Linear(normalizedfactor, targetminexp, targetexp); + // fixed_t easedexp = Easing_Linear(normalizedfactor, MINEXP*FRACUNIT, MAXEXP*FRACUNIT); + UINT16 exp = easedexp; + // CONS_Printf("Player %s numgradingpoints=%d targetminexp=%d targetexp=%d factormin=%.2f factormax=%.2f clampedfactor=%.2f normalizedfactor=%.2f easedexp=%d\n", + // player_names[player - players], numgradingpoints, targetminexp, targetexp, FIXED_TO_FLOAT(factormin), FIXED_TO_FLOAT(factormax), + // FIXED_TO_FLOAT(clampedfactor), FIXED_TO_FLOAT(normalizedfactor), easedexp); + // UINT16 exp = (player->gradingfactor*100)>>FRACBITS; return exp; } diff --git a/src/k_kart.h b/src/k_kart.h index cd5dee152..a0fd8a1b9 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -310,8 +310,8 @@ boolean K_ThunderDome(void); boolean K_PlayerCanUseItem(player_t *player); -fixed_t K_GetGradingMultAdjustment(player_t *player); - +fixed_t K_GetGradingFactorAdjustment(player_t *player); +fixed_t K_GetGradingFactorMinMax(UINT32 gradingpointnum, boolean max); UINT16 K_GetEXP(player_t *player); UINT32 K_GetNumGradingPoints(void); From 4b88ea04fd6427e973289e4a7ef9ead8ab97c05f Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sun, 25 May 2025 17:29:59 -0400 Subject: [PATCH 5/7] FIx warnings to not appear in tutorial --- src/objects/checkpoint.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/objects/checkpoint.cpp b/src/objects/checkpoint.cpp index 1ab035865..83b7ed0bf 100644 --- a/src/objects/checkpoint.cpp +++ b/src/objects/checkpoint.cpp @@ -497,7 +497,7 @@ struct CheckpointManager if (chk->linetag()) { auto lines = tagged_lines(chk->linetag()); - if (lines.empty()) + if (lines.empty() && gametype != GT_TUTORIAL) { CONS_Alert(CONS_WARNING, "Checkpoint thing %d, has linetag %d, but no lines found. Please ensure all checkpoints have associated lines.\n", chk->spawnpoint - mapthings, chk->linetag()); } @@ -508,7 +508,10 @@ struct CheckpointManager } else { - CONS_Alert(CONS_WARNING, "Checkpoint thing %d, has no linetag. Please ensure all checkpoint things have a linetag.\n", chk->spawnpoint - mapthings, chk->spawnpoint->type); + if (gametype != GT_TUTORIAL) + { + CONS_Alert(CONS_WARNING, "Checkpoint thing %d, has no linetag. Please ensure all checkpoint things have a linetag.\n", chk->spawnpoint - mapthings); + } } list_.push_front(chk); count_ += 1; // Mobjlist can't have a count on it, so we keep it here From 10a694cc0b0a9733ea1a19598629e6ef356024a4 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sun, 25 May 2025 18:13:49 -0400 Subject: [PATCH 6/7] Disallow interacting with checkpoints after you finish --- src/objects/checkpoint.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/objects/checkpoint.cpp b/src/objects/checkpoint.cpp index 83b7ed0bf..97bba1cd5 100644 --- a/src/objects/checkpoint.cpp +++ b/src/objects/checkpoint.cpp @@ -584,6 +584,11 @@ void Obj_CheckpointThink(mobj_t* end) void Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y) { + if (player->exiting) // can't cross checkpoints when exiting + { + return; + } + LineOnDemand ray(old_x, old_y, player->mo->x, player->mo->y, player->mo->radius); auto it = std::find_if( From 6e49378bc857a344c5d4edbe03ca16dbc03eb203 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sun, 25 May 2025 18:30:40 -0400 Subject: [PATCH 7/7] Fix botched tally rate increase --- src/y_inter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 095484090..3857b37a3 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -2175,7 +2175,9 @@ void Y_Ticker(void) // Basic bitch points if (data.increase[data.num[q]]) { - if (std::max(0,data.increase[data.num[q]]-3)) + data.increase[data.num[q]] = std::max(data.increase[data.num[q]] - 3, 0); + + if (data.increase[data.num[q]] != 0) kaching = false; } }