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