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/MenuUI/ReadyRoom.cpp $
15 * Ready Room code, which is the UI screen for selecting Campaign/mission to play next mainly.
18 * Revision 1.4 2003/05/25 02:30:42 taylor
21 * Revision 1.3 2002/06/09 04:41:22 relnev
22 * added copyright header
24 * Revision 1.2 2002/06/02 04:26:34 relnev
27 * Revision 1.1.1.1 2002/05/03 03:28:09 root
31 * 20 9/30/99 5:59p Jefff
32 * fixed compile error in OEM ver
34 * 19 9/08/99 12:28p Jefff
36 * 18 9/06/99 6:38p Dave
37 * Improved CD detection code.
39 * 17 9/02/99 2:33p Jefff
40 * column heading coordinate changes
42 * 16 8/22/99 4:16p Jefff
43 * scroll button coord fixes
45 * 15 7/20/99 1:49p Dave
46 * Peter Drake build. Fixed some release build warnings.
48 * 14 7/19/99 2:13p Dave
49 * Added some new strings for Heiko.
51 * 13 7/15/99 9:20a Andsager
52 * FS2_DEMO initial checkin
54 * 12 7/09/99 5:54p Dave
55 * Seperated cruiser types into individual types. Added tons of new
56 * briefing icons. Campaign screen.
58 * 11 2/01/99 5:55p Dave
59 * Removed the idea of explicit bitmaps for buttons. Fixed text
60 * highlighting for disabled gadgets.
62 * 10 1/30/99 9:01p Dave
65 * 9 1/30/99 5:08p Dave
66 * More new hi-res stuff.Support for nice D3D textures.
68 * 8 1/29/99 12:47a Dave
69 * Put in sounds for beam weapon. A bunch of interface screens (tech
72 * 7 12/11/98 4:35p Andsager
73 * Fix sim room bug when no standalone missions
75 * 6 12/07/98 5:02p Dan
76 * Removed improper use of bitmap filename with extension,
78 * 5 10/13/98 9:28a Dave
79 * Started neatening up freespace.h. Many variables renamed and
80 * reorganized. Added AlphaColors.[h,cpp]
94 #include "gamesequence.h"
95 #include "missioncampaign.h"
98 #include "missionscreencommon.h"
99 #include "freespace.h"
100 #include "missionparse.h"
102 #include "managepilot.h"
104 #include "contexthelp.h"
105 #include "cfilesystem.h"
106 #include "freespace.h"
107 #include "alphacolors.h"
109 #define MAX_MISSIONS 1024
111 int Mission_list_coords[GR_NUM_RESOLUTIONS][4] = {
124 int Campaign_list_coords[GR_NUM_RESOLUTIONS][4] = {
138 // x coordinate offsets for data when campaign tab active
140 #define C_SUBTEXT_X 19
142 // x coordinate offsets for data when mission tab active
145 #define MODE_CAMPAIGNS 0
146 #define MODE_MISSIONS 1
148 #define MAX_LINES 200
149 #define MAX_DESC_LINES 200
150 #define NUM_BUTTONS 11
151 #define LIST_BUTTONS_MAX 40
153 #define SCROLL_UP_BUTTON 0
154 #define SCROLL_DOWN_BUTTON 1
155 #define MISSION_TAB 2
156 #define CAMPAIGN_TAB 3
157 #define HELP_BUTTON 4
158 #define COMMIT_BUTTON 5
159 #define OPTIONS_BUTTON 6
160 #define TECH_DATABASE_BUTTON 7
161 #define SIMULATOR_BUTTON 8
162 #define CUTSCENES_BUTTON 9
163 #define CREDITS_BUTTON 10
165 #define CAMPAIGN_MISSION_HASH_SIZE 307
167 struct sim_room_buttons {
171 UI_BUTTON button; // because we have a class inside this struct, we need the constructor below..
173 sim_room_buttons(char *name, int x1, int y1, int xt1, int yt1, int h) : filename(name), x(x1), y(y1), xt(xt1), yt(yt1), hotspot(h) {}
176 static sim_room_buttons Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
180 sim_room_buttons("LMB_04", 7, 135, -1, -1, 4), // up arrows
181 sim_room_buttons("LMB_05", 7, 182, -1, -1, 5), // down arrows
182 sim_room_buttons("LMB_06", 23, 396, -1, -1, 6), // single missions
183 sim_room_buttons("LMB_07", 198, 396, -1, -1, 7), // campaign missions
184 sim_room_buttons("LMB_08", 469, 427, -1, -1, 8), // help
185 sim_room_buttons("LMB_09", 554, 411, -1, -1, 9), // commit
186 sim_room_buttons("LMB_10", 447, 452, -1, -1, 10), // options
188 sim_room_buttons("TDB_00", 0, 0, -1, -1, 0), // technical database
189 sim_room_buttons("TDB_01", 0, 19, -1, -1, 1), // mission simulator
190 sim_room_buttons("TDB_02", 0, 35, -1, -1, 2), // cutscenes
191 sim_room_buttons("TDB_03", 0, 56, -1, -1, 3), // credits
193 sim_room_buttons("LMB_04", 1, 99, -1, -1, 4),
194 sim_room_buttons("LMB_05", 1, 381, -1, -1, 5),
195 sim_room_buttons("LMB_06", 6, 438, 40, 445, 6),
196 sim_room_buttons("LMB_07", 6, 457, 40, 462, 7),
197 sim_room_buttons("LMB_08", 534, 426, 500, 440, 8),
198 sim_room_buttons("LMB_09", 571, 426, 572, 413, 9),
199 sim_room_buttons("LMB_10", 534, 455, 480, 462, 10),
201 sim_room_buttons("TDB_00", 7, 3, 37, 7, 0),
202 sim_room_buttons("TDB_01", 7, 18, 37, 23, 1),
203 sim_room_buttons("TDB_02", 7, 34, 37, 38, 2),
204 sim_room_buttons("TDB_03", 7, 49, 37, 54, 3),
208 sim_room_buttons("2_LMB_04", 2, 159, -1, -1, 4),
209 sim_room_buttons("2_LMB_05", 2, 609, -1, -1, 5),
210 sim_room_buttons("2_LMB_06", 10, 701, 64, 712, 6),
211 sim_room_buttons("2_LMB_07", 10, 732, 64, 739, 7),
212 sim_room_buttons("2_LMB_08", 854, 681, 800, 704, 8),
213 sim_room_buttons("2_LMB_09", 914, 681, 915, 660, 9),
214 sim_room_buttons("2_LMB_10", 854, 728, 800, 728, 10),
216 sim_room_buttons("2_TDB_00", 12, 5, 59, 12, 0),
217 sim_room_buttons("2_TDB_01", 12, 31, 59, 37, 1),
218 sim_room_buttons("2_TDB_02", 12, 56, 59, 62, 2),
219 sim_room_buttons("2_TDB_03", 12, 81, 59, 88, 3),
224 char *Sim_filename[GR_NUM_RESOLUTIONS] = {
228 char *Sim_mask_filename[GR_NUM_RESOLUTIONS] = {
233 char *Campaign_filename[GR_NUM_RESOLUTIONS] = {
237 char *Campaign_mask_filename[GR_NUM_RESOLUTIONS] = {
242 // misc text. ("Mission" and "Filename"
244 #define NUM_SIM_MISC_TEXT 0
246 #define NUM_SIM_MISC_TEXT 2
248 #define SIM_MISC_TEXT_MISSION 0
249 #define SIM_MISC_TEXT_FILENAME 1
250 int Sim_misc_text_coords[GR_NUM_RESOLUTIONS][NUM_SIM_MISC_TEXT][2] = {
252 // nothing needed for FS1
259 // nothing needed for FS1
267 // readyroom text line stuff
268 #define READYROOM_LINE_CAMPAIGN 1
269 #define READYROOM_LINE_CMISSION 2
270 #define READYROOM_LINE_MISSION 3
272 #define READYROOM_FLAG_FROM_VOLITION (1<<0) // volition made
274 #define READYROOM_FLAG_FROM_MDISK (1<<1) // mission disk
277 int type; // see READYROOM_LINE_* defines above
280 int x; // X coordinate of line
281 int y; // Y coordinate of line
282 int flags; // special flags, see READYROOM_FLAG_* defines above
283 } sim_room_lines[MAX_LINES];
285 static char Cur_campaign[MAX_FILENAME_LEN];
286 static char *Mission_filenames[MAX_MISSIONS];
287 static char *Standalone_mission_names[MAX_MISSIONS];
288 static int Standalone_mission_flags[MAX_MISSIONS];
289 static char *Campaign_missions[MAX_MISSIONS];
290 static char *Campaign_mission_names[MAX_CAMPAIGN_MISSIONS];
291 static int Campaign_mission_flags[MAX_MISSIONS];
292 static char *Campaign_descs[MAX_CAMPAIGNS];
293 static char *Campaign_descs_temp[MAX_CAMPAIGNS];
294 static char *Campaign_file_names_temp[MAX_CAMPAIGNS];
295 static int Standalone_mission_names_inited = 0;
296 static int Campaign_names_inited = 0;
297 static int Campaign_mission_names_inited = 0;
298 static int Num_standalone_missions;
299 static int Num_campaign_missions;
300 static int Scroll_offset;
301 static int Selected_line;
302 static int Num_lines;
303 static int Num_campaign_missions_with_info = 0;
304 static int Num_standalone_missions_with_info = 0;
311 static int Background_bitmap;
312 static UI_WINDOW Ui_window;
313 static UI_BUTTON List_buttons[LIST_BUTTONS_MAX]; // buttons for each line of text in list
315 typedef struct hash_node {
320 static hash_node *Campaign_mission_hash_table[CAMPAIGN_MISSION_HASH_SIZE];
321 static int Hash_table_inited;
323 // special icons (1.04 + stuff)
325 #define NUM_MISSION_ICONS 2
327 #define NUM_MISSION_ICONS 1
329 #define MISSION_ICON_VOLITION 0 // mini volition death's head :)
331 #define MISSION_ICON_MDISK 1 // Silent Threat mini icon
334 // icon offsets (see LIST_ defines above
335 //#define MISSION_ICON_VOLITION_X (46)
336 #define MISSION_ICON_VOLITION_Y_OFFSET (-1)
338 #define MISSION_ICON_MDISK_Y_OFFSET (0)
342 static int Sim_volition_icon_x[GR_NUM_RESOLUTIONS] = {
352 static int Sim_silent_icon_x[GR_NUM_RESOLUTIONS] = {
358 // special icons themselves
359 int Mission_icon_bitmaps[NUM_MISSION_ICONS];
361 char *Mission_icon_bitmap_filenames[NUM_MISSION_ICONS] = {
370 void sim_room_load_mission_icons();
371 void sim_room_unload_mission_icons();
372 void sim_room_blit_icons(int line_index, int y_start, fs_builtin_mission *fb = NULL, int is_md = 0);
374 // Finds a hash value for mission filename
376 // returns hash value
377 int hash_filename(char *filename) {
378 unsigned __int64 hash_val = 0;
379 char *ptr = filename;
381 // Dont hash .fsm extension, convert all to upper case
382 for (int i=0; i < ((signed int)(strlen(filename)) - 4); i++) {
383 hash_val = (hash_val << 4) + toupper(*ptr++);
386 return int(hash_val % CAMPAIGN_MISSION_HASH_SIZE);
389 // insert filename into Campaign_mission_hash_table
391 // returns 1 if successful, 0 if could not allocate memory
392 int hash_insert(char *filename) {
393 int hash_val = hash_filename(filename);
396 // Check if table empty
397 if (Campaign_mission_hash_table[hash_val] == NULL) {
398 Campaign_mission_hash_table[hash_val] = new hash_node;
400 cur_node = Campaign_mission_hash_table[hash_val];
402 if (cur_node == NULL) {
403 // Unable to allocate memory
407 // Walk down list to first empty node
408 cur_node = Campaign_mission_hash_table[hash_val];
409 while (cur_node->next != NULL) {
410 cur_node = cur_node->next;
414 cur_node->next = new hash_node;
416 if (cur_node->next == NULL) {
417 // unable to allocate memory
420 cur_node = cur_node->next;
425 cur_node->next = NULL;
426 cur_node->filename = filename;
432 // Checks if a filename already exitst in the hash table
434 // returns 1 if found (collision), 0 if no collision
435 int campaign_mission_hash_collision(char *filename)
437 int hash_val = hash_filename(filename);
438 hash_node *cur_node = Campaign_mission_hash_table[hash_val];
440 if (cur_node == NULL) {
445 if (!stricmp(filename, cur_node->filename)) {
449 cur_node = cur_node->next;
450 } while (cur_node != NULL);
452 // Ran out of stuff to check
456 // builds hash table of campaign mission filenames
458 // returns 1 if successful, 0 if not successful
459 int build_campaign_mission_filename_hash_table()
462 // Go through all campaign missions
463 for (int i=0; i<Num_campaign_missions; i++) {
464 rval = hash_insert(Campaign_missions[i]);
474 // deletes hash table nodes
476 void campaign_mission_hash_table_delete()
480 for (int i=0; i<CAMPAIGN_MISSION_HASH_SIZE; i++) {
481 // Look for entries into array
482 if (Campaign_mission_hash_table[i] != NULL) {
483 cur_node = Campaign_mission_hash_table[i];
485 // Walk down the list deleting self
486 while (cur_node->next != NULL) {
487 hash_node *temp = cur_node->next;
494 Campaign_mission_hash_table[i] = NULL;
500 // add a line of sim_room smuck to end of list
501 int sim_room_line_add(int type, char *name, char *filename, int x, int y, int flags)
503 if (Num_lines >= MAX_LINES)
506 sim_room_lines[Num_lines].type = type;
507 sim_room_lines[Num_lines].name = name;
508 sim_room_lines[Num_lines].filename = filename;
509 sim_room_lines[Num_lines].x = x;
510 sim_room_lines[Num_lines].y = y;
511 sim_room_lines[Num_lines].flags = flags;
515 // filter out all multiplayer campaigns
516 int campaign_room_campaign_filter(char *filename)
518 int type, max_players;
519 char name[NAME_LENGTH], *desc = NULL;
522 // also need to check if this is the builtin campaign
523 if ( game_find_builtin_mission(filename) && mission_campaign_get_info(filename, name, &type, &max_players, &desc) ) {
525 if ( mission_campaign_get_info(filename, name, &type, &max_players, &desc) ) {
527 if ( type == CAMPAIGN_TYPE_SINGLE ) {
528 Campaign_file_names_temp[Num_campaigns] = strdup(filename);
529 Campaign_descs_temp[Num_campaigns++] = desc;
541 // build up a list of all missions in all campaigns.
542 int sim_room_campaign_mission_filter(char *filename)
546 num = mission_campaign_get_mission_list(filename, &Campaign_missions[Num_campaign_missions], MAX_CAMPAIGN_MISSIONS - Num_campaign_missions);
550 Num_campaign_missions += num;
554 // filter out all missions already used in existing campaigns
555 int sim_room_standalone_mission_filter(char *filename)
558 char mission_name[255];
560 // Check if a campaign mission (single and multi)
561 if (campaign_mission_hash_collision(filename)) {
565 // Check if a standalone multi mission OR Mdisk mission with data
566 type = mission_parse_is_multi(filename, mission_name);
567 if (type && !(type & MISSION_TYPE_SINGLE))
573 // builds up list of standalone missions and adds them to missions simulator
574 // processes one mission per frame
576 // returns 1 if finished with all missions, 0 otherwise
578 int build_standalone_mission_list_do_frame()
580 int font_height = gr_get_font_height();
581 char filename[MAX_FILENAME_LEN];
584 // When no standalone missions in data directory
585 if (Num_standalone_missions == 0) {
586 Standalone_mission_names_inited = 1;
590 // Set global variable so we we'll have list available next time
591 Standalone_mission_names[Num_standalone_missions_with_info] = NULL;
592 Standalone_mission_flags[Num_standalone_missions_with_info] = 0;
594 if (Num_standalone_missions > 0) { // sanity check
595 if (strlen(Mission_filenames[Num_standalone_missions_with_info]) < MAX_FILENAME_LEN - 4) { // sanity check?
596 strcpy(filename, Mission_filenames[Num_standalone_missions_with_info]);
600 sprintf(str, XSTR("Single Mission\n\n%s",989), filename);
601 popup_change_text(str);
603 // tack on an extension
604 strcat(filename, FS_MISSION_FILE_EXT);
605 if (!get_mission_info(filename)) {
606 Standalone_mission_names[Num_standalone_missions_with_info] = strdup(The_mission.name);
607 Standalone_mission_flags[Num_standalone_missions_with_info] = The_mission.game_type;
608 int y = Num_lines * (font_height + 2);
610 // determine some extra information
612 fs_builtin_mission *fb = game_find_builtin_mission(filename);
613 if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
614 flags |= READYROOM_FLAG_FROM_VOLITION;
617 if((fb != NULL) && (fb->flags & FSB_FROM_MDISK)){
618 flags |= READYROOM_FLAG_FROM_MDISK;
623 sim_room_line_add(READYROOM_LINE_MISSION, Standalone_mission_names[Num_standalone_missions_with_info], Mission_filenames[Num_standalone_missions_with_info], list_x1 + M_TEXT_X, y, flags);
627 Num_standalone_missions_with_info++;
630 if (Num_standalone_missions_with_info == Num_standalone_missions) {
631 Standalone_mission_names_inited = 1;
638 // builds up list of already played missions in a campaign and adds them to missions simulator
639 // processes one mission per frame
641 // returns 1 if finished with all missions, 0 otherwise
643 int build_campaign_mission_list_do_frame()
645 int font_height = gr_get_font_height();
648 // When no campaign files in data directory
649 if (Campaign.num_missions == 0) {
650 Campaign_mission_names_inited = 1;
656 sprintf(str, XSTR("Campaign Mission\n\n%s",990), Campaign.missions[Num_campaign_missions_with_info].name);
657 popup_change_text(str);
659 // Set global variable so we we'll have list available next time
660 Campaign_mission_names[Num_campaign_missions_with_info] = NULL;
661 Campaign_mission_flags[Num_campaign_missions_with_info] = 0;
663 // Only allow missions already completed
664 if (Campaign.missions[Num_campaign_missions_with_info].completed) {
665 if (!get_mission_info(Campaign.missions[Num_campaign_missions_with_info].name)) {
667 Campaign_mission_names[Num_campaign_missions_with_info] = strdup(The_mission.name);
668 Campaign_mission_flags[Num_campaign_missions_with_info] = The_mission.game_type;
669 int y = Num_campaign_missions_with_info * (font_height + 2);
671 // determine some extra information
673 fs_builtin_mission *fb = game_find_builtin_mission(Campaign.missions[Num_campaign_missions_with_info].name);
674 if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
675 flags |= READYROOM_FLAG_FROM_VOLITION;
679 if((fb != NULL) && (fb->flags & FSB_FROM_MDISK)){
680 flags |= READYROOM_FLAG_FROM_MDISK;
684 sim_room_line_add(READYROOM_LINE_CMISSION, Campaign_mission_names[Num_campaign_missions_with_info], Campaign.missions[Num_campaign_missions_with_info].name, list_x1 + C_SUBTEXT_X, y, flags);
688 Num_campaign_missions_with_info++;
690 if (Num_campaign_missions_with_info == Campaign.num_missions) {
691 Campaign_mission_names_inited = 1;
698 // Builds list of either (1) standalone missions or (2) already played missions in current campaign
699 // First time through, it builds list, next time it uses precompiled list
700 void sim_room_build_listing()
703 int font_height = gr_get_font_height();
704 char full_filename[256];
707 list_y = Mission_list_coords[gr_screen.res][1];
708 list_h = Mission_list_coords[gr_screen.res][3];
710 // Stand alone single player missions.
711 if (Player->readyroom_listing_mode == MODE_MISSIONS) {
712 if (Hash_table_inited) {
713 if (!Standalone_mission_names_inited) { // Is this the first time through
714 // build_list_do_frame builds list and adds sim room line and sets Standalone_mission_names_inited
715 popup_till_condition(build_standalone_mission_list_do_frame, POPUP_CANCEL, XSTR("Loading missions", 991) );
717 for (i=0; i<Num_standalone_missions_with_info; i++) {
718 if (Standalone_mission_names[i]) {
719 // determine some extra information
721 memset(full_filename, 0, 256);
722 strcpy(full_filename, cf_add_ext(Mission_filenames[i], FS_MISSION_FILE_EXT));
723 fs_builtin_mission *fb = game_find_builtin_mission(full_filename);
724 if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
725 flags |= READYROOM_FLAG_FROM_VOLITION;
729 if((fb != NULL) && (fb->flags & FSB_FROM_MDISK)){
730 flags |= READYROOM_FLAG_FROM_MDISK;
734 sim_room_line_add(READYROOM_LINE_MISSION, Standalone_mission_names[i], Mission_filenames[i], list_x1 + M_TEXT_X, y, flags);
735 y += font_height + 2;
742 list_y += font_height + 2;
743 list_h -= font_height - 2;
745 if (!Campaign_mission_names_inited) { // Is this the first time through
746 popup_till_condition(build_campaign_mission_list_do_frame, POPUP_CANCEL, XSTR("Loading campaign missions",992));
747 // builds list, adds sim room line and sets Campaign_mission_names_inited
749 for (i=0; i<Num_campaign_missions_with_info; i++) {
750 if (Campaign_mission_names[i]) {
751 // determine some extra information
753 memset(full_filename, 0, 256);
754 strcpy(full_filename, cf_add_ext(Campaign.missions[i].name, FS_MISSION_FILE_EXT));
755 fs_builtin_mission *fb = game_find_builtin_mission(full_filename);
756 if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
757 flags |= READYROOM_FLAG_FROM_VOLITION;
761 if((fb != NULL) && (fb->flags & FSB_FROM_MDISK)){
762 flags |= READYROOM_FLAG_FROM_MDISK;
766 sim_room_line_add(READYROOM_LINE_CMISSION, Campaign_mission_names[i], Campaign.missions[i].name, list_x1 + C_SUBTEXT_X, y, flags);
774 int sim_room_line_query_visible(int n)
778 if ((n < 0) || (n >= Num_lines))
781 y = sim_room_lines[n].y - sim_room_lines[Scroll_offset].y;
782 if ((y < 0) || (y + gr_get_font_height() > list_h))
788 void sim_room_scroll_screen_up()
790 if (Player->readyroom_listing_mode != MODE_MISSIONS) {
793 gamesnd_play_iface(SND_SCROLL);
796 gamesnd_play_iface(SND_GENERAL_FAIL);
803 Assert(Selected_line > Scroll_offset);
804 while (!sim_room_line_query_visible(Selected_line))
807 gamesnd_play_iface(SND_SCROLL);
810 gamesnd_play_iface(SND_GENERAL_FAIL);
813 void sim_room_scroll_line_up()
817 if (Selected_line < Scroll_offset)
818 Scroll_offset = Selected_line;
820 gamesnd_play_iface(SND_SCROLL);
823 gamesnd_play_iface(SND_GENERAL_FAIL);
826 void sim_room_scroll_screen_down()
828 if (Player->readyroom_listing_mode != MODE_MISSIONS) {
829 if (sim_room_lines[Num_lines - 1].y + gr_get_font_height() > sim_room_lines[Scroll_offset].y + list_h) {
831 gamesnd_play_iface(SND_SCROLL);
834 gamesnd_play_iface(SND_GENERAL_FAIL);
839 if (sim_room_lines[Num_lines - 1].y + gr_get_font_height() > sim_room_lines[Scroll_offset].y + list_h) {
841 while (!sim_room_line_query_visible(Selected_line)) {
843 Assert(Selected_line < Num_lines);
846 gamesnd_play_iface(SND_SCROLL);
849 gamesnd_play_iface(SND_GENERAL_FAIL);
852 void sim_room_scroll_line_down()
854 if (Selected_line < Num_lines - 1) {
857 Assert(Selected_line > Scroll_offset);
858 while (!sim_room_line_query_visible(Selected_line))
861 gamesnd_play_iface(SND_SCROLL);
864 gamesnd_play_iface(SND_GENERAL_FAIL);
867 // returns: 0 = success, !0 = aborted or failed
868 int ready_room_reset_campaign()
872 z = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_CANCEL, POPUP_OK, XSTR( "Warning\nThis will cause all progress in your\ncurrent campaign to be lost", 110) );
875 mission_campaign_savefile_delete(Campaign.filename);
876 mission_campaign_load(Campaign.filename);
883 // Decide if we should offer choice to resume this savegame
884 int sim_room_can_resume_savegame(char *savegame_filename)
886 #ifdef FREESPACE_SAVERESTORE_SYSTEM
887 char savegame_mission[MAX_FILENAME_LEN];
889 if (state_read_description(savegame_filename, NULL, savegame_mission)) {
893 if (stricmp(Game_current_mission_filename, savegame_mission)) {
903 // Decide wether to resume a save game or not
904 // exit: 1 => savegame has been restored
905 // 0 => no restore, proceed to briefing
906 // -1 => don't start mission at all
907 int sim_room_maybe_resume_savegame()
909 // MWA -- 3/26/98 -- removed all savegame references in game
913 char savegame_filename[_MAX_FNAME];
914 int popup_rval = -1, resume_savegame = 0;
916 // Generate the save-game filename for this campaign
917 memset(savegame_filename, 0, _MAX_FNAME);
918 mission_campaign_savefile_generate_root(savegame_filename);
919 strcat(savegame_filename, NOX("svg"));
921 // Decide if we should offer choice to resume this savegame
922 if ( sim_room_can_resume_savegame(savegame_filename) ) {
923 popup_rval = popup(0, 3, XSTR("&Cancel",-1), XSTR("&Overwrite",-1), XSTR("&Resume",-1), XSTR("A save game for this mission exists.", -1));
924 switch ( popup_rval ) {
927 resume_savegame = -1;
937 resume_savegame = -1;
944 if (resume_savegame == 1) {
945 if ( state_restore_all(savegame_filename) == -1 ) {
946 popup_rval = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_NO, POPUP_YES, XSTR("Error\nSaved misison could not be loaded.\nDo you wish to start this mission from the beginning?", -1));
947 if (popup_rval == 1) {
950 resume_savegame = -1;
958 // If we are resuming this savegame, then delete the file
959 if (resume_savegame == 1) {
960 cf_delete(savegame_filename);
963 return resume_savegame;
967 int readyroom_continue_campaign()
969 if (mission_campaign_next_mission()) { // is campaign and next mission valid?
971 #if defined(FS2_DEMO) || defined(FS1_DEMO)
972 int reset_campaign = 0;
973 reset_campaign = popup(PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Demo Campaign Is Over. Would you like to play the campaign again?", 111) );
974 if ( reset_campaign == 1 ) {
975 mission_campaign_savefile_delete(Campaign.filename);
976 mission_campaign_load(Campaign.filename);
977 mission_campaign_next_mission();
982 gamesnd_play_iface(SND_GENERAL_FAIL);
984 // make it the bottom button so that the graphic looks right
985 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "The campaign is over. To replay the campaign, either create a new pilot or restart the campaign in the campaign room.", 112) );
987 popup(0, 1, POPUP_OK, XSTR( "The campaign is over. To replay the campaign, either create a new pilot or restart the campaign in the campaign room.", 112) );
994 if(!game_do_cd_mission_check(Game_current_mission_filename)){
998 // set the bit for campaign mode
999 Game_mode |= GM_CAMPAIGN_MODE;
1000 gameseq_post_event( GS_EVENT_START_GAME );
1005 void sim_room_commit()
1007 if ((Selected_line >= Num_lines) || !sim_room_lines[Selected_line].filename) {
1008 gamesnd_play_iface(SND_GENERAL_FAIL);
1012 strncpy(Game_current_mission_filename, sim_room_lines[Selected_line].filename, MAX_FILENAME_LEN);
1014 Game_mode &= ~(GM_CAMPAIGN_MODE); // be sure this bit is clear
1017 if(game_do_cd_mission_check(Game_current_mission_filename)){
1018 // don't resume savegame, proceed to briefing
1019 gameseq_post_event(GS_EVENT_START_GAME);
1020 gamesnd_play_iface(SND_COMMIT_PRESSED);
1024 int sim_room_button_pressed(int n)
1027 case SCROLL_UP_BUTTON:
1028 sim_room_scroll_screen_up();
1031 case SCROLL_DOWN_BUTTON:
1032 sim_room_scroll_screen_down();
1037 game_feature_not_in_demo_popup();
1038 // gamesnd_play_iface(SND_GENERAL_FAIL);
1041 Player->readyroom_listing_mode = MODE_MISSIONS;
1042 Selected_line = Scroll_offset = 0;
1043 gamesnd_play_iface(SND_USER_SELECT);
1044 sim_room_build_listing();
1049 Player->readyroom_listing_mode = MODE_CAMPAIGNS;
1051 gamesnd_play_iface(SND_USER_SELECT);
1052 sim_room_build_listing();
1060 launch_context_help();
1061 gamesnd_play_iface(SND_HELP_PRESSED);
1064 case OPTIONS_BUTTON:
1065 gamesnd_play_iface(SND_SWITCH_SCREENS);
1066 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
1069 case TECH_DATABASE_BUTTON:
1070 gamesnd_play_iface(SND_SWITCH_SCREENS);
1071 gameseq_post_event(GS_EVENT_TECH_MENU);
1074 case CUTSCENES_BUTTON:
1075 gamesnd_play_iface(SND_SWITCH_SCREENS);
1076 gameseq_post_event(GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN);
1079 case CREDITS_BUTTON:
1080 gamesnd_play_iface(SND_SWITCH_SCREENS);
1081 gameseq_post_event(GS_EVENT_CREDITS);
1088 // ---------------------------------------------------------------------
1089 // mission_sim_room_init()
1091 // Initialize the sim_room assignment screen system. Called when GS_STATE_sim_room_SCREEN
1094 void sim_room_init()
1097 sim_room_buttons *b;
1098 char wild_card[256];
1100 list_x1 = Mission_list_coords[gr_screen.res][0];
1101 list_x2 = Campaign_list_coords[gr_screen.res][0];
1102 list_y = Mission_list_coords[gr_screen.res][1];
1103 list_w1 = Mission_list_coords[gr_screen.res][2];
1104 list_w2 = Campaign_list_coords[gr_screen.res][2];
1105 list_h = Mission_list_coords[gr_screen.res][3];
1107 // force mode to valid range. I once had a bogus value here. Don't know how that happened, though.
1108 if (Player->readyroom_listing_mode != MODE_MISSIONS)
1109 Player->readyroom_listing_mode = MODE_CAMPAIGNS;
1111 *Game_current_mission_filename = 0;
1112 common_set_interface_palette("InterfacePalette"); // set the interface palette
1113 Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
1114 Ui_window.set_mask_bmap(Sim_mask_filename[gr_screen.res]);
1116 for (i=0; i<NUM_BUTTONS; i++) {
1117 b = &Buttons[gr_screen.res][i];
1119 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
1120 // set up callback for when a mouse first goes over a button
1121 b->button.set_highlight_action(common_play_highlight_sound);
1122 b->button.set_bmaps(b->filename);
1123 b->button.link_hotspot(b->hotspot);
1127 // screen/button specific text
1128 Ui_window.add_XSTR("Single Missions", 1060, Buttons[gr_screen.res][MISSION_TAB].xt, Buttons[gr_screen.res][MISSION_TAB].yt, &Buttons[gr_screen.res][MISSION_TAB].button, UI_XSTR_COLOR_GREEN);
1129 Ui_window.add_XSTR("Campaign Missions", 1061, Buttons[gr_screen.res][CAMPAIGN_TAB].xt, Buttons[gr_screen.res][CAMPAIGN_TAB].yt, &Buttons[gr_screen.res][CAMPAIGN_TAB].button, UI_XSTR_COLOR_GREEN);
1130 Ui_window.add_XSTR("Help", 928, Buttons[gr_screen.res][HELP_BUTTON].xt, Buttons[gr_screen.res][HELP_BUTTON].yt, &Buttons[gr_screen.res][HELP_BUTTON].button, UI_XSTR_COLOR_GREEN);
1131 Ui_window.add_XSTR("Commit", 1062, Buttons[gr_screen.res][COMMIT_BUTTON].xt, Buttons[gr_screen.res][COMMIT_BUTTON].yt, &Buttons[gr_screen.res][COMMIT_BUTTON].button, UI_XSTR_COLOR_PINK);
1132 Ui_window.add_XSTR("Options", 1036, Buttons[gr_screen.res][OPTIONS_BUTTON].xt, Buttons[gr_screen.res][OPTIONS_BUTTON].yt, &Buttons[gr_screen.res][OPTIONS_BUTTON].button, UI_XSTR_COLOR_GREEN);
1134 // common tab button text
1135 Ui_window.add_XSTR("Technical Database", 1055, Buttons[gr_screen.res][TECH_DATABASE_BUTTON].xt, Buttons[gr_screen.res][TECH_DATABASE_BUTTON].yt, &Buttons[gr_screen.res][TECH_DATABASE_BUTTON].button, UI_XSTR_COLOR_GREEN);
1136 Ui_window.add_XSTR("Mission Simulator", 1056, Buttons[gr_screen.res][SIMULATOR_BUTTON].xt, Buttons[gr_screen.res][SIMULATOR_BUTTON].yt, &Buttons[gr_screen.res][SIMULATOR_BUTTON].button, UI_XSTR_COLOR_GREEN);
1137 Ui_window.add_XSTR("Cutscenes", 1057, Buttons[gr_screen.res][CUTSCENES_BUTTON].xt, Buttons[gr_screen.res][CUTSCENES_BUTTON].yt, &Buttons[gr_screen.res][CUTSCENES_BUTTON].button, UI_XSTR_COLOR_GREEN);
1138 Ui_window.add_XSTR("Credits", 1058, Buttons[gr_screen.res][CREDITS_BUTTON].xt, Buttons[gr_screen.res][CREDITS_BUTTON].yt, &Buttons[gr_screen.res][CREDITS_BUTTON].button, UI_XSTR_COLOR_GREEN);
1140 // misc text - not associated with any buttons
1141 Ui_window.add_XSTR("Mission", 1063, Sim_misc_text_coords[gr_screen.res][SIM_MISC_TEXT_MISSION][0], Sim_misc_text_coords[gr_screen.res][SIM_MISC_TEXT_MISSION][1], NULL, UI_XSTR_COLOR_GREEN);
1142 Ui_window.add_XSTR("Filename", 1064, Sim_misc_text_coords[gr_screen.res][SIM_MISC_TEXT_FILENAME][0], Sim_misc_text_coords[gr_screen.res][SIM_MISC_TEXT_FILENAME][1], NULL, UI_XSTR_COLOR_GREEN);
1145 for (i=0; i<LIST_BUTTONS_MAX; i++) {
1146 List_buttons[i].create(&Ui_window, "", 0, 0, 60, 30, 0, 1);
1147 List_buttons[i].hide();
1148 List_buttons[i].disable();
1151 // set up sim_rooms for buttons so we draw the correct animation frame when a key is pressed
1152 Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
1153 Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
1154 Buttons[gr_screen.res][COMMIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
1156 Background_bitmap = bm_load(Sim_filename[gr_screen.res]);
1158 // load in help overlay bitmap
1159 help_overlay_load(SIM_ROOM_OVERLAY);
1160 help_overlay_set_state(SIM_ROOM_OVERLAY,0);
1162 Scroll_offset = Selected_line = 0;
1164 strcpy(Cur_campaign, Player->current_campaign);
1165 mission_load_up_campaign();
1166 mission_campaign_next_mission();
1168 Num_campaigns = Num_campaign_missions = 0;
1169 Get_file_list_filter = sim_room_campaign_mission_filter;
1170 memset(wild_card, 0, 256);
1171 strcpy(wild_card, NOX("*"));
1172 strcat(wild_card, FS_CAMPAIGN_FILE_EXT);
1173 Num_campaigns = cf_get_file_list(MAX_CAMPAIGNS, Campaign_file_names, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME);
1175 Hash_table_inited = 0;
1176 if (build_campaign_mission_filename_hash_table()) {
1177 Hash_table_inited = 1;
1181 GR_MAYBE_CLEAR_RES(Background_bitmap);
1182 if(Background_bitmap != -1){
1183 gr_set_bitmap(Background_bitmap);
1189 Get_file_list_filter = sim_room_standalone_mission_filter;
1190 memset(wild_card, 0, 256);
1191 strcpy(wild_card, NOX("*"));
1192 strcat(wild_card, FS_MISSION_FILE_EXT);
1193 Num_standalone_missions = cf_get_file_list(MAX_MISSIONS, Mission_filenames, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME);
1195 Num_campaign_missions_with_info = Num_standalone_missions_with_info = Standalone_mission_names_inited = Campaign_names_inited = Campaign_mission_names_inited = 0;
1196 sim_room_build_listing();
1198 // load special mission icons
1199 sim_room_load_mission_icons();
1202 // ---------------------------------------------------------------------
1205 // Cleanup the sim_room assignment screen system. Called when GS_STATE_sim_room_SCREEN
1208 void sim_room_close()
1212 for (i=0; i<Num_campaign_missions; i++)
1213 if (Campaign_missions[i])
1214 free(Campaign_missions[i]);
1216 if (Background_bitmap >= 0)
1217 bm_unload(Background_bitmap);
1219 if (Standalone_mission_names_inited){
1220 for (i=0; i<Num_standalone_missions; i++){
1221 if (Standalone_mission_names[i]){
1222 free(Standalone_mission_names[i]);
1224 Standalone_mission_flags[i] = 0;
1228 if (Campaign_names_inited)
1229 for (i=0; i<Num_campaigns; i++)
1230 if (Campaign_names[i])
1231 free(Campaign_names[i]);
1233 if (Campaign_mission_names_inited)
1234 for (i=0; i<Campaign.num_missions; i++)
1235 if (Campaign_mission_names[i])
1236 free(Campaign_mission_names[i]);
1238 for (i=0; i<Num_campaigns; i++)
1239 free(Campaign_file_names[i]);
1241 for (i=0; i<Num_standalone_missions; i++)
1242 free(Mission_filenames[i]);
1244 // unload the overlay bitmap
1245 help_overlay_unload(SIM_ROOM_OVERLAY);
1247 campaign_mission_hash_table_delete();
1249 Ui_window.destroy();
1250 common_free_interface_palette(); // restore game palette
1253 // unload special mission icons
1254 sim_room_unload_mission_icons();
1257 // ---------------------------------------------------------------------
1258 // sim_room_do_frame()
1260 // Called once per frame to process user input for the sim_room Assignment Screen
1262 void sim_room_do_frame(float frametime)
1265 int i, k, y, z, line;
1266 int font_height = gr_get_font_height();
1267 int select_tease_line = -1; // line mouse is down on, but won't be selected until button released
1270 for (i=0; i<Num_campaigns; i++)
1271 if (!stricmp(Campaign_file_names[i], Campaign.filename)) {
1276 if ( help_overlay_active(SIM_ROOM_OVERLAY) ) {
1277 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
1278 Ui_window.set_ignore_gadgets(1);
1281 k = Ui_window.process() & ~KEY_DEBUGGED;
1283 if ( (k > 0) || B1_JUST_RELEASED ) {
1284 if ( help_overlay_active(SIM_ROOM_OVERLAY) ) {
1285 help_overlay_set_state(SIM_ROOM_OVERLAY, 0);
1286 Ui_window.set_ignore_gadgets(0);
1291 if ( !help_overlay_active(SIM_ROOM_OVERLAY) ) {
1292 Ui_window.set_ignore_gadgets(0);
1296 case KEY_DOWN: // scroll list down
1297 sim_room_scroll_line_down();
1300 case KEY_UP: // scroll list up
1301 sim_room_scroll_line_up();
1305 gameseq_post_event(GS_EVENT_MAIN_MENU);
1308 case KEY_CTRLED | KEY_UP:
1309 sim_room_button_pressed(TECH_DATABASE_BUTTON);
1312 case KEY_CTRLED | KEY_DOWN:
1313 sim_room_button_pressed(CUTSCENES_BUTTON);
1317 if (Player->readyroom_listing_mode == MODE_CAMPAIGNS)
1318 Player->readyroom_listing_mode = MODE_MISSIONS;
1320 Player->readyroom_listing_mode = MODE_CAMPAIGNS;
1322 Selected_line = Scroll_offset = 0;
1323 gamesnd_play_iface(SND_USER_SELECT);
1324 sim_room_build_listing();
1328 gamesnd_play_iface(SND_SWITCH_SCREENS);
1329 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
1333 for (i=0; i<NUM_BUTTONS; i++){
1334 if (Buttons[gr_screen.res][i].button.pressed()){
1335 if (sim_room_button_pressed(i)){
1341 for (i=0; i<LIST_BUTTONS_MAX; i++) {
1342 if (List_buttons[i].is_mouse_on())
1343 select_tease_line = i + Scroll_offset;
1345 if (List_buttons[i].pressed()) {
1346 Selected_line = i + Scroll_offset;
1347 gamesnd_play_iface(SND_USER_SELECT);
1351 GR_MAYBE_CLEAR_RES(Background_bitmap);
1352 if (Background_bitmap >= 0) {
1353 gr_set_bitmap(Background_bitmap);
1359 for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
1360 if (Buttons[gr_screen.res][i].button.button_down()){
1365 if (i > CREDITS_BUTTON){
1366 Buttons[gr_screen.res][SIMULATOR_BUTTON].button.draw_forced(2);
1369 if (!Buttons[gr_screen.res][CAMPAIGN_TAB].button.button_down() && !Buttons[gr_screen.res][MISSION_TAB].button.button_down()) {
1370 if (Player->readyroom_listing_mode == MODE_CAMPAIGNS){
1371 Buttons[gr_screen.res][CAMPAIGN_TAB].button.draw_forced(2);
1372 } else if (Player->readyroom_listing_mode == MODE_MISSIONS){
1373 Buttons[gr_screen.res][MISSION_TAB].button.draw_forced(2);
1378 if (Player->readyroom_listing_mode == MODE_CAMPAIGNS) {
1379 gr_set_color_fast(&Color_text_heading);
1380 strcpy(buf, Campaign.name);
1381 gr_force_fit_string(buf, 255, list_w1);
1382 gr_printf(list_x1, Mission_list_coords[gr_screen.res][1], buf);
1384 if (Campaign.filename) {
1385 sprintf(buf, NOX("%s%s"), Campaign.filename, FS_CAMPAIGN_FILE_EXT);
1386 gr_force_fit_string(buf, 255, list_w2);
1387 gr_printf(list_x2, Mission_list_coords[gr_screen.res][1], buf);
1389 // blit the proper icons if necessary
1390 char full_name[256];
1391 memset(full_name, 0, 256);
1392 strcpy(full_name, cf_add_ext(Campaign.filename,FS_CAMPAIGN_FILE_EXT));
1393 fs_builtin_mission *fb = game_find_builtin_mission(full_name);
1395 // sim_room_blit_icons(0, Mission_list_coords[gr_screen.res][1], fb, 0);
1400 line = Scroll_offset;
1401 while (sim_room_line_query_visible(line)) {
1402 y = list_y + sim_room_lines[line].y - sim_room_lines[Scroll_offset].y;
1404 if (sim_room_lines[line].type != READYROOM_LINE_CAMPAIGN) {
1405 List_buttons[line - Scroll_offset].update_dimensions(list_x1, y, list_x2 + list_w2 - list_x1, font_height);
1406 List_buttons[line - Scroll_offset].enable();
1409 List_buttons[line - Scroll_offset].disable();
1411 if (line == Selected_line)
1412 gr_set_color_fast(&Color_text_selected);
1413 else if (line == select_tease_line)
1414 gr_set_color_fast(&Color_text_subselected);
1416 gr_set_color_fast(&Color_text_normal);
1418 strcpy(buf, sim_room_lines[line].name);
1419 gr_force_fit_string(buf, 255, list_x1 + list_w1 - sim_room_lines[line].x);
1420 gr_printf(sim_room_lines[line].x, y, buf);
1422 if (sim_room_lines[line].filename) {
1423 strcpy(buf, sim_room_lines[line].filename);
1424 gr_force_fit_string(buf, 255, list_w2);
1425 gr_printf(list_x2, y, buf);
1428 // blit additional icon information
1429 sim_room_blit_icons(line, y);
1434 i = line - Scroll_offset;
1435 while (i < LIST_BUTTONS_MAX)
1436 List_buttons[i++].disable();
1438 // blit help overlay if active
1439 help_overlay_maybe_blit(SIM_ROOM_OVERLAY);
1444 void sim_room_blit_icons(int line_index, int y_start, fs_builtin_mission *fb, int is_md)
1446 int is_from_volition = 0;
1448 // determine icon status
1450 is_from_volition = (sim_room_lines[line_index].flags & READYROOM_FLAG_FROM_VOLITION) ? 1 : 0;
1452 is_md = (sim_room_lines[line_index].flags & READYROOM_FLAG_FROM_MDISK) ? 1 : 0;
1455 is_from_volition = (fb->flags & FSB_FROM_VOLITION) ? 1 : 0;
1457 is_md = (fb->flags & FSB_FROM_MDISK) ? 1 : 0;
1461 // if the line is flagged as a volition file
1462 if(is_from_volition && (Mission_icon_bitmaps[MISSION_ICON_VOLITION] >= 0)){
1463 gr_set_bitmap(Mission_icon_bitmaps[MISSION_ICON_VOLITION]);
1464 gr_bitmap(Sim_volition_icon_x[gr_screen.res], y_start + MISSION_ICON_VOLITION_Y_OFFSET);
1468 if(is_md && (Mission_icon_bitmaps[MISSION_ICON_MDISK] >= 0)){
1469 gr_set_bitmap(Mission_icon_bitmaps[MISSION_ICON_MDISK]);
1470 gr_bitmap(Sim_silent_icon_x[gr_screen.res], y_start + MISSION_ICON_MDISK_Y_OFFSET);
1475 /// Campaign room stuff below
1476 int Cr_list_coords[GR_NUM_RESOLUTIONS][4] = {
1489 int Cr_info_coords[GR_NUM_RESOLUTIONS][4] = {
1502 #define CR_NUM_BUTTONS 6
1504 #define CR_SCROLL_UP_BUTTON 0
1505 #define CR_SCROLL_DOWN_BUTTON 1
1506 #define CR_SCROLL_INFO_UP_BUTTON 2
1507 #define CR_SCROLL_INFO_DOWN_BUTTON 3
1508 #define CR_RESET_BUTTON 4
1509 #define CR_COMMIT_BUTTON 5
1511 #define MAX_INFO_LINES 20
1513 #define MAX_INFO_LINE_LEN 256
1515 ui_button_info Cr_buttons[GR_NUM_RESOLUTIONS][CR_NUM_BUTTONS] = {
1518 ui_button_info("CAB_00", 0, 95, -1, -1, 0), // scroll up
1519 ui_button_info("CAB_01", 0, 142, -1, -1, 1), // scroll down
1520 ui_button_info("CAB_02", 17, 259, -1, -1, 2), // info scroll up
1521 ui_button_info("CAB_03", 17, 307, -1, -1, 3), // info scroll down
1522 ui_button_info("CAB_07", 545, 323, -1, -1, 7), // reset
1523 ui_button_info("CAB_04", 561, 411, -1, -1, 4), // select
1525 ui_button_info("CAB_00", 2, 42, -1, -1, 0),
1526 ui_button_info("CAB_01", 2, 89, -1, -1, 1),
1527 ui_button_info("CAB_02", 2, 279, -1, -1, 2),
1528 ui_button_info("CAB_03", 2, 325, -1, -1, 3),
1529 ui_button_info("CAB_04", 579, 353, -1, -1, 4),
1530 ui_button_info("CAB_05", 575, 434, -1, -1, 5),
1534 ui_button_info("2_CAB_00", 3, 68, -1, -1, 0),
1535 ui_button_info("2_CAB_01", 3, 142, -1, -1, 1),
1536 ui_button_info("2_CAB_02", 3, 446, -1, -1, 2),
1537 ui_button_info("2_CAB_03", 3, 520, -1, -1, 3),
1538 ui_button_info("2_CAB_04", 927, 565, -1, -1, 4),
1539 ui_button_info("2_CAB_05", 920, 694, -1, -1, 5),
1545 #define CR_NUM_TEXT 0
1547 #define CR_NUM_TEXT 3
1549 UI_XSTR Cr_text[GR_NUM_RESOLUTIONS][CR_NUM_TEXT] = {
1551 // not needed for FS1
1553 { "Restart", 1403, 569, 326, UI_XSTR_COLOR_GREEN, -1, &Cr_buttons[0][CR_RESET_BUTTON].button },
1554 { "Campaign", 1404, 569, 337, UI_XSTR_COLOR_GREEN, -1, &Cr_buttons[0][CR_RESET_BUTTON].button },
1555 { "Select", 1409, 568, 413, UI_XSTR_COLOR_PINK, -1, &Cr_buttons[0][CR_COMMIT_BUTTON].button },
1559 // not needed for FS1
1561 { "Restart", 1403, 922, 523, UI_XSTR_COLOR_GREEN, -1, &Cr_buttons[1][CR_RESET_BUTTON].button },
1562 { "Campaign", 1404, 922, 538, UI_XSTR_COLOR_GREEN, -1, &Cr_buttons[1][CR_RESET_BUTTON].button },
1563 { "Select", 1409, 921, 665, UI_XSTR_COLOR_PINK, -1, &Cr_buttons[1][CR_COMMIT_BUTTON].button },
1568 static int Num_desc_lines;
1569 static int Desc_scroll_offset;
1570 static int Selected_campaign_index;
1571 static int Active_campaign_index;
1573 char *Info_text_ptrs[MAX_INFO_LINES];
1574 int Num_info_lines, Info_text_line_size[MAX_INFO_LINES];
1576 void campaign_room_build_listing()
1578 int c, i, y, type, max_players;
1579 int font_height = gr_get_font_height();
1580 char name[NAME_LENGTH];
1583 if (!Campaign_names_inited) {
1584 for (i=0; i<Num_campaigns; i++) {
1585 Campaign_names[i] = NULL;
1586 if ( mission_campaign_get_info(Campaign_file_names[i], name, &type, &max_players) ) {
1588 if((game_find_builtin_mission(name) == NULL) && !strstr(name, "peterdrake")){
1591 Campaign_names[i] = strdup(name);
1594 if (type == CAMPAIGN_TYPE_SINGLE){
1595 Campaign_names[i] = strdup(name);
1601 Campaign_names_inited = 1;
1604 for (c=0; c<Num_campaigns; c++) {
1605 if (Campaign_names[c]) {
1607 // determine some extra information
1609 fs_builtin_mission *fb = game_find_builtin_mission(Campaign_file_names[c]);
1611 if(fb->flags & FSB_FROM_VOLITION){
1612 flags |= READYROOM_FLAG_FROM_VOLITION;
1615 if(fb->flags & FSB_FROM_MDISK){
1616 flags |= READYROOM_FLAG_FROM_MDISK;
1621 sim_room_line_add(READYROOM_LINE_CAMPAIGN, Campaign_names[c], Campaign_file_names[c], Cr_list_coords[gr_screen.res][0], y, flags);
1622 y += font_height + 2;
1627 void set_new_campaign_line(int n)
1631 Selected_campaign_index = n;
1632 str = Campaign_descs[Selected_campaign_index];
1635 Num_info_lines = split_str(str, Cr_info_coords[gr_screen.res][2], Info_text_line_size, Info_text_ptrs, MAX_INFO_LINES);
1636 Assert(Num_info_lines >= 0);
1639 Desc_scroll_offset = 0;
1642 void campaign_room_scroll_info_up()
1644 if (Desc_scroll_offset) {
1645 Desc_scroll_offset--;
1646 gamesnd_play_iface(SND_SCROLL);
1649 gamesnd_play_iface(SND_GENERAL_FAIL);
1652 void campaign_room_scroll_info_down()
1654 if ( (Num_info_lines - Desc_scroll_offset) * gr_get_font_height() > Cr_info_coords[gr_screen.res][3]) {
1655 Desc_scroll_offset++;
1656 gamesnd_play_iface(SND_SCROLL);
1659 gamesnd_play_iface(SND_GENERAL_FAIL);
1662 // returns: 0 = success, !0 = aborted or failed
1663 int campaign_room_reset_campaign(int n)
1668 // z = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_CANCEL, POPUP_OK, XSTR( "Warning\nThis will cause all progress in your\ncurrent campaign to be lost", 110), Campaign_names[n]);
1669 z = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_CANCEL, POPUP_OK, XSTR( "Warning\nThis will cause all progress in your\ncurrent campaign to be lost", 110));
1671 filename = (char *) malloc(strlen(Campaign_file_names[n]) + 5);
1672 strcpy(filename, Campaign_file_names[n]);
1673 strcat(filename, FS_CAMPAIGN_FILE_EXT);
1675 mission_campaign_savefile_delete(filename);
1676 mission_campaign_load(filename);
1677 mission_campaign_next_mission();
1684 void campaign_room_commit()
1686 if (Selected_campaign_index < 0) {
1687 gamesnd_play_iface(SND_GENERAL_FAIL);
1691 if (stricmp(Campaign_file_names[Selected_campaign_index], Campaign.filename)) { // new campaign selected
1692 if ((Active_campaign_index >= 0) && campaign_room_reset_campaign(Active_campaign_index)) {
1693 gamesnd_play_iface(SND_GENERAL_FAIL);
1697 mission_campaign_savefile_delete(Campaign_file_names[Selected_campaign_index]);
1698 mission_campaign_load(Campaign_file_names[Selected_campaign_index]);
1699 strcpy(Player->current_campaign, Campaign.filename); // track new campaign for player
1702 if (mission_campaign_next_mission()) { // is campaign and next mission valid?
1703 gamesnd_play_iface(SND_GENERAL_FAIL);
1707 gameseq_post_event(GS_EVENT_MAIN_MENU);
1708 gamesnd_play_iface(SND_COMMIT_PRESSED);
1711 int campaign_room_button_pressed(int n)
1714 case CR_SCROLL_UP_BUTTON:
1715 sim_room_scroll_screen_up();
1718 case CR_SCROLL_DOWN_BUTTON:
1719 sim_room_scroll_screen_down();
1722 case CR_SCROLL_INFO_UP_BUTTON:
1723 campaign_room_scroll_info_up();
1726 case CR_SCROLL_INFO_DOWN_BUTTON:
1727 campaign_room_scroll_info_down();
1730 case CR_COMMIT_BUTTON:
1731 campaign_room_commit();
1735 case CR_HELP_BUTTON:
1736 launch_context_help();
1737 gamesnd_play_iface(SND_HELP_PRESSED);
1740 case CR_OPTIONS_BUTTON:
1741 gamesnd_play_iface(SND_SWITCH_SCREENS);
1742 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
1746 case CR_RESET_BUTTON:
1747 if ( (Active_campaign_index < 0) || (Active_campaign_index >= Num_campaigns) )
1748 gamesnd_play_iface(SND_GENERAL_FAIL);
1749 else if (campaign_room_reset_campaign(Active_campaign_index))
1750 gamesnd_play_iface(SND_GENERAL_FAIL);
1752 gamesnd_play_iface(SND_USER_SELECT);
1760 void campaign_room_init()
1762 int i, j, load_failed;
1764 char wild_card[256];
1766 list_h = Mission_list_coords[gr_screen.res][3];
1769 common_set_interface_palette("InterfacePalette"); // set the interface palette
1771 Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
1772 Ui_window.set_mask_bmap(Campaign_mask_filename[gr_screen.res]);
1774 for (i=0; i<CR_NUM_BUTTONS; i++) {
1775 b = &Cr_buttons[gr_screen.res][i];
1777 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
1778 // set up callback for when a mouse first goes over a button
1779 b->button.set_highlight_action(common_play_highlight_sound);
1780 b->button.set_bmaps(b->filename);
1781 b->button.link_hotspot(b->hotspot);
1784 for (i=0; i<LIST_BUTTONS_MAX; i++) {
1785 List_buttons[i].create(&Ui_window, "", 0, 0, 60, 30, 0, 1);
1786 List_buttons[i].hide();
1787 List_buttons[i].disable();
1791 for(i=0; i<CR_NUM_TEXT; i++){
1792 Ui_window.add_XSTR(&Cr_text[gr_screen.res][i]);
1795 // set up sim_rooms for buttons so we draw the correct animation frame when a key is pressed
1796 Cr_buttons[gr_screen.res][CR_SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
1797 Cr_buttons[gr_screen.res][CR_SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
1798 Cr_buttons[gr_screen.res][CR_RESET_BUTTON].button.set_hotkey(KEY_DELETE);
1799 Cr_buttons[gr_screen.res][CR_COMMIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
1800 // Cr_buttons[gr_screen.res][CR_HELP_BUTTON].button.set_hotkey(KEY_F2);
1802 Background_bitmap = bm_load(Campaign_filename[gr_screen.res]);
1804 // load in help overlay bitmap
1805 help_overlay_load(CAMPAIGN_ROOM_OVERLAY);
1806 help_overlay_set_state(CAMPAIGN_ROOM_OVERLAY,0);
1810 Desc_scroll_offset = Scroll_offset = 0;
1811 load_failed = mission_load_up_campaign();
1813 mission_campaign_next_mission();
1816 Campaign.filename[0] = 0;
1817 Campaign.num_missions = 0;
1822 Get_file_list_filter = campaign_room_campaign_filter;
1823 memset(wild_card, 0, 256);
1824 strcpy(wild_card, NOX("*"));
1825 strcat(wild_card, FS_CAMPAIGN_FILE_EXT);
1826 Num_campaigns = cf_get_file_list(MAX_CAMPAIGNS, Campaign_file_names, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME);
1828 for (i=0; i<Num_campaigns; i++) {
1829 for (j=0; j<Num_campaigns; j++) {
1830 if (Campaign_file_names_temp[j]) {
1831 if (!strncmp(Campaign_file_names[i], Campaign_file_names_temp[j], strlen(Campaign_file_names_temp[j]) - 4)) {
1832 Campaign_descs[i] = Campaign_descs_temp[j];
1833 free(Campaign_file_names_temp[j]);
1834 Campaign_file_names_temp[j] = NULL;
1840 Assert(j < Num_campaigns); // Campaign not found? How is that possible?
1843 Campaign_names_inited = 0;
1844 campaign_room_build_listing();
1846 Selected_campaign_index = Active_campaign_index = -1;
1848 for (i=0; i<Num_campaigns; i++)
1849 if (!stricmp(Campaign_file_names[i], Campaign.filename)) {
1850 set_new_campaign_line(i);
1851 Active_campaign_index = i;
1857 void campaign_room_close()
1861 for (i=0; i<Num_campaigns; i++)
1862 if (Campaign_descs[i])
1863 free(Campaign_descs[i]);
1865 if (Background_bitmap >= 0)
1866 bm_unload(Background_bitmap);
1868 if (Campaign_names_inited)
1869 for (i=0; i<Num_campaigns; i++)
1870 if (Campaign_names[i])
1871 free(Campaign_names[i]);
1873 for (i=0; i<Num_campaigns; i++)
1874 free(Campaign_file_names[i]);
1876 // unload the overlay bitmap
1877 help_overlay_unload(CAMPAIGN_ROOM_OVERLAY);
1879 Ui_window.destroy();
1880 common_free_interface_palette(); // restore game palette
1884 void campaign_room_do_frame(float frametime)
1887 char line_text[MAX_INFO_LINE_LEN];
1889 int font_height = gr_get_font_height();
1890 int select_tease_line = -1; // line mouse is down on, but won't be selected until button released
1892 if ( help_overlay_active(CAMPAIGN_ROOM_OVERLAY) ) {
1893 // Cr_buttons[gr_screen.res][CR_HELP_BUTTON].button.reset_status();
1894 Ui_window.set_ignore_gadgets(1);
1897 k = Ui_window.process() & ~KEY_DEBUGGED;
1899 if ( (k > 0) || B1_JUST_RELEASED ) {
1900 if ( help_overlay_active(CAMPAIGN_ROOM_OVERLAY) ) {
1901 help_overlay_set_state(CAMPAIGN_ROOM_OVERLAY, 0);
1902 Ui_window.set_ignore_gadgets(0);
1907 if ( !help_overlay_active(CAMPAIGN_ROOM_OVERLAY) ) {
1908 Ui_window.set_ignore_gadgets(0);
1912 case KEY_DOWN: // scroll list down
1913 if (Selected_campaign_index < Num_campaigns - 1) {
1914 set_new_campaign_line(Selected_campaign_index + 1);
1915 gamesnd_play_iface(SND_SCROLL);
1918 gamesnd_play_iface(SND_GENERAL_FAIL);
1922 case KEY_UP: // scroll list up
1923 if (Selected_campaign_index < 0)
1924 Selected_campaign_index = 1;
1926 if (Selected_campaign_index) {
1927 set_new_campaign_line(Selected_campaign_index - 1);
1928 gamesnd_play_iface(SND_SCROLL);
1931 gamesnd_play_iface(SND_GENERAL_FAIL);
1936 gameseq_post_event(GS_EVENT_MAIN_MENU);
1940 for (i=0; i<CR_NUM_BUTTONS; i++){
1941 if (Cr_buttons[gr_screen.res][i].button.pressed()){
1942 if (campaign_room_button_pressed(i)){
1948 for (i=0; i<LIST_BUTTONS_MAX; i++) {
1949 if (List_buttons[i].is_mouse_on()){
1950 select_tease_line = i + Scroll_offset;
1953 if (List_buttons[i].pressed()) {
1954 set_new_campaign_line(i + Scroll_offset);
1955 gamesnd_play_iface(SND_USER_SELECT);
1959 GR_MAYBE_CLEAR_RES(Background_bitmap);
1960 if (Background_bitmap >= 0) {
1961 gr_set_bitmap(Background_bitmap);
1968 line = Scroll_offset;
1969 while (sim_room_line_query_visible(line)) {
1970 y = Cr_list_coords[gr_screen.res][1] + sim_room_lines[line].y - sim_room_lines[Scroll_offset].y;
1972 List_buttons[line - Scroll_offset].update_dimensions(Cr_list_coords[gr_screen.res][0], y, Cr_list_coords[gr_screen.res][2], font_height);
1973 List_buttons[line - Scroll_offset].enable();
1975 if (!stricmp(sim_room_lines[line].filename, Campaign.filename)) {
1976 gr_set_color_fast(&Color_white);
1977 i = y + font_height / 2 - 1;
1978 gr_circle(Cr_list_coords[gr_screen.res][0] - 6, i, 5);
1980 gr_set_color_fast(&Color_bright_white);
1981 gr_line(Cr_list_coords[gr_screen.res][0] - 10, i, Cr_list_coords[gr_screen.res][0] - 8, i);
1982 gr_line(Cr_list_coords[gr_screen.res][0] - 6, i - 4, Cr_list_coords[gr_screen.res][0] - 6, i - 2);
1983 gr_line(Cr_list_coords[gr_screen.res][0] - 4, i, Cr_list_coords[gr_screen.res][0] - 2, i);
1984 gr_line(Cr_list_coords[gr_screen.res][0] - 6, i + 2, Cr_list_coords[gr_screen.res][0] - 6, i + 4);
1987 if (line == Selected_campaign_index)
1988 gr_set_color_fast(&Color_text_selected);
1989 else if (line == select_tease_line)
1990 gr_set_color_fast(&Color_text_subselected);
1992 gr_set_color_fast(&Color_text_normal);
1994 strcpy(buf, sim_room_lines[line].name);
1995 gr_force_fit_string(buf, 255, Cr_list_coords[gr_screen.res][0] + Cr_list_coords[gr_screen.res][2] - sim_room_lines[line].x);
1996 gr_printf(sim_room_lines[line].x, y, buf);
2000 i = line - Scroll_offset;
2001 while (i < LIST_BUTTONS_MAX)
2002 List_buttons[i++].disable();
2005 i = Desc_scroll_offset;
2006 gr_set_color_fast(&Color_text_normal);
2008 while (y + font_height <= Cr_info_coords[gr_screen.res][3]) {
2009 if (i >= Num_info_lines)
2012 Assert(Info_text_line_size[i] < MAX_INFO_LINE_LEN);
2013 strncpy(line_text, Info_text_ptrs[i], Info_text_line_size[i]);
2014 line_text[Info_text_line_size[i]] = 0;
2015 drop_white_space(line_text);
2016 gr_string(Cr_info_coords[gr_screen.res][0], Cr_info_coords[gr_screen.res][1] + y, line_text);
2021 // blit help overlay if active
2022 help_overlay_maybe_blit(CAMPAIGN_ROOM_OVERLAY);
2027 void sim_room_load_mission_icons()
2032 for(idx=0; idx<NUM_MISSION_ICONS; idx++){
2033 Mission_icon_bitmaps[idx] = -1;
2034 Mission_icon_bitmaps[idx] = bm_load(Mission_icon_bitmap_filenames[idx]);
2038 void sim_room_unload_mission_icons()
2042 // unload all bitmaps
2043 for(idx=0; idx<NUM_MISSION_ICONS; idx++){
2044 if(Mission_icon_bitmaps[idx] >= 0){
2045 bm_unload(Mission_icon_bitmaps[idx]);
2046 Mission_icon_bitmaps[idx] = -1;