2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Cutscene/Cutscenes.cpp $
15 * Code for the cutscenes viewer screen
18 * Revision 1.10 2005/03/29 02:18:47 taylor
19 * Various 64-bit platform fixes
20 * Fix compiler errors with MAKE_FS1 and fix gr_set_bitmap() too
21 * Make sure that turrets can fire at asteroids for FS1 (needed for a couple missions)
22 * Streaming audio support (big thanks to Pierre Willenbrock!!)
23 * Removed dependance on strings.tbl for FS1 since we don't actually need it now
25 * Revision 1.9 2004/09/20 01:31:44 theoddone33
28 * Revision 1.8 2003/06/11 18:30:32 taylor
31 * Revision 1.7 2003/05/25 02:30:42 taylor
34 * Revision 1.6 2002/07/24 00:20:41 relnev
37 * Revision 1.5 2002/06/09 04:41:15 relnev
38 * added copyright header
40 * Revision 1.4 2002/06/02 04:26:34 relnev
43 * Revision 1.3 2002/05/26 22:06:17 relnev
44 * makefile: disable stand_gui for now.
46 * rest: staticize some globals
48 * Revision 1.2 2002/05/07 03:16:43 theoddone33
49 * The Great Newline Fix
51 * Revision 1.1.1.1 2002/05/03 03:28:08 root
55 * 15 6/16/00 3:15p Jefff
56 * sim of the year dvd version changes, a few german soty localization
59 * 14 10/13/99 10:20a Jefff
60 * fixed bug where intro cutscene showed 2x after getting bad ending
62 * 13 10/06/99 10:30a Jefff
65 * 12 9/30/99 6:01p Jefff
68 * 11 9/07/99 1:10p Mikek
69 * Make movie check not hang in ~RELEASE_REAL build.
71 * 10 9/06/99 6:38p Dave
72 * Improved CD detection code.
74 * 9 9/06/99 1:16a Dave
75 * Make sure the user sees the intro movie.
77 * 8 9/03/99 1:31a Dave
78 * CD checking by act. Added support to play 2 cutscenes in a row
79 * seamlessly. Fixed super low level cfile bug related to files in the
80 * root directory of a CD. Added cheat code to set campaign mission # in
83 * 7 7/19/99 2:13p Dave
84 * Added some new strings for Heiko.
86 * 6 6/01/99 3:52p Dave
87 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
88 * dead popup, pxo find player popup, pxo private room popup.
90 * 5 1/30/99 5:08p Dave
91 * More new hi-res stuff.Support for nice D3D textures.
93 * 4 10/23/98 3:51p Dave
94 * Full support for tstrings.tbl and foreign languages. All that remains
95 * is to make it active in Fred.
97 * 3 10/13/98 9:28a Dave
98 * Started neatening up freespace.h. Many variables renamed and
99 * reorganized. Added AlphaColors.[h,cpp]
101 * 2 10/07/98 10:52a Dave
104 * 1 10/07/98 10:48a Dave
106 * 18 6/09/98 10:31a Hoffoss
107 * Created index numbers for all xstr() references. Any new xstr() stuff
108 * added from here on out should be added to the end if the list. The
109 * current list count can be found in FreeSpace.cpp (search for
112 * 17 6/01/98 11:43a John
113 * JAS & MK: Classified all strings for localization.
115 * 16 5/24/98 9:01p Lawrance
116 * Add commit sounds when accept is pressed
118 * 15 5/21/98 8:05p Allender
119 * fix possible bug with number of cutscenes shown in the list
121 * 14 5/21/98 12:35a Lawrance
122 * Tweak how CD is checked for
124 * 13 5/20/98 1:34p Hoffoss
125 * Added cutscene description rendering.
127 * 12 5/19/98 12:19p Mike
130 * 11 5/12/98 4:17p Hoffoss
131 * Make ctrl-arrows (up/down) switch between tech room screens.
133 * 10 5/11/98 8:04p Hoffoss
136 * 9 5/10/98 10:05p Allender
137 * only show cutscenes which have been seen before. Made Fred able to
138 * write missions anywhere, defaulting to player misison folder, not data
139 * mission folder. Fix FreeSpace code to properly read missions from
142 * 8 5/08/98 5:30p Lawrance
143 * add CD checks for movie playing
145 * 7 5/08/98 4:07p Allender
146 * more cutscene stuff
148 * 6 5/07/98 2:33p Hoffoss
149 * Removed help and options buttons.
151 * 5 4/30/98 4:53p John
152 * Restructured and cleaned up cfile code. Added capability to read off
153 * of CD-ROM drive and out of multiple pack files.
155 * 4 4/23/98 8:27p Allender
156 * basic support for cutscene playback. Into movie code in place. Tech
157 * room can view cutscenes stored in CDROM_dir variable
159 * 3 4/21/98 7:07p Hoffoss
160 * Fixed problem where when switching screens flashes old tab hilight once
161 * before switching to new state.
163 * 2 4/17/98 6:33p Hoffoss
164 * Made changes to the tech room group of screens. Cutscenes screen is
170 #include "cutscenes.h"
174 #include "gamesequence.h"
175 #include "freespace.h"
180 #include "mainhallmenu.h"
181 #include "alphacolors.h"
182 #include "localize.h"
184 const char *Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
188 const char *Cutscene_mask_name[GR_NUM_RESOLUTIONS] = {
194 int Cutscenes_viewable;
195 int Description_index;
196 cutscene_info Cutscenes[MAX_CUTSCENES];
198 extern int All_movies_enabled; // If set, all movies may be viewed. Keyed off cheat code.
200 // initialization stuff for cutscenes
203 #ifndef FS1_DEMO // no cuscenes in FS1 demo
204 char buf[MULTITEXT_LENGTH];
210 read_file_text("cutscenes.tbl");
213 // parse in all the rank names
215 skip_to_string("#Cutscenes");
216 ignore_white_space();
217 while ( required_string_either("#End", "$Filename:") ) {
218 SDL_assert ( Num_cutscenes < MAX_CUTSCENES );
219 required_string("$Filename:");
220 stuff_string( Cutscenes[Num_cutscenes].filename, F_PATHNAME, NULL );
221 required_string("$Name:");
222 stuff_string( Cutscenes[Num_cutscenes].name, F_NAME, NULL );
223 required_string("$Description:");
224 stuff_string(buf, F_MULTITEXT, NULL);
225 drop_white_space(buf);
226 compact_multitext_string(buf);
227 Cutscenes[Num_cutscenes].description = strdup(buf);
228 required_string("$cd:");
229 stuff_int( &Cutscenes[Num_cutscenes].cd );
234 required_string("#End");
235 } catch (parse_error_t rval) {
236 Error(LOCATION, "Error parsing 'cutscenes.tbl'\r\nError code = %i.\r\n", (int)rval);
239 Cutscenes_viewable = INTRO_CUTSCENE_FLAG;
241 // close localization
246 // free up memory from table parsing
247 void cutscene_tbl_close()
251 for (i=0; i<MAX_CUTSCENES; i++) {
252 if (Cutscenes[i].description) {
253 free(Cutscenes[i].description);
254 Cutscenes[i].description = NULL;
259 // marks a cutscene as viewable
260 void cutscene_mark_viewable(const char *filename)
264 for (i = 0; i < Num_cutscenes; i++ ) {
265 if ( !SDL_strcasecmp(Cutscenes[i].filename, filename) ) {
266 Cutscenes_viewable |= (1<<i);
272 #define NUM_BUTTONS 8
274 #define TECH_DATABASE_BUTTON 0
275 #define SIMULATOR_BUTTON 1
276 #define CUTSCENES_BUTTON 2
277 #define CREDITS_BUTTON 3
279 #define SCROLL_UP_BUTTON 4
280 #define SCROLL_DOWN_BUTTON 5
281 #define PLAY_BUTTON 6
282 #define EXIT_BUTTON 7
284 static int Num_files;
285 static int Cutscene_list[MAX_CUTSCENES];
286 static int Selected_line = 0; // line that is currently selected for binding
287 static int Scroll_offset;
288 static int Background_bitmap;
289 static UI_BUTTON List_region;
290 static UI_WINDOW Ui_window;
292 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
295 ui_button_info("TDB_00", 0, 0, -1, -1, 0), // technical database tab
296 ui_button_info("TDB_01", 0, 19, -1, -1, 1), // mission simulator tab
297 ui_button_info("TDB_02", 0, 35, -1, -1, 2), // cutscenes tab
298 ui_button_info("TDB_03", 0, 56, -1, -1, 3), // credits tab
300 ui_button_info("VFB_04", 570, 304, -1, -1, 4), // scroll up
301 ui_button_info("VFB_05", 600, 304, -1, -1, 5), // scroll down
302 ui_button_info("VFB_06", 573, 347, -1, -1, 6), // play
303 ui_button_info("VFB_07", 566, 411, -1, -1, 7), // exit
305 ui_button_info("TDB_00", 7, 5, 37, 7, 0), // tech database 1
306 ui_button_info("TDB_01", 7, 19, 37, 23, 1), // tech database 2
307 ui_button_info("TDB_02", 7, 34, 37, 38, 2), // tech database 3
308 ui_button_info("TDB_03", 7, 49, 37, 54, 3), // tech database 4
310 ui_button_info("VFB_04", 6, 318, -1, -1, 4), // scroll up
311 ui_button_info("VFB_05", 36, 318, -1, -1, 5), // scroll down
312 ui_button_info("VFB_06", 578, 319, 587, 366, 6), // play
313 ui_button_info("VFB_07", 574, 431, 587, 413, 7), // exit
317 ui_button_info("2_TDB_00", 12, 7, 59, 12, 0), // tech database 1
318 ui_button_info("2_TDB_01", 12, 31, 59, 37, 1), // tech database 2
319 ui_button_info("2_TDB_02", 12, 56, 59, 62, 2), // tech database 3
320 ui_button_info("2_TDB_03", 12, 81, 59, 88, 3), // tech database 4
322 ui_button_info("2_VFB_04", 9, 509, -1, -1, 4), // scroll up
323 ui_button_info("2_VFB_05", 58, 509, -1, -1, 5), // scroll down
324 ui_button_info("2_VFB_06", 925, 511, 940, 586, 6), // play
325 ui_button_info("2_VFB_07", 918, 689, 940, 661, 7), // exit
331 #define NUM_CUTSCENE_TEXT 6
333 UI_XSTR Cutscene_text[GR_NUM_RESOLUTIONS][NUM_CUTSCENE_TEXT] = {
335 {"Technical Database", 1055, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][TECH_DATABASE_BUTTON].button },
336 {"Mission Simulator", 1056, 37, 23, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][SIMULATOR_BUTTON].button },
337 {"Cutscenes", 1057, 37, 38, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CUTSCENES_BUTTON].button },
338 {"Credits", 1058, 37, 54, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CREDITS_BUTTON].button },
340 {"Play", 1335, 587, 366, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][PLAY_BUTTON].button },
341 {"Exit", 1419, 587, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][EXIT_BUTTON].button },
344 {"Technical Database", 1055, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][TECH_DATABASE_BUTTON].button },
345 {"Mission Simulator", 1056, 59, 37, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][SIMULATOR_BUTTON].button },
346 {"Cutscenes", 1057, 59, 62, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CUTSCENES_BUTTON].button },
347 {"Credits", 1058, 59, 88, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CREDITS_BUTTON].button },
349 {"Play", 1335, 940, 586, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][PLAY_BUTTON].button },
350 {"Exit", 1419, 940, 661, UI_XSTR_COLOR_PINK, -1, &Buttons[1][EXIT_BUTTON].button },
355 int Cutscene_list_coords[GR_NUM_RESOLUTIONS][4] = {
368 int Cutscene_desc_coords[GR_NUM_RESOLUTIONS][4] = {
381 #define MAX_TEXT_LINES 20
382 int Cutscene_max_text_lines[GR_NUM_RESOLUTIONS] = {
386 #define MAX_TEXT_LINE_LEN 256
388 static int Text_size;
389 static int Text_offset = 0;
390 static int Text_line_size[MAX_TEXT_LINES];
391 static char *Text_lines[MAX_TEXT_LINES];
394 void cutscenes_screen_play()
396 char name[MAX_FILENAME_LEN], *full_name;
399 SDL_assert( (Selected_line >= 0) && (Selected_line < Num_files) );
400 which_cutscene = Cutscene_list[Selected_line];
402 SDL_strlcpy(name, Cutscenes[which_cutscene].filename, SDL_arraysize(name));
403 full_name = cf_add_ext(name, NOX(".mve"));
405 int rval = movie_play(full_name);
409 SDL_snprintf(str, SDL_arraysize(str), XSTR( "Unable to play movie %s.", 204), Cutscenes[which_cutscene].name );
410 popup(0, 1, POPUP_OK, str );
414 void cutscenes_screen_scroll_line_up()
418 gamesnd_play_iface(SND_SCROLL);
421 gamesnd_play_iface(SND_GENERAL_FAIL);
423 if (Selected_line < Scroll_offset)
424 Scroll_offset = Selected_line;
427 void cutscenes_screen_scroll_line_down()
431 if (Selected_line < Num_files - 1) {
433 gamesnd_play_iface(SND_SCROLL);
436 gamesnd_play_iface(SND_GENERAL_FAIL);
438 h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
439 if (Selected_line >= Scroll_offset + h){
444 void cutscenes_screen_scroll_screen_up()
450 SDL_assert(Selected_line > Scroll_offset);
451 h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
452 while (Selected_line >= Scroll_offset + h){
456 gamesnd_play_iface(SND_SCROLL);
459 gamesnd_play_iface(SND_GENERAL_FAIL);
463 void cutscenes_screen_scroll_screen_down()
467 h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
468 if (Scroll_offset + h < Num_files) {
470 if (Selected_line < Scroll_offset){
471 Selected_line = Scroll_offset;
474 gamesnd_play_iface(SND_SCROLL);
476 gamesnd_play_iface(SND_GENERAL_FAIL);
480 int cutscenes_screen_button_pressed(int n)
483 case TECH_DATABASE_BUTTON:
484 gamesnd_play_iface(SND_SWITCH_SCREENS);
485 gameseq_post_event(GS_EVENT_TECH_MENU);
488 case SIMULATOR_BUTTON:
489 gamesnd_play_iface(SND_SWITCH_SCREENS);
490 gameseq_post_event(GS_EVENT_SIMULATOR_ROOM);
494 gamesnd_play_iface(SND_SWITCH_SCREENS);
495 gameseq_post_event(GS_EVENT_CREDITS);
498 case SCROLL_UP_BUTTON:
499 cutscenes_screen_scroll_screen_up();
502 case SCROLL_DOWN_BUTTON:
503 cutscenes_screen_scroll_screen_down();
507 cutscenes_screen_play();
511 gamesnd_play_iface(SND_COMMIT_PRESSED);
512 gameseq_post_event(GS_EVENT_MAIN_MENU);
520 void cutscenes_screen_init()
525 Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
526 Ui_window.set_mask_bmap(Cutscene_mask_name[gr_screen.res]);
528 for (i=0; i<NUM_BUTTONS; i++) {
529 b = &Buttons[gr_screen.res][i];
531 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
532 // set up callback for when a mouse first goes over a button
533 b->button.set_highlight_action(common_play_highlight_sound);
534 b->button.set_bmaps(b->filename);
535 b->button.link_hotspot(b->hotspot);
540 for(i=0; i<NUM_CUTSCENE_TEXT; i++){
541 Ui_window.add_XSTR(&Cutscene_text[gr_screen.res][i]);
545 Buttons[gr_screen.res][EXIT_BUTTON].button.set_hotkey(KEY_CTRLED | SDLK_RETURN);
546 Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(SDLK_PAGEUP);
547 Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(SDLK_PAGEDOWN);
549 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);
552 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
553 Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(SDLK_PAGEUP);
554 Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(SDLK_PAGEDOWN);
556 Background_bitmap = bm_load(Cutscene_bitmap_name[gr_screen.res]);
557 Scroll_offset = Selected_line = 0;
558 Description_index = -1;
560 // when doing a debug version, just put all of the movie files here.
562 //Cutscenes_viewable = 0xffffffff; // makes all cutscenes viewble.
565 if (All_movies_enabled)
566 Cutscenes_viewable = 0xffffffff; // Cheat code enables all movies.
569 for ( i = 0; i < Num_cutscenes; i++ ) {
570 if ( Cutscenes_viewable & (1<<i) ) {
571 Cutscene_list[Num_files] = i;
577 void cutscenes_screen_close()
579 if (Background_bitmap)
580 bm_unload(Background_bitmap);
585 void cutscenes_screen_do_frame()
588 int font_height = gr_get_font_height();
589 int select_tease_line = -1;
591 k = Ui_window.process();
593 case SDLK_DOWN: // select next line
594 cutscenes_screen_scroll_line_down();
597 case SDLK_UP: // select previous line
598 cutscenes_screen_scroll_line_up();
602 case KEY_CTRLED | SDLK_DOWN:
603 cutscenes_screen_button_pressed(CREDITS_BUTTON);
606 case KEY_SHIFTED | SDLK_TAB:
607 case KEY_CTRLED | SDLK_UP:
608 cutscenes_screen_button_pressed(SIMULATOR_BUTTON);
612 cutscenes_screen_play();
615 case SDLK_ESCAPE: // cancel
616 gameseq_post_event(GS_EVENT_MAIN_MENU);
620 case SDLK_F1: // show help overlay
623 case SDLK_F2: // goto options screen
624 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
628 for (i=0; i<NUM_BUTTONS; i++){
629 if (Buttons[gr_screen.res][i].button.pressed()){
630 if (cutscenes_screen_button_pressed(i)){
636 if (List_region.button_down()) {
637 List_region.get_mouse_pos(NULL, &y);
638 z = Scroll_offset + y / font_height;
639 if ((z >= 0) && (z < Num_files))
640 select_tease_line = z;
643 if (List_region.pressed()) {
644 List_region.get_mouse_pos(NULL, &y);
645 z = Scroll_offset + y / font_height;
646 if ((z >= 0) && (z < Num_files))
650 GR_MAYBE_CLEAR_RES(Background_bitmap);
651 if (Background_bitmap >= 0) {
652 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
658 for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
659 if (Buttons[gr_screen.res][i].button.button_down()){
664 if (i > CREDITS_BUTTON){
665 Buttons[gr_screen.res][CUTSCENES_BUTTON].button.draw_forced(2);
670 while (y + font_height <= Cutscene_list_coords[gr_screen.res][3]) {
675 if (z == Selected_line){
676 gr_set_color_fast(&Color_text_selected);
677 } else if (z == select_tease_line) {
678 gr_set_color_fast(&Color_text_subselected);
680 gr_set_color_fast(&Color_text_normal);
683 gr_printf(Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1] + y, Cutscenes[Cutscene_list[z]].name);
689 if (Description_index != Selected_line) {
692 Description_index = Selected_line;
694 src = Cutscenes[Cutscene_list[Description_index]].description;
696 Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines, Cutscene_max_text_lines[gr_screen.res]);
697 SDL_assert(Text_size >= 0 && Text_size < Cutscene_max_text_lines[gr_screen.res]);
701 if (Description_index >= 0) {
703 char line[MAX_TEXT_LINE_LEN + 1];
705 gr_set_color_fast(&Color_text_normal);
709 while (y + font_height <= Cutscene_desc_coords[gr_screen.res][3]) {
713 len = Text_line_size[z];
714 if (len > MAX_TEXT_LINE_LEN)
715 len = MAX_TEXT_LINE_LEN;
717 SDL_strlcpy(line, Text_lines[z], len+1);
718 gr_string(Cutscene_desc_coords[gr_screen.res][0], Cutscene_desc_coords[gr_screen.res][1] + y, line);