2 * $Logfile: /Freespace2/code/Cutscene/Cutscenes.cpp $
7 * Code for the cutscenes viewer screen
10 * Revision 1.3 2002/05/26 22:06:17 relnev
11 * makefile: disable stand_gui for now.
13 * rest: staticize some globals
15 * Revision 1.2 2002/05/07 03:16:43 theoddone33
16 * The Great Newline Fix
18 * Revision 1.1.1.1 2002/05/03 03:28:08 root
22 * 15 6/16/00 3:15p Jefff
23 * sim of the year dvd version changes, a few german soty localization
26 * 14 10/13/99 10:20a Jefff
27 * fixed bug where intro cutscene showed 2x after getting bad ending
29 * 13 10/06/99 10:30a Jefff
32 * 12 9/30/99 6:01p Jefff
35 * 11 9/07/99 1:10p Mikek
36 * Make movie check not hang in ~RELEASE_REAL build.
38 * 10 9/06/99 6:38p Dave
39 * Improved CD detection code.
41 * 9 9/06/99 1:16a Dave
42 * Make sure the user sees the intro movie.
44 * 8 9/03/99 1:31a Dave
45 * CD checking by act. Added support to play 2 cutscenes in a row
46 * seamlessly. Fixed super low level cfile bug related to files in the
47 * root directory of a CD. Added cheat code to set campaign mission # in
50 * 7 7/19/99 2:13p Dave
51 * Added some new strings for Heiko.
53 * 6 6/01/99 3:52p Dave
54 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
55 * dead popup, pxo find player popup, pxo private room popup.
57 * 5 1/30/99 5:08p Dave
58 * More new hi-res stuff.Support for nice D3D textures.
60 * 4 10/23/98 3:51p Dave
61 * Full support for tstrings.tbl and foreign languages. All that remains
62 * is to make it active in Fred.
64 * 3 10/13/98 9:28a Dave
65 * Started neatening up freespace.h. Many variables renamed and
66 * reorganized. Added AlphaColors.[h,cpp]
68 * 2 10/07/98 10:52a Dave
71 * 1 10/07/98 10:48a Dave
73 * 18 6/09/98 10:31a Hoffoss
74 * Created index numbers for all xstr() references. Any new xstr() stuff
75 * added from here on out should be added to the end if the list. The
76 * current list count can be found in FreeSpace.cpp (search for
79 * 17 6/01/98 11:43a John
80 * JAS & MK: Classified all strings for localization.
82 * 16 5/24/98 9:01p Lawrance
83 * Add commit sounds when accept is pressed
85 * 15 5/21/98 8:05p Allender
86 * fix possible bug with number of cutscenes shown in the list
88 * 14 5/21/98 12:35a Lawrance
89 * Tweak how CD is checked for
91 * 13 5/20/98 1:34p Hoffoss
92 * Added cutscene description rendering.
94 * 12 5/19/98 12:19p Mike
97 * 11 5/12/98 4:17p Hoffoss
98 * Make ctrl-arrows (up/down) switch between tech room screens.
100 * 10 5/11/98 8:04p Hoffoss
103 * 9 5/10/98 10:05p Allender
104 * only show cutscenes which have been seen before. Made Fred able to
105 * write missions anywhere, defaulting to player misison folder, not data
106 * mission folder. Fix FreeSpace code to properly read missions from
109 * 8 5/08/98 5:30p Lawrance
110 * add CD checks for movie playing
112 * 7 5/08/98 4:07p Allender
113 * more cutscene stuff
115 * 6 5/07/98 2:33p Hoffoss
116 * Removed help and options buttons.
118 * 5 4/30/98 4:53p John
119 * Restructured and cleaned up cfile code. Added capability to read off
120 * of CD-ROM drive and out of multiple pack files.
122 * 4 4/23/98 8:27p Allender
123 * basic support for cutscene playback. Into movie code in place. Tech
124 * room can view cutscenes stored in CDROM_dir variable
126 * 3 4/21/98 7:07p Hoffoss
127 * Fixed problem where when switching screens flashes old tab hilight once
128 * before switching to new state.
130 * 2 4/17/98 6:33p Hoffoss
131 * Made changes to the tech room group of screens. Cutscenes screen is
137 #include "cutscenes.h"
141 #include "gamesequence.h"
142 #include "freespace.h"
145 // #include "movie.h"
147 #include "mainhallmenu.h"
148 #include "alphacolors.h"
149 #include "localize.h"
151 char *Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
155 char *Cutscene_mask_name[GR_NUM_RESOLUTIONS] = {
161 int Cutscenes_viewable;
162 int Description_index;
163 cutscene_info Cutscenes[MAX_CUTSCENES];
165 extern int All_movies_enabled; // If set, all movies may be viewed. Keyed off cheat code.
167 // initialization stuff for cutscenes
170 char buf[MULTITEXT_LENGTH];
173 if ((rval = setjmp(parse_abort)) != 0) {
174 Error(LOCATION, "Error parsing 'rank.tbl'\r\nError code = %i.\r\n", rval);
180 read_file_text("cutscenes.tbl");
183 // parse in all the rank names
185 skip_to_string("#Cutscenes");
186 ignore_white_space();
187 while ( required_string_either("#End", "$Filename:") ) {
188 Assert ( Num_cutscenes < MAX_CUTSCENES );
189 required_string("$Filename:");
190 stuff_string( Cutscenes[Num_cutscenes].filename, F_PATHNAME, NULL );
191 required_string("$Name:");
192 stuff_string( Cutscenes[Num_cutscenes].name, F_NAME, NULL );
193 required_string("$Description:");
194 stuff_string(buf, F_MULTITEXT, NULL);
195 drop_white_space(buf);
196 compact_multitext_string(buf);
197 Cutscenes[Num_cutscenes].description = strdup(buf);
198 required_string("$cd:");
199 stuff_int( &Cutscenes[Num_cutscenes].cd );
204 required_string("#End");
206 Cutscenes_viewable = INTRO_CUTSCENE_FLAG;
208 // close localization
212 // function to return 0 based index of which CD a particular movie is on
213 // returns -1 on failure.
214 int cutscenes_get_cd_num( char *filename )
216 #if defined(OEM_BUILD)
217 return 0; // only 1 cd for OEM
221 for (i = 0; i < Num_cutscenes; i++ ) {
222 if ( !stricmp(Cutscenes[i].filename, filename) ) {
223 return (Cutscenes[i].cd - 1);
228 #endif // defined(OEM_BUILD)
231 // marks a cutscene as viewable
232 void cutscene_mark_viewable(char *filename)
236 for (i = 0; i < Num_cutscenes; i++ ) {
237 if ( !stricmp(Cutscenes[i].filename, filename) ) {
238 Cutscenes_viewable |= (1<<i);
244 #define NUM_BUTTONS 8
246 #define TECH_DATABASE_BUTTON 0
247 #define SIMULATOR_BUTTON 1
248 #define CUTSCENES_BUTTON 2
249 #define CREDITS_BUTTON 3
251 #define SCROLL_UP_BUTTON 4
252 #define SCROLL_DOWN_BUTTON 5
253 #define PLAY_BUTTON 6
254 #define EXIT_BUTTON 7
256 static int Num_files;
257 static int Cutscene_list[MAX_CUTSCENES];
258 static int Stats_scroll_offset;
259 static int Selected_line = 0; // line that is currently selected for binding
260 static int Scroll_offset;
261 static int Background_bitmap;
262 static UI_BUTTON List_region;
263 static UI_WINDOW Ui_window;
265 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
267 ui_button_info("TDB_00", 7, 5, 37, 7, 0), // tech database 1
268 ui_button_info("TDB_01", 7, 19, 37, 23, 1), // tech database 2
269 ui_button_info("TDB_02", 7, 34, 37, 38, 2), // tech database 3
270 ui_button_info("TDB_03", 7, 49, 37, 54, 3), // tech database 4
272 ui_button_info("VFB_04", 6, 318, -1, -1, 4), // scroll up
273 ui_button_info("VFB_05", 36, 318, -1, -1, 5), // scroll down
274 ui_button_info("VFB_06", 578, 319, 587, 366, 6), // play
275 ui_button_info("VFB_07", 574, 431, 587, 413, 7), // exit
278 ui_button_info("2_TDB_00", 12, 7, 59, 12, 0), // tech database 1
279 ui_button_info("2_TDB_01", 12, 31, 59, 37, 1), // tech database 2
280 ui_button_info("2_TDB_02", 12, 56, 59, 62, 2), // tech database 3
281 ui_button_info("2_TDB_03", 12, 81, 59, 88, 3), // tech database 4
283 ui_button_info("2_VFB_04", 9, 509, -1, -1, 4), // scroll up
284 ui_button_info("2_VFB_05", 58, 509, -1, -1, 5), // scroll down
285 ui_button_info("2_VFB_06", 925, 511, 940, 586, 6), // play
286 ui_button_info("2_VFB_07", 918, 689, 940, 661, 7), // exit
291 #define NUM_CUTSCENE_TEXT 6
292 UI_XSTR Cutscene_text[GR_NUM_RESOLUTIONS][NUM_CUTSCENE_TEXT] = {
294 {"Technical Database", 1055, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][TECH_DATABASE_BUTTON].button },
295 {"Mission Simulator", 1056, 37, 23, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][SIMULATOR_BUTTON].button },
296 {"Cutscenes", 1057, 37, 38, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CUTSCENES_BUTTON].button },
297 {"Credits", 1058, 37, 54, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CREDITS_BUTTON].button },
299 {"Play", 1335, 587, 366, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][PLAY_BUTTON].button },
300 {"Exit", 1419, 587, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][EXIT_BUTTON].button },
303 {"Technical Database", 1055, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][TECH_DATABASE_BUTTON].button },
304 {"Mission Simulator", 1056, 59, 37, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][SIMULATOR_BUTTON].button },
305 {"Cutscenes", 1057, 59, 62, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CUTSCENES_BUTTON].button },
306 {"Credits", 1058, 59, 88, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CREDITS_BUTTON].button },
308 {"Play", 1335, 940, 586, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][PLAY_BUTTON].button },
309 {"Exit", 1419, 940, 661, UI_XSTR_COLOR_PINK, -1, &Buttons[1][EXIT_BUTTON].button },
313 int Cutscene_list_coords[GR_NUM_RESOLUTIONS][4] = {
322 int Cutscene_desc_coords[GR_NUM_RESOLUTIONS][4] = {
331 #define MAX_TEXT_LINES 20
332 int Cutscene_max_text_lines[GR_NUM_RESOLUTIONS] = {
336 #define MAX_TEXT_LINE_LEN 256
338 static int Text_size;
339 static int Text_offset = 0;
340 static int Text_line_size[MAX_TEXT_LINES];
341 static char *Text_lines[MAX_TEXT_LINES];
344 int cutscenes_validate_cd(char *mve_name, int prompt_for_cd)
349 char volume_name[128];
352 int num_attempts = 0;
358 cd_mve_is_on = cutscenes_get_cd_num(mve_name);
359 if ((cd_mve_is_on != 0) && (cd_mve_is_on != 1) && (cd_mve_is_on != 2)) {
364 #if defined(OEM_BUILD)
365 sprintf(volume_name, NOX("FS2_OEM"));
367 sprintf(volume_name, NOX("FREESPACE2_%c"), '1' + cd_mve_is_on);
371 cd_drive_num = find_freespace_cd(volume_name);
372 path_set_ok = set_cdrom_path(cd_drive_num);
380 if ( !prompt_for_cd ) {
385 // no CD found, so prompt user
389 #if defined(DVD_MESSAGE_HACK)
390 sprintf(popup_msg, XSTR( "Movie not found\n\nInsert FreeSpace DVD to continue", 203));
392 sprintf(popup_msg, XSTR( "Movie not found\n\nInsert FreeSpace CD #%d to continue", 203), cd_mve_is_on+1);
395 popup_rval = popup(PF_BODY_BIG, 2, POPUP_CANCEL, POPUP_OK, popup_msg);
396 if ( popup_rval != 1 ) {
401 if ( num_attempts++ > 5 ) {
415 void cutscenes_screen_play()
417 char name[MAX_FILENAME_LEN], *full_name;
420 Assert( (Selected_line >= 0) && (Selected_line < Num_files) );
421 which_cutscene = Cutscene_list[Selected_line];
423 strcpy(name, Cutscenes[which_cutscene].filename );
424 full_name = cf_add_ext(name, NOX(".mve"));
428 int rval = movie_play(full_name);
432 sprintf(str, XSTR( "Unable to play movie %s.", 204), Cutscenes[which_cutscene].name );
433 popup(0, 1, POPUP_OK, str );
438 void cutscenes_screen_scroll_line_up()
442 gamesnd_play_iface(SND_SCROLL);
445 gamesnd_play_iface(SND_GENERAL_FAIL);
447 if (Selected_line < Scroll_offset)
448 Scroll_offset = Selected_line;
451 void cutscenes_screen_scroll_line_down()
455 if (Selected_line < Num_files - 1) {
457 gamesnd_play_iface(SND_SCROLL);
460 gamesnd_play_iface(SND_GENERAL_FAIL);
462 h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
463 if (Selected_line >= Scroll_offset + h){
468 void cutscenes_screen_scroll_screen_up()
474 Assert(Selected_line > Scroll_offset);
475 h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
476 while (Selected_line >= Scroll_offset + h){
480 gamesnd_play_iface(SND_SCROLL);
483 gamesnd_play_iface(SND_GENERAL_FAIL);
487 void cutscenes_screen_scroll_screen_down()
491 h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
492 if (Scroll_offset + h < Num_files) {
494 if (Selected_line < Scroll_offset){
495 Selected_line = Scroll_offset;
498 gamesnd_play_iface(SND_SCROLL);
500 gamesnd_play_iface(SND_GENERAL_FAIL);
504 int cutscenes_screen_button_pressed(int n)
507 case TECH_DATABASE_BUTTON:
508 gamesnd_play_iface(SND_SWITCH_SCREENS);
509 gameseq_post_event(GS_EVENT_TECH_MENU);
512 case SIMULATOR_BUTTON:
513 gamesnd_play_iface(SND_SWITCH_SCREENS);
514 gameseq_post_event(GS_EVENT_SIMULATOR_ROOM);
518 gamesnd_play_iface(SND_SWITCH_SCREENS);
519 gameseq_post_event(GS_EVENT_CREDITS);
522 case SCROLL_UP_BUTTON:
523 cutscenes_screen_scroll_screen_up();
526 case SCROLL_DOWN_BUTTON:
527 cutscenes_screen_scroll_screen_down();
531 cutscenes_screen_play();
535 gamesnd_play_iface(SND_COMMIT_PRESSED);
536 gameseq_post_event(GS_EVENT_MAIN_MENU);
544 void cutscenes_screen_init()
549 Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
550 Ui_window.set_mask_bmap(Cutscene_mask_name[gr_screen.res]);
552 for (i=0; i<NUM_BUTTONS; i++) {
553 b = &Buttons[gr_screen.res][i];
555 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
556 // set up callback for when a mouse first goes over a button
557 b->button.set_highlight_action(common_play_highlight_sound);
558 b->button.set_bmaps(b->filename);
559 b->button.link_hotspot(b->hotspot);
563 for(i=0; i<NUM_CUTSCENE_TEXT; i++){
564 Ui_window.add_XSTR(&Cutscene_text[gr_screen.res][i]);
567 Buttons[gr_screen.res][EXIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
568 Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
569 Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
571 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);
574 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
575 Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
576 Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
578 Background_bitmap = bm_load(Cutscene_bitmap_name[gr_screen.res]);
579 Scroll_offset = Selected_line = 0;
580 Description_index = -1;
582 // when doing a debug version, just put all of the movie files here.
584 //Cutscenes_viewable = 0xffffffff; // makes all cutscenes viewble.
587 if (All_movies_enabled)
588 Cutscenes_viewable = 0xffffffff; // Cheat code enables all movies.
591 for ( i = 0; i < Num_cutscenes; i++ ) {
592 if ( Cutscenes_viewable & (1<<i) ) {
593 Cutscene_list[Num_files] = i;
599 void cutscenes_screen_close()
601 if (Background_bitmap)
602 bm_unload(Background_bitmap);
607 void cutscenes_screen_do_frame()
610 int font_height = gr_get_font_height();
611 int select_tease_line = -1;
613 k = Ui_window.process();
615 case KEY_DOWN: // select next line
616 cutscenes_screen_scroll_line_down();
619 case KEY_UP: // select previous line
620 cutscenes_screen_scroll_line_up();
624 case KEY_CTRLED | KEY_DOWN:
625 cutscenes_screen_button_pressed(CREDITS_BUTTON);
628 case KEY_SHIFTED | KEY_TAB:
629 case KEY_CTRLED | KEY_UP:
630 cutscenes_screen_button_pressed(SIMULATOR_BUTTON);
634 cutscenes_screen_play();
637 case KEY_ESC: // cancel
638 gameseq_post_event(GS_EVENT_MAIN_MENU);
642 case KEY_F1: // show help overlay
645 case KEY_F2: // goto options screen
646 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
650 for (i=0; i<NUM_BUTTONS; i++){
651 if (Buttons[gr_screen.res][i].button.pressed()){
652 if (cutscenes_screen_button_pressed(i)){
658 if (List_region.button_down()) {
659 List_region.get_mouse_pos(NULL, &y);
660 z = Scroll_offset + y / font_height;
661 if ((z >= 0) && (z < Num_files))
662 select_tease_line = z;
665 if (List_region.pressed()) {
666 List_region.get_mouse_pos(NULL, &y);
667 z = Scroll_offset + y / font_height;
668 if ((z >= 0) && (z < Num_files))
672 GR_MAYBE_CLEAR_RES(Background_bitmap);
673 if (Background_bitmap >= 0) {
674 gr_set_bitmap(Background_bitmap);
680 for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
681 if (Buttons[gr_screen.res][i].button.button_down()){
686 if (i > CREDITS_BUTTON){
687 Buttons[gr_screen.res][CUTSCENES_BUTTON].button.draw_forced(2);
692 while (y + font_height <= Cutscene_list_coords[gr_screen.res][3]) {
697 if (z == Selected_line){
698 gr_set_color_fast(&Color_text_selected);
699 } else if (z == select_tease_line) {
700 gr_set_color_fast(&Color_text_subselected);
702 gr_set_color_fast(&Color_text_normal);
705 gr_printf(Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1] + y, Cutscenes[Cutscene_list[z]].name);
711 if (Description_index != Selected_line) {
714 Description_index = Selected_line;
716 src = Cutscenes[Cutscene_list[Description_index]].description;
718 Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines, Cutscene_max_text_lines[gr_screen.res]);
719 Assert(Text_size >= 0 && Text_size < Cutscene_max_text_lines[gr_screen.res]);
723 if (Description_index >= 0) {
725 char line[MAX_TEXT_LINE_LEN + 1];
727 gr_set_color_fast(&Color_text_normal);
731 while (y + font_height <= Cutscene_desc_coords[gr_screen.res][3]) {
735 len = Text_line_size[z];
736 if (len > MAX_TEXT_LINE_LEN)
737 len = MAX_TEXT_LINE_LEN;
739 strncpy(line, Text_lines[z], len);
741 gr_string(Cutscene_desc_coords[gr_screen.res][0], Cutscene_desc_coords[gr_screen.res][1] + y, line);