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.5 2006/04/26 19:39:20 taylor
19 * fix music handling for FS1 to better match the original
21 * Revision 1.4 2002/06/09 04:41:17 relnev
22 * added copyright header
24 * Revision 1.3 2002/05/28 08:52:03 relnev
25 * implemented two assembly stubs.
27 * cleaned up a few warnings.
29 * added a little demo hackery to make it progress a little farther.
31 * Revision 1.2 2002/05/07 03:16:45 theoddone33
32 * The Great Newline Fix
34 * Revision 1.1.1.1 2002/05/03 03:28:09 root
38 * 14 8/19/99 9:41a Alanl
39 * don't play victory 2 music if there are no goals in the mission
41 * 13 8/11/99 5:33p Jefff
42 * added 3rd debrief music track
44 * 12 8/01/99 2:11p Alanl
45 * make hull value to play more intense battle music a constant
47 * 11 8/01/99 2:06p Alanl
48 * tweak battle music track switching
50 * 10 7/25/99 9:57p Alanl
51 * change battle music track selection after enemy arrivals to make battle
52 * tracks less repetitive
54 * 9 7/19/99 10:13p Andsager
55 * Tie in hud_targeting to hostile_ships_present() used to determine next
58 * 8 6/24/99 10:47p Alanl
59 * loop battle between tracks 2 and 3 if hull integrity < 70%
61 * 7 6/21/99 1:34p Alanl
64 * 6 6/20/99 12:06a Alanl
65 * new event music changes
67 * 5 11/23/98 11:55a Johnson
68 * return -1 if a score isn't found
70 * 4 11/20/98 4:08p Dave
71 * Fixed flak effect in multiplayer.
73 * 3 10/23/98 3:51p Dave
74 * Full support for tstrings.tbl and foreign languages. All that remains
75 * is to make it active in Fred.
77 * 2 10/07/98 10:52a Dave
80 * 1 10/07/98 10:48a Dave
82 * 107 6/09/98 5:15p Lawrance
83 * French/German localization
85 * 106 6/09/98 10:31a Hoffoss
86 * Created index numbers for all xstr() references. Any new xstr() stuff
87 * added from here on out should be added to the end if the list. The
88 * current list count can be found in FreeSpace.cpp (search for
91 * 105 5/24/98 5:28p Dan
92 * let event_music_level_init() over-ride Event_music_enabled
94 * 104 5/24/98 4:42p Dan
95 * AL: Fix several bugs related to pausing and enabling/disabling event
98 * 103 5/23/98 3:17a Lawrance
99 * Tweak how battle music gets restarted
101 * 102 5/22/98 10:43a Lawrance
102 * If mission doesn't have event music, don't choose random track
104 * 101 5/21/98 6:56p Lawrance
105 * Tweak how victory music plays
107 * 100 5/21/98 2:47a Lawrance
108 * Fix some problems with event music
110 * 99 5/18/98 3:21p Mike
111 * Don't play arrival and goals tracks in a training mission.
113 * 98 5/04/98 3:15p Duncan
114 * AL: remove bogus assert in event_music_player_respawn()
116 * 97 5/03/98 1:54a Lawrance
117 * Fix event music problems related to respawning
119 * 96 4/03/98 12:56a Lawrance
120 * Fix bug with music not starting in the first mission
122 * 95 4/01/98 6:46p Lawrance
123 * Lower default music volume
130 #include "eventmusic.h"
133 #include "linklist.h"
134 #include "missionload.h" /* for Builtin_mission_names[] */
135 #include "missionparse.h"
137 #include "freespace.h"
138 #include "audiostr.h"
139 #include "missioncampaign.h"
143 #include "missiongoals.h"
144 #include "localize.h"
147 #pragma optimize("", off)
150 #define DEFAULT_MASTER_EVENT_MUSIC_VOLUME 0.5f
152 #define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
154 ////////////////////////////
156 ////////////////////////////
157 int Event_Music_battle_started = 0;
158 float Master_event_music_volume = DEFAULT_MASTER_EVENT_MUSIC_VOLUME; // range is 0->1
160 // array that holds which soundtrack is used for which mission (data comes from music.tbl)
161 //int Mission_soundtracks[MAX_CAMPAIGN_MISSIONS];
163 // array that holds which briefing track to play for which mission. Index into Spooled_music[][].
164 //int Mission_briefingmusic[MAX_CAMPAIGN_MISSIONS];
166 typedef struct tagSNDPATTERN {
167 int default_next_pattern; // Needed so the next_pattern member can be reset
168 int next_pattern; // Next pattern to play at loop time (can be same pattern)
169 int default_loop_for; // Needed so the loop_for variable can be reset
170 int loop_for; // Number of times to loop before switching to next pattern
171 int handle; // handle to open audio stream
172 int force_pattern; // flag to indicate that we want to not continue loop, but go to next_pattern
173 int can_force; // whether this pattern can be interrupted
174 int bytes_per_measure; // number of bytes in a measure
175 float num_measures; // number of measures in wave file
178 SNDPATTERN Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
180 // Holds filenames for the different sections of a soundtrack
181 SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
183 int Current_soundtrack_num; // Active soundtrack for the current mission.. index into Soundtracks[]
185 #define PATTERN_DELAY 1000 // in ms
186 int Current_pattern = -1; // currently playing part of track
187 int Pending_pattern = -1;
188 int Pattern_timer_id = 0;
191 static int Num_enemy_arrivals;
192 static int Num_friendly_arrivals;
194 #define ARRIVAL_INTERVAL_TIMESTAMP 5000
195 #define BATTLE_CHECK_INTERVAL 15000
196 static int Battle_over_timestamp;
197 static int Mission_over_timestamp;
198 static int Victory2_music_played;
199 static int Next_arrival_timestamp;
200 static int Check_for_battle_music;
202 // stores the number of measures for the different patterns (data from music.tbl)
203 float Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS];
205 // stores the number of bytes per measure (data from music.tbl)
206 int Pattern_bytes_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS];
208 const char* Pattern_names[MAX_PATTERNS] =
211 "NRML_1", // Normal Song 1
213 "NRML_2", // Normal Song 2
214 "NRML_3", // Normal Song 3
216 "AARV_1", // Allied Arrival 1
217 "EARV_1", // Enemy Arrival 1
218 "BTTL_1", // Battle Song 1
219 "BTTL_2", // Battle Song 2
220 "BTTL_3", // Battle Song 3
221 "AARV_2", // Allied Arrival 2
222 "EARV_2", // Enemy Arrival 2
223 "VICT_1", // Victory Song 1
224 "VICT_2", // Victory Song 2
225 "FAIL_1" // Goal Failed 1
226 "DEAD_1" // Death Song 1
230 const char* Pattern_description[MAX_PATTERNS] =
238 "friendly arrival 1",
243 "friendly arrival 2",
252 int Pattern_loop_for[MAX_PATTERNS] =
259 1, // Allied Arrival 1
260 1, // Enemy Arrival 1
264 1, // Allied Arrival 2
265 1, // Enemy Arrival 2
272 int Pattern_default_next[MAX_PATTERNS] =
275 SONG_NRML_2, // NRML_1 progresses to NRML_2 by default
276 SONG_NRML_1, // NRML_2 progresses to NRML_1 by default
277 SONG_NRML_1, // NRML_3 progresses to NRML_1 by default
278 SONG_NRML_2, // AARV_1 progresses to NRML_2 by default
279 SONG_BTTL_1, // EARV_1 progresses to BTTL_1 by default
280 SONG_BTTL_2, // BTTL_1 progresses to BTTL_2 by default
281 SONG_BTTL_3, // BTTL_2 progresses to BTTL_3 by default
282 SONG_BTTL_1, // BTTL_3 progresses to BTTL_1 by default
283 SONG_BTTL_2, // AARV_2 progresses to BTTL_2 by default
284 SONG_BTTL_2, // EARV_2 progresses to BTTL_2 by default
285 SONG_NRML_3, // VICT_1 progresses to NRML_3 by default
286 SONG_NRML_3, // VICT_2 progresses to NRML_3 by default
287 SONG_NRML_1, // FAIL_1 progresses to NRML_1 by default
288 -1 // no music playes after dead
290 SONG_NRML_1, // NRML_1 progresses to NRML_1 by default
291 SONG_NRML_1, // AARV_1 progresses to NRML_1 by default
292 SONG_BTTL_1, // EARV_1 progresses to BTTL_1 by default
293 SONG_BTTL_2, // BTTL_1 progresses to BTTL_2 by default
294 SONG_BTTL_3, // BTTL_2 progresses to BTTL_3 by default
295 SONG_BTTL_1, // BTTL_3 progresses to BTTL_1 by default
296 SONG_BTTL_2, // AARV_2 progresses to BTTL_2 by default
297 SONG_BTTL_3, // EARV_2 progresses to BTTL_3 by default
298 SONG_NRML_1, // VICT_1 progresses to NRML_1 by default
299 SONG_NRML_1, // VICT_2 progresses to NRML_1 by default
300 SONG_NRML_1, // FAIL_1 progresses to NRML_1 by default
301 -1 // no music plays after dead
306 // Certain patterns can be interrupted (such as the long-playing NRML and BTTL tracks).
307 // Other shorter tracks (such as arrivals) play their entire duration.
308 int Pattern_can_force[MAX_PATTERNS] =
329 int Event_music_enabled = TRUE;
330 static int Event_music_inited = FALSE;
331 static int Event_music_level_inited = FALSE;
332 static int Event_music_begun = FALSE;
334 // forward function declarations
335 int hostile_ships_present();
336 int hostile_ships_to_arrive();
337 extern int hud_target_invalid_awacs(object *objp);
339 // Holds file names of spooled music that is played at menus, briefings, credits etc.
340 // Indexed into by a #define enumeration of the different kinds of spooled music
341 menu_music Spooled_music[MAX_SPOOLED_MUSIC];
342 int Num_music_files; // Number of spooled music files
344 // Array that holds indicies into Spooled_music[], these specify which music is played in breifing/debriefing
345 int Mission_music[NUM_SCORES];
347 // -------------------------------------------------------------------------------------------------
348 // event_music_init()
350 // Called once at game start-up to parse music.tbl and set some state variables
352 void event_music_init()
354 if ( snd_is_inited() == FALSE ) {
355 Event_music_enabled = FALSE;
359 if ( Cmdline_freespace_no_music ) {
363 if ( Event_music_inited == TRUE )
366 event_music_parse_musictbl();
367 Event_music_inited = TRUE;
368 Event_music_begun = FALSE;
371 // -------------------------------------------------------------------------------------------------
372 // event_music_close()
374 // Called once at game end
376 void event_music_close()
378 if ( Event_music_inited == FALSE )
381 Event_music_inited = FALSE;
384 // -------------------------------------------------------------------------------------------------
385 // event_music_force_switch()
387 // Performs a switch between patterns. Sets the cutoff limit for the pattern that is being
390 void event_music_force_switch()
392 if ( Event_music_enabled == FALSE )
395 if ( Event_music_level_inited == FALSE )
399 Patterns[Current_pattern].loop_for = Patterns[Current_pattern].default_loop_for;
401 new_pattern = Patterns[Current_pattern].next_pattern;
403 if ( (new_pattern == SONG_BTTL_3) && (Patterns[SONG_BTTL_3].handle == -1) ) {
404 if ( Current_pattern == SONG_BTTL_2 ) {
405 new_pattern = SONG_BTTL_1;
407 new_pattern = SONG_BTTL_2;
410 if (Current_pattern == SONG_BTTL_3 && new_pattern == SONG_BTTL_1) {
411 // AL 06-24-99: maybe switch to battle 2 if hull is less than 70%
412 if (Player_obj != NULL && Player_ship != NULL) {
413 SDL_assert(Player_ship->ship_info_index >= 0);
414 SDL_assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
415 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
416 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
417 new_pattern = SONG_BTTL_2;
423 if ( new_pattern == -1 ) {
427 if ( Patterns[new_pattern].num_measures == 0 )
428 return; // invalid pattern
430 SDL_assert(new_pattern >= 0 && new_pattern < MAX_PATTERNS);
431 audiostream_play(Patterns[new_pattern].handle, Master_event_music_volume, 0); // no looping
432 audiostream_set_byte_cutoff(Patterns[new_pattern].handle, fl2i(Patterns[new_pattern].num_measures * Patterns[new_pattern].bytes_per_measure) );
433 Patterns[Current_pattern].next_pattern = Patterns[Current_pattern].default_next_pattern;
434 Patterns[Current_pattern].force_pattern = FALSE;
435 nprintf(("EVENTMUSIC", "EVENTMUSIC => switching to %s from %s\n", Pattern_names[new_pattern], Pattern_names[Current_pattern]));
436 Current_pattern = new_pattern;
439 // -------------------------------------------------------------------------------------------------
440 // event_music_do_frame()
442 // Called once per game frame, to check for transitions of patterns (and to start the music off at
445 void event_music_do_frame()
447 if ( Event_music_level_inited == FALSE ) {
451 if ( Event_music_enabled == FALSE ) {
455 // start off the music delayed
456 if ( timestamp_elapsed(Pattern_timer_id) ) {
457 Pattern_timer_id = 0;
458 Event_music_begun = TRUE;
459 if ( Current_pattern != -1 ) {
460 SDL_assert(Patterns[Current_pattern].handle >= 0 );
461 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
462 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
466 if ( Event_music_begun == FALSE ) {
470 if ( Current_pattern != -1 ) {
472 pat = &Patterns[Current_pattern];
474 // First case: switching to a different track since first track is almost at end
475 if ( audiostream_done_reading(pat->handle) ) {
476 event_music_force_switch();
478 // Second case: looping back to start of same track since at the end
479 else if ( !audiostream_is_playing(pat->handle) && !audiostream_is_paused(pat->handle) ) {
480 audiostream_stop(pat->handle); // stop current and rewind
482 if ( pat->loop_for > 0 ) {
483 audiostream_play(pat->handle, Master_event_music_volume, 0); // no looping
484 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
487 event_music_force_switch();
490 // Third case: switching to a different track by interruption
491 else if ( (pat->force_pattern == TRUE && pat->can_force == TRUE) ) {
492 int bytes_streamed = audiostream_get_bytes_committed(pat->handle);
493 int measures_played = bytes_streamed / pat->bytes_per_measure;
494 if ( measures_played < pat->num_measures ) {
495 audiostream_set_byte_cutoff(pat->handle, pat->bytes_per_measure * (measures_played+1) );
496 pat->force_pattern = FALSE;
501 // We want to go back to NRML track music if all the hostiles have been
502 // destroyed, and we are still playing the battle music
503 if ( Current_pattern == SONG_BTTL_1 || Current_pattern == SONG_BTTL_2 || Current_pattern == SONG_BTTL_3 ) {
504 if ( timestamp_elapsed(Battle_over_timestamp) && Event_Music_battle_started == 1) {
505 //Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
506 if ( hostile_ships_present() == FALSE ) {
507 if ( Patterns[Current_pattern].next_pattern != SONG_VICT_2 ) {
508 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
509 Patterns[Current_pattern].force_pattern = TRUE;
510 Event_Music_battle_started = 0;
516 if (Event_Music_battle_started == 0) {
518 if ( (Current_pattern == SONG_NRML_1) || (Current_pattern == SONG_NRML_2) ) {
520 if (Current_pattern == SONG_NRML_1) {
522 if (timestamp_elapsed(Check_for_battle_music)) {
523 Check_for_battle_music = timestamp(1000);
524 if (hostile_ships_present() == TRUE) {
525 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
526 Patterns[Current_pattern].force_pattern = TRUE;
532 if ( !Victory2_music_played ) {
533 if ( timestamp_elapsed(Mission_over_timestamp) ) {
534 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
535 if ( mission_goals_met() && (!hostile_ships_present()) ) {
536 Patterns[Current_pattern].next_pattern = SONG_VICT_2;
537 Patterns[Current_pattern].force_pattern = TRUE;
538 Victory2_music_played = 1;
545 // -------------------------------------------------------------------------------------------------
546 // event_music_level_init()
548 // Called at the start of a mission (level). Sets up the pattern data, and kicks off the
549 // first track to play().
551 // input: force_soundtrack => OPTIONAL parameter (default value -1)
552 // forces the soundtrack to ignore the music.tbl assignment
554 void event_music_level_init(int force_soundtrack)
557 SOUNDTRACK_INFO *strack;
559 if ( Cmdline_freespace_no_music ) {
563 if ( !audiostream_is_inited() )
566 if ( Event_music_level_inited == TRUE )
569 Current_pattern = -1;
571 if ( Event_music_inited == FALSE )
575 if ( force_soundtrack != -1 ) {
576 Current_soundtrack_num = force_soundtrack;
579 if ( Current_soundtrack_num < 0 ) {
582 // okay, assign a random soundtrack if one exists
583 if ( Num_soundtracks > 0 ) {
584 Current_soundtrack_num = rand()%Num_soundtracks;
585 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Picking random event music soundtrack: %s\n", Soundtracks[Current_soundtrack_num].name));
592 SDL_assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < Num_soundtracks);
593 strack = &Soundtracks[Current_soundtrack_num];
595 // open the pattern files, and get ready to play them
596 for ( i = 0; i < strack->num_patterns; i++ ) {
597 if ( !SDL_strcasecmp(NOX("none.wav"), strack->pattern_fnames[i]) ) {
598 Patterns[i].handle = -1;
602 Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
604 if ( Patterns[i].handle >= 0 ) {
605 Event_music_level_inited = TRUE;
606 Event_music_enabled = TRUE;
609 Patterns[i].next_pattern = Pattern_default_next[i];
610 Patterns[i].default_next_pattern = Pattern_default_next[i];
611 Patterns[i].loop_for = Pattern_loop_for[i];
612 Patterns[i].default_loop_for = Pattern_loop_for[i];
613 Patterns[i].force_pattern = FALSE;
614 Patterns[i].can_force = Pattern_can_force[i];
615 Patterns[i].bytes_per_measure = Pattern_bytes_per_measure[Current_soundtrack_num][i];
616 Patterns[i].num_measures = Pattern_num_measures[Current_soundtrack_num][i];
619 Num_enemy_arrivals = 0;
620 Num_friendly_arrivals = 0;
621 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
622 Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
623 Next_arrival_timestamp = timestamp(1);
624 Victory2_music_played = 0;
625 Check_for_battle_music = 0;
627 if ( Event_music_level_inited ) {
628 if ( force_soundtrack != -1 ) {
629 event_music_first_pattern();
634 // -------------------------------------------------------------------------------------------------
635 // event_music_first_pattern()
637 // Picks the first pattern to play, based on whether the battle has started. Delay start
640 void event_music_first_pattern()
642 if ( Event_music_inited == FALSE ) {
646 if ( Event_music_enabled == FALSE ) {
650 if ( Event_music_level_inited == FALSE ) {
651 event_music_level_init();
654 if ( Event_music_level_inited == FALSE ) {
658 if ( Event_music_begun == TRUE ) {
662 if ( Current_pattern != -1 ) {
663 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
664 audiostream_stop( Patterns[Current_pattern].handle );
667 Pattern_timer_id = 2000; // start music delay
669 Event_music_begun = FALSE;
670 if ( Event_Music_battle_started == TRUE ) {
671 Current_pattern = SONG_BTTL_1;
674 Current_pattern = SONG_NRML_1;
678 // -------------------------------------------------------------------------------------------------
679 // event_music_level_close()
681 // Called at the end of each mission (level). Stops any playing patterns by fading them out.
683 void event_music_level_close()
687 if ( Event_music_level_inited == FALSE )
690 if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS ) {
691 SOUNDTRACK_INFO *strack;
693 SDL_assert( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS );
694 strack = &Soundtracks[Current_soundtrack_num];
696 // close the pattern files
697 for ( i = 0; i < strack->num_patterns; i++ ) {
698 if ( i == Current_pattern ) {
699 if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
700 audiostream_close_file( Patterns[i].handle );
702 audiostream_close_file( Patterns[i].handle, 0 );
705 audiostream_close_file( Patterns[i].handle, 0 );
708 // close em all down then
709 audiostream_close_all(0);
712 Current_pattern = -1;
713 Event_music_level_inited = FALSE;
714 Event_Music_battle_started = FALSE;
715 Event_music_enabled = 0;
716 Event_music_begun = FALSE;
719 // -------------------------------------------------------------------------------------------------
720 // event_music_battle_start()
722 // Start the battle music. If the music is already started before, do nothing.
724 int event_music_battle_start()
726 if ( !hostile_ships_present() ) {
730 // No special tracks in training.
731 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
734 // Check to see if we've already started off the battle song
735 if ( Event_Music_battle_started == 1 ) {
739 if ( Event_music_enabled == FALSE )
742 if ( Event_music_level_inited == FALSE )
745 if ( Current_pattern == SONG_BTTL_1 )
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 != -1 ) {
752 Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
753 Patterns[Current_pattern].force_pattern = TRUE;
756 Event_Music_battle_started = 1; // keep track of this state though, need on restore
757 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
762 // -------------------------------------------------------------------------------------------------
763 // event_music_enemy_arrival()
765 // An enemy has arrived, play an enemy arrival pattern.
767 int event_music_enemy_arrival()
769 if ( Event_music_enabled == FALSE ) {
773 if ( Event_music_level_inited == FALSE ) {
778 if ( Event_Music_battle_started == TRUE ) {
779 next_pattern = SONG_EARV_2;
782 next_pattern = SONG_EARV_1;
785 if ( Current_pattern == next_pattern )
786 return 0; // already playing
788 if ( Current_pattern == SONG_DEAD_1 )
789 return 0; // death is the last song to play
791 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
794 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
795 return 0; // don't squash a pending pattern
797 Num_enemy_arrivals++;
799 // AL 7-25-99: If hull is less than 70% then switch to battle 2 or 3, otherwise switch to 1 or 2
800 bool play_intense_battle_music = false;
801 if (Player_obj != NULL && Player_ship != NULL) {
802 SDL_assert(Player_ship->ship_info_index >= 0);
803 SDL_assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength != 0);
804 float integrity = Player_obj->hull_strength / Ship_info[Player_ship->ship_info_index].initial_hull_strength;
805 if (integrity < HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC) {
806 play_intense_battle_music = true;
810 if (play_intense_battle_music == true) {
811 if (Current_pattern == SONG_BTTL_2) {
812 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
814 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
817 if (Current_pattern == SONG_BTTL_1) {
818 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
819 } else if (Current_pattern == SONG_BTTL_2) {
820 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
822 Patterns[next_pattern].next_pattern = SONG_BTTL_1;
828 // Alternate between BTTL_2 and BTTL_3 following enemy arrivals
829 if ( Num_enemy_arrivals & 1 ) {
830 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
832 if ( Patterns[SONG_BTTL_3].handle != -1 ) {
833 Patterns[next_pattern].next_pattern = SONG_BTTL_3;
835 Patterns[next_pattern].next_pattern = SONG_BTTL_2;
840 if ( Current_pattern != -1 ) {
841 Patterns[Current_pattern].next_pattern = next_pattern;
842 Patterns[Current_pattern].force_pattern = TRUE;
845 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
850 // -------------------------------------------------------------------------------------------------
851 // event_music_friendly_arrival()
853 // An friendly has arrived, play a friendly arrival pattern.
855 int event_music_friendly_arrival()
857 if ( Event_music_enabled == FALSE )
860 if ( Event_music_level_inited == FALSE )
863 if (timestamp_elapsed(Next_arrival_timestamp) == false) {
868 if ( Event_Music_battle_started == TRUE ) {
869 next_pattern = SONG_AARV_2;
872 next_pattern = SONG_AARV_1;
875 if ( Current_pattern == next_pattern )
876 return 0; // already playing
878 if ( Current_pattern == SONG_DEAD_1 )
879 return 0; // death is the last song to play
881 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_1) )
884 if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
885 return 0; // don't squash a pending pattern
887 // After the second friendly arrival, default to SONG_BTTL_3
888 Num_friendly_arrivals++;
890 if ( Current_pattern != -1 ) {
891 // AL 06-24-99: always overlay allied arrivals
893 if (next_pattern == SONG_AARV_1) {
894 Patterns[Current_pattern].next_pattern = next_pattern;
895 Patterns[Current_pattern].force_pattern = TRUE;
898 SDL_assert(Patterns[SONG_AARV_1].handle >= 0 );
899 audiostream_play(Patterns[SONG_AARV_1].handle, Master_event_music_volume, 0); // no looping
900 audiostream_set_byte_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].bytes_per_measure) );
904 Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
906 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
911 // Play arrival music keyed to team "team".
912 void event_music_arrival(int team)
914 // No friendly arrival music in a training mission.
915 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
918 if ( Player_ship->team == team ) {
919 event_music_friendly_arrival();
921 event_music_enemy_arrival();
925 // -------------------------------------------------------------------------------------------------
926 // event_music_primary_goals_met()
928 // A primary goal has failed
930 int event_music_primary_goal_failed()
934 // No special tracks in training.
935 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
938 if ( Event_music_enabled == FALSE )
941 if ( Event_music_level_inited == FALSE )
944 if ( Current_pattern == SONG_DEAD_1 )
945 return 0; // death is the last song to play
947 if ( Patterns[SONG_FAIL_1].handle < 0 ) // can't play if music file doesn't exist
950 if ( hostile_ships_present() ) {
951 next_pattern = SONG_BTTL_1;
954 next_pattern = SONG_NRML_1;
955 Event_Music_battle_started = 0;
958 if ( Current_pattern != -1 ) {
959 Patterns[Current_pattern].next_pattern = next_pattern;
960 Patterns[Current_pattern].force_pattern = TRUE;
966 // -------------------------------------------------------------------------------------------------
967 // event_music_primary_goals_met()
969 // A goal has been achieved, play the appropriate victory music.
971 int event_music_primary_goals_met()
973 int next_pattern = SONG_VICT_1;
975 // No special tracks in training.
976 if ( The_mission.game_type & MISSION_TYPE_TRAINING )
979 if ( Event_music_enabled == FALSE )
982 if ( Event_music_level_inited == FALSE )
985 if ( (Current_pattern == SONG_VICT_1) || (Current_pattern == SONG_VICT_2) )
986 return 0; // already playing
988 if ( Current_pattern == SONG_DEAD_1 )
989 return 0; // death is the last song to play
991 if ( hostile_ships_present() ) {
992 Patterns[SONG_VICT_1].next_pattern = SONG_BTTL_1;
995 Patterns[SONG_VICT_1].next_pattern = SONG_VICT_2;
996 Event_Music_battle_started = 0;
998 // If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
999 // to the next default track
1000 if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
1001 Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
1003 Victory2_music_played = 1;
1007 if ( Current_pattern != -1 ) {
1008 Patterns[Current_pattern].next_pattern = next_pattern;
1009 Patterns[Current_pattern].force_pattern = TRUE;
1015 // -------------------------------------------------------------------------------------------------
1016 // event_music_player_death()
1018 // The player has died, play death pattern.
1020 int event_music_player_death()
1022 if ( Event_music_enabled == FALSE )
1025 if ( Event_music_level_inited == FALSE )
1028 if ( Current_pattern == SONG_DEAD_1 )
1029 return 0; // already playing
1031 if ( Current_pattern != -1 ) {
1032 Patterns[Current_pattern].next_pattern = SONG_DEAD_1;
1033 Patterns[Current_pattern].force_pattern = TRUE;
1039 // -------------------------------------------------------------------------------------------------
1040 // event_music_player_respawn()
1042 // Player has respawned (multiplayer only)
1044 int event_music_player_respawn()
1046 if ( Event_music_enabled == FALSE )
1049 if ( Event_music_level_inited == FALSE )
1052 // SDL_assert(Current_pattern == SONG_DEAD_1);
1054 Event_Music_battle_started = 0;
1055 Patterns[Current_pattern].next_pattern = SONG_NRML_1;
1056 Patterns[Current_pattern].force_pattern = TRUE;
1061 // -------------------------------------------------------------------------------------------------
1062 // event_music_player_respawn_as_observer()
1064 // Player has respawned (multiplayer only)
1066 int event_music_player_respawn_as_observer()
1068 if ( Event_music_enabled == FALSE )
1071 if ( Event_music_level_inited == FALSE )
1074 if ( Current_pattern >= 0 ) {
1075 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1076 audiostream_stop(Patterns[Current_pattern].handle);
1077 Current_pattern = -1;
1084 // -------------------------------------------------------------------------------------------------
1085 // event_music_parse_musictbl() will parse the music.tbl file, and set up the Mission_songs[]
1088 void event_music_parse_musictbl()
1090 char fname[MAX_FILENAME_LEN];
1093 int num_patterns = 0;
1095 Num_music_files = 0;
1096 Num_soundtracks = 0; // Global
1097 event_music_reset_choices();
1099 // open localization
1103 read_file_text("music.tbl");
1106 // Loop through all the sound-tracks
1107 while (required_string_either("#Menu Music Start","#SoundTrack Start")) {
1108 SDL_assert(Num_soundtracks < MAX_SOUNDTRACKS);
1109 required_string("#SoundTrack Start");
1110 required_string("$SoundTrack Name:");
1111 stuff_string(Soundtracks[Num_soundtracks].name, F_NAME, NULL);
1112 while (required_string_either("#SoundTrack End","$Name:")) {
1113 SDL_assert( num_patterns < MAX_PATTERNS );
1114 required_string("$Name:");
1115 stuff_string(line_buf, F_NAME, NULL);
1117 // line_buf holds 3 fields: filename, num measures, bytes per measure
1121 token = strtok( line_buf, NOX(" ,\t"));
1122 SDL_strlcpy(fname, token, SDL_arraysize(fname));
1123 while ( token != NULL ) {
1124 token = strtok( NULL, NOX(" ,\t") );
1125 if ( token == NULL ) {
1126 SDL_assert(count == 2 );
1131 Pattern_num_measures[Num_soundtracks][num_patterns] = (float)atof(token);
1134 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] = atoi(token);
1140 // convert from samples per measure to bytes per measure
1141 Pattern_bytes_per_measure[Num_soundtracks][num_patterns] *= 2;
1142 SDL_strlcpy(Soundtracks[Num_soundtracks].pattern_fnames[num_patterns], fname, MAX_FILENAME_LEN);
1146 required_string("#SoundTrack End");
1147 Soundtracks[Num_soundtracks].num_patterns = num_patterns;
1152 // Parse the menu music section
1153 required_string("#Menu Music Start");
1154 while (required_string_either("#Menu Music End","$Name:")) {
1155 SDL_assert( Num_music_files < MAX_SPOOLED_MUSIC );
1157 required_string("$Name:");
1158 stuff_string(fname, F_PATHNAME, NULL);
1159 SDL_assert( strlen(fname) < (NAME_LENGTH-1) );
1160 SDL_strlcpy( Spooled_music[Num_music_files].name, fname, SDL_arraysize(Spooled_music[0].name) );
1162 required_string("$Filename:");
1163 stuff_string(fname, F_PATHNAME, NULL);
1164 if ( SDL_strcasecmp(fname, NOX("none.wav")) ) {
1165 SDL_assert( strlen(fname) < (MAX_FILENAME_LEN-1) );
1166 SDL_strlcpy( Spooled_music[Num_music_files].filename, fname, SDL_arraysize(Spooled_music[0].filename) );
1172 required_string("#Menu Music End");
1173 } catch (parse_error_t rval) {
1174 Error(LOCATION, "Unable to parse music.tbl! Code = %i.\n", (int)rval);
1177 // close localization
1181 // -------------------------------------------------------------------------------------------------
1182 // event_music_change_pattern()
1184 // Force a particular pattern to play. This is used for debugging purposes.
1186 void event_music_change_pattern(int new_pattern)
1188 if ( Event_music_enabled == FALSE ) {
1189 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1193 if ( Event_music_level_inited == FALSE ) {
1194 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1198 if ( Current_pattern == new_pattern )
1199 return; // already playing
1201 if ( Current_pattern != -1 ) {
1202 Patterns[Current_pattern].next_pattern = new_pattern;
1203 Patterns[Current_pattern].force_pattern = TRUE;
1207 // -------------------------------------------------------------------------------------------------
1208 // event_music_return_current_pattern()
1210 // Simply return what the current pattern being played is. Don't want to make global.
1212 int event_music_return_current_pattern()
1214 return Current_pattern;
1217 // -------------------------------------------------------------------------------------------------
1218 // event_music_disable()
1220 // Stop any patterns that are playing, and prevent any further patterns from playing (ie
1221 // set Event_music_enabled = FALSE). We don't uninit event music, since it might be toggled
1222 // back on this level.
1224 void event_music_disable()
1226 if ( Event_music_level_inited == FALSE )
1229 if ( Event_music_enabled == FALSE )
1232 if (Current_pattern == -1)
1235 SDL_assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1236 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1237 audiostream_stop(Patterns[Current_pattern].handle); // stop current and rewind
1240 Event_music_begun = FALSE;
1241 Event_music_enabled = FALSE;
1242 Current_pattern = -1;
1245 // -------------------------------------------------------------------------------------------------
1246 // event_music_enable()
1248 // Init the event music (ie load the patterns) if required. Set up the first song to play, and
1249 // set Event_music_enabled = TRUE to allow patterns to play.
1251 void event_music_enable()
1253 if ( Event_music_enabled == TRUE )
1256 Event_music_enabled = TRUE;
1258 if ( Event_music_level_inited == FALSE ) {
1259 event_music_level_init();
1260 // start the first pattern to play (delayed)
1261 if ( Game_mode & GM_IN_MISSION ) {
1262 event_music_first_pattern();
1266 // start a new pattern
1267 Event_music_begun = FALSE;
1268 Pattern_timer_id = timestamp(150);
1269 event_music_start_default();
1273 // -------------------------------------------------------------------------------------------------
1274 // event_music_start_default()
1276 // Start playing a default track, based on how far the mission has progressed
1278 void event_music_start_default()
1282 if ( Event_Music_battle_started == TRUE ) {
1283 if ( hostile_ships_present() ) {
1284 next_pattern = SONG_BTTL_1;
1287 Event_Music_battle_started = FALSE;
1289 next_pattern = SONG_NRML_3;
1291 next_pattern = SONG_NRML_1;
1296 next_pattern = SONG_NRML_1;
1298 if ( Current_pattern == -1 ) {
1299 Current_pattern = next_pattern;
1302 Patterns[Current_pattern].next_pattern = next_pattern;
1303 Patterns[Current_pattern].force_pattern = TRUE;
1308 // -------------------------------------------------------------------------------------------------
1309 // event_music_pause()
1311 // Stop any playing pattern, but don't rewind.
1313 void event_music_pause()
1315 if ( Event_music_enabled == FALSE ) {
1316 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1320 if ( Event_music_level_inited == FALSE ) {
1321 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1325 if (Current_pattern == -1)
1328 SDL_assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1329 if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1330 audiostream_stop(Patterns[Current_pattern].handle, 0); // stop current and don't rewind
1334 // -------------------------------------------------------------------------------------------------
1335 // event_music_unpause()
1337 // Start the Current_pattern if it is paused.
1339 void event_music_unpause()
1341 if ( Event_music_enabled == FALSE ) {
1342 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1346 if ( Event_music_level_inited == FALSE ) {
1347 nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1351 if (Current_pattern == -1)
1354 SDL_assert( Current_pattern >= 0 && Current_pattern < MAX_PATTERNS );
1355 if ( audiostream_is_paused(Patterns[Current_pattern].handle) == TRUE ) {
1356 audiostream_play(Patterns[Current_pattern].handle, Master_event_music_volume, 0); // no looping
1357 audiostream_set_byte_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].bytes_per_measure) );
1361 // -------------------------------------------------------------------------------------------------
1362 // event_music_set_volume_all()
1364 // Set the volume of the event driven music. Used when using the game-wide music volume is changed
1367 void event_music_set_volume_all(float volume)
1369 audiostream_set_volume_all(volume, ASF_EVENTMUSIC);
1372 // ----------------------------------------------------------------------
1373 // hostile_ships_present()
1375 // Determine if there are any non-friendly ships in existance
1377 // returns: 1 => there are non-friendly ships in existance
1378 // 0 => any ships in existance are friendly
1379 int hostile_ships_present()
1384 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1385 shipp = &Ships[Objects[so->objnum].instance];
1387 // check if ship if enemy ship
1388 if ( (shipp->team == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR) )
1391 // check if ship is threatening
1392 if ( (shipp->flags & (SF_DISABLED|SF_DYING|SF_DEPARTING)) || (ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE)) )
1395 // check if ship is flyable
1396 if ( Ship_info[shipp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
1400 // check if ship is visible by player's team
1401 if ( hud_target_invalid_awacs(&Objects[so->objnum]) == 1 ) {
1410 // ----------------------------------------------------------------------
1411 // hostile_ships_to_arrive()
1413 // Determine if there are any non-friendly ships yet to arrive
1415 // NOTE: neutral ships are considered hostile for the purpose of event music
1417 int hostile_ships_to_arrive()
1421 p_objp = GET_FIRST(&ship_arrival_list);
1422 while( p_objp != END_OF_LIST(&ship_arrival_list) ) {
1423 if ( (p_objp->team != Player_ship->team) && !(p_objp->flags & P_SF_CANNOT_ARRIVE) ) {
1426 p_objp = GET_NEXT(p_objp);
1431 // ----------------------------------------------------------------
1432 // event_music_get_info()
1434 // Return information about the event music in the buffer outbuf
1435 // NOTE: callers to this function are advised to allocate a 256 byte buffer
1436 void event_music_get_info(char *outbuf, const int outbuf_size)
1438 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
1439 SDL_strlcpy(outbuf, XSTR( "Event music is not playing", 213), outbuf_size);
1442 SDL_snprintf(outbuf, outbuf_size, XSTR( "soundtrack: %s [%s]", 214), Soundtracks[Current_soundtrack_num].name, Pattern_description[Current_pattern]);
1446 // ----------------------------------------------------------------
1447 // event_music_next_soundtrack()
1449 // input: delta => 1 or -1, depending if you want to go to next or previous song
1451 // returns: New soundtrack number if successfully changed, otherwise return -1
1453 int event_music_next_soundtrack(int delta)
1457 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1461 new_soundtrack = Current_soundtrack_num + delta;
1462 if ( new_soundtrack >= Num_soundtracks )
1465 event_music_level_close();
1466 event_music_level_init(new_soundtrack);
1468 return Current_soundtrack_num;
1471 // ----------------------------------------------------------------
1472 // event_music_get_soundtrack_name()
1474 // Return information about the event music in the buffer outbuf
1475 // NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
1476 void event_music_get_soundtrack_name(char *outbuf, const int outbuf_size)
1478 if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1479 SDL_strlcpy(outbuf, XSTR( "Event music is not playing", 213), outbuf_size);
1482 SDL_strlcpy(outbuf, Soundtracks[Current_soundtrack_num].name, outbuf_size);
1486 // set the current soundtrack based on name
1487 void event_music_set_soundtrack(char *name)
1491 // find the correct index for the event music
1492 for ( i = 0; i < Num_soundtracks; i++ ) {
1493 if ( !SDL_strcasecmp(name, Soundtracks[i].name) ) {
1494 Current_soundtrack_num = i;
1499 if ( i == Num_soundtracks ) {
1500 Current_soundtrack_num = -1;
1501 mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
1505 int event_music_get_spooled_music_index(const char *name)
1507 // find the correct index for the event music
1508 for ( int i = 0; i < Num_music_files; i++ ) {
1509 if ( !SDL_strcasecmp(name, Spooled_music[i].name) ) {
1517 // set a score based on name
1518 void event_music_set_score(int score_index, const char *name)
1520 SDL_assert(score_index < NUM_SCORES);
1522 // find the correct index for the event music
1523 Mission_music[score_index] = event_music_get_spooled_music_index(name);
1526 // reset what sort of music is to be used for this mission
1527 void event_music_reset_choices()
1529 Current_soundtrack_num = -1;
1530 mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
1531 Mission_music[SCORE_BRIEFING] = -1;
1532 event_music_set_score(SCORE_DEBRIEF_SUCCESS, "Success");
1533 event_music_set_score(SCORE_DEBRIEF_AVERAGE, "Average");
1534 event_music_set_score(SCORE_DEBRIEF_FAIL, "Failure");
1535 //Mission_music[SCORE_DEBRIEF_SUCCESS] = MUSIC_DEBRIEF_SUCCESS_1;
1536 //Mission_music[SCORE_DEBRIEF_FAIL] = MUSIC_DEBRIEF_FAIL_1;
1539 void event_music_hostile_ship_destroyed()
1541 Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
1545 #pragma optimize("", on)