Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
animatedsoundmgr.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** 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 ***
21 ***********************************************************************************************
22 * *
23 * Project Name : ww3d2 *
24 * *
25 * $Archive:: /Commando/Code/ww3d2/animatedsoundmgr.cpp $*
26 * *
27 * Author:: Patrick Smith *
28 * *
29 * $Modtime:: 12/13/01 6:05p $*
30 * *
31 * $Revision:: 2 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
36//
37// MBL Update for CNC3 INCURSION - 10.23.2002 - Expanded param handling, Added STOP command
38//
39
40#include <string.h> // stricmp()
41#include "animatedsoundmgr.h"
42#include "ini.h"
43#include "inisup.h"
44#include "ffactory.h"
45#include "wwfile.h"
46#include <stdio.h>
47#include "definition.h"
48#include "definitionmgr.h"
49#include "definitionclassids.h"
50#include "wwaudio.h"
51#include "audiblesound.h"
52#include "htree.h"
53#include "hanim.h"
54#include "soundlibrarybridge.h"
55
56#include "WWDebug.h"
57
59// Static member initialization
62DynamicVectorClass<AnimatedSoundMgrClass::ANIM_SOUND_LIST *> AnimatedSoundMgrClass::AnimSoundLists;
63SoundLibraryBridgeClass* AnimatedSoundMgrClass::SoundLibrary = NULL;
64
66// Local inlines
68static WWINLINE INIClass *
69Get_INI (const char *filename)
70{
71 INIClass *ini = NULL;
72
73 //
74 // Get the file from our filefactory
75 //
76 FileClass *file = _TheFileFactory->Get_File (filename);
77 if (file) {
78
79 //
80 // Create the INI object
81 //
82 if (file->Is_Available ()) {
83 ini = new INIClass (*file);
84 }
85
86 //
87 // Close the file
88 //
89 _TheFileFactory->Return_File (file);
90 }
91
92 return ini;
93}
94
95static int
96Build_List_From_String
97(
98 const char * buffer,
99 const char * delimiter,
100 StringClass ** string_list
101)
102{
103 int count = 0;
104
105 WWASSERT (buffer != NULL);
106 WWASSERT (delimiter != NULL);
107 WWASSERT (string_list != NULL);
108 if ((buffer != NULL) &&
109 (delimiter != NULL) &&
110 (string_list != NULL))
111 {
112 int delim_len = ::strlen (delimiter);
113
114 //
115 // Determine how many entries there will be in the list
116 //
117 for (const char *entry = buffer;
118 (entry != NULL) && (entry[1] != 0);
119 entry = ::strstr (entry, delimiter))
120 {
121
122 //
123 // Move past the current delimiter (if necessary)
124 //
125 if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
126 entry += delim_len;
127 }
128
129 // Increment the count of entries
130 count ++;
131 }
132
133 if (count > 0) {
134
135 //
136 // Allocate enough StringClass objects to hold all the strings in the list
137 //
138 (*string_list) = new StringClass[count];
139
140 //
141 // Parse the string and pull out its entries.
142 //
143 count = 0;
144 for (entry = buffer;
145 (entry != NULL) && (entry[1] != 0);
146 entry = ::strstr (entry, delimiter))
147 {
148
149 //
150 // Move past the current delimiter (if necessary)
151 //
152 if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
153 entry += delim_len;
154 }
155
156 //
157 // Copy this entry into its own string
158 //
159 StringClass entry_string = entry;
160 char *delim_start = ::strstr (entry_string, delimiter);
161 if (delim_start != NULL) {
162 delim_start[0] = 0;
163 }
164
165 //
166 // Add this entry to our list
167 //
168 if ((entry_string.Get_Length () > 0) || (count == 0)) {
169 (*string_list)[count++] = entry_string;
170 }
171 }
172
173 } else if (delim_len > 0) {
174 count = 1;
175 (*string_list) = new StringClass[count];
176 (*string_list)[0] = buffer;
177 }
178
179 }
180
181 //
182 // Return the number of entries in our list
183 //
184 return count;
185}
186
187
188static bool
189Is_In_Param_List
190(
191 StringClass *param_list,
192 int param_count,
193 const char *param_to_check
194)
195{
196 //
197 // Check incoming parameters
198 //
199 WWASSERT( param_list != NULL );
200 if ( param_list == NULL )
201 {
202 return( false );
203 }
204 WWASSERT( param_count >= 2 );
205 if ( param_count < 2 )
206 {
207 return( false );
208 }
209 WWASSERT( param_to_check != NULL );
210 if ( param_to_check == NULL )
211 {
212 return( false );
213 }
214
215 //
216 // Note: params 0 & 1 are fixed to frame and name...
217 //
218 for ( int param_index = 2; param_index < param_count; param_index ++ )
219 {
220 {
221 StringClass string = param_list[ param_index ];
222
223 // OutputDebugString( "MBL: Comparing " );
224 // OutputDebugString( string.Peek_Buffer() );
225 // OutputDebugString( " with " );
226 // OutputDebugString( param_to_check );
227 // OutputDebugString( "\n" );
228
229 // if ( stricmp( string.Peek_Buffer(), param_to_check ) == 0 ) // Breaks with whitespaces
230 if ( strstr( string.Peek_Buffer(), param_to_check ) != 0 )
231 {
232 return( true );
233 }
234 }
235 }
236
237 return( false );
238}
239
241//
242// Initialize
243//
245void
246AnimatedSoundMgrClass::Initialize (const char *ini_filename)
247{
248 //
249 // Don't re-initialize...
250 //
251 if (AnimSoundLists.Count () > 0) {
252 return ;
253 }
254
255 const char *DEFAULT_INI_FILENAME = "w3danimsound.ini";
256
257 //
258 // Determine which filename to use
259 //
260 const char *filename_to_use = ini_filename;
261 if (filename_to_use == NULL) {
262 filename_to_use = DEFAULT_INI_FILENAME;
263 }
264
265 //
266 // Get the INI file which contains the data for this viewer
267 //
268 INIClass *ini_file = ::Get_INI (filename_to_use);
269 if (ini_file != NULL) {
270
271 //
272 // Loop over all the sections in the INI
273 //
274 List<INISection *> &section_list = ini_file->Get_Section_List ();
275 for ( INISection *section = section_list.First ();
276 section != NULL && section->Is_Valid ();
277 section = section->Next_Valid ())
278 {
279 //
280 // Get the animation name from the section name
281 //
282 StringClass animation_name = section->Section;
283 ::strupr (animation_name.Peek_Buffer ());
284
285 // OutputDebugString( "MBL Section / animation: " );
286 // OutputDebugString( animation_name.Peek_Buffer() );
287 // OutputDebugString( "\n" );
288
289 //
290 // Allocate a sound list
291 //
292 ANIM_SOUND_LIST *sound_list = new ANIM_SOUND_LIST;
293
294 //
295 // Loop over all the entries in this section
296 //
297 int entry_count = ini_file->Entry_Count (section->Section);
298
299 for (int entry_index = 0; entry_index < entry_count; entry_index ++) {
301
302 //
303 // Get the data associated with this entry
304 //
305 const char *entry_name = ini_file->Get_Entry (section->Section, entry_index);
306
307 // OutputDebugString( " MBL Entry name: " );
308 // OutputDebugString( entry_name );
309 // OutputDebugString( "\n" );
310
311 if (strcmp(entry_name, "BoneName") == 0) {
312 ini_file->Get_String (value, section->Section, entry_name);
313 sound_list->BoneName = value;
314
315 // OutputDebugString( " MBL (BoneName) entry line value: " );
316 // OutputDebugString( value.Peek_Buffer() );
317 // OutputDebugString( "\n" );
318
319 } else {
320 ini_file->Get_String (value, section->Section, entry_name);
321
322 // OutputDebugString( " MBL (not BoneName) entry line value: " );
323 // OutputDebugString( value.Peek_Buffer() );
324 // OutputDebugString( "\n" );
325
326 //
327 // Extract the parameters from the section
328 //
329 int len = value.Get_Length ();
330 StringClass definition_name (len + 1, true);
331 int action_frame = 0;
332
333 //
334 // Separate the parameters into an easy-to-handle data structure
335 //
336 StringClass *param_list = NULL;
337 int param_count = ::Build_List_From_String (value, ",", &param_list);
338
339 // if ((param_count >= 2) && (param_count <= 3))
340 {
341 action_frame = ::atoi (param_list[0]);
342 definition_name = param_list[1];
343 definition_name.Trim ();
344
345 //
346 // Tie the relevant information together and store it
347 // in the list of sounds for this animation
348 //
349 ANIM_SOUND_INFO* sound_info = new ANIM_SOUND_INFO;
350 sound_info->Frame = action_frame;
351 sound_info->SoundName = definition_name;
352
353 //
354 // "2D" check
355 //
356 // if ((param_count == 3) && (atoi(param_list[2]) == 2)) {
357 // sound_info->Is2D = true;
358 // }
359 //
360 sound_info->Is2D = false;
361 if ( Is_In_Param_List( param_list, param_count, "2D" ) )
362 {
363 sound_info->Is2D = true;
364 }
365
366 //
367 // "STOP" check
368 //
369 sound_info->IsStop = false;
370 if ( Is_In_Param_List( param_list, param_count, "STOP" ) )
371 {
372 sound_info->IsStop = true;
373 }
374
375 sound_list->Add_Sound_Info (sound_info);
376 delete [] param_list;
377 }
378 }
379 }
380
381 if (sound_list->List.Count () != 0) {
382
383 //
384 // Add this sound list to our hash-table and vector-array
385 //
386 AnimationNameHash.Insert (animation_name, sound_list);
387 AnimSoundLists.Add (sound_list);
388
389 } else {
390 //WWDEBUG_SAY (("AnimatedSoundMgrClass::Initialize -- No sounds added for %d!\n", animation_name.Peek_Buffer ()));
391 delete sound_list;
392 }
393 }
394
395 delete ini_file;
396 }
397
398 return ;
399}
400
401
403//
404// Shutdown
405//
407void
409{
410 //
411 // Reset the animation name hash
412 //
413 AnimationNameHash.Remove_All ();
414
415 //
416 // Free each of the sound objects
417 //
418 for (int index = 0; index < AnimSoundLists.Count (); index ++) {
419 /*
420 ANIM_SOUND_LIST* list = AnimSoundLists[index];
421 for (int i = 0; i < list->Count(); i++) {
422 delete (*list)[i];
423 }
424 */
425 delete AnimSoundLists[index];
426 }
427
428 AnimSoundLists.Delete_All ();
429 return ;
430}
431
432
434//
435// Does_Animation_Have_Embedded_Sounds
436//
438const char*
440{
441 if (anim == NULL) {
442 return NULL;
443 }
444 ANIM_SOUND_LIST* list = Find_Sound_List (anim);
445 if (list == NULL) {
446 return NULL;
447 }
448
449 return list->BoneName.Peek_Buffer();
450}
451
452
453
455//
456// Find_Sound_List
457//
459AnimatedSoundMgrClass::ANIM_SOUND_LIST *
460AnimatedSoundMgrClass::Find_Sound_List (HAnimClass *anim)
461{
462 //
463 // Build the full name of the animation
464 //
465 StringClass full_name (0, true);
466 full_name = anim->Get_Name ();
467
468 //
469 // Make the name uppercase
470 //
471 ::strupr (full_name.Peek_Buffer ());
472
473 //
474 // Lookup the sound list for this animation
475 //
476 ANIM_SOUND_LIST *retval = AnimationNameHash.Get (full_name);
477 return retval;
478}
479
480
482//
483// Trigger_Sound
484//
486float
488(
489 HAnimClass * anim,
490 float old_frame,
491 float new_frame,
492 const Matrix3D & tm
493)
494{
495 if ((SoundLibrary == NULL) || (anim == NULL)) {
496 return old_frame;
497 }
498
499 float retval = old_frame;
500
501#ifndef W3D_MAX4
502 //
503 // Lookup the sound list for this animation
504 //
505 ANIM_SOUND_LIST *sound_list = Find_Sound_List (anim);
506 if (sound_list != NULL) {
507
508 for (int index = 0; index < sound_list->List.Count (); index ++) {
509 int frame = sound_list->List[index]->Frame;
510
511 //
512 // Is the animation passing the frame we need?
513 //
514 if ((old_frame < frame) && (new_frame >= frame)) {
515
516 //
517 // Don't trigger the sound if its skipped too far past...
518 //
519 //if (WWMath::Fabs (new_frame - old_frame) < 3.0F) {
520
521 //
522 // Stop the audio?
523 //
524 if (sound_list->List[index]->IsStop == true)
525 {
526 //
527 // Stop the audio
528 //
529 SoundLibrary->Stop_Playing_Audio( sound_list->List[index]->SoundName.Peek_Buffer() );
530 }
531 else
532 {
533 //
534 // Play the audio
535 //
536 if (sound_list->List[index]->Is2D == true)
537 {
538 SoundLibrary->Play_2D_Audio(sound_list->List[index]->SoundName.Peek_Buffer());
539 }
540 else
541 {
542 SoundLibrary->Play_3D_Audio(sound_list->List[index]->SoundName.Peek_Buffer(), tm);
543 }
544 }
545
546 //WWDEBUG_SAY (("Triggering Sound %d %s\n", GetTickCount (), sound_list->List[index]->SoundName));
547
548 retval = frame;
549
550 //}
551 }
552
553 }
554
555 //retval = true;
556 }
557#endif
558
559 return retval;
560}
561
563{
564 SoundLibrary = library;
565}
#define NULL
Definition BaseType.h:92
void const char * value
#define WWASSERT
#define WWINLINE
Definition always.h:172
static void Shutdown(void)
static void Set_Sound_Library(SoundLibraryBridgeClass *library)
static void Initialize(const char *ini_filename=NULL)
static const char * Get_Embedded_Sound_Name(HAnimClass *anim)
static float Trigger_Sound(HAnimClass *anim, float old_frame, float new_frame, const Matrix3D &tm)
virtual bool Is_Available(int forced=false)=0
virtual const char * Get_Name(void) const =0
ValueType Get(const KeyType &s) const
Definition INI.H:80
char const * Get_Entry(char const *section, int index) const
Definition ini.cpp:828
List< INISection * > & Get_Section_List()
Definition INI.H:196
int Get_String(char const *section, char const *entry, char const *defvalue, char *buffer, int size) const
Definition ini.cpp:1700
int Entry_Count(char const *section) const
Definition ini.cpp:772
Definition list.h:60
T First(void) const
Definition LISTNODE.H:206
int Count(void) const
Definition simplevec.h:263
void Trim(void)
Definition wwstring.h:495
int Get_Length(void) const
Definition wwstring.h:664
TCHAR * Peek_Buffer(void)
Definition wwstring.h:560
FileFactoryClass * _TheFileFactory
Definition ffactory.cpp:51
else return(RetVal)