2 * $Logfile: /Freespace2/code/Gamesnd/EventMusic.cpp $
7 * C module for high-level control of event driven music
10 * Revision 1.2 2002/05/07 03:16:45 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:09 root
17 * 14 8/19/99 9:41a Alanl
18 * don't play victory 2 music if there are no goals in the mission
20 * 13 8/11/99 5:33p Jefff
21 * added 3rd debrief music track
23 * 12 8/01/99 2:11p Alanl
24 * make hull value to play more intense battle music a constant
26 * 11 8/01/99 2:06p Alanl
27 * tweak battle music track switching
29 * 10 7/25/99 9:57p Alanl
30 * change battle music track selection after enemy arrivals to make battle
31 * tracks less repetitive
33 * 9 7/19/99 10:13p Andsager
34 * Tie in hud_targeting to hostile_ships_present() used to determine next
37 * 8 6/24/99 10:47p Alanl
38 * loop battle between tracks 2 and 3 if hull integrity < 70%
40 * 7 6/21/99 1:34p Alanl
43 * 6 6/20/99 12:06a Alanl
44 * new event music changes
46 * 5 11/23/98 11:55a Johnson
47 * return -1 if a score isn't found
49 * 4 11/20/98 4:08p Dave
50 * Fixed flak effect in multiplayer.
52 * 3 10/23/98 3:51p Dave
53 * Full support for tstrings.tbl and foreign languages. All that remains
54 * is to make it active in Fred.
56 * 2 10/07/98 10:52a Dave
59 * 1 10/07/98 10:48a Dave
61 * 107 6/09/98 5:15p Lawrance
62 * French/German localization
64 * 106 6/09/98 10:31a Hoffoss
65 * Created index numbers for all xstr() references. Any new xstr() stuff
66 * added from here on out should be added to the end if the list. The
67 * current list count can be found in FreeSpace.cpp (search for
70 * 105 5/24/98 5:28p Dan
71 * let event_music_level_init() over-ride Event_music_enabled
73 * 104 5/24/98 4:42p Dan
74 * AL: Fix several bugs related to pausing and enabling/disabling event
77 * 103 5/23/98 3:17a Lawrance
78 * Tweak how battle music gets restarted
80 * 102 5/22/98 10:43a Lawrance
81 * If mission doesn't have event music, don't choose random track
83 * 101 5/21/98 6:56p Lawrance
84 * Tweak how victory music plays
86 * 100 5/21/98 2:47a Lawrance
87 * Fix some problems with event music
89 * 99 5/18/98 3:21p Mike
90 * Don't play arrival and goals tracks in a training mission.
92 * 98 5/04/98 3:15p Duncan
93 * AL: remove bogus assert in event_music_player_respawn()
95 * 97 5/03/98 1:54a Lawrance
96 * Fix event music problems related to respawning
98 * 96 4/03/98 12:56a Lawrance
99 * Fix bug with music not starting in the first mission
101 * 95 4/01/98 6:46p Lawrance
102 * Lower default music volume
109 #include "eventmusic.h"
112 #include "linklist.h"
113 #include "missionload.h" /* for Builtin_mission_names[] */
114 #include "missionparse.h"
116 #include "freespace.h"
117 #include "audiostr.h"
118 #include "missioncampaign.h"
122 #include "missiongoals.h"
123 #include "localize.h"
125 #pragma optimize("", off)
127 #define DEFAULT_MASTER_EVENT_MUSIC_VOLUME 0.5f
129 #define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
131 ////////////////////////////
133 ////////////////////////////
134 int Event_Music_battle_started = 0;
135 float Master_event_music_volume = DEFAULT_MASTER_EVENT_MUSIC_VOLUME; // range is 0->1
137 // array that holds which soundtrack is used for which mission (data comes from music.tbl)
138 //int Mission_soundtracks[MAX_CAMPAIGN_MISSIONS];
140 // array that holds which briefing track to play for which mission. Index into Spooled_music[][].
141 //int Mission_briefingmusic[MAX_CAMPAIGN_MISSIONS];
143 typedef struct tagSNDPATTERN {
144 int default_next_pattern; // Needed so the next_pattern member can be reset
145 int next_pattern; // Next pattern to play at loop time (can be same pattern)
146 int default_loop_for; // Needed so the loop_for variable can be reset
147 int loop_for; // Number of times to loop before switching to next pattern
148 int handle; // handle to open audio stream
149 int force_pattern; // flag to indicate that we want to not continue loop, but go to next_pattern
150 int can_force; // whether this pattern can be interrupted
151 int bytes_per_measure; // number of bytes in a measure
152 float num_measures; // number of measures in wave file
155 SNDPATTERN Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
157 // Holds filenames for the different sections of a soundtrack
158 SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
160 int Current_soundtrack_num; // Active soundtrack for the current mission.. index into Soundtracks[]
162 #define PATTERN_DELAY 1000 // in ms
163 int Current_pattern = -1; // currently playing part of track
164 int Pending_pattern = -1;
165 int Pattern_timer_id = 0;
168 static int Num_enemy_arrivals;
169 static int Num_friendly_arrivals;
171 #define ARRIVAL_INTERVAL_TIMESTAMP 5000
172 #define BATTLE_CHECK_INTERVAL 15000
173 static int Battle_over_timestamp;
174 static int Mission_over_timestamp;
175 static int Victory2_music_played;
176 static int Next_arrival_timestamp;
177 static int Check_for_battle_music;
179 // stores the number of measures for the different patterns (data from music.tbl)
180 float Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS];
182 // stores the number of bytes per measure (data from music.tbl)
183 int Pattern_bytes_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS];
185 char* Pattern_names[MAX_PATTERNS] =
188 "NRML_1", // Normal Song 1
189 "AARV_1", // Allied Arrival 1
190 "EARV_1", // Enemy Arrival 1
191 "BTTL_1", // Battle Song 1
192 "BTTL_2", // Battle Song 2
193 "BTTL_3", // Battle Song 3
194 "AARV_2", // Allied Arrival 2
195 "EARV_2", // Enemy Arrival 2
196 "VICT_1", // Victory Song 1
197 "VICT_2", // Victory Song 2
198 "FAIL_1" // Goal Failed 1
199 "DEAD_1" // Death Song 1
203 char* Pattern_description[MAX_PATTERNS] =
207 "friendly arrival 1",
212 "friendly arrival 2",
221 int Pattern_loop_for[MAX_PATTERNS] =
224 1, // Allied Arrival 1
225 1, // Enemy Arrival 1
229 1, // Allied Arrival 2
230 1, // Enemy Arrival 2
237 int Pattern_default_next[MAX_PATTERNS] =
239 SONG_NRML_1, // NRML_1 progresses to NRML_1 by default
240 SONG_NRML_1, // AARV_1 progresses to NRML_1 by default
241 SONG_BTTL_1, // EARV_1 progresses to BTTL_1 by default
242 SONG_BTTL_2, // BTTL_1 progresses to BTTL_2 by default
243 SONG_BTTL_3, // BTTL_2 progresses to BTTL_3 by default
244 SONG_BTTL_1, // BTTL_3 progresses to BTTL_1 by default
245 SONG_BTTL_2, // AARV_2 progresses to BTTL_2 by default
246 SONG_BTTL_3, // EARV_2 progresses to BTTL_3 by default
247 SONG_NRML_1, // VICT_1 progresses to NRML_1 by default
248 SONG_NRML_1, // VICT_2 progresses to NRML_1 by default
249 SONG_NRML_1, // FAIL_1 progresses to NRML_1 by default
250 -1 // no music plays after dead
254 // Certain patterns can be interrupted (such as the long-playing NRML and BTTL tracks).
255 // Other shorter tracks (such as arrivals) play their entire duration.
256 int Pattern_can_force[MAX_PATTERNS] =
273 int Event_music_enabled = TRUE;
274 static int Event_music_inited = FALSE;
275 static int Event_music_level_inited = FALSE;
276 static int Event_music_begun = FALSE;
278 // forward function declarations
279 int hostile_ships_present();
280 int hostile_ships_to_arrive();
281 extern int hud_target_invalid_awacs(object *objp);
283 // Holds file names of spooled music that is played at menus, briefings, credits etc.
284 // Indexed into by a #define enumeration of the different kinds of spooled music
285 menu_music Spooled_music[MAX_SPOOLED_MUSIC];
286 int Num_music_files; // Number of spooled music files
288 // Array that holds indicies into Spooled_music[], these specify which music is played in breifing/debriefing
289 int Mission_music[NUM_SCORES];
291 // -------------------------------------------------------------------------------------------------
292 // event_music_init()
294 // Called once at game start-up to parse music.tbl and set some state variables
296 void event_music_init()
298 if ( snd_is_inited() == FALSE ) {
299 Event_music_enabled = FALSE;
303 if ( Cmdline_freespace_no_music ) {
307 if ( Event_music_inited == TRUE )
310 event_music_parse_musictbl();
311 Event_music_inited = TRUE;
312 Event_music_begun = FALSE;
315 // -------------------------------------------------------------------------------------------------
316 // event_music_close()
318 // Called once at game end
320 void event_music_close()
322 if ( Event_music_inited == FALSE )
325 Event_music_inited = FALSE;
328 // -------------------------------------------------------------------------------------------------
329 // event_music_force_switch()
331 // Performs a switch between patterns. Sets the cutoff limit for the pattern that is being
334 void event_music_force_switch()
336 if ( Event_music_enabled == FALSE )
339 if ( Event_music_level_inited == FALSE )
343 Patterns[Current_pattern].loop_for = Patterns[Current_pattern].default_loop_for;
345 new_pattern = Patterns[Current_pattern].next_pattern;
347 if ( (new_pattern == SONG_BTTL_3) && (Patterns[SONG_BTTL_3].handle == -1) ) {
348 if ( Current_pattern == SONG_BTTL_2 ) {
349 new_pattern = SONG_BTTL_1;
351 new_pattern = SONG_BTTL_2;
354 if (Current_pattern == SONG_BTTL_3 && new_pattern == SONG_BTTL_1) {
355 // AL 06-24-99: maybe switch to battle 2 if hull is less than 70%
356 if (Player_obj != NULL && Player_ship != NULL) {
357 Assert(Player_ship->ship_info_index >= 0);
358 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
359 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
360 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
361 new_pattern = SONG_BTTL_2;
367 if ( new_pattern == -1 ) {
371 if ( Patterns[new_pattern].num_measures == 0 )
372 return; // invalid pattern
374 Assert(new_pattern >= 0 && new_pattern < MAX_PATTERNS);
375 audiostream_play(Patterns[new_pattern].handle, Master_event_music_volume, 0); // no looping
376 audiostream_set_byte_cutoff(Patterns[new_pattern].handle, fl2i(Patterns[new_pattern].num_measures * Patterns[new_pattern].bytes_per_measure) );
377 Patterns[Current_pattern].next_pattern = Patterns[Current_pattern].default_next_pattern;
378 Patterns[Current_pattern].force_pattern = FALSE;
379 nprintf(("EVENTMUSIC", "EVENTMUSIC => switching to %s from %s\n", Pattern_names[new_pattern], Pattern_names[Current_pattern]));
380 Current_pattern = new_pattern;
383 // -------------------------------------------------------------------------------------------------
384 // event_music_do_frame()
386 // Called once per game frame, to check for transitions of patterns (and to start the music off at
389 void event_music_do_frame()
391 if ( Event_music_level_inited == FALSE ) {
395 if ( Event_music_enabled == FALSE ) {
399 // start off the music delayed
400 if ( timestamp_elapsed(Pattern_timer_id) ) {
401 Pattern_timer_id = 0;
402 Event_music_begun = TRUE;
403 if ( Current_pattern != -1 ) {
404 Assert(Patterns[Current_pattern].handle >= 0 );
405 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
406 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
410 if ( Event_music_begun == FALSE ) {
414 if ( Current_pattern != -1 ) {
416 pat = &Patterns[Current_pattern];
418 // First case: switching to a different track since first track is almost at end
419 if ( audiostream_done_reading(pat->handle) ) {
420 event_music_force_switch();
422 // Second case: looping back to start of same track since at the end
423 else if ( !audiostream_is_playing(pat->handle) && !audiostream_is_paused(pat->handle) ) {
424 audiostream_stop(pat->handle); // stop current and rewind
426 if ( pat->loop_for > 0 ) {
427 audiostream_play(pat->handle, Master_event_music_volume, 0); // no looping
428 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
431 event_music_force_switch();
434 // Third case: switching to a different track by interruption
435 else if ( (pat->force_pattern == TRUE && pat->can_force == TRUE) ) {
436 int bytes_streamed = audiostream_get_bytes_committed(pat->handle);
437 int measures_played = bytes_streamed / pat->bytes_per_measure;
438 if ( measures_played < pat->num_measures ) {
439 audiostream_set_byte_cutoff(pat->handle, pat->bytes_per_measure * (measures_played+1) );
440 pat->force_pattern = FALSE;
445 // We want to go back to NRML track music if all the hostiles have been
446 // destroyed, and we are still playing the battle music
447 if ( Current_pattern == SONG_BTTL_1 || Current_pattern == SONG_BTTL_2 || Current_pattern == SONG_BTTL_3 ) {
448 if ( timestamp_elapsed(Battle_over_timestamp) && Event_Music_battle_started == 1) {
449 //Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
450 if ( hostile_ships_present() == FALSE ) {
451 if ( Patterns[Current_pattern].next_pattern != SONG_VICT_2 ) {
452 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
453 Patterns[Current_pattern].force_pattern = TRUE;
454 Event_Music_battle_started = 0;
460 if (Event_Music_battle_started == 0) {
461 if (Current_pattern == SONG_NRML_1) {
462 if (timestamp_elapsed(Check_for_battle_music)) {
463 Check_for_battle_music = timestamp(1000);
464 if (hostile_ships_present() == TRUE) {
465 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
466 Patterns[Current_pattern].force_pattern = TRUE;
472 if ( !Victory2_music_played ) {
473 if ( timestamp_elapsed(Mission_over_timestamp) ) {
474 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
475 if ( mission_goals_met() && (!hostile_ships_present()) ) {
476 Patterns[Current_pattern].next_pattern = SONG_VICT_2;
477 Patterns[Current_pattern].force_pattern = TRUE;
478 Victory2_music_played = 1;
485 // -------------------------------------------------------------------------------------------------
486 // event_music_level_init()
488 // Called at the start of a mission (level). Sets up the pattern data, and kicks off the
489 // first track to play().
491 // input: force_soundtrack => OPTIONAL parameter (default value -1)
492 // forces the soundtrack to ignore the music.tbl assignment
494 void event_music_level_init(int force_soundtrack)
497 SOUNDTRACK_INFO *strack;
499 if ( Cmdline_freespace_no_music ) {
503 if ( !audiostream_is_inited() )
506 if ( Event_music_level_inited == TRUE )
509 Current_pattern = -1;
511 if ( Event_music_inited == FALSE )
515 if ( force_soundtrack != -1 ) {
516 Current_soundtrack_num = force_soundtrack;
519 if ( Current_soundtrack_num < 0 ) {
522 // okay, assign a random soundtrack if one exists
523 if ( Num_soundtracks > 0 ) {
524 Current_soundtrack_num = rand()%Num_soundtracks;
525 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Picking random event music soundtrack: %s\n", Soundtracks[Current_soundtrack_num].name));
532 Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < Num_soundtracks);
533 strack = &Soundtracks[Current_soundtrack_num];
535 // open the pattern files, and get ready to play them
536 for ( i = 0; i < strack->num_patterns; i++ ) {
537 if ( !stricmp(NOX("none.wav"), strack->pattern_fnames[i]) ) {
538 Patterns[i].handle = -1;
542 Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
544 if ( Patterns[i].handle >= 0 ) {
545 Event_music_level_inited = TRUE;
546 Event_music_enabled = TRUE;
549 Patterns[i].next_pattern = Pattern_default_next[i];
550 Patterns[i].default_next_pattern = Pattern_default_next[i];
551 Patterns[i].loop_for = Pattern_loop_for[i];
552 Patterns[i].default_loop_for = Pattern_loop_for[i];
553 Patterns[i].force_pattern = FALSE;
554 Patterns[i].can_force = Pattern_can_force[i];
555 Patterns[i].bytes_per_measure = Pattern_bytes_per_measure[Current_soundtrack_num][i];
556 Patterns[i].num_measures = Pattern_num_measures[Current_soundtrack_num][i];
559 Num_enemy_arrivals = 0;
560 Num_friendly_arrivals = 0;
561 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
562 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
563 Next_arrival_timestamp = timestamp(1);
564 Victory2_music_played = 0;
565 Check_for_battle_music = 0;
567 if ( Event_music_level_inited ) {
568 if ( force_soundtrack != -1 ) {
569 event_music_first_pattern();
574 // -------------------------------------------------------------------------------------------------
575 // event_music_first_pattern()
577 // Picks the first pattern to play, based on whether the battle has started. Delay start
580 void event_music_first_pattern()
582 if ( Event_music_inited == FALSE ) {
586 if ( Event_music_enabled == FALSE ) {
590 if ( Event_music_level_inited == FALSE ) {
591 event_music_level_init();
594 if ( Event_music_level_inited == FALSE ) {
598 if ( Event_music_begun == TRUE ) {
602 if ( Current_pattern != -1 ) {
603 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
604 audiostream_stop( Patterns[Current_pattern].handle );
607 Pattern_timer_id = 2000; // start music delay
609 Event_music_begun = FALSE;
610 if ( Event_Music_battle_started == TRUE ) {
611 Current_pattern = SONG_BTTL_1;
614 Current_pattern = SONG_NRML_1;
618 // -------------------------------------------------------------------------------------------------
619 // event_music_level_close()
621 // Called at the end of each mission (level). Stops any playing patterns by fading them out.
623 void event_music_level_close()
627 if ( Event_music_level_inited == FALSE )
630 if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS ) {
631 SOUNDTRACK_INFO *strack;
633 Assert( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS );
634 strack = &Soundtracks[Current_soundtrack_num];
636 // close the pattern files
637 for ( i = 0; i < strack->num_patterns; i++ ) {
638 if ( i == Current_pattern ) {
639 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
640 audiostream_close_file( Patterns[i].handle );
642 audiostream_close_file( Patterns[i].handle, 0 );
645 audiostream_close_file( Patterns[i].handle, 0 );
648 // close em all down then
649 audiostream_close_all(0);
652 Current_pattern = -1;
653 Event_music_level_inited = FALSE;
654 Event_Music_battle_started = FALSE;
655 Event_music_enabled = 0;
656 Event_music_begun = FALSE;
659 // -------------------------------------------------------------------------------------------------
660 // event_music_battle_start()
662 // Start the battle music. If the music is already started before, do nothing.
664 int event_music_battle_start()
666 if ( !hostile_ships_present() ) {
670 // No special tracks in training.
671 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
674 // Check to see if we've already started off the battle song
675 if ( Event_Music_battle_started == 1 ) {
679 if ( Event_music_enabled == FALSE )
682 if ( Event_music_level_inited == FALSE )
685 if ( Current_pattern == SONG_BTTL_1 )
686 return 0; // already playing
688 if ( Current_pattern == SONG_DEAD_1 )
689 return 0; // death is the last song to play
691 if ( Current_pattern != -1 ) {
692 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
693 Patterns[Current_pattern].force_pattern = TRUE;
696 Event_Music_battle_started = 1; // keep track of this state though, need on restore
697 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
702 // -------------------------------------------------------------------------------------------------
703 // event_music_enemy_arrival()
705 // An enemy has arrived, play an enemy arrival pattern.
707 int event_music_enemy_arrival()
709 if ( Event_music_enabled == FALSE ) {
713 if ( Event_music_level_inited == FALSE ) {
718 if ( Event_Music_battle_started == TRUE ) {
719 next_pattern = SONG_EARV_2;
722 next_pattern = SONG_EARV_1;
725 if ( Current_pattern == next_pattern )
726 return 0; // already playing
728 if ( Current_pattern == SONG_DEAD_1 )
729 return 0; // death is the last song to play
731 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
734 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
735 return 0; // don't squash a pending pattern
737 Num_enemy_arrivals++;
739 // AL 7-25-99: If hull is less than 70% then switch to battle 2 or 3, otherwise switch to 1 or 2
740 bool play_intense_battle_music = false;
741 if (Player_obj != NULL && Player_ship != NULL) {
742 Assert(Player_ship->ship_info_index >= 0);
743 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
744 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
745 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
746 play_intense_battle_music = true;
750 if (play_intense_battle_music == true) {
751 if (Current_pattern == SONG_BTTL_2) {
752 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
754 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
757 if (Current_pattern == SONG_BTTL_1) {
758 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
759 } else if (Current_pattern == SONG_BTTL_2) {
760 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
762 Patterns[next_pattern].next_pattern = SONG_BTTL_1;
768 // Alternate between BTTL_2 and BTTL_3 following enemy arrivals
769 if ( Num_enemy_arrivals & 1 ) {
770 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
772 if ( Patterns[SONG_BTTL_3].handle != -1 ) {
773 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
775 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
780 if ( Current_pattern != -1 ) {
781 Patterns[Current_pattern].next_pattern = next_pattern;
782 Patterns[Current_pattern].force_pattern = TRUE;
785 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
790 // -------------------------------------------------------------------------------------------------
791 // event_music_friendly_arrival()
793 // An friendly has arrived, play a friendly arrival pattern.
795 int event_music_friendly_arrival()
797 if ( Event_music_enabled == FALSE )
800 if ( Event_music_level_inited == FALSE )
803 if (timestamp_elapsed(Next_arrival_timestamp) == false) {
808 if ( Event_Music_battle_started == TRUE ) {
809 next_pattern = SONG_AARV_2;
812 next_pattern = SONG_AARV_1;
815 if ( Current_pattern == next_pattern )
816 return 0; // already playing
818 if ( Current_pattern == SONG_DEAD_1 )
819 return 0; // death is the last song to play
821 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
824 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
825 return 0; // don't squash a pending pattern
827 // After the second friendly arrival, default to SONG_BTTL_3
828 Num_friendly_arrivals++;
830 if ( Current_pattern != -1 ) {
831 // AL 06-24-99: always overlay allied arrivals
833 if (next_pattern == SONG_AARV_1) {
834 Patterns[Current_pattern].next_pattern = next_pattern;
835 Patterns[Current_pattern].force_pattern = TRUE;
838 Assert(Patterns[SONG_AARV_1].handle >= 0 );
839 audiostream_play(Patterns[SONG_AARV_1].handle, Master_event_music_volume, 0); // no looping
840 audiostream_set_byte_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].bytes_per_measure) );
844 Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
846 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
851 // Play arrival music keyed to team "team".
852 void event_music_arrival(int team)
854 // No friendly arrival music in a training mission.
855 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
858 if ( Player_ship->team == team ) {
859 event_music_friendly_arrival();
861 event_music_enemy_arrival();
865 // -------------------------------------------------------------------------------------------------
866 // event_music_primary_goals_met()
868 // A primary goal has failed
870 int event_music_primary_goal_failed()
874 // No special tracks in training.
875 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
878 if ( Event_music_enabled == FALSE )
881 if ( Event_music_level_inited == FALSE )
884 if ( Current_pattern == SONG_DEAD_1 )
885 return 0; // death is the last song to play
887 if ( Patterns[SONG_FAIL_1].handle < 0 ) // can't play if music file doesn't exist
890 if ( hostile_ships_present() ) {
891 next_pattern = SONG_BTTL_1;
894 next_pattern = SONG_NRML_1;
895 Event_Music_battle_started = 0;
898 if ( Current_pattern != -1 ) {
899 Patterns[Current_pattern].next_pattern = next_pattern;
900 Patterns[Current_pattern].force_pattern = TRUE;
906 // -------------------------------------------------------------------------------------------------
907 // event_music_primary_goals_met()
909 // A goal has been achieved, play the appropriate victory music.
911 int event_music_primary_goals_met()
913 int next_pattern = SONG_VICT_1;
915 // No special tracks in training.
916 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
919 if ( Event_music_enabled == FALSE )
922 if ( Event_music_level_inited == FALSE )
925 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_2) )
926 return 0; // already playing
928 if ( Current_pattern == SONG_DEAD_1 )
929 return 0; // death is the last song to play
931 if ( hostile_ships_present() ) {
932 Patterns[SONG_VICT_1].next_pattern = SONG_BTTL_1;
935 Patterns[SONG_VICT_1].next_pattern = SONG_VICT_2;
936 Event_Music_battle_started = 0;
938 // If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
939 // to the next default track
940 if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
941 Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
943 Victory2_music_played = 1;
947 if ( Current_pattern != -1 ) {
948 Patterns[Current_pattern].next_pattern = next_pattern;
949 Patterns[Current_pattern].force_pattern = TRUE;
955 // -------------------------------------------------------------------------------------------------
956 // event_music_player_death()
958 // The player has died, play death pattern.
960 int event_music_player_death()
962 if ( Event_music_enabled == FALSE )
965 if ( Event_music_level_inited == FALSE )
968 if ( Current_pattern == SONG_DEAD_1 )
969 return 0; // already playing
971 if ( Current_pattern != -1 ) {
972 Patterns[Current_pattern].next_pattern = SONG_DEAD_1;
973 Patterns[Current_pattern].force_pattern = TRUE;
979 // -------------------------------------------------------------------------------------------------
980 // event_music_player_respawn()
982 // Player has respawned (multiplayer only)
984 int event_music_player_respawn()
986 if ( Event_music_enabled == FALSE )
989 if ( Event_music_level_inited == FALSE )
992 // Assert(Current_pattern == SONG_DEAD_1);
994 Event_Music_battle_started = 0;
995 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
996 Patterns[Current_pattern].force_pattern = TRUE;
1001 // -------------------------------------------------------------------------------------------------
1002 // event_music_player_respawn_as_observer()
1004 // Player has respawned (multiplayer only)
1006 int event_music_player_respawn_as_observer()
1008 if ( Event_music_enabled == FALSE )
1011 if ( Event_music_level_inited == FALSE )
1014 if ( Current_pattern >= 0 ) {
1015 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1016 audiostream_stop(Patterns[Current_pattern].handle);
1017 Current_pattern = -1;
1024 // -------------------------------------------------------------------------------------------------
1025 // event_music_parse_musictbl() will parse the music.tbl file, and set up the Mission_songs[]
1028 void event_music_parse_musictbl()
1030 char fname[MAX_FILENAME_LEN];
1034 int num_patterns = 0;
1036 Num_music_files = 0;
1037 Num_soundtracks = 0; // Global
1038 event_music_reset_choices();
1040 if ((rval = setjmp(parse_abort)) != 0) {
1041 Error(LOCATION, "Unable to parse music.tbl! Code = %i.\n", rval);
1044 // open localization
1047 read_file_text("music.tbl");
1050 // Loop through all the sound-tracks
1051 while (required_string_either("#Menu Music Start","#SoundTrack Start")) {
1052 Assert(Num_soundtracks < MAX_SOUNDTRACKS);
1053 required_string("#SoundTrack Start");
1054 required_string("$SoundTrack Name:");
1055 stuff_string(Soundtracks[Num_soundtracks].name, F_NAME, NULL);
1056 while (required_string_either("#SoundTrack End","$Name:")) {
1057 Assert( num_patterns < MAX_PATTERNS );
1058 required_string("$Name:");
1059 stuff_string(line_buf, F_NAME, NULL);
1061 // line_buf holds 3 fields: filename, num measures, bytes per measure
1065 token = strtok( line_buf, NOX(" ,\t"));
1066 strcpy(fname, token);
1067 while ( token != NULL ) {
1068 token = strtok( NULL, NOX(" ,\t") );
1069 if ( token == NULL ) {
1070 Assert(count == 2 );
1075 Pattern_num_measures[Num_soundtracks][num_patterns] = (float)atof(token);
1078 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] = atoi(token);
1084 // convert from samples per measure to bytes per measure
1085 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] *= 2;
1086 strcpy(Soundtracks[Num_soundtracks].pattern_fnames[num_patterns], fname);
1090 required_string("#SoundTrack End");
1091 Soundtracks[Num_soundtracks].num_patterns = num_patterns;
1096 // Parse the menu music section
1097 required_string("#Menu Music Start");
1098 while (required_string_either("#Menu Music End","$Name:")) {
1099 Assert( Num_music_files < MAX_SPOOLED_MUSIC );
1101 required_string("$Name:");
1102 stuff_string(fname, F_PATHNAME, NULL);
1103 Assert( strlen(fname) < (NAME_LENGTH-1) );
1104 strcpy( Spooled_music[Num_music_files].name, fname );
1106 required_string("$Filename:");
1107 stuff_string(fname, F_PATHNAME, NULL);
1108 if ( stricmp(fname, NOX("none.wav")) ) {
1109 Assert( strlen(fname) < (MAX_FILENAME_LEN-1) );
1110 strcpy( Spooled_music[Num_music_files].filename, fname );
1116 required_string("#Menu Music End");
1118 // close localization
1123 // -------------------------------------------------------------------------------------------------
1124 // event_music_change_pattern()
1126 // Force a particular pattern to play. This is used for debugging purposes.
1128 void event_music_change_pattern(int new_pattern)
1130 if ( Event_music_enabled == FALSE ) {
1131 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1135 if ( Event_music_level_inited == FALSE ) {
1136 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1140 if ( Current_pattern == new_pattern )
1141 return; // already playing
1143 if ( Current_pattern != -1 ) {
1144 Patterns[Current_pattern].next_pattern = new_pattern;
1145 Patterns[Current_pattern].force_pattern = TRUE;
1149 // -------------------------------------------------------------------------------------------------
1150 // event_music_return_current_pattern()
1152 // Simply return what the current pattern being played is. Don't want to make global.
1154 int event_music_return_current_pattern()
1156 return Current_pattern;
1159 // -------------------------------------------------------------------------------------------------
1160 // event_music_disable()
1162 // Stop any patterns that are playing, and prevent any further patterns from playing (ie
1163 // set Event_music_enabled = FALSE). We don't uninit event music, since it might be toggled
1164 // back on this level.
1166 void event_music_disable()
1168 if ( Event_music_level_inited == FALSE )
1171 if ( Event_music_enabled == FALSE )
1174 if (Current_pattern == -1)
1177 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1178 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1179 audiostream_stop(Patterns[Current_pattern].handle); // stop current and rewind
1182 Event_music_begun = FALSE;
1183 Event_music_enabled = FALSE;
1184 Current_pattern = -1;
1187 // -------------------------------------------------------------------------------------------------
1188 // event_music_enable()
1190 // Init the event music (ie load the patterns) if required. Set up the first song to play, and
1191 // set Event_music_enabled = TRUE to allow patterns to play.
1193 void event_music_enable()
1195 if ( Event_music_enabled == TRUE )
1198 Event_music_enabled = TRUE;
1200 if ( Event_music_level_inited == FALSE ) {
1201 event_music_level_init();
1202 // start the first pattern to play (delayed)
1203 if ( Game_mode & GM_IN_MISSION ) {
1204 event_music_first_pattern();
1208 // start a new pattern
1209 Event_music_begun = FALSE;
1210 Pattern_timer_id = timestamp(150);
1211 event_music_start_default();
1215 // -------------------------------------------------------------------------------------------------
1216 // event_music_start_default()
1218 // Start playing a default track, based on how far the mission has progressed
1220 void event_music_start_default()
1224 if ( Event_Music_battle_started == TRUE ) {
1225 if ( hostile_ships_present() ) {
1226 next_pattern = SONG_BTTL_1;
1229 Event_Music_battle_started = FALSE;
1230 next_pattern = SONG_NRML_1;
1234 next_pattern = SONG_NRML_1;
1236 if ( Current_pattern == -1 ) {
1237 Current_pattern = next_pattern;
1240 Patterns[Current_pattern].next_pattern = next_pattern;
1241 Patterns[Current_pattern].force_pattern = TRUE;
1246 // -------------------------------------------------------------------------------------------------
1247 // event_music_pause()
1249 // Stop any playing pattern, but don't rewind.
1251 void event_music_pause()
1253 if ( Event_music_enabled == FALSE ) {
1254 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1258 if ( Event_music_level_inited == FALSE ) {
1259 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1263 if (Current_pattern == -1)
1266 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1267 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1268 audiostream_stop(Patterns[Current_pattern].handle, 0); // stop current and don't rewind
1272 // -------------------------------------------------------------------------------------------------
1273 // event_music_unpause()
1275 // Start the Current_pattern if it is paused.
1277 void event_music_unpause()
1279 if ( Event_music_enabled == FALSE ) {
1280 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1284 if ( Event_music_level_inited == FALSE ) {
1285 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1289 if (Current_pattern == -1)
1292 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1293 if ( audiostream_is_paused(Patterns[Current_pattern].handle) == TRUE ) {
1294 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
1295 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
1299 // -------------------------------------------------------------------------------------------------
1300 // event_music_set_volume_all()
1302 // Set the volume of the event driven music. Used when using the game-wide music volume is changed
1305 void event_music_set_volume_all(float volume)
1307 audiostream_set_volume_all(volume, ASF_EVENTMUSIC);
1310 // ----------------------------------------------------------------------
1311 // hostile_ships_present()
1313 // Determine if there are any non-friendly ships in existance
1315 // returns: 1 => there are non-friendly ships in existance
1316 // 0 => any ships in existance are friendly
1317 int hostile_ships_present()
1322 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1323 shipp = &Ships[Objects[so->objnum].instance];
1325 // check if ship if enemy ship
1326 if ( (shipp->team == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR) )
1329 // check if ship is threatening
1330 if ( (shipp->flags & (SF_DISABLED|SF_DYING|SF_DEPARTING)) || (ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE)) )
1333 // check if ship is flyable
1334 if ( Ship_info[shipp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
1338 // check if ship is visible by player's team
1339 if ( hud_target_invalid_awacs(&Objects[so->objnum]) == 1 ) {
1348 // ----------------------------------------------------------------------
1349 // hostile_ships_to_arrive()
1351 // Determine if there are any non-friendly ships yet to arrive
1353 // NOTE: neutral ships are considered hostile for the purpose of event music
1355 int hostile_ships_to_arrive()
1359 p_objp = GET_FIRST(&ship_arrival_list);
1360 while( p_objp != END_OF_LIST(&ship_arrival_list) ) {
1361 if ( (p_objp->team != Player_ship->team) && !(p_objp->flags & P_SF_CANNOT_ARRIVE) ) {
1364 p_objp = GET_NEXT(p_objp);
1369 // ----------------------------------------------------------------
1370 // event_music_get_info()
1372 // Return information about the event music in the buffer outbuf
1373 // NOTE: callers to this function are advised to allocate a 256 byte buffer
1374 void event_music_get_info(char *outbuf)
1376 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
1377 sprintf(outbuf,XSTR( "Event music is not playing", 213));
1380 sprintf(outbuf,XSTR( "soundtrack: %s [%s]", 214), Soundtracks[Current_soundtrack_num].name, Pattern_description[Current_pattern]);
1384 // ----------------------------------------------------------------
1385 // event_music_next_soundtrack()
1387 // input: delta => 1 or -1, depending if you want to go to next or previous song
1389 // returns: New soundtrack number if successfully changed, otherwise return -1
1391 int event_music_next_soundtrack(int delta)
1395 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1399 new_soundtrack = Current_soundtrack_num + delta;
1400 if ( new_soundtrack >= Num_soundtracks )
1403 event_music_level_close();
1404 event_music_level_init(new_soundtrack);
1406 return Current_soundtrack_num;
1409 // ----------------------------------------------------------------
1410 // event_music_get_soundtrack_name()
1412 // Return information about the event music in the buffer outbuf
1413 // NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
1414 void event_music_get_soundtrack_name(char *outbuf)
1416 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1417 strcpy(outbuf, XSTR( "Event music is not playing", 213));
1420 sprintf(outbuf, Soundtracks[Current_soundtrack_num].name);
1424 // set the current soundtrack based on name
1425 void event_music_set_soundtrack(char *name)
1429 // find the correct index for the event music
1430 for ( i = 0; i < Num_soundtracks; i++ ) {
1431 if ( !stricmp(name, Soundtracks[i].name) ) {
1432 Current_soundtrack_num = i;
1437 if ( i == Num_soundtracks ) {
1438 Current_soundtrack_num = -1;
1439 mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
1443 int event_music_get_spooled_music_index(char *name)
1445 // find the correct index for the event music
1446 for ( int i = 0; i < Num_music_files; i++ ) {
1447 if ( !stricmp(name, Spooled_music[i].name) ) {
1455 // set a score based on name
1456 void event_music_set_score(int score_index, char *name)
1458 Assert(score_index < NUM_SCORES);
1460 // find the correct index for the event music
1461 Mission_music[score_index] = event_music_get_spooled_music_index(name);
1464 // reset what sort of music is to be used for this mission
1465 void event_music_reset_choices()
1467 Current_soundtrack_num = -1;
1468 mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
1469 Mission_music[SCORE_BRIEFING] = -1;
1470 event_music_set_score(SCORE_DEBRIEF_SUCCESS, "Success");
1471 event_music_set_score(SCORE_DEBRIEF_AVERAGE, "Average");
1472 event_music_set_score(SCORE_DEBRIEF_FAIL, "Failure");
1473 //Mission_music[SCORE_DEBRIEF_SUCCESS] = MUSIC_DEBRIEF_SUCCESS_1;
1474 //Mission_music[SCORE_DEBRIEF_FAIL] = MUSIC_DEBRIEF_FAIL_1;
1477 void event_music_hostile_ship_destroyed()
1479 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
1483 #pragma optimize("", on)