FS2_Open
Open source remastering of the Freespace 2 engine
eventmusic.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include "cmdline/cmdline.h"
14 #include "gamesnd/eventmusic.h"
15 #include "globalincs/linklist.h"
16 #include "iff_defs/iff_defs.h"
17 #include "io/timer.h"
18 #include "localization/localize.h"
19 #include "mission/missiongoals.h"
20 #include "mission/missionparse.h"
21 #include "object/object.h"
22 #include "parse/parselo.h"
23 #include "ship/ship.h"
24 #include "sound/audiostr.h"
25 #include "sound/sound.h"
26 
27 
28 #ifdef _MSC_VER
29 #pragma optimize("", off)
30 #endif
31 
32 #define DEFAULT_MASTER_EVENT_MUSIC_VOLUME 0.5f
33 
34 #define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
35 
37 // Globals
41 
42 typedef struct tagSNDPATTERN {
43  int default_next_pattern; // Needed so the next_pattern member can be reset
44  int next_pattern; // Next pattern to play at loop time (can be same pattern)
45  int default_loop_for; // Needed so the loop_for variable can be reset
46  int loop_for; // Number of times to loop before switching to next pattern
47  int handle; // handle to open audio stream
48  int force_pattern; // flag to indicate that we want to not continue loop, but go to next_pattern
49  int can_force; // whether this pattern can be interrupted
50  int samples_per_measure; // number of bytes in a measure
51  float num_measures; // number of measures in wave file
52 } SNDPATTERN;
53 
54 SNDPATTERN Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
55 
56 // Holds filenames for the different sections of a soundtrack
59 int Current_soundtrack_num; // Active soundtrack for the current mission.. index into Soundtracks[]
60 
61 #define PATTERN_DELAY 1000 // in ms
62 int Current_pattern = -1; // currently playing part of track
63 int Pending_pattern = -1;
66 
67 // File Globals
68 static int Num_enemy_arrivals;
69 static int Num_friendly_arrivals;
70 
71 #define ARRIVAL_INTERVAL_TIMESTAMP 5000
72 #define BATTLE_CHECK_INTERVAL 15000
73 static int Battle_over_timestamp;
74 static int Mission_over_timestamp;
75 static int Victory2_music_played;
76 static int Next_arrival_timestamp;
77 static int Check_for_battle_music;
78 
79 // stores the number of measures for the different patterns (data from music.tbl)
81 
82 // stores the number of bytes per measure (data from music.tbl)
84 
85 typedef struct pattern_info
86 {
87  char *pattern_name;
88  char *pattern_desc;
93 } pattern_info;
94 
96 {
97  {"NRML_1", "Normal 1", TRUE, 1, SONG_NRML_2, SONG_NRML_1 },
98  {"NRML_2", "Normal 2", TRUE, 1, SONG_NRML_1, SONG_NRML_1 },
99  {"NRML_3", "Normal 3", TRUE, 1, SONG_NRML_1, SONG_NRML_1 },
100  {"AARV_1", "Ally arrival 1", FALSE, 1, SONG_NRML_2, SONG_NRML_1 },
101  {"AARV_2", "Ally arrival 2", FALSE, 1, SONG_BTTL_2, SONG_BTTL_2 },
102  {"EARV_1", "Enemy arrival 1", FALSE, 1, SONG_BTTL_1, SONG_BTTL_1 },
103  {"EARV_2", "Enemy arrival 2", FALSE, 1, SONG_BTTL_2, SONG_BTTL_3 },
104  {"BTTL_1", "Battle 1", TRUE, 1, SONG_BTTL_2, SONG_BTTL_2 },
105  {"BTTL_2", "Battle 2", TRUE, 1, SONG_BTTL_3, SONG_BTTL_3 },
106  {"BTTL_3", "Battle 3", TRUE, 1, SONG_BTTL_1, SONG_BTTL_1 },
107  {"FAIL_1", "Failure 1", FALSE, 1, SONG_NRML_3, SONG_NRML_1 },
108  {"VICT_1", "Victory 1", FALSE, 1, SONG_NRML_3, SONG_NRML_1 },
109  {"VICT_2", "Victory 2", TRUE, 1, SONG_NRML_3, SONG_NRML_1 },
110  {"DEAD_1", "Dead 1", TRUE, 1, -1, -1 },
111 };
112 
114 
115 //Because of how inflexible music.tbl is, to make it flexible, we must keep the stuff
116 //in the old order. So to make it reasonable, we use this.
117 //This is a list of the old pattern indexes. If you add a song you should
118 //add it in the right spot in here, with a value of largest+1.
120 {
121  0, //normal 1
122  12, //normal 2
123  13, //normal 3
124  1, //friendly arrival 1
125  6, //friendly arrival 2
126  2, //enemy arrival 1
127  7, //enemy arrival 2
128  3, //battle 1
129  4, //battle 2
130  5, //battle 3
131  10, //goal failed 1
132  8, //victory 1
133  9, //victory 2
134  11, //death
135 };
136 
137 
138 /*
139 char* Pattern_names[MAX_PATTERNS] =
140 {
141 //XSTR:OFF
142  "NRML_1", // Normal Song 1
143  "AARV_1", // Allied Arrival 1
144  "EARV_1", // Enemy Arrival 1
145  "BTTL_1", // Battle Song 1
146  "BTTL_2", // Battle Song 2
147  "BTTL_3", // Battle Song 3
148  "AARV_2", // Allied Arrival 2
149  "EARV_2", // Enemy Arrival 2
150  "VICT_1", // Victory Song 1
151  "VICT_2", // Victory Song 2
152  "FAIL_1", // Goal Failed 1
153  "DEAD_1", // Death Song 1
154  "NRML_2", // Normal Song 2
155  "NRML_3" // Normal Song 3
156 //XSTR:ON
157 };
158 
159 char* Pattern_description[MAX_PATTERNS] =
160 {
161 //XSTR:OFF
162  "normal 1",
163  "friendly arrival 1",
164  "enemy arrival 2",
165  "battle 1",
166  "battle 2",
167  "battle 3",
168  "friendly arrival 2",
169  "enemey arrival 2",
170  "victory 1",
171  "victory 2",
172  "goal failed 1",
173  "death",
174  "normal 2",
175  "normal 3"
176 //XSTR:ON
177 };
178 
179 int Pattern_loop_for[MAX_PATTERNS] =
180 {
181  1, // Normal Song 1
182  1, // Allied Arrival 1
183  1, // Enemy Arrival 1
184  1, // Battle Song 1
185  1, // Battle Song 2
186  1, // Battle Song 3
187  1, // Allied Arrival 2
188  1, // Enemy Arrival 2
189  1, // Victory Song 1
190  1, // Victory Song 2
191  1, // Goal Failed 1
192  1, // Death Song 1
193  1, // Normal Song 2
194  1 // Normal Song 3
195 };
196 
197 int Pattern_default_next[MAX_PATTERNS] =
198 {
199  SONG_NRML_1, // NRML_1 progresses to NRML_1 by default
200  SONG_NRML_1, // AARV_1 progresses to NRML_1 by default
201  SONG_BTTL_1, // EARV_1 progresses to BTTL_1 by default
202  SONG_BTTL_2, // BTTL_1 progresses to BTTL_2 by default
203  SONG_BTTL_3, // BTTL_2 progresses to BTTL_3 by default
204  SONG_BTTL_1, // BTTL_3 progresses to BTTL_1 by default
205  SONG_BTTL_2, // AARV_2 progresses to BTTL_2 by default
206  SONG_BTTL_3, // EARV_2 progresses to BTTL_3 by default
207  SONG_NRML_1, // VICT_1 progresses to NRML_1 by default
208  SONG_NRML_1, // VICT_2 progresses to NRML_1 by default
209  SONG_NRML_1, // FAIL_1 progresses to NRML_1 by default
210  -1, // no music plays after dead
211  SONG_NRML_1, // NRML_2 progresses to NRML_1 by default (but we intercept this)
212  SONG_NRML_1 // NRML_3 progresses to NRML_1 by default (but we intercept this)
213 };
214 
215 
216 // Certain patterns can be interrupted (such as the long-playing NRML and BTTL tracks).
217 // Other shorter tracks (such as arrivals) play their entire duration.
218 int Pattern_can_force[MAX_PATTERNS] =
219 {
220  TRUE, // NRML_1
221  FALSE, // AARV_1
222  FALSE, // EARV_1
223  TRUE, // BTTL_1
224  TRUE, // BTTL_2
225  TRUE, // BTTL_3
226  FALSE, // AARV_2
227  FALSE, // EARV_2
228  FALSE, // VICT_1
229  TRUE, // VICT_2
230  FALSE, // FAIL_1
231  TRUE, // DEAD_1
232  TRUE, // NRML_2
233  TRUE // NRML_3
234 };
235 */
236 
238 static int Event_music_inited = FALSE;
239 static int Event_music_level_inited = FALSE;
240 static int Event_music_begun = FALSE;
241 
242 // forward function declarations
245 extern int hud_target_invalid_awacs(object *objp);
246 
247 // Holds file names of spooled music that is played at menus, briefings, credits etc.
248 // Indexed into by a #define enumeration of the different kinds of spooled music
250 int Num_music_files; // Number of spooled music files
251 
252 // Array that holds indicies into Spooled_music[], these specify which music is played in briefing/debriefing
254 
255 
256 // -------------------------------------------------------------------------------------------------
257 // event_music_init()
258 //
259 // Called once at game start-up to parse music.tbl and set some state variables
260 //
262 {
263  if(!Fred_running)
264  {
265  if ( snd_is_inited() == FALSE ) {
266  Event_music_enabled = FALSE;
267  return;
268  }
269 
271  return;
272  }
273 
274  if ( Event_music_inited == TRUE )
275  return;
276  }
277 
278  int i, j;
279 
280  //MUST be called before parsing stuffzors.
281  Num_music_files = 0;
282  Num_soundtracks = 0; // Global
284 
285  // Goober5000
286  // set all the filenames to "none" so we're compatible with the extra NRMLs in FS1 music
287  memset(Soundtracks, 0, MAX_SOUNDTRACKS * sizeof(SOUNDTRACK_INFO));
288  for (i = 0; i < MAX_SOUNDTRACKS; i++)
289  for (j = 0; j < MAX_PATTERNS; j++)
290  strcpy_s(Soundtracks[i].pattern_fnames[j], NOX("none.wav"));
291 
292  // Goober5000
293  memset(Spooled_music, 0, MAX_SPOOLED_MUSIC * sizeof(menu_music));
294 
295  //Do teh parsing
296  event_music_parse_musictbl("music.tbl");
297 
298  // look for any modular tables
300 
301  /* this doesn't work properly!!
302  for (i = 0; i < Num_soundtracks; i++) {
303  for (j = 0; j < Soundtracks[i].num_patterns; j++) {
304  int spm = snd_get_samples_per_measure(Soundtracks[i].pattern_fnames[j], Pattern_num_measures[i][j]);
305 
306  if (spm > 0)
307  Pattern_samples_per_measure[i][j] = spm;
308  }
309  } */
310 
311  Event_music_inited = TRUE;
312  Event_music_begun = FALSE;
313 }
314 
315 // -------------------------------------------------------------------------------------------------
316 // event_music_close()
317 //
318 // Called once at game end
319 //
321 {
322  if ( Event_music_inited == FALSE )
323  return;
324 
325  Event_music_inited = FALSE;
326 }
327 
328 // Goober5000
330 {
331  // default
332  int new_pattern = Patterns[Current_pattern].next_pattern;
333 
334  // Goober5000 - not for FS1
335  if (!(Soundtracks[Current_soundtrack_num].flags & EMF_CYCLE_FS1))
336  {
337  if (Current_pattern == SONG_BTTL_3 && new_pattern == SONG_BTTL_1)
338  {
339  // AL 06-24-99: maybe switch to battle 2 if hull is less than 70%
340  if (Player_obj != NULL && Player_ship != NULL)
341  {
343 
346  new_pattern = SONG_BTTL_2;
347  }
348  }
349  }
350 
351  // make sure we have a valid BTTL track to switch to
352  if ((new_pattern == SONG_BTTL_2) && (Patterns[SONG_BTTL_2].handle < 0))
353  {
354  new_pattern = SONG_BTTL_1;
355  }
356  else if ((new_pattern == SONG_BTTL_3) && (Patterns[SONG_BTTL_3].handle < 0))
357  {
358  if ((Current_pattern == SONG_BTTL_2) || (Patterns[SONG_BTTL_2].handle < 0))
359  new_pattern = SONG_BTTL_1;
360  else
361  new_pattern = SONG_BTTL_2;
362  }
363 
364  // make sure we have a valid NRML track to switch to
365  if ((new_pattern == SONG_NRML_2) && (Patterns[SONG_NRML_2].handle < 0))
366  {
367  new_pattern = SONG_NRML_1;
368  }
369  else if ((new_pattern == SONG_NRML_3) && (Patterns[SONG_NRML_3].handle < 0))
370  {
371  new_pattern = SONG_NRML_1;
372  }
373 
374  return new_pattern;
375 }
376 
377 // -------------------------------------------------------------------------------------------------
378 // event_music_force_switch()
379 //
380 // Performs a switch between patterns. Sets the cutoff limit for the pattern that is being
381 // switch to.
382 //
384 {
385  if ( Event_music_enabled == FALSE )
386  return;
387 
388  if ( Event_music_level_inited == FALSE )
389  return;
390 
392 
393  int new_pattern = event_music_cycle_pattern();
394 
395  if ( new_pattern == -1 ) {
396  return;
397  }
398 
399  if ( Patterns[new_pattern].num_measures == 0 )
400  return; // invalid pattern
401 
402  Assert(new_pattern >= 0 && new_pattern < MAX_PATTERNS);
403  audiostream_play(Patterns[new_pattern].handle, (Master_event_music_volume * aav_music_volume), 0); // no looping
404  audiostream_set_sample_cutoff(Patterns[new_pattern].handle, fl2i(Patterns[new_pattern].num_measures * Patterns[new_pattern].samples_per_measure) );
406  Patterns[Current_pattern].force_pattern = FALSE;
407  nprintf(("EVENTMUSIC", "EVENTMUSIC => switching to %s from %s\n", Pattern_info[new_pattern].pattern_name, Pattern_info[Current_pattern].pattern_name));
408 
409  // actually switch the pattern
410  Current_pattern = new_pattern;
411 }
412 
413 // -------------------------------------------------------------------------------------------------
414 // event_music_do_frame()
415 //
416 // Called once per game frame, to check for transitions of patterns (and to start the music off at
417 // the beginning).
418 //
420 {
421  if ( Event_music_level_inited == FALSE ) {
422  return;
423  }
424 
425  if ( Event_music_enabled == FALSE ) {
426  return;
427  }
428 
429  // start off the music delayed
431  Pattern_timer_id = 0;
432  Event_music_begun = TRUE;
433  if ( Current_pattern != -1 && Patterns[Current_pattern].handle >= 0) {
434  //WMC - removed in favor of if
435  //Assert(Patterns[Current_pattern].handle >= 0 );
436  audiostream_play(Patterns[Current_pattern].handle, (Master_event_music_volume * aav_music_volume), 0); // no looping
437  audiostream_set_sample_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].samples_per_measure) );
438  }
439  }
440 
441  if ( Event_music_begun == FALSE ) {
442  return;
443  }
444 
445  if ( Current_pattern != -1 ) {
446  SNDPATTERN *pat;
447  pat = &Patterns[Current_pattern];
448 
449  // First case: switching to a different track since first track is almost at end
450  if ( audiostream_done_reading(pat->handle) ) {
452  }
453  // Second case: looping back to start of same track since at the end
454  else if ( !audiostream_is_playing(pat->handle) && !audiostream_is_paused(pat->handle) ) {
455  audiostream_stop(pat->handle); // stop current and rewind
456  pat->loop_for--;
457  if ( pat->loop_for > 0 ) {
459  audiostream_set_sample_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].samples_per_measure) );
460  }
461  else {
463  }
464  }
465  // Third case: switching to a different track by interruption
466  else if ( (pat->force_pattern == TRUE && pat->can_force == TRUE) ) {
467  int samples_streamed = audiostream_get_samples_committed(pat->handle);
468  int measures_played = samples_streamed / pat->samples_per_measure;
469  if ( measures_played < pat->num_measures ) {
470  audiostream_set_sample_cutoff(pat->handle, pat->samples_per_measure * (measures_played+1) );
471  pat->force_pattern = FALSE;
472  pat->loop_for = 0;
473  }
474  }
475 
476  if (Event_Music_battle_started == 0) {
478  if (timestamp_elapsed(Check_for_battle_music)) {
479  Check_for_battle_music = timestamp(1000);
480  if (hostile_ships_present() == TRUE) {
482  Patterns[Current_pattern].force_pattern = TRUE;
483  }
484  }
486  if (timestamp_elapsed(Battle_over_timestamp)) {
487  Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
488  if (hostile_ships_present() == FALSE) {
489  Patterns[Current_pattern].force_pattern = TRUE;
490 
491  if (Soundtracks[Current_soundtrack_num].flags & EMF_CYCLE_FS1) {
493  } else {
495  }
496  }
497  }
498  }
499  } else {
500  // We want to go back to NRML track music if all the hostiles have been
501  // destroyed, and we are still playing the battle music
503  if (timestamp_elapsed(Battle_over_timestamp)) {
504  if (hostile_ships_present() == FALSE) {
505  if (Patterns[Current_pattern].next_pattern != SONG_VICT_2) {
506  // Goober5000
507  if (Soundtracks[Current_soundtrack_num].flags & EMF_CYCLE_FS1) {
509  } else {
511  }
512 
513  Patterns[Current_pattern].force_pattern = TRUE;
515  }
516  }
517  }
518  }
519  }
520 
521  if ( !Victory2_music_played ) {
522  if ( timestamp_elapsed(Mission_over_timestamp) ) {
523  Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
524  if ( mission_goals_met() && (!hostile_ships_present()) ) {
526  Patterns[Current_pattern].force_pattern = TRUE;
527  Victory2_music_played = 1;
528  }
529  }
530  }
531  }
532 }
533 
534 // -------------------------------------------------------------------------------------------------
535 // event_music_level_init()
536 //
537 // Called at the start of a mission (level). Sets up the pattern data, and kicks off the
538 // first track to play().
539 //
540 // input: force_soundtrack => OPTIONAL parameter (default value -1)
541 // forces the soundtrack to ignore the music.tbl assignment
542 //
543 void event_music_level_init(int force_soundtrack)
544 {
545  int i;
546  SOUNDTRACK_INFO *strack;
547 
549  return;
550 
551  if (!audiostream_is_inited())
552  return;
553 
554  if (Event_music_level_inited == TRUE)
555  return;
556 
557  Current_pattern = -1;
559 
560  if (Event_music_inited == FALSE)
561  return;
562 
563 
564  if (force_soundtrack != -1)
565  Current_soundtrack_num = force_soundtrack;
566 
567  if (Current_soundtrack_num < 0)
568  {
569  return;
570 /*
571  // okay, assign a random soundtrack if one exists
572  if ( Num_soundtracks > 0 ) {
573  Current_soundtrack_num = rand()%Num_soundtracks;
574  nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Picking random event music soundtrack: %s\n", Soundtracks[Current_soundtrack_num].name));
575  } else {
576  return;
577  }
578 */
579  }
580 
582 
583  if (Current_soundtrack_num < 0 || Current_soundtrack_num > Num_soundtracks)
584  return;
585 
586  strack = &Soundtracks[Current_soundtrack_num];
587 
588  // open the pattern files, and get ready to play them
589  // Goober5000 - changed from strack->num_patterns to MAX_PATTERNS so that *all*
590  // patterns would be checked; the behavior is the same because they were previously
591  // set to none.wav in event_music_parse_musictbl, but this change was needed because
592  // the NRML_2 and NRML_3 at the end of the pattern array kept getting spurious music
593  // tracks because their patterns weren't -1
594  for (i = 0; i < MAX_PATTERNS; i++)
595  {
596  if (!strnicmp(strack->pattern_fnames[i], NOX("none.wav"), 4))
597  {
598  Patterns[i].handle = -1;
599  continue;
600  }
601 
602  Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
603 
604  if (Patterns[i].handle >= 0)
605  {
606  Event_music_level_inited = TRUE;
607  Event_music_enabled = TRUE;
608  }
609 
610  pattern_info *pip = &Pattern_info[i];
611 
612  // Goober5000
613  if (strack->flags & EMF_CYCLE_FS1)
615  else
617 
618  Patterns[i].next_pattern = Patterns[i].default_next_pattern;
619  Patterns[i].default_loop_for = pip->pattern_loop_for;
620  Patterns[i].loop_for = Patterns[i].default_loop_for;
621  Patterns[i].force_pattern = FALSE;
622  Patterns[i].can_force = pip->pattern_can_force;
625  }
626 
627  Num_enemy_arrivals = 0;
628  Num_friendly_arrivals = 0;
629  Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
630  Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
631  Next_arrival_timestamp = timestamp(1);
632  Victory2_music_played = 0;
633  Check_for_battle_music = 0;
634 
635  if (Event_music_level_inited)
636  {
637  if (force_soundtrack >= 0)
639  }
640 }
641 
642 // -------------------------------------------------------------------------------------------------
643 // event_music_first_pattern()
644 //
645 // Picks the first pattern to play, based on whether the battle has started. Delay start
646 // by PATTERN_DELAY
647 //
649 {
650  if ( Event_music_inited == FALSE ) {
651  return;
652  }
653 
654  if ( Event_music_enabled == FALSE ) {
655  return;
656  }
657 
658  if ( Event_music_level_inited == FALSE ) {
660  }
661 
662  if ( Event_music_level_inited == FALSE ) { //-V581
663  return;
664  }
665 
666  if ( Event_music_begun == TRUE ) {
667  return;
668  }
669 
670  if ( Current_pattern != -1 ) {
671  if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
672  audiostream_stop( Patterns[Current_pattern].handle );
673  }
674 
675  Pattern_timer_id = 2000; // start music delay
676 
677  Event_music_begun = FALSE;
678  if ( Event_Music_battle_started == TRUE ) {
680  }
681  else {
683  }
684 }
685 
686 // -------------------------------------------------------------------------------------------------
687 // event_music_level_close()
688 //
689 // Called at the end of each mission (level). Stops any playing patterns by fading them out.
690 //
692 {
693  int i;
694 
695  if ( Event_music_level_inited == FALSE )
696  return;
697 
699  SOUNDTRACK_INFO *strack;
700 
702  strack = &Soundtracks[Current_soundtrack_num];
703 
704  // close the pattern files
705  for ( i = 0; i < strack->num_patterns; i++ ) {
706  if ( i == Current_pattern ) {
707  if ( audiostream_is_playing(Patterns[Current_pattern].handle) )
708  audiostream_close_file( Patterns[i].handle );
709  else
710  audiostream_close_file( Patterns[i].handle, 0 );
711  }
712  else
713  audiostream_close_file( Patterns[i].handle, 0 );
714  }
715  } else {
716  // close em all down then
718  }
719 
720  Current_pattern = -1;
721  Event_music_level_inited = FALSE;
723  Event_music_enabled = 0;
724  Event_music_begun = FALSE;
725 }
726 
727 // -------------------------------------------------------------------------------------------------
728 // event_music_battle_start()
729 //
730 // Start the battle music. If the music is already started before, do nothing.
731 //
733 {
734  if ( !hostile_ships_present() ) {
735  return 0;
736  }
737 
738  // No special tracks in training.
740  return -1;
741 
742  // Check to see if we've already started off the battle song
743  if ( Event_Music_battle_started == 1 ) {
744  return 0;
745  }
746 
747  if ( Event_music_enabled == FALSE )
748  return -1;
749 
750  if ( Event_music_level_inited == FALSE )
751  return -1;
752 
753  if ( Current_pattern == SONG_BTTL_1 )
754  return 0; // already playing
755 
756  if ( Current_pattern == SONG_DEAD_1 )
757  return 0; // death is the last song to play
758 
759  if ( Current_pattern != -1 ) {
761  Patterns[Current_pattern].force_pattern = TRUE;
762  }
763 
764  Event_Music_battle_started = 1; // keep track of this state though, need on restore
765  Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
766 
767  return 0;
768 }
769 
770 // -------------------------------------------------------------------------------------------------
771 // event_music_enemy_arrival()
772 //
773 // An enemy has arrived, play an enemy arrival pattern.
774 //
776 {
777  if ( Event_music_enabled == FALSE ) {
778  return -1;
779  }
780 
781  if ( Event_music_level_inited == FALSE ) {
782  return -1;
783  }
784 
785  int next_pattern;
786  if ( Event_Music_battle_started == TRUE ) {
787  next_pattern = SONG_EARV_2;
788  }
789  else {
790  next_pattern = SONG_EARV_1;
791  }
792 
793  if ( Current_pattern < 0 )
794  return 0;
795 
796  if ( Current_pattern == next_pattern )
797  return 0; // already playing
798 
799  if ( Current_pattern == SONG_DEAD_1 )
800  return 0; // death is the last song to play
801 
803  return 0;
804 
805  if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
806  return 0; // don't squash a pending pattern
807 
808  Num_enemy_arrivals++;
809 
810 
811  // Goober5000 - cycle according to flag
812  if (Soundtracks[Current_soundtrack_num].flags & EMF_CYCLE_FS1)
813  {
814  // AL 11-03-97:
815  // Alternate between BTTL_2 and BTTL_3 following enemy arrivals
816  if ( Num_enemy_arrivals & 1 ) {
817  Patterns[next_pattern].next_pattern = SONG_BTTL_2;
818  } else {
819  if ( Patterns[SONG_BTTL_3].handle != -1 ) {
820  Patterns[next_pattern].next_pattern = SONG_BTTL_3;
821  } else {
822  Patterns[next_pattern].next_pattern = SONG_BTTL_2;
823  }
824  }
825  }
826  else
827  {
828  // AL 7-25-99: If hull is less than 70% then switch to battle 2 or 3, otherwise switch to 1 or 2
829  bool play_intense_battle_music = false;
830  if (Player_obj != NULL && Player_ship != NULL) {
832 
835  play_intense_battle_music = true;
836  }
837 
838  if (play_intense_battle_music == true) {
839  if (Current_pattern == SONG_BTTL_2) {
840  Patterns[next_pattern].next_pattern = SONG_BTTL_3;
841  } else {
842  Patterns[next_pattern].next_pattern = SONG_BTTL_2;
843  }
844  } else {
845  if (Current_pattern == SONG_BTTL_1) {
846  Patterns[next_pattern].next_pattern = SONG_BTTL_2;
847  } else if (Current_pattern == SONG_BTTL_2) {
848  Patterns[next_pattern].next_pattern = SONG_BTTL_3;
849  } else {
850  Patterns[next_pattern].next_pattern = SONG_BTTL_1;
851  }
852  }
853  }
854 
855  if ( Current_pattern != -1 ) {
856  Patterns[Current_pattern].next_pattern = next_pattern;
857  Patterns[Current_pattern].force_pattern = TRUE;
858  }
859 
860  Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
861 
862  return 0;
863 }
864 
865 // -------------------------------------------------------------------------------------------------
866 // event_music_friendly_arrival()
867 //
868 // An friendly has arrived, play a friendly arrival pattern.
869 //
871 {
872  if ( Event_music_enabled == FALSE )
873  return -1;
874 
875  if ( Event_music_level_inited == FALSE )
876  return -1;
877 
878  if (timestamp_elapsed(Next_arrival_timestamp) == false) {
879  return 0;
880  }
881 
882  int next_pattern;
883  if ( Event_Music_battle_started == TRUE ) {
884  next_pattern = SONG_AARV_2;
885  }
886  else {
887  next_pattern = SONG_AARV_1;
888  }
889 
890  if ( Current_pattern == next_pattern )
891  return 0; // already playing
892 
893  if ( Current_pattern == SONG_DEAD_1 )
894  return 0; // death is the last song to play
895 
897  return 0;
898 
899  // Goober5000 - to avoid array out-of-bounds
900  //Assert(Current_pattern >= 0 && Current_pattern < MAX_PATTERNS);
901 
902  if(Current_pattern < 0 || Current_pattern >= MAX_PATTERNS)
903  return 0;
904 
905  if ( Patterns[Current_pattern].next_pattern != Patterns[Current_pattern].default_next_pattern )
906  return 0; // don't squash a pending pattern
907 
908  // After the second friendly arrival, default to SONG_BTTL_3
909  Num_friendly_arrivals++;
910 
911 
912  if ( Current_pattern != -1 )
913  {
914  // AL 06-24-99: always overlay allied arrivals
915  // Goober5000 - do this based on a flag (set in music.tbl for FS1 soundtracks)
916 
917  // overlay
919  {
920  // Goober5000 - I didn't touch this part... for some reason, FS2 only has one
921  // arrival music pattern, and this is it
922  Assert(Patterns[SONG_AARV_1].handle >= 0 );
923  audiostream_play(Patterns[SONG_AARV_1].handle, (Master_event_music_volume * aav_music_volume), 0); // no looping
924  audiostream_set_sample_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].samples_per_measure) );
925  }
926  // don't overlay
927  else
928  {
929  Patterns[Current_pattern].next_pattern = next_pattern;
930  Patterns[Current_pattern].force_pattern = TRUE;
931 
932  // Goober5000 - default to SONG_BTTL_3 as specified above
933  // (this is my attempted recreation of the FS1 behavior)
934  if (Soundtracks[Current_soundtrack_num].flags & EMF_CYCLE_FS1)
935  {
936  if ((Event_Music_battle_started == TRUE) && (Num_friendly_arrivals > 2))
937  {
938  if (Patterns[SONG_BTTL_3].handle != -1)
939  {
940  Patterns[next_pattern].next_pattern = SONG_BTTL_3;
941  }
942  }
943  }
944  }
945  }
946 
947  Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
948 
949  Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
950 
951  return 0;
952 }
953 
954 // Play arrival music keyed to team "team".
956 {
957  // No friendly arrival music in a training mission.
959  return;
960 
961  // check if ship is enemy ship (we attack it)
962  if (iff_x_attacks_y(Player_ship->team, team))
964  else
966 }
967 
968 // -------------------------------------------------------------------------------------------------
969 // event_music_primary_goals_met()
970 //
971 // A primary goal has failed
972 //
974 {
975  int next_pattern;
976 
977  // No special tracks in training.
979  return -1;
980 
981  if ( Event_music_enabled == FALSE )
982  return -1;
983 
984  if ( Event_music_level_inited == FALSE )
985  return -1;
986 
987  if ( Current_pattern == SONG_DEAD_1 )
988  return 0; // death is the last song to play
989 
990  if ( Patterns[SONG_FAIL_1].handle < 0 ) // can't play if music file doesn't exist
991  return 0;
992 
993  if ( hostile_ships_present() ) {
994  next_pattern = SONG_BTTL_1;
995  }
996  else {
997  next_pattern = SONG_NRML_1;
999  }
1000 
1001  if ( Current_pattern != -1 ) {
1003  Patterns[Current_pattern].next_pattern = next_pattern;
1004  Patterns[Current_pattern].force_pattern = TRUE;
1005  }
1006 
1007  return 0;
1008 }
1009 
1010 // -------------------------------------------------------------------------------------------------
1011 // event_music_primary_goals_met()
1012 //
1013 // A goal has been achieved, play the appropriate victory music.
1014 //
1016 {
1017  int next_pattern = SONG_VICT_1;
1018 
1019  // No special tracks in training.
1021  return -1;
1022 
1023  if ( Event_music_enabled == FALSE )
1024  return -1;
1025 
1026  if ( Event_music_level_inited == FALSE )
1027  return -1;
1028 
1030  return 0; // already playing
1031 
1032  if ( Current_pattern == SONG_DEAD_1 )
1033  return 0; // death is the last song to play
1034 
1035  if ( hostile_ships_present() ) {
1036  Patterns[SONG_VICT_1].next_pattern = SONG_BTTL_1;
1037  }
1038  else {
1039  Patterns[SONG_VICT_1].next_pattern = SONG_VICT_2;
1041 
1042  // If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
1043  // to the next default track
1044  if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
1045  Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
1046  } else {
1047  Victory2_music_played = 1;
1048  }
1049  }
1050 
1051  if ( Current_pattern != -1 ) {
1052  Patterns[Current_pattern].next_pattern = next_pattern;
1053  Patterns[Current_pattern].force_pattern = TRUE;
1054  }
1055 
1056  return 0;
1057 }
1058 
1059 // -------------------------------------------------------------------------------------------------
1060 // event_music_player_death()
1061 //
1062 // The player has died, play death pattern.
1063 //
1065 {
1066  if ( Event_music_enabled == FALSE )
1067  return -1;
1068 
1069  if ( Event_music_level_inited == FALSE )
1070  return -1;
1071 
1072  if ( Current_pattern == SONG_DEAD_1 )
1073  return 0; // already playing
1074 
1075  if ( Current_pattern != -1 ) {
1078  Patterns[Current_pattern].force_pattern = TRUE;
1079  }
1080 
1081  return 0;
1082 }
1083 
1084 // -------------------------------------------------------------------------------------------------
1085 // event_music_player_respawn()
1086 //
1087 // Player has respawned (multiplayer only)
1088 //
1090 {
1091  if ( Event_music_enabled == FALSE )
1092  return -1;
1093 
1094  if ( Event_music_level_inited == FALSE )
1095  return -1;
1096 
1097 // Assert(Current_pattern == SONG_DEAD_1);
1098 
1101  Patterns[Current_pattern].force_pattern = TRUE;
1102 
1103  return 0;
1104 }
1105 
1106 // -------------------------------------------------------------------------------------------------
1107 // event_music_player_respawn_as_observer()
1108 //
1109 // Player has respawned (multiplayer only)
1110 //
1112 {
1113  if ( Event_music_enabled == FALSE )
1114  return -1;
1115 
1116  if ( Event_music_level_inited == FALSE )
1117  return -1;
1118 
1119  if ( Current_pattern >= 0 ) {
1120  if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1121  audiostream_stop(Patterns[Current_pattern].handle);
1122  Current_pattern = -1;
1123  }
1124  }
1125 
1126  return 0;
1127 }
1128 
1129 bool parse_soundtrack_line(int strack_idx, int pattern_idx)
1130 {
1131  char fname[MAX_FILENAME_LEN];
1132  char line_buf[MAX_PATH_LEN];
1133  char *token;
1134  int count = 0;
1135 
1136  // line_buf holds 3 fields: filename, num measures, bytes per measure
1137  stuff_string(line_buf, F_NAME, sizeof(line_buf));
1138 
1139  //Check if we can add this pattern
1140  if( pattern_idx >= MAX_PATTERNS ) {
1141  Warning(LOCATION, "Too many $Name: entries for soundtrack %s", Soundtracks[strack_idx].name);
1142  return false;
1143  }
1144 
1145  //We can apparently still add this pattern, so go ahead and do it.
1146  token = strtok( line_buf, NOX(" ,\t"));
1147  strcpy_s(fname, token);
1148  while ( token != NULL )
1149  {
1150  token = strtok( NULL, NOX(" ,\t") );
1151  //If we have no more items, get out and return
1152  if ( token == NULL && count != 2)
1153  {
1154  Warning(LOCATION, "Missing or additional field for soundtrack %s, pattern %s", Soundtracks[strack_idx].name, Pattern_info[pattern_idx].pattern_desc);
1155  break;
1156  }
1157 
1158 
1159  if ( count == 0 ) {
1160  Pattern_num_measures[strack_idx][pattern_idx] = (float)atof(token); //Num_measures
1161  } else if(count == 1) {
1162  Pattern_samples_per_measure[strack_idx][pattern_idx] = atoi(token); //Samples per measure
1163  }
1164 
1165  count++;
1166  } // end while
1167 
1168  strcpy_s(Soundtracks[strack_idx].pattern_fnames[pattern_idx], fname);
1169  return true;
1170 }
1171 
1173 {
1174  char namebuf[NAME_LENGTH];
1175  int i, strack_idx = -1;
1176  bool nocreate = false;
1177 
1178  //Start parsing soundtrack
1179  //required_string("#Soundtrack Start");
1180 
1181  //Get the name, and do we have this track already?
1182  required_string("$SoundTrack Name:");
1183  stuff_string(namebuf, F_NAME, NAME_LENGTH);
1184  strack_idx = event_music_get_soundtrack_index(namebuf);
1185 
1186  //Do we have a nocreate?
1187  if(optional_string("+nocreate")) {
1188  nocreate = true;
1189  }
1190 
1191  //Get a valid strack_idx
1192  if(strack_idx < 0 && (nocreate || Num_soundtracks >= MAX_SOUNDTRACKS))
1193  {
1195  Warning(LOCATION, "Maximum number of soundtracks reached after '%s'; max is '%d'", Soundtracks[MAX_SOUNDTRACKS-1].name, MAX_SOUNDTRACKS);
1196  }
1197 
1198  //Track doesn't exist and has nocreate, so don't create it
1199  Assertion(skip_to_start_of_string_either("#SoundTrack Start", "#Menu Music Start") || skip_to_string("#SoundTrack End"), "Couldn't find #Soundtrack Start, #Menu Music Start or #Soundtrack End. Music.tbl or -mus.tbm is invalid.\n");
1200 
1201  return;
1202  }
1203  else if(strack_idx < 0)
1204  {
1205  //If we don't have this soundtrack already, create it
1206  strack_idx = Num_soundtracks;
1207 
1208  strcpy_s(Soundtracks[strack_idx].name, namebuf);
1209  Soundtracks[strack_idx].num_patterns = 0;
1210 
1211  Num_soundtracks++;
1212  }
1213 
1214  // Goober5000
1215  if (optional_string("+Cycle:"))
1216  {
1217  char temp[NAME_LENGTH];
1219  if (!stricmp(temp, "FS1"))
1220  Soundtracks[strack_idx].flags |= EMF_CYCLE_FS1;
1221  }
1222 
1223  // Goober5000
1224  if (optional_string("+Allied Arrival Overlay:"))
1225  {
1226  stuff_boolean_flag(&Soundtracks[strack_idx].flags, EMF_ALLIED_ARRIVAL_OVERLAY);
1227  }
1228  else
1229  {
1230  // default to on
1231  Soundtracks[strack_idx].flags |= EMF_ALLIED_ARRIVAL_OVERLAY;
1232  }
1233 
1234  //If the next string is $Name:, use default Volition stuff
1235  if(check_for_string("$Name:"))
1236  {
1237  int old_pattern_num = 0;
1238 
1239  while (required_string_either("#SoundTrack End","$Name:"))
1240  {
1241  required_string("$Name:");
1242 
1243  //Find which new pattern index this corresponds to
1244  for(i = 0; i < Num_pattern_types; i++)
1245  {
1246  if(New_pattern_order[i] == old_pattern_num)
1247  {
1248  if(parse_soundtrack_line(strack_idx, i))
1249  {
1250  //If new pattern is higher, change the old value
1251  if(i+1 > Soundtracks[strack_idx].num_patterns) {
1252  Soundtracks[strack_idx].num_patterns = i+1;
1253  }
1254  }
1255 
1256  //Get out of the loop
1257  break;
1258  }
1259  }
1260 
1261  if(i == Num_pattern_types)
1262  {
1263  Warning(LOCATION, "Could not find new index for pattern %d of soundtrack '%s'", old_pattern_num, Soundtracks[strack_idx].name);
1264  }
1265 
1266  old_pattern_num++;
1267  }
1268  }
1269  else
1270  {
1271  //Use our new stuff
1272  char tagbuf[64];
1273 
1274  //try the new pattern order
1275  for(i = 0; i < Num_pattern_types; i++)
1276  {
1277  //Check for the tag based on description
1278  sprintf(tagbuf, "$%s:", Pattern_info[i].pattern_desc);
1279  if(optional_string(tagbuf))
1280  {
1281  //Parse it
1282  if(parse_soundtrack_line(strack_idx, i))
1283  {
1284  //If the new pattern is higher than the old one, change num_patterns
1285  if(i+1 > Soundtracks[strack_idx].num_patterns) {
1286  Soundtracks[strack_idx].num_patterns = i+1;
1287  }
1288  }
1289  }
1290  }
1291  }
1292 
1293  //We're done here.
1294  //required_string("#SoundTrack End");
1295 
1296 
1297  // Goober5000 - set the valid flag according to whether we can load all our patterns
1298  // (since someone may be running an enhanced music.tbl without warble_fs1 installed)
1299  for (i = 0; i < Soundtracks[strack_idx].num_patterns; i++)
1300  {
1301  // check for "none"
1302  if (!strlen(Soundtracks[strack_idx].pattern_fnames[i]) || !strnicmp(Soundtracks[strack_idx].pattern_fnames[i], "none", 4))
1303  continue;
1304 
1305  // check for file
1306  if (!cf_exists_full(Soundtracks[strack_idx].pattern_fnames[i], CF_TYPE_MUSIC))
1307  return;
1308  }
1309 
1310  // made it here okay, so it's valid
1311  Soundtracks[strack_idx].flags |= EMF_VALID;
1312 }
1313 
1315 {
1316  char spoolname[NAME_LENGTH];
1317  char fname[MAX_FILENAME_LEN];
1318  bool nocreate = false;
1319 
1320  required_string("$Name:");
1321  stuff_string(spoolname, F_NAME, NAME_LENGTH);
1322 
1323  if(optional_string("+nocreate")) {
1324  nocreate = true;
1325  }
1326 
1327  int idx = event_music_get_spooled_music_index(spoolname);
1328 
1329  if(idx < 0 && (nocreate || Num_music_files >= MAX_SPOOLED_MUSIC))
1330  {
1331  if(Num_music_files >= MAX_SPOOLED_MUSIC) {
1332  Warning(LOCATION, "Could not load spooled music file after '%s' as maximum number of spooled music was reached (Max is %d)", Spooled_music[Num_music_files - 1].name, MAX_SPOOLED_MUSIC);
1333  }
1334 
1335  if (!skip_to_start_of_string_either("$Name:", "#Menu Music End")) {
1336  Error(LOCATION, "Couldn't find $Name or #Menu Music End. Music.tbl or -mus.tbm is invalid.\n");
1337  }
1338 
1339  return;
1340  }
1341  else if(idx < 0)
1342  {
1343  idx = Num_music_files;
1344 
1345  strcpy_s( Spooled_music[idx].name, spoolname );
1346  strcpy_s( Spooled_music[idx].filename, "");
1347  }
1348 
1349  if(optional_string("$Filename:"))
1350  {
1352  if ( strnicmp(fname, NOX("none.wav"), 4) ) {
1353  strcpy_s( Spooled_music[idx].filename, fname );
1354  }
1355  else
1356  {
1357  //Clear this
1358  strcpy_s( Spooled_music[idx].filename, "");
1359  }
1360  }
1361 
1362  // Goober5000 - check for existence of file
1363  // taylor - check for all file types
1364  // chief1983 - use type list defined in audiostr.h
1366  Spooled_music[idx].flags |= SMF_VALID;
1367 
1368  if (!nocreate)
1369  Num_music_files++;
1370 }
1371 
1372 // -------------------------------------------------------------------------------------------------
1373 // event_music_parse_musictbl() will parse the music.tbl file, and set up the Mission_songs[]
1374 // array
1375 //
1377 {
1378  try
1379  {
1380  read_file_text(filename, CF_TYPE_TABLES);
1381  reset_parse();
1382 
1383  while ( skip_to_start_of_string_either("#Soundtrack Start", "#Menu Music Start", NULL ) )
1384  {
1385  if ( optional_string("#Soundtrack Start") )
1386  {
1387  parse_soundtrack( );
1388  required_string("#Soundtrack End");
1389  }
1390  if ( optional_string("#Menu Music Start") )
1391  {
1392  while ( required_string_either("$Name", "#Menu Music End") == 0 )
1393  {
1394  parse_menumusic( );
1395  }
1396  }
1397  }
1398  }
1399  catch (const parse::ParseException& e)
1400  {
1401  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
1402  }
1403 }
1404 
1405 // -------------------------------------------------------------------------------------------------
1406 // event_music_change_pattern()
1407 //
1408 // Force a particular pattern to play. This is used for debugging purposes.
1409 //
1410 void event_music_change_pattern(int new_pattern)
1411 {
1412  if ( Event_music_enabled == FALSE ) {
1413  nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1414  return;
1415  }
1416 
1417  if ( Event_music_level_inited == FALSE ) {
1418  nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1419  return;
1420  }
1421 
1422  if ( Current_pattern == new_pattern )
1423  return; // already playing
1424 
1425  if ( Current_pattern != -1 ) {
1427  Patterns[Current_pattern].next_pattern = new_pattern;
1428  Patterns[Current_pattern].force_pattern = TRUE;
1429  }
1430 }
1431 
1432 // -------------------------------------------------------------------------------------------------
1433 // event_music_return_current_pattern()
1434 //
1435 // Simply return what the current pattern being played is. Don't want to make global.
1436 //
1438 {
1439  return Current_pattern;
1440 }
1441 
1442 // -------------------------------------------------------------------------------------------------
1443 // event_music_disable()
1444 //
1445 // Stop any patterns that are playing, and prevent any further patterns from playing (ie
1446 // set Event_music_enabled = FALSE). We don't uninit event music, since it might be toggled
1447 // back on in this level.
1448 //
1450 {
1451  if ( Event_music_level_inited == FALSE )
1452  return;
1453 
1454  if ( Event_music_enabled == FALSE )
1455  return;
1456 
1457  if (Current_pattern == -1)
1458  return;
1459 
1461  if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1462  audiostream_stop(Patterns[Current_pattern].handle); // stop current and rewind
1463  }
1464 
1465  Event_music_begun = FALSE;
1466  Event_music_enabled = FALSE;
1467  Current_pattern = -1;
1468 }
1469 
1470 // -------------------------------------------------------------------------------------------------
1471 // event_music_enable()
1472 //
1473 // Init the event music (ie load the patterns) if required. Set up the first song to play, and
1474 // set Event_music_enabled = TRUE to allow patterns to play.
1475 //
1477 {
1478  if ( Event_music_enabled == TRUE )
1479  return;
1480 
1481  Event_music_enabled = TRUE;
1482 
1483  if ( Event_music_level_inited == FALSE ) {
1485  // start the first pattern to play (delayed)
1486  if ( Game_mode & GM_IN_MISSION ) {
1488  }
1489  }
1490  else {
1491  // start a new pattern
1492  Event_music_begun = FALSE;
1493  Pattern_timer_id = timestamp(150);
1495  }
1496 }
1497 
1498 // -------------------------------------------------------------------------------------------------
1499 // event_music_start_default()
1500 //
1501 // Start playing a default track, based on how far the mission has progressed
1502 //
1504 {
1505  int next_pattern;
1506 
1507  if ( Event_Music_battle_started == TRUE ) {
1508  if ( hostile_ships_present() ) {
1509  next_pattern = SONG_BTTL_1;
1510  }
1511  else {
1513  next_pattern = SONG_NRML_1;
1514  }
1515  }
1516  else
1517  {
1518  next_pattern = SONG_NRML_1;
1519  }
1520 
1521  // switch now
1522  if ( Current_pattern == -1 ) {
1523  Current_pattern = next_pattern;
1524  }
1525  // switch later
1526  else {
1527  Patterns[Current_pattern].next_pattern = next_pattern;
1528  Patterns[Current_pattern].force_pattern = TRUE;
1529  }
1530 
1531 }
1532 
1533 // -------------------------------------------------------------------------------------------------
1534 // event_music_pause()
1535 //
1536 // Stop any playing pattern, but don't rewind.
1537 //
1539 {
1540  if ( Event_music_enabled == FALSE ) {
1541  nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1542  return;
1543  }
1544 
1545  if ( Event_music_level_inited == FALSE ) {
1546  nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1547  return;
1548  }
1549 
1550  if (Current_pattern == -1)
1551  return;
1552 
1554  if ( audiostream_is_playing(Patterns[Current_pattern].handle) ) {
1555  audiostream_stop(Patterns[Current_pattern].handle, 0); // stop current and don't rewind
1556  }
1557 }
1558 
1559 // -------------------------------------------------------------------------------------------------
1560 // event_music_unpause()
1561 //
1562 // Start the Current_pattern if it is paused.
1563 //
1565 {
1566  if ( Event_music_enabled == FALSE ) {
1567  nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Requested a song switch when event music is not enabled\n"));
1568  return;
1569  }
1570 
1571  if ( Event_music_level_inited == FALSE ) {
1572  nprintf(("EVENTMUSIC", "EVENTMUSIC ==> Event music is not enabled\n"));
1573  return;
1574  }
1575 
1576  if (Current_pattern == -1)
1577  return;
1578 
1580  if ( audiostream_is_paused(Patterns[Current_pattern].handle) == TRUE ) {
1581  audiostream_play(Patterns[Current_pattern].handle, (Master_event_music_volume * aav_music_volume), 0); // no looping
1582  audiostream_set_sample_cutoff(Patterns[Current_pattern].handle, fl2i(Patterns[Current_pattern].num_measures * Patterns[Current_pattern].samples_per_measure) );
1583  }
1584 }
1585 
1586 // -------------------------------------------------------------------------------------------------
1587 // event_music_set_volume_all()
1588 //
1589 // Set the volume of the event driven music. Used when using the game-wide music volume is changed
1590 // by the user.
1591 //
1592 void event_music_set_volume_all(float volume)
1593 {
1595 }
1596 
1597 // ----------------------------------------------------------------------
1598 // hostile_ships_present()
1599 //
1600 // Determine if there are any non-friendly ships in existance
1601 //
1602 // returns: 1 => there are non-friendly ships in existance
1603 // 0 => any ships in existance are friendly
1605 {
1606  ship *shipp;
1607  ship_obj *so;
1608 
1609  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) )
1610  {
1611  shipp = &Ships[Objects[so->objnum].instance];
1612 
1613  // skip ourselves
1614  if ( shipp == Player_ship )
1615  continue;
1616 
1617  // check if ship is enemy ship (we attack it)
1618  if (!(iff_x_attacks_y(Player_ship->team, shipp->team)))
1619  continue;
1620 
1621  // check if ship is threatening
1623  continue;
1624 
1625  // check if ship is flyable
1626  if ( Ship_info[shipp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
1627  continue;
1628  }
1629 
1630  // check if ship is visible by player's team
1631  if ( hud_target_invalid_awacs(&Objects[so->objnum]) == 1 ) {
1632  continue;
1633  }
1634 
1635  return 1;
1636  }
1637 
1638  return 0;
1639 }
1640 
1641 // ----------------------------------------------------------------------
1642 // hostile_ships_to_arrive()
1643 //
1644 // Determine if there are any non-friendly ships yet to arrive
1645 //
1646 // NOTE: neutral ships are considered hostile for the purpose of event music
1647 //
1649 {
1650  p_object *p_objp;
1651 
1652  for (p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp))
1653  {
1654  // check if ship can arrive
1655  if (p_objp->flags & P_SF_CANNOT_ARRIVE)
1656  continue;
1657 
1658  // check if ship is enemy ship (we attack it)
1659  if (!(iff_x_attacks_y(Player_ship->team, p_objp->team)))
1660  continue;
1661 
1662  return 1;
1663  }
1664 
1665  return 0;
1666 }
1667 
1668 // ----------------------------------------------------------------
1669 // event_music_get_info()
1670 //
1671 // Return information about the event music in the buffer outbuf
1672 // NOTE: callers to this function are advised to allocate a 256 byte buffer
1673 void event_music_get_info(char *outbuf)
1674 {
1675  if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
1676  strcpy(outbuf,XSTR( "Event music is not playing", 213));
1677  }
1678  else {
1679  sprintf(outbuf,XSTR( "soundtrack: %s [%s]", 214), Soundtracks[Current_soundtrack_num].name, Pattern_info[Current_pattern].pattern_desc);
1680  }
1681 }
1682 
1683 // ----------------------------------------------------------------
1684 // event_music_next_soundtrack()
1685 //
1686 // input: delta => 1 or -1, depending if you want to go to next or previous song
1687 //
1688 // returns: New soundtrack number if successfully changed, otherwise return -1
1689 //
1691 {
1692  int new_soundtrack;
1693 
1694  if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1695  return -1;
1696  }
1697 
1698  new_soundtrack = Current_soundtrack_num + delta;
1699  if ( new_soundtrack >= Num_soundtracks )
1700  new_soundtrack = 0;
1701 
1703  event_music_level_init(new_soundtrack);
1704 
1705  return Current_soundtrack_num;
1706 }
1707 
1708 // Goober5000 - along the same lines; this is for the sexp
1710 {
1711  Assert(name);
1712 
1713  int i, new_soundtrack = -1;
1714 
1715  for (i = 0; i < Num_soundtracks; i++) {
1716  if ( !stricmp(name, Soundtracks[i].name) ) {
1717  new_soundtrack = i;
1718  }
1719  }
1720 
1721  // if we are already on this soundtrack then bail
1722  if (new_soundtrack == Current_soundtrack_num) {
1723  return;
1724  }
1725 
1727  Current_soundtrack_num = -1;
1728  event_music_level_init(new_soundtrack);
1729 }
1730 
1731 // ----------------------------------------------------------------
1732 // event_music_get_soundtrack_name()
1733 //
1734 // Return information about the event music in the buffer outbuf
1735 // NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
1737 {
1738  if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
1739  strcpy(outbuf, XSTR( "Event music is not playing", 213));
1740  }
1741  else {
1742  strcpy(outbuf, Soundtracks[Current_soundtrack_num].name);
1743  }
1744 }
1745 
1746 // set the current soundtrack based on name
1748 {
1750 
1751  if ( Current_soundtrack_num == -1 ) {
1752  mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
1753  }
1754 }
1755 
1757 {
1758  // find the correct index for the event music
1759  for ( int i = 0; i < Num_soundtracks; i++ ) {
1760  if ( !stricmp(name, Soundtracks[i].name) ) {
1761  return i;
1762  }
1763  }
1764 
1765  return -1;
1766 }
1767 
1769 {
1770  // find the correct index for the event music
1771  for ( int i = 0; i < Num_music_files; i++ ) {
1772  if ( !stricmp(name, Spooled_music[i].name) ) {
1773  return i;
1774  }
1775  }
1776 
1777  return -1;
1778 }
1779 
1781 {
1782  return event_music_get_spooled_music_index(name.c_str());
1783  }
1784 
1785 // set a score based on name
1786 void event_music_set_score(int score_index, char *name)
1787 {
1788  Assert(score_index < NUM_SCORES);
1789 
1790  // find the correct index for the event music
1791  Mission_music[score_index] = event_music_get_spooled_music_index(name);
1792 }
1793 
1794 // reset what sort of music is to be used for this mission
1796 {
1798  mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
1799  Mission_music[SCORE_BRIEFING] = -1;
1800  Mission_music[SCORE_FICTION_VIEWER] = -1;
1804 
1805  // Goober5000
1808 }
1809 
1811 {
1812  Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
1813 }
1814 
1815 #ifdef _MSC_VER
1816 #pragma optimize("", on)
1817 #endif
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
int timestamp(int delta_ms)
Definition: timer.cpp:226
int Pattern_timer_id
Definition: eventmusic.cpp:64
int i
Definition: multi_pxo.cpp:466
void audiostream_set_volume_all(float volume, int type)
Definition: audiostr.cpp:1857
#define NUM_SCORES
Definition: eventmusic.h:50
void event_music_unpause()
int team
Definition: ship.h:606
int Cmdline_freespace_no_music
Definition: cmdline.cpp:271
int snd_is_inited()
Definition: sound.cpp:1073
int check_for_string(const char *pstr)
Definition: parselo.cpp:517
int Game_mode
Definition: systemvars.cpp:24
int game_type
Definition: missionparse.h:138
int Mission_music[NUM_SCORES]
Definition: eventmusic.cpp:253
SNDPATTERN Patterns[MAX_PATTERNS]
Definition: eventmusic.cpp:54
int Current_soundtrack_num
Definition: eventmusic.cpp:59
void event_music_pause()
bool parse_soundtrack_line(int strack_idx, int pattern_idx)
const char * audio_ext_list[]
Definition: audiostr.cpp:49
int mission_goals_met()
#define ASF_EVENTMUSIC
Definition: audiostr.h:19
struct pattern_info pattern_info
int pattern_loop_for
Definition: eventmusic.cpp:90
void audiostream_close_all(int fade)
Definition: audiostr.cpp:1791
int Fred_running
Definition: fred.cpp:44
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
int Current_nrml
Definition: eventmusic.cpp:65
#define SONG_VICT_2
Definition: eventmusic.h:34
#define mprintf(args)
Definition: pstypes.h:238
void stuff_boolean_flag(int *i, int flag, bool a_to_eol)
Definition: parselo.cpp:2529
int event_music_next_soundtrack(int delta)
void event_music_enable()
void event_music_arrival(int team)
Definition: eventmusic.cpp:955
CButton * team
int Pattern_samples_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS]
Definition: eventmusic.cpp:83
#define TRUE
Definition: pstypes.h:399
#define Assertion(expr, msg,...)
Definition: clang.h:41
int Current_pattern
Definition: eventmusic.cpp:62
void event_music_get_info(char *outbuf)
#define SCORE_FICTION_VIEWER
Definition: eventmusic.h:55
uint flags
Definition: ship.h:644
#define SCORE_BRIEFING
Definition: eventmusic.h:51
void event_music_do_frame()
Definition: eventmusic.cpp:419
void event_music_start_default()
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
object * objp
Definition: lua.cpp:3105
#define SONG_NRML_2
Definition: eventmusic.h:23
SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS]
Definition: eventmusic.cpp:57
float num_measures
Definition: eventmusic.cpp:51
int required_string_either(char *str1, char *str2)
Checks for one of two required strings.
Definition: parselo.cpp:673
ship * shipp
Definition: lua.cpp:9162
#define MAX_SOUNDTRACKS
Definition: eventmusic.h:86
#define EMF_VALID
Definition: eventmusic.h:89
void event_music_set_score(int score_index, char *name)
void parse_menumusic()
int audiostream_is_inited()
Definition: audiostr.cpp:1938
int audiostream_is_playing(int i)
Definition: audiostr.cpp:1827
int New_pattern_order[]
Definition: eventmusic.cpp:119
int objnum
Definition: ship.h:1483
#define SCORE_DEBRIEF_FAIL
Definition: eventmusic.h:54
int Num_music_files
Definition: eventmusic.cpp:250
uint audiostream_get_samples_committed(int i)
Definition: audiostr.cpp:1912
void parse_soundtrack()
int instance
Definition: object.h:150
#define SCORE_DEBRIEF_AVERAGE
Definition: eventmusic.h:53
#define SONG_EARV_1
Definition: eventmusic.h:27
float Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS]
Definition: eventmusic.cpp:80
#define MAX_SPOOLED_MUSIC
Definition: eventmusic.h:69
float ship_max_hull_strength
Definition: ship.h:597
int default_next_pattern
Definition: eventmusic.cpp:43
void event_music_get_soundtrack_name(char *outbuf)
#define nprintf(args)
Definition: pstypes.h:239
void audiostream_stop(int i, int rewind, int paused)
Definition: audiostr.cpp:1840
int cf_exists_full(const char *filename, int dir_type)
Definition: cfile.cpp:527
int ship_subsys_disrupted(ship_subsys *ss)
Definition: ship.cpp:9033
char * filename
#define strnicmp(s1, s2, n)
Definition: config.h:272
#define ARRIVAL_INTERVAL_TIMESTAMP
Definition: eventmusic.cpp:71
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
float hull_strength
Definition: object.h:160
#define CF_TYPE_TABLES
Definition: cfile.h:50
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
void event_music_reset_choices()
void event_music_hostile_ship_destroyed()
const int NUM_AUDIO_EXT
Definition: audiostr.cpp:50
int required_string(const char *pstr)
Definition: parselo.cpp:468
#define P_SF_CANNOT_ARRIVE
Definition: missionparse.h:478
int event_music_player_death()
int optional_string(const char *pstr)
Definition: parselo.cpp:539
#define DEFAULT_MASTER_EVENT_MUSIC_VOLUME
Definition: eventmusic.cpp:32
void event_music_init()
Definition: eventmusic.cpp:261
Definition: ship.h:534
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
int skip_to_start_of_string_either(char *pstr1, char *pstr2, char *end)
Definition: parselo.cpp:433
pattern_info Pattern_info[]
Definition: eventmusic.cpp:95
#define delta
Definition: fvi.cpp:418
int idx
Definition: multiui.cpp:761
int Num_pattern_types
Definition: eventmusic.cpp:113
#define SF_DISABLED
Definition: ship.h:448
void event_sexp_change_soundtrack(char *name)
int iff_x_attacks_y(int team_x, int team_y)
Definition: iff_defs.cpp:605
int event_music_player_respawn_as_observer()
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
void event_music_set_soundtrack(char *name)
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
ship * Player_ship
Definition: ship.cpp:124
#define GM_IN_MISSION
Definition: systemvars.h:23
struct tagSNDPATTERN SNDPATTERN
#define NOX(s)
Definition: pstypes.h:473
#define SONG_AARV_2
Definition: eventmusic.h:26
int pattern_default_next_fs2
Definition: eventmusic.cpp:92
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
GLbitfield flags
Definition: Glext.h:6722
menu_music Spooled_music[MAX_SPOOLED_MUSIC]
Definition: eventmusic.cpp:249
void reset_parse(char *text)
Definition: parselo.cpp:3305
#define SONG_VICT_1
Definition: eventmusic.h:33
GLuint const GLchar * name
Definition: Glext.h:5608
int hostile_ships_present()
#define BATTLE_CHECK_INTERVAL
Definition: eventmusic.cpp:72
#define SONG_BTTL_1
Definition: eventmusic.h:29
#define MAX_PATH_LEN
Definition: pstypes.h:325
void event_music_force_switch()
Definition: eventmusic.cpp:383
#define SUBSYSTEM_ENGINE
Definition: model.h:53
#define MISSION_TYPE_TRAINING
Definition: missionparse.h:63
int event_music_player_respawn()
int samples_per_measure
Definition: eventmusic.cpp:50
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
char * pattern_name
Definition: eventmusic.cpp:87
#define MAX_PATTERNS
Definition: eventmusic.h:37
void audiostream_close_file(int i, int fade)
Definition: audiostr.cpp:1772
#define SF_DEPARTING
Definition: ship.h:475
void event_music_set_volume_all(float volume)
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
int Event_Music_battle_started
Definition: eventmusic.cpp:39
int event_music_cycle_pattern()
Definition: eventmusic.cpp:329
#define SONG_NRML_3
Definition: eventmusic.h:24
#define NAME_LENGTH
Definition: globals.h:15
#define fl2i(fl)
Definition: floating.h:33
int audiostream_is_paused(int i)
Definition: audiostr.cpp:1885
#define CF_TYPE_MUSIC
Definition: cfile.h:61
void event_music_parse_musictbl(const char *filename)
#define SONG_BTTL_3
Definition: eventmusic.h:31
int event_music_primary_goal_failed()
Definition: eventmusic.cpp:973
void event_music_level_init(int force_soundtrack)
Definition: eventmusic.cpp:543
int event_music_get_soundtrack_index(char *name)
#define SONG_DEAD_1
Definition: eventmusic.h:35
ship_obj Ship_obj_list
Definition: ship.cpp:162
void event_music_close()
Definition: eventmusic.cpp:320
int Pending_pattern
Definition: eventmusic.cpp:63
int ship_info_index
Definition: ship.h:539
char substitute_briefing_music_name[NAME_LENGTH]
Definition: missionparse.h:165
int event_music_friendly_arrival()
Definition: eventmusic.cpp:870
char pattern_fnames[MAX_PATTERNS][MAX_FILENAME_LEN]
Definition: eventmusic.h:83
#define F_NAME
Definition: parselo.h:34
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
float Master_event_music_volume
Definition: eventmusic.cpp:40
#define timestamp_elapsed(stamp)
Definition: timer.h:102
void audiostream_play(int i, float volume, int looping)
Definition: audiostr.cpp:1803
int Num_soundtracks
Definition: eventmusic.cpp:58
int pattern_can_force
Definition: eventmusic.cpp:89
#define SIF_NOT_FLYABLE
Definition: ship.h:946
void event_music_level_close()
Definition: eventmusic.cpp:691
GLint GLsizei count
Definition: Gl.h:1491
int parse_modular_table(const char *name_check, void(*parse_callback)(const char *filename), int path_type, int sort_type)
Definition: parselo.cpp:4205
p_object Ship_arrival_list
#define SCORE_DEBRIEF_SUCCESS
Definition: eventmusic.h:52
object * Player_obj
Definition: object.cpp:56
int pattern_default_next_fs1
Definition: eventmusic.cpp:91
void audiostream_set_sample_cutoff(int i, uint cutoff)
Definition: audiostr.cpp:1898
#define EMF_ALLIED_ARRIVAL_OVERLAY
Definition: eventmusic.h:90
#define SF_DYING
Definition: ship.h:447
int event_music_get_spooled_music_index(const char *name)
int temp
Definition: lua.cpp:4996
int audiostream_open(const char *filename, int type)
Definition: audiostr.cpp:1713
int event_music_return_current_pattern()
int event_music_enemy_arrival()
Definition: eventmusic.cpp:775
mission The_mission
#define SONG_NRML_1
Definition: eventmusic.h:22
#define SONG_EARV_2
Definition: eventmusic.h:28
int Num_goals
#define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC
Definition: eventmusic.cpp:34
int Event_music_enabled
Definition: eventmusic.cpp:237
void event_music_change_pattern(int new_pattern)
#define FALSE
Definition: pstypes.h:400
#define SONG_AARV_1
Definition: eventmusic.h:25
int event_music_primary_goals_met()
#define SONG_BTTL_2
Definition: eventmusic.h:30
float aav_music_volume
Definition: sound.cpp:79
#define stricmp(s1, s2)
Definition: config.h:271
char * pattern_desc
Definition: eventmusic.cpp:88
int skip_to_string(char *pstr, char *end)
Definition: parselo.cpp:375
void event_music_first_pattern()
Definition: eventmusic.cpp:648
int default_loop_for
Definition: eventmusic.cpp:45
void event_music_disable()
#define SONG_FAIL_1
Definition: eventmusic.h:32
int audiostream_done_reading(int i)
Definition: audiostr.cpp:1925
int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, const char **ext_list)
Definition: cfile.cpp:536
int event_music_battle_start()
Definition: eventmusic.cpp:732
int hud_target_invalid_awacs(object *objp)
Definition: hudtarget.cpp:460
#define EMF_CYCLE_FS1
Definition: eventmusic.h:91
char substitute_event_music_name[NAME_LENGTH]
Definition: missionparse.h:164
#define strcpy_s(...)
Definition: safe_strings.h:67
#define SMF_VALID
Definition: eventmusic.h:72
int hostile_ships_to_arrive()
#define F_LNAME
Definition: parselo.h:45