From 3c076419383e970bc8b57e243820646873f6cb9f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 4 Mar 2023 16:16:37 -0500 Subject: [PATCH] Add final position as a ranking requirement 1st is a large bonus, 2nd is a medium bonus, 3rd place is no bonus, and everything below is a penalty. This will help make Loser Valley grades never be above a C at most. --- src/g_game.c | 5 +++ src/k_hud.c | 18 ++++---- src/k_kart.c | 120 +++++++++++++++++++++++-------------------------- src/k_podium.c | 48 +++++++++++++------- src/k_rank.c | 25 ++++++++--- src/k_rank.h | 4 ++ 6 files changed, 125 insertions(+), 95 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 3eae4f03b..22760c3e0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4128,6 +4128,7 @@ static void G_DoCompleted(void) G_SetGamestate(GS_NULL); wipegamestate = GS_NULL; + g_gpRank.position = MAXPLAYERS; g_gpRank.difficulty = 0; for (i = 0; i < MAXPLAYERS; i++) @@ -4160,6 +4161,10 @@ static void G_DoCompleted(void) { g_gpRank.difficulty = max(g_gpRank.difficulty, players[i].botvars.difficulty); } + else + { + g_gpRank.position = min(g_gpRank.position, K_GetPodiumPosition(&players[i])); + } } } diff --git a/src/k_hud.c b/src/k_hud.c index af93c6ef0..db1464ceb 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4821,19 +4821,21 @@ static void K_DrawGPRankDebugger(void) grade = K_CalculateGPGrade(&g_gpRank); V_DrawThinString(0, 0, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("PTS: %d / %d", g_gpRank.winPoints, g_gpRank.totalPoints)); + va("POS: %d / %d", g_gpRank.position, RANK_NEUTRAL_POSITION)); V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("LAPS: %d / %d", g_gpRank.laps, g_gpRank.totalLaps)); + va("PTS: %d / %d", g_gpRank.winPoints, g_gpRank.totalPoints)); V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("CONTINUES: %d", g_gpRank.continuesUsed)); + va("LAPS: %d / %d", g_gpRank.laps, g_gpRank.totalLaps)); V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("CAPSULES: %d / %d", g_gpRank.capsules, g_gpRank.totalCapsules)); + va("CONTINUES: %d", g_gpRank.continuesUsed)); V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings)); + va("CAPSULES: %d / %d", g_gpRank.capsules, g_gpRank.totalCapsules)); V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("DIFFICULTY: %d / %d", g_gpRank.difficulty, g_gpRank.difficultyTarget)); + va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings)); V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("SPECIAL: %s", (g_gpRank.specialWon == true) ? "YES" : "NO")); + va("DIFFICULTY: %d / %d", g_gpRank.difficulty, g_gpRank.difficultyTarget)); + V_DrawThinString(0, 70, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("EMERALD: %s", (g_gpRank.specialWon == true) ? "YES" : "NO")); switch (grade) { @@ -4846,7 +4848,7 @@ static void K_DrawGPRankDebugger(void) default: { break; } } - V_DrawThinString(0, 80, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_YELLOWMAP, + V_DrawThinString(0, 90, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_YELLOWMAP, va(" ** FINAL GRADE: %c", gradeChar)); } diff --git a/src/k_kart.c b/src/k_kart.c index 10ab61c8d..3231f47cd 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9319,85 +9319,79 @@ void K_KartUpdatePosition(player_t *player) return; } - for (i = 0; i < MAXPLAYERS; i++) + if (K_PodiumSequence() == true) { - if (!playeringame[i] || players[i].spectator || !players[i].mo) - continue; + position = K_GetPodiumPosition(player); - realplayers++; - - if (K_PodiumSequence() == true) + for (i = 0; i < MAXPLAYERS; i++) { - if (players[i].score > player->score) - { - // Final score is the important part. - position++; - } - else if (players[i].score == player->score) - { - if (players[i].bot == false && player->bot == true) - { - // Bots are never as important as players. - position++; - } - else if (i < player - players) - { - // Port priority is the final tie breaker. - position++; - } - } + if (!playeringame[i] || players[i].spectator || !players[i].mo) + continue; + + realplayers++; } - else if (gametyperules & GTR_CIRCUIT) + } + else + { + for (i = 0; i < MAXPLAYERS; i++) { - if (player->exiting) // End of match standings - { - // Only time matters - if (players[i].realtime < player->realtime) - position++; - } - else - { - // I'm a lap behind this player OR - // My distance to the finish line is higher, so I'm behind - if ((players[i].laps > player->laps) - || (players[i].distancetofinish < player->distancetofinish)) - { - position++; - } - } - } - else - { - if (player->exiting) // End of match standings - { - // Only score matters - if (players[i].roundscore > player->roundscore) - position++; - } - else - { - UINT8 myEmeralds = K_NumEmeralds(player); - UINT8 yourEmeralds = K_NumEmeralds(&players[i]); + if (!playeringame[i] || players[i].spectator || !players[i].mo) + continue; - // First compare all points - if (players[i].roundscore > player->roundscore) + realplayers++; + + if (gametyperules & GTR_CIRCUIT) + { + if (player->exiting) // End of match standings { - position++; + // Only time matters + if (players[i].realtime < player->realtime) + position++; } - else if (players[i].roundscore == player->roundscore) + else { - // Emeralds are a tie breaker - if (yourEmeralds > myEmeralds) + // I'm a lap behind this player OR + // My distance to the finish line is higher, so I'm behind + if ((players[i].laps > player->laps) + || (players[i].distancetofinish < player->distancetofinish)) { position++; } - else if (yourEmeralds == myEmeralds) + } + } + else + { + if (player->exiting) // End of match standings + { + // Only score matters + if (players[i].roundscore > player->roundscore) + position++; + } + else + { + UINT8 myEmeralds = K_NumEmeralds(player); + UINT8 yourEmeralds = K_NumEmeralds(&players[i]); + + // First compare all points + if (players[i].roundscore > player->roundscore) { - // Bumpers are the second tier tie breaker - if (players[i].bumpers > player->bumpers) + position++; + } + else if (players[i].roundscore == player->roundscore) + { + // Emeralds are a tie breaker + if (yourEmeralds > myEmeralds) { position++; } + else if (yourEmeralds == myEmeralds) + { + // Bumpers are the second tier tie breaker + if (players[i].bumpers > player->bumpers) + { + position++; + } + } } } } diff --git a/src/k_podium.c b/src/k_podium.c index 0ff0e23a5..2e610db1b 100644 --- a/src/k_podium.c +++ b/src/k_podium.c @@ -57,7 +57,7 @@ static struct podiumData_s UINT8 fade; } podiumData; -#define PODIUM_STATES (9) // TODO: enum +#define PODIUM_STATES (10) // TODO: enum when this actually gets made /*-------------------------------------------------- boolean K_PodiumSequence(void) @@ -326,7 +326,7 @@ void K_CeremonyTicker(boolean run) { podiumData.delay++; - if (podiumData.delay > TICRATE) + if (podiumData.delay > TICRATE/2) { podiumData.state++; podiumData.delay = 0; @@ -429,60 +429,74 @@ void K_CeremonyDrawer(void) { case 1: { - V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, - va("PTS: %d / %d", g_gpRank.winPoints, g_gpRank.totalPoints) + V_DrawString(x, y, V_ALLOWLOWERCASE, + va("POS: %d / %d", podiumData.rankData.position, RANK_NEUTRAL_POSITION) ); break; } case 2: { - V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, - va("LAPS: %d / %d", g_gpRank.laps, g_gpRank.totalLaps) + V_DrawString(x, y, V_ALLOWLOWERCASE, + va("PTS: %d / %d", podiumData.rankData.winPoints, podiumData.rankData.totalPoints) ); break; } case 3: { - V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, - va("CONTINUES: %d", g_gpRank.continuesUsed) + V_DrawString(x, y, V_ALLOWLOWERCASE, + va("LAPS: %d / %d", podiumData.rankData.laps, podiumData.rankData.totalLaps) ); break; } case 4: { - V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, - va("CAPSULES: %d / %d", g_gpRank.capsules, g_gpRank.totalCapsules) + V_DrawString(x, y, V_ALLOWLOWERCASE, + va("CONTINUES: %d", podiumData.rankData.continuesUsed) ); break; } case 5: { - V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, - va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings) + V_DrawString(x, y, V_ALLOWLOWERCASE, + va("CAPSULES: %d / %d", podiumData.rankData.capsules, podiumData.rankData.totalCapsules) ); break; } case 6: { - V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, - va("DIFFICULTY: %d / %d", g_gpRank.difficulty, g_gpRank.difficultyTarget) + V_DrawString(x, y, V_ALLOWLOWERCASE, + va("RINGS: %d / %d", podiumData.rankData.rings, podiumData.rankData.totalRings) ); break; } case 7: { - V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, - va("SPECIAL: %s", (g_gpRank.specialWon == true) ? "YES" : "NO") + V_DrawString(x, y, V_ALLOWLOWERCASE, + va("DIFFICULTY: %d / %d", podiumData.rankData.difficulty, podiumData.rankData.difficultyTarget) ); break; } case 8: { - V_DrawString(x, y + 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + V_DrawString(x, y, V_ALLOWLOWERCASE, + va("EMERALD: %s", (podiumData.rankData.specialWon == true) ? "YES" : "NO") + ); + break; + } + case 9: + { + V_DrawString(x, y + 10, V_YELLOWMAP|V_ALLOWLOWERCASE, va(" ** FINAL GRADE: %c", gradeChar) ); break; } + case 10: + { + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, BASEVIDHEIGHT - 10, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + "Press some button type deal to continue" + ); + break; + } } y += 10; diff --git a/src/k_rank.c b/src/k_rank.c index b4d2b90df..08bf19c80 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -56,6 +56,9 @@ void K_InitGrandPrixRank(gpRank_t *rankData) rankData->players = numHumans; rankData->totalPlayers = K_GetGPPlayerCount(numHumans); + // Initialize to the neutral value. + rankData->position = RANK_NEUTRAL_POSITION; + // Calculate total of points // (Should this account for all coop players?) for (i = 0; i < numHumans; i++) @@ -111,17 +114,25 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData) gp_rank_e retGrade = GRADE_E; - const INT32 pointsWeight = 100; - const INT32 lapsWeight = 100; - const INT32 capsulesWeight = 100; - const INT32 ringsWeight = 50; - const INT32 difficultyWeight = 20; - const INT32 total = pointsWeight + lapsWeight + capsulesWeight + ringsWeight + difficultyWeight; - const INT32 continuesPenalty = 20; + const INT32 positionWeight = 1500; + const INT32 pointsWeight = 1000; + const INT32 lapsWeight = 1000; + const INT32 capsulesWeight = 1000; + const INT32 ringsWeight = 500; + const INT32 difficultyWeight = 200; + const INT32 total = positionWeight + pointsWeight + lapsWeight + capsulesWeight + ringsWeight + difficultyWeight; + const INT32 continuesPenalty = 200; INT32 ours = 0; fixed_t percent = 0; + if (rankData->position > 0) + { + const INT32 sc = (rankData->position - 1); + const INT32 loser = (RANK_NEUTRAL_POSITION - 1); + ours += ((loser - sc) * positionWeight) / loser; + } + if (rankData->totalPoints > 0) { ours += (rankData->winPoints * pointsWeight) / rankData->totalPoints; diff --git a/src/k_rank.h b/src/k_rank.h index 93c139df0..b86744c7e 100644 --- a/src/k_rank.h +++ b/src/k_rank.h @@ -25,6 +25,8 @@ struct gpRank_t UINT8 players; UINT8 totalPlayers; + UINT8 position; + UINT32 winPoints; UINT32 totalPoints; @@ -57,6 +59,8 @@ typedef enum GRADE_S } gp_rank_e; +// 3rd place is neutral, anything below is a penalty +#define RANK_NEUTRAL_POSITION (3) /*-------------------------------------------------- void K_InitGrandPrixRank(gpRank_t *rankData);