From 55de982fa380dc74329ee4a72c6682500981141a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 22 Feb 2023 04:31:15 -0500 Subject: [PATCH 01/13] GP ranking Needs balancing + intermission, but mostly functional --- src/d_player.h | 1 + src/g_game.c | 18 ++++++ src/k_battle.c | 1 + src/k_grandprix.c | 160 ++++++++++++++++++++++++++++++++++++++++++++-- src/k_grandprix.h | 54 ++++++++++++++++ src/k_hud.c | 35 ++++++++++ src/p_inter.c | 2 + src/p_saveg.c | 2 + src/p_setup.c | 1 + src/p_spec.c | 13 +++- src/p_user.c | 11 ++++ 11 files changed, 291 insertions(+), 7 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index f38076f6f..40bfcc95a 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -634,6 +634,7 @@ struct player_t tic_t realtime; // integer replacement for leveltime UINT8 laps; // Number of laps (optional) UINT8 latestlap; + UINT32 lapPoints; // Points given from laps INT32 starpostnum; // The number of the last starpost you hit UINT8 ctfteam; // 0 == Spectator, 1 == Red, 2 == Blue diff --git a/src/g_game.c b/src/g_game.c index 5468cf505..601834123 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2388,6 +2388,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT16 totalring; UINT8 laps; UINT8 latestlap; + UINT32 lapPoints; UINT16 skincolor; INT32 skin; UINT8 availabilities[MAXAVAILABILITY]; @@ -2497,6 +2498,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) nocontrol = 0; laps = 0; latestlap = 0; + lapPoints = 0; roundscore = 0; exiting = 0; khudfinish = 0; @@ -2532,6 +2534,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) laps = players[player].laps; latestlap = players[player].latestlap; + lapPoints = players[player].lapPoints; roundscore = players[player].roundscore; @@ -2604,6 +2607,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->laps = laps; p->latestlap = latestlap; + p->lapPoints = lapPoints; p->totalring = totalring; p->bot = bot; @@ -4123,6 +4127,8 @@ static void G_DoCompleted(void) G_SetGamestate(GS_NULL); wipegamestate = GS_NULL; + UINT8 bestDifficulty = 0; + for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) @@ -4148,9 +4154,16 @@ static void G_DoCompleted(void) } G_PlayerFinishLevel(i); // take away cards and stuff + + if (players[i].bot) + { + bestDifficulty = max(bestDifficulty, players[i].botvars.difficulty); + } } } + gpRank.difficulty = bestDifficulty; + // See Y_StartIntermission timer handling if ((gametyperules & GTR_CIRCUIT) && ((multiplayer && demo.playback) || j == r_splitscreen+1) && (!K_CanChangeRules(false) || cv_inttime.value > 0)) // play some generic music if there's no win/cool/lose music going on (for exitlevel commands) @@ -5485,6 +5498,11 @@ boolean G_GetExitGameFlag(void) // Same deal with retrying. void G_SetRetryFlag(void) { + if (retrying == false) + { + gpRank.continuesUsed++; + } + retrying = true; } diff --git a/src/k_battle.c b/src/k_battle.c index b34c7a151..8e5db972b 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -780,6 +780,7 @@ void K_BattleInit(boolean singleplayercontext) P_SpawnMapThing(mt); } + gpRank.totalCapsules += maptargets; battlecapsules = true; } diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 6d879054b..c061d271f 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -21,6 +21,7 @@ #include "r_things.h" struct grandprixinfo grandprixinfo; +struct gpRank gpRank; /*-------------------------------------------------- UINT8 K_BotStartingDifficulty(SINT8 value) @@ -114,6 +115,86 @@ UINT8 K_BotDefaultSkin(void) return (UINT8)defaultbotskin; } +/*-------------------------------------------------- + static UINT8 K_GetGPPlayerCount(UINT8 humans) + + Counts the number of total players, + including humans and bots, to put into + a GP session. +--------------------------------------------------*/ +static UINT8 K_GetGPPlayerCount(UINT8 humans) +{ + UINT8 playerCount = 8; + + if (humans > 2) + { + // Add 3 bots per player beyond 2P + playerCount += (humans - 2) * 3; + } + + return playerCount; +} + +/*-------------------------------------------------- + void K_InitGrandPrixRank(void) + + See header file for description. +--------------------------------------------------*/ +void K_InitGrandPrixRank(void) +{ + UINT8 numHumans = 0; + INT32 i; + + memset(&gpRank, 0, sizeof(gpRank)); + + if (grandprixinfo.cup == NULL) + { + return; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + if (numHumans < MAXSPLITSCREENPLAYERS && players[i].spectator == false) + { + numHumans++; + } + } + } + + // Calculate players + gpRank.players = numHumans; + gpRank.totalPlayers = K_GetGPPlayerCount(numHumans); + + // Calculate total of points + // (Should this account for all coop players?) + for (i = 0; i < numHumans; i++) + { + gpRank.totalPoints += grandprixinfo.cup->numlevels * K_CalculateGPRankPoints(i + 1, gpRank.totalPlayers); + } + + gpRank.totalRings = grandprixinfo.cup->numlevels * numHumans * 20; + + UINT32 laps = 0; + for (i = 0; i < grandprixinfo.cup->numlevels; i++) + { + const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[i]; + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] != NULL) + { + laps += mapheaderinfo[cupLevelNum]->numlaps; + } + } + + // +1, since 1st place laps are worth 2 pts. + for (i = 0; i < numHumans+1; i++) + { + gpRank.totalLaps += laps; + } + + // Total capsules will need to be calculated as you enter the bonus stages... +} + /*-------------------------------------------------- void K_InitGrandPrixBots(void) @@ -198,12 +279,7 @@ void K_InitGrandPrixBots(void) } } - if (numplayers > 2) - { - // Add 3 bots per player beyond 2P - playercount += (numplayers-2) * 3; - } - + playercount = K_GetGPPlayerCount(numplayers); wantedbots = playercount - numplayers; // Create rival list @@ -728,3 +804,75 @@ boolean K_CanChangeRules(boolean allowdemos) return true; } + +/*-------------------------------------------------- + gp_rank_e K_CalculateGPGrade(void) + + See header file for description. +--------------------------------------------------*/ +gp_rank_e K_CalculateGPGrade(void) +{ + static const fixed_t gradePercents[GRADE_A] = { + 9*FRACUNIT/20, // GRADE_E -> GRADE_D + 12*FRACUNIT/20, // GRADE_D -> GRADE_C + 15*FRACUNIT/20, // GRADE_C -> GRADE_B + 18*FRACUNIT/20 // GRADE_B -> GRADE_A + }; + + gp_rank_e retGrade = GRADE_E; + + // TODO: + 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; + + INT32 ours = 0; + fixed_t percent = 0; + + if (gpRank.totalPoints > 0) + { + ours += (gpRank.winPoints * pointsWeight) / gpRank.totalPoints; + } + + if (gpRank.totalLaps > 0) + { + ours += (gpRank.laps * lapsWeight) / gpRank.totalLaps; + } + + if (gpRank.totalCapsules > 0) + { + ours += (gpRank.capsules * capsulesWeight) / gpRank.totalCapsules; + } + + if (gpRank.totalRings > 0) + { + ours += (gpRank.rings * ringsWeight) / gpRank.totalRings; + } + + ours += (gpRank.difficulty * difficultyWeight) / MAXBOTDIFFICULTY; + + ours -= gpRank.continuesUsed * continuesPenalty; + + percent = FixedDiv(ours, total); + + for (retGrade = 0; retGrade < GRADE_A; retGrade++) + { + if (percent < gradePercents[retGrade]) + { + break; + } + } + + if (gpRank.specialWon == true) + { + // Winning the Special Stage gives you + // a free grade increase. + retGrade++; + } + + return retGrade; +} diff --git a/src/k_grandprix.h b/src/k_grandprix.h index a862245c7..9103b047f 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -37,6 +37,38 @@ extern struct grandprixinfo UINT8 eventmode; ///< See GPEVENT_ constants } grandprixinfo; +extern struct gpRank +{ + UINT8 players; + UINT8 totalPlayers; + + UINT32 winPoints; + UINT32 totalPoints; + + UINT32 laps; + UINT32 totalLaps; + + UINT32 continuesUsed; + + UINT32 capsules; + UINT32 totalCapsules; + + UINT32 rings; + UINT32 totalRings; + + boolean specialWon; + UINT8 difficulty; +} gpRank; + +typedef enum +{ + GRADE_E, + GRADE_D, + GRADE_C, + GRADE_B, + GRADE_A, + GRADE_S +} gp_rank_e; /*-------------------------------------------------- UINT8 K_BotStartingDifficulty(SINT8 value); @@ -80,6 +112,13 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers); UINT8 K_BotDefaultSkin(void); +/*-------------------------------------------------- + void K_InitGrandPrixRank(void); + + Calculates rank requirements for a GP session. +--------------------------------------------------*/ + +void K_InitGrandPrixRank(void); /*-------------------------------------------------- void K_InitGrandPrixBots(void); @@ -170,6 +209,21 @@ void K_PlayerLoseLife(player_t *player); boolean K_CanChangeRules(boolean allowdemos); +/*-------------------------------------------------- + gp_rank_e K_CalculateGPGrade(void); + + Calculates the player's grade using the + variables from gpRank. + + Input Arguments:- + N/A + + Return:- + gp_rank_e representing the total grade. +--------------------------------------------------*/ + +gp_rank_e K_CalculateGPGrade(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_hud.c b/src/k_hud.c index bbc008520..947032b41 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5067,4 +5067,39 @@ void K_drawKartHUD(void) K_DrawWaypointDebugger(); K_DrawDirectorDebugger(); + + if (grandprixinfo.gp == true) + { + gp_rank_e grade = K_CalculateGPGrade(); + char gradeChar = '?'; + + V_DrawThinString(0, 0, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("PTS: %d / %d", gpRank.winPoints, gpRank.totalPoints)); + V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("LAPS: %d / %d", gpRank.laps, gpRank.totalLaps)); + V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("CONTINUES: %d", gpRank.continuesUsed)); + V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("CAPSULES: %d / %d", gpRank.capsules, gpRank.totalCapsules)); + V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("RINGS: %d / %d", gpRank.rings, gpRank.totalRings)); + V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("SPECIAL: %d", gpRank.specialWon)); + V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("DIFFICULTY: %d", gpRank.difficulty)); + + switch (grade) + { + case GRADE_E: { gradeChar = 'E'; break; } + case GRADE_D: { gradeChar = 'D'; break; } + case GRADE_C: { gradeChar = 'C'; break; } + case GRADE_B: { gradeChar = 'B'; break; } + case GRADE_A: { gradeChar = 'A'; break; } + case GRADE_S: { gradeChar = 'S'; break; } + default: { break; } + } + + V_DrawThinString(0, 80, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_YELLOWMAP, + va(" ** FINAL GRADE: %c", gradeChar)); + } } diff --git a/src/p_inter.c b/src/p_inter.c index 3d69eec25..be0de4620 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1595,6 +1595,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget K_SpawnBattlePoints(source->player, NULL, 1); } + gpRank.capsules++; + // All targets busted! if (++numtargets >= maptargets) { diff --git a/src/p_saveg.c b/src/p_saveg.c index 4d252c64b..8e6a4dd15 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -178,6 +178,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT32(save->p, players[i].realtime); WRITEUINT8(save->p, players[i].laps); WRITEUINT8(save->p, players[i].latestlap); + WRITEUINT32(save->p, players[i].lapPoints); WRITEINT32(save->p, players[i].starpostnum); WRITEUINT8(save->p, players[i].ctfteam); @@ -567,6 +568,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].realtime = READUINT32(save->p); // integer replacement for leveltime players[i].laps = READUINT8(save->p); // Number of laps (optional) players[i].latestlap = READUINT8(save->p); + players[i].lapPoints = READUINT32(save->p); players[i].starpostnum = READINT32(save->p); players[i].ctfteam = READUINT8(save->p); // 1 == Red, 2 == Blue diff --git a/src/p_setup.c b/src/p_setup.c index 77261176e..e8043d56e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7388,6 +7388,7 @@ static void P_InitGametype(void) { if (grandprixinfo.initalize == true) { + K_InitGrandPrixRank(); K_InitGrandPrixBots(); grandprixinfo.initalize = false; } diff --git a/src/p_spec.c b/src/p_spec.c index 0d844cb27..e81620426 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2027,7 +2027,6 @@ static void K_HandleLapIncrement(player_t *player) SetRandomFakePlayerSkin(player, true); } } - if (player->laps > player->latestlap) { @@ -2046,6 +2045,18 @@ static void K_HandleLapIncrement(player_t *player) // Update power levels for this lap. K_UpdatePowerLevels(player, player->laps, false); + + if (nump > 1 && K_IsPlayerLosing(player) == false) + { + if (nump > 2 && player->position == 1) // 1st place in 1v1 uses thumbs up + { + player->lapPoints += 2; + } + else + { + player->lapPoints++; + } + } } player->latestlap = player->laps; diff --git a/src/p_user.c b/src/p_user.c index f5cb57df2..140e2c7de 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1353,6 +1353,7 @@ void P_DoPlayerExit(player_t *player) if (RINGTOTAL(player) > 0) { player->totalring += RINGTOTAL(player); + gpRank.rings += player->totalring; extra = player->totalring / lifethreshold; @@ -1363,6 +1364,16 @@ void P_DoPlayerExit(player_t *player) player->xtralife = extra; } } + + if (grandprixinfo.eventmode == GPEVENT_NONE) + { + gpRank.winPoints += K_CalculateGPRankPoints(player->position, gpRank.totalPlayers); + gpRank.laps += player->lapPoints; + } + else if (grandprixinfo.eventmode == GPEVENT_SPECIAL) + { + gpRank.specialWon = true; + } } } } From c61e017c38e4ba66e06eb3c4fd1a601cc2e56ff2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 23 Feb 2023 12:05:01 -0500 Subject: [PATCH 02/13] GP rank cleanup - Move ranking to its own file. - gpRank (the variable) -> g_gpRank - gpRank (the struct) -> gpRank_t - Functions that worked on the global directly now take a pointer to a struct - Fixed total ring increment - Fixed final lap's lapPoints being discarded - Capsules are now added when exiting with the rest of the stuff --- src/CMakeLists.txt | 1 + src/g_game.c | 9 ++- src/k_battle.c | 3 +- src/k_grandprix.c | 141 +--------------------------------------- src/k_grandprix.h | 65 ++++--------------- src/k_hud.c | 18 +++--- src/k_rank.c | 156 +++++++++++++++++++++++++++++++++++++++++++++ src/k_rank.h | 95 +++++++++++++++++++++++++++ src/p_inter.c | 2 - src/p_setup.c | 3 +- src/p_spec.c | 57 ++++++++--------- src/p_user.c | 12 ++-- src/typedef.h | 3 + 13 files changed, 326 insertions(+), 239 deletions(-) create mode 100644 src/k_rank.c create mode 100644 src/k_rank.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ad870cec4..04d1c6040 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -135,6 +135,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 k_specialstage.c k_roulette.c k_podium.c + k_rank.c ) if(SRB2_CONFIG_ENABLE_WEBM_MOVIES) diff --git a/src/g_game.c b/src/g_game.c index 601834123..3eae4f03b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -63,6 +63,7 @@ #include "doomstat.h" #include "k_director.h" #include "k_podium.h" +#include "k_rank.h" #ifdef HAVE_DISCORDRPC #include "discord.h" @@ -4127,7 +4128,7 @@ static void G_DoCompleted(void) G_SetGamestate(GS_NULL); wipegamestate = GS_NULL; - UINT8 bestDifficulty = 0; + g_gpRank.difficulty = 0; for (i = 0; i < MAXPLAYERS; i++) { @@ -4157,13 +4158,11 @@ static void G_DoCompleted(void) if (players[i].bot) { - bestDifficulty = max(bestDifficulty, players[i].botvars.difficulty); + g_gpRank.difficulty = max(g_gpRank.difficulty, players[i].botvars.difficulty); } } } - gpRank.difficulty = bestDifficulty; - // See Y_StartIntermission timer handling if ((gametyperules & GTR_CIRCUIT) && ((multiplayer && demo.playback) || j == r_splitscreen+1) && (!K_CanChangeRules(false) || cv_inttime.value > 0)) // play some generic music if there's no win/cool/lose music going on (for exitlevel commands) @@ -5500,7 +5499,7 @@ void G_SetRetryFlag(void) { if (retrying == false) { - gpRank.continuesUsed++; + g_gpRank.continuesUsed++; } retrying = true; diff --git a/src/k_battle.c b/src/k_battle.c index 8e5db972b..4c5c01b54 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -20,6 +20,7 @@ #include "k_boss.h" // bossinfo.valid #include "p_spec.h" #include "k_objects.h" +#include "k_rank.h" // Battle overtime info struct battleovertime battleovertime; @@ -780,7 +781,7 @@ void K_BattleInit(boolean singleplayercontext) P_SpawnMapThing(mt); } - gpRank.totalCapsules += maptargets; + g_gpRank.totalCapsules += maptargets; battlecapsules = true; } diff --git a/src/k_grandprix.c b/src/k_grandprix.c index c061d271f..bc4779386 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -21,7 +21,6 @@ #include "r_things.h" struct grandprixinfo grandprixinfo; -struct gpRank gpRank; /*-------------------------------------------------- UINT8 K_BotStartingDifficulty(SINT8 value) @@ -116,13 +115,11 @@ UINT8 K_BotDefaultSkin(void) } /*-------------------------------------------------- - static UINT8 K_GetGPPlayerCount(UINT8 humans) + UINT8 K_GetGPPlayerCount(UINT8 humans) - Counts the number of total players, - including humans and bots, to put into - a GP session. + See header file for description. --------------------------------------------------*/ -static UINT8 K_GetGPPlayerCount(UINT8 humans) +UINT8 K_GetGPPlayerCount(UINT8 humans) { UINT8 playerCount = 8; @@ -135,66 +132,6 @@ static UINT8 K_GetGPPlayerCount(UINT8 humans) return playerCount; } -/*-------------------------------------------------- - void K_InitGrandPrixRank(void) - - See header file for description. ---------------------------------------------------*/ -void K_InitGrandPrixRank(void) -{ - UINT8 numHumans = 0; - INT32 i; - - memset(&gpRank, 0, sizeof(gpRank)); - - if (grandprixinfo.cup == NULL) - { - return; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - { - if (numHumans < MAXSPLITSCREENPLAYERS && players[i].spectator == false) - { - numHumans++; - } - } - } - - // Calculate players - gpRank.players = numHumans; - gpRank.totalPlayers = K_GetGPPlayerCount(numHumans); - - // Calculate total of points - // (Should this account for all coop players?) - for (i = 0; i < numHumans; i++) - { - gpRank.totalPoints += grandprixinfo.cup->numlevels * K_CalculateGPRankPoints(i + 1, gpRank.totalPlayers); - } - - gpRank.totalRings = grandprixinfo.cup->numlevels * numHumans * 20; - - UINT32 laps = 0; - for (i = 0; i < grandprixinfo.cup->numlevels; i++) - { - const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[i]; - if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] != NULL) - { - laps += mapheaderinfo[cupLevelNum]->numlaps; - } - } - - // +1, since 1st place laps are worth 2 pts. - for (i = 0; i < numHumans+1; i++) - { - gpRank.totalLaps += laps; - } - - // Total capsules will need to be calculated as you enter the bonus stages... -} - /*-------------------------------------------------- void K_InitGrandPrixBots(void) @@ -804,75 +741,3 @@ boolean K_CanChangeRules(boolean allowdemos) return true; } - -/*-------------------------------------------------- - gp_rank_e K_CalculateGPGrade(void) - - See header file for description. ---------------------------------------------------*/ -gp_rank_e K_CalculateGPGrade(void) -{ - static const fixed_t gradePercents[GRADE_A] = { - 9*FRACUNIT/20, // GRADE_E -> GRADE_D - 12*FRACUNIT/20, // GRADE_D -> GRADE_C - 15*FRACUNIT/20, // GRADE_C -> GRADE_B - 18*FRACUNIT/20 // GRADE_B -> GRADE_A - }; - - gp_rank_e retGrade = GRADE_E; - - // TODO: - 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; - - INT32 ours = 0; - fixed_t percent = 0; - - if (gpRank.totalPoints > 0) - { - ours += (gpRank.winPoints * pointsWeight) / gpRank.totalPoints; - } - - if (gpRank.totalLaps > 0) - { - ours += (gpRank.laps * lapsWeight) / gpRank.totalLaps; - } - - if (gpRank.totalCapsules > 0) - { - ours += (gpRank.capsules * capsulesWeight) / gpRank.totalCapsules; - } - - if (gpRank.totalRings > 0) - { - ours += (gpRank.rings * ringsWeight) / gpRank.totalRings; - } - - ours += (gpRank.difficulty * difficultyWeight) / MAXBOTDIFFICULTY; - - ours -= gpRank.continuesUsed * continuesPenalty; - - percent = FixedDiv(ours, total); - - for (retGrade = 0; retGrade < GRADE_A; retGrade++) - { - if (percent < gradePercents[retGrade]) - { - break; - } - } - - if (gpRank.specialWon == true) - { - // Winning the Special Stage gives you - // a free grade increase. - retGrade++; - } - - return retGrade; -} diff --git a/src/k_grandprix.h b/src/k_grandprix.h index 9103b047f..2bd3be61c 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -37,39 +37,6 @@ extern struct grandprixinfo UINT8 eventmode; ///< See GPEVENT_ constants } grandprixinfo; -extern struct gpRank -{ - UINT8 players; - UINT8 totalPlayers; - - UINT32 winPoints; - UINT32 totalPoints; - - UINT32 laps; - UINT32 totalLaps; - - UINT32 continuesUsed; - - UINT32 capsules; - UINT32 totalCapsules; - - UINT32 rings; - UINT32 totalRings; - - boolean specialWon; - UINT8 difficulty; -} gpRank; - -typedef enum -{ - GRADE_E, - GRADE_D, - GRADE_C, - GRADE_B, - GRADE_A, - GRADE_S -} gp_rank_e; - /*-------------------------------------------------- UINT8 K_BotStartingDifficulty(SINT8 value); @@ -112,13 +79,23 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers); UINT8 K_BotDefaultSkin(void); -/*-------------------------------------------------- - void K_InitGrandPrixRank(void); - Calculates rank requirements for a GP session. +/*-------------------------------------------------- + UINT8 K_GetGPPlayerCount(UINT8 humans) + + Counts the number of total players, + including humans and bots, to put into + a GP session. + + Input Arguments:- + humans - Number of human players. + + Return:- + Number of both human players and CPU. --------------------------------------------------*/ -void K_InitGrandPrixRank(void); +UINT8 K_GetGPPlayerCount(UINT8 humans); + /*-------------------------------------------------- void K_InitGrandPrixBots(void); @@ -209,20 +186,6 @@ void K_PlayerLoseLife(player_t *player); boolean K_CanChangeRules(boolean allowdemos); -/*-------------------------------------------------- - gp_rank_e K_CalculateGPGrade(void); - - Calculates the player's grade using the - variables from gpRank. - - Input Arguments:- - N/A - - Return:- - gp_rank_e representing the total grade. ---------------------------------------------------*/ - -gp_rank_e K_CalculateGPGrade(void); #ifdef __cplusplus } // extern "C" diff --git a/src/k_hud.c b/src/k_hud.c index 947032b41..27bed0e83 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -37,6 +37,8 @@ #include "r_fps.h" #include "m_random.h" #include "k_roulette.h" +#include "k_bot.h" +#include "k_rank.h" //{ Patch Definitions static patch_t *kp_nodraw; @@ -5070,23 +5072,23 @@ void K_drawKartHUD(void) if (grandprixinfo.gp == true) { - gp_rank_e grade = K_CalculateGPGrade(); + gp_rank_e grade = K_CalculateGPGrade(&g_gpRank); char gradeChar = '?'; V_DrawThinString(0, 0, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("PTS: %d / %d", gpRank.winPoints, gpRank.totalPoints)); + va("PTS: %d / %d", g_gpRank.winPoints, g_gpRank.totalPoints)); V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("LAPS: %d / %d", gpRank.laps, gpRank.totalLaps)); + va("LAPS: %d / %d", g_gpRank.laps, g_gpRank.totalLaps)); V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("CONTINUES: %d", gpRank.continuesUsed)); + va("CONTINUES: %d", g_gpRank.continuesUsed)); V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("CAPSULES: %d / %d", gpRank.capsules, gpRank.totalCapsules)); + va("CAPSULES: %d / %d", g_gpRank.capsules, g_gpRank.totalCapsules)); V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("RINGS: %d / %d", gpRank.rings, gpRank.totalRings)); + va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings)); V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("SPECIAL: %d", gpRank.specialWon)); + va("DIFFICULTY: %d / %d", g_gpRank.difficulty, MAXBOTDIFFICULTY)); V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("DIFFICULTY: %d", gpRank.difficulty)); + va("SPECIAL: %s", (g_gpRank.specialWon == true) ? "YES" : "NO")); switch (grade) { diff --git a/src/k_rank.c b/src/k_rank.c new file mode 100644 index 000000000..629bf1640 --- /dev/null +++ b/src/k_rank.c @@ -0,0 +1,156 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) by Sally "TehRealSalt" Cochenour +// Copyright (C) by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_rank.c +/// \brief Grand Prix mode ranking + +#include "k_rank.h" +#include "k_grandprix.h" +#include "k_specialstage.h" +#include "doomdef.h" +#include "d_player.h" +#include "g_game.h" +#include "k_bot.h" +#include "k_kart.h" +#include "m_random.h" +#include "r_things.h" + +gpRank_t g_gpRank = {0}; + +/*-------------------------------------------------- + void K_InitGrandPrixRank(gpRank_t *rankData) + + See header file for description. +--------------------------------------------------*/ +void K_InitGrandPrixRank(gpRank_t *rankData) +{ + UINT8 numHumans = 0; + INT32 i; + + memset(rankData, 0, sizeof(gpRank_t)); + + if (grandprixinfo.cup == NULL) + { + return; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + if (numHumans < MAXSPLITSCREENPLAYERS && players[i].spectator == false) + { + numHumans++; + } + } + } + + // Calculate players + rankData->players = numHumans; + rankData->totalPlayers = K_GetGPPlayerCount(numHumans); + + // Calculate total of points + // (Should this account for all coop players?) + for (i = 0; i < numHumans; i++) + { + rankData->totalPoints += grandprixinfo.cup->numlevels * K_CalculateGPRankPoints(i + 1, rankData->totalPlayers); + } + + rankData->totalRings = grandprixinfo.cup->numlevels * numHumans * 20; + + UINT32 laps = 0; + for (i = 0; i < grandprixinfo.cup->numlevels; i++) + { + const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[i]; + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] != NULL) + { + laps += mapheaderinfo[cupLevelNum]->numlaps; + } + } + + // +1, since 1st place laps are worth 2 pts. + for (i = 0; i < numHumans+1; i++) + { + rankData->totalLaps += laps; + } + + // Total capsules will need to be calculated as you enter the bonus stages... +} + +/*-------------------------------------------------- + gp_rank_e K_CalculateGPGrade(gpRank_t *rankData) + + See header file for description. +--------------------------------------------------*/ +gp_rank_e K_CalculateGPGrade(gpRank_t *rankData) +{ + static const fixed_t gradePercents[GRADE_A] = { + 9*FRACUNIT/20, // GRADE_E -> GRADE_D + 12*FRACUNIT/20, // GRADE_D -> GRADE_C + 15*FRACUNIT/20, // GRADE_C -> GRADE_B + 18*FRACUNIT/20 // GRADE_B -> GRADE_A + }; + + gp_rank_e retGrade = GRADE_E; + + // TODO: Balance requirements + 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; + + INT32 ours = 0; + fixed_t percent = 0; + + if (rankData->totalPoints > 0) + { + ours += (rankData->winPoints * pointsWeight) / rankData->totalPoints; + } + + if (rankData->totalLaps > 0) + { + ours += (rankData->laps * lapsWeight) / rankData->totalLaps; + } + + if (rankData->totalCapsules > 0) + { + ours += (rankData->capsules * capsulesWeight) / rankData->totalCapsules; + } + + if (rankData->totalRings > 0) + { + ours += (rankData->rings * ringsWeight) / rankData->totalRings; + } + + ours += (rankData->difficulty * difficultyWeight) / MAXBOTDIFFICULTY; + + ours -= rankData->continuesUsed * continuesPenalty; + + percent = FixedDiv(ours, total); + + for (retGrade = 0; retGrade < GRADE_A; retGrade++) + { + if (percent < gradePercents[retGrade]) + { + break; + } + } + + if (rankData->specialWon == true) + { + // Winning the Special Stage gives you + // a free grade increase. + retGrade++; + } + + return retGrade; +} diff --git a/src/k_rank.h b/src/k_rank.h new file mode 100644 index 000000000..6f417ce82 --- /dev/null +++ b/src/k_rank.h @@ -0,0 +1,95 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) by Sally "TehRealSalt" Cochenour +// Copyright (C) by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_rank.h +/// \brief Grand Prix mode ranking + +#ifndef __K_RANK__ +#define __K_RANK__ + +#include "doomdef.h" +#include "doomstat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct gpRank_t +{ + UINT8 players; + UINT8 totalPlayers; + + UINT32 winPoints; + UINT32 totalPoints; + + UINT32 laps; + UINT32 totalLaps; + + UINT32 continuesUsed; + + UINT32 capsules; + UINT32 totalCapsules; + + UINT32 rings; + UINT32 totalRings; + + boolean specialWon; + UINT8 difficulty; +}; + +extern gpRank_t g_gpRank; + +typedef enum +{ + GRADE_E, + GRADE_D, + GRADE_C, + GRADE_B, + GRADE_A, + GRADE_S +} gp_rank_e; + + +/*-------------------------------------------------- + void K_InitGrandPrixRank(gpRank_t *rankData); + + Calculates rank requirements for a GP session. + + Input Arguments:- + rankData - Pointer to struct that contains all + of the information required to calculate GP rank. + + Return:- + N/A +--------------------------------------------------*/ + +void K_InitGrandPrixRank(gpRank_t *rankData); + + +/*-------------------------------------------------- + gp_rank_e K_CalculateGPGrade(gpRank_t *rankData); + + Calculates the player's grade using the + variables from gpRank. + + Input Arguments:- + rankData - struct containing existing rank data. + + Return:- + gp_rank_e representing the total grade. +--------------------------------------------------*/ + +gp_rank_e K_CalculateGPGrade(gpRank_t *rankData); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/src/p_inter.c b/src/p_inter.c index be0de4620..3d69eec25 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1595,8 +1595,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget K_SpawnBattlePoints(source->player, NULL, 1); } - gpRank.capsules++; - // All targets busted! if (++numtargets >= maptargets) { diff --git a/src/p_setup.c b/src/p_setup.c index e8043d56e..fe769e1e5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -102,6 +102,7 @@ #include "acs/interface.h" #include "doomstat.h" // MAXMUSNAMES #include "k_podium.h" +#include "k_rank.h" // Replay names have time #if !defined (UNDER_CE) @@ -7388,7 +7389,7 @@ static void P_InitGametype(void) { if (grandprixinfo.initalize == true) { - K_InitGrandPrixRank(); + K_InitGrandPrixRank(&g_gpRank); K_InitGrandPrixBots(); grandprixinfo.initalize = false; } diff --git a/src/p_spec.c b/src/p_spec.c index e81620426..94506b429 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2000,34 +2000,6 @@ static void K_HandleLapIncrement(player_t *player) } } - // finished race exit setup - if (player->laps > numlaps) - { - if (specialstageinfo.valid == true) - { - // Don't permit a win just by sneaking ahead of the UFO/emerald. - if (!(specialstageinfo.ufo == NULL || P_MobjWasRemoved(specialstageinfo.ufo))) - { - player->pflags |= PF_NOCONTEST; - } - } - - P_DoPlayerExit(player); - - if (!(player->pflags & PF_NOCONTEST)) - P_SetupSignExit(player); - } - else - { - UINT32 skinflags = (demo.playback) - ? demo.skinlist[demo.currentskinid[(player-players)]].flags - : skins[player->skin].flags; - if (skinflags & SF_IRONMAN) - { - SetRandomFakePlayerSkin(player, true); - } - } - if (player->laps > player->latestlap) { if (player->laps > 1) @@ -2062,8 +2034,35 @@ static void K_HandleLapIncrement(player_t *player) player->latestlap = player->laps; } - thwompsactive = true; // Lap 2 effects + // finished race exit setup + if (player->laps > numlaps) + { + if (specialstageinfo.valid == true) + { + // Don't permit a win just by sneaking ahead of the UFO/emerald. + if (!(specialstageinfo.ufo == NULL || P_MobjWasRemoved(specialstageinfo.ufo))) + { + player->pflags |= PF_NOCONTEST; + } + } + P_DoPlayerExit(player); + + if (!(player->pflags & PF_NOCONTEST)) + P_SetupSignExit(player); + } + else + { + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[(player-players)]].flags + : skins[player->skin].flags; + if (skinflags & SF_IRONMAN) + { + SetRandomFakePlayerSkin(player, true); + } + } + + thwompsactive = true; // Lap 2 effects lowestLap = P_FindLowestLap(); for (i = 0; i < numlines; i++) diff --git a/src/p_user.c b/src/p_user.c index 140e2c7de..7c0a9f13a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -58,6 +58,8 @@ #include "k_terrain.h" // K_SpawnSplashForMobj #include "k_color.h" #include "k_follower.h" +#include "k_battle.h" +#include "k_rank.h" #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -1353,7 +1355,7 @@ void P_DoPlayerExit(player_t *player) if (RINGTOTAL(player) > 0) { player->totalring += RINGTOTAL(player); - gpRank.rings += player->totalring; + g_gpRank.rings += RINGTOTAL(player); extra = player->totalring / lifethreshold; @@ -1367,13 +1369,15 @@ void P_DoPlayerExit(player_t *player) if (grandprixinfo.eventmode == GPEVENT_NONE) { - gpRank.winPoints += K_CalculateGPRankPoints(player->position, gpRank.totalPlayers); - gpRank.laps += player->lapPoints; + g_gpRank.winPoints += K_CalculateGPRankPoints(player->position, g_gpRank.totalPlayers); + g_gpRank.laps += player->lapPoints; } else if (grandprixinfo.eventmode == GPEVENT_SPECIAL) { - gpRank.specialWon = true; + g_gpRank.specialWon = true; } + + g_gpRank.capsules += numtargets; } } } diff --git a/src/typedef.h b/src/typedef.h index 0b745eb30..ae61dea9a 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -198,6 +198,9 @@ TYPEDEF (t_floor_t); // k_waypoint.h TYPEDEF (waypoint_t); +// k_rank.h +TYPEDEF (gpRank_t); + // lua_hudlib_drawlist.h typedef struct huddrawlist_s *huddrawlist_h; From f7851623ff979d8d82b57034a6201c4510039508 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 23 Feb 2023 12:43:08 -0500 Subject: [PATCH 03/13] Calculate a bot difficulty to reach 13 is very unlikely for Normal, likely impossible for Easy. (If we want a bonus game speeds, it should be explicitly defined) --- src/k_hud.c | 2 +- src/k_rank.c | 19 +++++++++++++++++-- src/k_rank.h | 4 +++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 27bed0e83..7fe62a8a6 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5086,7 +5086,7 @@ void K_drawKartHUD(void) V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings)); V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("DIFFICULTY: %d / %d", g_gpRank.difficulty, MAXBOTDIFFICULTY)); + va("DIFFICULTY: %d / %d", g_gpRank.difficulty, g_gpRank.difficultyTarget)); V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, va("SPECIAL: %s", (g_gpRank.specialWon == true) ? "YES" : "NO")); diff --git a/src/k_rank.c b/src/k_rank.c index 629bf1640..bf548b1ed 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -31,6 +31,7 @@ gpRank_t g_gpRank = {0}; void K_InitGrandPrixRank(gpRank_t *rankData) { UINT8 numHumans = 0; + UINT32 laps = 0; INT32 i; memset(rankData, 0, sizeof(gpRank_t)); @@ -64,7 +65,18 @@ void K_InitGrandPrixRank(gpRank_t *rankData) rankData->totalRings = grandprixinfo.cup->numlevels * numHumans * 20; - UINT32 laps = 0; + if (grandprixinfo.masterbots == true) + { + rankData->difficultyTarget = MAXBOTDIFFICULTY; + } + else + { + rankData->difficultyTarget = min( + MAXBOTDIFFICULTY, + K_BotStartingDifficulty(grandprixinfo.gamespeed) + ((grandprixinfo.cup->numlevels + 1) / 2) + ); + } + for (i = 0; i < grandprixinfo.cup->numlevels; i++) { const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[i]; @@ -131,7 +143,10 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData) ours += (rankData->rings * ringsWeight) / rankData->totalRings; } - ours += (rankData->difficulty * difficultyWeight) / MAXBOTDIFFICULTY; + if (rankData->difficultyTarget > 0) + { + ours += (rankData->difficulty * difficultyWeight) / rankData->difficultyTarget; + } ours -= rankData->continuesUsed * continuesPenalty; diff --git a/src/k_rank.h b/src/k_rank.h index 6f417ce82..93c139df0 100644 --- a/src/k_rank.h +++ b/src/k_rank.h @@ -39,8 +39,10 @@ struct gpRank_t UINT32 rings; UINT32 totalRings; - boolean specialWon; UINT8 difficulty; + UINT8 difficultyTarget; + + boolean specialWon; }; extern gpRank_t g_gpRank; From 6a4b4d8b70e0327f116565cc444152854eec8f9e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 23 Feb 2023 13:22:12 -0500 Subject: [PATCH 04/13] Balance rank requirements Old values were taken from Snap, which has a small number of very straight-forward and relatively easy to 100% requirements, so it has very high standards. RR has lots of requirements, they're slightly more nuanced, and it's extremely improbable to have them all 100% in one run even if you're good. - Toned A rank down very slightly. (90% -> 85%) - Rest of the ranks are more evenly distributed. (D: 45% -> 35%, C: 60% -> 50%, B: 75% -> 70%) --- src/k_rank.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/k_rank.c b/src/k_rank.c index bf548b1ed..b4d2b90df 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -103,15 +103,14 @@ void K_InitGrandPrixRank(gpRank_t *rankData) gp_rank_e K_CalculateGPGrade(gpRank_t *rankData) { static const fixed_t gradePercents[GRADE_A] = { - 9*FRACUNIT/20, // GRADE_E -> GRADE_D - 12*FRACUNIT/20, // GRADE_D -> GRADE_C - 15*FRACUNIT/20, // GRADE_C -> GRADE_B - 18*FRACUNIT/20 // GRADE_B -> GRADE_A + 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 }; gp_rank_e retGrade = GRADE_E; - // TODO: Balance requirements const INT32 pointsWeight = 100; const INT32 lapsWeight = 100; const INT32 capsulesWeight = 100; From 3d1070c2f219663d74772a2e976c0b439d51db50 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 4 Mar 2023 00:37:51 -0500 Subject: [PATCH 05/13] Show ranking data on the screen --- src/d_netcmd.c | 1 + src/d_netcmd.h | 1 + src/k_hud.c | 88 ++++++++++++++++++++++---------------- src/k_kart.c | 1 + src/k_podium.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 166 insertions(+), 37 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 54ebdcebd..a1fae65f2 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -453,6 +453,7 @@ consvar_t cv_kartdebugcolorize = CVAR_INIT ("debugcolorize", "Off", CV_CHEAT, CV consvar_t cv_kartdebugdirector = CVAR_INIT ("debugdirector", "Off", CV_CHEAT, CV_OnOff, NULL); consvar_t cv_spbtest = CVAR_INIT ("spbtest", "Off", CV_CHEAT|CV_NETVAR, CV_OnOff, NULL); consvar_t cv_gptest = CVAR_INIT ("gptest", "Off", CV_CHEAT|CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_debugrank = CVAR_INIT ("debugrank", "Off", CV_CHEAT, CV_OnOff, NULL); static CV_PossibleValue_t capsuletest_cons_t[] = { {CV_CAPSULETEST_OFF, "Off"}, diff --git a/src/d_netcmd.h b/src/d_netcmd.h index a126de023..e6c10fa11 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -96,6 +96,7 @@ extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugdistribution, extern consvar_t cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector; extern consvar_t cv_spbtest, cv_gptest, cv_reducevfx; extern consvar_t cv_kartdebugwaypoints, cv_kartdebugbotpredict; +extern consvar_t cv_debugrank; typedef enum { CV_CAPSULETEST_OFF, diff --git a/src/k_hud.c b/src/k_hud.c index 7fe62a8a6..af93c6ef0 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4798,6 +4798,58 @@ static void K_DrawWaypointDebugger(void) } } +static void K_DrawGPRankDebugger(void) +{ + gp_rank_e grade = GRADE_E; + char gradeChar = '?'; + + if (cv_debugrank.value == 0) + { + return; + } + + if (stplyr != &players[displayplayers[0]]) // only for p1 + { + return; + } + + if (grandprixinfo.gp == false) + { + return; + } + + 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)); + V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("LAPS: %d / %d", g_gpRank.laps, g_gpRank.totalLaps)); + V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("CONTINUES: %d", g_gpRank.continuesUsed)); + V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("CAPSULES: %d / %d", g_gpRank.capsules, g_gpRank.totalCapsules)); + V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings)); + V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("DIFFICULTY: %d / %d", g_gpRank.difficulty, g_gpRank.difficultyTarget)); + V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + va("SPECIAL: %s", (g_gpRank.specialWon == true) ? "YES" : "NO")); + + switch (grade) + { + case GRADE_E: { gradeChar = 'E'; break; } + case GRADE_D: { gradeChar = 'D'; break; } + case GRADE_C: { gradeChar = 'C'; break; } + case GRADE_B: { gradeChar = 'B'; break; } + case GRADE_A: { gradeChar = 'A'; break; } + case GRADE_S: { gradeChar = 'S'; break; } + default: { break; } + } + + V_DrawThinString(0, 80, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_YELLOWMAP, + va(" ** FINAL GRADE: %c", gradeChar)); +} + void K_drawKartHUD(void) { boolean islonesome = false; @@ -5069,39 +5121,5 @@ void K_drawKartHUD(void) K_DrawWaypointDebugger(); K_DrawDirectorDebugger(); - - if (grandprixinfo.gp == true) - { - gp_rank_e grade = K_CalculateGPGrade(&g_gpRank); - char gradeChar = '?'; - - V_DrawThinString(0, 0, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("PTS: %d / %d", g_gpRank.winPoints, g_gpRank.totalPoints)); - V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("LAPS: %d / %d", g_gpRank.laps, g_gpRank.totalLaps)); - V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("CONTINUES: %d", g_gpRank.continuesUsed)); - V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("CAPSULES: %d / %d", g_gpRank.capsules, g_gpRank.totalCapsules)); - V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings)); - V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("DIFFICULTY: %d / %d", g_gpRank.difficulty, g_gpRank.difficultyTarget)); - V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("SPECIAL: %s", (g_gpRank.specialWon == true) ? "YES" : "NO")); - - switch (grade) - { - case GRADE_E: { gradeChar = 'E'; break; } - case GRADE_D: { gradeChar = 'D'; break; } - case GRADE_C: { gradeChar = 'C'; break; } - case GRADE_B: { gradeChar = 'B'; break; } - case GRADE_A: { gradeChar = 'A'; break; } - case GRADE_S: { gradeChar = 'S'; break; } - default: { break; } - } - - V_DrawThinString(0, 80, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_YELLOWMAP, - va(" ** FINAL GRADE: %c", gradeChar)); - } + K_DrawGPRankDebugger(); } diff --git a/src/k_kart.c b/src/k_kart.c index 6b1a54739..10ab61c8d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -347,6 +347,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartdebugnodes); CV_RegisterVar(&cv_kartdebugcolorize); CV_RegisterVar(&cv_kartdebugdirector); + CV_RegisterVar(&cv_debugrank); CV_RegisterVar(&cv_spbtest); CV_RegisterVar(&cv_gptest); CV_RegisterVar(&cv_capsuletest); diff --git a/src/k_podium.c b/src/k_podium.c index c7d5a4af1..0ff0e23a5 100644 --- a/src/k_podium.c +++ b/src/k_podium.c @@ -45,13 +45,20 @@ #include "k_menu.h" #include "k_grandprix.h" +#include "k_rank.h" static struct podiumData_s { boolean ranking; + gpRank_t rankData; + gp_rank_e grade; + UINT8 state; + UINT8 delay; UINT8 fade; } podiumData; +#define PODIUM_STATES (9) // TODO: enum + /*-------------------------------------------------- boolean K_PodiumSequence(void) @@ -267,6 +274,14 @@ void K_FinishCeremony(void) void K_ResetCeremony(void) { memset(&podiumData, 0, sizeof(struct podiumData_s)); + + if (K_PodiumSequence() == false) + { + return; + } + + podiumData.rankData = g_gpRank; + podiumData.grade = K_CalculateGPGrade(&podiumData.rankData); } /*-------------------------------------------------- @@ -305,6 +320,19 @@ void K_CeremonyTicker(boolean run) { podiumData.fade++; } + else + { + if (podiumData.state < PODIUM_STATES) + { + podiumData.delay++; + + if (podiumData.delay > TICRATE) + { + podiumData.state++; + podiumData.delay = 0; + } + } + } } } @@ -317,7 +345,7 @@ boolean K_CeremonyResponder(event_t *event) { INT32 key = event->data1; - if (podiumData.ranking == false || podiumData.fade < 16) + if (podiumData.ranking == false || podiumData.state < PODIUM_STATES) { return false; } @@ -377,8 +405,88 @@ void K_CeremonyDrawer(void) { if (podiumData.ranking == true) { + char gradeChar = '?'; + INT32 x = 64; + INT32 y = 48; + INT32 i; + + switch (podiumData.grade) + { + case GRADE_E: { gradeChar = 'E'; break; } + case GRADE_D: { gradeChar = 'D'; break; } + case GRADE_C: { gradeChar = 'C'; break; } + case GRADE_B: { gradeChar = 'B'; break; } + case GRADE_A: { gradeChar = 'A'; break; } + case GRADE_S: { gradeChar = 'S'; break; } + default: { break; } + } + V_DrawFadeScreen(0xFF00, podiumData.fade); - V_DrawCenteredString(BASEVIDWIDTH / 2, 64, 0, "STUFF GOES HERE"); + + for (i = 0; i <= podiumData.state; i++) + { + switch (i) + { + case 1: + { + V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + va("PTS: %d / %d", g_gpRank.winPoints, g_gpRank.totalPoints) + ); + break; + } + case 2: + { + V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + va("LAPS: %d / %d", g_gpRank.laps, g_gpRank.totalLaps) + ); + break; + } + case 3: + { + V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + va("CONTINUES: %d", g_gpRank.continuesUsed) + ); + break; + } + case 4: + { + V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + va("CAPSULES: %d / %d", g_gpRank.capsules, g_gpRank.totalCapsules) + ); + break; + } + case 5: + { + V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings) + ); + break; + } + case 6: + { + V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + va("DIFFICULTY: %d / %d", g_gpRank.difficulty, g_gpRank.difficultyTarget) + ); + break; + } + case 7: + { + V_DrawString(x, y, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + va("SPECIAL: %s", (g_gpRank.specialWon == true) ? "YES" : "NO") + ); + break; + } + case 8: + { + V_DrawString(x, y + 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, + va(" ** FINAL GRADE: %c", gradeChar) + ); + break; + } + } + + y += 10; + } } if (timeinmap < 16) From 3c076419383e970bc8b57e243820646873f6cb9f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 4 Mar 2023 16:16:37 -0500 Subject: [PATCH 06/13] 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); From d5d0647ae6b858030fde139e30990c83c25c0c8f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 4 Mar 2023 16:27:22 -0500 Subject: [PATCH 07/13] Remove difficulty as a ranking requirement Was a cute idea, but removing it since it's not something you can 100% guarantee every time, which was the same reasoning for getting rid of times getting damaged / dealing damage from the requirements. --- src/g_game.c | 7 +------ src/k_hud.c | 4 +--- src/k_podium.c | 15 ++++----------- src/k_rank.c | 32 +++++++------------------------- src/k_rank.h | 3 --- 5 files changed, 13 insertions(+), 48 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 22760c3e0..aae7d02a3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4129,7 +4129,6 @@ static void G_DoCompleted(void) wipegamestate = GS_NULL; g_gpRank.position = MAXPLAYERS; - g_gpRank.difficulty = 0; for (i = 0; i < MAXPLAYERS; i++) { @@ -4157,11 +4156,7 @@ static void G_DoCompleted(void) G_PlayerFinishLevel(i); // take away cards and stuff - if (players[i].bot) - { - g_gpRank.difficulty = max(g_gpRank.difficulty, players[i].botvars.difficulty); - } - else + if (players[i].bot == false) { g_gpRank.position = min(g_gpRank.position, K_GetPodiumPosition(&players[i])); } diff --git a/src/k_hud.c b/src/k_hud.c index db1464ceb..630baca43 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4833,8 +4833,6 @@ static void K_DrawGPRankDebugger(void) V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings)); V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - 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) @@ -4848,7 +4846,7 @@ static void K_DrawGPRankDebugger(void) default: { break; } } - V_DrawThinString(0, 90, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_YELLOWMAP, + V_DrawThinString(0, 80, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_YELLOWMAP, va(" ** FINAL GRADE: %c", gradeChar)); } diff --git a/src/k_podium.c b/src/k_podium.c index 2e610db1b..cf8c3cc85 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 (10) // TODO: enum when this actually gets made +#define PODIUM_STATES (9) // TODO: enum when this actually gets made /*-------------------------------------------------- boolean K_PodiumSequence(void) @@ -470,29 +470,22 @@ void K_CeremonyDrawer(void) break; } case 7: - { - V_DrawString(x, y, V_ALLOWLOWERCASE, - va("DIFFICULTY: %d / %d", podiumData.rankData.difficulty, podiumData.rankData.difficultyTarget) - ); - break; - } - case 8: { V_DrawString(x, y, V_ALLOWLOWERCASE, va("EMERALD: %s", (podiumData.rankData.specialWon == true) ? "YES" : "NO") ); break; } - case 9: + case 8: { V_DrawString(x, y + 10, V_YELLOWMAP|V_ALLOWLOWERCASE, va(" ** FINAL GRADE: %c", gradeChar) ); break; } - case 10: + case 9: { - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, BASEVIDHEIGHT - 10, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, + V_DrawThinString(2, BASEVIDHEIGHT - 10, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, "Press some button type deal to continue" ); break; diff --git a/src/k_rank.c b/src/k_rank.c index 08bf19c80..369b940e1 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -68,18 +68,6 @@ void K_InitGrandPrixRank(gpRank_t *rankData) rankData->totalRings = grandprixinfo.cup->numlevels * numHumans * 20; - if (grandprixinfo.masterbots == true) - { - rankData->difficultyTarget = MAXBOTDIFFICULTY; - } - else - { - rankData->difficultyTarget = min( - MAXBOTDIFFICULTY, - K_BotStartingDifficulty(grandprixinfo.gamespeed) + ((grandprixinfo.cup->numlevels + 1) / 2) - ); - } - for (i = 0; i < grandprixinfo.cup->numlevels; i++) { const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[i]; @@ -114,14 +102,13 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData) gp_rank_e retGrade = GRADE_E; - 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; + const INT32 positionWeight = 150; + const INT32 pointsWeight = 100; + const INT32 lapsWeight = 100; + const INT32 capsulesWeight = 100; + const INT32 ringsWeight = 50; + const INT32 total = positionWeight + pointsWeight + lapsWeight + capsulesWeight + ringsWeight; + const INT32 continuesPenalty = 20; INT32 ours = 0; fixed_t percent = 0; @@ -153,11 +140,6 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData) ours += (rankData->rings * ringsWeight) / rankData->totalRings; } - if (rankData->difficultyTarget > 0) - { - ours += (rankData->difficulty * difficultyWeight) / rankData->difficultyTarget; - } - ours -= rankData->continuesUsed * continuesPenalty; percent = FixedDiv(ours, total); diff --git a/src/k_rank.h b/src/k_rank.h index b86744c7e..093bb178e 100644 --- a/src/k_rank.h +++ b/src/k_rank.h @@ -41,9 +41,6 @@ struct gpRank_t UINT32 rings; UINT32 totalRings; - UINT8 difficulty; - UINT8 difficultyTarget; - boolean specialWon; }; From cf20e2e8311d7886838777cd1986af030f7754fd Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 4 Mar 2023 16:35:50 -0500 Subject: [PATCH 08/13] SS requirement is now getting A rank --- src/g_game.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index aae7d02a3..c7c423d03 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3887,20 +3887,9 @@ static void G_GetNextMap(void) // Special stage else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) { - INT16 totaltotalring = 0; + gp_rank_e grade = K_CalculateGPGrade(&g_gpRank); - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - if (players[i].spectator) - continue; - if (players[i].bot) - continue; - totaltotalring += players[i].totalring; - } - - if (totaltotalring >= 50) + if (grade >= GRADE_A) // On A rank pace? Then you get a chance for S rank! { const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_SPECIAL]; if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) From 57f53a5531f638229b898e476bae7a21cd7eb1af Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 4 Mar 2023 19:02:40 -0500 Subject: [PATCH 09/13] Search bonus maps to calculate total capsules No more moving goalpost! This means we can put it on the intermission screen and not just the final rankings screen. --- src/k_battle.c | 1 - src/k_rank.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 255 insertions(+), 2 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index 4c5c01b54..a49883f6f 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -781,7 +781,6 @@ void K_BattleInit(boolean singleplayercontext) P_SpawnMapThing(mt); } - g_gpRank.totalCapsules += maptargets; battlecapsules = true; } diff --git a/src/k_rank.c b/src/k_rank.c index 369b940e1..09651015a 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -20,9 +20,240 @@ #include "k_kart.h" #include "m_random.h" #include "r_things.h" +#include "fastcmp.h" +#include "byteptr.h" gpRank_t g_gpRank = {0}; +// I was ALMOST tempted to start tearing apart all +// of the map loading code and turning it into C++ +// and making it properly split between read-only +// and true level loading and clean up all of the +// global variable garbage it uses ... but I stopped +// myself. So here's code duplication hell instead. +static UINT32 g_rankCapsules_mapthingsPos[UINT16_MAX]; +static size_t g_rankCapsules_nummapthings = 0; +static boolean g_rankCapsules_udmf = false; +static UINT32 g_rankCapsules_count = 0; + +/*-------------------------------------------------- + static void RankCapsules_TextmapCount(size_t size) + + Counts the number of map things and records + the structure positions, for the result of + RankCapsules_CountFromMap. + + Input Arguments:- + size - Length of the TEXTMAP lump. + + Return:- + N/A +--------------------------------------------------*/ +static UINT32 RankCapsules_TextmapCount(size_t size) +{ + const char *tkn = M_TokenizerRead(0); + UINT8 brackets = 0; + + g_rankCapsules_nummapthings = 0; + + // Look for namespace at the beginning. + if (!fastcmp(tkn, "namespace")) + { + return false; + } + + // Check if namespace is valid. + tkn = M_TokenizerRead(0); + + while ((tkn = M_TokenizerRead(0)) && M_TokenizerGetEndPos() < size) + { + // Avoid anything inside bracketed stuff, only look for external keywords. + if (brackets) + { + if (fastcmp(tkn, "}")) + brackets--; + } + else if (fastcmp(tkn, "{")) + brackets++; + // Check for valid fields. + else if (fastcmp(tkn, "thing")) + g_rankCapsules_mapthingsPos[g_rankCapsules_nummapthings++] = M_TokenizerGetEndPos(); + } + + if (brackets) + { + return false; + } + + return true; +} + +/*-------------------------------------------------- + static void RankCapsules_LoadTextmap(void) + + Loads UDMF map data for the result of + RankCapsules_CountFromMap. +--------------------------------------------------*/ +static void RankCapsules_LoadTextmap(void) +{ + size_t i; + + for (i = 0; i < g_rankCapsules_nummapthings; i++) + { + const char *param, *val; + + M_TokenizerSetEndPos(g_rankCapsules_mapthingsPos[i]); + param = M_TokenizerRead(0); + + if (!fastcmp(param, "{")) + { + continue; + } + + while (true) + { + param = M_TokenizerRead(0); + + if (fastcmp(param, "}")) + { + break; + } + + val = M_TokenizerRead(1); + + if (fastcmp(param, "type")) + { + UINT16 type = atol(val); + + if (type == mobjinfo[MT_BATTLECAPSULE].doomednum) + { + g_rankCapsules_count++; + } + + break; + } + } + } +} + +/*-------------------------------------------------- + static void RankCapsules_LoadThingsLump(UINT8 *data) + + Loads binary map data for the result of + RankCapsules_CountFromMap. + + Input Arguments:- + data - Pointer to a THINGS lump. + + Return:- + N/A +--------------------------------------------------*/ +static void RankCapsules_LoadThingsLump(UINT8 *data) +{ + size_t i; + + for (i = 0; i < g_rankCapsules_nummapthings; i++) + { + UINT16 type = 0; + + data += 2; // x + data += 2; // y + + data += 2; // angle + type = READUINT16(data); // type + type &= 4095; + + data += 2; // options + + if (type == mobjinfo[MT_BATTLECAPSULE].doomednum) + { + g_rankCapsules_count++; + } + } +} + +/*-------------------------------------------------- + static boolean RankCapsules_LoadMapData(const virtres_t *virt) + + Loads either UDMF or binary map data, for the + result of RankCapsules_CountFromMap. + + Input Arguments:- + virt - Pointer to the map's virtual resource. + + Return:- + true if we could successfully load the map data, + otherwise false. +--------------------------------------------------*/ +static boolean RankCapsules_LoadMapData(const virtres_t *virt) +{ + virtlump_t *virtthings = NULL; + + // Count map data. + if (g_rankCapsules_udmf) // Count how many entries for each type we got in textmap. + { + virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); + M_TokenizerOpen((char *)textmap->data); + if (!RankCapsules_TextmapCount(textmap->size)) + { + M_TokenizerClose(); + return false; + } + } + else + { + virtthings = vres_Find(virt, "THINGS"); + + if (!virtthings) + { + return false; + } + + // Traditional doom map format just assumes the number of elements from the lump sizes. + g_rankCapsules_nummapthings = virtthings->size / (5 * sizeof (INT16)); + } + + // Load map data. + if (g_rankCapsules_udmf) + { + RankCapsules_LoadTextmap(); + M_TokenizerClose(); + } + else + { + RankCapsules_LoadThingsLump(virtthings->data); + } + + return true; +} + +/*-------------------------------------------------- + static UINT32 RankCapsules_CountFromMap(const virtres_t *virt) + + Counts the number of capsules in a map, without + needing to fully load it. + + Input Arguments:- + virt - Pointer to the map's virtual resource. + + Return:- + Number of MT_BATTLECAPSULE instances found. +--------------------------------------------------*/ +static UINT32 RankCapsules_CountFromMap(const virtres_t *virt) +{ + virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); + + g_rankCapsules_udmf = (textmap != NULL); + g_rankCapsules_count = 0; + + if (RankCapsules_LoadMapData(virt) == true) + { + return g_rankCapsules_count; + } + + return 0; +} + /*-------------------------------------------------- void K_InitGrandPrixRank(gpRank_t *rankData) @@ -83,7 +314,30 @@ void K_InitGrandPrixRank(gpRank_t *rankData) rankData->totalLaps += laps; } - // Total capsules will need to be calculated as you enter the bonus stages... + // Search through all of the cup's bonus levels + // for an accurate count of how many capsules they have. + for (i = 0; i < grandprixinfo.cup->numbonus; i++) + { + const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS + i]; + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] != NULL) + { + lumpnum_t lp = mapheaderinfo[cupLevelNum]->lumpnum; + virtres_t *virt = NULL; + + if (lp == LUMPERROR) + { + continue; + } + + virt = vres_GetMap(lp); + if (virt == NULL) + { + continue; + } + + rankData->totalCapsules += RankCapsules_CountFromMap(virt); + } + } } /*-------------------------------------------------- From 96477caa88ec7c84d32e3c194588626df69d021c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 4 Mar 2023 19:28:31 -0500 Subject: [PATCH 10/13] Move K_ResetCeremony Properly carry over GP ranking data to the ceremony --- src/g_game.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index c7c423d03..103255e78 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1472,8 +1472,6 @@ void G_DoLoadLevelEx(boolean resetplayer, gamestate_t newstate) if (gamestate == GS_VOTING) Y_EndVote(); - K_ResetCeremony(); - // cleanup // Is this actually necessary? Doesn't F_StartTitleScreen already do a significantly more comprehensive check? if (newstate == GS_TITLESCREEN) @@ -1500,6 +1498,8 @@ void G_DoLoadLevelEx(boolean resetplayer, gamestate_t newstate) M_ClearMenus(true); I_UpdateMouseGrab(); + K_ResetCeremony(); + for (i = 0; i < MAXPLAYERS; i++) { if (resetplayer || (playeringame[i] && players[i].playerstate == PST_DEAD)) From ca178324de6c8fee9e2bc38913cbb47ac963126c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 5 Mar 2023 19:10:23 -0500 Subject: [PATCH 11/13] Free capsules counting virtual resources --- src/k_rank.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/k_rank.c b/src/k_rank.c index 09651015a..648f3a0c8 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -336,6 +336,7 @@ void K_InitGrandPrixRank(gpRank_t *rankData) } rankData->totalCapsules += RankCapsules_CountFromMap(virt); + vres_Free(virt); } } } From 23a00b1d00cc64194e70d326ef3670b52829d49a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 5 Mar 2023 19:33:43 -0500 Subject: [PATCH 12/13] Move GP ranking data to grandprixinfo --- src/g_game.c | 8 ++++---- src/k_grandprix.h | 13 +++++++++---- src/k_hud.c | 16 ++++++++-------- src/k_podium.c | 20 ++++++++++---------- src/k_rank.c | 2 -- src/k_rank.h | 2 -- src/p_setup.c | 2 +- src/p_user.c | 10 +++++----- 8 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 103255e78..497c54320 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3887,7 +3887,7 @@ static void G_GetNextMap(void) // Special stage else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) { - gp_rank_e grade = K_CalculateGPGrade(&g_gpRank); + gp_rank_e grade = K_CalculateGPGrade(&grandprixinfo.rank); if (grade >= GRADE_A) // On A rank pace? Then you get a chance for S rank! { @@ -4117,7 +4117,7 @@ static void G_DoCompleted(void) G_SetGamestate(GS_NULL); wipegamestate = GS_NULL; - g_gpRank.position = MAXPLAYERS; + grandprixinfo.rank.position = MAXPLAYERS; for (i = 0; i < MAXPLAYERS; i++) { @@ -4147,7 +4147,7 @@ static void G_DoCompleted(void) if (players[i].bot == false) { - g_gpRank.position = min(g_gpRank.position, K_GetPodiumPosition(&players[i])); + grandprixinfo.rank.position = min(grandprixinfo.rank.position, K_GetPodiumPosition(&players[i])); } } } @@ -5488,7 +5488,7 @@ void G_SetRetryFlag(void) { if (retrying == false) { - g_gpRank.continuesUsed++; + grandprixinfo.rank.continuesUsed++; } retrying = true; diff --git a/src/k_grandprix.h b/src/k_grandprix.h index 2bd3be61c..efa251246 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -15,14 +15,18 @@ #include "doomdef.h" #include "doomstat.h" +#include "k_rank.h" // gpRank_t #ifdef __cplusplus extern "C" { #endif -#define GPEVENT_NONE 0 -#define GPEVENT_BONUS 1 -#define GPEVENT_SPECIAL 2 +typedef enum +{ + GPEVENT_NONE = 0, + GPEVENT_BONUS, + GPEVENT_SPECIAL, +} gpEvent_e; extern struct grandprixinfo { @@ -34,7 +38,8 @@ extern struct grandprixinfo boolean masterbots; ///< If true, all bots should be max difficulty (Master Mode) boolean initalize; ///< If true, we need to initialize a new session. boolean wonround; ///< If false, then we retry the map instead of going to the next. - UINT8 eventmode; ///< See GPEVENT_ constants + gpEvent_e eventmode; ///< Special event mode, bots are set to spectate and a special gametype is played + gpRank_t rank; ///< Struct containing grading information. (See also: k_rank.h) } grandprixinfo; /*-------------------------------------------------- diff --git a/src/k_hud.c b/src/k_hud.c index 630baca43..2ee8fa7e0 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4818,22 +4818,22 @@ static void K_DrawGPRankDebugger(void) return; } - grade = K_CalculateGPGrade(&g_gpRank); + grade = K_CalculateGPGrade(&grandprixinfo.rank); V_DrawThinString(0, 0, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("POS: %d / %d", g_gpRank.position, RANK_NEUTRAL_POSITION)); + va("POS: %d / %d", grandprixinfo.rank.position, RANK_NEUTRAL_POSITION)); V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("PTS: %d / %d", g_gpRank.winPoints, g_gpRank.totalPoints)); + va("PTS: %d / %d", grandprixinfo.rank.winPoints, grandprixinfo.rank.totalPoints)); V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("LAPS: %d / %d", g_gpRank.laps, g_gpRank.totalLaps)); + va("LAPS: %d / %d", grandprixinfo.rank.laps, grandprixinfo.rank.totalLaps)); V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("CONTINUES: %d", g_gpRank.continuesUsed)); + va("CONTINUES: %d", grandprixinfo.rank.continuesUsed)); V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("CAPSULES: %d / %d", g_gpRank.capsules, g_gpRank.totalCapsules)); + va("CAPSULES: %d / %d", grandprixinfo.rank.capsules, grandprixinfo.rank.totalCapsules)); V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("RINGS: %d / %d", g_gpRank.rings, g_gpRank.totalRings)); + va("RINGS: %d / %d", grandprixinfo.rank.rings, grandprixinfo.rank.totalRings)); V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE, - va("EMERALD: %s", (g_gpRank.specialWon == true) ? "YES" : "NO")); + va("EMERALD: %s", (grandprixinfo.rank.specialWon == true) ? "YES" : "NO")); switch (grade) { diff --git a/src/k_podium.c b/src/k_podium.c index cf8c3cc85..7f00834d9 100644 --- a/src/k_podium.c +++ b/src/k_podium.c @@ -50,7 +50,7 @@ static struct podiumData_s { boolean ranking; - gpRank_t rankData; + gpRank_t rank; gp_rank_e grade; UINT8 state; UINT8 delay; @@ -280,8 +280,8 @@ void K_ResetCeremony(void) return; } - podiumData.rankData = g_gpRank; - podiumData.grade = K_CalculateGPGrade(&podiumData.rankData); + podiumData.rank = grandprixinfo.rank; + podiumData.grade = K_CalculateGPGrade(&podiumData.rank); } /*-------------------------------------------------- @@ -430,49 +430,49 @@ void K_CeremonyDrawer(void) case 1: { V_DrawString(x, y, V_ALLOWLOWERCASE, - va("POS: %d / %d", podiumData.rankData.position, RANK_NEUTRAL_POSITION) + va("POS: %d / %d", podiumData.rank.position, RANK_NEUTRAL_POSITION) ); break; } case 2: { V_DrawString(x, y, V_ALLOWLOWERCASE, - va("PTS: %d / %d", podiumData.rankData.winPoints, podiumData.rankData.totalPoints) + va("PTS: %d / %d", podiumData.rank.winPoints, podiumData.rank.totalPoints) ); break; } case 3: { V_DrawString(x, y, V_ALLOWLOWERCASE, - va("LAPS: %d / %d", podiumData.rankData.laps, podiumData.rankData.totalLaps) + va("LAPS: %d / %d", podiumData.rank.laps, podiumData.rank.totalLaps) ); break; } case 4: { V_DrawString(x, y, V_ALLOWLOWERCASE, - va("CONTINUES: %d", podiumData.rankData.continuesUsed) + va("CONTINUES: %d", podiumData.rank.continuesUsed) ); break; } case 5: { V_DrawString(x, y, V_ALLOWLOWERCASE, - va("CAPSULES: %d / %d", podiumData.rankData.capsules, podiumData.rankData.totalCapsules) + va("CAPSULES: %d / %d", podiumData.rank.capsules, podiumData.rank.totalCapsules) ); break; } case 6: { V_DrawString(x, y, V_ALLOWLOWERCASE, - va("RINGS: %d / %d", podiumData.rankData.rings, podiumData.rankData.totalRings) + va("RINGS: %d / %d", podiumData.rank.rings, podiumData.rank.totalRings) ); break; } case 7: { V_DrawString(x, y, V_ALLOWLOWERCASE, - va("EMERALD: %s", (podiumData.rankData.specialWon == true) ? "YES" : "NO") + va("EMERALD: %s", (podiumData.rank.specialWon == true) ? "YES" : "NO") ); break; } diff --git a/src/k_rank.c b/src/k_rank.c index 648f3a0c8..0e07c33ec 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -23,8 +23,6 @@ #include "fastcmp.h" #include "byteptr.h" -gpRank_t g_gpRank = {0}; - // I was ALMOST tempted to start tearing apart all // of the map loading code and turning it into C++ // and making it properly split between read-only diff --git a/src/k_rank.h b/src/k_rank.h index 093bb178e..cc675db17 100644 --- a/src/k_rank.h +++ b/src/k_rank.h @@ -44,8 +44,6 @@ struct gpRank_t boolean specialWon; }; -extern gpRank_t g_gpRank; - typedef enum { GRADE_E, diff --git a/src/p_setup.c b/src/p_setup.c index fe769e1e5..d0cc73d6f 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7389,7 +7389,7 @@ static void P_InitGametype(void) { if (grandprixinfo.initalize == true) { - K_InitGrandPrixRank(&g_gpRank); + K_InitGrandPrixRank(&grandprixinfo.rank); K_InitGrandPrixBots(); grandprixinfo.initalize = false; } diff --git a/src/p_user.c b/src/p_user.c index 7c0a9f13a..44a8c58de 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1355,7 +1355,7 @@ void P_DoPlayerExit(player_t *player) if (RINGTOTAL(player) > 0) { player->totalring += RINGTOTAL(player); - g_gpRank.rings += RINGTOTAL(player); + grandprixinfo.rank.rings += RINGTOTAL(player); extra = player->totalring / lifethreshold; @@ -1369,15 +1369,15 @@ void P_DoPlayerExit(player_t *player) if (grandprixinfo.eventmode == GPEVENT_NONE) { - g_gpRank.winPoints += K_CalculateGPRankPoints(player->position, g_gpRank.totalPlayers); - g_gpRank.laps += player->lapPoints; + grandprixinfo.rank.winPoints += K_CalculateGPRankPoints(player->position, grandprixinfo.rank.totalPlayers); + grandprixinfo.rank.laps += player->lapPoints; } else if (grandprixinfo.eventmode == GPEVENT_SPECIAL) { - g_gpRank.specialWon = true; + grandprixinfo.rank.specialWon = true; } - g_gpRank.capsules += numtargets; + grandprixinfo.rank.capsules += numtargets; } } } From 0f87e177b9605de4039f3c523608fb58d03d48dd Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 5 Mar 2023 19:58:16 -0500 Subject: [PATCH 13/13] Be able to get partial credit for capsules again --- src/g_game.c | 1 + src/p_user.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 497c54320..fed0efd34 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4117,6 +4117,7 @@ static void G_DoCompleted(void) G_SetGamestate(GS_NULL); wipegamestate = GS_NULL; + grandprixinfo.rank.capsules += numtargets; grandprixinfo.rank.position = MAXPLAYERS; for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/p_user.c b/src/p_user.c index 44a8c58de..3d290a678 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1376,8 +1376,6 @@ void P_DoPlayerExit(player_t *player) { grandprixinfo.rank.specialWon = true; } - - grandprixinfo.rank.capsules += numtargets; } } }