/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : ww3d2 * * * * $Archive:: /Commando/Code/ww3d2/animatedsoundmgr.cpp $* * * * Author:: Patrick Smith * * * * $Modtime:: 12/13/01 6:05p $* * * * $Revision:: 2 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "animatedsoundmgr.h" #include "ini.h" #include "inisup.h" #include "ffactory.h" #include "wwfile.h" #include #include "definition.h" #include "definitionmgr.h" #include "definitionclassids.h" #include "wwaudio.h" #include "audiblesound.h" #include "htree.h" #include "hanim.h" ////////////////////////////////////////////////////////////////////// // Static member initialization ////////////////////////////////////////////////////////////////////// HashTemplateClass AnimatedSoundMgrClass::AnimationNameHash; DynamicVectorClass AnimatedSoundMgrClass::AnimSoundLists; ////////////////////////////////////////////////////////////////////// // Local inlines ////////////////////////////////////////////////////////////////////// static WWINLINE INIClass * Get_INI (const char *filename) { INIClass *ini = NULL; // // Get the file from our filefactory // FileClass *file = _TheFileFactory->Get_File (filename); if (file) { // // Create the INI object // if (file->Is_Available ()) { ini = new INIClass (*file); } // // Close the file // _TheFileFactory->Return_File (file); } return ini; } static int Build_List_From_String ( const char * buffer, const char * delimiter, StringClass ** string_list ) { int count = 0; WWASSERT (buffer != NULL); WWASSERT (delimiter != NULL); WWASSERT (string_list != NULL); if ((buffer != NULL) && (delimiter != NULL) && (string_list != NULL)) { int delim_len = ::strlen (delimiter); // // Determine how many entries there will be in the list // for (const char *entry = buffer; (entry != NULL) && (entry[1] != 0); entry = ::strstr (entry, delimiter)) { // // Move past the current delimiter (if necessary) // if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) { entry += delim_len; } // Increment the count of entries count ++; } if (count > 0) { // // Allocate enough StringClass objects to hold all the strings in the list // (*string_list) = new StringClass[count]; // // Parse the string and pull out its entries. // count = 0; for (entry = buffer; (entry != NULL) && (entry[1] != 0); entry = ::strstr (entry, delimiter)) { // // Move past the current delimiter (if necessary) // if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) { entry += delim_len; } // // Copy this entry into its own string // StringClass entry_string = entry; char *delim_start = ::strstr (entry_string, delimiter); if (delim_start != NULL) { delim_start[0] = 0; } // // Add this entry to our list // if ((entry_string.Get_Length () > 0) || (count == 0)) { (*string_list)[count++] = entry_string; } } } else if (delim_len > 0) { count = 1; (*string_list) = new StringClass[count]; (*string_list)[0] = buffer; } } // // Return the number of entries in our list // return count; } ////////////////////////////////////////////////////////////////////// // // Initialize // ////////////////////////////////////////////////////////////////////// void AnimatedSoundMgrClass::Initialize (const char *ini_filename) { // // Don't re-initialize... // if (AnimSoundLists.Count () > 0) { return ; } const char *DEFAULT_INI_FILENAME = "w3danimsound.ini"; // // Determine which filename to use // const char *filename_to_use = ini_filename; if (filename_to_use == NULL) { filename_to_use = DEFAULT_INI_FILENAME; } // // Get the INI file which contains the data for this viewer // INIClass *ini_file = ::Get_INI (filename_to_use); if (ini_file != NULL) { // // Loop over all the sections in the INI // List §ion_list = ini_file->Get_Section_List (); for ( INISection *section = section_list.First (); section != NULL && section->Is_Valid (); section = section->Next_Valid ()) { // // Get the animation name from the section name // StringClass animation_name = section->Section; ::strupr (animation_name.Peek_Buffer ()); // // Allocate a sound list // ANIM_SOUND_LIST *sound_list = new ANIM_SOUND_LIST; // // Loop over all the entries in this section // int entry_count = ini_file->Entry_Count (section->Section); for (int entry_index = 0; entry_index < entry_count; entry_index ++) { StringClass value; // // Get the data associated with this entry // const char *entry_name = ini_file->Get_Entry (section->Section, entry_index); ini_file->Get_String (value, section->Section, entry_name); // // Extract the parameters from the section // int len = value.Get_Length (); StringClass definition_name (len + 1, true); int frame_start = 0; // // Separate the parameters into an easy-to-handle data structure // StringClass *param_list = NULL; int param_count = ::Build_List_From_String (value, ",", ¶m_list); if (param_count == 2) { frame_start = ::atoi (param_list[0]); definition_name = param_list[1]; definition_name.Trim (); delete [] param_list; // // Find this sound definition // DefinitionClass *definition = DefinitionMgrClass::Find_Typed_Definition (definition_name, CLASSID_SOUND); if (definition != NULL) { // // Tie the relevant information together and store it // in the list of sounds for this animation // ANIM_SOUND_INFO sound_info; sound_info.Frame = frame_start; sound_info.SoundDefinitionID = definition->Get_ID (); sound_list->Add (sound_info); } } } if (sound_list->Count () != 0) { // // Add this sound list to our hash-table and vector-array // AnimationNameHash.Insert (animation_name, sound_list); AnimSoundLists.Add (sound_list); } else { WWDEBUG_SAY (("AnimatedSoundMgrClass::Initialize -- No sounds added for %d!\n", animation_name.Peek_Buffer ())); delete sound_list; } } delete ini_file; } return ; } ////////////////////////////////////////////////////////////////////// // // Shutdown // ////////////////////////////////////////////////////////////////////// void AnimatedSoundMgrClass::Shutdown (void) { // // Reset the animation name hash // AnimationNameHash.Remove_All (); // // Free each of the sound objects // for (int index = 0; index < AnimSoundLists.Count (); index ++) { delete AnimSoundLists[index]; } AnimSoundLists.Delete_All (); return ; } ////////////////////////////////////////////////////////////////////// // // Does_Animation_Have_Embedded_Sounds // ////////////////////////////////////////////////////////////////////// bool AnimatedSoundMgrClass::Does_Animation_Have_Embedded_Sounds (HAnimClass *anim) { return (Find_Sound_List (anim) != NULL); } ////////////////////////////////////////////////////////////////////// // // Find_Sound_List // ////////////////////////////////////////////////////////////////////// AnimatedSoundMgrClass::ANIM_SOUND_LIST * AnimatedSoundMgrClass::Find_Sound_List (HAnimClass *anim) { // // Build the full name of the animation // StringClass full_name (0, true); full_name = anim->Get_Name (); // // Make the name uppercase // ::strupr (full_name.Peek_Buffer ()); // // Lookup the sound list for this animation // ANIM_SOUND_LIST *retval = AnimationNameHash.Get (full_name); return retval; } ////////////////////////////////////////////////////////////////////// // // Trigger_Sound // ////////////////////////////////////////////////////////////////////// float AnimatedSoundMgrClass::Trigger_Sound ( HAnimClass * anim, float old_frame, float new_frame, const Matrix3D & tm ) { if (anim == NULL) { return old_frame; } float retval = old_frame; // // Lookup the sound list for this animation // ANIM_SOUND_LIST *sound_list = Find_Sound_List (anim); if (sound_list != NULL) { for (int index = 0; index < sound_list->Count (); index ++) { int frame = (*sound_list)[index].Frame; // // Is the animation passing the frame we need? // if (old_frame < frame && new_frame >= frame) { // // Don't trigger the sound if its skipped to far past... // if (WWMath::Fabs (new_frame - old_frame) < 3.0F) { // // Play the sound // int def_id = (*sound_list)[index].SoundDefinitionID; WWAudioClass::Get_Instance ()->Create_Instant_Sound (def_id, tm); WWDEBUG_SAY (("Triggering Sound %d\n", GetTickCount ())); retval = frame; } } } //retval = true; } return retval; }