]> icculus.org git repositories - taylor/freespace2.git/blob - src/gamesnd/eventmusic.cpp
implemented two assembly stubs.
[taylor/freespace2.git] / src / gamesnd / eventmusic.cpp
1 /*
2  * $Logfile: /Freespace2/code/Gamesnd/EventMusic.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * C module for high-level control of event driven music 
8  *
9  * $Log$
10  * Revision 1.3  2002/05/28 08:52:03  relnev
11  * implemented two assembly stubs.
12  *
13  * cleaned up a few warnings.
14  *
15  * added a little demo hackery to make it progress a little farther.
16  *
17  * Revision 1.2  2002/05/07 03:16:45  theoddone33
18  * The Great Newline Fix
19  *
20  * Revision 1.1.1.1  2002/05/03 03:28:09  root
21  * Initial import.
22  *
23  * 
24  * 14    8/19/99 9:41a Alanl
25  * don't play victory 2 music if there are no goals in the mission
26  * 
27  * 13    8/11/99 5:33p Jefff
28  * added 3rd debrief music track
29  * 
30  * 12    8/01/99 2:11p Alanl
31  * make hull value to play more intense battle music a constant
32  * 
33  * 11    8/01/99 2:06p Alanl
34  * tweak battle music track switching
35  * 
36  * 10    7/25/99 9:57p Alanl
37  * change battle music track selection after enemy arrivals to make battle
38  * tracks less repetitive
39  * 
40  * 9     7/19/99 10:13p Andsager
41  * Tie in hud_targeting to  hostile_ships_present() used to determine next
42  * song.
43  * 
44  * 8     6/24/99 10:47p Alanl
45  * loop battle between tracks 2 and 3 if hull integrity < 70%
46  * 
47  * 7     6/21/99 1:34p Alanl
48  * event music tweaks
49  * 
50  * 6     6/20/99 12:06a Alanl
51  * new event music changes
52  * 
53  * 5     11/23/98 11:55a Johnson
54  * return -1 if a score isn't found
55  * 
56  * 4     11/20/98 4:08p Dave
57  * Fixed flak effect in multiplayer.
58  * 
59  * 3     10/23/98 3:51p Dave
60  * Full support for tstrings.tbl and foreign languages. All that remains
61  * is to make it active in Fred.
62  * 
63  * 2     10/07/98 10:52a Dave
64  * Initial checkin.
65  * 
66  * 1     10/07/98 10:48a Dave
67  * 
68  * 107   6/09/98 5:15p Lawrance
69  * French/German localization
70  * 
71  * 106   6/09/98 10:31a Hoffoss
72  * Created index numbers for all xstr() references.  Any new xstr() stuff
73  * added from here on out should be added to the end if the list.  The
74  * current list count can be found in FreeSpace.cpp (search for
75  * XSTR_SIZE).
76  * 
77  * 105   5/24/98 5:28p Dan
78  * let event_music_level_init() over-ride Event_music_enabled
79  * 
80  * 104   5/24/98 4:42p Dan
81  * AL: Fix several bugs related to pausing and enabling/disabling event
82  * music
83  * 
84  * 103   5/23/98 3:17a Lawrance
85  * Tweak how battle music gets restarted
86  * 
87  * 102   5/22/98 10:43a Lawrance
88  * If mission doesn't have event music, don't choose random track
89  * 
90  * 101   5/21/98 6:56p Lawrance
91  * Tweak how victory music plays
92  * 
93  * 100   5/21/98 2:47a Lawrance
94  * Fix some problems with event music
95  * 
96  * 99    5/18/98 3:21p Mike
97  * Don't play arrival and goals tracks in a training mission.
98  * 
99  * 98    5/04/98 3:15p Duncan
100  * AL: remove bogus assert in event_music_player_respawn()
101  * 
102  * 97    5/03/98 1:54a Lawrance
103  * Fix event music problems related to respawning
104  * 
105  * 96    4/03/98 12:56a Lawrance
106  * Fix bug with music not starting in the first mission
107  * 
108  * 95    4/01/98 6:46p Lawrance
109  * Lower default music volume 
110  *
111  * $NoKeywords: $
112  */
113
114
115 #include        "pstypes.h"
116 #include "eventmusic.h"
117 #include "object.h"
118 #include "ship.h"
119 #include "linklist.h"
120 #include "missionload.h"        /* for Builtin_mission_names[] */
121 #include "missionparse.h"
122 #include "timer.h"
123 #include "freespace.h"
124 #include "audiostr.h"
125 #include "missioncampaign.h"
126 #include "sound.h"
127 #include "time.h"
128 #include "cmdline.h"
129 #include "missiongoals.h"
130 #include "localize.h"
131
132 #ifndef PLAT_UNIX
133 #pragma optimize("", off)
134 #endif
135
136 #define DEFAULT_MASTER_EVENT_MUSIC_VOLUME       0.5f
137
138 #define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
139
140 ////////////////////////////
141 // Globals
142 ////////////////////////////
143 int Event_Music_battle_started = 0;
144 float Master_event_music_volume = DEFAULT_MASTER_EVENT_MUSIC_VOLUME;                    // range is 0->1
145
146 // array that holds which soundtrack is used for which mission (data comes from music.tbl)
147 //int Mission_soundtracks[MAX_CAMPAIGN_MISSIONS];
148
149 // array that holds which briefing track to play for which mission.  Index into Spooled_music[][].
150 //int Mission_briefingmusic[MAX_CAMPAIGN_MISSIONS];
151
152 typedef struct tagSNDPATTERN {
153         int default_next_pattern;       // Needed so the next_pattern member can be reset
154         int next_pattern;                               // Next pattern to play at loop time (can be same pattern)
155         int default_loop_for;           // Needed so the loop_for variable can be reset
156         int loop_for;                                   // Number of times to loop before switching to next pattern
157         int handle;                                             // handle to open audio stream
158         int force_pattern;                      // flag to indicate that we want to not continue loop, but go to next_pattern
159         int can_force;                                  // whether this pattern can be interrupted
160         int bytes_per_measure;          // number of bytes in a measure
161         float num_measures;                             // number of measures in wave file
162 }       SNDPATTERN;
163
164 SNDPATTERN      Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
165
166 // Holds filenames for the different sections of a soundtrack
167 SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
168 int Num_soundtracks;
169 int Current_soundtrack_num;     // Active soundtrack for the current mission.. index into Soundtracks[]
170
171 #define PATTERN_DELAY   1000    // in ms
172 int Current_pattern = -1;               // currently playing part of track
173 int Pending_pattern = -1;
174 int Pattern_timer_id = 0;
175
176 // File Globals
177 static int Num_enemy_arrivals;
178 static int Num_friendly_arrivals;
179
180 #define ARRIVAL_INTERVAL_TIMESTAMP  5000
181 #define BATTLE_CHECK_INTERVAL                   15000
182 static int Battle_over_timestamp;
183 static int Mission_over_timestamp;
184 static int Victory2_music_played;
185 static int Next_arrival_timestamp;
186 static int Check_for_battle_music;
187
188 // stores the number of measures for the different patterns (data from music.tbl)
189 float   Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS];
190
191 // stores the number of bytes per measure (data from music.tbl)
192 int     Pattern_bytes_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS];
193
194 char* Pattern_names[MAX_PATTERNS] =
195 {
196 //XSTR:OFF
197         "NRML_1",       // Normal Song 1
198         "AARV_1",       // Allied Arrival 1
199         "EARV_1",       // Enemy Arrival 1
200         "BTTL_1",       // Battle Song 1
201         "BTTL_2",       // Battle Song 2
202         "BTTL_3",       // Battle Song 3
203         "AARV_2",       // Allied Arrival 2
204         "EARV_2",       // Enemy Arrival 2
205         "VICT_1",       // Victory Song 1
206         "VICT_2",       // Victory Song 2
207         "FAIL_1"                // Goal Failed 1
208         "DEAD_1"                // Death Song 1
209 //XSTR:ON
210 };
211
212 char* Pattern_description[MAX_PATTERNS] =
213 {
214 //XSTR:OFF
215         "normal 1",
216         "friendly arrival 1",
217         "enemy arrival 2",
218         "battle 1",
219         "battle 2",
220         "battle 3",
221         "friendly arrival 2",
222         "enemey arrival 2",
223         "victory 1",
224         "victory 2",
225         "goal failed 1"
226         "death "
227 //XSTR:ON
228 };
229
230 int Pattern_loop_for[MAX_PATTERNS] =
231 {
232         1,      // Normal Song 1
233         1,      // Allied Arrival 1
234         1,      // Enemy Arrival 1
235         1,      // Battle Song 1
236         1,      // Battle Song 2
237         1,      // Battle Song 3
238         1,      // Allied Arrival 2
239         1,      // Enemy Arrival 2
240         1,      // Victory Song 1
241         1,      // Victory Song 2
242         1, // Goal Failed 1
243         1       // Death Song 1
244 };
245
246 int Pattern_default_next[MAX_PATTERNS] =
247 {
248         SONG_NRML_1,    // NRML_1 progresses to NRML_1 by default
249         SONG_NRML_1,    // AARV_1 progresses to NRML_1 by default
250         SONG_BTTL_1,    // EARV_1 progresses to BTTL_1 by default
251         SONG_BTTL_2,    // BTTL_1 progresses to BTTL_2 by default
252         SONG_BTTL_3,    // BTTL_2 progresses to BTTL_3 by default
253         SONG_BTTL_1,    // BTTL_3 progresses to BTTL_1 by default
254         SONG_BTTL_2,    // AARV_2 progresses to BTTL_2 by default
255         SONG_BTTL_3,    // EARV_2 progresses to BTTL_3 by default
256         SONG_NRML_1,    // VICT_1 progresses to NRML_1 by default
257         SONG_NRML_1,    // VICT_2 progresses to NRML_1 by default
258         SONG_NRML_1,    //      FAIL_1 progresses to NRML_1 by default
259         -1                                      // no music plays after dead
260 };
261
262
263 // Certain patterns can be interrupted (such as the long-playing NRML and BTTL tracks).  
264 // Other shorter tracks (such as arrivals) play their entire duration.
265 int Pattern_can_force[MAX_PATTERNS] =
266 {
267         TRUE,           // NRML_1 
268         FALSE,  // AARV_1 
269         FALSE,  // EARV_1 
270         TRUE,           // BTTL_1
271         TRUE,           // BTTL_2 
272         TRUE,           // BTTL_3
273         FALSE,  // AARV_2 
274         FALSE,  // EARV_2 
275         FALSE,  // VICT_1 
276         TRUE,           // VICT_2 
277         FALSE,  // FAIL_1
278         TRUE            // DEAD_1
279 };
280
281
282 int Event_music_enabled = TRUE;
283 static int Event_music_inited = FALSE;
284 static int Event_music_level_inited = FALSE;
285 static int Event_music_begun = FALSE;
286
287 // forward function declarations
288 int hostile_ships_present();
289 int hostile_ships_to_arrive();
290 extern int hud_target_invalid_awacs(object *objp);
291
292 // Holds file names of spooled music that is played at menus, briefings, credits etc.
293 // Indexed into by a #define enumeration of the different kinds of spooled music
294 menu_music Spooled_music[MAX_SPOOLED_MUSIC];
295 int Num_music_files;                            // Number of spooled music files
296
297 // Array that holds indicies into Spooled_music[], these specify which music is played in breifing/debriefing
298 int Mission_music[NUM_SCORES];  
299
300 // -------------------------------------------------------------------------------------------------
301 // event_music_init() 
302 //
303 // Called once at game start-up to parse music.tbl and set some state variables
304 //
305 void event_music_init()
306 {
307         if ( snd_is_inited() == FALSE ) {
308                 Event_music_enabled = FALSE;
309                 return;
310         }
311
312         if ( Cmdline_freespace_no_music ) {
313                 return;
314         }
315
316         if ( Event_music_inited == TRUE )
317                 return;
318
319         event_music_parse_musictbl();
320         Event_music_inited = TRUE;
321         Event_music_begun = FALSE;
322 }
323
324 // -------------------------------------------------------------------------------------------------
325 // event_music_close() 
326 //
327 // Called once at game end
328 //
329 void event_music_close()
330 {
331         if ( Event_music_inited == FALSE )
332                 return;
333
334         Event_music_inited = FALSE;
335 }
336
337 // -------------------------------------------------------------------------------------------------
338 // event_music_force_switch() 
339 //
340 // Performs a switch between patterns.  Sets the cutoff limit for the pattern that is being
341 // switch to.
342 //
343 void event_music_force_switch()
344 {
345         if ( Event_music_enabled == FALSE )
346                 return;
347
348         if ( Event_music_level_inited == FALSE )
349                 return;
350
351         int new_pattern;
352         Patterns[Current_pattern].loop_for = Patterns[Current_pattern].default_loop_for;
353
354         new_pattern = Patterns[Current_pattern].next_pattern;
355
356         if ( (new_pattern == SONG_BTTL_3) && (Patterns[SONG_BTTL_3].handle == -1) ) {
357                 if ( Current_pattern == SONG_BTTL_2 ) {
358                         new_pattern = SONG_BTTL_1;
359                 } else {
360                         new_pattern = SONG_BTTL_2;
361                 }
362         } else {
363                 if (Current_pattern == SONG_BTTL_3 && new_pattern == SONG_BTTL_1) {
364                         // AL 06-24-99: maybe switch to battle 2 if hull is less than 70%
365                         if (Player_obj != NULL && Player_ship != NULL) {
366                                 Assert(Player_ship->ship_info_index >= 0);
367                                 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
368                                 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
369                                 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
370                                         new_pattern = SONG_BTTL_2;
371                                 }
372                         }
373                 }
374         }
375
376         if ( new_pattern == -1 ) {
377                 return;
378         }
379
380         if ( Patterns[new_pattern].num_measures == 0 )
381                 return; // invalid pattern
382
383         Assert(new_pattern >= 0 && new_pattern < MAX_PATTERNS);
384         audiostream_play(Patterns[new_pattern].handle, Master_event_music_volume, 0);   // no looping
385         audiostream_set_byte_cutoff(Patterns[new_pattern].handle, fl2i(Patterns[new_pattern].num_measures * Patterns[new_pattern].bytes_per_measure) );
386         Patterns[Current_pattern].next_pattern = Patterns[Current_pattern].default_next_pattern;
387         Patterns[Current_pattern].force_pattern = FALSE;
388         nprintf(("EVENTMUSIC", "EVENTMUSIC => switching to %s from %s\n", Pattern_names[new_pattern], Pattern_names[Current_pattern]));
389         Current_pattern = new_pattern;
390 }
391
392 // -------------------------------------------------------------------------------------------------
393 // event_music_do_frame() 
394 //
395 // Called once per game frame, to check for transitions of patterns (and to start the music off at
396 // the beginning).
397 //
398 void event_music_do_frame()
399 {
400         if ( Event_music_level_inited == FALSE ) {
401                 return;
402         }
403
404         if ( Event_music_enabled == FALSE ) {
405                 return;
406         }
407
408         // start off the music delayed
409         if ( timestamp_elapsed(Pattern_timer_id) ) {
410                 Pattern_timer_id = 0;
411                 Event_music_begun = TRUE;
412                 if ( Current_pattern != -1 ) {
413                         Assert(Patterns[Current_pattern].handle >= 0 );
414                         audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0);       // no looping
415                         audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
416                 }
417         }
418
419         if ( Event_music_begun == FALSE ) {
420                 return;
421         }
422
423         if ( Current_pattern != -1 ) {
424                 SNDPATTERN *pat;
425                 pat = &Patterns[Current_pattern];
426
427                 // First case: switching to a different track since first track is almost at end
428                 if ( audiostream_done_reading(pat->handle) ) {
429                         event_music_force_switch();     
430                 }
431                 // Second case: looping back to start of same track since at the end
432                 else if ( !audiostream_is_playing(pat->handle) && !audiostream_is_paused(pat->handle) ) {
433                         audiostream_stop(pat->handle);  // stop current and rewind
434                         pat->loop_for--;
435                         if ( pat->loop_for > 0 ) {
436                                 audiostream_play(pat->handle, Master_event_music_volume, 0);    // no looping
437                                 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
438                         }
439                         else {
440                                 event_music_force_switch();
441                         }
442                 }
443                 // Third case: switching to a different track by interruption
444                 else if ( (pat->force_pattern == TRUE && pat->can_force == TRUE) ) {
445                         int bytes_streamed = audiostream_get_bytes_committed(pat->handle);
446                         int measures_played = bytes_streamed / pat->bytes_per_measure;
447                         if ( measures_played < pat->num_measures ) {
448                                 audiostream_set_byte_cutoff(pat->handle, pat->bytes_per_measure * (measures_played+1) );
449                                 pat->force_pattern = FALSE;
450                                 pat->loop_for = 0;
451                         }
452                 }
453
454                 // We want to go back to NRML track music if all the hostiles have been 
455                 // destroyed, and we are still playing the battle music
456                 if ( Current_pattern == SONG_BTTL_1 || Current_pattern == SONG_BTTL_2 || Current_pattern == SONG_BTTL_3 ) {
457                         if ( timestamp_elapsed(Battle_over_timestamp) && Event_Music_battle_started == 1) {
458                                 //Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
459                                 if ( hostile_ships_present() == FALSE ) {
460                                         if ( Patterns[Current_pattern].next_pattern != SONG_VICT_2 ) {
461                                                 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
462                                                 Patterns[Current_pattern].force_pattern = TRUE;
463                                                 Event_Music_battle_started = 0;
464                                         }
465                                 }
466                         }
467                 }
468
469                 if (Event_Music_battle_started == 0) {
470                         if (Current_pattern == SONG_NRML_1) {
471                                 if (timestamp_elapsed(Check_for_battle_music)) {
472                                         Check_for_battle_music = timestamp(1000);
473                                         if (hostile_ships_present() == TRUE) {
474                                                 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
475                                                 Patterns[Current_pattern].force_pattern = TRUE;
476                                         }
477                                 }
478                         }
479                 }
480
481                 if ( !Victory2_music_played ) {
482                         if ( timestamp_elapsed(Mission_over_timestamp) ) {
483                                 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
484                                 if ( mission_goals_met() && (!hostile_ships_present()) ) {
485                                         Patterns[Current_pattern].next_pattern = SONG_VICT_2;
486                                         Patterns[Current_pattern].force_pattern = TRUE;
487                                         Victory2_music_played = 1;
488                                 }
489                         }
490                 }
491         }
492 }
493
494 // -------------------------------------------------------------------------------------------------
495 // event_music_level_init() 
496 //
497 // Called at the start of a mission (level).  Sets up the pattern data, and kicks off the
498 // first track to play().
499 //
500 // input:       force_soundtrack        =>              OPTIONAL parameter (default value -1)
501 //                                                                                              forces the soundtrack to ignore the music.tbl assignment
502 //
503 void event_music_level_init(int force_soundtrack)
504 {
505         int                                     i;
506         SOUNDTRACK_INFO *strack;
507
508         if ( Cmdline_freespace_no_music ) {
509                 return;
510         }
511
512         if ( !audiostream_is_inited() )
513                 return;
514
515         if ( Event_music_level_inited == TRUE )
516                 return;
517
518         Current_pattern = -1;
519
520         if ( Event_music_inited == FALSE )
521                 return;
522
523
524         if ( force_soundtrack != -1 ) {
525                 Current_soundtrack_num = force_soundtrack;
526         }
527
528         if ( Current_soundtrack_num < 0 ) {
529                 return;
530 /*
531                 // okay, assign a random soundtrack if one exists
532                 if ( Num_soundtracks > 0 ) {
533                         Current_soundtrack_num = rand()%Num_soundtracks;
534                         nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Picking random event music soundtrack: %s\n", Soundtracks[Current_soundtrack_num].name));
535                 } else {
536                         return;
537                 }
538 */
539         }
540
541         Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < Num_soundtracks);
542         strack = &Soundtracks[Current_soundtrack_num];
543
544         // open the pattern files, and get ready to play them
545         for ( i = 0; i < strack->num_patterns; i++ ) {
546                 if ( !stricmp(NOX("none.wav"), strack->pattern_fnames[i]) ) {
547                         Patterns[i].handle = -1;        
548                         continue;
549                 }
550
551                 Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
552
553                 if ( Patterns[i].handle >= 0 ) {
554                         Event_music_level_inited = TRUE;
555                         Event_music_enabled = TRUE;
556                 }
557
558                 Patterns[i].next_pattern = Pattern_default_next[i];
559                 Patterns[i].default_next_pattern = Pattern_default_next[i];
560                 Patterns[i].loop_for = Pattern_loop_for[i];
561                 Patterns[i].default_loop_for = Pattern_loop_for[i];
562                 Patterns[i].force_pattern = FALSE;
563                 Patterns[i].can_force = Pattern_can_force[i];
564                 Patterns[i].bytes_per_measure = Pattern_bytes_per_measure[Current_soundtrack_num][i];
565                 Patterns[i].num_measures = Pattern_num_measures[Current_soundtrack_num][i];
566         }
567
568         Num_enemy_arrivals = 0;
569         Num_friendly_arrivals = 0;
570         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
571         Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
572         Next_arrival_timestamp = timestamp(1);
573         Victory2_music_played = 0;
574         Check_for_battle_music = 0;
575
576         if ( Event_music_level_inited ) {
577                 if ( force_soundtrack != -1 )  {
578                         event_music_first_pattern();
579                 }
580         }
581 }
582
583 // -------------------------------------------------------------------------------------------------
584 // event_music_first_pattern() 
585 //
586 // Picks the first pattern to play, based on whether the battle has started.  Delay start
587 // by PATTERN_DELAY
588 //
589 void event_music_first_pattern()
590 {
591         if ( Event_music_inited == FALSE ) {
592                 return;
593         }
594
595         if ( Event_music_enabled == FALSE ) {
596                 return;
597         }
598
599         if ( Event_music_level_inited == FALSE ) {
600                 event_music_level_init();
601         }
602
603         if ( Event_music_level_inited == FALSE ) {
604                 return;
605         }
606
607         if ( Event_music_begun == TRUE ) {
608                 return;
609         }
610
611         if ( Current_pattern != -1 ) {
612                 if (  audiostream_is_playing(Patterns[Current_pattern].handle) )
613                         audiostream_stop( Patterns[Current_pattern].handle );
614         }
615
616         Pattern_timer_id = 2000;        // start music delay
617         
618         Event_music_begun = FALSE;
619         if ( Event_Music_battle_started == TRUE ) {
620                 Current_pattern = SONG_BTTL_1;
621         }
622         else {
623                 Current_pattern = SONG_NRML_1;
624         }
625 }
626
627 // -------------------------------------------------------------------------------------------------
628 // event_music_level_close() 
629 //
630 // Called at the end of each mission (level).  Stops any playing patterns by fading them out.
631 //
632 void event_music_level_close()
633 {
634         int i;
635
636         if ( Event_music_level_inited == FALSE )
637                 return;
638
639         if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS ) {
640                 SOUNDTRACK_INFO *strack;
641    
642                 Assert( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS );
643                 strack = &Soundtracks[Current_soundtrack_num];
644
645                 // close the pattern files
646                 for ( i = 0; i < strack->num_patterns; i++ ) {
647                         if ( i == Current_pattern ) {
648                                 if (  audiostream_is_playing(Patterns[Current_pattern].handle) )
649                                         audiostream_close_file( Patterns[i].handle );
650                                 else
651                                         audiostream_close_file( Patterns[i].handle, 0 );
652                         }
653                         else
654                                 audiostream_close_file( Patterns[i].handle, 0 );
655                 }
656         } else {
657                 // close em all down then
658                 audiostream_close_all(0);
659         }
660
661         Current_pattern = -1;
662         Event_music_level_inited = FALSE;
663         Event_Music_battle_started = FALSE;
664         Event_music_enabled = 0;
665         Event_music_begun = FALSE;
666 }
667
668 // -------------------------------------------------------------------------------------------------
669 // event_music_battle_start() 
670 //
671 // Start the battle music.  If the music is already started before, do nothing.
672 //
673 int event_music_battle_start()
674 {       
675         if ( !hostile_ships_present() ) {
676                 return 0;
677         }
678
679         //      No special tracks in training.
680         if ( The_mission.game_type & MISSION_TYPE_TRAINING )
681                 return -1;
682
683         // Check to see if we've already started off the battle song
684         if ( Event_Music_battle_started == 1 ) {
685                 return 0;
686         }
687
688         if ( Event_music_enabled == FALSE )
689                 return -1;
690
691         if ( Event_music_level_inited == FALSE )
692                 return -1;
693
694         if ( Current_pattern == SONG_BTTL_1 )
695                 return 0;       // already playing
696
697         if ( Current_pattern == SONG_DEAD_1 )
698                 return 0;       // death is the last song to play
699
700         if ( Current_pattern != -1 ) {
701                 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
702                 Patterns[Current_pattern].force_pattern = TRUE;
703         }
704
705         Event_Music_battle_started = 1; // keep track of this state though, need on restore
706         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
707
708         return 0;
709 }
710
711 // -------------------------------------------------------------------------------------------------
712 // event_music_enemy_arrival() 
713 //
714 // An enemy has arrived, play an enemy arrival pattern.
715 //
716 int event_music_enemy_arrival()
717 {
718         if ( Event_music_enabled == FALSE ) {
719                 return -1;
720         }
721
722         if ( Event_music_level_inited == FALSE ) {
723                 return -1;
724         }
725
726         int next_pattern;
727         if ( Event_Music_battle_started == TRUE ) {
728                 next_pattern = SONG_EARV_2;
729         }
730         else {
731                 next_pattern = SONG_EARV_1;
732         }
733
734         if ( Current_pattern == next_pattern )
735                 return 0;       // already playing
736
737         if ( Current_pattern == SONG_DEAD_1 )
738                 return 0;       // death is the last song to play
739
740         if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
741                 return 0;
742
743         if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
744                 return 0;       // don't squash a pending pattern
745
746         Num_enemy_arrivals++;
747
748         // AL 7-25-99: If hull is less than 70% then switch to battle 2 or 3, otherwise switch to 1 or 2
749         bool play_intense_battle_music = false;
750         if (Player_obj != NULL && Player_ship != NULL) {
751                 Assert(Player_ship->ship_info_index >= 0);
752                 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
753                 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
754                 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
755                         play_intense_battle_music = true;
756                 }
757         }
758
759         if (play_intense_battle_music == true) {
760                 if (Current_pattern == SONG_BTTL_2) {
761                         Patterns[next_pattern].next_pattern = SONG_BTTL_3;
762                 } else {
763                         Patterns[next_pattern].next_pattern = SONG_BTTL_2;
764                 }
765         } else {
766                 if (Current_pattern == SONG_BTTL_1) {
767                         Patterns[next_pattern].next_pattern = SONG_BTTL_2;
768                 } else if (Current_pattern == SONG_BTTL_2) {
769                         Patterns[next_pattern].next_pattern = SONG_BTTL_3;
770                 } else {
771                         Patterns[next_pattern].next_pattern = SONG_BTTL_1;
772                 }
773         }
774
775         /*
776         // AL 11-03-97:
777         // Alternate between BTTL_2 and BTTL_3 following enemy arrivals
778         if ( Num_enemy_arrivals & 1 ) {
779                 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
780         } else {
781                 if ( Patterns[SONG_BTTL_3].handle != -1 ) {
782                         Patterns[next_pattern].next_pattern = SONG_BTTL_3;
783                 } else {
784                         Patterns[next_pattern].next_pattern = SONG_BTTL_2;
785                 }
786         }
787         */
788
789         if ( Current_pattern != -1 ) {
790                 Patterns[Current_pattern].next_pattern = next_pattern;
791                 Patterns[Current_pattern].force_pattern = TRUE;
792         }
793
794         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
795
796         return 0;
797 }
798
799 // -------------------------------------------------------------------------------------------------
800 // event_music_friendly_arrival() 
801 //
802 // An friendly has arrived, play a friendly arrival pattern.
803 //
804 int event_music_friendly_arrival()
805 {
806         if ( Event_music_enabled == FALSE )
807                 return -1;
808
809         if ( Event_music_level_inited == FALSE )
810                 return -1;
811
812         if (timestamp_elapsed(Next_arrival_timestamp) == false) {
813                 return 0;
814         }
815
816         int next_pattern;
817         if ( Event_Music_battle_started == TRUE ) {
818                 next_pattern = SONG_AARV_2;
819         }
820         else {
821                 next_pattern = SONG_AARV_1;
822         }
823
824         if ( Current_pattern == next_pattern )
825                 return 0;       // already playing
826
827         if ( Current_pattern == SONG_DEAD_1 )
828                 return 0;       // death is the last song to play
829
830         if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
831                 return 0;
832
833         if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
834                 return 0;       // don't squash a pending pattern
835
836         // After the second friendly arrival, default to SONG_BTTL_3
837         Num_friendly_arrivals++;
838
839         if ( Current_pattern != -1 ) {
840                 // AL 06-24-99: always overlay allied arrivals
841                 /*
842                 if (next_pattern == SONG_AARV_1) {
843                         Patterns[Current_pattern].next_pattern = next_pattern;
844                         Patterns[Current_pattern].force_pattern = TRUE;
845                 } else {
846                 */
847                         Assert(Patterns[SONG_AARV_1].handle >= 0 );
848                         audiostream_play(Patterns[SONG_AARV_1].handle, Master_event_music_volume, 0);   // no looping
849                         audiostream_set_byte_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].bytes_per_measure) );
850                 //}
851         }
852
853         Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
854
855         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
856
857         return 0;
858 }
859
860 //      Play arrival music keyed to team "team".
861 void event_music_arrival(int team)
862 {
863         //      No friendly arrival music in a training mission.
864         if ( The_mission.game_type & MISSION_TYPE_TRAINING )
865                 return;
866
867         if ( Player_ship->team == team ) {
868                 event_music_friendly_arrival();
869         } else {
870                 event_music_enemy_arrival();
871         }
872 }
873
874 // -------------------------------------------------------------------------------------------------
875 // event_music_primary_goals_met() 
876 //
877 // A primary goal has failed
878 //
879 int event_music_primary_goal_failed()
880 {
881         int next_pattern;
882
883         //      No special tracks in training.
884         if ( The_mission.game_type & MISSION_TYPE_TRAINING )
885                 return -1;
886
887         if ( Event_music_enabled == FALSE )
888                 return -1;
889
890         if ( Event_music_level_inited == FALSE )
891                 return -1;
892
893         if ( Current_pattern == SONG_DEAD_1 )
894                 return 0;       // death is the last song to play
895
896         if ( Patterns[SONG_FAIL_1].handle < 0 ) // can't play if music file doesn't exist
897                 return 0;
898
899         if ( hostile_ships_present() ) {
900                 next_pattern = SONG_BTTL_1;
901         }
902         else {
903                 next_pattern = SONG_NRML_1;
904                 Event_Music_battle_started = 0;
905         }
906
907         if ( Current_pattern != -1 ) {
908                 Patterns[Current_pattern].next_pattern = next_pattern;
909                 Patterns[Current_pattern].force_pattern = TRUE;
910         }
911
912         return 0;
913 }
914
915 // -------------------------------------------------------------------------------------------------
916 // event_music_primary_goals_met() 
917 //
918 // A goal has been achieved, play the appropriate victory music.
919 //
920 int event_music_primary_goals_met()
921 {
922         int next_pattern = SONG_VICT_1;
923
924         //      No special tracks in training.
925         if ( The_mission.game_type & MISSION_TYPE_TRAINING )
926                 return -1;
927
928         if ( Event_music_enabled == FALSE )
929                 return -1;
930
931         if ( Event_music_level_inited == FALSE )
932                 return -1;
933
934         if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_2) )
935                 return 0;       // already playing
936
937         if ( Current_pattern == SONG_DEAD_1 )
938                 return 0;       // death is the last song to play
939
940         if ( hostile_ships_present() ) {
941                 Patterns[SONG_VICT_1].next_pattern = SONG_BTTL_1;
942         }
943         else {
944                 Patterns[SONG_VICT_1].next_pattern = SONG_VICT_2;
945                 Event_Music_battle_started = 0;
946
947                 // If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
948                 // to the next default track
949                 if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
950                         Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
951                 } else {
952                         Victory2_music_played = 1;
953                 }
954         }
955
956         if ( Current_pattern != -1 ) {
957                 Patterns[Current_pattern].next_pattern = next_pattern;
958                 Patterns[Current_pattern].force_pattern = TRUE;
959         }
960
961         return 0;
962 }
963
964 // -------------------------------------------------------------------------------------------------
965 // event_music_player_death() 
966 //
967 // The player has died, play death pattern.
968 //
969 int event_music_player_death()
970 {
971         if ( Event_music_enabled == FALSE )
972                 return -1;
973
974         if ( Event_music_level_inited == FALSE )
975                 return -1;
976
977         if ( Current_pattern == SONG_DEAD_1 )
978                 return 0;       // already playing
979
980         if ( Current_pattern != -1 ) {
981                 Patterns[Current_pattern].next_pattern = SONG_DEAD_1;
982                 Patterns[Current_pattern].force_pattern = TRUE;
983         }
984
985         return 0;
986 }
987
988 // -------------------------------------------------------------------------------------------------
989 // event_music_player_respawn() 
990 //
991 // Player has respawned (multiplayer only)
992 //
993 int event_music_player_respawn()
994 {
995         if ( Event_music_enabled == FALSE )
996                 return -1;
997
998         if ( Event_music_level_inited == FALSE )
999                 return -1;
1000
1001 //      Assert(Current_pattern == SONG_DEAD_1);
1002
1003         Event_Music_battle_started = 0;
1004         Patterns[Current_pattern].next_pattern = SONG_NRML_1;
1005         Patterns[Current_pattern].force_pattern = TRUE;
1006
1007         return 0;
1008 }
1009
1010 // -------------------------------------------------------------------------------------------------
1011 // event_music_player_respawn_as_observer() 
1012 //
1013 // Player has respawned (multiplayer only)
1014 //
1015 int event_music_player_respawn_as_observer()
1016 {
1017         if ( Event_music_enabled == FALSE )
1018                 return -1;
1019
1020         if ( Event_music_level_inited == FALSE )
1021                 return -1;
1022
1023         if ( Current_pattern >= 0 ) {
1024                 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1025                         audiostream_stop(Patterns[Current_pattern].handle);
1026                         Current_pattern = -1;
1027                 }
1028         }
1029
1030         return 0;
1031 }
1032
1033 // -------------------------------------------------------------------------------------------------
1034 // event_music_parse_musictbl() will parse the music.tbl file, and set up the Mission_songs[]
1035 // array
1036 //
1037 void event_music_parse_musictbl()
1038 {
1039         char fname[MAX_FILENAME_LEN];
1040         char line_buf[128];
1041         int rval;
1042
1043         int num_patterns = 0;
1044
1045         Num_music_files = 0;
1046         Num_soundtracks = 0;            // Global
1047         event_music_reset_choices();
1048
1049         if ((rval = setjmp(parse_abort)) != 0) {
1050                 Error(LOCATION, "Unable to parse music.tbl!  Code = %i.\n", rval);
1051
1052         } else {
1053                 // open localization
1054                 lcl_ext_open();
1055
1056                 read_file_text("music.tbl");
1057                 reset_parse();          
1058
1059                 // Loop through all the sound-tracks
1060                 while (required_string_either("#Menu Music Start","#SoundTrack Start")) {
1061                         Assert(Num_soundtracks < MAX_SOUNDTRACKS);
1062                         required_string("#SoundTrack Start");
1063                         required_string("$SoundTrack Name:");
1064                         stuff_string(Soundtracks[Num_soundtracks].name, F_NAME, NULL);
1065                         while (required_string_either("#SoundTrack End","$Name:")) {
1066                                 Assert( num_patterns < MAX_PATTERNS );
1067                                 required_string("$Name:");
1068                                 stuff_string(line_buf, F_NAME, NULL);
1069
1070                                 // line_buf holds 3 fields:  filename, num measures, bytes per measure
1071
1072                                 char *token;
1073                                 int count = 0;
1074                                 token = strtok( line_buf, NOX(" ,\t"));
1075                                 strcpy(fname, token);
1076                                 while ( token != NULL ) {
1077                                         token = strtok( NULL, NOX(" ,\t") );
1078                                         if ( token == NULL ) {
1079                                                 Assert(count == 2 );
1080                                                 break;
1081                                         }
1082
1083                                         if ( count == 0 ) {
1084                                                 Pattern_num_measures[Num_soundtracks][num_patterns] = (float)atof(token);
1085
1086                                         } else {
1087                                                 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] = atoi(token);
1088                                         }
1089
1090                                         count++;
1091                                 }       // end while
1092
1093                                 // convert from samples per measure to bytes per measure
1094                                 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] *= 2;
1095                                 strcpy(Soundtracks[Num_soundtracks].pattern_fnames[num_patterns], fname);
1096                                 num_patterns++;
1097                         }
1098
1099                         required_string("#SoundTrack End");
1100                         Soundtracks[Num_soundtracks].num_patterns = num_patterns;
1101                         Num_soundtracks++;
1102                         num_patterns = 0;
1103                 }
1104
1105                 // Parse the menu music section
1106                 required_string("#Menu Music Start");
1107                 while (required_string_either("#Menu Music End","$Name:")) {
1108                         Assert( Num_music_files < MAX_SPOOLED_MUSIC );
1109
1110                         required_string("$Name:");
1111                         stuff_string(fname, F_PATHNAME, NULL);
1112                         Assert( strlen(fname) < (NAME_LENGTH-1) );
1113                         strcpy( Spooled_music[Num_music_files].name, fname );
1114
1115                         required_string("$Filename:");
1116                         stuff_string(fname, F_PATHNAME, NULL);
1117                         if ( stricmp(fname, NOX("none.wav"))  ) {
1118                                 Assert( strlen(fname) < (MAX_FILENAME_LEN-1) );
1119                                 strcpy( Spooled_music[Num_music_files].filename, fname );
1120                         }
1121
1122                         Num_music_files++;                      
1123                 }
1124
1125                 required_string("#Menu Music End");
1126
1127                 // close localization
1128                 lcl_ext_close();
1129         }
1130 }
1131
1132 // -------------------------------------------------------------------------------------------------
1133 // event_music_change_pattern()
1134 //
1135 // Force a particular pattern to play.  This is used for debugging purposes.
1136 //
1137 void event_music_change_pattern(int new_pattern)
1138 {
1139         if ( Event_music_enabled == FALSE ) {
1140                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1141                 return;
1142         }
1143
1144         if ( Event_music_level_inited == FALSE ) {
1145                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1146                 return;
1147         }
1148
1149         if ( Current_pattern == new_pattern )
1150                 return; // already playing
1151
1152         if ( Current_pattern != -1 ) {
1153                 Patterns[Current_pattern].next_pattern = new_pattern;
1154                 Patterns[Current_pattern].force_pattern = TRUE;
1155         }
1156 }
1157
1158 // -------------------------------------------------------------------------------------------------
1159 // event_music_return_current_pattern()
1160 //
1161 // Simply return what the current pattern being played is.  Don't want to make global.
1162 //
1163 int event_music_return_current_pattern()
1164 {
1165         return Current_pattern;
1166 }
1167
1168 // -------------------------------------------------------------------------------------------------
1169 // event_music_disable()
1170 //
1171 // Stop any patterns that are playing, and prevent any further patterns from playing (ie
1172 // set Event_music_enabled = FALSE).  We don't uninit event music, since it might be toggled
1173 // back on this level.
1174 //
1175 void event_music_disable()
1176 {
1177         if ( Event_music_level_inited == FALSE )
1178                 return;
1179
1180         if ( Event_music_enabled == FALSE )
1181                 return;
1182
1183         if (Current_pattern == -1)
1184                 return;
1185
1186         Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1187         if (  audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1188                         audiostream_stop(Patterns[Current_pattern].handle);     // stop current and rewind
1189         }
1190
1191         Event_music_begun = FALSE;
1192         Event_music_enabled = FALSE;
1193         Current_pattern = -1;
1194 }
1195
1196 // -------------------------------------------------------------------------------------------------
1197 // event_music_enable()
1198 //
1199 // Init the event music (ie load the patterns) if required.  Set up the first song to play, and
1200 // set Event_music_enabled = TRUE to allow patterns to play.
1201 //
1202 void event_music_enable()
1203 {
1204         if ( Event_music_enabled == TRUE )
1205                 return;
1206
1207         Event_music_enabled = TRUE;
1208
1209         if ( Event_music_level_inited == FALSE ) {
1210                 event_music_level_init();
1211                 // start the first pattern to play (delayed)
1212                 if ( Game_mode & GM_IN_MISSION ) {
1213                         event_music_first_pattern();
1214                 }
1215         }
1216         else {
1217                 // start a new pattern
1218                 Event_music_begun = FALSE;
1219                 Pattern_timer_id = timestamp(150);
1220                 event_music_start_default();
1221         }
1222 }
1223
1224 // -------------------------------------------------------------------------------------------------
1225 // event_music_start_default()
1226 //
1227 //      Start playing a default track, based on how far the mission has progressed
1228 //
1229 void event_music_start_default()
1230 {       
1231         int next_pattern;
1232
1233         if ( Event_Music_battle_started == TRUE ) {
1234                 if ( hostile_ships_present() ) {
1235                         next_pattern = SONG_BTTL_1;
1236                 }
1237                 else {
1238                         Event_Music_battle_started = FALSE;
1239                         next_pattern = SONG_NRML_1;
1240                 }
1241         }
1242         else
1243                 next_pattern = SONG_NRML_1;     
1244
1245         if ( Current_pattern == -1 ) {
1246                 Current_pattern = next_pattern;
1247         }
1248         else {
1249                 Patterns[Current_pattern].next_pattern = next_pattern;
1250                 Patterns[Current_pattern].force_pattern = TRUE;
1251         }
1252
1253 }
1254
1255 // -------------------------------------------------------------------------------------------------
1256 // event_music_pause()
1257 //
1258 //      Stop any playing pattern, but don't rewind.
1259 //
1260 void event_music_pause()
1261 {
1262         if ( Event_music_enabled == FALSE ) {
1263                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1264                 return;
1265         }
1266
1267         if ( Event_music_level_inited == FALSE ) {
1268                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1269                 return;
1270         }
1271
1272         if (Current_pattern == -1)
1273                 return;
1274
1275         Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1276         if (  audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1277                         audiostream_stop(Patterns[Current_pattern].handle, 0);  // stop current and don't rewind
1278         }
1279 }
1280
1281 // -------------------------------------------------------------------------------------------------
1282 // event_music_unpause()
1283 //
1284 //      Start the Current_pattern if it is paused.
1285 //
1286 void event_music_unpause()
1287 {
1288         if ( Event_music_enabled == FALSE ) {
1289                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1290                 return;
1291         }
1292
1293         if ( Event_music_level_inited == FALSE ) {
1294                 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1295                 return;
1296         }
1297
1298         if (Current_pattern == -1)
1299                 return;
1300
1301         Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1302         if ( audiostream_is_paused(Patterns[Current_pattern].handle) == TRUE ) {
1303                 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0);       // no looping
1304                 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
1305         }
1306 }
1307
1308 // -------------------------------------------------------------------------------------------------
1309 // event_music_set_volume_all()
1310 //
1311 //      Set the volume of the event driven music.  Used when using the game-wide music volume is changed
1312 // by the user.
1313 //
1314 void event_music_set_volume_all(float volume)
1315 {
1316         audiostream_set_volume_all(volume, ASF_EVENTMUSIC);
1317 }
1318
1319 // ----------------------------------------------------------------------
1320 // hostile_ships_present()
1321 //
1322 // Determine if there are any non-friendly ships in existance
1323 //
1324 // returns: 1 =>        there are non-friendly ships in existance
1325 //                              0 =>  any ships in existance are friendly
1326 int hostile_ships_present()
1327 {
1328         ship            *shipp;
1329         ship_obj *so;
1330
1331         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1332                 shipp = &Ships[Objects[so->objnum].instance];
1333
1334                 // check if ship if enemy ship
1335                 if ( (shipp->team == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR)  )
1336                         continue;
1337
1338                 // check if ship is threatening
1339                 if ( (shipp->flags & (SF_DISABLED|SF_DYING|SF_DEPARTING)) || (ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE)) ) 
1340                         continue;
1341         
1342                 // check if ship is flyable
1343                 if ( Ship_info[shipp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
1344                         continue;
1345                 }
1346
1347                 // check if ship is visible by player's team
1348                 if ( hud_target_invalid_awacs(&Objects[so->objnum]) == 1 ) {
1349                         continue;
1350                 }
1351
1352                 return 1;
1353         }
1354         return 0;
1355 }
1356
1357 // ----------------------------------------------------------------------
1358 // hostile_ships_to_arrive()
1359 //
1360 // Determine if there are any non-friendly ships yet to arrive
1361 //
1362 // NOTE: neutral ships are considered hostile for the purpose of event music
1363 //
1364 int hostile_ships_to_arrive()
1365 {
1366         p_object *p_objp;
1367
1368         p_objp = GET_FIRST(&ship_arrival_list);
1369         while( p_objp != END_OF_LIST(&ship_arrival_list) )      {
1370                 if ( (p_objp->team != Player_ship->team) && !(p_objp->flags & P_SF_CANNOT_ARRIVE) ) {
1371                         return 1;
1372                 }
1373                 p_objp = GET_NEXT(p_objp);
1374         }
1375         return 0;
1376 }
1377
1378 // ----------------------------------------------------------------
1379 // event_music_get_info()
1380 //
1381 // Return information about the event music in the buffer outbuf
1382 // NOTE: callers to this function are advised to allocate a 256 byte buffer
1383 void event_music_get_info(char *outbuf)
1384 {
1385         if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
1386                 sprintf(outbuf,XSTR( "Event music is not playing", 213));
1387         }
1388         else {  
1389                 sprintf(outbuf,XSTR( "soundtrack: %s [%s]", 214), Soundtracks[Current_soundtrack_num].name, Pattern_description[Current_pattern]);
1390         }
1391 }
1392
1393 // ----------------------------------------------------------------
1394 // event_music_next_soundtrack()
1395 //
1396 // input:       delta           =>              1 or -1, depending if you want to go to next or previous song
1397 //
1398 // returns: New soundtrack number if successfully changed, otherwise return -1
1399 //
1400 int event_music_next_soundtrack(int delta)
1401 {
1402         int new_soundtrack;
1403
1404         if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1405                 return -1;
1406         }
1407                 
1408         new_soundtrack = Current_soundtrack_num + delta;
1409         if ( new_soundtrack >= Num_soundtracks )
1410                 new_soundtrack = 0;
1411
1412         event_music_level_close();
1413         event_music_level_init(new_soundtrack);
1414
1415         return Current_soundtrack_num;
1416 }
1417
1418 // ----------------------------------------------------------------
1419 // event_music_get_soundtrack_name()
1420 //
1421 // Return information about the event music in the buffer outbuf
1422 // NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
1423 void event_music_get_soundtrack_name(char *outbuf)
1424 {
1425         if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1426                 strcpy(outbuf, XSTR( "Event music is not playing", 213));
1427         }
1428         else {
1429                 sprintf(outbuf, Soundtracks[Current_soundtrack_num].name);
1430         }
1431 }
1432
1433 // set the current soundtrack based on name
1434 void event_music_set_soundtrack(char *name)
1435 {
1436         int i;
1437
1438         // find the correct index for the event music
1439         for ( i = 0; i < Num_soundtracks; i++ ) {
1440                 if ( !stricmp(name, Soundtracks[i].name) ) {
1441                         Current_soundtrack_num = i;
1442                         break;
1443                 }
1444         }
1445
1446         if ( i == Num_soundtracks ) {
1447                 Current_soundtrack_num = -1;
1448                 mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
1449         }
1450 }
1451
1452 int event_music_get_spooled_music_index(char *name)
1453 {
1454         // find the correct index for the event music
1455         for ( int i = 0; i < Num_music_files; i++ ) {
1456                 if ( !stricmp(name, Spooled_music[i].name) ) {
1457                         return i;
1458                 }
1459         }
1460
1461         return -1;
1462 }
1463
1464 // set a score based on name
1465 void event_music_set_score(int score_index, char *name)
1466 {
1467         Assert(score_index < NUM_SCORES);
1468
1469         // find the correct index for the event music
1470         Mission_music[score_index] = event_music_get_spooled_music_index(name);
1471 }
1472
1473 // reset what sort of music is to be used for this mission
1474 void event_music_reset_choices()
1475 {
1476         Current_soundtrack_num = -1;
1477         mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
1478         Mission_music[SCORE_BRIEFING] = -1;
1479         event_music_set_score(SCORE_DEBRIEF_SUCCESS, "Success");
1480         event_music_set_score(SCORE_DEBRIEF_AVERAGE, "Average");
1481         event_music_set_score(SCORE_DEBRIEF_FAIL, "Failure");
1482         //Mission_music[SCORE_DEBRIEF_SUCCESS] = MUSIC_DEBRIEF_SUCCESS_1;
1483         //Mission_music[SCORE_DEBRIEF_FAIL] = MUSIC_DEBRIEF_FAIL_1;
1484 }
1485
1486 void event_music_hostile_ship_destroyed()
1487 {
1488         Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
1489 }
1490
1491 #ifndef PLAT_UNIX
1492 #pragma optimize("", on)
1493 #endif