diff --git a/src/d_main.c b/src/d_main.c index e52ad6a61..a206148ef 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -953,7 +953,10 @@ void D_SRB2Loop(void) // consoleplayer -> displayplayers (hear sounds from viewpoint) S_UpdateSounds(); // move positional sounds if (realtics > 0 || singletics) + { S_UpdateClosedCaptions(); + S_TickSoundTest(); + } #ifdef HW3SOUND HW3S_EndFrameUpdate(); diff --git a/src/deh_soc.c b/src/deh_soc.c index f286a7ce1..a23ba330b 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1187,8 +1187,42 @@ void readlevelheader(MYFILE *f, char * name) mapheaderinfo[num]->musname_size = j; } } - else if (fastcmp(word, "MUSICSLOT")) - deh_warning("Level header %d: MusicSlot parameter is deprecated and will be removed.\nUse \"Music\" instead.", num); + else if (fastcmp(word, "ASSOCIATEDMUSIC")) + { + if (fastcmp(word2, "NONE")) + { + mapheaderinfo[num]->associatedmus[0][0] = 0; // becomes empty string + mapheaderinfo[num]->associatedmus_size = 0; + } + else + { + UINT8 j = 0; // i was declared elsewhere + tmp = strtok(word2, ","); + do { + if (j >= MAXMUSNAMES) + break; + deh_strlcpy(mapheaderinfo[num]->associatedmus[j], tmp, + sizeof(mapheaderinfo[num]->associatedmus[j]), va("Level header %d: associated music", num)); + j++; + } while ((tmp = strtok(NULL,",")) != NULL); + + if (tmp != NULL) + deh_warning("Level header %d: additional associated music slots past %d discarded", num, MAXMUSNAMES); + mapheaderinfo[num]->associatedmus_size = j; + } + } + else if (fastcmp(word, "POSITIONMUSIC")) + { + if (fastcmp(word2, "NONE")) + { + mapheaderinfo[num]->positionmus[0] = 0; // becomes empty string + } + else + { + deh_strlcpy(mapheaderinfo[num]->positionmus, word2, + sizeof(mapheaderinfo[num]->positionmus), va("Level header %d: POSITION!! music", num)); + } + } else if (fastcmp(word, "MUSICTRACK")) mapheaderinfo[num]->mustrack = ((UINT16)i - 1); else if (fastcmp(word, "MUSICPOS")) diff --git a/src/doomstat.h b/src/doomstat.h index 2bf01f261..a0f28098f 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -445,9 +445,12 @@ struct mapheader_t // Music information char musname[MAXMUSNAMES][7]; ///< Music tracks to play. First dimension is the track number, second is the music string. "" for no music. + char associatedmus[MAXMUSNAMES][7]; ///< Associated music tracks for sound test unlock. + char positionmus[7]; ///< Custom Position track. Doesn't play in Encore or other fun game-controlled contexts + UINT8 musname_size; ///< Number of music tracks defined + UINT8 associatedmus_size; ///< Number of associated music tracks defined UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. UINT32 muspos; ///< Music position to jump to. - UINT8 musname_size; ///< Number of music tracks defined // Sky information UINT8 weather; ///< See preciptype_t diff --git a/src/k_menu.h b/src/k_menu.h index cff331600..cd7bbbe68 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -129,6 +129,12 @@ void M_HandlePauseMenuGametype(INT32 choice); // MENU TYPEDEFS // +typedef enum +{ + MBF_UD_LR_FLIPPED = 1, // flip up-down and left-right axes + MBF_SOUNDLESS = 2, // do not play base menu sounds +} menubehaviourflags_t; + struct menuitem_t { UINT16 status; // show IT_xxx @@ -154,6 +160,7 @@ struct menu_t INT16 x, y; // x, y of menu INT16 extra1, extra2; // Can be whatever really! Options menu uses extra1 for bg colour. + INT16 behaviourflags; // menubehaviourflags_t const char *music; // Track to play in M_PlayMenuJam. NULL for default, "." to stop INT16 transitionID; // only transition if IDs match @@ -419,10 +426,14 @@ extern menuitem_t MISC_ChallengesStatsDummyMenu[]; extern menu_t MISC_ChallengesDef; extern menu_t MISC_StatisticsDef; +extern menuitem_t MISC_SoundTest[]; +extern menu_t MISC_SoundTestDef; + // We'll need this since we're gonna have to dynamically enable and disable options depending on which state we're in. typedef enum { mpause_addons = 0, + mpause_stereo, mpause_changegametype, mpause_switchmap, mpause_restartmap, @@ -574,7 +585,9 @@ boolean M_NextOpt(void); boolean M_PrevOpt(void); boolean M_MenuConfirmPressed(UINT8 pid); +boolean M_MenuConfirmHeld(UINT8 pid); boolean M_MenuBackPressed(UINT8 pid); +boolean M_MenuBackHeld(UINT8 pid); boolean M_MenuExtraPressed(UINT8 pid); boolean M_MenuExtraHeld(UINT8 pid); @@ -1000,6 +1013,16 @@ extern struct extrasmenu_s { } extrasmenu; +typedef enum +{ + extras_addons = 0, + extras_challenges, + //extras_tutorial, + extras_statistics, + extras_eggtv, + extras_stereo, +} extras_e; + void M_InitExtras(INT32 choice); // init for the struct void M_ExtrasTick(void); boolean M_ExtrasInputs(INT32 ch); @@ -1196,6 +1219,21 @@ void M_Statistics(INT32 choice); void M_DrawStatistics(void); boolean M_StatisticsInputs(INT32 ch); +typedef enum +{ + stereospecial_none = 0, + stereospecial_back, + stereospecial_pause, + stereospecial_play, + stereospecial_seq, + stereospecial_vol, + stereospecial_track, +} stereospecial_e; + +void M_SoundTest(INT32 choice); +void M_DrawSoundTest(void); +consvar_t *M_GetSoundTestVolumeCvar(void); + // These defines make it a little easier to make menus #define DEFAULTMENUSTYLE(source, prev, x, y)\ {\ @@ -1204,6 +1242,8 @@ boolean M_StatisticsInputs(INT32 ch); 0,\ source,\ x, y,\ + 0, 0,\ + 0,\ NULL,\ 0, 0,\ M_DrawGenericMenu,\ @@ -1222,6 +1262,7 @@ boolean M_StatisticsInputs(INT32 ch); source,\ 0, 0,\ 0, 0,\ + 0,\ NULL,\ 1, 5,\ M_DrawKartGamemodeMenu,\ @@ -1239,6 +1280,7 @@ boolean M_StatisticsInputs(INT32 ch); source,\ 0, 0,\ 0, 0,\ + 0,\ "EXTRAS",\ 1, 5,\ M_DrawImageDef,\ diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 39144a6d8..abf0f7e1f 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5925,3 +5925,269 @@ void M_DrawStatistics(void) } #undef STATSSTEP + +void M_DrawSoundTest(void) +{ + UINT8 pid = 0; // todo: Add ability for any splitscreen player to bring up the menu. + + INT32 x, y, i, cursorx = 0; + INT32 titleoffset = 0, titlewidth; + const char *titletext; + + patch_t *btn = W_CachePatchName("STER_BTN", PU_CACHE); + + if (gamestate == GS_MENU) + { + patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE); + V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL); + } + + V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("STER_BG", PU_CACHE), NULL); + + x = 24; + y = 18; + + V_SetClipRect( + x << FRACBITS, y << FRACBITS, + 272 << FRACBITS, 106 << FRACBITS, + 0 + ); + + y += 32; + + if (soundtest.current != NULL) + { + if (soundtest.current->sequence.map < nummapheaders) + { + K_DrawMapThumbnail( + 0, 0, + BASEVIDWIDTH<sequence.map, + NULL); + + V_DrawFixedPatch( + 0, 0, + FRACUNIT, + V_60TRANS|V_SUBTRACT, + W_CachePatchName("STER_DOT", PU_CACHE), + NULL + ); + } + + titletext = soundtest.current->title; + + V_DrawThinString(x, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE, titletext); + if (soundtest.current->numtracks > 1) + V_DrawThinString(x, (y += 10), V_ALLOWLOWERCASE|V_6WIDTHSPACE, va("Track %c", 'A'+soundtest.currenttrack)); + if (soundtest.current->author) + V_DrawThinString(x, (y += 10), V_ALLOWLOWERCASE|V_6WIDTHSPACE, soundtest.current->author); + if (soundtest.current->source) + V_DrawThinString(x, (y += 10), V_ALLOWLOWERCASE|V_6WIDTHSPACE, soundtest.current->source); + if (soundtest.current->composers) + V_DrawThinString(x, (y += 10), V_ALLOWLOWERCASE|V_6WIDTHSPACE, soundtest.current->composers); + } + else + { + const char *sfxstr = (cv_soundtest.value) ? S_sfx[cv_soundtest.value].name : "N/A"; + + titletext = "Sound Test"; + + V_DrawThinString(x, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE, "Track "); + V_DrawThinString( + x + V_ThinStringWidth("Track ", V_ALLOWLOWERCASE|V_6WIDTHSPACE), + y, + V_6WIDTHSPACE, + va("%04X - %s", cv_soundtest.value, sfxstr) + ); + } + + titletext = va("%s - ", titletext); + titlewidth = V_LSTitleHighStringWidth(titletext, 0); + titleoffset = (-soundtest.menutick) % titlewidth; + + while (titleoffset < 272) + { + V_DrawLSTitleHighString(x + titleoffset, 18+1, 0, titletext); + titleoffset += titlewidth; + } + + V_DrawRightAlignedString(x + 272-1, 18+32, 0, + va("%02u:%02u", + G_TicsToMinutes(soundtest.currenttime, true), + G_TicsToSeconds(soundtest.currenttime) + ) + ); + + if ((soundtest.playing && soundtest.current) + && (soundtest.current->basenoloop[soundtest.currenttrack] == true + || soundtest.autosequence == true)) + { + UINT32 exittime = soundtest.sequencemaxtime; + if (soundtest.dosequencefadeout == true) + { + exittime += 3*TICRATE; + } + + V_DrawRightAlignedString(x + 272-1, 18+32+10, 0, + va("%02u:%02u", + G_TicsToMinutes(exittime, true), + G_TicsToSeconds(exittime) + ) + ); + } + + V_ClearClipRect(); + + x = currentMenu->x; + + for (i = 0; i < currentMenu->numitems; i++) + { + if (currentMenu->menuitems[i].status == IT_SPACE) + { + if (currentMenu->menuitems[i].mvar2 != 0) + { + x = currentMenu->menuitems[i].mvar2; + } + + x += currentMenu->menuitems[i].mvar1; + + continue; + } + + y = currentMenu->y; + + if (i == itemOn) + { + cursorx = x + 13; + } + + if (currentMenu->menuitems[i].tooltip) + { + V_SetClipRect( + x << FRACBITS, y << FRACBITS, + 27 << FRACBITS, 22 << FRACBITS, + 0 + ); + + // Special cases + if (currentMenu->menuitems[i].mvar2 == stereospecial_back) // back + { + if (!soundtest.justopened && M_MenuBackHeld(pid)) + { + y = currentMenu->y + 7; + } + } + // The following are springlocks. + else if (currentMenu->menuitems[i].mvar2 == stereospecial_pause) // pause + { + if (soundtest.paused == true) + y = currentMenu->y + 6; + } + else if (currentMenu->menuitems[i].mvar2 == stereospecial_play) // play + { + if (soundtest.playing == true && soundtest.paused == false) + y = currentMenu->y + 6; + } + else if (currentMenu->menuitems[i].mvar2 == stereospecial_seq) // seq + { + if (soundtest.autosequence == true) + y = currentMenu->y + 6; + } + + // Button is being pressed + if (i == itemOn && !soundtest.justopened && M_MenuConfirmHeld(pid)) + { + y = currentMenu->y + 7; + } + + // Button itself + V_DrawFixedPatch(x << FRACBITS, y << FRACBITS, FRACUNIT, 0, btn, NULL); + + // Icon + V_DrawFixedPatch(x << FRACBITS, y << FRACBITS, + FRACUNIT, 0, + W_CachePatchName(currentMenu->menuitems[i].tooltip, PU_CACHE), + NULL + ); + + // Text + V_DrawCenteredThinString(x + 13, y + 1, V_6WIDTHSPACE, currentMenu->menuitems[i].text); + + V_ClearClipRect(); + + V_DrawFill(x+2, currentMenu->y + 22, 23, 1, 30); + } + else if (currentMenu->menuitems[i].mvar2 == stereospecial_vol) // Vol + { + consvar_t *voltoadjust = M_GetSoundTestVolumeCvar(); + INT32 j, vol = 0; + const INT32 barheight = 22; + + V_DrawFixedPatch((x+1) << FRACBITS, y << FRACBITS, + FRACUNIT, 0, + W_CachePatchName("STER_KNB", PU_CACHE), + NULL + ); + + V_DrawFill(x+1+24, y+1, 5, barheight, 30); + + if (voltoadjust != NULL) + { + vol = (barheight*voltoadjust->value)/(MAX_SOUND_VOLUME*3); + } + + for (j = 0; j <= barheight/3; j++) + { + UINT8 col = 130; + + if (j == 0) + { + continue; + } + + if (j > vol) + { + col = 20; + } + else if (j > (barheight/3)-2) + { + col = 34; + } + + V_DrawFill(x+1+24+2, y+1 + (barheight-(j*3)), 1, 2, col); + } + + x += 5; + } + else if (currentMenu->menuitems[i].mvar2 == stereospecial_track) // Track + { + if (i == itemOn) + { + if (menucmd[pid].dpad_ud < 0 || M_MenuConfirmHeld(pid)) + { + y--; + } + else if (menucmd[pid].dpad_ud > 0) + { + y++; + } + } + + V_DrawFixedPatch(x << FRACBITS, (y-1) << FRACBITS, + FRACUNIT, 0, + W_CachePatchName("STER_WH0", PU_CACHE), + NULL + ); + } + else + { + V_DrawCenteredThinString(x + 13, y + 1, V_6WIDTHSPACE, currentMenu->menuitems[i].text); + } + + x += 27; + } + + V_DrawCharacter(cursorx - 4, currentMenu->y - 8 - (skullAnimCounter/5), + '\x1B' | V_SNAPTOTOP|highlightflags, false); // up arrow +} diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 2ed924289..4727f2fbe 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -382,7 +382,7 @@ void M_PlayMenuJam(void) return; } - if (Playing()) + if (Playing() || soundtest.playing) return; if (refMenu != NULL && refMenu->music != NULL) @@ -799,10 +799,10 @@ boolean M_MenuConfirmPressed(UINT8 pid) return M_MenuButtonPressed(pid, MBT_A); } -/*static boolean M_MenuConfirmHeld(UINT8 pid) +boolean M_MenuConfirmHeld(UINT8 pid) { return M_MenuButtonHeld(pid, MBT_A); -}*/ +} // Returns true if we press the Cancel button boolean M_MenuBackPressed(UINT8 pid) @@ -810,10 +810,10 @@ boolean M_MenuBackPressed(UINT8 pid) return (M_MenuButtonPressed(pid, MBT_B) || M_MenuButtonPressed(pid, MBT_X)); } -/*static boolean M_MenuBackHeld(UINT8 pid) +boolean M_MenuBackHeld(UINT8 pid) { return (M_MenuButtonHeld(pid, MBT_B) || M_MenuButtonHeld(pid, MBT_X)); -}*/ +} // Retrurns true if we press the tertiary option button (C) boolean M_MenuExtraPressed(UINT8 pid) @@ -902,8 +902,7 @@ static void M_HandleMenuInput(void) lr = menucmd[pid].dpad_lr; ud = menucmd[pid].dpad_ud; - // If we ever add a second horizontal menu, make it a menu_t property, not an extra check. - if (currentMenu == &PAUSE_PlaybackMenuDef) + if (currentMenu->behaviourflags & MBF_UD_LR_FLIPPED) { ud = menucmd[pid].dpad_lr; lr = -menucmd[pid].dpad_ud; @@ -916,14 +915,14 @@ static void M_HandleMenuInput(void) // Keys usable within menu if (ud > 0) { - if (M_NextOpt()) + if (M_NextOpt() && !(currentMenu->behaviourflags & MBF_SOUNDLESS)) S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); return; } else if (ud < 0) { - if (M_PrevOpt()) + if (M_PrevOpt() && !(currentMenu->behaviourflags & MBF_SOUNDLESS)) S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); return; @@ -933,7 +932,8 @@ static void M_HandleMenuInput(void) if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR)) { - S_StartSound(NULL, sfx_s3k5b); + if (!(currentMenu->behaviourflags & MBF_SOUNDLESS)) + S_StartSound(NULL, sfx_s3k5b); routine(0); M_SetMenuDelay(pid); } @@ -945,7 +945,8 @@ static void M_HandleMenuInput(void) if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR)) { - S_StartSound(NULL, sfx_s3k5b); + if (!(currentMenu->behaviourflags & MBF_SOUNDLESS)) + S_StartSound(NULL, sfx_s3k5b); routine(1); M_SetMenuDelay(pid); } @@ -959,7 +960,8 @@ static void M_HandleMenuInput(void) if (routine) { - S_StartSound(NULL, sfx_s3k5b); + if (!(currentMenu->behaviourflags & MBF_SOUNDLESS)) + S_StartSound(NULL, sfx_s3k5b); if (((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CALL || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_SUBMENU) @@ -1014,7 +1016,8 @@ static void M_HandleMenuInput(void) return; }*/ - S_StartSound(NULL, sfx_s3k5b); + if (!(currentMenu->behaviourflags & MBF_SOUNDLESS)) + S_StartSound(NULL, sfx_s3k5b); routine(-1); M_SetMenuDelay(pid); diff --git a/src/menus/extras-1.c b/src/menus/extras-1.c index 2ed90301a..771f70036 100644 --- a/src/menus/extras-1.c +++ b/src/menus/extras-1.c @@ -22,6 +22,9 @@ menuitem_t EXTRAS_Main[] = {IT_STRING | IT_CALL, NULL, NULL, NULL, {.routine = M_ReplayHut}, 0, 0}, + + {IT_STRING | IT_CALL, NULL, NULL, + NULL, {.routine = M_SoundTest}, 0, 0}, }; // the extras menu essentially reuses the options menu stuff @@ -32,8 +35,9 @@ menu_t EXTRAS_MainDef = { EXTRAS_Main, 0, 0, 0, 0, + 0, "EXTRAS", - 2, 5, + 28, 5, M_DrawExtras, M_ExtrasTick, NULL, @@ -61,35 +65,44 @@ void M_InitExtras(INT32 choice) // Addons if (M_SecretUnlocked(SECRET_ADDONS, true)) { - EXTRAS_Main[0].status = IT_STRING | IT_CALL; - EXTRAS_Main[0].text = "Addons"; - EXTRAS_Main[0].tooltip = "Add files to customize your experience."; + EXTRAS_Main[extras_addons].status = IT_STRING | IT_CALL; + EXTRAS_Main[extras_addons].text = "Addons"; + EXTRAS_Main[extras_addons].tooltip = "Add files to customize your experience."; } else { - EXTRAS_Main[0].status = IT_STRING | IT_TRANSTEXT; - EXTRAS_Main[0].text = EXTRAS_Main[0].tooltip = "???"; - if (EXTRAS_MainDef.lastOn == 0) + EXTRAS_Main[extras_addons].status = IT_STRING | IT_TRANSTEXT; + EXTRAS_Main[extras_addons].text = EXTRAS_Main[extras_addons].tooltip = "???"; + if (EXTRAS_MainDef.lastOn == extras_addons) { - EXTRAS_MainDef.lastOn = 1; + EXTRAS_MainDef.lastOn = extras_challenges; } } // Egg TV if (M_SecretUnlocked(SECRET_EGGTV, true)) { - EXTRAS_Main[3].status = IT_STRING | IT_CALL; - EXTRAS_Main[3].text = "Egg TV"; - EXTRAS_Main[3].tooltip = "Watch the replays you've saved throughout your many races & battles!"; + EXTRAS_Main[extras_eggtv].status = IT_STRING | IT_CALL; + EXTRAS_Main[extras_eggtv].text = "Egg TV"; + EXTRAS_Main[extras_eggtv].tooltip = "Watch the replays you've saved throughout your many races & battles!"; } else { - EXTRAS_Main[3].status = IT_STRING | IT_TRANSTEXT; - EXTRAS_Main[3].text = EXTRAS_Main[3].tooltip = "???"; - if (EXTRAS_MainDef.lastOn == 3) - { - EXTRAS_MainDef.lastOn = 2; - } + EXTRAS_Main[extras_eggtv].status = IT_STRING | IT_TRANSTEXT; + EXTRAS_Main[extras_eggtv].text = EXTRAS_Main[extras_eggtv].tooltip = "???"; + } + + // Stereo Mode + if (M_SecretUnlocked(SECRET_SOUNDTEST, true)) + { + EXTRAS_Main[extras_stereo].status = IT_STRING | IT_CALL; + EXTRAS_Main[extras_stereo].text = "Stereo Mode"; + EXTRAS_Main[extras_stereo].tooltip = "You can listen to your favourite tunes here!"; + } + else + { + EXTRAS_Main[extras_stereo].status = IT_STRING | IT_TRANSTEXT; + EXTRAS_Main[extras_stereo].text = EXTRAS_Main[extras_stereo].tooltip = "???"; } M_SetupNextMenu(&EXTRAS_MainDef, false); diff --git a/src/menus/extras-addons.c b/src/menus/extras-addons.c index a63c35e7f..868ba4cd4 100644 --- a/src/menus/extras-addons.c +++ b/src/menus/extras-addons.c @@ -23,6 +23,7 @@ menu_t MISC_AddonsDef = { MISC_AddonsMenu, 50, 28, 0, 0, + 0, "EXTRAS", 0, 0, M_DrawAddons, diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index c5cda4bc8..642067e83 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -20,6 +20,7 @@ menu_t MISC_ChallengesDef = { MISC_ChallengesStatsDummyMenu, BASEVIDWIDTH/2, 30, 0, 0, + 0, "EXTRAS", 98, 0, M_DrawChallenges, @@ -38,6 +39,7 @@ menu_t MISC_StatisticsDef = { MISC_ChallengesStatsDummyMenu, 280, 185, 0, 0, + 0, "EXTRAS", 98, 0, M_DrawStatistics, diff --git a/src/menus/extras-replay-hut.c b/src/menus/extras-replay-hut.c index 2dbf2c86a..881304719 100644 --- a/src/menus/extras-replay-hut.c +++ b/src/menus/extras-replay-hut.c @@ -26,6 +26,7 @@ menu_t EXTRAS_ReplayHutDef = EXTRAS_ReplayHut, 30, 80, 0, 0, + 0, "REPLAY", 41, 1, M_DrawReplayHut, @@ -59,6 +60,7 @@ menu_t EXTRAS_ReplayStartDef = EXTRAS_ReplayStart, 27, 80, 0, 0, + 0, "REPLAY", 41, 1, M_DrawReplayStartMenu, diff --git a/src/menus/main-profile-select.c b/src/menus/main-profile-select.c index e070e2b5b..13b840f9a 100644 --- a/src/menus/main-profile-select.c +++ b/src/menus/main-profile-select.c @@ -15,6 +15,7 @@ menu_t MAIN_ProfilesDef = { MAIN_Profiles, 32, 80, SKINCOLOR_ULTRAMARINE, 0, + 0, NULL, 2, 5, M_DrawProfileSelect, diff --git a/src/menus/options-1.c b/src/menus/options-1.c index bc55f41e6..6d91ab224 100644 --- a/src/menus/options-1.c +++ b/src/menus/options-1.c @@ -43,6 +43,7 @@ menu_t OPTIONS_MainDef = { OPTIONS_Main, 0, 0, SKINCOLOR_SLATE, 0, + 0, NULL, 2, 5, M_DrawOptions, diff --git a/src/menus/options-data-1.c b/src/menus/options-data-1.c index 632da7977..c0bc72468 100644 --- a/src/menus/options-data-1.c +++ b/src/menus/options-data-1.c @@ -36,6 +36,7 @@ menu_t OPTIONS_DataDef = { OPTIONS_Data, 48, 80, SKINCOLOR_BLUEBERRY, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-data-addons.c b/src/menus/options-data-addons.c index a8ea39ecb..4d7a35e14 100644 --- a/src/menus/options-data-addons.c +++ b/src/menus/options-data-addons.c @@ -37,6 +37,7 @@ menu_t OPTIONS_DataAddonDef = { OPTIONS_DataAddon, 48, 80, SKINCOLOR_BLUEBERRY, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-data-discord.c b/src/menus/options-data-discord.c index 5e5518c51..45cb9846d 100644 --- a/src/menus/options-data-discord.c +++ b/src/menus/options-data-discord.c @@ -33,6 +33,7 @@ menu_t OPTIONS_DataDiscordDef = { OPTIONS_DataDiscord, 48, 80, SKINCOLOR_BLUEBERRY, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-data-erase-1.c b/src/menus/options-data-erase-1.c index faf893d32..57869c561 100644 --- a/src/menus/options-data-erase-1.c +++ b/src/menus/options-data-erase-1.c @@ -40,6 +40,7 @@ menu_t OPTIONS_DataEraseDef = { OPTIONS_DataErase, 48, 80, SKINCOLOR_BLACK, 0, + 0, "SHWDN2", // Danger. 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-data-erase-profile.c b/src/menus/options-data-erase-profile.c index 378a3471d..090f2d60e 100644 --- a/src/menus/options-data-erase-profile.c +++ b/src/menus/options-data-erase-profile.c @@ -17,6 +17,7 @@ menu_t OPTIONS_DataProfileEraseDef = { OPTIONS_DataProfileErase, 48, 80, SKINCOLOR_BLACK, 0, + 0, "SHWDN2", // Danger. 2, 5, M_DrawProfileErase, diff --git a/src/menus/options-data-replays.c b/src/menus/options-data-replays.c index 20e3aa8a3..13e95779c 100644 --- a/src/menus/options-data-replays.c +++ b/src/menus/options-data-replays.c @@ -19,6 +19,7 @@ menu_t OPTIONS_DataReplayDef = { OPTIONS_DataReplay, 48, 80, SKINCOLOR_BLUEBERRY, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-data-screenshots.c b/src/menus/options-data-screenshots.c index d67c2dc5e..0d24e9662 100644 --- a/src/menus/options-data-screenshots.c +++ b/src/menus/options-data-screenshots.c @@ -35,6 +35,7 @@ menu_t OPTIONS_DataScreenshotDef = { OPTIONS_DataScreenshot, 48, 80, SKINCOLOR_BLUEBERRY, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-gameplay-1.c b/src/menus/options-gameplay-1.c index fc528258b..d6207d8df 100644 --- a/src/menus/options-gameplay-1.c +++ b/src/menus/options-gameplay-1.c @@ -51,6 +51,7 @@ menu_t OPTIONS_GameplayDef = { OPTIONS_Gameplay, 48, 80, SKINCOLOR_SCARLET, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-gameplay-item-toggles.c b/src/menus/options-gameplay-item-toggles.c index 0a5cf9ba5..fd4bc5818 100644 --- a/src/menus/options-gameplay-item-toggles.c +++ b/src/menus/options-gameplay-item-toggles.c @@ -55,6 +55,7 @@ menu_t OPTIONS_GameplayItemsDef = { OPTIONS_GameplayItems, 14, 40, SKINCOLOR_SCARLET, 0, + 0, NULL, 2, 5, M_DrawItemToggles, diff --git a/src/menus/options-hud-1.c b/src/menus/options-hud-1.c index 33f660657..54bb4449c 100644 --- a/src/menus/options-hud-1.c +++ b/src/menus/options-hud-1.c @@ -48,6 +48,7 @@ menu_t OPTIONS_HUDDef = { OPTIONS_HUD, 48, 80, SKINCOLOR_SUNSLAM, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-hud-online.c b/src/menus/options-hud-online.c index 3a731883d..3b2b7defa 100644 --- a/src/menus/options-hud-online.c +++ b/src/menus/options-hud-online.c @@ -45,6 +45,7 @@ menu_t OPTIONS_HUDOnlineDef = { OPTIONS_HUDOnline, 48, 80, SKINCOLOR_SUNSLAM, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-profiles-1.c b/src/menus/options-profiles-1.c index 18a0316bc..17d4c241b 100644 --- a/src/menus/options-profiles-1.c +++ b/src/menus/options-profiles-1.c @@ -17,6 +17,7 @@ menu_t OPTIONS_ProfilesDef = { OPTIONS_Profiles, 32, 80, SKINCOLOR_ULTRAMARINE, 0, + 0, NULL, 2, 5, M_DrawProfileSelect, diff --git a/src/menus/options-profiles-edit-1.c b/src/menus/options-profiles-edit-1.c index 99caa532d..b1ed78f98 100644 --- a/src/menus/options-profiles-edit-1.c +++ b/src/menus/options-profiles-edit-1.c @@ -29,6 +29,7 @@ menu_t OPTIONS_EditProfileDef = { OPTIONS_EditProfile, 32, 80, SKINCOLOR_ULTRAMARINE, 0, + 0, NULL, 2, 5, M_DrawEditProfile, diff --git a/src/menus/options-profiles-edit-controls.c b/src/menus/options-profiles-edit-controls.c index 13633deed..779fc625c 100644 --- a/src/menus/options-profiles-edit-controls.c +++ b/src/menus/options-profiles-edit-controls.c @@ -103,6 +103,7 @@ menu_t OPTIONS_ProfileControlsDef = { OPTIONS_ProfileControls, 32, 80, SKINCOLOR_ULTRAMARINE, 0, + 0, NULL, 3, 5, M_DrawProfileControls, diff --git a/src/menus/options-server-1.c b/src/menus/options-server-1.c index 4e793d3b5..3ee92e38f 100644 --- a/src/menus/options-server-1.c +++ b/src/menus/options-server-1.c @@ -55,6 +55,7 @@ menu_t OPTIONS_ServerDef = { OPTIONS_Server, 48, 70, // This menu here is slightly higher because there's a lot of options... SKINCOLOR_VIOLET, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-server-advanced.c b/src/menus/options-server-advanced.c index 55fca8043..6af9c3cd9 100644 --- a/src/menus/options-server-advanced.c +++ b/src/menus/options-server-advanced.c @@ -53,6 +53,7 @@ menu_t OPTIONS_ServerAdvancedDef = { OPTIONS_ServerAdvanced, 48, 70, // This menu here is slightly higher because there's a lot of options... SKINCOLOR_VIOLET, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-sound.c b/src/menus/options-sound.c index 027c8448f..21298e1ed 100644 --- a/src/menus/options-sound.c +++ b/src/menus/options-sound.c @@ -57,6 +57,7 @@ menu_t OPTIONS_SoundDef = { OPTIONS_Sound, 48, 80, SKINCOLOR_THUNDER, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-video-1.c b/src/menus/options-video-1.c index 4447531cf..35d937da8 100644 --- a/src/menus/options-video-1.c +++ b/src/menus/options-video-1.c @@ -59,6 +59,7 @@ menu_t OPTIONS_VideoDef = { OPTIONS_Video, 32, 80, SKINCOLOR_PLAGUE, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-video-gl.c b/src/menus/options-video-gl.c index 2fabeaccc..bb91244f0 100644 --- a/src/menus/options-video-gl.c +++ b/src/menus/options-video-gl.c @@ -51,6 +51,7 @@ menu_t OPTIONS_VideoOGLDef = { OPTIONS_VideoOGL, 32, 80, SKINCOLOR_PLAGUE, 0, + 0, NULL, 2, 5, M_DrawGenericOptions, diff --git a/src/menus/options-video-modes.c b/src/menus/options-video-modes.c index 872e23384..056fc2a10 100644 --- a/src/menus/options-video-modes.c +++ b/src/menus/options-video-modes.c @@ -19,6 +19,7 @@ menu_t OPTIONS_VideoModesDef = { OPTIONS_VideoModes, 48, 80, SKINCOLOR_PLAGUE, 0, + 0, NULL, 2, 5, M_DrawVideoModes, diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index 8c0d36601..35e918a65 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -19,6 +19,7 @@ menu_t PLAY_CharSelectDef = { PLAY_CharSelect, 0, 0, 0, 0, + 0, NULL, 0, 0, M_DrawCharacterSelect, diff --git a/src/menus/play-local-race-difficulty.c b/src/menus/play-local-race-difficulty.c index db9704be2..600176816 100644 --- a/src/menus/play-local-race-difficulty.c +++ b/src/menus/play-local-race-difficulty.c @@ -39,6 +39,7 @@ menu_t PLAY_RaceDifficultyDef = { PLAY_RaceDifficulty, 0, 0, 0, 0, + 0, NULL, 1, 5, M_DrawRaceDifficulty, diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index 4c51a2a6c..fac09dcc0 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -73,6 +73,7 @@ menu_t PLAY_TimeAttackDef = { PLAY_TimeAttack, 0, 0, 0, 0, + 0, NULL, 2, 5, M_DrawTimeAttack, @@ -115,6 +116,7 @@ menu_t PLAY_TAReplayDef = { PLAY_TAReplay, 0, 0, 0, 0, + 0, NULL, 2, 5, M_DrawTimeAttack, @@ -159,6 +161,7 @@ menu_t PLAY_TAReplayGuestDef = { PLAY_TAReplayGuest, 0, 0, 0, 0, + 0, NULL, 2, 5, M_DrawTimeAttack, @@ -198,6 +201,7 @@ menu_t PLAY_TAGhostsDef = { PLAY_TAGhosts, 0, 0, 0, 0, + 0, NULL, 2, 5, M_DrawTimeAttack, diff --git a/src/menus/play-online-1.c b/src/menus/play-online-1.c index e146926b1..ed4ef704f 100644 --- a/src/menus/play-online-1.c +++ b/src/menus/play-online-1.c @@ -37,6 +37,7 @@ menu_t PLAY_MP_OptSelectDef = { PLAY_MP_OptSelect, 0, 0, 0, 0, + 0, "NETMD2", -1, 1, M_DrawMPOptSelect, diff --git a/src/menus/play-online-host.c b/src/menus/play-online-host.c index 319cda9e3..95ce0660e 100644 --- a/src/menus/play-online-host.c +++ b/src/menus/play-online-host.c @@ -33,6 +33,7 @@ menu_t PLAY_MP_HostDef = { PLAY_MP_Host, 0, 0, 0, 0, + 0, "NETMD2", -1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe M_DrawMPHost, diff --git a/src/menus/play-online-join-ip.c b/src/menus/play-online-join-ip.c index bd72a1ffb..6d26b85cb 100644 --- a/src/menus/play-online-join-ip.c +++ b/src/menus/play-online-join-ip.c @@ -38,6 +38,7 @@ menu_t PLAY_MP_JoinIPDef = { PLAY_MP_JoinIP, 0, 0, 0, 0, + 0, "NETMD2", -1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe M_DrawMPJoinIP, diff --git a/src/menus/play-online-room-select.c b/src/menus/play-online-room-select.c index b1364f020..666b7c987 100644 --- a/src/menus/play-online-room-select.c +++ b/src/menus/play-online-room-select.c @@ -17,6 +17,7 @@ menu_t PLAY_MP_RoomSelectDef = { PLAY_MP_RoomSelect, 0, 0, 0, 0, + 0, "NETMD2", 0, 0, M_DrawMPRoomSelect, diff --git a/src/menus/play-online-server-browser.c b/src/menus/play-online-server-browser.c index 393a2ae28..795febc0b 100644 --- a/src/menus/play-online-server-browser.c +++ b/src/menus/play-online-server-browser.c @@ -29,6 +29,7 @@ menu_t PLAY_MP_ServerBrowserDef = { PLAY_MP_ServerBrowser, 32, 36, 0, 0, + 0, "NETMD2", 0, 0, M_DrawMPServerBrowser, diff --git a/src/menus/transient/CMakeLists.txt b/src/menus/transient/CMakeLists.txt index bea478d5f..a1d0cd1c6 100644 --- a/src/menus/transient/CMakeLists.txt +++ b/src/menus/transient/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(SRB2SDL2 PRIVATE level-select.c gametype.c manual.c + sound-test.c message-box.c pause-game.c pause-replay.c diff --git a/src/menus/transient/cup-select.c b/src/menus/transient/cup-select.c index cca546f9e..f4f97ed29 100644 --- a/src/menus/transient/cup-select.c +++ b/src/menus/transient/cup-select.c @@ -20,6 +20,7 @@ menu_t PLAY_CupSelectDef = { PLAY_CupSelect, 0, 0, 0, 0, + 0, NULL, 2, 5, M_DrawCupSelect, diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index 11a62e944..234d6d539 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -23,6 +23,7 @@ menu_t PLAY_LevelSelectDef = { PLAY_LevelSelect, 0, 0, 0, 0, + 0, NULL, 2, 5, M_DrawLevelSelect, diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index ff6c5c3b4..f6ad377e0 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -15,6 +15,9 @@ menuitem_t PAUSE_Main[] = {IT_STRING | IT_CALL, "ADDONS", "M_ICOADD", NULL, {.routine = M_Addons}, 0, 0}, + {IT_STRING | IT_CALL, "STEREO MODE", "M_ICOSTM", + NULL, {.routine = M_SoundTest}, 0, 0}, + {IT_STRING | IT_KEYHANDLER, "GAMETYPE", "M_ICOGAM", NULL, {.routine = M_HandlePauseMenuGametype}, 0, 0}, @@ -64,6 +67,7 @@ menu_t PAUSE_MainDef = { PAUSE_Main, 0, 0, 0, 0, + 0, NULL, 1, 10, // For transition with some menus! M_DrawPause, @@ -110,6 +114,7 @@ void M_OpenPauseMenu(void) // By default, disable anything sensitive: PAUSE_Main[mpause_addons].status = IT_DISABLED; + PAUSE_Main[mpause_stereo].status = IT_DISABLED; PAUSE_Main[mpause_changegametype].status = IT_DISABLED; PAUSE_Main[mpause_switchmap].status = IT_DISABLED; PAUSE_Main[mpause_restartmap].status = IT_DISABLED; @@ -126,6 +131,11 @@ void M_OpenPauseMenu(void) Dummymenuplayer_OnChange(); // Make sure the consvar is within bounds of the amount of splitscreen players we have. + if (M_SecretUnlocked(SECRET_SOUNDTEST, true)) + { + PAUSE_Main[mpause_stereo].status = IT_STRING | IT_CALL; + } + if (K_CanChangeRules(false)) { PAUSE_Main[mpause_psetup].status = IT_STRING | IT_CALL; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 5a7c45826..b1a1353a3 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -39,6 +39,7 @@ menu_t PAUSE_PlaybackMenuDef = { PAUSE_PlaybackMenu, BASEVIDWIDTH/2 - 88, 2, 0, 0, + MBF_UD_LR_FLIPPED, NULL, 0, 0, M_DrawPlaybackMenu, diff --git a/src/menus/transient/sound-test.c b/src/menus/transient/sound-test.c new file mode 100644 index 000000000..fb16972f4 --- /dev/null +++ b/src/menus/transient/sound-test.c @@ -0,0 +1,204 @@ +/// \file menus/transient/sound-test.c +/// \brief Stereo Mode menu + +#include "../../k_menu.h" +#include "../../s_sound.h" + +static void M_SoundTestMainControl(INT32 choice) +{ + (void)choice; + + // Sound test exception + if (soundtest.current == NULL || soundtest.current->numtracks == 0) + { + if (cv_soundtest.value != 0) + { + S_StopSounds(); + + if (currentMenu->menuitems[itemOn].mvar1 == 0) // Stop + { + CV_SetValue(&cv_soundtest, 0); + } + else if (currentMenu->menuitems[itemOn].mvar1 == 1) // Play + { + S_StartSound(NULL, cv_soundtest.value); + } + } + else if (currentMenu->menuitems[itemOn].mvar1 == 1) // Play + { + soundtest.playing = true; + soundtest.autosequence = true; + S_UpdateSoundTestDef(false, false, false); + } + + return; + } + + if (currentMenu->menuitems[itemOn].mvar1 == 1) // Play + { + if (soundtest.paused == true) + { + S_SoundTestTogglePause(); + } + else if (soundtest.playing == false) + { + S_SoundTestPlay(); + } + } + else if (soundtest.playing == true) + { + if (currentMenu->menuitems[itemOn].mvar1 == 2) // Pause + { + if (soundtest.paused == false) + { + S_SoundTestTogglePause(); + } + } + else // Stop + { + S_SoundTestStop(); + } + } + else if (currentMenu->menuitems[itemOn].mvar1 == 0) // Stop while stopped? + { + soundtest.current = NULL; + soundtest.currenttrack = 0; + CV_SetValue(&cv_soundtest, 0); + } +} + +static void M_SoundTestNextPrev(INT32 choice) +{ + (void)choice; + + S_UpdateSoundTestDef((currentMenu->menuitems[itemOn].mvar1 < 0), true, false); +} + +static void M_SoundTestSeq(INT32 choice) +{ + (void)choice; + + soundtest.autosequence ^= true; +} + +consvar_t *M_GetSoundTestVolumeCvar(void) +{ + if (soundtest.current == NULL) + { + if (cv_soundtest.value == 0) + return NULL; + + return &cv_soundvolume; + } + + return &cv_digmusicvolume; +} + +static void M_SoundTestVol(INT32 choice) +{ + consvar_t *voltoadjust = M_GetSoundTestVolumeCvar(); + + if (!voltoadjust) + return; + + M_ChangeCvarDirect(choice, voltoadjust); +} + +static void M_SoundTestTrack(INT32 choice) +{ + const UINT8 numtracks = (soundtest.current != NULL) ? soundtest.current->numtracks : 0; + + if (numtracks == 1 // No cycling + || choice == -1) // Extra + { + return; + } + + // Confirm is generally treated as Up. + + // Soundtest exception + if (numtracks == 0) + { + S_StopSounds(); + CV_AddValue(&cv_soundtest, ((choice == 0) ? -1 : 1)); + + return; + } + + if (choice == 0) // Down + { + soundtest.currenttrack--; + if (soundtest.currenttrack < 0) + soundtest.currenttrack = numtracks-1; + } + else //if (choice == 1) -- Up + { + soundtest.currenttrack++; + if (soundtest.currenttrack >= numtracks) + soundtest.currenttrack = 0; + } + + if (soundtest.playing) + { + S_SoundTestPlay(); + } +} + +static boolean M_SoundTestInputs(INT32 ch) +{ + (void)ch; + soundtest.justopened = false; + return false; +} + +static void M_SoundTestTick(void) +{ + soundtest.menutick++; +} + +menuitem_t MISC_SoundTest[] = +{ + {IT_STRING | IT_CALL, "Back", "STER_IC0", NULL, {.routine = M_GoBack}, 0, stereospecial_back}, + {IT_SPACE, NULL, NULL, NULL, {NULL}, 11, 0}, + {IT_STRING | IT_CALL, "Stop", "STER_IC1", NULL, {.routine = M_SoundTestMainControl}, 0, 0}, + {IT_SPACE, NULL, NULL, NULL, {NULL}, 8, 0}, + {IT_STRING | IT_CALL, "Pause", "STER_IC2", NULL, {.routine = M_SoundTestMainControl}, 2, stereospecial_pause}, + {IT_STRING | IT_CALL, "Play", "STER_IC3", NULL, {.routine = M_SoundTestMainControl}, 1, stereospecial_play}, + {IT_SPACE, NULL, NULL, NULL, {NULL}, 8, 0}, + {IT_STRING | IT_CALL, "Prev", "STER_IC4", NULL, {.routine = M_SoundTestNextPrev}, -1, 0}, + {IT_STRING | IT_CALL, "Next", "STER_IC5", NULL, {.routine = M_SoundTestNextPrev}, 1, 0}, + {IT_SPACE, NULL, NULL, NULL, {NULL}, 8, 0}, + {IT_STRING | IT_ARROWS, "Seq", "STER_IC6", NULL, {.routine = M_SoundTestSeq}, 0, stereospecial_seq}, + {IT_SPACE, NULL, NULL, NULL, {NULL}, 0, 244}, + {IT_STRING | IT_ARROWS, "Vol", NULL, NULL, {.routine = M_SoundTestVol}, 0, stereospecial_vol}, + {IT_STRING | IT_ARROWS, "Track", NULL, NULL, {.routine = M_SoundTestTrack}, 0, stereospecial_track}, +}; + +menu_t MISC_SoundTestDef = { + sizeof (MISC_SoundTest)/sizeof (menuitem_t), + &MainDef, + 0, + MISC_SoundTest, + 19, 140, + 0, 0, + MBF_UD_LR_FLIPPED|MBF_SOUNDLESS, + ".", + 98, 0, + M_DrawSoundTest, + M_SoundTestTick, + NULL, + NULL, + M_SoundTestInputs, +}; + +void M_SoundTest(INT32 choice) +{ + (void)choice; + + // I reserve the right to add some sort of setup here -- toast 250323 + soundtest.menutick = 0; + soundtest.justopened = true; + + MISC_SoundTestDef.prevMenu = currentMenu; + M_SetupNextMenu(&MISC_SoundTestDef, false); +} diff --git a/src/p_setup.c b/src/p_setup.c index 97f9680df..612c16e7b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -382,8 +382,6 @@ void P_DeleteFlickies(INT16 i) */ static void P_ClearSingleMapHeaderInfo(INT16 num) { - UINT8 i = 0; - mapheaderinfo[num]->lvlttl[0] = '\0'; mapheaderinfo[num]->subttl[0] = '\0'; mapheaderinfo[num]->zonttl[0] = '\0'; @@ -391,11 +389,12 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->typeoflevel = 0; mapheaderinfo[num]->gravity = DEFAULT_GRAVITY; mapheaderinfo[num]->keywords[0] = '\0'; - for (i = 0; i < MAXMUSNAMES; i++) - mapheaderinfo[num]->musname[i][0] = 0; + mapheaderinfo[num]->musname[0][0] = 0; + mapheaderinfo[num]->musname_size = 0; + mapheaderinfo[num]->associatedmus[0][0] = 0; + mapheaderinfo[num]->associatedmus_size = 0; mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; - mapheaderinfo[num]->musname_size = 0; mapheaderinfo[num]->weather = PRECIP_NONE; snprintf(mapheaderinfo[num]->skytexture, 5, "SKY1"); mapheaderinfo[num]->skytexture[4] = 0; @@ -8599,6 +8598,9 @@ boolean P_MultiSetupWadFiles(boolean fullsetup) if (partadd_stage < 0) { + // possible future work: only do this if musicdefs/map headers changed + S_PopulateSoundTestSequence(); + partadd_important = false; partadd_earliestfile = UINT16_MAX; return true; diff --git a/src/p_tick.c b/src/p_tick.c index 6c450d959..7327e5c1d 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -803,7 +803,11 @@ void P_Ticker(boolean run) { // Plays the POSITION music after the camera spin if (leveltime == introtime) - S_ChangeMusicInternal("postn", true); + S_ChangeMusicInternal( + (mapheaderinfo[gamemap-1]->positionmus[0] + ? mapheaderinfo[gamemap-1]->positionmus + : "postn" + ), true); } } diff --git a/src/s_sound.c b/src/s_sound.c index e8adb2a70..d45a3da26 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -33,6 +33,7 @@ #include "byteptr.h" #include "k_menu.h" // M_PlayMenuJam #include "m_random.h" // P_RandomKey +#include "i_time.h" #ifdef HW3SOUND // 3D Sound Interface @@ -1356,12 +1357,415 @@ static UINT32 queue_fadeinms; static tic_t pause_starttic; +static void S_AttemptToRestoreMusic(void) +{ + switch (gamestate) + { + case GS_LEVEL: + P_RestoreMusic(&players[consoleplayer]); + break; + case GS_TITLESCREEN: + S_ChangeMusicInternal("_title", looptitle); + break; + case GS_MENU: + M_PlayMenuJam(); + break; + default: + break; + } +} + /// ------------------------ /// Music Definitions /// ------------------------ musicdef_t *musicdefstart = NULL; struct cursongcredit cursongcredit; // Currently displayed song credit info +struct soundtest soundtest; // Sound Test (sound test) + +static void S_InsertMusicAtSoundTestSequenceTail(const char *musname, UINT16 map, musicdef_t ***tail) +{ + UINT8 i = 0; + musicdef_t *def = S_FindMusicDef(musname, &i); + + if (def == NULL) + return; + + if (def->sequence.id == soundtest.sequence.id) + return; + + def->sequence.id = soundtest.sequence.id; + def->sequence.map = map; + + // So what we're doing here is to avoid iterating + // for every insertion, we dereference the pointer + // to get **tail from S_PopulateSoundTestSequence, + // then dereference that to get the musicdef_t *. + // We do it this way so that soundtest.sequence.next + // can be handled natively without special cases. + // I have officially lost my MIND. ~toast 270323 + *(*tail) = def; + *tail = &def->sequence.next; +} + +static void S_InsertMapIntoSoundTestSequence(UINT16 map, musicdef_t ***tail) +{ + UINT8 i; + + if (mapheaderinfo[map]->positionmus[0]) + { + S_InsertMusicAtSoundTestSequenceTail(mapheaderinfo[map]->positionmus, map, tail); + } + + for (i = 0; i < mapheaderinfo[map]->musname_size; i++) + { + S_InsertMusicAtSoundTestSequenceTail(mapheaderinfo[map]->musname[i], map, tail); + } + + for (i = 0; i < mapheaderinfo[map]->associatedmus_size; i++) + { + S_InsertMusicAtSoundTestSequenceTail(mapheaderinfo[map]->associatedmus[i], map, tail); + } +} + +void S_PopulateSoundTestSequence(void) +{ + UINT16 i; + musicdef_t **tail; + + // First, increment the sequence and wipe the HEAD. + // This invalidates all existing musicdefs without us + // having to iterate through everything all the time, + // and offers a very convenient checking mechanism. + // ...preventing id 0 protects against inconsistencies + // caused by newly Calloc'd music definitions. + soundtest.sequence.id = (soundtest.sequence.id + 1) & 255; + if (soundtest.sequence.id == 0) + soundtest.sequence.id = 1; + + soundtest.sequence.next = NULL; + + tail = &soundtest.sequence.next; + + // We iterate over all cups. + { + cupheader_t *cup; + for (cup = kartcupheaders; cup; cup = cup->next) + { + for (i = 0; i < CUPCACHE_MAX; i++) + { + if (cup->cachedlevels[i] >= nummapheaders) + continue; + + if (!mapheaderinfo[cup->cachedlevels[i]]) + continue; + + if (mapheaderinfo[cup->cachedlevels[i]]->cup != cup) + continue; + + S_InsertMapIntoSoundTestSequence(cup->cachedlevels[i], &tail); + } + } + } + + // Then, we iterate over all non-cupped maps. + for (i = 0; i < nummapheaders; i++) + { + if (!mapheaderinfo[i]) + continue; + + if (mapheaderinfo[i]->cup != NULL) + continue; + + S_InsertMapIntoSoundTestSequence(i, &tail); + } + + // Finally, we insert all other musicdefstart at the head. + // It's being added to the sequence in reverse order... + // but because musicdefstart is ALSO populated in reverse, + // the reverse of the reverse is the right way around! + { + musicdef_t *def; + + for (def = musicdefstart; def; def = def->next) + { + if (def->sequence.id == soundtest.sequence.id) + continue; + + def->sequence.id = soundtest.sequence.id; + def->sequence.map = NEXTMAP_INVALID; + + def->sequence.next = soundtest.sequence.next; + soundtest.sequence.next = def; + } + } +} + +static boolean S_SoundTestDefLocked(musicdef_t *def) +{ + // temporary - i'd like to find a way to conditionally hide + // specific musicdefs that don't have any map associated. + if (def->sequence.map >= nummapheaders) + return false; + + // Is the level tied to SP progression? + if ((mapheaderinfo[def->sequence.map]->menuflags & LF2_FINISHNEEDED) + && !(mapheaderinfo[def->sequence.map]->mapvisited & MV_BEATEN)) + return true; + + // Finally, do a full-fat map check. + return M_MapLocked(def->sequence.map+1); +} + +void S_UpdateSoundTestDef(boolean reverse, boolean dotracks, boolean skipnull) +{ + musicdef_t *newdef; + + newdef = NULL; + + if (reverse == false) + { + if (dotracks == true && soundtest.current != NULL + && soundtest.currenttrack < soundtest.current->numtracks-1) + { + soundtest.currenttrack++; + goto updatetrackonly; + } + + newdef = (soundtest.current != NULL) + ? soundtest.current->sequence.next + : soundtest.sequence.next; + while (newdef != NULL && S_SoundTestDefLocked(newdef)) + newdef = newdef->sequence.next; + if (newdef == NULL && skipnull == true) + { + newdef = soundtest.sequence.next; + while (newdef != NULL && S_SoundTestDefLocked(newdef)) + newdef = newdef->sequence.next; + } + } + else + { + musicdef_t *def, *lastdef = NULL; + + if (dotracks == true && soundtest.current != NULL + && soundtest.currenttrack > 0) + { + soundtest.currenttrack--; + goto updatetrackonly; + } + + if (soundtest.current == soundtest.sequence.next + && skipnull == false) + { + goto updatecurrent; + } + + for (def = soundtest.sequence.next; def; def = def->sequence.next) + { + if (!S_SoundTestDefLocked(def)) + { + lastdef = def; + } + + if (def->sequence.next != soundtest.current) + { + continue; + } + + newdef = lastdef; + break; + } + } + +updatecurrent: + soundtest.current = newdef; + soundtest.currenttrack = + (reverse == true && dotracks == true && newdef != NULL) + ? newdef->numtracks-1 + : 0; + + if (newdef == NULL) + { + CV_SetValue(&cv_soundtest, 0); + } + +updatetrackonly: + if (soundtest.playing == true) + { + S_SoundTestPlay(); + } +} + +void S_SoundTestPlay(void) +{ + if (soundtest.current == NULL) + { + S_SoundTestStop(); + return; + } + + soundtest.privilegedrequest = true; + + S_StopMusic(); + + soundtest.playing = true; + + if (soundtest.paused == true) + { + S_SoundTestTogglePause(); + } + + S_ChangeMusicInternal(soundtest.current->name[soundtest.currenttrack], + !soundtest.current->basenoloop[soundtest.currenttrack]); + S_ShowMusicCredit(); + + soundtest.currenttime = 0; + soundtest.sequencemaxtime = S_GetMusicLength(); + soundtest.sequencefadeout = 0; + + if (soundtest.sequencemaxtime) + { + // Does song have default loop? + if (soundtest.current->basenoloop[soundtest.currenttrack] == false) + { + soundtest.dosequencefadeout = (soundtest.currenttrack == soundtest.current->numtracks-1); + soundtest.sequencemaxtime *= 2; // Two loops by default. + soundtest.sequencemaxtime -= S_GetMusicLoopPoint(); // Otherwise the intro is counted twice. + } + else + { + soundtest.dosequencefadeout = false; + } + + // ms to TICRATE conversion + soundtest.sequencemaxtime = (TICRATE*soundtest.sequencemaxtime)/1000; + } + + soundtest.privilegedrequest = false; +} + +void S_SoundTestStop(void) +{ + if (soundtest.playing == false) + { + return; + } + + soundtest.privilegedrequest = true; + + soundtest.playing = false; + soundtest.paused = false; + soundtest.autosequence = false; + + S_StopMusic(); + cursongcredit.def = NULL; + + soundtest.currenttime = 0; + soundtest.sequencemaxtime = 0; + soundtest.sequencefadeout = 0; + soundtest.dosequencefadeout = false; + + S_AttemptToRestoreMusic(); + + soundtest.privilegedrequest = false; +} + +void S_SoundTestTogglePause(void) +{ + if (soundtest.playing == false) + { + return; + } + + if (soundtest.paused == true) + { + soundtest.paused = false; + S_ResumeAudio(); + } + else + { + soundtest.paused = true; + S_PauseAudio(); + } +} + +void S_TickSoundTest(void) +{ + static UINT32 storetime = 0; + UINT32 lasttime = storetime; + boolean donext = false; + + storetime = I_GetTime(); + + if (soundtest.playing == false || soundtest.current == NULL) + { + return; + } + + if (I_SongPlaying() == false) + { + S_SoundTestStop(); + return; + } + + if (I_SongPaused() == false) + { + soundtest.currenttime += (storetime - lasttime); + } + + if (soundtest.sequencefadeout > 0) + { + if (soundtest.currenttime >= soundtest.sequencefadeout) + { + donext = true; + } + } + else if (soundtest.currenttime >= soundtest.sequencemaxtime) + { + if (soundtest.autosequence == false) + { + if (soundtest.current->basenoloop[soundtest.currenttrack] == true) + { + S_SoundTestStop(); + } + + return; + } + else if (soundtest.dosequencefadeout == false) + { + donext = true; + } + else + { + if (soundtest.sequencemaxtime > 0) + { + soundtest.privilegedrequest = true; + S_FadeMusic(0, 3000); + soundtest.privilegedrequest = false; + } + + soundtest.sequencefadeout = soundtest.currenttime + 3*TICRATE; + } + } + + if (donext == false) + { + return; + } + + S_UpdateSoundTestDef(false, true, true); +} + +boolean S_PlaysimMusicDisabled(void) +{ + if (soundtest.privilegedrequest) + return false; + + return (soundtest.playing // Ring Racers: Stereo Mode + || demo.rewinding // Don't mess with music while rewinding! + || demo.title); // SRB2Kart: Demos don't interrupt title screen music +} // // S_FindMusicDef @@ -1370,9 +1774,14 @@ struct cursongcredit cursongcredit; // Currently displayed song credit info // musicdef_t *S_FindMusicDef(const char *name, UINT8 *i) { - UINT32 hash = quickncasehash (name, 6); + UINT32 hash; musicdef_t *def; + if (!name || !name[0]) + return NULL; + + hash = quickncasehash (name, 6); + for (def = musicdefstart; def; def = def->next) { for (*i = 0; *i < def->numtracks; (*i)++) @@ -1450,6 +1859,11 @@ ReadMusicDefFields do { if (i >= MAXDEFTRACKS) break; + if (value[0] == '\\') + { + def->basenoloop[i] = true; + value++; + } STRBUFCPY(def->name[i], value); strlwr(def->name[i]); def->hash[i] = quickncasehash (def->name[i], 6); @@ -1635,6 +2049,7 @@ void S_InitMusicDefs(void) UINT16 i; for (i = 0; i < numwadfiles; i++) S_LoadMusicDefs(i); + S_PopulateSoundTestSequence(); } // @@ -1651,7 +2066,7 @@ void S_ShowMusicCredit(void) char *work = NULL; size_t len = 128, worklen; - if (!cv_songcredits.value || demo.rewinding) + if (!cv_songcredits.value || S_PlaysimMusicDisabled()) return; if (!def) // No definitions @@ -1798,8 +2213,7 @@ UINT32 S_GetMusicLoopPoint(void) boolean S_SetMusicPosition(UINT32 position) { - if (demo.rewinding // Don't mess with music while rewinding! - || demo.title) // SRB2Kart: Demos don't interrupt title screen music + if (S_PlaysimMusicDisabled()) return false; return I_SetSongPosition(position); @@ -2005,8 +2419,7 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst) musicstack_t *result; musicstack_t *entry; - if (demo.rewinding // Don't mess with music while rewinding! - || demo.title) // SRB2Kart: Demos don't interrupt title screen music + if (S_PlaysimMusicDisabled()) return false; entry = Z_Calloc(sizeof (*result), PU_MUSIC, NULL); @@ -2243,9 +2656,7 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 &fadeinms }; - if (S_MusicDisabled() - || demo.rewinding // Don't mess with music while rewinding! - || demo.title) // SRB2Kart: Demos don't interrupt title screen music + if (S_MusicDisabled() || S_PlaysimMusicDisabled()) return; strncpy(newmusic, mmusic, 7); @@ -2325,9 +2736,7 @@ void S_ChangeMusicSpecial (const char *mmusic) void S_StopMusic(void) { - if (!I_SongPlaying() - || demo.rewinding // Don't mess with music while rewinding! - || demo.title) // SRB2Kart: Demos don't interrupt title screen music + if (!I_SongPlaying() || S_PlaysimMusicDisabled()) return; if (strcasecmp(music_name, mapmusname) == 0) @@ -2373,6 +2782,9 @@ void S_ResumeAudio(void) if (S_MusicNotInFocus()) return; + if (soundtest.paused == true) + return; + if (I_SongPlaying() && I_SongPaused()) I_ResumeSong(); @@ -2433,8 +2845,7 @@ void S_StopFadingMusic(void) boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms) { - if (demo.rewinding // Don't mess with music while rewinding! - || demo.title) // SRB2Kart: Demos don't interrupt title screen music + if (S_PlaysimMusicDisabled()) return false; if (source_volume < 0) @@ -2445,8 +2856,7 @@ boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 m boolean S_FadeOutStopMusic(UINT32 ms) { - if (demo.rewinding // Don't mess with music while rewinding! - || demo.title) // SRB2Kart: Demos don't interrupt title screen music + if (S_PlaysimMusicDisabled()) return false; return I_FadeSong(0, ms, &S_StopMusic); @@ -2628,10 +3038,7 @@ static void Command_RestartAudio_f(void) S_StartSound(NULL, sfx_strpst); - if (Playing()) // Gotta make sure the player is in a level - P_RestoreMusic(&players[consoleplayer]); - else - S_ChangeMusicInternal("titles", looptitle); + S_AttemptToRestoreMusic(); } static void Command_PlaySound(void) @@ -2821,18 +3228,7 @@ void GameDigiMusic_OnChange(void) I_StartupSound(); // will return early if initialised I_InitMusic(); - if (Playing()) - { - P_RestoreMusic(&players[consoleplayer]); - } - else if (gamestate == GS_TITLESCREEN) - { - S_ChangeMusicInternal("_title", looptitle); - } - else - { - M_PlayMenuJam(); - } + S_AttemptToRestoreMusic(); } else { diff --git a/src/s_sound.h b/src/s_sound.h index dcda1751d..da0ca75fc 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -176,11 +176,19 @@ boolean S_SpeedMusic(float speed); #define MAXDEFTRACKS 3 +struct soundtestsequence_t +{ + UINT8 id; + UINT16 map; + musicdef_t *next; +}; + // Music credits struct musicdef_t { char name[MAXDEFTRACKS][7]; UINT32 hash[MAXDEFTRACKS]; + boolean basenoloop[MAXDEFTRACKS]; UINT8 numtracks; char *title; char *author; @@ -189,6 +197,7 @@ struct musicdef_t int volume; int debug_volume; musicdef_t *next; + soundtestsequence_t sequence; }; extern struct cursongcredit @@ -201,6 +210,36 @@ extern struct cursongcredit fixed_t old_x; } cursongcredit; +extern struct soundtest +{ + boolean playing; // Music is playing? + boolean paused; // System paused? + boolean justopened; // Menu visual assist + boolean privilegedrequest; // Overrides S_PlaysimMusicDisabled w/o changing every function signature + + INT32 menutick; // Menu visual timer + + musicdef_t *current; // Current selected music definition + SINT8 currenttrack; // Current selected music track for definition + UINT32 currenttime; // Current music playing time + + soundtestsequence_t sequence; // Sequence head + + boolean autosequence; // In auto sequence mode? + boolean dosequencefadeout; // Fade out when reaching the end? + UINT32 sequencemaxtime; // Maximum playing time for current music + UINT32 sequencefadeout; // auto sequence fadeout +} soundtest; + +void S_PopulateSoundTestSequence(void); +void S_UpdateSoundTestDef(boolean reverse, boolean dotracks, boolean skipnull); +void S_SoundTestPlay(void); +void S_SoundTestStop(void); +void S_SoundTestTogglePause(void); +void S_TickSoundTest(void); + +boolean S_PlaysimMusicDisabled(void); + extern musicdef_t *musicdefstart; void S_LoadMusicDefs(UINT16 wadnum); diff --git a/src/typedef.h b/src/typedef.h index 0615e7034..04298277c 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -388,6 +388,7 @@ TYPEDEF (listener_t); TYPEDEF (channel_t); TYPEDEF (caption_t); TYPEDEF (musicdef_t); +TYPEDEF (soundtestsequence_t); TYPEDEF (musicstack_t); // screen.h