2 * $Logfile: /Freespace2/code/Gamesnd/EventMusic.cpp $
7 * C module for high-level control of event driven music
10 * Revision 1.3 2002/05/28 08:52:03 relnev
11 * implemented two assembly stubs.
13 * cleaned up a few warnings.
15 * added a little demo hackery to make it progress a little farther.
17 * Revision 1.2 2002/05/07 03:16:45 theoddone33
18 * The Great Newline Fix
20 * Revision 1.1.1.1 2002/05/03 03:28:09 root
24 * 14 8/19/99 9:41a Alanl
25 * don't play victory 2 music if there are no goals in the mission
27 * 13 8/11/99 5:33p Jefff
28 * added 3rd debrief music track
30 * 12 8/01/99 2:11p Alanl
31 * make hull value to play more intense battle music a constant
33 * 11 8/01/99 2:06p Alanl
34 * tweak battle music track switching
36 * 10 7/25/99 9:57p Alanl
37 * change battle music track selection after enemy arrivals to make battle
38 * tracks less repetitive
40 * 9 7/19/99 10:13p Andsager
41 * Tie in hud_targeting to hostile_ships_present() used to determine next
44 * 8 6/24/99 10:47p Alanl
45 * loop battle between tracks 2 and 3 if hull integrity < 70%
47 * 7 6/21/99 1:34p Alanl
50 * 6 6/20/99 12:06a Alanl
51 * new event music changes
53 * 5 11/23/98 11:55a Johnson
54 * return -1 if a score isn't found
56 * 4 11/20/98 4:08p Dave
57 * Fixed flak effect in multiplayer.
59 * 3 10/23/98 3:51p Dave
60 * Full support for tstrings.tbl and foreign languages. All that remains
61 * is to make it active in Fred.
63 * 2 10/07/98 10:52a Dave
66 * 1 10/07/98 10:48a Dave
68 * 107 6/09/98 5:15p Lawrance
69 * French/German localization
71 * 106 6/09/98 10:31a Hoffoss
72 * Created index numbers for all xstr() references. Any new xstr() stuff
73 * added from here on out should be added to the end if the list. The
74 * current list count can be found in FreeSpace.cpp (search for
77 * 105 5/24/98 5:28p Dan
78 * let event_music_level_init() over-ride Event_music_enabled
80 * 104 5/24/98 4:42p Dan
81 * AL: Fix several bugs related to pausing and enabling/disabling event
84 * 103 5/23/98 3:17a Lawrance
85 * Tweak how battle music gets restarted
87 * 102 5/22/98 10:43a Lawrance
88 * If mission doesn't have event music, don't choose random track
90 * 101 5/21/98 6:56p Lawrance
91 * Tweak how victory music plays
93 * 100 5/21/98 2:47a Lawrance
94 * Fix some problems with event music
96 * 99 5/18/98 3:21p Mike
97 * Don't play arrival and goals tracks in a training mission.
99 * 98 5/04/98 3:15p Duncan
100 * AL: remove bogus assert in event_music_player_respawn()
102 * 97 5/03/98 1:54a Lawrance
103 * Fix event music problems related to respawning
105 * 96 4/03/98 12:56a Lawrance
106 * Fix bug with music not starting in the first mission
108 * 95 4/01/98 6:46p Lawrance
109 * Lower default music volume
116 #include "eventmusic.h"
119 #include "linklist.h"
120 #include "missionload.h" /* for Builtin_mission_names[] */
121 #include "missionparse.h"
123 #include "freespace.h"
124 #include "audiostr.h"
125 #include "missioncampaign.h"
129 #include "missiongoals.h"
130 #include "localize.h"
133 #pragma optimize("", off)
136 #define DEFAULT_MASTER_EVENT_MUSIC_VOLUME 0.5f
138 #define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
140 ////////////////////////////
142 ////////////////////////////
143 int Event_Music_battle_started = 0;
144 float Master_event_music_volume = DEFAULT_MASTER_EVENT_MUSIC_VOLUME; // range is 0->1
146 // array that holds which soundtrack is used for which mission (data comes from music.tbl)
147 //int Mission_soundtracks[MAX_CAMPAIGN_MISSIONS];
149 // array that holds which briefing track to play for which mission. Index into Spooled_music[][].
150 //int Mission_briefingmusic[MAX_CAMPAIGN_MISSIONS];
152 typedef struct tagSNDPATTERN {
153 int default_next_pattern; // Needed so the next_pattern member can be reset
154 int next_pattern; // Next pattern to play at loop time (can be same pattern)
155 int default_loop_for; // Needed so the loop_for variable can be reset
156 int loop_for; // Number of times to loop before switching to next pattern
157 int handle; // handle to open audio stream
158 int force_pattern; // flag to indicate that we want to not continue loop, but go to next_pattern
159 int can_force; // whether this pattern can be interrupted
160 int bytes_per_measure; // number of bytes in a measure
161 float num_measures; // number of measures in wave file
164 SNDPATTERN Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
166 // Holds filenames for the different sections of a soundtrack
167 SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
169 int Current_soundtrack_num; // Active soundtrack for the current mission.. index into Soundtracks[]
171 #define PATTERN_DELAY 1000 // in ms
172 int Current_pattern = -1; // currently playing part of track
173 int Pending_pattern = -1;
174 int Pattern_timer_id = 0;
177 static int Num_enemy_arrivals;
178 static int Num_friendly_arrivals;
180 #define ARRIVAL_INTERVAL_TIMESTAMP 5000
181 #define BATTLE_CHECK_INTERVAL 15000
182 static int Battle_over_timestamp;
183 static int Mission_over_timestamp;
184 static int Victory2_music_played;
185 static int Next_arrival_timestamp;
186 static int Check_for_battle_music;
188 // stores the number of measures for the different patterns (data from music.tbl)
189 float Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS];
191 // stores the number of bytes per measure (data from music.tbl)
192 int Pattern_bytes_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS];
194 char* Pattern_names[MAX_PATTERNS] =
197 "NRML_1", // Normal Song 1
198 "AARV_1", // Allied Arrival 1
199 "EARV_1", // Enemy Arrival 1
200 "BTTL_1", // Battle Song 1
201 "BTTL_2", // Battle Song 2
202 "BTTL_3", // Battle Song 3
203 "AARV_2", // Allied Arrival 2
204 "EARV_2", // Enemy Arrival 2
205 "VICT_1", // Victory Song 1
206 "VICT_2", // Victory Song 2
207 "FAIL_1" // Goal Failed 1
208 "DEAD_1" // Death Song 1
212 char* Pattern_description[MAX_PATTERNS] =
216 "friendly arrival 1",
221 "friendly arrival 2",
230 int Pattern_loop_for[MAX_PATTERNS] =
233 1, // Allied Arrival 1
234 1, // Enemy Arrival 1
238 1, // Allied Arrival 2
239 1, // Enemy Arrival 2
246 int Pattern_default_next[MAX_PATTERNS] =
248 SONG_NRML_1, // NRML_1 progresses to NRML_1 by default
249 SONG_NRML_1, // AARV_1 progresses to NRML_1 by default
250 SONG_BTTL_1, // EARV_1 progresses to BTTL_1 by default
251 SONG_BTTL_2, // BTTL_1 progresses to BTTL_2 by default
252 SONG_BTTL_3, // BTTL_2 progresses to BTTL_3 by default
253 SONG_BTTL_1, // BTTL_3 progresses to BTTL_1 by default
254 SONG_BTTL_2, // AARV_2 progresses to BTTL_2 by default
255 SONG_BTTL_3, // EARV_2 progresses to BTTL_3 by default
256 SONG_NRML_1, // VICT_1 progresses to NRML_1 by default
257 SONG_NRML_1, // VICT_2 progresses to NRML_1 by default
258 SONG_NRML_1, // FAIL_1 progresses to NRML_1 by default
259 -1 // no music plays after dead
263 // Certain patterns can be interrupted (such as the long-playing NRML and BTTL tracks).
264 // Other shorter tracks (such as arrivals) play their entire duration.
265 int Pattern_can_force[MAX_PATTERNS] =
282 int Event_music_enabled = TRUE;
283 static int Event_music_inited = FALSE;
284 static int Event_music_level_inited = FALSE;
285 static int Event_music_begun = FALSE;
287 // forward function declarations
288 int hostile_ships_present();
289 int hostile_ships_to_arrive();
290 extern int hud_target_invalid_awacs(object *objp);
292 // Holds file names of spooled music that is played at menus, briefings, credits etc.
293 // Indexed into by a #define enumeration of the different kinds of spooled music
294 menu_music Spooled_music[MAX_SPOOLED_MUSIC];
295 int Num_music_files; // Number of spooled music files
297 // Array that holds indicies into Spooled_music[], these specify which music is played in breifing/debriefing
298 int Mission_music[NUM_SCORES];
300 // -------------------------------------------------------------------------------------------------
301 // event_music_init()
303 // Called once at game start-up to parse music.tbl and set some state variables
305 void event_music_init()
307 if ( snd_is_inited() == FALSE ) {
308 Event_music_enabled = FALSE;
312 if ( Cmdline_freespace_no_music ) {
316 if ( Event_music_inited == TRUE )
319 event_music_parse_musictbl();
320 Event_music_inited = TRUE;
321 Event_music_begun = FALSE;
324 // -------------------------------------------------------------------------------------------------
325 // event_music_close()
327 // Called once at game end
329 void event_music_close()
331 if ( Event_music_inited == FALSE )
334 Event_music_inited = FALSE;
337 // -------------------------------------------------------------------------------------------------
338 // event_music_force_switch()
340 // Performs a switch between patterns. Sets the cutoff limit for the pattern that is being
343 void event_music_force_switch()
345 if ( Event_music_enabled == FALSE )
348 if ( Event_music_level_inited == FALSE )
352 Patterns[Current_pattern].loop_for = Patterns[Current_pattern].default_loop_for;
354 new_pattern = Patterns[Current_pattern].next_pattern;
356 if ( (new_pattern == SONG_BTTL_3) && (Patterns[SONG_BTTL_3].handle == -1) ) {
357 if ( Current_pattern == SONG_BTTL_2 ) {
358 new_pattern = SONG_BTTL_1;
360 new_pattern = SONG_BTTL_2;
363 if (Current_pattern == SONG_BTTL_3 && new_pattern == SONG_BTTL_1) {
364 // AL 06-24-99: maybe switch to battle 2 if hull is less than 70%
365 if (Player_obj != NULL && Player_ship != NULL) {
366 Assert(Player_ship->ship_info_index >= 0);
367 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
368 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
369 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
370 new_pattern = SONG_BTTL_2;
376 if ( new_pattern == -1 ) {
380 if ( Patterns[new_pattern].num_measures == 0 )
381 return; // invalid pattern
383 Assert(new_pattern >= 0 && new_pattern < MAX_PATTERNS);
384 audiostream_play(Patterns[new_pattern].handle, Master_event_music_volume, 0); // no looping
385 audiostream_set_byte_cutoff(Patterns[new_pattern].handle, fl2i(Patterns[new_pattern].num_measures * Patterns[new_pattern].bytes_per_measure) );
386 Patterns[Current_pattern].next_pattern = Patterns[Current_pattern].default_next_pattern;
387 Patterns[Current_pattern].force_pattern = FALSE;
388 nprintf(("EVENTMUSIC", "EVENTMUSIC => switching to %s from %s\n", Pattern_names[new_pattern], Pattern_names[Current_pattern]));
389 Current_pattern = new_pattern;
392 // -------------------------------------------------------------------------------------------------
393 // event_music_do_frame()
395 // Called once per game frame, to check for transitions of patterns (and to start the music off at
398 void event_music_do_frame()
400 if ( Event_music_level_inited == FALSE ) {
404 if ( Event_music_enabled == FALSE ) {
408 // start off the music delayed
409 if ( timestamp_elapsed(Pattern_timer_id) ) {
410 Pattern_timer_id = 0;
411 Event_music_begun = TRUE;
412 if ( Current_pattern != -1 ) {
413 Assert(Patterns[Current_pattern].handle >= 0 );
414 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
415 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
419 if ( Event_music_begun == FALSE ) {
423 if ( Current_pattern != -1 ) {
425 pat = &Patterns[Current_pattern];
427 // First case: switching to a different track since first track is almost at end
428 if ( audiostream_done_reading(pat->handle) ) {
429 event_music_force_switch();
431 // Second case: looping back to start of same track since at the end
432 else if ( !audiostream_is_playing(pat->handle) && !audiostream_is_paused(pat->handle) ) {
433 audiostream_stop(pat->handle); // stop current and rewind
435 if ( pat->loop_for > 0 ) {
436 audiostream_play(pat->handle, Master_event_music_volume, 0); // no looping
437 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
440 event_music_force_switch();
443 // Third case: switching to a different track by interruption
444 else if ( (pat->force_pattern == TRUE && pat->can_force == TRUE) ) {
445 int bytes_streamed = audiostream_get_bytes_committed(pat->handle);
446 int measures_played = bytes_streamed / pat->bytes_per_measure;
447 if ( measures_played < pat->num_measures ) {
448 audiostream_set_byte_cutoff(pat->handle, pat->bytes_per_measure * (measures_played+1) );
449 pat->force_pattern = FALSE;
454 // We want to go back to NRML track music if all the hostiles have been
455 // destroyed, and we are still playing the battle music
456 if ( Current_pattern == SONG_BTTL_1 || Current_pattern == SONG_BTTL_2 || Current_pattern == SONG_BTTL_3 ) {
457 if ( timestamp_elapsed(Battle_over_timestamp) && Event_Music_battle_started == 1) {
458 //Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
459 if ( hostile_ships_present() == FALSE ) {
460 if ( Patterns[Current_pattern].next_pattern != SONG_VICT_2 ) {
461 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
462 Patterns[Current_pattern].force_pattern = TRUE;
463 Event_Music_battle_started = 0;
469 if (Event_Music_battle_started == 0) {
470 if (Current_pattern == SONG_NRML_1) {
471 if (timestamp_elapsed(Check_for_battle_music)) {
472 Check_for_battle_music = timestamp(1000);
473 if (hostile_ships_present() == TRUE) {
474 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
475 Patterns[Current_pattern].force_pattern = TRUE;
481 if ( !Victory2_music_played ) {
482 if ( timestamp_elapsed(Mission_over_timestamp) ) {
483 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
484 if ( mission_goals_met() && (!hostile_ships_present()) ) {
485 Patterns[Current_pattern].next_pattern = SONG_VICT_2;
486 Patterns[Current_pattern].force_pattern = TRUE;
487 Victory2_music_played = 1;
494 // -------------------------------------------------------------------------------------------------
495 // event_music_level_init()
497 // Called at the start of a mission (level). Sets up the pattern data, and kicks off the
498 // first track to play().
500 // input: force_soundtrack => OPTIONAL parameter (default value -1)
501 // forces the soundtrack to ignore the music.tbl assignment
503 void event_music_level_init(int force_soundtrack)
506 SOUNDTRACK_INFO *strack;
508 if ( Cmdline_freespace_no_music ) {
512 if ( !audiostream_is_inited() )
515 if ( Event_music_level_inited == TRUE )
518 Current_pattern = -1;
520 if ( Event_music_inited == FALSE )
524 if ( force_soundtrack != -1 ) {
525 Current_soundtrack_num = force_soundtrack;
528 if ( Current_soundtrack_num < 0 ) {
531 // okay, assign a random soundtrack if one exists
532 if ( Num_soundtracks > 0 ) {
533 Current_soundtrack_num = rand()%Num_soundtracks;
534 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Picking random event music soundtrack: %s\n", Soundtracks[Current_soundtrack_num].name));
541 Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < Num_soundtracks);
542 strack = &Soundtracks[Current_soundtrack_num];
544 // open the pattern files, and get ready to play them
545 for ( i = 0; i < strack->num_patterns; i++ ) {
546 if ( !stricmp(NOX("none.wav"), strack->pattern_fnames[i]) ) {
547 Patterns[i].handle = -1;
551 Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
553 if ( Patterns[i].handle >= 0 ) {
554 Event_music_level_inited = TRUE;
555 Event_music_enabled = TRUE;
558 Patterns[i].next_pattern = Pattern_default_next[i];
559 Patterns[i].default_next_pattern = Pattern_default_next[i];
560 Patterns[i].loop_for = Pattern_loop_for[i];
561 Patterns[i].default_loop_for = Pattern_loop_for[i];
562 Patterns[i].force_pattern = FALSE;
563 Patterns[i].can_force = Pattern_can_force[i];
564 Patterns[i].bytes_per_measure = Pattern_bytes_per_measure[Current_soundtrack_num][i];
565 Patterns[i].num_measures = Pattern_num_measures[Current_soundtrack_num][i];
568 Num_enemy_arrivals = 0;
569 Num_friendly_arrivals = 0;
570 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
571 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
572 Next_arrival_timestamp = timestamp(1);
573 Victory2_music_played = 0;
574 Check_for_battle_music = 0;
576 if ( Event_music_level_inited ) {
577 if ( force_soundtrack != -1 ) {
578 event_music_first_pattern();
583 // -------------------------------------------------------------------------------------------------
584 // event_music_first_pattern()
586 // Picks the first pattern to play, based on whether the battle has started. Delay start
589 void event_music_first_pattern()
591 if ( Event_music_inited == FALSE ) {
595 if ( Event_music_enabled == FALSE ) {
599 if ( Event_music_level_inited == FALSE ) {
600 event_music_level_init();
603 if ( Event_music_level_inited == FALSE ) {
607 if ( Event_music_begun == TRUE ) {
611 if ( Current_pattern != -1 ) {
612 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
613 audiostream_stop( Patterns[Current_pattern].handle );
616 Pattern_timer_id = 2000; // start music delay
618 Event_music_begun = FALSE;
619 if ( Event_Music_battle_started == TRUE ) {
620 Current_pattern = SONG_BTTL_1;
623 Current_pattern = SONG_NRML_1;
627 // -------------------------------------------------------------------------------------------------
628 // event_music_level_close()
630 // Called at the end of each mission (level). Stops any playing patterns by fading them out.
632 void event_music_level_close()
636 if ( Event_music_level_inited == FALSE )
639 if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS ) {
640 SOUNDTRACK_INFO *strack;
642 Assert( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS );
643 strack = &Soundtracks[Current_soundtrack_num];
645 // close the pattern files
646 for ( i = 0; i < strack->num_patterns; i++ ) {
647 if ( i == Current_pattern ) {
648 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
649 audiostream_close_file( Patterns[i].handle );
651 audiostream_close_file( Patterns[i].handle, 0 );
654 audiostream_close_file( Patterns[i].handle, 0 );
657 // close em all down then
658 audiostream_close_all(0);
661 Current_pattern = -1;
662 Event_music_level_inited = FALSE;
663 Event_Music_battle_started = FALSE;
664 Event_music_enabled = 0;
665 Event_music_begun = FALSE;
668 // -------------------------------------------------------------------------------------------------
669 // event_music_battle_start()
671 // Start the battle music. If the music is already started before, do nothing.
673 int event_music_battle_start()
675 if ( !hostile_ships_present() ) {
679 // No special tracks in training.
680 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
683 // Check to see if we've already started off the battle song
684 if ( Event_Music_battle_started == 1 ) {
688 if ( Event_music_enabled == FALSE )
691 if ( Event_music_level_inited == FALSE )
694 if ( Current_pattern == SONG_BTTL_1 )
695 return 0; // already playing
697 if ( Current_pattern == SONG_DEAD_1 )
698 return 0; // death is the last song to play
700 if ( Current_pattern != -1 ) {
701 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
702 Patterns[Current_pattern].force_pattern = TRUE;
705 Event_Music_battle_started = 1; // keep track of this state though, need on restore
706 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
711 // -------------------------------------------------------------------------------------------------
712 // event_music_enemy_arrival()
714 // An enemy has arrived, play an enemy arrival pattern.
716 int event_music_enemy_arrival()
718 if ( Event_music_enabled == FALSE ) {
722 if ( Event_music_level_inited == FALSE ) {
727 if ( Event_Music_battle_started == TRUE ) {
728 next_pattern = SONG_EARV_2;
731 next_pattern = SONG_EARV_1;
734 if ( Current_pattern == next_pattern )
735 return 0; // already playing
737 if ( Current_pattern == SONG_DEAD_1 )
738 return 0; // death is the last song to play
740 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
743 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
744 return 0; // don't squash a pending pattern
746 Num_enemy_arrivals++;
748 // AL 7-25-99: If hull is less than 70% then switch to battle 2 or 3, otherwise switch to 1 or 2
749 bool play_intense_battle_music = false;
750 if (Player_obj != NULL && Player_ship != NULL) {
751 Assert(Player_ship->ship_info_index >= 0);
752 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
753 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
754 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
755 play_intense_battle_music = true;
759 if (play_intense_battle_music == true) {
760 if (Current_pattern == SONG_BTTL_2) {
761 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
763 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
766 if (Current_pattern == SONG_BTTL_1) {
767 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
768 } else if (Current_pattern == SONG_BTTL_2) {
769 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
771 Patterns[next_pattern].next_pattern = SONG_BTTL_1;
777 // Alternate between BTTL_2 and BTTL_3 following enemy arrivals
778 if ( Num_enemy_arrivals & 1 ) {
779 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
781 if ( Patterns[SONG_BTTL_3].handle != -1 ) {
782 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
784 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
789 if ( Current_pattern != -1 ) {
790 Patterns[Current_pattern].next_pattern = next_pattern;
791 Patterns[Current_pattern].force_pattern = TRUE;
794 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
799 // -------------------------------------------------------------------------------------------------
800 // event_music_friendly_arrival()
802 // An friendly has arrived, play a friendly arrival pattern.
804 int event_music_friendly_arrival()
806 if ( Event_music_enabled == FALSE )
809 if ( Event_music_level_inited == FALSE )
812 if (timestamp_elapsed(Next_arrival_timestamp) == false) {
817 if ( Event_Music_battle_started == TRUE ) {
818 next_pattern = SONG_AARV_2;
821 next_pattern = SONG_AARV_1;
824 if ( Current_pattern == next_pattern )
825 return 0; // already playing
827 if ( Current_pattern == SONG_DEAD_1 )
828 return 0; // death is the last song to play
830 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
833 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
834 return 0; // don't squash a pending pattern
836 // After the second friendly arrival, default to SONG_BTTL_3
837 Num_friendly_arrivals++;
839 if ( Current_pattern != -1 ) {
840 // AL 06-24-99: always overlay allied arrivals
842 if (next_pattern == SONG_AARV_1) {
843 Patterns[Current_pattern].next_pattern = next_pattern;
844 Patterns[Current_pattern].force_pattern = TRUE;
847 Assert(Patterns[SONG_AARV_1].handle >= 0 );
848 audiostream_play(Patterns[SONG_AARV_1].handle, Master_event_music_volume, 0); // no looping
849 audiostream_set_byte_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].bytes_per_measure) );
853 Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
855 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
860 // Play arrival music keyed to team "team".
861 void event_music_arrival(int team)
863 // No friendly arrival music in a training mission.
864 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
867 if ( Player_ship->team == team ) {
868 event_music_friendly_arrival();
870 event_music_enemy_arrival();
874 // -------------------------------------------------------------------------------------------------
875 // event_music_primary_goals_met()
877 // A primary goal has failed
879 int event_music_primary_goal_failed()
883 // No special tracks in training.
884 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
887 if ( Event_music_enabled == FALSE )
890 if ( Event_music_level_inited == FALSE )
893 if ( Current_pattern == SONG_DEAD_1 )
894 return 0; // death is the last song to play
896 if ( Patterns[SONG_FAIL_1].handle < 0 ) // can't play if music file doesn't exist
899 if ( hostile_ships_present() ) {
900 next_pattern = SONG_BTTL_1;
903 next_pattern = SONG_NRML_1;
904 Event_Music_battle_started = 0;
907 if ( Current_pattern != -1 ) {
908 Patterns[Current_pattern].next_pattern = next_pattern;
909 Patterns[Current_pattern].force_pattern = TRUE;
915 // -------------------------------------------------------------------------------------------------
916 // event_music_primary_goals_met()
918 // A goal has been achieved, play the appropriate victory music.
920 int event_music_primary_goals_met()
922 int next_pattern = SONG_VICT_1;
924 // No special tracks in training.
925 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
928 if ( Event_music_enabled == FALSE )
931 if ( Event_music_level_inited == FALSE )
934 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_2) )
935 return 0; // already playing
937 if ( Current_pattern == SONG_DEAD_1 )
938 return 0; // death is the last song to play
940 if ( hostile_ships_present() ) {
941 Patterns[SONG_VICT_1].next_pattern = SONG_BTTL_1;
944 Patterns[SONG_VICT_1].next_pattern = SONG_VICT_2;
945 Event_Music_battle_started = 0;
947 // If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
948 // to the next default track
949 if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
950 Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
952 Victory2_music_played = 1;
956 if ( Current_pattern != -1 ) {
957 Patterns[Current_pattern].next_pattern = next_pattern;
958 Patterns[Current_pattern].force_pattern = TRUE;
964 // -------------------------------------------------------------------------------------------------
965 // event_music_player_death()
967 // The player has died, play death pattern.
969 int event_music_player_death()
971 if ( Event_music_enabled == FALSE )
974 if ( Event_music_level_inited == FALSE )
977 if ( Current_pattern == SONG_DEAD_1 )
978 return 0; // already playing
980 if ( Current_pattern != -1 ) {
981 Patterns[Current_pattern].next_pattern = SONG_DEAD_1;
982 Patterns[Current_pattern].force_pattern = TRUE;
988 // -------------------------------------------------------------------------------------------------
989 // event_music_player_respawn()
991 // Player has respawned (multiplayer only)
993 int event_music_player_respawn()
995 if ( Event_music_enabled == FALSE )
998 if ( Event_music_level_inited == FALSE )
1001 // Assert(Current_pattern == SONG_DEAD_1);
1003 Event_Music_battle_started = 0;
1004 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
1005 Patterns[Current_pattern].force_pattern = TRUE;
1010 // -------------------------------------------------------------------------------------------------
1011 // event_music_player_respawn_as_observer()
1013 // Player has respawned (multiplayer only)
1015 int event_music_player_respawn_as_observer()
1017 if ( Event_music_enabled == FALSE )
1020 if ( Event_music_level_inited == FALSE )
1023 if ( Current_pattern >= 0 ) {
1024 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1025 audiostream_stop(Patterns[Current_pattern].handle);
1026 Current_pattern = -1;
1033 // -------------------------------------------------------------------------------------------------
1034 // event_music_parse_musictbl() will parse the music.tbl file, and set up the Mission_songs[]
1037 void event_music_parse_musictbl()
1039 char fname[MAX_FILENAME_LEN];
1043 int num_patterns = 0;
1045 Num_music_files = 0;
1046 Num_soundtracks = 0; // Global
1047 event_music_reset_choices();
1049 if ((rval = setjmp(parse_abort)) != 0) {
1050 Error(LOCATION, "Unable to parse music.tbl! Code = %i.\n", rval);
1053 // open localization
1056 read_file_text("music.tbl");
1059 // Loop through all the sound-tracks
1060 while (required_string_either("#Menu Music Start","#SoundTrack Start")) {
1061 Assert(Num_soundtracks < MAX_SOUNDTRACKS);
1062 required_string("#SoundTrack Start");
1063 required_string("$SoundTrack Name:");
1064 stuff_string(Soundtracks[Num_soundtracks].name, F_NAME, NULL);
1065 while (required_string_either("#SoundTrack End","$Name:")) {
1066 Assert( num_patterns < MAX_PATTERNS );
1067 required_string("$Name:");
1068 stuff_string(line_buf, F_NAME, NULL);
1070 // line_buf holds 3 fields: filename, num measures, bytes per measure
1074 token = strtok( line_buf, NOX(" ,\t"));
1075 strcpy(fname, token);
1076 while ( token != NULL ) {
1077 token = strtok( NULL, NOX(" ,\t") );
1078 if ( token == NULL ) {
1079 Assert(count == 2 );
1084 Pattern_num_measures[Num_soundtracks][num_patterns] = (float)atof(token);
1087 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] = atoi(token);
1093 // convert from samples per measure to bytes per measure
1094 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] *= 2;
1095 strcpy(Soundtracks[Num_soundtracks].pattern_fnames[num_patterns], fname);
1099 required_string("#SoundTrack End");
1100 Soundtracks[Num_soundtracks].num_patterns = num_patterns;
1105 // Parse the menu music section
1106 required_string("#Menu Music Start");
1107 while (required_string_either("#Menu Music End","$Name:")) {
1108 Assert( Num_music_files < MAX_SPOOLED_MUSIC );
1110 required_string("$Name:");
1111 stuff_string(fname, F_PATHNAME, NULL);
1112 Assert( strlen(fname) < (NAME_LENGTH-1) );
1113 strcpy( Spooled_music[Num_music_files].name, fname );
1115 required_string("$Filename:");
1116 stuff_string(fname, F_PATHNAME, NULL);
1117 if ( stricmp(fname, NOX("none.wav")) ) {
1118 Assert( strlen(fname) < (MAX_FILENAME_LEN-1) );
1119 strcpy( Spooled_music[Num_music_files].filename, fname );
1125 required_string("#Menu Music End");
1127 // close localization
1132 // -------------------------------------------------------------------------------------------------
1133 // event_music_change_pattern()
1135 // Force a particular pattern to play. This is used for debugging purposes.
1137 void event_music_change_pattern(int new_pattern)
1139 if ( Event_music_enabled == FALSE ) {
1140 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1144 if ( Event_music_level_inited == FALSE ) {
1145 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1149 if ( Current_pattern == new_pattern )
1150 return; // already playing
1152 if ( Current_pattern != -1 ) {
1153 Patterns[Current_pattern].next_pattern = new_pattern;
1154 Patterns[Current_pattern].force_pattern = TRUE;
1158 // -------------------------------------------------------------------------------------------------
1159 // event_music_return_current_pattern()
1161 // Simply return what the current pattern being played is. Don't want to make global.
1163 int event_music_return_current_pattern()
1165 return Current_pattern;
1168 // -------------------------------------------------------------------------------------------------
1169 // event_music_disable()
1171 // Stop any patterns that are playing, and prevent any further patterns from playing (ie
1172 // set Event_music_enabled = FALSE). We don't uninit event music, since it might be toggled
1173 // back on this level.
1175 void event_music_disable()
1177 if ( Event_music_level_inited == FALSE )
1180 if ( Event_music_enabled == FALSE )
1183 if (Current_pattern == -1)
1186 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1187 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1188 audiostream_stop(Patterns[Current_pattern].handle); // stop current and rewind
1191 Event_music_begun = FALSE;
1192 Event_music_enabled = FALSE;
1193 Current_pattern = -1;
1196 // -------------------------------------------------------------------------------------------------
1197 // event_music_enable()
1199 // Init the event music (ie load the patterns) if required. Set up the first song to play, and
1200 // set Event_music_enabled = TRUE to allow patterns to play.
1202 void event_music_enable()
1204 if ( Event_music_enabled == TRUE )
1207 Event_music_enabled = TRUE;
1209 if ( Event_music_level_inited == FALSE ) {
1210 event_music_level_init();
1211 // start the first pattern to play (delayed)
1212 if ( Game_mode & GM_IN_MISSION ) {
1213 event_music_first_pattern();
1217 // start a new pattern
1218 Event_music_begun = FALSE;
1219 Pattern_timer_id = timestamp(150);
1220 event_music_start_default();
1224 // -------------------------------------------------------------------------------------------------
1225 // event_music_start_default()
1227 // Start playing a default track, based on how far the mission has progressed
1229 void event_music_start_default()
1233 if ( Event_Music_battle_started == TRUE ) {
1234 if ( hostile_ships_present() ) {
1235 next_pattern = SONG_BTTL_1;
1238 Event_Music_battle_started = FALSE;
1239 next_pattern = SONG_NRML_1;
1243 next_pattern = SONG_NRML_1;
1245 if ( Current_pattern == -1 ) {
1246 Current_pattern = next_pattern;
1249 Patterns[Current_pattern].next_pattern = next_pattern;
1250 Patterns[Current_pattern].force_pattern = TRUE;
1255 // -------------------------------------------------------------------------------------------------
1256 // event_music_pause()
1258 // Stop any playing pattern, but don't rewind.
1260 void event_music_pause()
1262 if ( Event_music_enabled == FALSE ) {
1263 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1267 if ( Event_music_level_inited == FALSE ) {
1268 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1272 if (Current_pattern == -1)
1275 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1276 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1277 audiostream_stop(Patterns[Current_pattern].handle, 0); // stop current and don't rewind
1281 // -------------------------------------------------------------------------------------------------
1282 // event_music_unpause()
1284 // Start the Current_pattern if it is paused.
1286 void event_music_unpause()
1288 if ( Event_music_enabled == FALSE ) {
1289 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1293 if ( Event_music_level_inited == FALSE ) {
1294 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1298 if (Current_pattern == -1)
1301 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1302 if ( audiostream_is_paused(Patterns[Current_pattern].handle) == TRUE ) {
1303 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
1304 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
1308 // -------------------------------------------------------------------------------------------------
1309 // event_music_set_volume_all()
1311 // Set the volume of the event driven music. Used when using the game-wide music volume is changed
1314 void event_music_set_volume_all(float volume)
1316 audiostream_set_volume_all(volume, ASF_EVENTMUSIC);
1319 // ----------------------------------------------------------------------
1320 // hostile_ships_present()
1322 // Determine if there are any non-friendly ships in existance
1324 // returns: 1 => there are non-friendly ships in existance
1325 // 0 => any ships in existance are friendly
1326 int hostile_ships_present()
1331 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1332 shipp = &Ships[Objects[so->objnum].instance];
1334 // check if ship if enemy ship
1335 if ( (shipp->team == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR) )
1338 // check if ship is threatening
1339 if ( (shipp->flags & (SF_DISABLED|SF_DYING|SF_DEPARTING)) || (ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE)) )
1342 // check if ship is flyable
1343 if ( Ship_info[shipp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
1347 // check if ship is visible by player's team
1348 if ( hud_target_invalid_awacs(&Objects[so->objnum]) == 1 ) {
1357 // ----------------------------------------------------------------------
1358 // hostile_ships_to_arrive()
1360 // Determine if there are any non-friendly ships yet to arrive
1362 // NOTE: neutral ships are considered hostile for the purpose of event music
1364 int hostile_ships_to_arrive()
1368 p_objp = GET_FIRST(&ship_arrival_list);
1369 while( p_objp != END_OF_LIST(&ship_arrival_list) ) {
1370 if ( (p_objp->team != Player_ship->team) && !(p_objp->flags & P_SF_CANNOT_ARRIVE) ) {
1373 p_objp = GET_NEXT(p_objp);
1378 // ----------------------------------------------------------------
1379 // event_music_get_info()
1381 // Return information about the event music in the buffer outbuf
1382 // NOTE: callers to this function are advised to allocate a 256 byte buffer
1383 void event_music_get_info(char *outbuf)
1385 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
1386 sprintf(outbuf,XSTR( "Event music is not playing", 213));
1389 sprintf(outbuf,XSTR( "soundtrack: %s [%s]", 214), Soundtracks[Current_soundtrack_num].name, Pattern_description[Current_pattern]);
1393 // ----------------------------------------------------------------
1394 // event_music_next_soundtrack()
1396 // input: delta => 1 or -1, depending if you want to go to next or previous song
1398 // returns: New soundtrack number if successfully changed, otherwise return -1
1400 int event_music_next_soundtrack(int delta)
1404 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1408 new_soundtrack = Current_soundtrack_num + delta;
1409 if ( new_soundtrack >= Num_soundtracks )
1412 event_music_level_close();
1413 event_music_level_init(new_soundtrack);
1415 return Current_soundtrack_num;
1418 // ----------------------------------------------------------------
1419 // event_music_get_soundtrack_name()
1421 // Return information about the event music in the buffer outbuf
1422 // NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
1423 void event_music_get_soundtrack_name(char *outbuf)
1425 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1426 strcpy(outbuf, XSTR( "Event music is not playing", 213));
1429 sprintf(outbuf, Soundtracks[Current_soundtrack_num].name);
1433 // set the current soundtrack based on name
1434 void event_music_set_soundtrack(char *name)
1438 // find the correct index for the event music
1439 for ( i = 0; i < Num_soundtracks; i++ ) {
1440 if ( !stricmp(name, Soundtracks[i].name) ) {
1441 Current_soundtrack_num = i;
1446 if ( i == Num_soundtracks ) {
1447 Current_soundtrack_num = -1;
1448 mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
1452 int event_music_get_spooled_music_index(char *name)
1454 // find the correct index for the event music
1455 for ( int i = 0; i < Num_music_files; i++ ) {
1456 if ( !stricmp(name, Spooled_music[i].name) ) {
1464 // set a score based on name
1465 void event_music_set_score(int score_index, char *name)
1467 Assert(score_index < NUM_SCORES);
1469 // find the correct index for the event music
1470 Mission_music[score_index] = event_music_get_spooled_music_index(name);
1473 // reset what sort of music is to be used for this mission
1474 void event_music_reset_choices()
1476 Current_soundtrack_num = -1;
1477 mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
1478 Mission_music[SCORE_BRIEFING] = -1;
1479 event_music_set_score(SCORE_DEBRIEF_SUCCESS, "Success");
1480 event_music_set_score(SCORE_DEBRIEF_AVERAGE, "Average");
1481 event_music_set_score(SCORE_DEBRIEF_FAIL, "Failure");
1482 //Mission_music[SCORE_DEBRIEF_SUCCESS] = MUSIC_DEBRIEF_SUCCESS_1;
1483 //Mission_music[SCORE_DEBRIEF_FAIL] = MUSIC_DEBRIEF_FAIL_1;
1486 void event_music_hostile_ship_destroyed()
1488 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
1492 #pragma optimize("", on)