2 * $Logfile: /Freespace2/code/Gamesnd/EventMusic.cpp $
7 * C module for high-level control of event driven music
10 * Revision 1.1 2002/05/03 03:28:09 root
14 * 14 8/19/99 9:41a Alanl
15 * don't play victory 2 music if there are no goals in the mission
17 * 13 8/11/99 5:33p Jefff
18 * added 3rd debrief music track
20 * 12 8/01/99 2:11p Alanl
21 * make hull value to play more intense battle music a constant
23 * 11 8/01/99 2:06p Alanl
24 * tweak battle music track switching
26 * 10 7/25/99 9:57p Alanl
27 * change battle music track selection after enemy arrivals to make battle
28 * tracks less repetitive
30 * 9 7/19/99 10:13p Andsager
31 * Tie in hud_targeting to hostile_ships_present() used to determine next
34 * 8 6/24/99 10:47p Alanl
35 * loop battle between tracks 2 and 3 if hull integrity < 70%
37 * 7 6/21/99 1:34p Alanl
40 * 6 6/20/99 12:06a Alanl
41 * new event music changes
43 * 5 11/23/98 11:55a Johnson
44 * return -1 if a score isn't found
46 * 4 11/20/98 4:08p Dave
47 * Fixed flak effect in multiplayer.
49 * 3 10/23/98 3:51p Dave
50 * Full support for tstrings.tbl and foreign languages. All that remains
51 * is to make it active in Fred.
53 * 2 10/07/98 10:52a Dave
56 * 1 10/07/98 10:48a Dave
58 * 107 6/09/98 5:15p Lawrance
59 * French/German localization
61 * 106 6/09/98 10:31a Hoffoss
62 * Created index numbers for all xstr() references. Any new xstr() stuff
63 * added from here on out should be added to the end if the list. The
64 * current list count can be found in FreeSpace.cpp (search for
67 * 105 5/24/98 5:28p Dan
68 * let event_music_level_init() over-ride Event_music_enabled
70 * 104 5/24/98 4:42p Dan
71 * AL: Fix several bugs related to pausing and enabling/disabling event
74 * 103 5/23/98 3:17a Lawrance
75 * Tweak how battle music gets restarted
77 * 102 5/22/98 10:43a Lawrance
78 * If mission doesn't have event music, don't choose random track
80 * 101 5/21/98 6:56p Lawrance
81 * Tweak how victory music plays
83 * 100 5/21/98 2:47a Lawrance
84 * Fix some problems with event music
86 * 99 5/18/98 3:21p Mike
87 * Don't play arrival and goals tracks in a training mission.
89 * 98 5/04/98 3:15p Duncan
90 * AL: remove bogus assert in event_music_player_respawn()
92 * 97 5/03/98 1:54a Lawrance
93 * Fix event music problems related to respawning
95 * 96 4/03/98 12:56a Lawrance
96 * Fix bug with music not starting in the first mission
98 * 95 4/01/98 6:46p Lawrance
99 * Lower default music volume
106 #include "eventmusic.h"
109 #include "linklist.h"
110 #include "missionload.h" /* for Builtin_mission_names[] */
111 #include "missionparse.h"
113 #include "freespace.h"
114 #include "audiostr.h"
115 #include "missioncampaign.h"
119 #include "missiongoals.h"
120 #include "localize.h"
122 #pragma optimize("", off)
124 #define DEFAULT_MASTER_EVENT_MUSIC_VOLUME 0.5f
126 #define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
128 ////////////////////////////
130 ////////////////////////////
131 int Event_Music_battle_started = 0;
132 float Master_event_music_volume = DEFAULT_MASTER_EVENT_MUSIC_VOLUME; // range is 0->1
134 // array that holds which soundtrack is used for which mission (data comes from music.tbl)
135 //int Mission_soundtracks[MAX_CAMPAIGN_MISSIONS];
137 // array that holds which briefing track to play for which mission. Index into Spooled_music[][].
138 //int Mission_briefingmusic[MAX_CAMPAIGN_MISSIONS];
140 typedef struct tagSNDPATTERN {
141 int default_next_pattern; // Needed so the next_pattern member can be reset
142 int next_pattern; // Next pattern to play at loop time (can be same pattern)
143 int default_loop_for; // Needed so the loop_for variable can be reset
144 int loop_for; // Number of times to loop before switching to next pattern
145 int handle; // handle to open audio stream
146 int force_pattern; // flag to indicate that we want to not continue loop, but go to next_pattern
147 int can_force; // whether this pattern can be interrupted
148 int bytes_per_measure; // number of bytes in a measure
149 float num_measures; // number of measures in wave file
152 SNDPATTERN Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
154 // Holds filenames for the different sections of a soundtrack
155 SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
157 int Current_soundtrack_num; // Active soundtrack for the current mission.. index into Soundtracks[]
159 #define PATTERN_DELAY 1000 // in ms
160 int Current_pattern = -1; // currently playing part of track
161 int Pending_pattern = -1;
162 int Pattern_timer_id = 0;
165 static int Num_enemy_arrivals;
166 static int Num_friendly_arrivals;
168 #define ARRIVAL_INTERVAL_TIMESTAMP 5000
169 #define BATTLE_CHECK_INTERVAL 15000
170 static int Battle_over_timestamp;
171 static int Mission_over_timestamp;
172 static int Victory2_music_played;
173 static int Next_arrival_timestamp;
174 static int Check_for_battle_music;
176 // stores the number of measures for the different patterns (data from music.tbl)
177 float Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS];
179 // stores the number of bytes per measure (data from music.tbl)
180 int Pattern_bytes_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS];
182 char* Pattern_names[MAX_PATTERNS] =
185 "NRML_1", // Normal Song 1
186 "AARV_1", // Allied Arrival 1
187 "EARV_1", // Enemy Arrival 1
188 "BTTL_1", // Battle Song 1
189 "BTTL_2", // Battle Song 2
190 "BTTL_3", // Battle Song 3
191 "AARV_2", // Allied Arrival 2
192 "EARV_2", // Enemy Arrival 2
193 "VICT_1", // Victory Song 1
194 "VICT_2", // Victory Song 2
195 "FAIL_1" // Goal Failed 1
196 "DEAD_1" // Death Song 1
200 char* Pattern_description[MAX_PATTERNS] =
204 "friendly arrival 1",
209 "friendly arrival 2",
218 int Pattern_loop_for[MAX_PATTERNS] =
221 1, // Allied Arrival 1
222 1, // Enemy Arrival 1
226 1, // Allied Arrival 2
227 1, // Enemy Arrival 2
234 int Pattern_default_next[MAX_PATTERNS] =
236 SONG_NRML_1, // NRML_1 progresses to NRML_1 by default
237 SONG_NRML_1, // AARV_1 progresses to NRML_1 by default
238 SONG_BTTL_1, // EARV_1 progresses to BTTL_1 by default
239 SONG_BTTL_2, // BTTL_1 progresses to BTTL_2 by default
240 SONG_BTTL_3, // BTTL_2 progresses to BTTL_3 by default
241 SONG_BTTL_1, // BTTL_3 progresses to BTTL_1 by default
242 SONG_BTTL_2, // AARV_2 progresses to BTTL_2 by default
243 SONG_BTTL_3, // EARV_2 progresses to BTTL_3 by default
244 SONG_NRML_1, // VICT_1 progresses to NRML_1 by default
245 SONG_NRML_1, // VICT_2 progresses to NRML_1 by default
246 SONG_NRML_1, // FAIL_1 progresses to NRML_1 by default
247 -1 // no music plays after dead
251 // Certain patterns can be interrupted (such as the long-playing NRML and BTTL tracks).
252 // Other shorter tracks (such as arrivals) play their entire duration.
253 int Pattern_can_force[MAX_PATTERNS] =
270 int Event_music_enabled = TRUE;
271 static int Event_music_inited = FALSE;
272 static int Event_music_level_inited = FALSE;
273 static int Event_music_begun = FALSE;
275 // forward function declarations
276 int hostile_ships_present();
277 int hostile_ships_to_arrive();
278 extern int hud_target_invalid_awacs(object *objp);
280 // Holds file names of spooled music that is played at menus, briefings, credits etc.
281 // Indexed into by a #define enumeration of the different kinds of spooled music
282 menu_music Spooled_music[MAX_SPOOLED_MUSIC];
283 int Num_music_files; // Number of spooled music files
285 // Array that holds indicies into Spooled_music[], these specify which music is played in breifing/debriefing
286 int Mission_music[NUM_SCORES];
288 // -------------------------------------------------------------------------------------------------
289 // event_music_init()
291 // Called once at game start-up to parse music.tbl and set some state variables
293 void event_music_init()
295 if ( snd_is_inited() == FALSE ) {
296 Event_music_enabled = FALSE;
300 if ( Cmdline_freespace_no_music ) {
304 if ( Event_music_inited == TRUE )
307 event_music_parse_musictbl();
308 Event_music_inited = TRUE;
309 Event_music_begun = FALSE;
312 // -------------------------------------------------------------------------------------------------
313 // event_music_close()
315 // Called once at game end
317 void event_music_close()
319 if ( Event_music_inited == FALSE )
322 Event_music_inited = FALSE;
325 // -------------------------------------------------------------------------------------------------
326 // event_music_force_switch()
328 // Performs a switch between patterns. Sets the cutoff limit for the pattern that is being
331 void event_music_force_switch()
333 if ( Event_music_enabled == FALSE )
336 if ( Event_music_level_inited == FALSE )
340 Patterns[Current_pattern].loop_for = Patterns[Current_pattern].default_loop_for;
342 new_pattern = Patterns[Current_pattern].next_pattern;
344 if ( (new_pattern == SONG_BTTL_3) && (Patterns[SONG_BTTL_3].handle == -1) ) {
345 if ( Current_pattern == SONG_BTTL_2 ) {
346 new_pattern = SONG_BTTL_1;
348 new_pattern = SONG_BTTL_2;
351 if (Current_pattern == SONG_BTTL_3 && new_pattern == SONG_BTTL_1) {
352 // AL 06-24-99: maybe switch to battle 2 if hull is less than 70%
353 if (Player_obj != NULL && Player_ship != NULL) {
354 Assert(Player_ship->ship_info_index >= 0);
355 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
356 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
357 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
358 new_pattern = SONG_BTTL_2;
364 if ( new_pattern == -1 ) {
368 if ( Patterns[new_pattern].num_measures == 0 )
369 return; // invalid pattern
371 Assert(new_pattern >= 0 && new_pattern < MAX_PATTERNS);
372 audiostream_play(Patterns[new_pattern].handle, Master_event_music_volume, 0); // no looping
373 audiostream_set_byte_cutoff(Patterns[new_pattern].handle, fl2i(Patterns[new_pattern].num_measures * Patterns[new_pattern].bytes_per_measure) );
374 Patterns[Current_pattern].next_pattern = Patterns[Current_pattern].default_next_pattern;
375 Patterns[Current_pattern].force_pattern = FALSE;
376 nprintf(("EVENTMUSIC", "EVENTMUSIC => switching to %s from %s\n", Pattern_names[new_pattern], Pattern_names[Current_pattern]));
377 Current_pattern = new_pattern;
380 // -------------------------------------------------------------------------------------------------
381 // event_music_do_frame()
383 // Called once per game frame, to check for transitions of patterns (and to start the music off at
386 void event_music_do_frame()
388 if ( Event_music_level_inited == FALSE ) {
392 if ( Event_music_enabled == FALSE ) {
396 // start off the music delayed
397 if ( timestamp_elapsed(Pattern_timer_id) ) {
398 Pattern_timer_id = 0;
399 Event_music_begun = TRUE;
400 if ( Current_pattern != -1 ) {
401 Assert(Patterns[Current_pattern].handle >= 0 );
402 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
403 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
407 if ( Event_music_begun == FALSE ) {
411 if ( Current_pattern != -1 ) {
413 pat = &Patterns[Current_pattern];
415 // First case: switching to a different track since first track is almost at end
416 if ( audiostream_done_reading(pat->handle) ) {
417 event_music_force_switch();
419 // Second case: looping back to start of same track since at the end
420 else if ( !audiostream_is_playing(pat->handle) && !audiostream_is_paused(pat->handle) ) {
421 audiostream_stop(pat->handle); // stop current and rewind
423 if ( pat->loop_for > 0 ) {
424 audiostream_play(pat->handle, Master_event_music_volume, 0); // no looping
425 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
428 event_music_force_switch();
431 // Third case: switching to a different track by interruption
432 else if ( (pat->force_pattern == TRUE && pat->can_force == TRUE) ) {
433 int bytes_streamed = audiostream_get_bytes_committed(pat->handle);
434 int measures_played = bytes_streamed / pat->bytes_per_measure;
435 if ( measures_played < pat->num_measures ) {
436 audiostream_set_byte_cutoff(pat->handle, pat->bytes_per_measure * (measures_played+1) );
437 pat->force_pattern = FALSE;
442 // We want to go back to NRML track music if all the hostiles have been
443 // destroyed, and we are still playing the battle music
444 if ( Current_pattern == SONG_BTTL_1 || Current_pattern == SONG_BTTL_2 || Current_pattern == SONG_BTTL_3 ) {
445 if ( timestamp_elapsed(Battle_over_timestamp) && Event_Music_battle_started == 1) {
446 //Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
447 if ( hostile_ships_present() == FALSE ) {
448 if ( Patterns[Current_pattern].next_pattern != SONG_VICT_2 ) {
449 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
450 Patterns[Current_pattern].force_pattern = TRUE;
451 Event_Music_battle_started = 0;
457 if (Event_Music_battle_started == 0) {
458 if (Current_pattern == SONG_NRML_1) {
459 if (timestamp_elapsed(Check_for_battle_music)) {
460 Check_for_battle_music = timestamp(1000);
461 if (hostile_ships_present() == TRUE) {
462 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
463 Patterns[Current_pattern].force_pattern = TRUE;
469 if ( !Victory2_music_played ) {
470 if ( timestamp_elapsed(Mission_over_timestamp) ) {
471 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
472 if ( mission_goals_met() && (!hostile_ships_present()) ) {
473 Patterns[Current_pattern].next_pattern = SONG_VICT_2;
474 Patterns[Current_pattern].force_pattern = TRUE;
475 Victory2_music_played = 1;
482 // -------------------------------------------------------------------------------------------------
483 // event_music_level_init()
485 // Called at the start of a mission (level). Sets up the pattern data, and kicks off the
486 // first track to play().
488 // input: force_soundtrack => OPTIONAL parameter (default value -1)
489 // forces the soundtrack to ignore the music.tbl assignment
491 void event_music_level_init(int force_soundtrack)
494 SOUNDTRACK_INFO *strack;
496 if ( Cmdline_freespace_no_music ) {
500 if ( !audiostream_is_inited() )
503 if ( Event_music_level_inited == TRUE )
506 Current_pattern = -1;
508 if ( Event_music_inited == FALSE )
512 if ( force_soundtrack != -1 ) {
513 Current_soundtrack_num = force_soundtrack;
516 if ( Current_soundtrack_num < 0 ) {
519 // okay, assign a random soundtrack if one exists
520 if ( Num_soundtracks > 0 ) {
521 Current_soundtrack_num = rand()%Num_soundtracks;
522 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Picking random event music soundtrack: %s\n", Soundtracks[Current_soundtrack_num].name));
529 Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < Num_soundtracks);
530 strack = &Soundtracks[Current_soundtrack_num];
532 // open the pattern files, and get ready to play them
533 for ( i = 0; i < strack->num_patterns; i++ ) {
534 if ( !stricmp(NOX("none.wav"), strack->pattern_fnames[i]) ) {
535 Patterns[i].handle = -1;
539 Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
541 if ( Patterns[i].handle >= 0 ) {
542 Event_music_level_inited = TRUE;
543 Event_music_enabled = TRUE;
546 Patterns[i].next_pattern = Pattern_default_next[i];
547 Patterns[i].default_next_pattern = Pattern_default_next[i];
548 Patterns[i].loop_for = Pattern_loop_for[i];
549 Patterns[i].default_loop_for = Pattern_loop_for[i];
550 Patterns[i].force_pattern = FALSE;
551 Patterns[i].can_force = Pattern_can_force[i];
552 Patterns[i].bytes_per_measure = Pattern_bytes_per_measure[Current_soundtrack_num][i];
553 Patterns[i].num_measures = Pattern_num_measures[Current_soundtrack_num][i];
556 Num_enemy_arrivals = 0;
557 Num_friendly_arrivals = 0;
558 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
559 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
560 Next_arrival_timestamp = timestamp(1);
561 Victory2_music_played = 0;
562 Check_for_battle_music = 0;
564 if ( Event_music_level_inited ) {
565 if ( force_soundtrack != -1 ) {
566 event_music_first_pattern();
571 // -------------------------------------------------------------------------------------------------
572 // event_music_first_pattern()
574 // Picks the first pattern to play, based on whether the battle has started. Delay start
577 void event_music_first_pattern()
579 if ( Event_music_inited == FALSE ) {
583 if ( Event_music_enabled == FALSE ) {
587 if ( Event_music_level_inited == FALSE ) {
588 event_music_level_init();
591 if ( Event_music_level_inited == FALSE ) {
595 if ( Event_music_begun == TRUE ) {
599 if ( Current_pattern != -1 ) {
600 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
601 audiostream_stop( Patterns[Current_pattern].handle );
604 Pattern_timer_id = 2000; // start music delay
606 Event_music_begun = FALSE;
607 if ( Event_Music_battle_started == TRUE ) {
608 Current_pattern = SONG_BTTL_1;
611 Current_pattern = SONG_NRML_1;
615 // -------------------------------------------------------------------------------------------------
616 // event_music_level_close()
618 // Called at the end of each mission (level). Stops any playing patterns by fading them out.
620 void event_music_level_close()
624 if ( Event_music_level_inited == FALSE )
627 if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS ) {
628 SOUNDTRACK_INFO *strack;
630 Assert( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS );
631 strack = &Soundtracks[Current_soundtrack_num];
633 // close the pattern files
634 for ( i = 0; i < strack->num_patterns; i++ ) {
635 if ( i == Current_pattern ) {
636 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
637 audiostream_close_file( Patterns[i].handle );
639 audiostream_close_file( Patterns[i].handle, 0 );
642 audiostream_close_file( Patterns[i].handle, 0 );
645 // close em all down then
646 audiostream_close_all(0);
649 Current_pattern = -1;
650 Event_music_level_inited = FALSE;
651 Event_Music_battle_started = FALSE;
652 Event_music_enabled = 0;
653 Event_music_begun = FALSE;
656 // -------------------------------------------------------------------------------------------------
657 // event_music_battle_start()
659 // Start the battle music. If the music is already started before, do nothing.
661 int event_music_battle_start()
663 if ( !hostile_ships_present() ) {
667 // No special tracks in training.
668 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
671 // Check to see if we've already started off the battle song
672 if ( Event_Music_battle_started == 1 ) {
676 if ( Event_music_enabled == FALSE )
679 if ( Event_music_level_inited == FALSE )
682 if ( Current_pattern == SONG_BTTL_1 )
683 return 0; // already playing
685 if ( Current_pattern == SONG_DEAD_1 )
686 return 0; // death is the last song to play
688 if ( Current_pattern != -1 ) {
689 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
690 Patterns[Current_pattern].force_pattern = TRUE;
693 Event_Music_battle_started = 1; // keep track of this state though, need on restore
694 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
699 // -------------------------------------------------------------------------------------------------
700 // event_music_enemy_arrival()
702 // An enemy has arrived, play an enemy arrival pattern.
704 int event_music_enemy_arrival()
706 if ( Event_music_enabled == FALSE ) {
710 if ( Event_music_level_inited == FALSE ) {
715 if ( Event_Music_battle_started == TRUE ) {
716 next_pattern = SONG_EARV_2;
719 next_pattern = SONG_EARV_1;
722 if ( Current_pattern == next_pattern )
723 return 0; // already playing
725 if ( Current_pattern == SONG_DEAD_1 )
726 return 0; // death is the last song to play
728 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
731 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
732 return 0; // don't squash a pending pattern
734 Num_enemy_arrivals++;
736 // AL 7-25-99: If hull is less than 70% then switch to battle 2 or 3, otherwise switch to 1 or 2
737 bool play_intense_battle_music = false;
738 if (Player_obj != NULL && Player_ship != NULL) {
739 Assert(Player_ship->ship_info_index >= 0);
740 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
741 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
742 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
743 play_intense_battle_music = true;
747 if (play_intense_battle_music == true) {
748 if (Current_pattern == SONG_BTTL_2) {
749 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
751 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
754 if (Current_pattern == SONG_BTTL_1) {
755 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
756 } else if (Current_pattern == SONG_BTTL_2) {
757 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
759 Patterns[next_pattern].next_pattern = SONG_BTTL_1;
765 // Alternate between BTTL_2 and BTTL_3 following enemy arrivals
766 if ( Num_enemy_arrivals & 1 ) {
767 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
769 if ( Patterns[SONG_BTTL_3].handle != -1 ) {
770 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
772 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
777 if ( Current_pattern != -1 ) {
778 Patterns[Current_pattern].next_pattern = next_pattern;
779 Patterns[Current_pattern].force_pattern = TRUE;
782 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
787 // -------------------------------------------------------------------------------------------------
788 // event_music_friendly_arrival()
790 // An friendly has arrived, play a friendly arrival pattern.
792 int event_music_friendly_arrival()
794 if ( Event_music_enabled == FALSE )
797 if ( Event_music_level_inited == FALSE )
800 if (timestamp_elapsed(Next_arrival_timestamp) == false) {
805 if ( Event_Music_battle_started == TRUE ) {
806 next_pattern = SONG_AARV_2;
809 next_pattern = SONG_AARV_1;
812 if ( Current_pattern == next_pattern )
813 return 0; // already playing
815 if ( Current_pattern == SONG_DEAD_1 )
816 return 0; // death is the last song to play
818 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
821 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
822 return 0; // don't squash a pending pattern
824 // After the second friendly arrival, default to SONG_BTTL_3
825 Num_friendly_arrivals++;
827 if ( Current_pattern != -1 ) {
828 // AL 06-24-99: always overlay allied arrivals
830 if (next_pattern == SONG_AARV_1) {
831 Patterns[Current_pattern].next_pattern = next_pattern;
832 Patterns[Current_pattern].force_pattern = TRUE;
835 Assert(Patterns[SONG_AARV_1].handle >= 0 );
836 audiostream_play(Patterns[SONG_AARV_1].handle, Master_event_music_volume, 0); // no looping
837 audiostream_set_byte_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].bytes_per_measure) );
841 Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
843 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
848 // Play arrival music keyed to team "team".
849 void event_music_arrival(int team)
851 // No friendly arrival music in a training mission.
852 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
855 if ( Player_ship->team == team ) {
856 event_music_friendly_arrival();
858 event_music_enemy_arrival();
862 // -------------------------------------------------------------------------------------------------
863 // event_music_primary_goals_met()
865 // A primary goal has failed
867 int event_music_primary_goal_failed()
871 // No special tracks in training.
872 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
875 if ( Event_music_enabled == FALSE )
878 if ( Event_music_level_inited == FALSE )
881 if ( Current_pattern == SONG_DEAD_1 )
882 return 0; // death is the last song to play
884 if ( Patterns[SONG_FAIL_1].handle < 0 ) // can't play if music file doesn't exist
887 if ( hostile_ships_present() ) {
888 next_pattern = SONG_BTTL_1;
891 next_pattern = SONG_NRML_1;
892 Event_Music_battle_started = 0;
895 if ( Current_pattern != -1 ) {
896 Patterns[Current_pattern].next_pattern = next_pattern;
897 Patterns[Current_pattern].force_pattern = TRUE;
903 // -------------------------------------------------------------------------------------------------
904 // event_music_primary_goals_met()
906 // A goal has been achieved, play the appropriate victory music.
908 int event_music_primary_goals_met()
910 int next_pattern = SONG_VICT_1;
912 // No special tracks in training.
913 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
916 if ( Event_music_enabled == FALSE )
919 if ( Event_music_level_inited == FALSE )
922 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_2) )
923 return 0; // already playing
925 if ( Current_pattern == SONG_DEAD_1 )
926 return 0; // death is the last song to play
928 if ( hostile_ships_present() ) {
929 Patterns[SONG_VICT_1].next_pattern = SONG_BTTL_1;
932 Patterns[SONG_VICT_1].next_pattern = SONG_VICT_2;
933 Event_Music_battle_started = 0;
935 // If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
936 // to the next default track
937 if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
938 Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
940 Victory2_music_played = 1;
944 if ( Current_pattern != -1 ) {
945 Patterns[Current_pattern].next_pattern = next_pattern;
946 Patterns[Current_pattern].force_pattern = TRUE;
952 // -------------------------------------------------------------------------------------------------
953 // event_music_player_death()
955 // The player has died, play death pattern.
957 int event_music_player_death()
959 if ( Event_music_enabled == FALSE )
962 if ( Event_music_level_inited == FALSE )
965 if ( Current_pattern == SONG_DEAD_1 )
966 return 0; // already playing
968 if ( Current_pattern != -1 ) {
969 Patterns[Current_pattern].next_pattern = SONG_DEAD_1;
970 Patterns[Current_pattern].force_pattern = TRUE;
976 // -------------------------------------------------------------------------------------------------
977 // event_music_player_respawn()
979 // Player has respawned (multiplayer only)
981 int event_music_player_respawn()
983 if ( Event_music_enabled == FALSE )
986 if ( Event_music_level_inited == FALSE )
989 // Assert(Current_pattern == SONG_DEAD_1);
991 Event_Music_battle_started = 0;
992 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
993 Patterns[Current_pattern].force_pattern = TRUE;
998 // -------------------------------------------------------------------------------------------------
999 // event_music_player_respawn_as_observer()
1001 // Player has respawned (multiplayer only)
1003 int event_music_player_respawn_as_observer()
1005 if ( Event_music_enabled == FALSE )
1008 if ( Event_music_level_inited == FALSE )
1011 if ( Current_pattern >= 0 ) {
1012 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1013 audiostream_stop(Patterns[Current_pattern].handle);
1014 Current_pattern = -1;
1021 // -------------------------------------------------------------------------------------------------
1022 // event_music_parse_musictbl() will parse the music.tbl file, and set up the Mission_songs[]
1025 void event_music_parse_musictbl()
1027 char fname[MAX_FILENAME_LEN];
1031 int num_patterns = 0;
1033 Num_music_files = 0;
1034 Num_soundtracks = 0; // Global
1035 event_music_reset_choices();
1037 if ((rval = setjmp(parse_abort)) != 0) {
1038 Error(LOCATION, "Unable to parse music.tbl! Code = %i.\n", rval);
1041 // open localization
1044 read_file_text("music.tbl");
1047 // Loop through all the sound-tracks
1048 while (required_string_either("#Menu Music Start","#SoundTrack Start")) {
1049 Assert(Num_soundtracks < MAX_SOUNDTRACKS);
1050 required_string("#SoundTrack Start");
1051 required_string("$SoundTrack Name:");
1052 stuff_string(Soundtracks[Num_soundtracks].name, F_NAME, NULL);
1053 while (required_string_either("#SoundTrack End","$Name:")) {
1054 Assert( num_patterns < MAX_PATTERNS );
1055 required_string("$Name:");
1056 stuff_string(line_buf, F_NAME, NULL);
1058 // line_buf holds 3 fields: filename, num measures, bytes per measure
1062 token = strtok( line_buf, NOX(" ,\t"));
1063 strcpy(fname, token);
1064 while ( token != NULL ) {
1065 token = strtok( NULL, NOX(" ,\t") );
1066 if ( token == NULL ) {
1067 Assert(count == 2 );
1072 Pattern_num_measures[Num_soundtracks][num_patterns] = (float)atof(token);
1075 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] = atoi(token);
1081 // convert from samples per measure to bytes per measure
1082 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] *= 2;
1083 strcpy(Soundtracks[Num_soundtracks].pattern_fnames[num_patterns], fname);
1087 required_string("#SoundTrack End");
1088 Soundtracks[Num_soundtracks].num_patterns = num_patterns;
1093 // Parse the menu music section
1094 required_string("#Menu Music Start");
1095 while (required_string_either("#Menu Music End","$Name:")) {
1096 Assert( Num_music_files < MAX_SPOOLED_MUSIC );
1098 required_string("$Name:");
1099 stuff_string(fname, F_PATHNAME, NULL);
1100 Assert( strlen(fname) < (NAME_LENGTH-1) );
1101 strcpy( Spooled_music[Num_music_files].name, fname );
1103 required_string("$Filename:");
1104 stuff_string(fname, F_PATHNAME, NULL);
1105 if ( stricmp(fname, NOX("none.wav")) ) {
1106 Assert( strlen(fname) < (MAX_FILENAME_LEN-1) );
1107 strcpy( Spooled_music[Num_music_files].filename, fname );
1113 required_string("#Menu Music End");
1115 // close localization
1120 // -------------------------------------------------------------------------------------------------
1121 // event_music_change_pattern()
1123 // Force a particular pattern to play. This is used for debugging purposes.
1125 void event_music_change_pattern(int new_pattern)
1127 if ( Event_music_enabled == FALSE ) {
1128 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1132 if ( Event_music_level_inited == FALSE ) {
1133 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1137 if ( Current_pattern == new_pattern )
1138 return; // already playing
1140 if ( Current_pattern != -1 ) {
1141 Patterns[Current_pattern].next_pattern = new_pattern;
1142 Patterns[Current_pattern].force_pattern = TRUE;
1146 // -------------------------------------------------------------------------------------------------
1147 // event_music_return_current_pattern()
1149 // Simply return what the current pattern being played is. Don't want to make global.
1151 int event_music_return_current_pattern()
1153 return Current_pattern;
1156 // -------------------------------------------------------------------------------------------------
1157 // event_music_disable()
1159 // Stop any patterns that are playing, and prevent any further patterns from playing (ie
1160 // set Event_music_enabled = FALSE). We don't uninit event music, since it might be toggled
1161 // back on this level.
1163 void event_music_disable()
1165 if ( Event_music_level_inited == FALSE )
1168 if ( Event_music_enabled == FALSE )
1171 if (Current_pattern == -1)
1174 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1175 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1176 audiostream_stop(Patterns[Current_pattern].handle); // stop current and rewind
1179 Event_music_begun = FALSE;
1180 Event_music_enabled = FALSE;
1181 Current_pattern = -1;
1184 // -------------------------------------------------------------------------------------------------
1185 // event_music_enable()
1187 // Init the event music (ie load the patterns) if required. Set up the first song to play, and
1188 // set Event_music_enabled = TRUE to allow patterns to play.
1190 void event_music_enable()
1192 if ( Event_music_enabled == TRUE )
1195 Event_music_enabled = TRUE;
1197 if ( Event_music_level_inited == FALSE ) {
1198 event_music_level_init();
1199 // start the first pattern to play (delayed)
1200 if ( Game_mode & GM_IN_MISSION ) {
1201 event_music_first_pattern();
1205 // start a new pattern
1206 Event_music_begun = FALSE;
1207 Pattern_timer_id = timestamp(150);
1208 event_music_start_default();
1212 // -------------------------------------------------------------------------------------------------
1213 // event_music_start_default()
1215 // Start playing a default track, based on how far the mission has progressed
1217 void event_music_start_default()
1221 if ( Event_Music_battle_started == TRUE ) {
1222 if ( hostile_ships_present() ) {
1223 next_pattern = SONG_BTTL_1;
1226 Event_Music_battle_started = FALSE;
1227 next_pattern = SONG_NRML_1;
1231 next_pattern = SONG_NRML_1;
1233 if ( Current_pattern == -1 ) {
1234 Current_pattern = next_pattern;
1237 Patterns[Current_pattern].next_pattern = next_pattern;
1238 Patterns[Current_pattern].force_pattern = TRUE;
1243 // -------------------------------------------------------------------------------------------------
1244 // event_music_pause()
1246 // Stop any playing pattern, but don't rewind.
1248 void event_music_pause()
1250 if ( Event_music_enabled == FALSE ) {
1251 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1255 if ( Event_music_level_inited == FALSE ) {
1256 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1260 if (Current_pattern == -1)
1263 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1264 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1265 audiostream_stop(Patterns[Current_pattern].handle, 0); // stop current and don't rewind
1269 // -------------------------------------------------------------------------------------------------
1270 // event_music_unpause()
1272 // Start the Current_pattern if it is paused.
1274 void event_music_unpause()
1276 if ( Event_music_enabled == FALSE ) {
1277 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1281 if ( Event_music_level_inited == FALSE ) {
1282 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1286 if (Current_pattern == -1)
1289 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1290 if ( audiostream_is_paused(Patterns[Current_pattern].handle) == TRUE ) {
1291 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
1292 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
1296 // -------------------------------------------------------------------------------------------------
1297 // event_music_set_volume_all()
1299 // Set the volume of the event driven music. Used when using the game-wide music volume is changed
1302 void event_music_set_volume_all(float volume)
1304 audiostream_set_volume_all(volume, ASF_EVENTMUSIC);
1307 // ----------------------------------------------------------------------
1308 // hostile_ships_present()
1310 // Determine if there are any non-friendly ships in existance
1312 // returns: 1 => there are non-friendly ships in existance
1313 // 0 => any ships in existance are friendly
1314 int hostile_ships_present()
1319 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1320 shipp = &Ships[Objects[so->objnum].instance];
1322 // check if ship if enemy ship
1323 if ( (shipp->team == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR) )
1326 // check if ship is threatening
1327 if ( (shipp->flags & (SF_DISABLED|SF_DYING|SF_DEPARTING)) || (ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE)) )
1330 // check if ship is flyable
1331 if ( Ship_info[shipp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
1335 // check if ship is visible by player's team
1336 if ( hud_target_invalid_awacs(&Objects[so->objnum]) == 1 ) {
1345 // ----------------------------------------------------------------------
1346 // hostile_ships_to_arrive()
1348 // Determine if there are any non-friendly ships yet to arrive
1350 // NOTE: neutral ships are considered hostile for the purpose of event music
1352 int hostile_ships_to_arrive()
1356 p_objp = GET_FIRST(&ship_arrival_list);
1357 while( p_objp != END_OF_LIST(&ship_arrival_list) ) {
1358 if ( (p_objp->team != Player_ship->team) && !(p_objp->flags & P_SF_CANNOT_ARRIVE) ) {
1361 p_objp = GET_NEXT(p_objp);
1366 // ----------------------------------------------------------------
1367 // event_music_get_info()
1369 // Return information about the event music in the buffer outbuf
1370 // NOTE: callers to this function are advised to allocate a 256 byte buffer
1371 void event_music_get_info(char *outbuf)
1373 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
1374 sprintf(outbuf,XSTR( "Event music is not playing", 213));
1377 sprintf(outbuf,XSTR( "soundtrack: %s [%s]", 214), Soundtracks[Current_soundtrack_num].name, Pattern_description[Current_pattern]);
1381 // ----------------------------------------------------------------
1382 // event_music_next_soundtrack()
1384 // input: delta => 1 or -1, depending if you want to go to next or previous song
1386 // returns: New soundtrack number if successfully changed, otherwise return -1
1388 int event_music_next_soundtrack(int delta)
1392 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1396 new_soundtrack = Current_soundtrack_num + delta;
1397 if ( new_soundtrack >= Num_soundtracks )
1400 event_music_level_close();
1401 event_music_level_init(new_soundtrack);
1403 return Current_soundtrack_num;
1406 // ----------------------------------------------------------------
1407 // event_music_get_soundtrack_name()
1409 // Return information about the event music in the buffer outbuf
1410 // NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
1411 void event_music_get_soundtrack_name(char *outbuf)
1413 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1414 strcpy(outbuf, XSTR( "Event music is not playing", 213));
1417 sprintf(outbuf, Soundtracks[Current_soundtrack_num].name);
1421 // set the current soundtrack based on name
1422 void event_music_set_soundtrack(char *name)
1426 // find the correct index for the event music
1427 for ( i = 0; i < Num_soundtracks; i++ ) {
1428 if ( !stricmp(name, Soundtracks[i].name) ) {
1429 Current_soundtrack_num = i;
1434 if ( i == Num_soundtracks ) {
1435 Current_soundtrack_num = -1;
1436 mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
1440 int event_music_get_spooled_music_index(char *name)
1442 // find the correct index for the event music
1443 for ( int i = 0; i < Num_music_files; i++ ) {
1444 if ( !stricmp(name, Spooled_music[i].name) ) {
1452 // set a score based on name
1453 void event_music_set_score(int score_index, char *name)
1455 Assert(score_index < NUM_SCORES);
1457 // find the correct index for the event music
1458 Mission_music[score_index] = event_music_get_spooled_music_index(name);
1461 // reset what sort of music is to be used for this mission
1462 void event_music_reset_choices()
1464 Current_soundtrack_num = -1;
1465 mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
1466 Mission_music[SCORE_BRIEFING] = -1;
1467 event_music_set_score(SCORE_DEBRIEF_SUCCESS, "Success");
1468 event_music_set_score(SCORE_DEBRIEF_AVERAGE, "Average");
1469 event_music_set_score(SCORE_DEBRIEF_FAIL, "Failure");
1470 //Mission_music[SCORE_DEBRIEF_SUCCESS] = MUSIC_DEBRIEF_SUCCESS_1;
1471 //Mission_music[SCORE_DEBRIEF_FAIL] = MUSIC_DEBRIEF_FAIL_1;
1474 void event_music_hostile_ship_destroyed()
1476 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
1480 #pragma optimize("", on)