mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
additional music checks
This adds several fixes to make the event and menu music more robust: 1. The game will now run with zero soundtracks. All accesses into a potentially empty vector should now have checks. 2. Soundtracks and menu music are now checked for validity before being played (not just when importing a FSM mission). 3. The parsing validity checks and the in-game event music now check for skippable patterns using the same function. 4. Zero measures and zero samples-per-measure now cause the game to skip a pattern. Negative values now trigger a warning. 5. Omitting some or all of the `$Name:` lines for a soundtrack will not cause an assert. Fixes #5576. Follow-up to #5572.
This commit is contained in:
1 parent
9d28ba568c
commit
6a550a6701
6 files changed
+75
-50
No files matched your search
+47
-24
@@ -257,6 +257,19 @@ SCP_vector<menu_music> Spooled_music;
|
||||
int Mission_music[NUM_SCORES];
|
||||
|
||||
|
||||
bool event_music_pattern_is_skippable(const SOUNDTRACK_PATTERN_INFO &pattern)
|
||||
{
|
||||
// check for blank or "none"
|
||||
if (pattern.fname[0] == '\0' || !strnicmp(pattern.fname, NOX("none.wav"), 4))
|
||||
return true;
|
||||
|
||||
// no content means this pattern isn't intended to play
|
||||
if (pattern.num_measures == 0 || pattern.samples_per_measure == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// event_music_init()
|
||||
//
|
||||
@@ -294,7 +307,7 @@ void event_music_init()
|
||||
// now that we've parsed everything, check the validity
|
||||
for (auto &soundtrack : Soundtracks)
|
||||
{
|
||||
bool all_patterns_found = true;
|
||||
bool all_patterns_valid = true;
|
||||
|
||||
// Goober5000 - set the valid flag according to whether we can load all our patterns
|
||||
// (since someone may be running an enhanced music.tbl without warble_fs1 installed)
|
||||
@@ -302,10 +315,18 @@ void event_music_init()
|
||||
{
|
||||
auto filename = soundtrack.patterns[i].fname;
|
||||
|
||||
// check for "none"
|
||||
if (!strlen(filename) || !strnicmp(filename, "none", 4))
|
||||
// some patterns aren't played for various legitimate reasons
|
||||
if (event_music_pattern_is_skippable(soundtrack.patterns[i]))
|
||||
continue;
|
||||
|
||||
// check for negative numbers (zero is allowed)
|
||||
if (soundtrack.patterns[i].num_measures < 0 || soundtrack.patterns[i].samples_per_measure < 0)
|
||||
{
|
||||
Warning(LOCATION, "Soundtrack file %s has a negative 'num_measures' or 'samples_per_measure'; this is not allowed", soundtrack.patterns[i].fname);
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// check for file with exact extension
|
||||
// (since event music specifies samples and measures, the audio format is important; so we don't want to assume any format will work)
|
||||
if (!cf_exists_full(filename, CF_TYPE_MUSIC))
|
||||
@@ -318,12 +339,12 @@ void event_music_init()
|
||||
#endif
|
||||
|
||||
Warning(LOCATION, "One or more files in '%s' could not be loaded. The soundtrack will not be used.", soundtrack.name);
|
||||
all_patterns_found = false;
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_patterns_found)
|
||||
if (all_patterns_valid)
|
||||
soundtrack.flags |= EMF_VALID;
|
||||
}
|
||||
|
||||
@@ -581,14 +602,11 @@ void event_music_level_start(int force_soundtrack)
|
||||
if (force_soundtrack != -1)
|
||||
Current_soundtrack_num = force_soundtrack;
|
||||
|
||||
// Check that soundtrack index is in range, except that < 0 means no soundtrack
|
||||
if (Current_soundtrack_num < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < (int)Soundtracks.size());
|
||||
|
||||
if (Current_soundtrack_num < 0 || Current_soundtrack_num > (int)Soundtracks.size())
|
||||
Assert(Current_soundtrack_num < (int)Soundtracks.size());
|
||||
if (Current_soundtrack_num >= (int)Soundtracks.size())
|
||||
return;
|
||||
|
||||
strack = &Soundtracks[Current_soundtrack_num];
|
||||
@@ -601,7 +619,7 @@ void event_music_level_start(int force_soundtrack)
|
||||
// tracks because their patterns weren't -1
|
||||
for (i = 0; i < MAX_PATTERNS; i++)
|
||||
{
|
||||
if (!strnicmp(strack->patterns[i].fname, NOX("none.wav"), 4))
|
||||
if (event_music_pattern_is_skippable(strack->patterns[i]))
|
||||
{
|
||||
Patterns[i].handle = -1;
|
||||
continue;
|
||||
@@ -1203,9 +1221,6 @@ void parse_soundtrack()
|
||||
int i, strack_idx = -1;
|
||||
bool nocreate = false;
|
||||
|
||||
//Start parsing soundtrack
|
||||
//required_string("#Soundtrack Start");
|
||||
|
||||
//Get the name, and do we have this track already?
|
||||
required_string("$SoundTrack Name:");
|
||||
stuff_string(namebuf, F_NAME, NAME_LENGTH);
|
||||
@@ -1599,7 +1614,7 @@ int hostile_ships_present()
|
||||
// NOTE: callers to this function are advised to allocate a 256 byte buffer
|
||||
void event_music_get_info(char *outbuf)
|
||||
{
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_soundtrack_num < 0 || Current_pattern < 0 ) {
|
||||
strcpy(outbuf,XSTR( "Event music is not playing", 213));
|
||||
}
|
||||
else {
|
||||
@@ -1618,7 +1633,7 @@ int event_music_next_soundtrack(int delta)
|
||||
{
|
||||
int new_soundtrack;
|
||||
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Soundtracks.empty() ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1662,7 +1677,7 @@ void event_sexp_change_soundtrack(const char *name)
|
||||
// NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
|
||||
void event_music_get_soundtrack_name(char *outbuf)
|
||||
{
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_soundtrack_num < 0 ) {
|
||||
strcpy(outbuf, XSTR( "Event music is not playing", 213));
|
||||
}
|
||||
else {
|
||||
@@ -1673,11 +1688,15 @@ void event_music_get_soundtrack_name(char *outbuf)
|
||||
// set the current soundtrack based on name
|
||||
void event_music_set_soundtrack(const char *name)
|
||||
{
|
||||
Current_soundtrack_num = event_music_get_soundtrack_index(name);
|
||||
int index = event_music_get_soundtrack_index(name);
|
||||
|
||||
if ( Current_soundtrack_num == -1 ) {
|
||||
if (index >= 0 && Soundtracks[index].flags & EMF_VALID)
|
||||
Current_soundtrack_num = index;
|
||||
else
|
||||
Current_soundtrack_num = -1;
|
||||
|
||||
if (Current_soundtrack_num == -1)
|
||||
mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
|
||||
}
|
||||
}
|
||||
|
||||
int event_music_get_soundtrack_index(const char *name)
|
||||
@@ -1694,7 +1713,7 @@ int event_music_get_soundtrack_index(const char *name)
|
||||
|
||||
int event_music_get_spooled_music_index(const char *name)
|
||||
{
|
||||
// find the correct index for the event music
|
||||
// find the correct index for the spooled music
|
||||
for ( int i = 0; i < (int)Spooled_music.size(); i++ ) {
|
||||
if ( !stricmp(name, Spooled_music[i].name) ) {
|
||||
return i;
|
||||
@@ -1714,8 +1733,12 @@ void event_music_set_score(int score_index, const char *name)
|
||||
{
|
||||
Assert(score_index < NUM_SCORES);
|
||||
|
||||
// find the correct index for the event music
|
||||
Mission_music[score_index] = event_music_get_spooled_music_index(name);
|
||||
int index = event_music_get_spooled_music_index(name);
|
||||
|
||||
if (index >= 0 && Spooled_music[index].flags & SMF_VALID)
|
||||
Mission_music[score_index] = index;
|
||||
else
|
||||
Mission_music[score_index] = -1;
|
||||
}
|
||||
|
||||
// reset what sort of music is to be used for this mission
|
||||
|
||||
@@ -74,15 +74,16 @@ extern SCP_vector<menu_music> Spooled_music;
|
||||
|
||||
|
||||
// event music soundtrack storage
|
||||
typedef struct tagSOUNDTRACK_PATTERN_INFO {
|
||||
char fname[MAX_FILENAME_LEN];
|
||||
float num_measures;
|
||||
int samples_per_measure;
|
||||
} SOUNDTRACK_PATTERN_INFO;
|
||||
typedef struct tagSOUNDTRACK_INFO {
|
||||
int flags;
|
||||
int num_patterns;
|
||||
char name[NAME_LENGTH];
|
||||
struct {
|
||||
char fname[MAX_FILENAME_LEN];
|
||||
float num_measures;
|
||||
int samples_per_measure;
|
||||
} patterns[MAX_PATTERNS];
|
||||
SOUNDTRACK_PATTERN_INFO patterns[MAX_PATTERNS];
|
||||
} SOUNDTRACK_INFO;
|
||||
|
||||
// Goober5000 - event music flags
|
||||
|
||||
@@ -1126,7 +1126,7 @@ void parse_briefing_info(mission * /*pm*/)
|
||||
*/
|
||||
void parse_music(mission *pm, int flags)
|
||||
{
|
||||
int index, num;
|
||||
int index;
|
||||
char *ch;
|
||||
char temp[NAME_LENGTH];
|
||||
|
||||
@@ -1233,9 +1233,12 @@ void parse_music(mission *pm, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
// last resort: pick a random track out of the 7 FS2 soundtracks
|
||||
num = std::max((int)Soundtracks.size(), 7);
|
||||
strcpy_s(pm->event_music_name, Soundtracks[Random::next(num)].name);
|
||||
if (!Soundtracks.empty())
|
||||
{
|
||||
// last resort: pick a random track out of the 7 FS2 soundtracks
|
||||
int num = std::max((int)Soundtracks.size(), 7);
|
||||
strcpy_s(pm->event_music_name, Soundtracks[Random::next(num)].name);
|
||||
}
|
||||
|
||||
|
||||
done_event_music:
|
||||
@@ -1260,9 +1263,12 @@ done_event_music:
|
||||
if (event_music_get_spooled_music_index(pm->briefing_music_name) >= 0)
|
||||
goto done_briefing_music;
|
||||
|
||||
// last resort: pick a random track out of the first 7 FS2 briefings (the regular ones)...
|
||||
num = std::max((int)Spooled_music.size(), 7);
|
||||
strcpy_s(pm->briefing_music_name, Spooled_music[Random::next(num)].name);
|
||||
if (!Spooled_music.empty())
|
||||
{
|
||||
// last resort: pick a random track out of the first 7 FS2 briefings (the regular ones)...
|
||||
int num = std::max((int)Spooled_music.size(), 7);
|
||||
strcpy_s(pm->briefing_music_name, Spooled_music[Random::next(num)].name);
|
||||
}
|
||||
|
||||
|
||||
done_briefing_music:
|
||||
|
||||
@@ -315,10 +315,10 @@ void set_active_ui(UI_WINDOW *ui_window)
|
||||
Active_ui_window = ui_window;
|
||||
}
|
||||
|
||||
SCP_string common_music_get_filename(int score_index)
|
||||
const char *common_music_get_filename(int score_index)
|
||||
{
|
||||
if (Cmdline_freespace_no_music) {
|
||||
return SCP_string();
|
||||
return "";
|
||||
}
|
||||
|
||||
Assertion(score_index >= 0 && score_index < NUM_SCORES, "Invalid score index %d.", score_index);
|
||||
@@ -330,7 +330,7 @@ SCP_string common_music_get_filename(int score_index)
|
||||
"No briefing music is selected, so play first briefing track: %s\n",
|
||||
Spooled_music[Mission_music[score_index]].name));
|
||||
} else {
|
||||
return SCP_string();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,11 +341,11 @@ void common_music_init(int score_index)
|
||||
{
|
||||
const auto file_name = common_music_get_filename(score_index);
|
||||
|
||||
if (file_name.empty()) {
|
||||
if (file_name[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
briefing_load_music(file_name.c_str());
|
||||
briefing_load_music(file_name);
|
||||
// Use this id to trigger the start of music playing on the briefing screen
|
||||
Briefing_music_begin_timestamp = ui_timestamp(BRIEFING_MUSIC_DELAY);
|
||||
}
|
||||
|
||||
@@ -106,15 +106,10 @@ void unload_wing_icons();
|
||||
void common_flash_button_init();
|
||||
int common_flash_bright();
|
||||
|
||||
// functions for the multiplayer chat window
|
||||
void common_render_chat_window();
|
||||
void multi_chat_scroll_up();
|
||||
void multi_chat_scroll_down();
|
||||
|
||||
void set_active_ui(UI_WINDOW *ui_window);
|
||||
|
||||
// music functions exported for multiplayer team selection screen to start briefing music
|
||||
SCP_string common_music_get_filename(int score_index);
|
||||
const char *common_music_get_filename(int score_index);
|
||||
void common_music_init( int score_index );
|
||||
void common_music_do();
|
||||
void common_music_close();
|
||||
|
||||
@@ -570,7 +570,7 @@ ADE_FUNC(getBriefingMusicName,
|
||||
"string",
|
||||
"The file name or empty if no music")
|
||||
{
|
||||
return ade_set_args(L, "s", common_music_get_filename(SCORE_BRIEFING).c_str());
|
||||
return ade_set_args(L, "s", common_music_get_filename(SCORE_BRIEFING));
|
||||
}
|
||||
|
||||
ADE_FUNC(runBriefingStageHook,
|
||||
@@ -956,7 +956,7 @@ ADE_FUNC(getDebriefingMusicName,
|
||||
"string",
|
||||
"The file name or empty if no music")
|
||||
{
|
||||
return ade_set_args(L, "s", common_music_get_filename(debrief_select_music()).c_str());
|
||||
return ade_set_args(L, "s", common_music_get_filename(debrief_select_music()));
|
||||
}
|
||||
|
||||
ADE_FUNC(getDebriefing, l_UserInterface_Debrief, nullptr, "Get the debriefing", "debriefing", "The debriefing data")
|
||||
@@ -1228,7 +1228,7 @@ ADE_FUNC(getFictionMusicName, l_UserInterface_FictionViewer, nullptr,
|
||||
"string",
|
||||
"The file name or empty if no music")
|
||||
{
|
||||
return ade_set_args(L, "s", common_music_get_filename(SCORE_FICTION_VIEWER).c_str());
|
||||
return ade_set_args(L, "s", common_music_get_filename(SCORE_FICTION_VIEWER));
|
||||
}
|
||||
|
||||
//**********SUBLIBRARY: UserInterface/ShipWepSelect
|
||||
|
||||
Reference in new issue
Block a user