From 2ec0fdcc46350395a5911a37a8f739a8a834b0de Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 22 Jun 2025 18:54:15 -0400 Subject: [PATCH] Refactor EXP logic to reuse math in minmax calcs --- src/k_kart.c | 98 +++++++++++++++++++++++++++------------------------- src/k_kart.h | 2 +- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 3cda6c47a..aedc6ac0b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -15964,18 +15964,11 @@ boolean K_PlayerCanUseItem(player_t *player) return (player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime); } -fixed_t K_GetGradingFactorAdjustment(player_t *player) +static UINT8 K_Opponents(player_t *player) { - 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; + UINT8 opponents = 0; // players we are competing against - if (g_teamplay) - power = 3 * power / 4; - - INT32 live_players = 0; // players we are competing against - - for (INT32 i = 0; i < MAXPLAYERS; i++) + for (UINT8 i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator || player == players+i) continue; @@ -15986,13 +15979,42 @@ fixed_t K_GetGradingFactorAdjustment(player_t *player) continue; } - live_players++; + opponents++; } - if (live_players < 8) - { - power += (8 - live_players) * power/4; - } + return opponents; +} + +static fixed_t K_EXPPower(player_t *player) +{ + fixed_t power = EXP_POWER; // adjust to change overall xp volatility + UINT8 opponents = K_Opponents(player); + + if (g_teamplay) + power = 3 * power / 4; + + if (opponents < 8) + power += (8 - opponents) * power/4; + + return power; +} + +static fixed_t K_EXPGainPerWin(player_t *player) +{ + return K_EXPPower(player); +} + +static fixed_t K_EXPDrainPerCheckpoint(player_t *player) +{ + // EXP_STABLERATE: How low do you have to place before losing XP? 4*FRACUNIT/10 = top 40% of race gains, 60% loses. + UINT8 opponents = K_Opponents(player); + fixed_t power = K_EXPPower(player); + return FixedMul(power, FixedMul(opponents*FRACUNIT, FRACUNIT - EXP_STABLERATE)); +} + +fixed_t K_GetGradingFactorAdjustment(player_t *player) +{ + fixed_t result = 0; // Increase XP for each player you're beating... for (INT32 i = 0; i < MAXPLAYERS; i++) @@ -16007,49 +16029,31 @@ fixed_t K_GetGradingFactorAdjustment(player_t *player) } if (player->position < players[i].position) - result += power; + result += K_EXPGainPerWin(player); } // ...then take all of the XP you could possibly have earned, // and lose it proportional to the stable rate. If you're below // the stable threshold, this results in you losing XP. - result -= FixedMul(power, FixedMul(live_players*FRACUNIT, FRACUNIT - stablerate)); + result -= K_EXPDrainPerCheckpoint(player); return result; } -fixed_t K_GetGradingFactorMinMax(UINT32 gradingpointnum, boolean max) +fixed_t K_GetGradingFactorMinMax(player_t *player, 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 + fixed_t factor = FRACUNIT; // Starting EXP. + UINT8 opponents = K_Opponents(player); + UINT8 winning = (max) ? opponents : 0; - if (G_GametypeHasTeams()) + for (UINT8 i = 0; i < player->gradingpointnum; i++) // For each gradingpoint you've reached... { - 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 + for (UINT8 j = 0; j < winning; j++) + factor += K_EXPGainPerWin(player); // If max, increase EXP for each player you could have been beating. + factor -= K_EXPDrainPerCheckpoint(player); // Then, drain like usual. } - 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; + + return factor; } UINT16 K_GetEXP(player_t *player) @@ -16057,8 +16061,8 @@ UINT16 K_GetEXP(player_t *player) UINT32 numgradingpoints = K_GetNumGradingPoints(); 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 factormin = K_GetGradingFactorMinMax(player, false); + fixed_t factormax = K_GetGradingFactorMinMax(player, true); fixed_t clampedfactor = max(factormin, min(factormax, player->gradingfactor)); fixed_t range = factormax - factormin; fixed_t normalizedfactor = FixedDiv(clampedfactor - factormin, range); diff --git a/src/k_kart.h b/src/k_kart.h index ff269dbb9..9d9f3fdf8 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -325,7 +325,7 @@ boolean K_ThunderDome(void); boolean K_PlayerCanUseItem(player_t *player); fixed_t K_GetGradingFactorAdjustment(player_t *player); -fixed_t K_GetGradingFactorMinMax(UINT32 gradingpointnum, boolean max); +fixed_t K_GetGradingFactorMinMax(player_t *player, boolean max); UINT16 K_GetEXP(player_t *player); UINT32 K_GetNumGradingPoints(void);