From 117a45422ad343a08c58cc79580560914041197c Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 14:02:46 +0100 Subject: [PATCH 1/8] G_SaveGameData: Fix an issue where if you somehow saved a skin with no wins as the most recent skin on GP, it'd be assigned to the first skin with any wins on your gamedata on the next load, instead of the correct question mark. --- src/g_game.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index f65f0ba6d..a74eed966 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5530,7 +5530,10 @@ void G_SaveGameData(void) for (i = 0; i < numskins; i++) { if (skins[i].records.wins == 0) + { + skins[i].records._saveid = UINT32_MAX; continue; + } WRITESTRINGN(save.p, skins[i].name, SKINNAMESIZE); From 3c505e2676c459c1e0dcea5a1ae5072f43c8ac0b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 14:11:14 +0100 Subject: [PATCH 2/8] K_UpdateGPRank - The previous location for updating grandprixinfo.rank.position and grandprixinfo.rank.skin was too early. - K_GetPodiumPosition checks player->score - Y_StartIntermission calls Y_CalculateMatchData - Y_CalculateMatchData checks K_CalculateGPGrade... which uses invalid position info to determine grade! - Y_CalculateMatchData updates player score - To this end, rearrange Y_CalculateMatchData to accomodate. - Calls K_UpdateGPRank. - Then, calls K_CalculateGPGrade. - Also called after G_UpdateVisited if no intermission occours, for general consistency. - In addition, adjust so earlier players have port priority for skin saved to gamedata. --- src/g_game.c | 17 ++---------- src/k_rank.c | 34 ++++++++++++++++++++++++ src/k_rank.h | 15 +++++++++++ src/y_inter.c | 73 +++++++++++++++++++++++++++------------------------ 4 files changed, 89 insertions(+), 50 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index a74eed966..f8d08183f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4464,15 +4464,11 @@ static void G_DoCompleted(void) G_SetGamestate(GS_NULL); wipegamestate = GS_NULL; - grandprixinfo.rank.prisons += numtargets; - grandprixinfo.rank.position = MAXPLAYERS; - grandprixinfo.rank.skin = MAXSKINS; - for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { - // SRB2Kart: exitlevel shouldn't get you the points + // Exitlevel shouldn't get you the points if (!players[i].exiting && !(players[i].pflags & PF_NOCONTEST)) { clientPowerAdd[i] = 0; @@ -4493,16 +4489,6 @@ static void G_DoCompleted(void) } G_PlayerFinishLevel(i); // take away cards and stuff - - if (players[i].bot == false) - { - UINT8 podiumposition = K_GetPodiumPosition(&players[i]); - if (podiumposition <= grandprixinfo.rank.position) - { - grandprixinfo.rank.position = podiumposition; - grandprixinfo.rank.skin = players[i].skin; - } - } } } @@ -4525,6 +4511,7 @@ static void G_DoCompleted(void) || (intertype == int_none)) { G_UpdateVisited(); + K_UpdateGPRank(); G_AfterIntermission(); } else diff --git a/src/k_rank.c b/src/k_rank.c index 1420cc7b3..dd05cc11f 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -18,6 +18,8 @@ #include "g_game.h" #include "k_bot.h" #include "k_kart.h" +#include "k_battle.h" +#include "k_podium.h" #include "m_random.h" #include "r_things.h" #include "fastcmp.h" @@ -342,6 +344,38 @@ void K_InitGrandPrixRank(gpRank_t *rankData) } } +/*-------------------------------------------------- + void K_UpdateGPRank(void) + + See header file for description. +--------------------------------------------------*/ +void K_UpdateGPRank(void) +{ + if (grandprixinfo.gp != true) + return; + + UINT8 i; + + grandprixinfo.rank.prisons += numtargets; + grandprixinfo.rank.position = MAXPLAYERS; + grandprixinfo.rank.skin = MAXSKINS; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] + || players[i].spectator == true + || players[i].bot == true) + continue; + + UINT8 podiumposition = K_GetPodiumPosition(&players[i]); + if (podiumposition >= grandprixinfo.rank.position) // port priority + continue; + + grandprixinfo.rank.position = podiumposition; + grandprixinfo.rank.skin = players[i].skin; + } +} + /*-------------------------------------------------- gp_rank_e K_CalculateGPGrade(gpRank_t *rankData) diff --git a/src/k_rank.h b/src/k_rank.h index fd3e86f97..701c01b7c 100644 --- a/src/k_rank.h +++ b/src/k_rank.h @@ -66,6 +66,21 @@ struct gpRank_t void K_InitGrandPrixRank(gpRank_t *rankData); +/*-------------------------------------------------- + void K_UpdateGPRank(void) + + Updates the best ranking across all human + players. + + Input Arguments:- + N/A + + Return:- + N/A +--------------------------------------------------*/ +void K_UpdateGPRank(void); + + /*-------------------------------------------------- gp_rank_e K_CalculateGPGrade(gpRank_t *rankData); diff --git a/src/y_inter.c b/src/y_inter.c index 70ae5e7fb..be02b4ee4 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -151,41 +151,6 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) { getmainplayer = true; - { - // See also G_GetNextMap, M_DrawPause - data.showrank = false; - if (grandprixinfo.gp == true - && netgame == false // TODO netgame Special Mode support - && grandprixinfo.gamespeed >= KARTSPEED_NORMAL - && roundqueue.size > 1 - && roundqueue.entries[roundqueue.size - 1].rankrestricted == true - ) - { - if (roundqueue.position == roundqueue.size-1) - { - // On A rank pace? Then you get a chance for S rank! - gp_rank_e rankforline = K_CalculateGPGrade(&grandprixinfo.rank); - - data.showrank = (rankforline >= GRADE_A); - - data.linemeter = - (min(rankforline, GRADE_A) - * (2 * TICRATE) - ) / GRADE_A; - - // A little extra time to take it all in - timer += TICRATE; - } - - if (gamedata->everseenspecial == true - || roundqueue.position == roundqueue.size) - { - // Additional cases in which it should always be shown. - data.showrank = true; - } - } - } - data.encore = encoremode; memset(data.jitter, 0, sizeof (data.jitter)); @@ -302,6 +267,44 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) if (getmainplayer == true) { + // Okay, player scores have been set now - we can calculate GP-relevant material. + { + K_UpdateGPRank(); + + // See also G_GetNextMap, M_DrawPause + data.showrank = false; + if (grandprixinfo.gp == true + && netgame == false // TODO netgame Special Mode support + && grandprixinfo.gamespeed >= KARTSPEED_NORMAL + && roundqueue.size > 1 + && roundqueue.entries[roundqueue.size - 1].rankrestricted == true + ) + { + if (roundqueue.position == roundqueue.size-1) + { + // On A rank pace? Then you get a chance for S rank! + gp_rank_e rankforline = K_CalculateGPGrade(&grandprixinfo.rank); + + data.showrank = (rankforline >= GRADE_A); + + data.linemeter = + (min(rankforline, GRADE_A) + * (2 * TICRATE) + ) / GRADE_A; + + // A little extra time to take it all in + timer += TICRATE; + } + + if (gamedata->everseenspecial == true + || roundqueue.position == roundqueue.size) + { + // Additional cases in which it should always be shown. + data.showrank = true; + } + } + } + i = MAXPLAYERS; for (j = 0; j < data.numplayers; j++) From 5a3ed5464e29295023d46c4019b82cf65465824d Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 14:18:01 +0100 Subject: [PATCH 3/8] P_Ticker: Do not start position music or play noises if gametype has no time between intro and start --- src/p_tick.c | 66 ++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/src/p_tick.c b/src/p_tick.c index da4cc46da..871420055 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -873,43 +873,47 @@ void P_Ticker(boolean run) } else if (leveltime < starttime + TICRATE) { - // Start countdown/music handling - if (leveltime == starttime-(3*TICRATE)) - { - S_StartSound(NULL, sfx_s3ka7); // 3, - S_FadeMusic(0, 3500); //S_FadeOutStopMusic(3500); -- TODO the S_StopMusic callback can halt successor music instead - } - else if ((leveltime == starttime-(2*TICRATE)) || (leveltime == starttime-TICRATE)) - { - S_StartSound(NULL, sfx_s3ka7); // 2, 1, - } - else if (leveltime == starttime) - { - S_StartSound(NULL, sfx_s3kad); // GO! - } - else if (leveltime == (starttime + (TICRATE/2))) + if (leveltime == (starttime + (TICRATE/2))) { // Plays the music after the starting countdown. S_ChangeMusic(mapmusname, mapmusflags, true); S_ShowMusicCredit(); } + else if (starttime != introtime) + { + // Start countdown/music handling + if (leveltime == starttime-(3*TICRATE)) + { + S_StartSound(NULL, sfx_s3ka7); // 3, + S_FadeMusic(0, 3500); //S_FadeOutStopMusic(3500); -- TODO the S_StopMusic callback can halt successor music instead + } + else if ((leveltime == starttime-(2*TICRATE)) + || (leveltime == starttime-TICRATE)) + { + S_StartSound(NULL, sfx_s3ka7); // 2, 1, + } + else if (leveltime == starttime) + { + S_StartSound(NULL, sfx_s3kad); // GO! + } - // POSITION!! music - if (encoremode) - { - // Encore humming starts immediately. - if (leveltime == 1) - S_ChangeMusicInternal("encore", true); - } - else - { - // Plays the POSITION music after the camera spin - if (leveltime == introtime) - S_ChangeMusicInternal( - (mapheaderinfo[gamemap-1]->positionmus[0] - ? mapheaderinfo[gamemap-1]->positionmus - : "postn" - ), true); + // POSITION!! music + if (encoremode) + { + // Encore humming starts immediately. + if (leveltime == 1) + S_ChangeMusicInternal("encore", true); + } + else + { + // Plays the POSITION music after the camera spin + if (leveltime == introtime) + S_ChangeMusicInternal( + (mapheaderinfo[gamemap-1]->positionmus[0] + ? mapheaderinfo[gamemap-1]->positionmus + : "postn" + ), true); + } } } From 10c18fe3fabdcf7b8f61b1bd02fc7e120435f239 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 14:20:48 +0100 Subject: [PATCH 4/8] Podium Music Uses the multiple alt music options of the podium map's level header in a specific sequence, so it can slot in to the Stereo Mode music list natively, and so custom Podiums don't have to replace existing tracks to function. --- src/k_podium.c | 15 +++++++++++++++ src/p_setup.c | 9 ++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/k_podium.c b/src/k_podium.c index ae1d45eef..480f3358c 100644 --- a/src/k_podium.c +++ b/src/k_podium.c @@ -316,6 +316,21 @@ void K_ResetCeremony(void) podiumData.rank = grandprixinfo.rank; podiumData.grade = K_CalculateGPGrade(&podiumData.rank); + // Set up music for podium. + { + if (podiumData.rank.position == 1) + mapmusrng = 2; + else if (podiumData.rank.position <= 3) + mapmusrng = 1; + else + mapmusrng = 0; + + if (mapmusrng >= mapheaderinfo[gamemap-1]->musname_size) + mapmusrng = 0; + + mapmusflags |= MUSIC_RELOADRESET; + } + if (!grandprixinfo.cup) { return; diff --git a/src/p_setup.c b/src/p_setup.c index ea1185a67..c38aef02b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8075,7 +8075,14 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) S_FadeMusic(0, FixedMul( FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); - if (!(reloadinggamestate || gamestate != GS_LEVEL)) + if (reloadinggamestate) + ; + else if (K_PodiumSequence()) + { + // mapmusrng is set by local player position in K_ResetCeremony + S_InitLevelMusic(true); + } + else if (gamestate == GS_LEVEL) { if (ranspecialwipe == 2) { From 1d619d10f213b3d74b58fde1046c6b2a6e630b89 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 14:24:39 +0100 Subject: [PATCH 5/8] Add Podium level to Stereo Mode - LF2_HIDEINMENU is considered equivalent to LF2_FINISHNEEDED for: - S_SoundTestDefLocked - So you don't see podium stuff without having beaten a GP - MV_FINISHNEEDED - So the status is saved to gamedata and persists between launches if custom - G_UpdateVisited is now called in K_FinishCeremony, so level is marked as beaten --- src/g_game.c | 4 ++-- src/g_game.h | 2 ++ src/k_podium.c | 6 +++--- src/s_sound.c | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index f8d08183f..d9d7378a2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3972,7 +3972,7 @@ void G_AddMapToBuffer(UINT16 map) // // G_UpdateVisited // -static void G_UpdateVisited(void) +void G_UpdateVisited(void) { UINT8 i; UINT8 earnedEmblems; @@ -5574,7 +5574,7 @@ void G_SaveGameData(void) UINT8 mapvisitedtemp = (mapheaderinfo[i]->records.mapvisited & MV_MAX); - if ((mapheaderinfo[i]->menuflags & LF2_FINISHNEEDED)) + if ((mapheaderinfo[i]->menuflags & (LF2_FINISHNEEDED|LF2_HIDEINMENU))) { mapvisitedtemp |= MV_FINISHNEEDED; } diff --git a/src/g_game.h b/src/g_game.h index 2f498134e..a8ba57e5e 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -281,6 +281,8 @@ INT16 G_GetFirstMapOfGametype(UINT8 pgametype); UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer); void G_AddMapToBuffer(UINT16 map); +void G_UpdateVisited(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_podium.c b/src/k_podium.c index 480f3358c..7b2a6eb0b 100644 --- a/src/k_podium.c +++ b/src/k_podium.c @@ -291,9 +291,9 @@ void K_FinishCeremony(void) podiumData.ranking = true; - // Play the noise now - M_UpdateUnlockablesAndExtraEmblems(true, true); - G_SaveGameData(); + // Play the noise now (via G_UpdateVisited's concluding gamedata save) + prevmap = gamemap-1; + G_UpdateVisited(); } /*-------------------------------------------------- diff --git a/src/s_sound.c b/src/s_sound.c index 9a2fbe466..966a61623 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1533,7 +1533,7 @@ static boolean S_SoundTestDefLocked(musicdef_t *def) return false; // Is the level tied to SP progression? - if ((mapheaderinfo[def->sequence.map]->menuflags & LF2_FINISHNEEDED) + if ((mapheaderinfo[def->sequence.map]->menuflags & (LF2_FINISHNEEDED|LF2_HIDEINMENU)) && !(mapheaderinfo[def->sequence.map]->records.mapvisited & MV_BEATEN)) return true; From ddde841194da37d87ac998a37c834a118a6f4dd0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 14:27:33 +0100 Subject: [PATCH 6/8] K_GetPodiumPosition: For consistent results, don't skip over a spectator if it's a bot. This is not ideal and I made an entire branch about avoiding making this change... but actually, this is necessary for consistent results in K_UpdateGPRank after both normal and GPEVENT rounds, and there's nothing we can do about it. --- src/k_podium.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_podium.c b/src/k_podium.c index 7b2a6eb0b..2502d268c 100644 --- a/src/k_podium.c +++ b/src/k_podium.c @@ -112,7 +112,7 @@ UINT8 K_GetPodiumPosition(player_t *player) } other = &players[i]; - if (other->spectator == true) + if (other->bot == false && other->spectator == true) { continue; } From 1f48d0b4ec85d7d524937d51d73296da1cb352ac Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 15:01:14 +0100 Subject: [PATCH 7/8] K_ResetCeremony: Adjust music set - Qualified/alt 1 is used if there's not enough music for unique First - Loser Club/alt 0 is used if position is invalid --- src/k_podium.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/k_podium.c b/src/k_podium.c index 2502d268c..7b658c944 100644 --- a/src/k_podium.c +++ b/src/k_podium.c @@ -318,15 +318,16 @@ void K_ResetCeremony(void) // Set up music for podium. { - if (podiumData.rank.position == 1) + if (podiumData.rank.position <= 1) mapmusrng = 2; - else if (podiumData.rank.position <= 3) + else if (podiumData.rank.position == 2 + || podiumData.rank.position == 3) mapmusrng = 1; else mapmusrng = 0; - if (mapmusrng >= mapheaderinfo[gamemap-1]->musname_size) - mapmusrng = 0; + while (mapmusrng >= max(1, mapheaderinfo[gamemap-1]->musname_size)) + mapmusrng--; mapmusflags |= MUSIC_RELOADRESET; } From ce6737aa6760234cd2de34d1bbc0552251f31007 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 15:41:52 +0100 Subject: [PATCH 8/8] S_SoundTestPlay: Set MINIMUM looping of ~4 seconds, for the sake the extremely short votepick song. --- src/s_sound.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/s_sound.c b/src/s_sound.c index 966a61623..e218870e5 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1665,7 +1665,14 @@ void S_SoundTestPlay(void) { // I'd personally like songs in sequence to last between 3 and 6 minutes. const UINT32 loopduration = (soundtest.sequencemaxtime - S_GetMusicLoopPoint()); - soundtest.sequencemaxtime += loopduration; + + if (!loopduration) + ; + else do + { + soundtest.sequencemaxtime += loopduration; + } while (soundtest.sequencemaxtime < 4*1000); + // If the track is EXTREMELY short, keep adding until about 4s! } // Only fade out if we're the last track for this song.