2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Gamesnd/EventMusic.cpp $
15 * C module for high-level control of event driven music
18 * Revision 1.4 2002/06/09 04:41:17 relnev
19 * added copyright header
21 * Revision 1.3 2002/05/28 08:52:03 relnev
22 * implemented two assembly stubs.
24 * cleaned up a few warnings.
26 * added a little demo hackery to make it progress a little farther.
28 * Revision 1.2 2002/05/07 03:16:45 theoddone33
29 * The Great Newline Fix
31 * Revision 1.1.1.1 2002/05/03 03:28:09 root
35 * 14 8/19/99 9:41a Alanl
36 * don't play victory 2 music if there are no goals in the mission
38 * 13 8/11/99 5:33p Jefff
39 * added 3rd debrief music track
41 * 12 8/01/99 2:11p Alanl
42 * make hull value to play more intense battle music a constant
44 * 11 8/01/99 2:06p Alanl
45 * tweak battle music track switching
47 * 10 7/25/99 9:57p Alanl
48 * change battle music track selection after enemy arrivals to make battle
49 * tracks less repetitive
51 * 9 7/19/99 10:13p Andsager
52 * Tie in hud_targeting to hostile_ships_present() used to determine next
55 * 8 6/24/99 10:47p Alanl
56 * loop battle between tracks 2 and 3 if hull integrity < 70%
58 * 7 6/21/99 1:34p Alanl
61 * 6 6/20/99 12:06a Alanl
62 * new event music changes
64 * 5 11/23/98 11:55a Johnson
65 * return -1 if a score isn't found
67 * 4 11/20/98 4:08p Dave
68 * Fixed flak effect in multiplayer.
70 * 3 10/23/98 3:51p Dave
71 * Full support for tstrings.tbl and foreign languages. All that remains
72 * is to make it active in Fred.
74 * 2 10/07/98 10:52a Dave
77 * 1 10/07/98 10:48a Dave
79 * 107 6/09/98 5:15p Lawrance
80 * French/German localization
82 * 106 6/09/98 10:31a Hoffoss
83 * Created index numbers for all xstr() references. Any new xstr() stuff
84 * added from here on out should be added to the end if the list. The
85 * current list count can be found in FreeSpace.cpp (search for
88 * 105 5/24/98 5:28p Dan
89 * let event_music_level_init() over-ride Event_music_enabled
91 * 104 5/24/98 4:42p Dan
92 * AL: Fix several bugs related to pausing and enabling/disabling event
95 * 103 5/23/98 3:17a Lawrance
96 * Tweak how battle music gets restarted
98 * 102 5/22/98 10:43a Lawrance
99 * If mission doesn't have event music, don't choose random track
101 * 101 5/21/98 6:56p Lawrance
102 * Tweak how victory music plays
104 * 100 5/21/98 2:47a Lawrance
105 * Fix some problems with event music
107 * 99 5/18/98 3:21p Mike
108 * Don't play arrival and goals tracks in a training mission.
110 * 98 5/04/98 3:15p Duncan
111 * AL: remove bogus assert in event_music_player_respawn()
113 * 97 5/03/98 1:54a Lawrance
114 * Fix event music problems related to respawning
116 * 96 4/03/98 12:56a Lawrance
117 * Fix bug with music not starting in the first mission
119 * 95 4/01/98 6:46p Lawrance
120 * Lower default music volume
127 #include "eventmusic.h"
130 #include "linklist.h"
131 #include "missionload.h" /* for Builtin_mission_names[] */
132 #include "missionparse.h"
134 #include "freespace.h"
135 #include "audiostr.h"
136 #include "missioncampaign.h"
140 #include "missiongoals.h"
141 #include "localize.h"
144 #pragma optimize("", off)
147 #define DEFAULT_MASTER_EVENT_MUSIC_VOLUME 0.5f
149 #define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
151 ////////////////////////////
153 ////////////////////////////
154 int Event_Music_battle_started = 0;
155 float Master_event_music_volume = DEFAULT_MASTER_EVENT_MUSIC_VOLUME; // range is 0->1
157 // array that holds which soundtrack is used for which mission (data comes from music.tbl)
158 //int Mission_soundtracks[MAX_CAMPAIGN_MISSIONS];
160 // array that holds which briefing track to play for which mission. Index into Spooled_music[][].
161 //int Mission_briefingmusic[MAX_CAMPAIGN_MISSIONS];
163 typedef struct tagSNDPATTERN {
164 int default_next_pattern; // Needed so the next_pattern member can be reset
165 int next_pattern; // Next pattern to play at loop time (can be same pattern)
166 int default_loop_for; // Needed so the loop_for variable can be reset
167 int loop_for; // Number of times to loop before switching to next pattern
168 int handle; // handle to open audio stream
169 int force_pattern; // flag to indicate that we want to not continue loop, but go to next_pattern
170 int can_force; // whether this pattern can be interrupted
171 int bytes_per_measure; // number of bytes in a measure
172 float num_measures; // number of measures in wave file
175 SNDPATTERN Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
177 // Holds filenames for the different sections of a soundtrack
178 SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
180 int Current_soundtrack_num; // Active soundtrack for the current mission.. index into Soundtracks[]
182 #define PATTERN_DELAY 1000 // in ms
183 int Current_pattern = -1; // currently playing part of track
184 int Pending_pattern = -1;
185 int Pattern_timer_id = 0;
188 static int Num_enemy_arrivals;
189 static int Num_friendly_arrivals;
191 #define ARRIVAL_INTERVAL_TIMESTAMP 5000
192 #define BATTLE_CHECK_INTERVAL 15000
193 static int Battle_over_timestamp;
194 static int Mission_over_timestamp;
195 static int Victory2_music_played;
196 static int Next_arrival_timestamp;
197 static int Check_for_battle_music;
199 // stores the number of measures for the different patterns (data from music.tbl)
200 float Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS];
202 // stores the number of bytes per measure (data from music.tbl)
203 int Pattern_bytes_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS];
205 char* Pattern_names[MAX_PATTERNS] =
208 "NRML_1", // Normal Song 1
209 "AARV_1", // Allied Arrival 1
210 "EARV_1", // Enemy Arrival 1
211 "BTTL_1", // Battle Song 1
212 "BTTL_2", // Battle Song 2
213 "BTTL_3", // Battle Song 3
214 "AARV_2", // Allied Arrival 2
215 "EARV_2", // Enemy Arrival 2
216 "VICT_1", // Victory Song 1
217 "VICT_2", // Victory Song 2
218 "FAIL_1" // Goal Failed 1
219 "DEAD_1" // Death Song 1
223 char* Pattern_description[MAX_PATTERNS] =
227 "friendly arrival 1",
232 "friendly arrival 2",
241 int Pattern_loop_for[MAX_PATTERNS] =
244 1, // Allied Arrival 1
245 1, // Enemy Arrival 1
249 1, // Allied Arrival 2
250 1, // Enemy Arrival 2
257 int Pattern_default_next[MAX_PATTERNS] =
259 SONG_NRML_1, // NRML_1 progresses to NRML_1 by default
260 SONG_NRML_1, // AARV_1 progresses to NRML_1 by default
261 SONG_BTTL_1, // EARV_1 progresses to BTTL_1 by default
262 SONG_BTTL_2, // BTTL_1 progresses to BTTL_2 by default
263 SONG_BTTL_3, // BTTL_2 progresses to BTTL_3 by default
264 SONG_BTTL_1, // BTTL_3 progresses to BTTL_1 by default
265 SONG_BTTL_2, // AARV_2 progresses to BTTL_2 by default
266 SONG_BTTL_3, // EARV_2 progresses to BTTL_3 by default
267 SONG_NRML_1, // VICT_1 progresses to NRML_1 by default
268 SONG_NRML_1, // VICT_2 progresses to NRML_1 by default
269 SONG_NRML_1, // FAIL_1 progresses to NRML_1 by default
270 -1 // no music plays after dead
274 // Certain patterns can be interrupted (such as the long-playing NRML and BTTL tracks).
275 // Other shorter tracks (such as arrivals) play their entire duration.
276 int Pattern_can_force[MAX_PATTERNS] =
293 int Event_music_enabled = TRUE;
294 static int Event_music_inited = FALSE;
295 static int Event_music_level_inited = FALSE;
296 static int Event_music_begun = FALSE;
298 // forward function declarations
299 int hostile_ships_present();
300 int hostile_ships_to_arrive();
301 extern int hud_target_invalid_awacs(object *objp);
303 // Holds file names of spooled music that is played at menus, briefings, credits etc.
304 // Indexed into by a #define enumeration of the different kinds of spooled music
305 menu_music Spooled_music[MAX_SPOOLED_MUSIC];
306 int Num_music_files; // Number of spooled music files
308 // Array that holds indicies into Spooled_music[], these specify which music is played in breifing/debriefing
309 int Mission_music[NUM_SCORES];
311 // -------------------------------------------------------------------------------------------------
312 // event_music_init()
314 // Called once at game start-up to parse music.tbl and set some state variables
316 void event_music_init()
318 if ( snd_is_inited() == FALSE ) {
319 Event_music_enabled = FALSE;
323 if ( Cmdline_freespace_no_music ) {
327 if ( Event_music_inited == TRUE )
330 event_music_parse_musictbl();
331 Event_music_inited = TRUE;
332 Event_music_begun = FALSE;
335 // -------------------------------------------------------------------------------------------------
336 // event_music_close()
338 // Called once at game end
340 void event_music_close()
342 if ( Event_music_inited == FALSE )
345 Event_music_inited = FALSE;
348 // -------------------------------------------------------------------------------------------------
349 // event_music_force_switch()
351 // Performs a switch between patterns. Sets the cutoff limit for the pattern that is being
354 void event_music_force_switch()
356 if ( Event_music_enabled == FALSE )
359 if ( Event_music_level_inited == FALSE )
363 Patterns[Current_pattern].loop_for = Patterns[Current_pattern].default_loop_for;
365 new_pattern = Patterns[Current_pattern].next_pattern;
367 if ( (new_pattern == SONG_BTTL_3) && (Patterns[SONG_BTTL_3].handle == -1) ) {
368 if ( Current_pattern == SONG_BTTL_2 ) {
369 new_pattern = SONG_BTTL_1;
371 new_pattern = SONG_BTTL_2;
374 if (Current_pattern == SONG_BTTL_3 && new_pattern == SONG_BTTL_1) {
375 // AL 06-24-99: maybe switch to battle 2 if hull is less than 70%
376 if (Player_obj != NULL && Player_ship != NULL) {
377 Assert(Player_ship->ship_info_index >= 0);
378 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
379 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
380 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
381 new_pattern = SONG_BTTL_2;
387 if ( new_pattern == -1 ) {
391 if ( Patterns[new_pattern].num_measures == 0 )
392 return; // invalid pattern
394 Assert(new_pattern >= 0 && new_pattern < MAX_PATTERNS);
395 audiostream_play(Patterns[new_pattern].handle, Master_event_music_volume, 0); // no looping
396 audiostream_set_byte_cutoff(Patterns[new_pattern].handle, fl2i(Patterns[new_pattern].num_measures * Patterns[new_pattern].bytes_per_measure) );
397 Patterns[Current_pattern].next_pattern = Patterns[Current_pattern].default_next_pattern;
398 Patterns[Current_pattern].force_pattern = FALSE;
399 nprintf(("EVENTMUSIC", "EVENTMUSIC => switching to %s from %s\n", Pattern_names[new_pattern], Pattern_names[Current_pattern]));
400 Current_pattern = new_pattern;
403 // -------------------------------------------------------------------------------------------------
404 // event_music_do_frame()
406 // Called once per game frame, to check for transitions of patterns (and to start the music off at
409 void event_music_do_frame()
411 if ( Event_music_level_inited == FALSE ) {
415 if ( Event_music_enabled == FALSE ) {
419 // start off the music delayed
420 if ( timestamp_elapsed(Pattern_timer_id) ) {
421 Pattern_timer_id = 0;
422 Event_music_begun = TRUE;
423 if ( Current_pattern != -1 ) {
424 Assert(Patterns[Current_pattern].handle >= 0 );
425 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
426 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
430 if ( Event_music_begun == FALSE ) {
434 if ( Current_pattern != -1 ) {
436 pat = &Patterns[Current_pattern];
438 // First case: switching to a different track since first track is almost at end
439 if ( audiostream_done_reading(pat->handle) ) {
440 event_music_force_switch();
442 // Second case: looping back to start of same track since at the end
443 else if ( !audiostream_is_playing(pat->handle) && !audiostream_is_paused(pat->handle) ) {
444 audiostream_stop(pat->handle); // stop current and rewind
446 if ( pat->loop_for > 0 ) {
447 audiostream_play(pat->handle, Master_event_music_volume, 0); // no looping
448 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
451 event_music_force_switch();
454 // Third case: switching to a different track by interruption
455 else if ( (pat->force_pattern == TRUE && pat->can_force == TRUE) ) {
456 int bytes_streamed = audiostream_get_bytes_committed(pat->handle);
457 int measures_played = bytes_streamed / pat->bytes_per_measure;
458 if ( measures_played < pat->num_measures ) {
459 audiostream_set_byte_cutoff(pat->handle, pat->bytes_per_measure * (measures_played+1) );
460 pat->force_pattern = FALSE;
465 // We want to go back to NRML track music if all the hostiles have been
466 // destroyed, and we are still playing the battle music
467 if ( Current_pattern == SONG_BTTL_1 || Current_pattern == SONG_BTTL_2 || Current_pattern == SONG_BTTL_3 ) {
468 if ( timestamp_elapsed(Battle_over_timestamp) && Event_Music_battle_started == 1) {
469 //Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
470 if ( hostile_ships_present() == FALSE ) {
471 if ( Patterns[Current_pattern].next_pattern != SONG_VICT_2 ) {
472 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
473 Patterns[Current_pattern].force_pattern = TRUE;
474 Event_Music_battle_started = 0;
480 if (Event_Music_battle_started == 0) {
481 if (Current_pattern == SONG_NRML_1) {
482 if (timestamp_elapsed(Check_for_battle_music)) {
483 Check_for_battle_music = timestamp(1000);
484 if (hostile_ships_present() == TRUE) {
485 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
486 Patterns[Current_pattern].force_pattern = TRUE;
492 if ( !Victory2_music_played ) {
493 if ( timestamp_elapsed(Mission_over_timestamp) ) {
494 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
495 if ( mission_goals_met() && (!hostile_ships_present()) ) {
496 Patterns[Current_pattern].next_pattern = SONG_VICT_2;
497 Patterns[Current_pattern].force_pattern = TRUE;
498 Victory2_music_played = 1;
505 // -------------------------------------------------------------------------------------------------
506 // event_music_level_init()
508 // Called at the start of a mission (level). Sets up the pattern data, and kicks off the
509 // first track to play().
511 // input: force_soundtrack => OPTIONAL parameter (default value -1)
512 // forces the soundtrack to ignore the music.tbl assignment
514 void event_music_level_init(int force_soundtrack)
517 SOUNDTRACK_INFO *strack;
519 if ( Cmdline_freespace_no_music ) {
523 if ( !audiostream_is_inited() )
526 if ( Event_music_level_inited == TRUE )
529 Current_pattern = -1;
531 if ( Event_music_inited == FALSE )
535 if ( force_soundtrack != -1 ) {
536 Current_soundtrack_num = force_soundtrack;
539 if ( Current_soundtrack_num < 0 ) {
542 // okay, assign a random soundtrack if one exists
543 if ( Num_soundtracks > 0 ) {
544 Current_soundtrack_num = rand()%Num_soundtracks;
545 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Picking random event music soundtrack: %s\n", Soundtracks[Current_soundtrack_num].name));
552 Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < Num_soundtracks);
553 strack = &Soundtracks[Current_soundtrack_num];
555 // open the pattern files, and get ready to play them
556 for ( i = 0; i < strack->num_patterns; i++ ) {
557 if ( !stricmp(NOX("none.wav"), strack->pattern_fnames[i]) ) {
558 Patterns[i].handle = -1;
562 Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
564 if ( Patterns[i].handle >= 0 ) {
565 Event_music_level_inited = TRUE;
566 Event_music_enabled = TRUE;
569 Patterns[i].next_pattern = Pattern_default_next[i];
570 Patterns[i].default_next_pattern = Pattern_default_next[i];
571 Patterns[i].loop_for = Pattern_loop_for[i];
572 Patterns[i].default_loop_for = Pattern_loop_for[i];
573 Patterns[i].force_pattern = FALSE;
574 Patterns[i].can_force = Pattern_can_force[i];
575 Patterns[i].bytes_per_measure = Pattern_bytes_per_measure[Current_soundtrack_num][i];
576 Patterns[i].num_measures = Pattern_num_measures[Current_soundtrack_num][i];
579 Num_enemy_arrivals = 0;
580 Num_friendly_arrivals = 0;
581 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
582 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
583 Next_arrival_timestamp = timestamp(1);
584 Victory2_music_played = 0;
585 Check_for_battle_music = 0;
587 if ( Event_music_level_inited ) {
588 if ( force_soundtrack != -1 ) {
589 event_music_first_pattern();
594 // -------------------------------------------------------------------------------------------------
595 // event_music_first_pattern()
597 // Picks the first pattern to play, based on whether the battle has started. Delay start
600 void event_music_first_pattern()
602 if ( Event_music_inited == FALSE ) {
606 if ( Event_music_enabled == FALSE ) {
610 if ( Event_music_level_inited == FALSE ) {
611 event_music_level_init();
614 if ( Event_music_level_inited == FALSE ) {
618 if ( Event_music_begun == TRUE ) {
622 if ( Current_pattern != -1 ) {
623 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
624 audiostream_stop( Patterns[Current_pattern].handle );
627 Pattern_timer_id = 2000; // start music delay
629 Event_music_begun = FALSE;
630 if ( Event_Music_battle_started == TRUE ) {
631 Current_pattern = SONG_BTTL_1;
634 Current_pattern = SONG_NRML_1;
638 // -------------------------------------------------------------------------------------------------
639 // event_music_level_close()
641 // Called at the end of each mission (level). Stops any playing patterns by fading them out.
643 void event_music_level_close()
647 if ( Event_music_level_inited == FALSE )
650 if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS ) {
651 SOUNDTRACK_INFO *strack;
653 Assert( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS );
654 strack = &Soundtracks[Current_soundtrack_num];
656 // close the pattern files
657 for ( i = 0; i < strack->num_patterns; i++ ) {
658 if ( i == Current_pattern ) {
659 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
660 audiostream_close_file( Patterns[i].handle );
662 audiostream_close_file( Patterns[i].handle, 0 );
665 audiostream_close_file( Patterns[i].handle, 0 );
668 // close em all down then
669 audiostream_close_all(0);
672 Current_pattern = -1;
673 Event_music_level_inited = FALSE;
674 Event_Music_battle_started = FALSE;
675 Event_music_enabled = 0;
676 Event_music_begun = FALSE;
679 // -------------------------------------------------------------------------------------------------
680 // event_music_battle_start()
682 // Start the battle music. If the music is already started before, do nothing.
684 int event_music_battle_start()
686 if ( !hostile_ships_present() ) {
690 // No special tracks in training.
691 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
694 // Check to see if we've already started off the battle song
695 if ( Event_Music_battle_started == 1 ) {
699 if ( Event_music_enabled == FALSE )
702 if ( Event_music_level_inited == FALSE )
705 if ( Current_pattern == SONG_BTTL_1 )
706 return 0; // already playing
708 if ( Current_pattern == SONG_DEAD_1 )
709 return 0; // death is the last song to play
711 if ( Current_pattern != -1 ) {
712 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
713 Patterns[Current_pattern].force_pattern = TRUE;
716 Event_Music_battle_started = 1; // keep track of this state though, need on restore
717 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
722 // -------------------------------------------------------------------------------------------------
723 // event_music_enemy_arrival()
725 // An enemy has arrived, play an enemy arrival pattern.
727 int event_music_enemy_arrival()
729 if ( Event_music_enabled == FALSE ) {
733 if ( Event_music_level_inited == FALSE ) {
738 if ( Event_Music_battle_started == TRUE ) {
739 next_pattern = SONG_EARV_2;
742 next_pattern = SONG_EARV_1;
745 if ( Current_pattern == next_pattern )
746 return 0; // already playing
748 if ( Current_pattern == SONG_DEAD_1 )
749 return 0; // death is the last song to play
751 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
754 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
755 return 0; // don't squash a pending pattern
757 Num_enemy_arrivals++;
759 // AL 7-25-99: If hull is less than 70% then switch to battle 2 or 3, otherwise switch to 1 or 2
760 bool play_intense_battle_music = false;
761 if (Player_obj != NULL && Player_ship != NULL) {
762 Assert(Player_ship->ship_info_index >= 0);
763 Assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
764 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
765 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
766 play_intense_battle_music = true;
770 if (play_intense_battle_music == true) {
771 if (Current_pattern == SONG_BTTL_2) {
772 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
774 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
777 if (Current_pattern == SONG_BTTL_1) {
778 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
779 } else if (Current_pattern == SONG_BTTL_2) {
780 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
782 Patterns[next_pattern].next_pattern = SONG_BTTL_1;
788 // Alternate between BTTL_2 and BTTL_3 following enemy arrivals
789 if ( Num_enemy_arrivals & 1 ) {
790 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
792 if ( Patterns[SONG_BTTL_3].handle != -1 ) {
793 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
795 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
800 if ( Current_pattern != -1 ) {
801 Patterns[Current_pattern].next_pattern = next_pattern;
802 Patterns[Current_pattern].force_pattern = TRUE;
805 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
810 // -------------------------------------------------------------------------------------------------
811 // event_music_friendly_arrival()
813 // An friendly has arrived, play a friendly arrival pattern.
815 int event_music_friendly_arrival()
817 if ( Event_music_enabled == FALSE )
820 if ( Event_music_level_inited == FALSE )
823 if (timestamp_elapsed(Next_arrival_timestamp) == false) {
828 if ( Event_Music_battle_started == TRUE ) {
829 next_pattern = SONG_AARV_2;
832 next_pattern = SONG_AARV_1;
835 if ( Current_pattern == next_pattern )
836 return 0; // already playing
838 if ( Current_pattern == SONG_DEAD_1 )
839 return 0; // death is the last song to play
841 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
844 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
845 return 0; // don't squash a pending pattern
847 // After the second friendly arrival, default to SONG_BTTL_3
848 Num_friendly_arrivals++;
850 if ( Current_pattern != -1 ) {
851 // AL 06-24-99: always overlay allied arrivals
853 if (next_pattern == SONG_AARV_1) {
854 Patterns[Current_pattern].next_pattern = next_pattern;
855 Patterns[Current_pattern].force_pattern = TRUE;
858 Assert(Patterns[SONG_AARV_1].handle >= 0 );
859 audiostream_play(Patterns[SONG_AARV_1].handle, Master_event_music_volume, 0); // no looping
860 audiostream_set_byte_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].bytes_per_measure) );
864 Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
866 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
871 // Play arrival music keyed to team "team".
872 void event_music_arrival(int team)
874 // No friendly arrival music in a training mission.
875 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
878 if ( Player_ship->team == team ) {
879 event_music_friendly_arrival();
881 event_music_enemy_arrival();
885 // -------------------------------------------------------------------------------------------------
886 // event_music_primary_goals_met()
888 // A primary goal has failed
890 int event_music_primary_goal_failed()
894 // No special tracks in training.
895 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
898 if ( Event_music_enabled == FALSE )
901 if ( Event_music_level_inited == FALSE )
904 if ( Current_pattern == SONG_DEAD_1 )
905 return 0; // death is the last song to play
907 if ( Patterns[SONG_FAIL_1].handle < 0 ) // can't play if music file doesn't exist
910 if ( hostile_ships_present() ) {
911 next_pattern = SONG_BTTL_1;
914 next_pattern = SONG_NRML_1;
915 Event_Music_battle_started = 0;
918 if ( Current_pattern != -1 ) {
919 Patterns[Current_pattern].next_pattern = next_pattern;
920 Patterns[Current_pattern].force_pattern = TRUE;
926 // -------------------------------------------------------------------------------------------------
927 // event_music_primary_goals_met()
929 // A goal has been achieved, play the appropriate victory music.
931 int event_music_primary_goals_met()
933 int next_pattern = SONG_VICT_1;
935 // No special tracks in training.
936 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
939 if ( Event_music_enabled == FALSE )
942 if ( Event_music_level_inited == FALSE )
945 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_2) )
946 return 0; // already playing
948 if ( Current_pattern == SONG_DEAD_1 )
949 return 0; // death is the last song to play
951 if ( hostile_ships_present() ) {
952 Patterns[SONG_VICT_1].next_pattern = SONG_BTTL_1;
955 Patterns[SONG_VICT_1].next_pattern = SONG_VICT_2;
956 Event_Music_battle_started = 0;
958 // If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
959 // to the next default track
960 if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
961 Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
963 Victory2_music_played = 1;
967 if ( Current_pattern != -1 ) {
968 Patterns[Current_pattern].next_pattern = next_pattern;
969 Patterns[Current_pattern].force_pattern = TRUE;
975 // -------------------------------------------------------------------------------------------------
976 // event_music_player_death()
978 // The player has died, play death pattern.
980 int event_music_player_death()
982 if ( Event_music_enabled == FALSE )
985 if ( Event_music_level_inited == FALSE )
988 if ( Current_pattern == SONG_DEAD_1 )
989 return 0; // already playing
991 if ( Current_pattern != -1 ) {
992 Patterns[Current_pattern].next_pattern = SONG_DEAD_1;
993 Patterns[Current_pattern].force_pattern = TRUE;
999 // -------------------------------------------------------------------------------------------------
1000 // event_music_player_respawn()
1002 // Player has respawned (multiplayer only)
1004 int event_music_player_respawn()
1006 if ( Event_music_enabled == FALSE )
1009 if ( Event_music_level_inited == FALSE )
1012 // Assert(Current_pattern == SONG_DEAD_1);
1014 Event_Music_battle_started = 0;
1015 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
1016 Patterns[Current_pattern].force_pattern = TRUE;
1021 // -------------------------------------------------------------------------------------------------
1022 // event_music_player_respawn_as_observer()
1024 // Player has respawned (multiplayer only)
1026 int event_music_player_respawn_as_observer()
1028 if ( Event_music_enabled == FALSE )
1031 if ( Event_music_level_inited == FALSE )
1034 if ( Current_pattern >= 0 ) {
1035 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1036 audiostream_stop(Patterns[Current_pattern].handle);
1037 Current_pattern = -1;
1044 // -------------------------------------------------------------------------------------------------
1045 // event_music_parse_musictbl() will parse the music.tbl file, and set up the Mission_songs[]
1048 void event_music_parse_musictbl()
1050 char fname[MAX_FILENAME_LEN];
1054 int num_patterns = 0;
1056 Num_music_files = 0;
1057 Num_soundtracks = 0; // Global
1058 event_music_reset_choices();
1060 if ((rval = setjmp(parse_abort)) != 0) {
1061 Error(LOCATION, "Unable to parse music.tbl! Code = %i.\n", rval);
1064 // open localization
1067 read_file_text("music.tbl");
1070 // Loop through all the sound-tracks
1071 while (required_string_either("#Menu Music Start","#SoundTrack Start")) {
1072 Assert(Num_soundtracks < MAX_SOUNDTRACKS);
1073 required_string("#SoundTrack Start");
1074 required_string("$SoundTrack Name:");
1075 stuff_string(Soundtracks[Num_soundtracks].name, F_NAME, NULL);
1076 while (required_string_either("#SoundTrack End","$Name:")) {
1077 Assert( num_patterns < MAX_PATTERNS );
1078 required_string("$Name:");
1079 stuff_string(line_buf, F_NAME, NULL);
1081 // line_buf holds 3 fields: filename, num measures, bytes per measure
1085 token = strtok( line_buf, NOX(" ,\t"));
1086 strcpy(fname, token);
1087 while ( token != NULL ) {
1088 token = strtok( NULL, NOX(" ,\t") );
1089 if ( token == NULL ) {
1090 Assert(count == 2 );
1095 Pattern_num_measures[Num_soundtracks][num_patterns] = (float)atof(token);
1098 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] = atoi(token);
1104 // convert from samples per measure to bytes per measure
1105 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] *= 2;
1106 strcpy(Soundtracks[Num_soundtracks].pattern_fnames[num_patterns], fname);
1110 required_string("#SoundTrack End");
1111 Soundtracks[Num_soundtracks].num_patterns = num_patterns;
1116 // Parse the menu music section
1117 required_string("#Menu Music Start");
1118 while (required_string_either("#Menu Music End","$Name:")) {
1119 Assert( Num_music_files < MAX_SPOOLED_MUSIC );
1121 required_string("$Name:");
1122 stuff_string(fname, F_PATHNAME, NULL);
1123 Assert( strlen(fname) < (NAME_LENGTH-1) );
1124 strcpy( Spooled_music[Num_music_files].name, fname );
1126 required_string("$Filename:");
1127 stuff_string(fname, F_PATHNAME, NULL);
1128 if ( stricmp(fname, NOX("none.wav")) ) {
1129 Assert( strlen(fname) < (MAX_FILENAME_LEN-1) );
1130 strcpy( Spooled_music[Num_music_files].filename, fname );
1136 required_string("#Menu Music End");
1138 // close localization
1143 // -------------------------------------------------------------------------------------------------
1144 // event_music_change_pattern()
1146 // Force a particular pattern to play. This is used for debugging purposes.
1148 void event_music_change_pattern(int new_pattern)
1150 if ( Event_music_enabled == FALSE ) {
1151 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1155 if ( Event_music_level_inited == FALSE ) {
1156 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1160 if ( Current_pattern == new_pattern )
1161 return; // already playing
1163 if ( Current_pattern != -1 ) {
1164 Patterns[Current_pattern].next_pattern = new_pattern;
1165 Patterns[Current_pattern].force_pattern = TRUE;
1169 // -------------------------------------------------------------------------------------------------
1170 // event_music_return_current_pattern()
1172 // Simply return what the current pattern being played is. Don't want to make global.
1174 int event_music_return_current_pattern()
1176 return Current_pattern;
1179 // -------------------------------------------------------------------------------------------------
1180 // event_music_disable()
1182 // Stop any patterns that are playing, and prevent any further patterns from playing (ie
1183 // set Event_music_enabled = FALSE). We don't uninit event music, since it might be toggled
1184 // back on this level.
1186 void event_music_disable()
1188 if ( Event_music_level_inited == FALSE )
1191 if ( Event_music_enabled == FALSE )
1194 if (Current_pattern == -1)
1197 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1198 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1199 audiostream_stop(Patterns[Current_pattern].handle); // stop current and rewind
1202 Event_music_begun = FALSE;
1203 Event_music_enabled = FALSE;
1204 Current_pattern = -1;
1207 // -------------------------------------------------------------------------------------------------
1208 // event_music_enable()
1210 // Init the event music (ie load the patterns) if required. Set up the first song to play, and
1211 // set Event_music_enabled = TRUE to allow patterns to play.
1213 void event_music_enable()
1215 if ( Event_music_enabled == TRUE )
1218 Event_music_enabled = TRUE;
1220 if ( Event_music_level_inited == FALSE ) {
1221 event_music_level_init();
1222 // start the first pattern to play (delayed)
1223 if ( Game_mode & GM_IN_MISSION ) {
1224 event_music_first_pattern();
1228 // start a new pattern
1229 Event_music_begun = FALSE;
1230 Pattern_timer_id = timestamp(150);
1231 event_music_start_default();
1235 // -------------------------------------------------------------------------------------------------
1236 // event_music_start_default()
1238 // Start playing a default track, based on how far the mission has progressed
1240 void event_music_start_default()
1244 if ( Event_Music_battle_started == TRUE ) {
1245 if ( hostile_ships_present() ) {
1246 next_pattern = SONG_BTTL_1;
1249 Event_Music_battle_started = FALSE;
1250 next_pattern = SONG_NRML_1;
1254 next_pattern = SONG_NRML_1;
1256 if ( Current_pattern == -1 ) {
1257 Current_pattern = next_pattern;
1260 Patterns[Current_pattern].next_pattern = next_pattern;
1261 Patterns[Current_pattern].force_pattern = TRUE;
1266 // -------------------------------------------------------------------------------------------------
1267 // event_music_pause()
1269 // Stop any playing pattern, but don't rewind.
1271 void event_music_pause()
1273 if ( Event_music_enabled == FALSE ) {
1274 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1278 if ( Event_music_level_inited == FALSE ) {
1279 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1283 if (Current_pattern == -1)
1286 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1287 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1288 audiostream_stop(Patterns[Current_pattern].handle, 0); // stop current and don't rewind
1292 // -------------------------------------------------------------------------------------------------
1293 // event_music_unpause()
1295 // Start the Current_pattern if it is paused.
1297 void event_music_unpause()
1299 if ( Event_music_enabled == FALSE ) {
1300 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1304 if ( Event_music_level_inited == FALSE ) {
1305 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1309 if (Current_pattern == -1)
1312 Assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1313 if ( audiostream_is_paused(Patterns[Current_pattern].handle) == TRUE ) {
1314 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
1315 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
1319 // -------------------------------------------------------------------------------------------------
1320 // event_music_set_volume_all()
1322 // Set the volume of the event driven music. Used when using the game-wide music volume is changed
1325 void event_music_set_volume_all(float volume)
1327 audiostream_set_volume_all(volume, ASF_EVENTMUSIC);
1330 // ----------------------------------------------------------------------
1331 // hostile_ships_present()
1333 // Determine if there are any non-friendly ships in existance
1335 // returns: 1 => there are non-friendly ships in existance
1336 // 0 => any ships in existance are friendly
1337 int hostile_ships_present()
1342 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1343 shipp = &Ships[Objects[so->objnum].instance];
1345 // check if ship if enemy ship
1346 if ( (shipp->team == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR) )
1349 // check if ship is threatening
1350 if ( (shipp->flags & (SF_DISABLED|SF_DYING|SF_DEPARTING)) || (ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE)) )
1353 // check if ship is flyable
1354 if ( Ship_info[shipp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
1358 // check if ship is visible by player's team
1359 if ( hud_target_invalid_awacs(&Objects[so->objnum]) == 1 ) {
1368 // ----------------------------------------------------------------------
1369 // hostile_ships_to_arrive()
1371 // Determine if there are any non-friendly ships yet to arrive
1373 // NOTE: neutral ships are considered hostile for the purpose of event music
1375 int hostile_ships_to_arrive()
1379 p_objp = GET_FIRST(&ship_arrival_list);
1380 while( p_objp != END_OF_LIST(&ship_arrival_list) ) {
1381 if ( (p_objp->team != Player_ship->team) && !(p_objp->flags & P_SF_CANNOT_ARRIVE) ) {
1384 p_objp = GET_NEXT(p_objp);
1389 // ----------------------------------------------------------------
1390 // event_music_get_info()
1392 // Return information about the event music in the buffer outbuf
1393 // NOTE: callers to this function are advised to allocate a 256 byte buffer
1394 void event_music_get_info(char *outbuf)
1396 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
1397 sprintf(outbuf,XSTR( "Event music is not playing", 213));
1400 sprintf(outbuf,XSTR( "soundtrack: %s [%s]", 214), Soundtracks[Current_soundtrack_num].name, Pattern_description[Current_pattern]);
1404 // ----------------------------------------------------------------
1405 // event_music_next_soundtrack()
1407 // input: delta => 1 or -1, depending if you want to go to next or previous song
1409 // returns: New soundtrack number if successfully changed, otherwise return -1
1411 int event_music_next_soundtrack(int delta)
1415 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1419 new_soundtrack = Current_soundtrack_num + delta;
1420 if ( new_soundtrack >= Num_soundtracks )
1423 event_music_level_close();
1424 event_music_level_init(new_soundtrack);
1426 return Current_soundtrack_num;
1429 // ----------------------------------------------------------------
1430 // event_music_get_soundtrack_name()
1432 // Return information about the event music in the buffer outbuf
1433 // NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
1434 void event_music_get_soundtrack_name(char *outbuf)
1436 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1437 strcpy(outbuf, XSTR( "Event music is not playing", 213));
1440 sprintf(outbuf, Soundtracks[Current_soundtrack_num].name);
1444 // set the current soundtrack based on name
1445 void event_music_set_soundtrack(char *name)
1449 // find the correct index for the event music
1450 for ( i = 0; i < Num_soundtracks; i++ ) {
1451 if ( !stricmp(name, Soundtracks[i].name) ) {
1452 Current_soundtrack_num = i;
1457 if ( i == Num_soundtracks ) {
1458 Current_soundtrack_num = -1;
1459 mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
1463 int event_music_get_spooled_music_index(char *name)
1465 // find the correct index for the event music
1466 for ( int i = 0; i < Num_music_files; i++ ) {
1467 if ( !stricmp(name, Spooled_music[i].name) ) {
1475 // set a score based on name
1476 void event_music_set_score(int score_index, char *name)
1478 Assert(score_index < NUM_SCORES);
1480 // find the correct index for the event music
1481 Mission_music[score_index] = event_music_get_spooled_music_index(name);
1484 // reset what sort of music is to be used for this mission
1485 void event_music_reset_choices()
1487 Current_soundtrack_num = -1;
1488 mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
1489 Mission_music[SCORE_BRIEFING] = -1;
1490 event_music_set_score(SCORE_DEBRIEF_SUCCESS, "Success");
1491 event_music_set_score(SCORE_DEBRIEF_AVERAGE, "Average");
1492 event_music_set_score(SCORE_DEBRIEF_FAIL, "Failure");
1493 //Mission_music[SCORE_DEBRIEF_SUCCESS] = MUSIC_DEBRIEF_SUCCESS_1;
1494 //Mission_music[SCORE_DEBRIEF_FAIL] = MUSIC_DEBRIEF_FAIL_1;
1497 void event_music_hostile_ship_destroyed()
1499 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
1503 #pragma optimize("", on)