From 581567dfae55bc4c135cbe39909d770e242fd23b Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 30 Apr 2023 21:47:07 +0100 Subject: [PATCH] musiccountdown A system for level completion jingles. - G_Ticker - Call P_EndingMusic after a certain amount of time has elapsed to begin a jingle - Play O_RACENT after the jingle's completion instead of baking it or an equivalent into the music - P_EndingMusic - Change the function signature to not take a player - Pick from a series of const char* jingles, instead of sprintfing into a buffer - _first - _win - _lose - RETIRE - Simplifying logic to handle intermission music --- src/doomstat.h | 4 +- src/g_game.c | 25 +++--- src/p_local.h | 2 +- src/p_setup.c | 2 +- src/p_tick.c | 6 +- src/p_user.c | 203 +++++++++++++++++++++++++++---------------------- src/y_inter.c | 2 +- 7 files changed, 139 insertions(+), 105 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 53ca57158..baa39a873 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -669,7 +669,7 @@ extern const tic_t bulbtime; extern UINT8 numbulbs; extern tic_t raceexittime; -extern tic_t battleexittime; +#define MUSICCOUNTDOWNMAX (raceexittime - (TICRATE/2)) extern INT32 hyudorotime; extern INT32 stealtime; @@ -694,7 +694,7 @@ extern UINT8 maxXtraLife; // Max extra lives from rings extern mobj_t *hunt1, *hunt2, *hunt3; // Emerald hunt locations // For racing -extern tic_t racecountdown, exitcountdown; +extern tic_t racecountdown, exitcountdown, musiccountdown; #define DEFAULT_GRAVITY (4*FRACUNIT/5) extern fixed_t gravity; diff --git a/src/g_game.c b/src/g_game.c index a83f27d1b..03346abc3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -249,8 +249,7 @@ tic_t starttime = 3; const tic_t bulbtime = TICRATE/2; UINT8 numbulbs = 1; -tic_t raceexittime = 5*TICRATE + (2*TICRATE/3); -tic_t battleexittime = 8*TICRATE; +tic_t raceexittime = 7*TICRATE + (TICRATE/2); INT32 hyudorotime = 7*TICRATE; INT32 stealtime = TICRATE/2; @@ -277,7 +276,7 @@ mobj_t *hunt1; mobj_t *hunt2; mobj_t *hunt3; -tic_t racecountdown, exitcountdown; // for racing +tic_t racecountdown, exitcountdown, musiccountdown; // for racing fixed_t gravity; fixed_t mapobjectscale; @@ -2392,6 +2391,19 @@ void G_Ticker(boolean run) if (Playing() == true) { + if (musiccountdown > 1) + { + musiccountdown--; + if (musiccountdown == 1) + { + S_ChangeMusicInternal("racent", true); + } + else if (musiccountdown == (MUSICCOUNTDOWNMAX - (3*TICRATE)/2)) + { + P_EndingMusic(); + } + } + K_TickMidVote(); } } @@ -4447,11 +4459,6 @@ static void G_DoCompleted(void) } } - // 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) - S_ChangeMusicInternal("racent", true); - if (automapactive) AM_Stop(); @@ -5542,7 +5549,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr // Clear a bunch of variables redscore = bluescore = lastmap = 0; - racecountdown = exitcountdown = mapreset = exitfadestarted = 0; + racecountdown = exitcountdown = musiccountdown = mapreset = exitfadestarted = 0; for (i = 0; i < MAXPLAYERS; i++) { diff --git a/src/p_local.h b/src/p_local.h index 32c265ec6..5c62261df 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -188,7 +188,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, an void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_RestoreMusic(player_t *player); -boolean P_EndingMusic(player_t *player); +void P_EndingMusic(void); mobj_t *P_SpawnGhostMobj(mobj_t *mobj); INT32 P_GivePlayerRings(player_t *player, INT32 num_rings); INT32 P_GivePlayerSpheres(player_t *player, INT32 num_spheres); diff --git a/src/p_setup.c b/src/p_setup.c index ccb8eec05..9ad523563 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7165,7 +7165,7 @@ static void P_InitLevelSettings(void) K_UpdateShrinkCheat(&players[i]); } - racecountdown = exitcountdown = exitfadestarted = 0; + racecountdown = exitcountdown = musiccountdown = exitfadestarted = 0; curlap = bestlap = 0; // SRB2Kart // Gamespeed and frantic items diff --git a/src/p_tick.c b/src/p_tick.c index 7a73bf223..393373ecc 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -813,7 +813,11 @@ void P_Ticker(boolean run) } } - if (K_CheckBossIntro() == true) + if (musiccountdown > 0) + { + // Music is controlled by completion sequence + } + else if (K_CheckBossIntro() == true) { // Bosses have a punchy start, so no position. if (leveltime == 3) diff --git a/src/p_user.c b/src/p_user.c index 7a1b2d017..b6aadd97a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -36,6 +36,7 @@ #include "r_splats.h" #include "z_zone.h" #include "w_wad.h" +#include "y_inter.h" // Y_DetermineIntermissionType #include "hu_stuff.h" // We need to affect the NiGHTS hud #include "st_stuff.h" @@ -710,91 +711,105 @@ void P_PlayVictorySound(mobj_t *source) // // Consistently sets ending music! // -boolean P_EndingMusic(player_t *player) +void P_EndingMusic(void) { - char buffer[9]; - boolean looping = true; - boolean racetracks = !!(gametyperules & GTR_CIRCUIT); - INT32 bestlocalpos, test; - player_t *bestlocalplayer; + const char *jingle = NULL; + boolean nointer = false; + UINT8 bestPos = UINT8_MAX; + player_t *bestPlayer = NULL; - if (!P_IsLocalPlayer(player)) // Only applies to a local player - return false; - - if (multiplayer && demo.playback) // Don't play this in multiplayer replays - return false; + SINT8 i; // Event - Level Finish // Check for if this is valid or not -#define getplayerpos(p) \ - (((players[p].position < 1) || (players[p].pflags & PF_NOCONTEST)) \ - ? MAXPLAYERS+1 \ - : players[p].position); - - if (r_splitscreen) + for (i = 0; i <= r_splitscreen; i++) { - const UINT8 *localplayertable = G_PartyArray(consoleplayer); + UINT8 pos = UINT8_MAX; + player_t *checkPlayer = NULL; - if (!((players[localplayertable[0]].exiting || (players[localplayertable[0]].pflags & PF_NOCONTEST)) - || (players[localplayertable[1]].exiting || (players[localplayertable[1]].pflags & PF_NOCONTEST)) - || ((r_splitscreen > 1) && (players[localplayertable[2]].exiting || (players[localplayertable[2]].pflags & PF_NOCONTEST))) - || ((r_splitscreen > 2) && (players[localplayertable[3]].exiting || (players[localplayertable[3]].pflags & PF_NOCONTEST))))) - return false; + checkPlayer = &players[displayplayers[i]]; + if (!checkPlayer || checkPlayer->spectator == true) + { + continue; + } - bestlocalplayer = &players[localplayertable[0]]; - bestlocalpos = getplayerpos(localplayertable[0]); -#define setbests(p) \ - test = getplayerpos(p); \ - if (test < bestlocalpos) \ - { \ - bestlocalplayer = &players[p]; \ - bestlocalpos = test; \ - } - setbests(localplayertable[1]); - if (r_splitscreen > 1) - setbests(localplayertable[2]); - if (r_splitscreen > 2) - setbests(localplayertable[3]); -#undef setbests - } - else - { - if (!(player->exiting || (player->pflags & PF_NOCONTEST))) - return false; - - bestlocalplayer = player; - bestlocalpos = getplayerpos((player-players)); - } - -#undef getplayerpos - - if (racetracks == true && bestlocalpos == MAXPLAYERS+1) - sprintf(buffer, "k*fail"); // F-Zero death results theme - else - { - if (K_IsPlayerLosing(bestlocalplayer)) - sprintf(buffer, "k*lose"); - else if (bestlocalpos == 1) - sprintf(buffer, "k*win"); + if (checkPlayer->pflags & PF_NOCONTEST) + { + // No Contest, use special value + ; + } + else if (checkPlayer->exiting) + { + // Standard exit, use their position + pos = checkPlayer->position; + } else - sprintf(buffer, "k*ok"); + { + // Not finished, ignore + continue; + } + + if (pos <= bestPos) + { + bestPlayer = checkPlayer; + bestPos = pos; + } } + // See G_DoCompleted and Y_DetermineIntermissionType + nointer = ((modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST)) + || (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)); + + if (bestPlayer == NULL) + { + // No jingle for you + return; + } + + if (bestPos == UINT8_MAX) + { + jingle = "RETIRE"; + + if (G_GametypeUsesLives() == true) + { + // A retry will be happening + nointer = true; + } + } + else + { + if (bestPlayer->position == 1) + { + jingle = "_first"; + } + else if (K_IsPlayerLosing(bestPlayer) == false) + { + jingle = "_win"; + } + else + { + jingle = "_lose"; + + if (G_GametypeUsesLives() == true) + { + // A retry will be happening + nointer = true; + } + } + } + + if (nointer == true) + { + // Do not set "racent" in G_Ticker + musiccountdown = 1; + } + + if (jingle == NULL) + return; + S_SpeedMusic(1.0f); - if (racetracks == true) - { - buffer[1] = 'r'; - } - else - { - buffer[1] = 'b'; - looping = false; - } - - S_ChangeMusicInternal(buffer, looping); - - return true; + S_ChangeMusicInternal(jingle, false); } // @@ -823,8 +838,10 @@ void P_RestoreMusic(player_t *player) } // Event - Level Ending - if (P_EndingMusic(player)) + if (musiccountdown > 0) + { return; + } // Event - Level Start if ((K_CheckBossIntro() == false) @@ -1243,9 +1260,12 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) void P_DoPlayerExit(player_t *player) { const boolean losing = K_IsPlayerLosing(player); + const boolean specialout = (specialstageinfo.valid == true && losing == true); if (player->exiting || mapreset) + { return; + } if (P_IsLocalPlayer(player) && (!player->spectator && !demo.playback)) { @@ -1260,13 +1280,19 @@ void P_DoPlayerExit(player_t *player) K_PlayerLoseLife(player); } + if (P_IsLocalPlayer(player) && !specialout) + { + S_StopMusic(); + musiccountdown = MUSICCOUNTDOWNMAX; + } + player->exiting = 1; if (!player->spectator) { ClearFakePlayerSkin(player); - if ((gametyperules & GTR_CIRCUIT)) // If in Race Mode, allow + if ((gametyperules & GTR_CIRCUIT)) // Special Race-like handling { K_UpdateAllPlayerPositions(); @@ -1290,13 +1316,9 @@ void P_DoPlayerExit(player_t *player) } } - // See Y_StartIntermission timer handling - if (!K_CanChangeRules(false) || cv_inttime.value > 0) - P_EndingMusic(player); - if (P_CheckRacers() && !exitcountdown) { - if (specialstageinfo.valid == true && losing == true) + if (specialout == true) { exitcountdown = TICRATE; } @@ -1306,16 +1328,9 @@ void P_DoPlayerExit(player_t *player) } } } - else if ((gametyperules & GTR_BUMPERS)) // Battle Mode exiting + else if (!exitcountdown) // All other gametypes { - if (!exitcountdown) - exitcountdown = battleexittime+1; - P_EndingMusic(player); - } - else // Accidental death safeguard??? - { - if (!exitcountdown) - exitcountdown = raceexittime+2; + exitcountdown = raceexittime+1; } if (grandprixinfo.gp == true && player->bot == false && losing == false) @@ -1334,7 +1349,9 @@ void P_DoPlayerExit(player_t *player) } if (modeattacking) + { G_UpdateRecords(); + } profile_t *pr = PR_GetPlayerProfile(player); if (pr != NULL && !losing) @@ -3801,10 +3818,16 @@ void P_DoTimeOver(player_t *player) P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER); } - P_EndingMusic(player); + if (P_IsLocalPlayer(player)) + { + S_StopMusic(); + musiccountdown = MUSICCOUNTDOWNMAX; + } if (!exitcountdown) - exitcountdown = 5*TICRATE; + { + exitcountdown = raceexittime; + } } // SRB2Kart: These are useful functions, but we aren't using them yet. diff --git a/src/y_inter.c b/src/y_inter.c index 3636834e2..07e2961b3 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -805,7 +805,7 @@ void Y_StartIntermission(void) if (prevmap >= nummapheaders || !mapheaderinfo[prevmap]) I_Error("Y_StartIntermission: Internal map ID %d not found (nummapheaders = %d)", prevmap, nummapheaders); - if (!(gametyperules & GTR_CIRCUIT) && (timer > 1)) + if (timer > 1 && musiccountdown == 0) S_ChangeMusicInternal("racent", true); // loop it S_ShowMusicCredit(); // Always call