]> icculus.org git repositories - taylor/freespace2.git/blob - src/missionui/missioncmdbrief.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / missionui / missioncmdbrief.cpp
1 /*
2  * $Logfile: /Freespace2/code/MissionUI/MissionCmdBrief.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Mission Command Briefing Screen
8  *
9  * $Log$
10  * Revision 1.2  2002/05/07 03:16:46  theoddone33
11  * The Great Newline Fix
12  *
13  * Revision 1.1.1.1  2002/05/03 03:28:10  root
14  * Initial import.
15  *
16  * 
17  * 14    10/06/99 10:28a Jefff
18  * for OEM: cmd brief anim defaults to the default anim if load failure
19  * 
20  * 13    9/03/99 1:32a Dave
21  * CD checking by act. Added support to play 2 cutscenes in a row
22  * seamlessly. Fixed super low level cfile bug related to files in the
23  * root directory of a CD. Added cheat code to set campaign mission # in
24  * main hall.
25  * 
26  * 12    8/27/99 12:04a Dave
27  * Campaign loop screen.
28  * 
29  * 11    8/19/99 6:28p Jefff
30  * move animation in 640 a bit
31  * 
32  * 10    7/15/99 4:11p Andsager
33  * Leave command briefs in DEMO
34  * 
35  * 9     7/15/99 9:20a Andsager
36  * FS2_DEMO initial checkin
37  * 
38  * 8     7/09/99 10:32p Dave
39  * Command brief and red alert screens.
40  * 
41  * 7     2/08/99 5:06p Johnson
42  * Removed reference to a now non-existent palette.
43  * 
44  * 6     1/30/99 5:08p Dave
45  * More new hi-res stuff.Support for nice D3D textures.
46  * 
47  * 5     1/14/99 5:15p Neilk
48  * changed credits, command debrief interfaces to high resolution support
49  * 
50  * 4     10/16/98 9:40a Andsager
51  * Remove ".h" files from model.h
52  * 
53  * 3     10/13/98 9:28a Dave
54  * Started neatening up freespace.h. Many variables renamed and
55  * reorganized. Added AlphaColors.[h,cpp]
56  * 
57  * 2     10/07/98 10:53a Dave
58  * Initial checkin.
59  * 
60  * 1     10/07/98 10:49a Dave
61  * 
62  * 42    6/09/98 10:31a Hoffoss
63  * Created index numbers for all xstr() references.  Any new xstr() stuff
64  * added from here on out should be added to the end if the list.  The
65  * current list count can be found in FreeSpace.cpp (search for
66  * XSTR_SIZE).
67  * 
68  * 41    6/05/98 9:54a Lawrance
69  * OEM changes
70  * 
71  * 40    6/01/98 11:43a John
72  * JAS & MK:  Classified all strings for localization.
73  * 
74  * 39    5/26/98 11:10a Lawrance
75  * Fix bug where window controls get disabled when F1 pressed twice
76  * 
77  * 38    5/23/98 10:38p Lawrance
78  * Avoid doing a cfile refresh when running debug
79  * 
80  * 37    5/23/98 6:49p Lawrance
81  * Fix problems with refreshing the file list when a CD is inserted
82  * 
83  * 36    5/22/98 11:15a Lawrance
84  * Tweak how CD gets asked for
85  * 
86  * 35    5/21/98 6:57p Lawrance
87  * Only ask for the CD once
88  * 
89  * 34    5/20/98 9:46p John
90  * added code so the places in code that change half the palette don't
91  * have to clear the screen.
92  * 
93  * 33    5/20/98 6:41p Lawrance
94  * Add hook for command brief stage changes
95  * 
96  * 32    5/18/98 5:59p Hoffoss
97  * Made command briefing advanced now once the speech stops and animation
98  * has fully played once, whichever is longer.
99  * 
100  * 31    5/14/98 3:34p Hoffoss
101  * Made command brief screen wait until animation finishes before
102  * auto-advancing to the next state (in addition to the wait that was
103  * already implemented).
104  * 
105  * 30    5/08/98 5:32p Lawrance
106  * prompt for CD if can't load animations or voice
107  * 
108  * 29    5/06/98 11:49p Lawrance
109  * Add help overlay for command brief
110  * 
111  * 28    5/05/98 2:44p Hoffoss
112  * Fixed bug where not having a valid command brief ani would crash the
113  * cmd brief screen.
114  * 
115  * 27    4/28/98 4:16p Hoffoss
116  * Implemented auto-advancing functionality to command briefings.
117  * 
118  * 26    4/27/98 11:01a Hoffoss
119  * Changed code to utilize proper palette.
120  * 
121  * 25    4/26/98 5:11p Hoffoss
122  * Fixed bug where going to options screen and then returning to the cmd
123  * brief screen didn't start ani back up.
124  * 
125  * 24    4/13/98 11:00a Hoffoss
126  * Made the ani in a cmd brief continue playing if it's the same as the
127  * new stage.
128  * 
129  * 23    4/06/98 8:37p Hoffoss
130  * Fixed a few bugs with command brief screen.  Now the voice starts after
131  * the text has printed, and options screen doesn't reset cmd brief.
132  * 
133  * 22    4/06/98 11:24a Lawrance
134  * stop command brief music if returning to main menu
135  * 
136  * 21    4/02/98 11:40a Lawrance
137  * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
138  * 
139  * 20    3/31/98 5:18p John
140  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
141  * bunch of debug stuff out of player file.  Made model code be able to
142  * unload models and malloc out only however many models are needed.
143  *  
144  * 
145  * 19    3/31/98 12:00p Hoffoss
146  * Fixed bug with setting palette using <default> as filename.
147  * 
148  * 18    3/30/98 3:22p Hoffoss
149  * Changed Command Brief screen to merge current ani's palette with
150  * interface palette for better overall color.
151  * 
152  * 17    3/30/98 12:18a Lawrance
153  * change some DEMO_RELEASE code to not compile code rather than return
154  * early
155  * 
156  * 16    3/29/98 12:55a Lawrance
157  * Get demo build working with limited set of data.
158  * 
159  * 15    3/27/98 9:49a Lawrance
160  * AL: Ensure anim stops playing when leaving the command brief
161  * 
162  * 14    3/26/98 5:24p Hoffoss
163  * Changed Command Brief to use memory mapped ani files instead, so we
164  * avoid the huge pauses for huge anis that play!
165  * 
166  * 13    3/24/98 8:52a Jasen
167  * Updated coords for new button.
168  * 
169  * 12    3/23/98 4:21p Hoffoss
170  * Fixed bug where command brief screen couldn't be re-entered unless
171  * mission was reloaded.
172  * 
173  * 11    3/19/98 5:59p Hoffoss
174  * Added reset to cmd brief shutdown.
175  * 
176  * 10    3/19/98 5:32p Lawrance
177  * Added music to the background of command brief screen.
178  * 
179  * 9     3/19/98 4:25p Hoffoss
180  * Added remaining support for command brief screen (ANI and WAVE file
181  * playing).
182  * 
183  * 8     3/18/98 12:03p John
184  * Marked all the new strings as externalized or not.
185  * 
186  * 7     3/17/98 6:24p Hoffoss
187  * Added ani playing to command brief screen, which defaults to
188  * CB_default.ani.
189  * 
190  * 6     3/13/98 6:12p Frank
191  * AL: Fix bug caused by conflict with command brief and red alert
192  * missions
193  * 
194  * 5     3/13/98 3:44p Hoffoss
195  * Added stage indication to Mission Command Briefing screen.
196  * 
197  * 4     3/12/98 4:02p Hoffoss
198  * Added commit sound
199  * 
200  * 3     3/05/98 9:38p Hoffoss
201  * Finished up command brief screen.
202  * 
203  * 2     3/05/98 3:59p Hoffoss
204  * Added a bunch of new command brief stuff, and asteroid initialization
205  * to Fred.
206  * 
207  * 1     3/02/98 6:13p Hoffoss
208  *
209  * $NoKeywords: $
210  */
211
212 #include "ui.h"
213 #include "uidefs.h"
214 #include "gamesnd.h"
215 #include "gamesequence.h"
216 #include "missionscreencommon.h"
217 #include "key.h"
218 #include "bmpman.h"
219 #include "font.h"
220 #include "missionbriefcommon.h"
221 #include "missioncmdbrief.h"
222 #include "redalert.h"
223 #include "audiostr.h"
224 #include "timer.h"
225 #include "eventmusic.h"
226 #include "player.h"
227 #include "contexthelp.h"
228 #include "alphacolors.h"
229 #include "animplay.h"
230
231 char *Cmd_brief_fname[GR_NUM_RESOLUTIONS] = {
232         "CommandBrief",
233         "2_CommandBrief"
234 };
235
236 char *Cmd_brief_mask[GR_NUM_RESOLUTIONS] = {
237         "CommandBrief-m",
238         "2_Commandbrief-m"
239 };
240
241 // lookups for coordinates
242 #define CMD_X_COORD 0
243 #define CMD_Y_COORD 1
244 #define CMD_W_COORD 2
245 #define CMD_H_COORD 3
246
247 int Cmd_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
248         {
249                 17, 109, 606, 108                       // GR_640
250         },
251         {
252                 28, 174, 969, 174                       // GR_1024
253         }
254 };
255
256
257 int Cmd_stage_y[GR_NUM_RESOLUTIONS] = {
258         90,             // GR_640
259         145             // GR_1024
260 };
261
262 int Cmd_image_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
263         {
264                 26, 258, 441, 204                               // GR_640
265         },
266         {
267                 155, 475, 706, 327              // GR_1024
268         }
269 };
270
271 #define NUM_BUTTONS     8
272
273 #define FIRST_STAGE_BUTTON      0
274 #define PREV_STAGE_BUTTON       1
275 #define PAUSE_BUTTON                    2
276 #define NEXT_STAGE_BUTTON       3
277 #define LAST_STAGE_BUTTON       4
278 #define HELP_BUTTON                     5
279 #define OPTIONS_BUTTON          6
280 #define ACCEPT_BUTTON           7
281
282 // buttons
283 ui_button_info Cmd_brief_buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
284         { // GR_640
285                 ui_button_info("CBB_00",        504,    221,    -1,     -1,     0),
286                 ui_button_info("CBB_01",        527,    221,    -1,     -1,     1),
287                 ui_button_info("CBB_02",        555,    221,    -1,     -1,     2),
288                 ui_button_info("CBB_03",        583,    221,    -1,     -1,     3),
289                 ui_button_info("CBB_04",        607,    221,    -1,     -1,     4),
290                 ui_button_info("CBB_05",        539,    431,    -1,     -1,     5),
291                 ui_button_info("CBB_06",        538,    455,    -1,     -1,     6),
292                 ui_button_info("CBB_07",        575,    432,    -1,     -1,     7),
293         },
294         { // GR_1024
295                 ui_button_info("2_CBB_00",      806,    354,    -1,     -1,     0),
296                 ui_button_info("2_CBB_01",      844,    354,    -1,     -1,     1),
297                 ui_button_info("2_CBB_02",      888,    354,    -1,     -1,     2),
298                 ui_button_info("2_CBB_03",      933,    354,    -1,     -1,     3),
299                 ui_button_info("2_CBB_04",      971,    354,    -1,     -1,     4),
300                 ui_button_info("2_CBB_05",      863,    690,    -1,     -1,     5),
301                 ui_button_info("2_CBB_06",      861,    728,    -1,     -1,     6),
302                 ui_button_info("2_CBB_07",      920,    692,    -1,     -1,     7),
303         }
304 };
305
306 // text
307 #define CMD_BRIEF_NUM_TEXT              3
308 UI_XSTR Cmd_brief_text[GR_NUM_RESOLUTIONS][CMD_BRIEF_NUM_TEXT] = {
309         { // GR_640
310                 { "Help",               928,    500,    440,    UI_XSTR_COLOR_GREEN,    -1,     &Cmd_brief_buttons[0][HELP_BUTTON].button },
311                 { "Options",    1036,   479,    464,    UI_XSTR_COLOR_GREEN,    -1,     &Cmd_brief_buttons[0][OPTIONS_BUTTON].button },
312                 { "Continue",   1069,   564,    413,    UI_XSTR_COLOR_PINK,     -1,     &Cmd_brief_buttons[0][ACCEPT_BUTTON].button },
313         },
314         { // GR_1024
315                 { "Help",               928,    800,    704,    UI_XSTR_COLOR_GREEN,    -1,     &Cmd_brief_buttons[1][HELP_BUTTON].button },
316                 { "Options",    1036,   797,    743,    UI_XSTR_COLOR_GREEN,    -1,     &Cmd_brief_buttons[1][OPTIONS_BUTTON].button },
317                 { "Continue",   1069,   917,    661,    UI_XSTR_COLOR_PINK,     -1,     &Cmd_brief_buttons[1][ACCEPT_BUTTON].button },
318         }
319 };
320
321 static UI_WINDOW Ui_window;
322 static int Background_bitmap;                                   // bitmap for the background of the cmd_briefing
323 static int Cur_stage;
324 static int Scroll_offset;
325 static int Cmd_brief_inited = 0;
326 // static int Cmd_brief_ask_for_cd;
327 static int Voice_good_to_go = 0;
328 static int Voice_started_time = 0;
329 static int Voice_ended_time;
330 static int Anim_playing_id = -1;
331 static anim_instance *Cur_anim_instance = NULL;
332 static int Last_anim_frame_num;
333
334 static int Cmd_brief_last_voice;
335 static int Palette_bmp = -1;
336 static ubyte Palette[768];
337 static char Palette_name[128];
338
339 void cmd_brief_init_voice()
340 {
341         int i;
342
343         Assert(Cur_cmd_brief);
344         for (i=0; i<Cur_cmd_brief->num_stages; i++) {
345                 Cur_cmd_brief->stage[i].wave = -1;
346                 if (stricmp(Cur_cmd_brief->stage[i].wave_filename, NOX("none")) && Cur_cmd_brief->stage[i].wave_filename[0]) {
347                         Cur_cmd_brief->stage[i].wave = audiostream_open(Cur_cmd_brief->stage[i].wave_filename, ASF_VOICE);
348                         if (Cur_cmd_brief->stage[i].wave < 0) {
349                                 nprintf(("General", "Failed to load \"%s\"", Cur_cmd_brief->stage[i].wave_filename));
350                         }
351                 }
352         }
353
354         Cmd_brief_last_voice = -1;
355 }
356
357 int cmd_brief_check_stage_done()
358 {
359         if (!Voice_good_to_go)
360                 return 0;
361
362         if (Voice_ended_time && (timer_get_milliseconds() - Voice_ended_time >= 1000))
363                 return 1;
364
365         if (Briefing_voice_enabled && (Cmd_brief_last_voice >= 0)) {
366                 if (audiostream_is_playing(Cmd_brief_last_voice)){
367                         return 0;
368                 }
369
370                 if (!Voice_ended_time){
371                         Voice_ended_time = timer_get_milliseconds();
372                 }
373
374                 return 0;
375         }
376
377         // if we get here, there is no voice, so we simulate the time it would take instead
378         if (!Voice_ended_time)
379                 Voice_ended_time = Voice_started_time + max(5000, Num_brief_text_lines[0] * 3500);
380
381         return 0;
382 }
383
384 // start playback of the voice for a particular briefing stage
385 void cmd_brief_voice_play(int stage_num)
386 {
387         int voice = -1;
388
389         if (!Voice_good_to_go) {
390                 Voice_started_time = 0;
391                 return;
392         }
393
394         if (!Voice_started_time) {
395                 Voice_started_time = timer_get_milliseconds();
396                 Voice_ended_time = 0;
397         }
398
399         if (!Briefing_voice_enabled){
400                 return;
401         }
402
403         if (Cur_stage >= 0 && Cur_stage < Cur_cmd_brief->num_stages){
404                 voice = Cur_cmd_brief->stage[stage_num].wave;
405         }
406
407         // are we still on same voice that is currently playing/played?
408         if (Cmd_brief_last_voice == voice){
409                 return;  // no changes, nothing to do.
410         }
411
412         // if previous wave is still playing, stop it first.
413         if (Cmd_brief_last_voice >= 0) {
414                 audiostream_stop(Cmd_brief_last_voice);  // stream is automatically rewound
415                 Cmd_brief_last_voice = -1;
416         }
417
418         // ok, new wave needs playing, so we can start playing it now (and it becomes the current wave)
419         Cmd_brief_last_voice = voice;
420         if (voice >= 0){
421                 audiostream_play(voice, Master_voice_volume, 0);
422         }
423 }
424
425 // called to leave the command briefing screen
426 void cmd_brief_exit()
427 {
428         gameseq_post_event(GS_EVENT_START_BRIEFING);
429 }
430
431 void cmd_brief_stop_anim(int id)
432 {
433         if (Cur_anim_instance && (id != Anim_playing_id)) {
434                 anim_stop_playing(Cur_anim_instance);
435                 Cur_anim_instance = NULL;
436         }
437
438         Voice_good_to_go = 0;
439         if (Cmd_brief_last_voice >= 0) {
440                 audiostream_stop(Cmd_brief_last_voice);  // stream is automatically rewound
441                 Cmd_brief_last_voice = -1;
442         }
443 }
444
445 void cmd_brief_new_stage(int stage)
446 {
447         int i;
448         anim_play_struct aps;
449
450         if (stage < 0) {
451                 cmd_brief_stop_anim(-1);
452                 Cur_stage = -1;
453                 Anim_playing_id = -1;
454         }
455
456         Cur_stage = stage;
457         brief_color_text_init(Cur_cmd_brief->stage[stage].text, Cmd_text_wnd_coords[gr_screen.res][CMD_W_COORD]);
458
459         i = Cur_cmd_brief->stage[Cur_stage].anim_ref;
460         if (i < 0)
461                 i = Cur_stage;
462
463         cmd_brief_stop_anim(i);
464
465         if (i != Anim_playing_id) {
466                 if (Cur_cmd_brief->stage[i].anim) {
467                         anim_play_init(&aps, Cur_cmd_brief->stage[i].anim,Cmd_image_wnd_coords[gr_screen.res][CMD_X_COORD], Cmd_image_wnd_coords[gr_screen.res][CMD_Y_COORD]);
468                         aps.looped = 1;
469                         Cur_anim_instance = anim_play(&aps);
470                         Last_anim_frame_num = 0;
471                 }
472
473                 Anim_playing_id = i;
474         }
475
476         if (Cur_cmd_brief->stage[i].anim) {
477                 memcpy(Palette, Cur_cmd_brief->stage[i].anim->palette, 384);
478                 gr_set_palette(Cur_cmd_brief->stage[i].ani_filename, Palette, 1);
479         }
480 }
481
482 void cmd_brief_hold()
483 {
484         cmd_brief_stop_anim(-1);
485         Anim_playing_id = -1;
486 }
487
488 void cmd_brief_unhold()
489 {
490         cmd_brief_new_stage(Cur_stage);
491 }
492
493 void cmd_brief_button_pressed(int n)
494 {
495         switch (n) {
496                 case HELP_BUTTON:
497                         launch_context_help();
498                         gamesnd_play_iface(SND_HELP_PRESSED);
499                         break;
500
501                 case OPTIONS_BUTTON:
502                         gamesnd_play_iface(SND_SWITCH_SCREENS);
503                         gameseq_post_event(GS_EVENT_OPTIONS_MENU);
504                         break;
505
506                 case FIRST_STAGE_BUTTON:
507                         if (Cur_stage) {
508                                 cmd_brief_new_stage(0);
509                                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
510                         } else {
511                                 gamesnd_play_iface(SND_GENERAL_FAIL);
512                         }
513
514                         break;
515
516                 case PREV_STAGE_BUTTON:
517                         if (Cur_stage) {
518                                 cmd_brief_new_stage(Cur_stage - 1);
519                                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
520                         } else {
521                                 gamesnd_play_iface(SND_GENERAL_FAIL);
522                         }
523
524                         break;
525
526                 case NEXT_STAGE_BUTTON:
527                         if (Cur_stage < Cur_cmd_brief->num_stages - 1) {
528                                 cmd_brief_new_stage(Cur_stage + 1);
529                                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
530                         } else {
531                                 gamesnd_play_iface(SND_GENERAL_FAIL);
532                         }
533
534                         break;
535
536                 case LAST_STAGE_BUTTON:
537                         if (Cur_stage < Cur_cmd_brief->num_stages - 1) {
538                                 cmd_brief_new_stage(Cur_cmd_brief->num_stages - 1);
539                                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
540                         } else {
541                                 gamesnd_play_iface(SND_GENERAL_FAIL);
542                         }
543                         break;
544
545                 case ACCEPT_BUTTON:
546                         cmd_brief_exit();
547                         gamesnd_play_iface(SND_COMMIT_PRESSED);
548                         break;
549
550                 case PAUSE_BUTTON:
551                         gamesnd_play_iface(SND_USER_SELECT);
552                         Player->auto_advance ^= 1;
553                         break;
554         }
555 }
556
557 void cmd_brief_ani_wave_init(int index)
558 {
559         char *name;
560         int i;
561
562         // first, search and see if anim is already used in another stage
563         for (i=0; i<index; i++) {
564                 if (!stricmp(Cur_cmd_brief->stage[i].ani_filename, Cur_cmd_brief->stage[index].ani_filename)) {
565                         if (Cur_cmd_brief->stage[i].anim_ref >= 0)
566                                 Cur_cmd_brief->stage[index].anim_ref = Cur_cmd_brief->stage[i].anim_ref;
567                         else
568                                 Cur_cmd_brief->stage[index].anim_ref = i;
569
570                         return;
571                 }
572         }
573
574         // this is the first instance of the given anim filename
575         Cur_cmd_brief->stage[index].anim_ref = -1;
576         name = Cur_cmd_brief->stage[index].ani_filename;
577         if (!name[0] || !stricmp(name, NOX("<default>")) || !stricmp(name, NOX("none.ani"))) {
578                 name = NOX("CB_default");
579                 strcpy(Cur_cmd_brief->stage[index].ani_filename, name);
580         }
581
582         int load_attempts = 0;
583         while (1) {
584
585                 if ( load_attempts++ > 5 ) {
586                         break;
587                 }
588
589                 Cur_cmd_brief->stage[index].anim = anim_load(name, 1);
590                 if ( Cur_cmd_brief->stage[index].anim ) {
591                         break;
592                 }
593
594                 // couldn't load animation, ask user to insert CD (if necessary)
595                 // if ( Cmd_brief_ask_for_cd ) {
596                         // if ( game_do_cd_check() == 0 ) {
597                                 // Cmd_brief_ask_for_cd = 0;
598                                 // break;
599                         // }
600                 // }
601         }
602
603         // check to see if cb anim loaded, if not, try the default one
604         if ( !Cur_cmd_brief->stage[index].anim ) {
605                 Cur_cmd_brief->stage[index].anim = anim_load(NOX("CB_default"), 1);
606         }
607 }
608
609 void cmd_brief_init(int team)
610 {
611         common_music_init(SCORE_BRIEFING);
612
613 //#ifndef FS2_DEMO
614
615         int i;
616         ui_button_info *b;
617
618         Cmd_brief_inited = 0;
619         Cur_cmd_brief = &Cmd_briefs[team];
620
621         if ( red_alert_mission() ) {
622                 gameseq_post_event(GS_EVENT_RED_ALERT);
623                 return;
624         }
625
626         if (Cur_cmd_brief->num_stages <= 0)
627                 return;
628
629         gr_reset_clip();
630         gr_clear();
631         Mouse_hidden++;
632         gr_flip();
633         Mouse_hidden--;
634
635         /*
636         Palette_bmp = bm_load("BarracksPalette");       //CommandBriefPalette");
637         Assert(Palette_bmp);
638         bm_get_palette(Palette_bmp, Palette, Palette_name);  // get the palette for this bitmap
639         gr_set_palette(Palette_name, Palette, 1);
640         */
641
642         Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
643         Ui_window.set_mask_bmap(Cmd_brief_mask[gr_screen.res]);
644
645         // Cmd_brief_ask_for_cd = 1;
646
647         for (i=0; i<NUM_BUTTONS; i++) {
648                 b = &Cmd_brief_buttons[gr_screen.res][i];
649
650                 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, 0, 1);
651                 // set up callback for when a mouse first goes over a button
652                 b->button.set_highlight_action(common_play_highlight_sound);
653                 b->button.set_bmaps(b->filename);
654                 b->button.link_hotspot(b->hotspot);
655         }
656
657         // add text
658         for(i=0; i<CMD_BRIEF_NUM_TEXT; i++){
659                 Ui_window.add_XSTR(&Cmd_brief_text[gr_screen.res][i]);
660         }
661
662         // set up readyrooms for buttons so we draw the correct animation frame when a key is pressed
663         Cmd_brief_buttons[gr_screen.res][FIRST_STAGE_BUTTON].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
664         Cmd_brief_buttons[gr_screen.res][LAST_STAGE_BUTTON].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
665         Cmd_brief_buttons[gr_screen.res][PREV_STAGE_BUTTON].button.set_hotkey(KEY_LEFT);
666         Cmd_brief_buttons[gr_screen.res][NEXT_STAGE_BUTTON].button.set_hotkey(KEY_RIGHT);
667         Cmd_brief_buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
668         Cmd_brief_buttons[gr_screen.res][HELP_BUTTON].button.set_hotkey(KEY_F1);
669         Cmd_brief_buttons[gr_screen.res][OPTIONS_BUTTON].button.set_hotkey(KEY_F2);
670
671         // load in help overlay bitmap  
672         help_overlay_load(CMD_BRIEF_OVERLAY);
673         help_overlay_set_state(CMD_BRIEF_OVERLAY,0);
674
675         Background_bitmap = bm_load(Cmd_brief_fname[gr_screen.res]);
676
677         for (i=0; i<Cur_cmd_brief->num_stages; i++)
678                 cmd_brief_ani_wave_init(i);
679
680         cmd_brief_init_voice();
681         Scroll_offset = 0;
682         Cur_anim_instance = NULL;
683         cmd_brief_new_stage(0);
684         Cmd_brief_inited = 1;
685
686 //#endif
687 }
688
689 void cmd_brief_close()
690 {
691         int i;
692
693         if (Cmd_brief_inited) {
694                 cmd_brief_stop_anim(-1);
695                 Anim_playing_id = -1;
696                 for (i=0; i<Cur_cmd_brief->num_stages; i++) {
697                         if (Cur_cmd_brief->stage[i].wave >= 0)
698                                 audiostream_close_file(Cur_cmd_brief->stage[i].wave, 0);
699
700                         if (Cur_cmd_brief->stage[i].anim_ref < 0)
701                                 if (Cur_cmd_brief->stage[i].anim)
702                                         anim_free(Cur_cmd_brief->stage[i].anim);
703                 }
704
705                 if (Background_bitmap >= 0)
706                         bm_unload(Background_bitmap);
707
708                 // unload the overlay bitmap
709                 help_overlay_unload(CMD_BRIEF_OVERLAY);
710
711                 Ui_window.destroy();
712                 /*
713                 if (Palette_bmp){
714                         bm_unload(Palette_bmp);
715                 }
716                 */
717
718                 game_flush();
719                 Cmd_brief_inited = 0;
720         }
721 }
722
723 void cmd_brief_do_frame(float frametime)
724 {
725         char buf[40];
726         int i, k, w;            
727
728         // if no command briefing exists, skip this screen.
729         if (!Cmd_brief_inited) {
730                 cmd_brief_exit();
731                 return;
732         }
733
734         if ( help_overlay_active(CMD_BRIEF_OVERLAY) ) {
735                 Cmd_brief_buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
736                 Ui_window.set_ignore_gadgets(1);
737         }
738
739         k = Ui_window.process() & ~KEY_DEBUGGED;
740
741         if ( (k > 0) || B1_JUST_RELEASED ) {
742                 if ( help_overlay_active(CMD_BRIEF_OVERLAY) ) {
743                         help_overlay_set_state(CMD_BRIEF_OVERLAY, 0);
744                         Ui_window.set_ignore_gadgets(0);
745                         k = 0;
746                 }
747         }
748
749         if ( !help_overlay_active(CMD_BRIEF_OVERLAY) ) {
750                 Ui_window.set_ignore_gadgets(0);
751         }
752
753         switch (k) {
754         case KEY_ESC:
755                 common_music_close();
756                 gameseq_post_event(GS_EVENT_MAIN_MENU);
757                 break;
758         }       // end switch
759
760         for (i=0; i<NUM_BUTTONS; i++){
761                 if (Cmd_brief_buttons[gr_screen.res][i].button.pressed()){
762                         cmd_brief_button_pressed(i);
763                 }
764         }
765
766         cmd_brief_voice_play(Cur_stage);
767         common_music_do();
768
769         if (cmd_brief_check_stage_done() && Player->auto_advance && (Cur_stage < Cur_cmd_brief->num_stages - 1)){
770 //              if (!Cur_anim_instance || (Cur_anim_instance->frame_num < Last_anim_frame_num))
771                 if (!Cur_anim_instance || Cur_anim_instance->loop_count){
772                         cmd_brief_new_stage(Cur_stage + 1);
773                 }
774         }
775
776         if (Cur_anim_instance){
777                 Last_anim_frame_num = Cur_anim_instance->frame_num;
778         }
779
780         GR_MAYBE_CLEAR_RES(Background_bitmap);
781         if (Background_bitmap >= 0) {
782                 gr_set_bitmap(Background_bitmap);
783                 gr_bitmap(0, 0);
784         } 
785
786         {
787                 // JAS: This code is hacked to allow the animation to use all 256 colors
788                 extern int Palman_allow_any_color;
789                 Palman_allow_any_color = 1;
790                 anim_render_all(0, frametime);
791                 Palman_allow_any_color = 0;
792         }
793         Ui_window.draw();
794
795         if (!Player->auto_advance){
796                 Cmd_brief_buttons[gr_screen.res][PAUSE_BUTTON].button.draw_forced(2);
797         }
798
799         gr_set_font(FONT1);
800         gr_set_color_fast(&Color_text_heading);
801
802         sprintf(buf, XSTR( "Stage %d of %d", 464), Cur_stage + 1, Cur_cmd_brief->num_stages);
803         gr_get_string_size(&w, NULL, buf);
804         gr_string(Cmd_text_wnd_coords[gr_screen.res][CMD_X_COORD] + Cmd_text_wnd_coords[gr_screen.res][CMD_W_COORD] - w, Cmd_stage_y[gr_screen.res], buf);
805
806         if (brief_render_text(Scroll_offset, Cmd_text_wnd_coords[gr_screen.res][CMD_X_COORD], Cmd_text_wnd_coords[gr_screen.res][CMD_Y_COORD], Cmd_text_wnd_coords[gr_screen.res][CMD_H_COORD], frametime, 0, 1)){
807                 Voice_good_to_go = 1;
808         }
809
810         // blit help overlay if active
811         help_overlay_maybe_blit(CMD_BRIEF_OVERLAY);
812
813         gr_flip();
814 }
815