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