]> icculus.org git repositories - taylor/freespace2.git/blob - src/cutscene/cutscenes.cpp
GCC 3.4 fixes.
[taylor/freespace2.git] / src / cutscene / cutscenes.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Cutscene/Cutscenes.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code for the cutscenes viewer screen
16  *
17  * $Log$
18  * Revision 1.9  2004/09/20 01:31:44  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.8  2003/06/11 18:30:32  taylor
22  * plug memory leaks
23  *
24  * Revision 1.7  2003/05/25 02:30:42  taylor
25  * Freespace 1 support
26  *
27  * Revision 1.6  2002/07/24 00:20:41  relnev
28  * nothing interesting
29  *
30  * Revision 1.5  2002/06/09 04:41:15  relnev
31  * added copyright header
32  *
33  * Revision 1.4  2002/06/02 04:26:34  relnev
34  * warning cleanup
35  *
36  * Revision 1.3  2002/05/26 22:06:17  relnev
37  * makefile: disable stand_gui for now.
38  *
39  * rest: staticize some globals
40  *
41  * Revision 1.2  2002/05/07 03:16:43  theoddone33
42  * The Great Newline Fix
43  *
44  * Revision 1.1.1.1  2002/05/03 03:28:08  root
45  * Initial import.
46  *
47  * 
48  * 15    6/16/00 3:15p Jefff
49  * sim of the year dvd version changes, a few german soty localization
50  * fixes
51  * 
52  * 14    10/13/99 10:20a Jefff
53  * fixed bug where intro cutscene showed 2x after getting bad ending
54  * 
55  * 13    10/06/99 10:30a Jefff
56  * OEM updates
57  * 
58  * 12    9/30/99 6:01p Jefff
59  * OEM updates
60  * 
61  * 11    9/07/99 1:10p Mikek
62  * Make movie check not hang in ~RELEASE_REAL build.
63  * 
64  * 10    9/06/99 6:38p Dave
65  * Improved CD detection code.
66  * 
67  * 9     9/06/99 1:16a Dave
68  * Make sure the user sees the intro movie.
69  * 
70  * 8     9/03/99 1:31a Dave
71  * CD checking by act. Added support to play 2 cutscenes in a row
72  * seamlessly. Fixed super low level cfile bug related to files in the
73  * root directory of a CD. Added cheat code to set campaign mission # in
74  * main hall.
75  * 
76  * 7     7/19/99 2:13p Dave
77  * Added some new strings for Heiko.
78  * 
79  * 6     6/01/99 3:52p Dave
80  * View footage screen. Fixed xstrings to not display the & symbol. Popup,
81  * dead popup, pxo find player popup, pxo private room popup.
82  * 
83  * 5     1/30/99 5:08p Dave
84  * More new hi-res stuff.Support for nice D3D textures.
85  * 
86  * 4     10/23/98 3:51p Dave
87  * Full support for tstrings.tbl and foreign languages. All that remains
88  * is to make it active in Fred.
89  * 
90  * 3     10/13/98 9:28a Dave
91  * Started neatening up freespace.h. Many variables renamed and
92  * reorganized. Added AlphaColors.[h,cpp]
93  * 
94  * 2     10/07/98 10:52a Dave
95  * Initial checkin.
96  * 
97  * 1     10/07/98 10:48a Dave
98  * 
99  * 18    6/09/98 10:31a Hoffoss
100  * Created index numbers for all xstr() references.  Any new xstr() stuff
101  * added from here on out should be added to the end if the list.  The
102  * current list count can be found in FreeSpace.cpp (search for
103  * XSTR_SIZE).
104  * 
105  * 17    6/01/98 11:43a John
106  * JAS & MK:  Classified all strings for localization.
107  * 
108  * 16    5/24/98 9:01p Lawrance
109  * Add commit sounds when accept is pressed
110  * 
111  * 15    5/21/98 8:05p Allender
112  * fix possible bug with number of cutscenes shown in the list
113  * 
114  * 14    5/21/98 12:35a Lawrance
115  * Tweak how CD is checked for
116  * 
117  * 13    5/20/98 1:34p Hoffoss
118  * Added cutscene description rendering.
119  * 
120  * 12    5/19/98 12:19p Mike
121  * Cheat codes!
122  * 
123  * 11    5/12/98 4:17p Hoffoss
124  * Make ctrl-arrows (up/down) switch between tech room screens.
125  * 
126  * 10    5/11/98 8:04p Hoffoss
127  * Fixed minor bugs.
128  * 
129  * 9     5/10/98 10:05p Allender
130  * only show cutscenes which have been seen before.  Made Fred able to
131  * write missions anywhere, defaulting to player misison folder, not data
132  * mission folder.  Fix FreeSpace code to properly read missions from
133  * correct locations
134  * 
135  * 8     5/08/98 5:30p Lawrance
136  * add CD checks for movie playing
137  * 
138  * 7     5/08/98 4:07p Allender
139  * more cutscene stuff
140  * 
141  * 6     5/07/98 2:33p Hoffoss
142  * Removed help and options buttons.
143  * 
144  * 5     4/30/98 4:53p John
145  * Restructured and cleaned up cfile code.  Added capability to read off
146  * of CD-ROM drive and out of multiple pack files.
147  * 
148  * 4     4/23/98 8:27p Allender
149  * basic support for cutscene playback.  Into movie code in place.  Tech
150  * room can view cutscenes stored in CDROM_dir variable
151  * 
152  * 3     4/21/98 7:07p Hoffoss
153  * Fixed problem where when switching screens flashes old tab hilight once
154  * before switching to new state.
155  * 
156  * 2     4/17/98 6:33p Hoffoss
157  * Made changes to the tech room group of screens.  Cutscenes screen is
158  * now in a new file.
159  *
160  * $NoKeywords: $
161  */
162
163 #include "cutscenes.h"
164 #include "ui.h"
165 #include "cfile.h"
166 #include "gamesnd.h"
167 #include "gamesequence.h"
168 #include "freespace.h"
169 #include "key.h"
170 #include "bmpman.h"
171 #include "movie.h"
172 #include "popup.h"
173 #include "mainhallmenu.h"
174 #include "alphacolors.h"
175 #include "localize.h"
176
177 char *Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
178         "ViewFootage",
179         "2_ViewFootage"
180 };
181 char *Cutscene_mask_name[GR_NUM_RESOLUTIONS] = {
182         "ViewFootage-m",
183         "2_ViewFootage-m"
184 };
185
186 int Num_cutscenes;
187 int Cutscenes_viewable;
188 int Description_index;
189 cutscene_info Cutscenes[MAX_CUTSCENES];
190
191 extern int All_movies_enabled;          //      If set, all movies may be viewed.  Keyed off cheat code.
192
193 // initialization stuff for cutscenes
194 void cutscene_init()
195 {
196 #ifndef FS1_DEMO  // no cuscenes in FS1 demo
197         char buf[MULTITEXT_LENGTH];
198         int rval;
199
200         if ((rval = setjmp(parse_abort)) != 0) {
201                 Error(LOCATION, "Error parsing 'rank.tbl'\r\nError code = %i.\r\n", rval);
202         } 
203
204         // open localization
205         lcl_ext_open();
206
207         read_file_text("cutscenes.tbl");
208         reset_parse();
209
210         // parse in all the rank names
211         Num_cutscenes = 0;
212         skip_to_string("#Cutscenes");
213         ignore_white_space();
214         while ( required_string_either("#End", "$Filename:") ) {
215                 Assert ( Num_cutscenes < MAX_CUTSCENES );
216                 required_string("$Filename:");
217                 stuff_string( Cutscenes[Num_cutscenes].filename, F_PATHNAME, NULL );
218                 required_string("$Name:");
219                 stuff_string( Cutscenes[Num_cutscenes].name, F_NAME, NULL );
220                 required_string("$Description:");
221                 stuff_string(buf, F_MULTITEXT, NULL);
222                 drop_white_space(buf);
223                 compact_multitext_string(buf);
224                 Cutscenes[Num_cutscenes].description = strdup(buf);
225                 required_string("$cd:");
226                 stuff_int( &Cutscenes[Num_cutscenes].cd );
227
228                 Num_cutscenes++;
229         }
230
231         required_string("#End");
232
233         Cutscenes_viewable = INTRO_CUTSCENE_FLAG;
234
235         // close localization
236         lcl_ext_close();
237 #endif  // FS1_DEMO
238 }
239
240 // free up memory from table parsing
241 void cutscene_tbl_close()
242 {
243         int i;
244         
245         for (i=0; i<MAX_CUTSCENES; i++) {
246                 if (Cutscenes[i].description) {
247                         free(Cutscenes[i].description);
248                         Cutscenes[i].description = NULL;
249                 }
250         }
251 }
252
253 // function to return 0 based index of which CD a particular movie is on
254 // returns -1 on failure.
255 int cutscenes_get_cd_num( char *filename )
256 {
257 #if defined(OEM_BUILD)
258         return 0;                               // only 1 cd for OEM
259 #else
260         int i;
261
262         for (i = 0; i < Num_cutscenes; i++ ) {
263                 if ( !stricmp(Cutscenes[i].filename, filename) ) {
264                         return (Cutscenes[i].cd - 1);
265                 }
266         }
267
268         return -1;
269 #endif // defined(OEM_BUILD)
270 }
271
272 // marks a cutscene as viewable
273 void cutscene_mark_viewable(char *filename)
274 {
275         int i;
276
277         for (i = 0; i < Num_cutscenes; i++ ) {
278                 if ( !stricmp(Cutscenes[i].filename, filename) ) {
279                         Cutscenes_viewable |= (1<<i);
280                         return;
281                 }
282         }
283 }
284
285 #define NUM_BUTTONS                             8
286
287 #define TECH_DATABASE_BUTTON    0
288 #define SIMULATOR_BUTTON                1
289 #define CUTSCENES_BUTTON                2
290 #define CREDITS_BUTTON                  3
291
292 #define SCROLL_UP_BUTTON                4
293 #define SCROLL_DOWN_BUTTON              5
294 #define PLAY_BUTTON                             6
295 #define EXIT_BUTTON                             7
296
297 static int Num_files;
298 static int Cutscene_list[MAX_CUTSCENES];
299 static int Selected_line = 0;  // line that is currently selected for binding
300 static int Scroll_offset;
301 static int Background_bitmap;
302 static UI_BUTTON List_region;
303 static UI_WINDOW Ui_window;
304
305 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
306         { // GR_640
307 #ifdef MAKE_FS1
308                 ui_button_info("TDB_00",        0,              0,              -1,     -1,     0),             // technical database tab
309                 ui_button_info("TDB_01",        0,              19,             -1,     -1,     1),             // mission simulator tab
310                 ui_button_info("TDB_02",        0,              35,             -1,     -1,     2),             // cutscenes tab
311                 ui_button_info("TDB_03",        0,              56,             -1,     -1,     3),             // credits tab
312
313                 ui_button_info("VFB_04",        570,    304,    -1,     -1,     4),             // scroll up
314                 ui_button_info("VFB_05",        600,    304,    -1,     -1,     5),             // scroll down
315                 ui_button_info("VFB_06",        573,    347,    -1,     -1,     6),             // play
316                 ui_button_info("VFB_07",        566,    411,    -1,     -1,     7),             // exit
317 #else
318                 ui_button_info("TDB_00",        7,              5,              37,     7,              0),                     // tech database 1
319                 ui_button_info("TDB_01",        7,              19,     37,     23,     1),                     // tech database 2
320                 ui_button_info("TDB_02",        7,              34,     37,     38,     2),                     // tech database 3
321                 ui_button_info("TDB_03",        7,              49,     37,     54,     3),                     // tech database 4
322
323                 ui_button_info("VFB_04",        6,              318,    -1,     -1,     4),                     // scroll up
324                 ui_button_info("VFB_05",        36,     318,    -1,     -1,     5),                     // scroll down
325                 ui_button_info("VFB_06",        578,    319,    587,    366,    6),                     // play
326                 ui_button_info("VFB_07",        574,    431,    587,    413,    7),                     // exit
327 #endif
328         },
329         { // GR_1024
330                 ui_button_info("2_TDB_00",      12,     7,              59,     12,     0),                     // tech database 1
331                 ui_button_info("2_TDB_01",      12,     31,     59,     37,     1),                     // tech database 2
332                 ui_button_info("2_TDB_02",      12,     56,     59,     62,     2),                     // tech database 3
333                 ui_button_info("2_TDB_03",      12,     81,     59,     88,     3),                     // tech database 4
334
335                 ui_button_info("2_VFB_04",      9,              509,    -1,     -1,     4),                     // scroll up
336                 ui_button_info("2_VFB_05",      58,     509,    -1,     -1,     5),                     // scroll down
337                 ui_button_info("2_VFB_06",      925,    511,    940,    586,    6),                     // play
338                 ui_button_info("2_VFB_07",      918,    689,    940,    661,    7),                     // exit
339         }
340 };
341
342 // text
343 #ifdef MAKE_FS1
344         #define NUM_CUTSCENE_TEXT                       0
345 #else
346         #define NUM_CUTSCENE_TEXT                       6
347 #endif
348 UI_XSTR Cutscene_text[GR_NUM_RESOLUTIONS][NUM_CUTSCENE_TEXT] = {
349         { // GR_640
350                 // nothing needed for FS1
351 #ifndef MAKE_FS1
352                 {"Technical Database",          1055,           37,     7,              UI_XSTR_COLOR_GREEN, -1, &Buttons[0][TECH_DATABASE_BUTTON].button },
353                 {"Mission Simulator",           1056,           37,     23,     UI_XSTR_COLOR_GREEN, -1, &Buttons[0][SIMULATOR_BUTTON].button },
354                 {"Cutscenes",                                   1057,           37,     38,     UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CUTSCENES_BUTTON].button },
355                 {"Credits",                                             1058,           37,     54,     UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CREDITS_BUTTON].button },
356                 
357                 {"Play",                                                        1335,           587,    366,    UI_XSTR_COLOR_GREEN, -1, &Buttons[0][PLAY_BUTTON].button },
358                 {"Exit",                                                        1419,           587,    413,    UI_XSTR_COLOR_PINK, -1, &Buttons[0][EXIT_BUTTON].button },                      
359 #endif
360         },
361         { // GR_1024
362                 // nothing needed for FS1
363 #ifndef MAKE_FS1
364                 {"Technical Database",          1055,           59,     12,     UI_XSTR_COLOR_GREEN, -1, &Buttons[1][TECH_DATABASE_BUTTON].button },
365                 {"Mission Simulator",           1056,           59,     37,     UI_XSTR_COLOR_GREEN, -1, &Buttons[1][SIMULATOR_BUTTON].button },
366                 {"Cutscenes",                                   1057,           59,     62,     UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CUTSCENES_BUTTON].button },
367                 {"Credits",                                             1058,           59,     88,     UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CREDITS_BUTTON].button },
368                 
369                 {"Play",                                                        1335,           940,    586,    UI_XSTR_COLOR_GREEN, -1, &Buttons[1][PLAY_BUTTON].button },
370                 {"Exit",                                                        1419,           940,    661,    UI_XSTR_COLOR_PINK, -1, &Buttons[1][EXIT_BUTTON].button },                      
371 #endif
372         }
373 };
374
375 int Cutscene_list_coords[GR_NUM_RESOLUTIONS][4] = {
376         { // GR_640
377 #ifdef MAKE_FS1
378                 25, 119, 542, 193
379 #else
380                 9,      117,    621,    198
381 #endif
382         },
383         { // GR_1024
384                 14,     188,    994,    316
385         }
386 };
387
388 int Cutscene_desc_coords[GR_NUM_RESOLUTIONS][4] = {
389         { // GR_640
390 #ifdef MAKE_FS1
391                 19, 356, 465, 40
392 #else
393                 9,      378, 484, 73
394 #endif
395         },
396         { // GR_1024
397                 14, 605, 775, 117
398         }
399 };
400
401 #define MAX_TEXT_LINES          20
402 int Cutscene_max_text_lines[GR_NUM_RESOLUTIONS] = {
403         10,
404         MAX_TEXT_LINES
405 };
406 #define MAX_TEXT_LINE_LEN       256
407
408 static int Text_size;
409 static int Text_offset = 0;
410 static int Text_line_size[MAX_TEXT_LINES];
411 static char *Text_lines[MAX_TEXT_LINES];
412
413
414 int cutscenes_validate_cd(char *mve_name, int prompt_for_cd)
415 {
416         int cd_present = 0;
417         int cd_drive_num;
418         int cd_mve_is_on;
419         char volume_name[128];
420
421 #ifdef RELEASE_REAL
422         int num_attempts = 0;
423 #endif
424
425         while(1) {
426                 int path_set_ok;
427
428                 cd_mve_is_on = cutscenes_get_cd_num(mve_name);
429                 if ((cd_mve_is_on != 0) && (cd_mve_is_on != 1) && (cd_mve_is_on != 2)) {
430                         cd_present = 0;
431                         break;
432                 }
433
434 #if defined(OEM_BUILD)
435                 sprintf(volume_name, NOX("FS2_OEM"));
436 #else
437                 sprintf(volume_name, NOX("FREESPACE2_%c"), '1' + cd_mve_is_on);
438 #endif
439
440
441                 cd_drive_num = find_freespace_cd(volume_name);
442                 path_set_ok = set_cdrom_path(cd_drive_num);
443
444                 if ( path_set_ok ) {
445                         cd_present = 1;
446                         break;
447                 }
448
449 #ifdef RELEASE_REAL
450                 if ( !prompt_for_cd ) {
451                         cd_present = 0;
452                         break;
453                 }
454
455                 // no CD found, so prompt user
456                 char popup_msg[256];
457                 int popup_rval;
458
459 #if defined(DVD_MESSAGE_HACK)
460                 sprintf(popup_msg, XSTR( "Movie not found\n\nInsert FreeSpace DVD to continue", 203));
461 #else 
462                 sprintf(popup_msg, XSTR( "Movie not found\n\nInsert FreeSpace CD #%d to continue", 203), cd_mve_is_on+1);
463 #endif
464
465                 popup_rval = popup(PF_BODY_BIG, 2, POPUP_CANCEL, POPUP_OK, popup_msg);
466                 if ( popup_rval != 1 ) {
467                         cd_present = 0;
468                         break;
469                 }
470
471                 if ( num_attempts++ > 5 ) {
472                         cd_present = 0;
473                         break;
474                 }
475 #else
476                 cd_present = 0;
477                 break;
478 #endif
479
480         }
481
482         return cd_present;
483 }
484
485 void cutscenes_screen_play()
486 {
487         char name[MAX_FILENAME_LEN], *full_name;
488         int which_cutscene;
489
490         Assert( (Selected_line >= 0) && (Selected_line < Num_files) );
491         which_cutscene = Cutscene_list[Selected_line];
492
493         strcpy(name, Cutscenes[which_cutscene].filename );
494         full_name = cf_add_ext(name, NOX(".mve"));
495
496         int rval = movie_play(full_name);
497         if ( !rval ) {
498                 char str[256];
499
500                 sprintf(str, XSTR( "Unable to play movie %s.", 204), Cutscenes[which_cutscene].name );
501                 popup(0, 1, POPUP_OK, str );
502         }
503 }
504
505 void cutscenes_screen_scroll_line_up()
506 {
507         if (Selected_line) {
508                 Selected_line--;
509                 gamesnd_play_iface(SND_SCROLL);
510
511         } else
512                 gamesnd_play_iface(SND_GENERAL_FAIL);
513         
514         if (Selected_line < Scroll_offset)
515                 Scroll_offset = Selected_line;
516 }
517
518 void cutscenes_screen_scroll_line_down()
519 {
520         int h;
521
522         if (Selected_line < Num_files - 1) {
523                 Selected_line++;
524                 gamesnd_play_iface(SND_SCROLL);
525
526         } else
527                 gamesnd_play_iface(SND_GENERAL_FAIL);
528         
529         h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
530         if (Selected_line >= Scroll_offset + h){
531                 Scroll_offset++;
532         }
533 }
534
535 void cutscenes_screen_scroll_screen_up()
536 {
537         int h;
538
539         if (Scroll_offset) {
540                 Scroll_offset--;
541                 Assert(Selected_line > Scroll_offset);
542                 h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
543                 while (Selected_line >= Scroll_offset + h){
544                         Selected_line--;
545                 }
546
547                 gamesnd_play_iface(SND_SCROLL);
548
549         } else {
550                 gamesnd_play_iface(SND_GENERAL_FAIL);
551         }
552 }
553
554 void cutscenes_screen_scroll_screen_down()
555 {
556         int h;
557
558         h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
559         if (Scroll_offset + h < Num_files) {
560                 Scroll_offset++;
561                 if (Selected_line < Scroll_offset){
562                         Selected_line = Scroll_offset;
563                 }
564
565                 gamesnd_play_iface(SND_SCROLL);
566         } else {
567                 gamesnd_play_iface(SND_GENERAL_FAIL);
568         }
569 }
570
571 int cutscenes_screen_button_pressed(int n)
572 {
573         switch (n) {
574                 case TECH_DATABASE_BUTTON:
575                         gamesnd_play_iface(SND_SWITCH_SCREENS);
576                         gameseq_post_event(GS_EVENT_TECH_MENU);
577                         return 1;
578
579                 case SIMULATOR_BUTTON:
580                         gamesnd_play_iface(SND_SWITCH_SCREENS);
581                         gameseq_post_event(GS_EVENT_SIMULATOR_ROOM);
582                         return 1;
583
584                 case CREDITS_BUTTON:
585                         gamesnd_play_iface(SND_SWITCH_SCREENS);
586                         gameseq_post_event(GS_EVENT_CREDITS);
587                         return 1;
588
589                 case SCROLL_UP_BUTTON:
590                         cutscenes_screen_scroll_screen_up();
591                         break;
592
593                 case SCROLL_DOWN_BUTTON:
594                         cutscenes_screen_scroll_screen_down();
595                         break;
596
597                 case PLAY_BUTTON:
598                         cutscenes_screen_play();
599                         break;
600
601                 case EXIT_BUTTON:
602                         gamesnd_play_iface(SND_COMMIT_PRESSED);
603                         gameseq_post_event(GS_EVENT_MAIN_MENU);
604                         game_flush();
605                         break;
606         }
607
608         return 0;
609 }
610
611 void cutscenes_screen_init()
612 {
613         int i;
614         ui_button_info *b;
615
616         Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
617         Ui_window.set_mask_bmap(Cutscene_mask_name[gr_screen.res]);
618
619         for (i=0; i<NUM_BUTTONS; i++) {
620                 b = &Buttons[gr_screen.res][i];
621
622                 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
623                 // set up callback for when a mouse first goes over a button
624                 b->button.set_highlight_action(common_play_highlight_sound);
625                 b->button.set_bmaps(b->filename);
626                 b->button.link_hotspot(b->hotspot);
627         }
628
629         // add xstrs
630         for(i=0; i<NUM_CUTSCENE_TEXT; i++){
631                 Ui_window.add_XSTR(&Cutscene_text[gr_screen.res][i]);
632         }
633
634         Buttons[gr_screen.res][EXIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
635         Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
636         Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);     
637
638         List_region.create(&Ui_window, "", Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1], Cutscene_list_coords[gr_screen.res][2], Cutscene_list_coords[gr_screen.res][3], 0, 1);
639         List_region.hide();
640
641         // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
642         Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
643         Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
644
645         Background_bitmap = bm_load(Cutscene_bitmap_name[gr_screen.res]);
646         Scroll_offset = Selected_line = 0;
647         Description_index = -1;
648
649         // when doing a debug version, just put all of the movie files here.
650 #ifndef NDEBUG
651         //Cutscenes_viewable = 0xffffffff;                      // makes all cutscenes viewble.
652 #endif
653
654         if (All_movies_enabled)
655                 Cutscenes_viewable = 0xffffffff;                //      Cheat code enables all movies.
656
657         Num_files = 0;
658         for ( i = 0; i < Num_cutscenes; i++ ) {
659                 if ( Cutscenes_viewable & (1<<i) ) {
660                         Cutscene_list[Num_files] = i;
661                         Num_files++;
662                 }
663         }
664 }
665
666 void cutscenes_screen_close()
667 {
668         if (Background_bitmap)
669                 bm_unload(Background_bitmap);
670
671         Ui_window.destroy();
672 }
673
674 void cutscenes_screen_do_frame()
675 {
676         int i, k, y, z;
677         int font_height = gr_get_font_height();
678         int select_tease_line = -1;
679
680         k = Ui_window.process();
681         switch (k) {
682                 case KEY_DOWN:  // select next line
683                         cutscenes_screen_scroll_line_down();
684                         break;
685
686                 case KEY_UP:  // select previous line
687                         cutscenes_screen_scroll_line_up();
688                         break;
689
690                 case KEY_TAB:
691                 case KEY_CTRLED | KEY_DOWN:
692                         cutscenes_screen_button_pressed(CREDITS_BUTTON);
693                         break;
694
695                 case KEY_SHIFTED | KEY_TAB:
696                 case KEY_CTRLED | KEY_UP:
697                         cutscenes_screen_button_pressed(SIMULATOR_BUTTON);
698                         break;
699
700                 case KEY_ENTER:
701                         cutscenes_screen_play();
702                         break;
703
704                 case KEY_ESC:  // cancel
705                         gameseq_post_event(GS_EVENT_MAIN_MENU);
706                         game_flush();
707                         break;
708
709                 case KEY_F1:  // show help overlay
710                         break;
711
712                 case KEY_F2:  // goto options screen
713                         gameseq_post_event(GS_EVENT_OPTIONS_MENU);
714                         break;
715         }       // end switch
716
717         for (i=0; i<NUM_BUTTONS; i++){
718                 if (Buttons[gr_screen.res][i].button.pressed()){
719                         if (cutscenes_screen_button_pressed(i)){
720                                 return;
721                         }
722                 }
723         }
724
725         if (List_region.button_down()) {
726                 List_region.get_mouse_pos(NULL, &y);
727                 z = Scroll_offset + y / font_height;
728                 if ((z >= 0) && (z < Num_files))
729                         select_tease_line = z;
730         }
731         
732         if (List_region.pressed()) {
733                 List_region.get_mouse_pos(NULL, &y);
734                 z = Scroll_offset + y / font_height;
735                 if ((z >= 0) && (z < Num_files))
736                         Selected_line = z;
737         }
738
739         GR_MAYBE_CLEAR_RES(Background_bitmap);
740         if (Background_bitmap >= 0) {
741                 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
742                 gr_bitmap(0, 0);
743         } 
744
745         Ui_window.draw();
746
747         for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
748                 if (Buttons[gr_screen.res][i].button.button_down()){
749                         break;
750                 }
751         }
752
753         if (i > CREDITS_BUTTON){
754                 Buttons[gr_screen.res][CUTSCENES_BUTTON].button.draw_forced(2);
755         }
756
757         y = 0;
758         z = Scroll_offset;
759         while (y + font_height <= Cutscene_list_coords[gr_screen.res][3]) {
760                 if (z >= Num_files){
761                         break;
762                 }
763
764                 if (z == Selected_line){
765                         gr_set_color_fast(&Color_text_selected);
766                 } else if (z == select_tease_line) {
767                         gr_set_color_fast(&Color_text_subselected);
768                 } else {
769                         gr_set_color_fast(&Color_text_normal);
770                 }
771
772                 gr_printf(Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1] + y, Cutscenes[Cutscene_list[z]].name);
773
774                 y += font_height;
775                 z++;
776         }
777
778         if (Description_index != Selected_line) {
779                 char *src;
780
781                 Description_index = Selected_line;
782                 Text_size = 0;
783                 src = Cutscenes[Cutscene_list[Description_index]].description;
784                 if (src) {
785                         Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines, Cutscene_max_text_lines[gr_screen.res]);
786                         Assert(Text_size >= 0 && Text_size < Cutscene_max_text_lines[gr_screen.res]);
787                 }
788         }
789
790         if (Description_index >= 0) {
791                 int len;
792                 char line[MAX_TEXT_LINE_LEN + 1];
793
794                 gr_set_color_fast(&Color_text_normal);
795
796                 y = 0;
797                 z = Text_offset;
798                 while (y + font_height <= Cutscene_desc_coords[gr_screen.res][3]) {
799                         if (z >= Text_size)
800                                 break;
801
802                         len = Text_line_size[z];
803                         if (len > MAX_TEXT_LINE_LEN)
804                                 len = MAX_TEXT_LINE_LEN;
805
806                         strncpy(line, Text_lines[z], len);
807                         line[len] = 0;
808                         gr_string(Cutscene_desc_coords[gr_screen.res][0], Cutscene_desc_coords[gr_screen.res][1] + y, line);
809
810                         y += font_height;
811                         z++;
812                 }
813         }
814
815         gr_flip();
816 }
817