Another update. This addresses some misplaced warnings, fixes a bunch of crashes, and adds flags instead of boolean parameters for the sound functions. Testing is required!
Index: code/gamesnd/gamesnd.cpp
===================================================================
--- code/gamesnd/gamesnd.cpp (revision 8068)
+++ code/gamesnd/gamesnd.cpp (working copy)
@@ -52,6 +52,30 @@
return -1;
}
+int gamesnd_get_by_iface_name(char* name)
+{
+ Assert( Snds_iface.size() <= INT_MAX );
+ Assert( Snds_iface.size() == Snds_iface_handle.size() );
+ int i = 0;
+ for(SCP_vector<game_snd>::iterator snd = Snds_iface.begin(); snd != Snds_iface.end(); ++snd)
+ {
+ char *p = strrchr( snd->filename, '.' );
+ if(p == NULL)
+ {
+ if(!stricmp(snd->filename, name))
+ {
+ return i;
+ }
+ }
+ else if(!strnicmp(snd->filename, name, p-snd->filename))
+ {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+}
+
int gamesnd_get_by_tbl_index(int index)
{
//if we get passed -1, don't bother trying to look it up.
@@ -71,6 +95,9 @@
int gamesnd_get_by_iface_tbl_index(int index)
{
+ //if we get passed -1, don't bother trying to look it up.
+ if (index == -1)
+ return -1;
Assert( Snds_iface.size() <= INT_MAX );
Assert( Snds_iface.size() == Snds_iface_handle.size() );
int i = 0;
@@ -85,41 +112,128 @@
}
/**
- * Parse a sound
- *
+ * Helper function for parse_sound and parse_sound_list. Do not use directly.
+ *
* @param tag Tag
* @param idx_dest Sound index destination
* @param object_name Object name being parsed
+ * @param buf Buffer holding string to be parsed
+ * @param flags See the parse_sound_flags enum
*
- * This also means you shouldn't use optional_string or required_string,
- * just make sure the destination sound index can handle -1 if things
- * don't work out.
*/
-void parse_sound(char* tag, int *idx_dest, char* object_name)
+void parse_sound_core(char* tag, int *idx_dest, char* object_name, char* buf, parse_sound_flags flags)
{
- char buf[MAX_FILENAME_LEN];
int idx;
+ if(flags & PARSE_SOUND_INTERFACE_SOUND)
+ idx = gamesnd_get_by_iface_name(buf);
+ else
+ idx = gamesnd_get_by_name(buf);
+
+ if(idx != -1)
+ {
+ (*idx_dest) = idx;
+ }
+ else
+ {
+ if(flags & PARSE_SOUND_INTERFACE_SOUND)
+ idx = gamesnd_get_by_iface_tbl_index(atoi(buf));
+ else
+ idx = gamesnd_get_by_tbl_index(atoi(buf));
+
+ if (idx != -1)
+ (*idx_dest) = idx;
+ }
+
+ int size_to_check = 0;
+
+ if(flags & PARSE_SOUND_INTERFACE_SOUND)
+ {
+ size_to_check = Snds_iface.size();
+ Assert( Snds_iface.size() == Snds_iface_handle.size() );
+ }
+ else
+ {
+ size_to_check = Snds.size();
+ }
+
+ Assert( size_to_check <= INT_MAX );
+
+ //Ensure sound is in range
+ if((*idx_dest) < -1 || (*idx_dest) >= (int)size_to_check)
+ {
+ (*idx_dest) = -1;
+ Warning(LOCATION, "%s sound index out of range on '%s'. Must be between 0 and %d. Forcing to -1 (Nonexistent sound).\n", tag, object_name, size_to_check);
+ }
+}
+
+/**
+ * Parse a sound. When using this function for a table entry,
+ * required_string and optional_string aren't needed, as this function deals with
+ * that as its tag parameter, just make sure that the destination sound index can
+ * handle -1 if things don't work out.
+ *
+ * @param tag Tag
+ * @param idx_dest Sound index destination
+ * @param object_name Object name being parsed
+ * @param flags See the parse_sound_flags enum
+ *
+ */
+void parse_sound(char* tag, int *idx_dest, char* object_name, parse_sound_flags flags)
+{
if(optional_string(tag))
{
+ char buf[MAX_FILENAME_LEN];
stuff_string(buf, F_NAME, MAX_FILENAME_LEN);
- idx = gamesnd_get_by_name(buf);
- if(idx != -1)
- (*idx_dest) = idx;
- else
+
+ parse_sound_core(tag, idx_dest, object_name, buf, flags);
+ }
+}
+
+/**
+ * CommanderDJ - Parse a list of sounds. When using this function for a table entry,
+ * required_string and optional_string aren't needed, as this function deals with
+ * that as its tag parameter, just make sure that the destination sound index(es) can
+ * handle -1 if things don't work out.
+ *
+ * @param destination Vector where sound indexes are to be stored
+ * @param tag Tag
+ * @param object_name Name of object being parsed
+ * @param flags See the parse_sound_flags enum
+ *
+ */
+void parse_sound_list(char* tag, SCP_vector<int>& destination, char* object_name, parse_sound_flags flags)
+{
+ if(optional_string(tag))
+ {
+ int check=0;
+
+ //if we're using the old format, parse the first entry separately
+ if(!(flags & PARSE_SOUND_SCP_SOUND_LIST))
{
- idx = gamesnd_get_by_tbl_index(atoi(buf));
- if (idx != -1)
- (*idx_dest) = idx;
+ stuff_int(&check);
}
- Assert( Snds.size() <= INT_MAX );
- //Ensure sound is in range
- if((*idx_dest) < -1 || (*idx_dest) >= (int)Snds.size())
+ //now read the rest of the entries on the line
+ for(int i=0;!check_for_eoln();i++)
{
- (*idx_dest) = -1;
- Warning(LOCATION, "%s sound index out of range on '%s'. Must be between 0 and %d. Forcing to -1 (Nonexistant sound).\n", tag, object_name, Snds.size());
+ char buf[MAX_FILENAME_LEN];
+ stuff_string_white(buf, MAX_FILENAME_LEN);
+
+ //we do this conditionally to avoid adding needless entries when reparsing
+ if(destination.size() <= (unsigned)i)
+ {
+ destination.push_back(-1);
+ }
+
+ parse_sound_core(tag, &destination.at(i), object_name, buf, flags);
}
+
+ //if we're using the old format, double check the size)
+ if(!(flags & PARSE_SOUND_SCP_SOUND_LIST) && (destination.size() != (unsigned)check))
+ {
+ mprintf(("%s in '%s' has %i entries. This does not match entered size of %i.", tag, object_name, destination.size(), check));
+ }
}
}
Index: code/gamesnd/gamesnd.h
===================================================================
--- code/gamesnd/gamesnd.h (revision 8068)
+++ code/gamesnd/gamesnd.h (working copy)
@@ -28,13 +28,25 @@
void gamesnd_play_iface(int n);
void gamesnd_play_error_beep();
int gamesnd_get_by_name(char* name);
+int gamesnd_get_by_iface_name(char* name);
int gamesnd_get_by_tbl_index(int index);
int gamesnd_get_by_iface_tbl_index(int index);
+//flags for parse_sound and parse_sound_list
+enum parse_sound_flags
+{
+ PARSE_SOUND_GENERAL_SOUND = 0, //!< search for sound in the general table in sound.tbl
+ PARSE_SOUND_INTERFACE_SOUND = (1 << 0), //!< Search for sound in the interface part of sounds.tbl
+ PARSE_SOUND_SCP_SOUND_LIST = (1 << 1), //!< Parse the list of sounds SCP style (just indexes and/or files names, no count first)
+ PARSE_SOUND_MAX
+};
+
//This should handle NO_SOUND just fine since it doesn't directly access lowlevel code
//Does all parsing for a sound
-void parse_sound(char* tag, int *idx_dest, char* object_name);
+void parse_sound(char* tag, int* idx_dest, char* object_name, parse_sound_flags = PARSE_SOUND_GENERAL_SOUND);
+void parse_sound_list(char* tag, SCP_vector<int>& destination, char* object_name, parse_sound_flags = PARSE_SOUND_GENERAL_SOUND);
+
// this is a callback, so it needs to be a real function
void common_play_highlight_sound();
Index: code/menuui/mainhallmenu.cpp
===================================================================
--- code/menuui/mainhallmenu.cpp (revision 8068)
+++ code/menuui/mainhallmenu.cpp (working copy)
@@ -107,8 +107,8 @@
// panning values for each of the misc anims
float misc_anim_sound_pan[MAX_MISC_ANIMATIONS];
- // [N][0] == # of sounds, [N][1-9] sound index
- int misc_anim_special_sounds[MAX_MISC_ANIMATIONS][10];
+ //sounds for each of the misc anims
+ SCP_vector<SCP_vector<int>> misc_anim_special_sounds;
// [N][0] == # of triggers, [N][1-9] >= frame num
int misc_anim_special_trigger[MAX_MISC_ANIMATIONS][10];
@@ -133,7 +133,7 @@
int door_anim_coords[MAX_DOOR_ANIMATIONS][4];
// sounds for each region (open/close)
- int door_sounds[MAX_DOOR_ANIMATIONS][2];
+ SCP_vector<SCP_vector<int>> door_sounds;
// pan values for the door sounds
float door_sound_pan[MAX_DOOR_ANIMATIONS];
@@ -1182,7 +1182,7 @@
}
// animation is not paused
else {
- for (s_idx = Main_hall->misc_anim_special_sounds[idx][0]; s_idx > 0; s_idx--) {
+ for (s_idx = 0; (unsigned)s_idx < Main_hall->misc_anim_special_sounds.at(idx).size(); s_idx++) {
// if we've passed the trigger point, then play the sound and break out of the loop
if ((Main_hall_misc_anim[idx].current_frame >= Main_hall->misc_anim_special_trigger[idx][s_idx]) && !Main_hall->misc_anim_sound_flag[idx][s_idx]) {
Main_hall->misc_anim_sound_flag[idx][s_idx] = 1;
@@ -1195,7 +1195,7 @@
}
// play the sound
- Main_hall->misc_anim_sound_handles[idx][s_idx] = snd_play(&Snds_iface[Main_hall->misc_anim_special_sounds[idx][s_idx]],Main_hall->misc_anim_sound_pan[idx]);
+ Main_hall->misc_anim_sound_handles[idx][s_idx] = snd_play(&Snds_iface[Main_hall->misc_anim_special_sounds.at(idx).at(s_idx)],Main_hall->misc_anim_sound_pan[idx]);
break;
}
}
@@ -1308,7 +1308,7 @@
if (Main_hall_door_sound_handles[region] != -1) {
snd_stop(Main_hall_door_sound_handles[region]);
}
- Main_hall_door_sound_handles[region] = snd_play(&Snds_iface[Main_hall->door_sounds[region][1]], Main_hall->door_sound_pan[region]);
+ Main_hall_door_sound_handles[region] = snd_play(&Snds_iface[Main_hall->door_sounds.at(region).at(1)], Main_hall->door_sound_pan[region]);
//TODO: track current frame
snd_set_pos(Main_hall_door_sound_handles[region], &Snds_iface[SND_MAIN_HALL_DOOR_CLOSE],
@@ -1334,7 +1334,7 @@
if(Main_hall_door_sound_handles[region] != -1){
snd_stop(Main_hall_door_sound_handles[region]);
}
- Main_hall_door_sound_handles[region] = snd_play(&Snds_iface[Main_hall->door_sounds[region][0]],Main_hall->door_sound_pan[region]);
+ Main_hall_door_sound_handles[region] = snd_play(&Snds_iface[Main_hall->door_sounds.at(region).at(0)],Main_hall->door_sound_pan[region]);
// start the sound playing at the right spot relative to the completion of the animation
if( (Main_hall_door_anim[region].num_frames > 0) && (Main_hall_door_anim[region].current_frame != -1) ) {
@@ -1660,8 +1660,7 @@
}
for(idx=0; idx<m->num_random_intercom_sounds; idx++){
// intercom sound id
- required_string("+Intercom sound:");
- stuff_int(&m->intercom_sounds[idx]);
+ parse_sound("+Intercom sound:", &m->intercom_sounds[idx], "+Intercom sound:", PARSE_SOUND_INTERFACE_SOUND);
}
for(idx=0; idx<m->num_random_intercom_sounds; idx++){
// intercom pan
@@ -1714,11 +1713,9 @@
}
for(idx=0; idx<m->num_misc_animations; idx++){
// anim sound id
- required_string("+Misc anim sounds:");
- stuff_int(&m->misc_anim_special_sounds[idx][0]);
- for(s_idx=0; s_idx<m->misc_anim_special_sounds[idx][0]; s_idx++){
- stuff_int(&m->misc_anim_special_sounds[idx][s_idx + 1]);
- }
+ SCP_vector<int> temp; //this is a short term hack and will be properly fixed when main_hall_defines is vectorised
+ m->misc_anim_special_sounds.push_back(temp);
+ parse_sound_list("+Misc anim sounds:", m->misc_anim_special_sounds.at(idx), "+Misc anim sounds:", PARSE_SOUND_INTERFACE_SOUND);
}
for(idx=0; idx<m->num_misc_animations; idx++){
// anim sound triggers
@@ -1761,9 +1758,9 @@
}
for(idx=0; idx<m->num_door_animations; idx++){
// door open and close sounds
- required_string("+Door sounds:");
- stuff_int(&m->door_sounds[idx][0]);
- stuff_int(&m->door_sounds[idx][1]);
+ SCP_vector<int> temp; //this is a short term hack and will be properly fixed when main_hall_defines is vectorised
+ m->door_sounds.push_back(temp);
+ parse_sound_list("+Door sounds:", m->door_sounds.at(idx), "+Door sounds:", (parse_sound_flags)(PARSE_SOUND_INTERFACE_SOUND | PARSE_SOUND_SCP_SOUND_LIST));
}
for(idx=0; idx<m->num_door_animations; idx++){
// door pan value
@@ -1790,10 +1787,10 @@
if(Vasudan_funny){
int hall = main_hall_id();
- Main_hall_defines[GR_640][hall].door_sounds[OPTIONS_REGION][0] = SND_VASUDAN_BUP;
- Main_hall_defines[GR_640][hall].door_sounds[OPTIONS_REGION][1] = SND_VASUDAN_BUP;
- Main_hall_defines[GR_1024][hall].door_sounds[OPTIONS_REGION][0] = SND_VASUDAN_BUP;
- Main_hall_defines[GR_1024][hall].door_sounds[OPTIONS_REGION][1] = SND_VASUDAN_BUP;
+ Main_hall_defines[GR_640][hall].door_sounds.at(OPTIONS_REGION).at(0) = SND_VASUDAN_BUP;
+ Main_hall_defines[GR_640][hall].door_sounds.at(OPTIONS_REGION).at(1) = SND_VASUDAN_BUP;
+ Main_hall_defines[GR_1024][hall].door_sounds.at(OPTIONS_REGION).at(0) = SND_VASUDAN_BUP;
+ Main_hall_defines[GR_1024][hall].door_sounds.at(OPTIONS_REGION).at(1) = SND_VASUDAN_BUP;
// set head anim. hehe
strcpy_s(Main_hall_defines[GR_640][hall].door_anim_name[OPTIONS_REGION], "vhallheads");
Index: code/parse/parselo.cpp
===================================================================
--- code/parse/parselo.cpp (revision 8068)
+++ code/parse/parselo.cpp (working copy)
@@ -430,6 +430,15 @@
return 0;
}
+int check_for_eoln()
+{
+ ignore_gray_space();
+
+ if(*Mp == EOLN)
+ return 1;
+ else
+ return 0;
+}
// similar to optional_string, but just checks if next token is a match.
// It doesn't advance Mp except to skip past white space.
//
Index: code/parse/parselo.h
===================================================================
--- code/parse/parselo.h (revision 8068)
+++ code/parse/parselo.h (working copy)
@@ -155,6 +155,7 @@
extern int check_for_string(char *pstr);
extern int check_for_string_raw(char *pstr);
extern int check_for_eof();
+extern int check_for_eoln();
// from aicode.cpp
extern void parse_float_list(float *plist, int size);
Apply this patch straight to trunk.
EDIT: This patch has been tested by both mjn.mixael and myself with different mainhall.tbls and everything now works correctly.