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