2 * $Logfile: /Freespace2/code/MenuUI/ReadyRoom.cpp $
7 * Ready Room code, which is the UI screen for selecting Campaign/mission to play next mainly.
10 * Revision 1.1 2002/05/03 03:28:09 root
14 * 20 9/30/99 5:59p Jefff
15 * fixed compile error in OEM ver
17 * 19 9/08/99 12:28p Jefff
19 * 18 9/06/99 6:38p Dave
20 * Improved CD detection code.
22 * 17 9/02/99 2:33p Jefff
23 * column heading coordinate changes
25 * 16 8/22/99 4:16p Jefff
26 * scroll button coord fixes
28 * 15 7/20/99 1:49p Dave
29 * Peter Drake build. Fixed some release build warnings.
31 * 14 7/19/99 2:13p Dave
32 * Added some new strings for Heiko.
34 * 13 7/15/99 9:20a Andsager
35 * FS2_DEMO initial checkin
37 * 12 7/09/99 5:54p Dave
38 * Seperated cruiser types into individual types. Added tons of new
39 * briefing icons. Campaign screen.
41 * 11 2/01/99 5:55p Dave
42 * Removed the idea of explicit bitmaps for buttons. Fixed text
43 * highlighting for disabled gadgets.
45 * 10 1/30/99 9:01p Dave
48 * 9 1/30/99 5:08p Dave
49 * More new hi-res stuff.Support for nice D3D textures.
51 * 8 1/29/99 12:47a Dave
52 * Put in sounds for beam weapon. A bunch of interface screens (tech
55 * 7 12/11/98 4:35p Andsager
56 * Fix sim room bug when no standalone missions
58 * 6 12/07/98 5:02p Dan
59 * Removed improper use of bitmap filename with extension,
61 * 5 10/13/98 9:28a Dave
62 * Started neatening up freespace.h. Many variables renamed and
63 * reorganized. Added AlphaColors.[h,cpp]
77 #include "gamesequence.h"
78 #include "missioncampaign.h"
81 #include "missionscreencommon.h"
82 #include "freespace.h"
83 #include "missionparse.h"
85 #include "managepilot.h"
87 #include "contexthelp.h"
88 #include "cfilesystem.h"
89 #include "freespace.h"
90 #include "alphacolors.h"
92 #define MAX_MISSIONS 1024
94 int Mission_list_coords[GR_NUM_RESOLUTIONS][4] = {
103 int Campaign_list_coords[GR_NUM_RESOLUTIONS][4] = {
113 // x coordinate offsets for data when campaign tab active
115 #define C_SUBTEXT_X 19
117 // x coordinate offsets for data when mission tab active
120 #define MODE_CAMPAIGNS 0
121 #define MODE_MISSIONS 1
123 #define MAX_LINES 200
124 #define MAX_DESC_LINES 200
125 #define NUM_BUTTONS 11
126 #define LIST_BUTTONS_MAX 40
128 #define SCROLL_UP_BUTTON 0
129 #define SCROLL_DOWN_BUTTON 1
130 #define MISSION_TAB 2
131 #define CAMPAIGN_TAB 3
132 #define HELP_BUTTON 4
133 #define COMMIT_BUTTON 5
134 #define OPTIONS_BUTTON 6
135 #define TECH_DATABASE_BUTTON 7
136 #define SIMULATOR_BUTTON 8
137 #define CUTSCENES_BUTTON 9
138 #define CREDITS_BUTTON 10
140 #define CAMPAIGN_MISSION_HASH_SIZE 307
142 struct sim_room_buttons {
146 UI_BUTTON button; // because we have a class inside this struct, we need the constructor below..
148 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) {}
151 static sim_room_buttons Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
154 sim_room_buttons("LMB_04", 1, 99, -1, -1, 4),
155 sim_room_buttons("LMB_05", 1, 381, -1, -1, 5),
156 sim_room_buttons("LMB_06", 6, 438, 40, 445, 6),
157 sim_room_buttons("LMB_07", 6, 457, 40, 462, 7),
158 sim_room_buttons("LMB_08", 534, 426, 500, 440, 8),
159 sim_room_buttons("LMB_09", 571, 426, 572, 413, 9),
160 sim_room_buttons("LMB_10", 534, 455, 480, 462, 10),
162 sim_room_buttons("TDB_00", 7, 3, 37, 7, 0),
163 sim_room_buttons("TDB_01", 7, 18, 37, 23, 1),
164 sim_room_buttons("TDB_02", 7, 34, 37, 38, 2),
165 sim_room_buttons("TDB_03", 7, 49, 37, 54, 3),
168 sim_room_buttons("2_LMB_04", 2, 159, -1, -1, 4),
169 sim_room_buttons("2_LMB_05", 2, 609, -1, -1, 5),
170 sim_room_buttons("2_LMB_06", 10, 701, 64, 712, 6),
171 sim_room_buttons("2_LMB_07", 10, 732, 64, 739, 7),
172 sim_room_buttons("2_LMB_08", 854, 681, 800, 704, 8),
173 sim_room_buttons("2_LMB_09", 914, 681, 915, 660, 9),
174 sim_room_buttons("2_LMB_10", 854, 728, 800, 728, 10),
176 sim_room_buttons("2_TDB_00", 12, 5, 59, 12, 0),
177 sim_room_buttons("2_TDB_01", 12, 31, 59, 37, 1),
178 sim_room_buttons("2_TDB_02", 12, 56, 59, 62, 2),
179 sim_room_buttons("2_TDB_03", 12, 81, 59, 88, 3),
184 char *Sim_filename[GR_NUM_RESOLUTIONS] = {
188 char *Sim_mask_filename[GR_NUM_RESOLUTIONS] = {
193 char *Campaign_filename[GR_NUM_RESOLUTIONS] = {
197 char *Campaign_mask_filename[GR_NUM_RESOLUTIONS] = {
202 // misc text. ("Mission" and "Filename"
203 #define NUM_SIM_MISC_TEXT 2
204 #define SIM_MISC_TEXT_MISSION 0
205 #define SIM_MISC_TEXT_FILENAME 1
206 int Sim_misc_text_coords[GR_NUM_RESOLUTIONS][NUM_SIM_MISC_TEXT][2] = {
217 // readyroom text line stuff
218 #define READYROOM_LINE_CAMPAIGN 1
219 #define READYROOM_LINE_CMISSION 2
220 #define READYROOM_LINE_MISSION 3
222 #define READYROOM_FLAG_FROM_VOLITION (1<<0) // volition made
224 int type; // see READYROOM_LINE_* defines above
227 int x; // X coordinate of line
228 int y; // Y coordinate of line
229 int flags; // special flags, see READYROOM_FLAG_* defines above
230 } sim_room_lines[MAX_LINES];
232 static char Cur_campaign[MAX_FILENAME_LEN];
233 static char *Mission_filenames[MAX_MISSIONS];
234 static char *Standalone_mission_names[MAX_MISSIONS];
235 static int Standalone_mission_flags[MAX_MISSIONS];
236 static char *Campaign_missions[MAX_MISSIONS];
237 static char *Campaign_mission_names[MAX_CAMPAIGN_MISSIONS];
238 static int Campaign_mission_flags[MAX_MISSIONS];
239 static char *Campaign_descs[MAX_CAMPAIGNS];
240 static char *Campaign_descs_temp[MAX_CAMPAIGNS];
241 static char *Campaign_file_names_temp[MAX_CAMPAIGNS];
242 static int Standalone_mission_names_inited = 0;
243 static int Campaign_names_inited = 0;
244 static int Campaign_mission_names_inited = 0;
245 static int Num_standalone_missions;
246 static int Num_campaign_missions;
247 static int Num_player_missions;
248 static int Scroll_offset;
249 static int Selected_line;
250 static int Num_lines;
251 static int Num_campaign_missions_with_info = 0;
252 static int Num_standalone_missions_with_info = 0;
259 static int Background_bitmap;
260 static UI_WINDOW Ui_window;
261 static UI_BUTTON List_buttons[LIST_BUTTONS_MAX]; // buttons for each line of text in list
263 typedef struct hash_node {
268 static hash_node *Campaign_mission_hash_table[CAMPAIGN_MISSION_HASH_SIZE];
269 static int Hash_table_inited;
271 // special icons (1.04 + stuff)
272 #define NUM_MISSION_ICONS 1
273 #define MISSION_ICON_VOLITION 0 // mini volition death's head :)
275 // icon offsets (see LIST_ defines above
276 //#define MISSION_ICON_VOLITION_X (46)
277 #define MISSION_ICON_VOLITION_Y_OFFSET (-1)
280 static int Sim_volition_icon_x[GR_NUM_RESOLUTIONS] = {
285 // special icons themselves
286 int Mission_icon_bitmaps[NUM_MISSION_ICONS];
288 char *Mission_icon_bitmap_filenames[NUM_MISSION_ICONS] = {
292 void sim_room_load_mission_icons();
293 void sim_room_unload_mission_icons();
294 void sim_room_blit_icons(int line_index, int y_start, fs_builtin_mission *fb = NULL, int is_md = 0);
296 // Finds a hash value for mission filename
298 // returns hash value
299 int hash_filename(char *filename) {
300 unsigned __int64 hash_val = 0;
301 char *ptr = filename;
303 // Dont hash .fsm extension, convert all to upper case
304 for (int i=0; i < ((signed int)(strlen(filename)) - 4); i++) {
305 hash_val = (hash_val << 4) + toupper(*ptr++);
308 return int(hash_val % CAMPAIGN_MISSION_HASH_SIZE);
311 // insert filename into Campaign_mission_hash_table
313 // returns 1 if successful, 0 if could not allocate memory
314 int hash_insert(char *filename) {
315 int hash_val = hash_filename(filename);
318 // Check if table empty
319 if (Campaign_mission_hash_table[hash_val] == NULL) {
320 Campaign_mission_hash_table[hash_val] = new hash_node;
322 cur_node = Campaign_mission_hash_table[hash_val];
324 if (cur_node == NULL) {
325 // Unable to allocate memory
329 // Walk down list to first empty node
330 cur_node = Campaign_mission_hash_table[hash_val];
331 while (cur_node->next != NULL) {
332 cur_node = cur_node->next;
336 cur_node->next = new hash_node;
338 if (cur_node->next == NULL) {
339 // unable to allocate memory
342 cur_node = cur_node->next;
347 cur_node->next = NULL;
348 cur_node->filename = filename;
354 // Checks if a filename already exitst in the hash table
356 // returns 1 if found (collision), 0 if no collision
357 int campaign_mission_hash_collision(char *filename)
359 int hash_val = hash_filename(filename);
360 hash_node *cur_node = Campaign_mission_hash_table[hash_val];
362 if (cur_node == NULL) {
367 if (!stricmp(filename, cur_node->filename)) {
371 cur_node = cur_node->next;
372 } while (cur_node != NULL);
374 // Ran out of stuff to check
378 // builds hash table of campaign mission filenames
380 // returns 1 if successful, 0 if not successful
381 int build_campaign_mission_filename_hash_table()
384 // Go through all campaign missions
385 for (int i=0; i<Num_campaign_missions; i++) {
386 rval = hash_insert(Campaign_missions[i]);
396 // deletes hash table nodes
398 void campaign_mission_hash_table_delete()
402 for (int i=0; i<CAMPAIGN_MISSION_HASH_SIZE; i++) {
403 // Look for entries into array
404 if (Campaign_mission_hash_table[i] != NULL) {
405 cur_node = Campaign_mission_hash_table[i];
407 // Walk down the list deleting self
408 while (cur_node->next != NULL) {
409 hash_node *temp = cur_node->next;
416 Campaign_mission_hash_table[i] = NULL;
422 // add a line of sim_room smuck to end of list
423 int sim_room_line_add(int type, char *name, char *filename, int x, int y, int flags)
425 if (Num_lines >= MAX_LINES)
428 sim_room_lines[Num_lines].type = type;
429 sim_room_lines[Num_lines].name = name;
430 sim_room_lines[Num_lines].filename = filename;
431 sim_room_lines[Num_lines].x = x;
432 sim_room_lines[Num_lines].y = y;
433 sim_room_lines[Num_lines].flags = flags;
437 // filter out all multiplayer campaigns
438 int campaign_room_campaign_filter(char *filename)
440 int type, max_players;
441 char name[NAME_LENGTH], *desc = NULL;
444 // also need to check if this is the builtin campaign
445 if ( game_find_builtin_mission(filename) && mission_campaign_get_info(filename, name, &type, &max_players, &desc) ) {
447 if ( mission_campaign_get_info(filename, name, &type, &max_players, &desc) ) {
449 if ( type == CAMPAIGN_TYPE_SINGLE ) {
450 Campaign_file_names_temp[Num_campaigns] = strdup(filename);
451 Campaign_descs_temp[Num_campaigns++] = desc;
463 // build up a list of all missions in all campaigns.
464 int sim_room_campaign_mission_filter(char *filename)
468 num = mission_campaign_get_mission_list(filename, &Campaign_missions[Num_campaign_missions], MAX_CAMPAIGN_MISSIONS - Num_campaign_missions);
472 Num_campaign_missions += num;
476 // filter out all missions already used in existing campaigns
477 int sim_room_standalone_mission_filter(char *filename)
480 char mission_name[255];
482 // Check if a campaign mission (single and multi)
483 if (campaign_mission_hash_collision(filename)) {
487 // Check if a standalone multi mission OR Mdisk mission with data
488 type = mission_parse_is_multi(filename, mission_name);
489 if (type && !(type & MISSION_TYPE_SINGLE))
495 // builds up list of standalone missions and adds them to missions simulator
496 // processes one mission per frame
498 // returns 1 if finished with all missions, 0 otherwise
500 int build_standalone_mission_list_do_frame()
502 int font_height = gr_get_font_height();
503 char filename[MAX_FILENAME_LEN];
506 // When no standalone missions in data directory
507 if (Num_standalone_missions == 0) {
508 Standalone_mission_names_inited = 1;
512 // Set global variable so we we'll have list available next time
513 Standalone_mission_names[Num_standalone_missions_with_info] = NULL;
514 Standalone_mission_flags[Num_standalone_missions_with_info] = 0;
516 if (Num_standalone_missions > 0) { // sanity check
517 if (strlen(Mission_filenames[Num_standalone_missions_with_info]) < MAX_FILENAME_LEN - 4) { // sanity check?
518 strcpy(filename, Mission_filenames[Num_standalone_missions_with_info]);
522 sprintf(str, XSTR("Single Mission\n\n%s",989), filename);
523 popup_change_text(str);
525 // tack on an extension
526 strcat(filename, FS_MISSION_FILE_EXT);
527 if (!get_mission_info(filename)) {
528 Standalone_mission_names[Num_standalone_missions_with_info] = strdup(The_mission.name);
529 Standalone_mission_flags[Num_standalone_missions_with_info] = The_mission.game_type;
530 int y = Num_lines * (font_height + 2);
532 // determine some extra information
534 fs_builtin_mission *fb = game_find_builtin_mission(filename);
535 if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
536 flags |= READYROOM_FLAG_FROM_VOLITION;
540 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);
544 Num_standalone_missions_with_info++;
547 if (Num_standalone_missions_with_info == Num_standalone_missions) {
548 Standalone_mission_names_inited = 1;
555 // builds up list of already played missions in a campaign and adds them to missions simulator
556 // processes one mission per frame
558 // returns 1 if finished with all missions, 0 otherwise
560 int build_campaign_mission_list_do_frame()
562 int font_height = gr_get_font_height();
565 // When no campaign files in data directory
566 if (Campaign.num_missions == 0) {
567 Campaign_mission_names_inited = 1;
573 sprintf(str, XSTR("Campaign Mission\n\n%s",990), Campaign.missions[Num_campaign_missions_with_info].name);
574 popup_change_text(str);
576 // Set global variable so we we'll have list available next time
577 Campaign_mission_names[Num_campaign_missions_with_info] = NULL;
578 Campaign_mission_flags[Num_campaign_missions_with_info] = 0;
580 // Only allow missions already completed
581 if (Campaign.missions[Num_campaign_missions_with_info].completed) {
582 if (!get_mission_info(Campaign.missions[Num_campaign_missions_with_info].name)) {
584 Campaign_mission_names[Num_campaign_missions_with_info] = strdup(The_mission.name);
585 Campaign_mission_flags[Num_campaign_missions_with_info] = The_mission.game_type;
586 int y = Num_campaign_missions_with_info * (font_height + 2);
588 // determine some extra information
590 fs_builtin_mission *fb = game_find_builtin_mission(Campaign.missions[Num_campaign_missions_with_info].name);
591 if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
592 flags |= READYROOM_FLAG_FROM_VOLITION;
595 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);
599 Num_campaign_missions_with_info++;
601 if (Num_campaign_missions_with_info == Campaign.num_missions) {
602 Campaign_mission_names_inited = 1;
609 // Builds list of either (1) standalone missions or (2) already played missions in current campaign
610 // First time through, it builds list, next time it uses precompiled list
611 void sim_room_build_listing()
614 int font_height = gr_get_font_height();
615 char full_filename[256];
618 list_y = Mission_list_coords[gr_screen.res][1];
619 list_h = Mission_list_coords[gr_screen.res][3];
621 // Stand alone single player missions.
622 if (Player->readyroom_listing_mode == MODE_MISSIONS) {
623 if (Hash_table_inited) {
624 if (!Standalone_mission_names_inited) { // Is this the first time through
625 // build_list_do_frame builds list and adds sim room line and sets Standalone_mission_names_inited
626 popup_till_condition(build_standalone_mission_list_do_frame, POPUP_CANCEL, XSTR("Loading missions", 991) );
628 for (i=0; i<Num_standalone_missions_with_info; i++) {
629 if (Standalone_mission_names[i]) {
630 // determine some extra information
632 memset(full_filename, 0, 256);
633 strcpy(full_filename, cf_add_ext(Mission_filenames[i], FS_MISSION_FILE_EXT));
634 fs_builtin_mission *fb = game_find_builtin_mission(full_filename);
635 if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
636 flags |= READYROOM_FLAG_FROM_VOLITION;
639 sim_room_line_add(READYROOM_LINE_MISSION, Standalone_mission_names[i], Mission_filenames[i], list_x1 + M_TEXT_X, y, flags);
640 y += font_height + 2;
647 list_y += font_height + 2;
648 list_h -= font_height - 2;
650 if (!Campaign_mission_names_inited) { // Is this the first time through
651 popup_till_condition(build_campaign_mission_list_do_frame, POPUP_CANCEL, XSTR("Loading campaign missions",992));
652 // builds list, adds sim room line and sets Campaign_mission_names_inited
654 for (i=0; i<Num_campaign_missions_with_info; i++) {
655 if (Campaign_mission_names[i]) {
656 // determine some extra information
658 memset(full_filename, 0, 256);
659 strcpy(full_filename, cf_add_ext(Campaign.missions[i].name, FS_MISSION_FILE_EXT));
660 fs_builtin_mission *fb = game_find_builtin_mission(full_filename);
661 if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
662 flags |= READYROOM_FLAG_FROM_VOLITION;
665 sim_room_line_add(READYROOM_LINE_CMISSION, Campaign_mission_names[i], Campaign.missions[i].name, list_x1 + C_SUBTEXT_X, y, flags);
673 int sim_room_line_query_visible(int n)
677 if ((n < 0) || (n >= Num_lines))
680 y = sim_room_lines[n].y - sim_room_lines[Scroll_offset].y;
681 if ((y < 0) || (y + gr_get_font_height() > list_h))
687 void sim_room_scroll_screen_up()
689 if (Player->readyroom_listing_mode != MODE_MISSIONS) {
692 gamesnd_play_iface(SND_SCROLL);
695 gamesnd_play_iface(SND_GENERAL_FAIL);
702 Assert(Selected_line > Scroll_offset);
703 while (!sim_room_line_query_visible(Selected_line))
706 gamesnd_play_iface(SND_SCROLL);
709 gamesnd_play_iface(SND_GENERAL_FAIL);
712 void sim_room_scroll_line_up()
716 if (Selected_line < Scroll_offset)
717 Scroll_offset = Selected_line;
719 gamesnd_play_iface(SND_SCROLL);
722 gamesnd_play_iface(SND_GENERAL_FAIL);
725 void sim_room_scroll_screen_down()
727 if (Player->readyroom_listing_mode != MODE_MISSIONS) {
728 if (sim_room_lines[Num_lines - 1].y + gr_get_font_height() > sim_room_lines[Scroll_offset].y + list_h) {
730 gamesnd_play_iface(SND_SCROLL);
733 gamesnd_play_iface(SND_GENERAL_FAIL);
738 if (sim_room_lines[Num_lines - 1].y + gr_get_font_height() > sim_room_lines[Scroll_offset].y + list_h) {
740 while (!sim_room_line_query_visible(Selected_line)) {
742 Assert(Selected_line < Num_lines);
745 gamesnd_play_iface(SND_SCROLL);
748 gamesnd_play_iface(SND_GENERAL_FAIL);
751 void sim_room_scroll_line_down()
753 if (Selected_line < Num_lines - 1) {
756 Assert(Selected_line > Scroll_offset);
757 while (!sim_room_line_query_visible(Selected_line))
760 gamesnd_play_iface(SND_SCROLL);
763 gamesnd_play_iface(SND_GENERAL_FAIL);
766 // returns: 0 = success, !0 = aborted or failed
767 int ready_room_reset_campaign()
771 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) );
774 mission_campaign_savefile_delete(Campaign.filename);
775 mission_campaign_load(Campaign.filename);
782 // Decide if we should offer choice to resume this savegame
783 int sim_room_can_resume_savegame(char *savegame_filename)
785 #ifdef FREESPACE_SAVERESTORE_SYSTEM
786 char savegame_mission[MAX_FILENAME_LEN];
788 if (state_read_description(savegame_filename, NULL, savegame_mission)) {
792 if (stricmp(Game_current_mission_filename, savegame_mission)) {
802 // Decide wether to resume a save game or not
803 // exit: 1 => savegame has been restored
804 // 0 => no restore, proceed to briefing
805 // -1 => don't start mission at all
806 int sim_room_maybe_resume_savegame()
808 // MWA -- 3/26/98 -- removed all savegame references in game
812 char savegame_filename[_MAX_FNAME];
813 int popup_rval = -1, resume_savegame = 0;
815 // Generate the save-game filename for this campaign
816 memset(savegame_filename, 0, _MAX_FNAME);
817 mission_campaign_savefile_generate_root(savegame_filename);
818 strcat(savegame_filename, NOX("svg"));
820 // Decide if we should offer choice to resume this savegame
821 if ( sim_room_can_resume_savegame(savegame_filename) ) {
822 popup_rval = popup(0, 3, XSTR("&Cancel",-1), XSTR("&Overwrite",-1), XSTR("&Resume",-1), XSTR("A save game for this mission exists.", -1));
823 switch ( popup_rval ) {
826 resume_savegame = -1;
836 resume_savegame = -1;
843 if (resume_savegame == 1) {
844 if ( state_restore_all(savegame_filename) == -1 ) {
845 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));
846 if (popup_rval == 1) {
849 resume_savegame = -1;
857 // If we are resuming this savegame, then delete the file
858 if (resume_savegame == 1) {
859 cf_delete(savegame_filename);
862 return resume_savegame;
866 int readyroom_continue_campaign()
868 if (mission_campaign_next_mission()) { // is campaign and next mission valid?
871 int reset_campaign = 0;
872 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) );
873 if ( reset_campaign == 1 ) {
874 mission_campaign_savefile_delete(Campaign.filename);
875 mission_campaign_load(Campaign.filename);
876 mission_campaign_next_mission();
881 gamesnd_play_iface(SND_GENERAL_FAIL);
882 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) );
888 if(!game_do_cd_mission_check(Game_current_mission_filename)){
892 // set the bit for campaign mode
893 Game_mode |= GM_CAMPAIGN_MODE;
894 gameseq_post_event( GS_EVENT_START_GAME );
899 void sim_room_commit()
901 if ((Selected_line >= Num_lines) || !sim_room_lines[Selected_line].filename) {
902 gamesnd_play_iface(SND_GENERAL_FAIL);
906 strncpy(Game_current_mission_filename, sim_room_lines[Selected_line].filename, MAX_FILENAME_LEN);
908 Game_mode &= ~(GM_CAMPAIGN_MODE); // be sure this bit is clear
911 if(game_do_cd_mission_check(Game_current_mission_filename)){
912 // don't resume savegame, proceed to briefing
913 gameseq_post_event(GS_EVENT_START_GAME);
914 gamesnd_play_iface(SND_COMMIT_PRESSED);
918 int sim_room_button_pressed(int n)
921 case SCROLL_UP_BUTTON:
922 sim_room_scroll_screen_up();
925 case SCROLL_DOWN_BUTTON:
926 sim_room_scroll_screen_down();
931 game_feature_not_in_demo_popup();
932 // gamesnd_play_iface(SND_GENERAL_FAIL);
935 Player->readyroom_listing_mode = MODE_MISSIONS;
936 Selected_line = Scroll_offset = 0;
937 gamesnd_play_iface(SND_USER_SELECT);
938 sim_room_build_listing();
943 Player->readyroom_listing_mode = MODE_CAMPAIGNS;
945 gamesnd_play_iface(SND_USER_SELECT);
946 sim_room_build_listing();
954 launch_context_help();
955 gamesnd_play_iface(SND_HELP_PRESSED);
959 gamesnd_play_iface(SND_SWITCH_SCREENS);
960 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
963 case TECH_DATABASE_BUTTON:
964 gamesnd_play_iface(SND_SWITCH_SCREENS);
965 gameseq_post_event(GS_EVENT_TECH_MENU);
968 case CUTSCENES_BUTTON:
969 gamesnd_play_iface(SND_SWITCH_SCREENS);
970 gameseq_post_event(GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN);
974 gamesnd_play_iface(SND_SWITCH_SCREENS);
975 gameseq_post_event(GS_EVENT_CREDITS);
982 // ---------------------------------------------------------------------
983 // mission_sim_room_init()
985 // Initialize the sim_room assignment screen system. Called when GS_STATE_sim_room_SCREEN
994 list_x1 = Mission_list_coords[gr_screen.res][0];
995 list_x2 = Campaign_list_coords[gr_screen.res][0];
996 list_y = Mission_list_coords[gr_screen.res][1];
997 list_w1 = Mission_list_coords[gr_screen.res][2];
998 list_w2 = Campaign_list_coords[gr_screen.res][2];
999 list_h = Mission_list_coords[gr_screen.res][3];
1001 // force mode to valid range. I once had a bogus value here. Don't know how that happened, though.
1002 if (Player->readyroom_listing_mode != MODE_MISSIONS)
1003 Player->readyroom_listing_mode = MODE_CAMPAIGNS;
1005 *Game_current_mission_filename = 0;
1006 common_set_interface_palette("InterfacePalette"); // set the interface palette
1007 Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
1008 Ui_window.set_mask_bmap(Sim_mask_filename[gr_screen.res]);
1010 for (i=0; i<NUM_BUTTONS; i++) {
1011 b = &Buttons[gr_screen.res][i];
1013 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
1014 // set up callback for when a mouse first goes over a button
1015 b->button.set_highlight_action(common_play_highlight_sound);
1016 b->button.set_bmaps(b->filename);
1017 b->button.link_hotspot(b->hotspot);
1020 // screen/button specific text
1021 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);
1022 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);
1023 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);
1024 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);
1025 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);
1027 // common tab button text
1028 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);
1029 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);
1030 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);
1031 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);
1033 // misc text - not associated with any buttons
1034 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);
1035 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);
1037 for (i=0; i<LIST_BUTTONS_MAX; i++) {
1038 List_buttons[i].create(&Ui_window, "", 0, 0, 60, 30, 0, 1);
1039 List_buttons[i].hide();
1040 List_buttons[i].disable();
1043 // set up sim_rooms for buttons so we draw the correct animation frame when a key is pressed
1044 Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
1045 Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
1046 Buttons[gr_screen.res][COMMIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
1048 Background_bitmap = bm_load(Sim_filename[gr_screen.res]);
1050 // load in help overlay bitmap
1051 help_overlay_load(SIM_ROOM_OVERLAY);
1052 help_overlay_set_state(SIM_ROOM_OVERLAY,0);
1054 Scroll_offset = Selected_line = 0;
1056 strcpy(Cur_campaign, Player->current_campaign);
1057 mission_load_up_campaign();
1058 mission_campaign_next_mission();
1060 Num_campaigns = Num_campaign_missions = 0;
1061 Get_file_list_filter = sim_room_campaign_mission_filter;
1062 memset(wild_card, 0, 256);
1063 strcpy(wild_card, NOX("*"));
1064 strcat(wild_card, FS_CAMPAIGN_FILE_EXT);
1065 Num_campaigns = cf_get_file_list(MAX_CAMPAIGNS, Campaign_file_names, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME);
1067 Hash_table_inited = 0;
1068 if (build_campaign_mission_filename_hash_table()) {
1069 Hash_table_inited = 1;
1073 GR_MAYBE_CLEAR_RES(Background_bitmap);
1074 if(Background_bitmap != -1){
1075 gr_set_bitmap(Background_bitmap);
1081 Get_file_list_filter = sim_room_standalone_mission_filter;
1082 memset(wild_card, 0, 256);
1083 strcpy(wild_card, NOX("*"));
1084 strcat(wild_card, FS_MISSION_FILE_EXT);
1085 Num_standalone_missions = cf_get_file_list(MAX_MISSIONS, Mission_filenames, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME);
1087 Num_campaign_missions_with_info = Num_standalone_missions_with_info = Standalone_mission_names_inited = Campaign_names_inited = Campaign_mission_names_inited = 0;
1088 sim_room_build_listing();
1090 // load special mission icons
1091 sim_room_load_mission_icons();
1094 // ---------------------------------------------------------------------
1097 // Cleanup the sim_room assignment screen system. Called when GS_STATE_sim_room_SCREEN
1100 void sim_room_close()
1104 for (i=0; i<Num_campaign_missions; i++)
1105 if (Campaign_missions[i])
1106 free(Campaign_missions[i]);
1108 if (Background_bitmap >= 0)
1109 bm_unload(Background_bitmap);
1111 if (Standalone_mission_names_inited){
1112 for (i=0; i<Num_standalone_missions; i++){
1113 if (Standalone_mission_names[i]){
1114 free(Standalone_mission_names[i]);
1116 Standalone_mission_flags[i] = 0;
1120 if (Campaign_names_inited)
1121 for (i=0; i<Num_campaigns; i++)
1122 if (Campaign_names[i])
1123 free(Campaign_names[i]);
1125 if (Campaign_mission_names_inited)
1126 for (i=0; i<Campaign.num_missions; i++)
1127 if (Campaign_mission_names[i])
1128 free(Campaign_mission_names[i]);
1130 for (i=0; i<Num_campaigns; i++)
1131 free(Campaign_file_names[i]);
1133 for (i=0; i<Num_standalone_missions; i++)
1134 free(Mission_filenames[i]);
1136 // unload the overlay bitmap
1137 help_overlay_unload(SIM_ROOM_OVERLAY);
1139 campaign_mission_hash_table_delete();
1141 Ui_window.destroy();
1142 common_free_interface_palette(); // restore game palette
1145 // unload special mission icons
1146 sim_room_unload_mission_icons();
1149 // ---------------------------------------------------------------------
1150 // sim_room_do_frame()
1152 // Called once per frame to process user input for the sim_room Assignment Screen
1154 void sim_room_do_frame(float frametime)
1157 int i, k, y, z, line;
1158 int font_height = gr_get_font_height();
1159 int select_tease_line = -1; // line mouse is down on, but won't be selected until button released
1162 for (i=0; i<Num_campaigns; i++)
1163 if (!stricmp(Campaign_file_names[i], Campaign.filename)) {
1168 if ( help_overlay_active(SIM_ROOM_OVERLAY) ) {
1169 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
1170 Ui_window.set_ignore_gadgets(1);
1173 k = Ui_window.process() & ~KEY_DEBUGGED;
1175 if ( (k > 0) || B1_JUST_RELEASED ) {
1176 if ( help_overlay_active(SIM_ROOM_OVERLAY) ) {
1177 help_overlay_set_state(SIM_ROOM_OVERLAY, 0);
1178 Ui_window.set_ignore_gadgets(0);
1183 if ( !help_overlay_active(SIM_ROOM_OVERLAY) ) {
1184 Ui_window.set_ignore_gadgets(0);
1188 case KEY_DOWN: // scroll list down
1189 sim_room_scroll_line_down();
1192 case KEY_UP: // scroll list up
1193 sim_room_scroll_line_up();
1197 gameseq_post_event(GS_EVENT_MAIN_MENU);
1200 case KEY_CTRLED | KEY_UP:
1201 sim_room_button_pressed(TECH_DATABASE_BUTTON);
1204 case KEY_CTRLED | KEY_DOWN:
1205 sim_room_button_pressed(CUTSCENES_BUTTON);
1209 if (Player->readyroom_listing_mode == MODE_CAMPAIGNS)
1210 Player->readyroom_listing_mode = MODE_MISSIONS;
1212 Player->readyroom_listing_mode = MODE_CAMPAIGNS;
1214 Selected_line = Scroll_offset = 0;
1215 gamesnd_play_iface(SND_USER_SELECT);
1216 sim_room_build_listing();
1220 gamesnd_play_iface(SND_SWITCH_SCREENS);
1221 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
1225 for (i=0; i<NUM_BUTTONS; i++){
1226 if (Buttons[gr_screen.res][i].button.pressed()){
1227 if (sim_room_button_pressed(i)){
1233 for (i=0; i<LIST_BUTTONS_MAX; i++) {
1234 if (List_buttons[i].is_mouse_on())
1235 select_tease_line = i + Scroll_offset;
1237 if (List_buttons[i].pressed()) {
1238 Selected_line = i + Scroll_offset;
1239 gamesnd_play_iface(SND_USER_SELECT);
1243 GR_MAYBE_CLEAR_RES(Background_bitmap);
1244 if (Background_bitmap >= 0) {
1245 gr_set_bitmap(Background_bitmap);
1251 for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
1252 if (Buttons[gr_screen.res][i].button.button_down()){
1257 if (i > CREDITS_BUTTON){
1258 Buttons[gr_screen.res][SIMULATOR_BUTTON].button.draw_forced(2);
1261 if (!Buttons[gr_screen.res][CAMPAIGN_TAB].button.button_down() && !Buttons[gr_screen.res][MISSION_TAB].button.button_down()) {
1262 if (Player->readyroom_listing_mode == MODE_CAMPAIGNS){
1263 Buttons[gr_screen.res][CAMPAIGN_TAB].button.draw_forced(2);
1264 } else if (Player->readyroom_listing_mode == MODE_MISSIONS){
1265 Buttons[gr_screen.res][MISSION_TAB].button.draw_forced(2);
1270 if (Player->readyroom_listing_mode == MODE_CAMPAIGNS) {
1271 gr_set_color_fast(&Color_text_heading);
1272 strcpy(buf, Campaign.name);
1273 gr_force_fit_string(buf, 255, list_w1);
1274 gr_printf(list_x1, Mission_list_coords[gr_screen.res][1], buf);
1276 if (Campaign.filename) {
1277 sprintf(buf, NOX("%s%s"), Campaign.filename, FS_CAMPAIGN_FILE_EXT);
1278 gr_force_fit_string(buf, 255, list_w2);
1279 gr_printf(list_x2, Mission_list_coords[gr_screen.res][1], buf);
1281 // blit the proper icons if necessary
1282 char full_name[256];
1283 memset(full_name, 0, 256);
1284 strcpy(full_name, cf_add_ext(Campaign.filename,FS_CAMPAIGN_FILE_EXT));
1285 fs_builtin_mission *fb = game_find_builtin_mission(full_name);
1287 // sim_room_blit_icons(0, Mission_list_coords[gr_screen.res][1], fb, 0);
1292 line = Scroll_offset;
1293 while (sim_room_line_query_visible(line)) {
1294 y = list_y + sim_room_lines[line].y - sim_room_lines[Scroll_offset].y;
1296 if (sim_room_lines[line].type != READYROOM_LINE_CAMPAIGN) {
1297 List_buttons[line - Scroll_offset].update_dimensions(list_x1, y, list_x2 + list_w2 - list_x1, font_height);
1298 List_buttons[line - Scroll_offset].enable();
1301 List_buttons[line - Scroll_offset].disable();
1303 if (line == Selected_line)
1304 gr_set_color_fast(&Color_text_selected);
1305 else if (line == select_tease_line)
1306 gr_set_color_fast(&Color_text_subselected);
1308 gr_set_color_fast(&Color_text_normal);
1310 strcpy(buf, sim_room_lines[line].name);
1311 gr_force_fit_string(buf, 255, list_x1 + list_w1 - sim_room_lines[line].x);
1312 gr_printf(sim_room_lines[line].x, y, buf);
1314 if (sim_room_lines[line].filename) {
1315 strcpy(buf, sim_room_lines[line].filename);
1316 gr_force_fit_string(buf, 255, list_w2);
1317 gr_printf(list_x2, y, buf);
1320 // blit additional icon information
1321 sim_room_blit_icons(line, y);
1326 i = line - Scroll_offset;
1327 while (i < LIST_BUTTONS_MAX)
1328 List_buttons[i++].disable();
1330 // blit help overlay if active
1331 help_overlay_maybe_blit(SIM_ROOM_OVERLAY);
1336 void sim_room_blit_icons(int line_index, int y_start, fs_builtin_mission *fb, int is_md)
1338 int is_from_volition = 0;
1340 // determine icon status
1342 is_from_volition = (sim_room_lines[line_index].flags & READYROOM_FLAG_FROM_VOLITION) ? 1 : 0;
1344 is_from_volition = (fb->flags & FSB_FROM_VOLITION) ? 1 : 0;
1347 // if the line is flagged as a volition file
1348 if(is_from_volition && (Mission_icon_bitmaps[MISSION_ICON_VOLITION] >= 0)){
1349 gr_set_bitmap(Mission_icon_bitmaps[MISSION_ICON_VOLITION]);
1350 gr_bitmap(Sim_volition_icon_x[gr_screen.res], y_start + MISSION_ICON_VOLITION_Y_OFFSET);
1354 /// Campaign room stuff below
1355 int Cr_list_coords[GR_NUM_RESOLUTIONS][4] = {
1364 int Cr_info_coords[GR_NUM_RESOLUTIONS][4] = {
1373 #define CR_NUM_BUTTONS 6
1375 #define CR_SCROLL_UP_BUTTON 0
1376 #define CR_SCROLL_DOWN_BUTTON 1
1377 #define CR_SCROLL_INFO_UP_BUTTON 2
1378 #define CR_SCROLL_INFO_DOWN_BUTTON 3
1379 #define CR_RESET_BUTTON 4
1380 #define CR_COMMIT_BUTTON 5
1382 #define MAX_INFO_LINES 20
1384 #define MAX_INFO_LINE_LEN 256
1386 ui_button_info Cr_buttons[GR_NUM_RESOLUTIONS][CR_NUM_BUTTONS] = {
1388 ui_button_info("CAB_00", 2, 42, -1, -1, 0),
1389 ui_button_info("CAB_01", 2, 89, -1, -1, 1),
1390 ui_button_info("CAB_02", 2, 279, -1, -1, 2),
1391 ui_button_info("CAB_03", 2, 325, -1, -1, 3),
1392 ui_button_info("CAB_04", 579, 353, -1, -1, 4),
1393 ui_button_info("CAB_05", 575, 434, -1, -1, 5),
1396 ui_button_info("2_CAB_00", 3, 68, -1, -1, 0),
1397 ui_button_info("2_CAB_01", 3, 142, -1, -1, 1),
1398 ui_button_info("2_CAB_02", 3, 446, -1, -1, 2),
1399 ui_button_info("2_CAB_03", 3, 520, -1, -1, 3),
1400 ui_button_info("2_CAB_04", 927, 565, -1, -1, 4),
1401 ui_button_info("2_CAB_05", 920, 694, -1, -1, 5),
1406 #define CR_NUM_TEXT 3
1407 UI_XSTR Cr_text[GR_NUM_RESOLUTIONS][CR_NUM_TEXT] = {
1409 { "Restart", 1403, 569, 326, UI_XSTR_COLOR_GREEN, -1, &Cr_buttons[0][CR_RESET_BUTTON].button },
1410 { "Campaign", 1404, 569, 337, UI_XSTR_COLOR_GREEN, -1, &Cr_buttons[0][CR_RESET_BUTTON].button },
1411 { "Select", 1409, 568, 413, UI_XSTR_COLOR_PINK, -1, &Cr_buttons[0][CR_COMMIT_BUTTON].button },
1414 { "Restart", 1403, 922, 523, UI_XSTR_COLOR_GREEN, -1, &Cr_buttons[1][CR_RESET_BUTTON].button },
1415 { "Campaign", 1404, 922, 538, UI_XSTR_COLOR_GREEN, -1, &Cr_buttons[1][CR_RESET_BUTTON].button },
1416 { "Select", 1409, 921, 665, UI_XSTR_COLOR_PINK, -1, &Cr_buttons[1][CR_COMMIT_BUTTON].button },
1423 } campaign_desc_lines[MAX_DESC_LINES];
1425 static int Num_desc_lines;
1426 static int Desc_scroll_offset;
1427 static int Selected_campaign_index;
1428 static int Active_campaign_index;
1430 char *Info_text_ptrs[MAX_INFO_LINES];
1431 int Num_info_lines, Info_text_line_size[MAX_INFO_LINES];
1433 void campaign_room_build_listing()
1435 int c, i, y, type, max_players;
1436 int font_height = gr_get_font_height();
1437 char name[NAME_LENGTH];
1440 if (!Campaign_names_inited) {
1441 for (i=0; i<Num_campaigns; i++) {
1442 Campaign_names[i] = NULL;
1443 if ( mission_campaign_get_info(Campaign_file_names[i], name, &type, &max_players) ) {
1445 if((game_find_builtin_mission(name) == NULL) && !strstr(name, "peterdrake")){
1448 Campaign_names[i] = strdup(name);
1451 if (type == CAMPAIGN_TYPE_SINGLE){
1452 Campaign_names[i] = strdup(name);
1458 Campaign_names_inited = 1;
1461 for (c=0; c<Num_campaigns; c++) {
1462 if (Campaign_names[c]) {
1464 // determine some extra information
1466 fs_builtin_mission *fb = game_find_builtin_mission(Campaign_file_names[c]);
1468 if(fb->flags & FSB_FROM_VOLITION){
1469 flags |= READYROOM_FLAG_FROM_VOLITION;
1473 sim_room_line_add(READYROOM_LINE_CAMPAIGN, Campaign_names[c], Campaign_file_names[c], Cr_list_coords[gr_screen.res][0], y, flags);
1474 y += font_height + 2;
1479 void set_new_campaign_line(int n)
1483 Selected_campaign_index = n;
1484 str = Campaign_descs[Selected_campaign_index];
1487 Num_info_lines = split_str(str, Cr_info_coords[gr_screen.res][2], Info_text_line_size, Info_text_ptrs, MAX_INFO_LINES);
1488 Assert(Num_info_lines >= 0);
1491 Desc_scroll_offset = 0;
1494 void campaign_room_scroll_info_up()
1496 if (Desc_scroll_offset) {
1497 Desc_scroll_offset--;
1498 gamesnd_play_iface(SND_SCROLL);
1501 gamesnd_play_iface(SND_GENERAL_FAIL);
1504 void campaign_room_scroll_info_down()
1506 if ( (Num_info_lines - Desc_scroll_offset) * gr_get_font_height() > Cr_info_coords[gr_screen.res][3]) {
1507 Desc_scroll_offset++;
1508 gamesnd_play_iface(SND_SCROLL);
1511 gamesnd_play_iface(SND_GENERAL_FAIL);
1514 // returns: 0 = success, !0 = aborted or failed
1515 int campaign_room_reset_campaign(int n)
1520 // 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]);
1521 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));
1523 filename = (char *) malloc(strlen(Campaign_file_names[n]) + 5);
1524 strcpy(filename, Campaign_file_names[n]);
1525 strcat(filename, FS_CAMPAIGN_FILE_EXT);
1527 mission_campaign_savefile_delete(filename);
1528 mission_campaign_load(filename);
1529 mission_campaign_next_mission();
1536 void campaign_room_commit()
1538 if (Selected_campaign_index < 0) {
1539 gamesnd_play_iface(SND_GENERAL_FAIL);
1543 if (stricmp(Campaign_file_names[Selected_campaign_index], Campaign.filename)) { // new campaign selected
1544 if ((Active_campaign_index >= 0) && campaign_room_reset_campaign(Active_campaign_index)) {
1545 gamesnd_play_iface(SND_GENERAL_FAIL);
1549 mission_campaign_savefile_delete(Campaign_file_names[Selected_campaign_index]);
1550 mission_campaign_load(Campaign_file_names[Selected_campaign_index]);
1551 strcpy(Player->current_campaign, Campaign.filename); // track new campaign for player
1554 if (mission_campaign_next_mission()) { // is campaign and next mission valid?
1555 gamesnd_play_iface(SND_GENERAL_FAIL);
1559 gameseq_post_event(GS_EVENT_MAIN_MENU);
1560 gamesnd_play_iface(SND_COMMIT_PRESSED);
1563 int campaign_room_button_pressed(int n)
1566 case CR_SCROLL_UP_BUTTON:
1567 sim_room_scroll_screen_up();
1570 case CR_SCROLL_DOWN_BUTTON:
1571 sim_room_scroll_screen_down();
1574 case CR_SCROLL_INFO_UP_BUTTON:
1575 campaign_room_scroll_info_up();
1578 case CR_SCROLL_INFO_DOWN_BUTTON:
1579 campaign_room_scroll_info_down();
1582 case CR_COMMIT_BUTTON:
1583 campaign_room_commit();
1587 case CR_HELP_BUTTON:
1588 launch_context_help();
1589 gamesnd_play_iface(SND_HELP_PRESSED);
1592 case CR_OPTIONS_BUTTON:
1593 gamesnd_play_iface(SND_SWITCH_SCREENS);
1594 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
1598 case CR_RESET_BUTTON:
1599 if ( (Active_campaign_index < 0) || (Active_campaign_index >= Num_campaigns) )
1600 gamesnd_play_iface(SND_GENERAL_FAIL);
1601 else if (campaign_room_reset_campaign(Active_campaign_index))
1602 gamesnd_play_iface(SND_GENERAL_FAIL);
1604 gamesnd_play_iface(SND_USER_SELECT);
1612 void campaign_room_init()
1614 int i, j, load_failed;
1616 char wild_card[256];
1618 list_h = Mission_list_coords[gr_screen.res][3];
1620 // common_set_interface_palette("InterfacePalette"); // set the interface palette
1621 Ui_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
1622 Ui_window.set_mask_bmap(Campaign_mask_filename[gr_screen.res]);
1624 for (i=0; i<CR_NUM_BUTTONS; i++) {
1625 b = &Cr_buttons[gr_screen.res][i];
1627 b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
1628 // set up callback for when a mouse first goes over a button
1629 b->button.set_highlight_action(common_play_highlight_sound);
1630 b->button.set_bmaps(b->filename);
1631 b->button.link_hotspot(b->hotspot);
1634 for (i=0; i<LIST_BUTTONS_MAX; i++) {
1635 List_buttons[i].create(&Ui_window, "", 0, 0, 60, 30, 0, 1);
1636 List_buttons[i].hide();
1637 List_buttons[i].disable();
1641 for(i=0; i<CR_NUM_TEXT; i++){
1642 Ui_window.add_XSTR(&Cr_text[gr_screen.res][i]);
1645 // set up sim_rooms for buttons so we draw the correct animation frame when a key is pressed
1646 Cr_buttons[gr_screen.res][CR_SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
1647 Cr_buttons[gr_screen.res][CR_SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
1648 Cr_buttons[gr_screen.res][CR_RESET_BUTTON].button.set_hotkey(KEY_DELETE);
1649 Cr_buttons[gr_screen.res][CR_COMMIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
1650 // Cr_buttons[gr_screen.res][CR_HELP_BUTTON].button.set_hotkey(KEY_F2);
1652 Background_bitmap = bm_load(Campaign_filename[gr_screen.res]);
1654 // load in help overlay bitmap
1655 help_overlay_load(CAMPAIGN_ROOM_OVERLAY);
1656 help_overlay_set_state(CAMPAIGN_ROOM_OVERLAY,0);
1660 Desc_scroll_offset = Scroll_offset = 0;
1661 load_failed = mission_load_up_campaign();
1663 mission_campaign_next_mission();
1666 Campaign.filename[0] = 0;
1667 Campaign.num_missions = 0;
1672 Get_file_list_filter = campaign_room_campaign_filter;
1673 memset(wild_card, 0, 256);
1674 strcpy(wild_card, NOX("*"));
1675 strcat(wild_card, FS_CAMPAIGN_FILE_EXT);
1676 Num_campaigns = cf_get_file_list(MAX_CAMPAIGNS, Campaign_file_names, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME);
1678 for (i=0; i<Num_campaigns; i++) {
1679 for (j=0; j<Num_campaigns; j++) {
1680 if (Campaign_file_names_temp[j]) {
1681 if (!strncmp(Campaign_file_names[i], Campaign_file_names_temp[j], strlen(Campaign_file_names_temp[j]) - 4)) {
1682 Campaign_descs[i] = Campaign_descs_temp[j];
1683 free(Campaign_file_names_temp[j]);
1684 Campaign_file_names_temp[j] = NULL;
1690 Assert(j < Num_campaigns); // Campaign not found? How is that possible?
1693 Campaign_names_inited = 0;
1694 campaign_room_build_listing();
1696 Selected_campaign_index = Active_campaign_index = -1;
1698 for (i=0; i<Num_campaigns; i++)
1699 if (!stricmp(Campaign_file_names[i], Campaign.filename)) {
1700 set_new_campaign_line(i);
1701 Active_campaign_index = i;
1707 void campaign_room_close()
1711 for (i=0; i<Num_campaigns; i++)
1712 if (Campaign_descs[i])
1713 free(Campaign_descs[i]);
1715 if (Background_bitmap >= 0)
1716 bm_unload(Background_bitmap);
1718 if (Campaign_names_inited)
1719 for (i=0; i<Num_campaigns; i++)
1720 if (Campaign_names[i])
1721 free(Campaign_names[i]);
1723 for (i=0; i<Num_campaigns; i++)
1724 free(Campaign_file_names[i]);
1726 // unload the overlay bitmap
1727 help_overlay_unload(CAMPAIGN_ROOM_OVERLAY);
1729 Ui_window.destroy();
1730 common_free_interface_palette(); // restore game palette
1734 void campaign_room_do_frame(float frametime)
1737 char line_text[MAX_INFO_LINE_LEN];
1739 int font_height = gr_get_font_height();
1740 int select_tease_line = -1; // line mouse is down on, but won't be selected until button released
1742 if ( help_overlay_active(CAMPAIGN_ROOM_OVERLAY) ) {
1743 // Cr_buttons[gr_screen.res][CR_HELP_BUTTON].button.reset_status();
1744 Ui_window.set_ignore_gadgets(1);
1747 k = Ui_window.process() & ~KEY_DEBUGGED;
1749 if ( (k > 0) || B1_JUST_RELEASED ) {
1750 if ( help_overlay_active(CAMPAIGN_ROOM_OVERLAY) ) {
1751 help_overlay_set_state(CAMPAIGN_ROOM_OVERLAY, 0);
1752 Ui_window.set_ignore_gadgets(0);
1757 if ( !help_overlay_active(CAMPAIGN_ROOM_OVERLAY) ) {
1758 Ui_window.set_ignore_gadgets(0);
1762 case KEY_DOWN: // scroll list down
1763 if (Selected_campaign_index < Num_campaigns - 1) {
1764 set_new_campaign_line(Selected_campaign_index + 1);
1765 gamesnd_play_iface(SND_SCROLL);
1768 gamesnd_play_iface(SND_GENERAL_FAIL);
1772 case KEY_UP: // scroll list up
1773 if (Selected_campaign_index < 0)
1774 Selected_campaign_index = 1;
1776 if (Selected_campaign_index) {
1777 set_new_campaign_line(Selected_campaign_index - 1);
1778 gamesnd_play_iface(SND_SCROLL);
1781 gamesnd_play_iface(SND_GENERAL_FAIL);
1786 gameseq_post_event(GS_EVENT_MAIN_MENU);
1790 for (i=0; i<CR_NUM_BUTTONS; i++){
1791 if (Cr_buttons[gr_screen.res][i].button.pressed()){
1792 if (campaign_room_button_pressed(i)){
1798 for (i=0; i<LIST_BUTTONS_MAX; i++) {
1799 if (List_buttons[i].is_mouse_on()){
1800 select_tease_line = i + Scroll_offset;
1803 if (List_buttons[i].pressed()) {
1804 set_new_campaign_line(i + Scroll_offset);
1805 gamesnd_play_iface(SND_USER_SELECT);
1809 GR_MAYBE_CLEAR_RES(Background_bitmap);
1810 if (Background_bitmap >= 0) {
1811 gr_set_bitmap(Background_bitmap);
1818 line = Scroll_offset;
1819 while (sim_room_line_query_visible(line)) {
1820 y = Cr_list_coords[gr_screen.res][1] + sim_room_lines[line].y - sim_room_lines[Scroll_offset].y;
1822 List_buttons[line - Scroll_offset].update_dimensions(Cr_list_coords[gr_screen.res][0], y, Cr_list_coords[gr_screen.res][2], font_height);
1823 List_buttons[line - Scroll_offset].enable();
1825 if (!stricmp(sim_room_lines[line].filename, Campaign.filename)) {
1826 gr_set_color_fast(&Color_white);
1827 i = y + font_height / 2 - 1;
1828 gr_circle(Cr_list_coords[gr_screen.res][0] - 6, i, 5);
1830 gr_set_color_fast(&Color_bright_white);
1831 gr_line(Cr_list_coords[gr_screen.res][0] - 10, i, Cr_list_coords[gr_screen.res][0] - 8, i);
1832 gr_line(Cr_list_coords[gr_screen.res][0] - 6, i - 4, Cr_list_coords[gr_screen.res][0] - 6, i - 2);
1833 gr_line(Cr_list_coords[gr_screen.res][0] - 4, i, Cr_list_coords[gr_screen.res][0] - 2, i);
1834 gr_line(Cr_list_coords[gr_screen.res][0] - 6, i + 2, Cr_list_coords[gr_screen.res][0] - 6, i + 4);
1837 if (line == Selected_campaign_index)
1838 gr_set_color_fast(&Color_text_selected);
1839 else if (line == select_tease_line)
1840 gr_set_color_fast(&Color_text_subselected);
1842 gr_set_color_fast(&Color_text_normal);
1844 strcpy(buf, sim_room_lines[line].name);
1845 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);
1846 gr_printf(sim_room_lines[line].x, y, buf);
1850 i = line - Scroll_offset;
1851 while (i < LIST_BUTTONS_MAX)
1852 List_buttons[i++].disable();
1855 i = Desc_scroll_offset;
1856 gr_set_color_fast(&Color_text_normal);
1858 while (y + font_height <= Cr_info_coords[gr_screen.res][3]) {
1859 if (i >= Num_info_lines)
1862 Assert(Info_text_line_size[i] < MAX_INFO_LINE_LEN);
1863 strncpy(line_text, Info_text_ptrs[i], Info_text_line_size[i]);
1864 line_text[Info_text_line_size[i]] = 0;
1865 drop_white_space(line_text);
1866 gr_string(Cr_info_coords[gr_screen.res][0], Cr_info_coords[gr_screen.res][1] + y, line_text);
1871 // blit help overlay if active
1872 help_overlay_maybe_blit(CAMPAIGN_ROOM_OVERLAY);
1877 void sim_room_load_mission_icons()
1882 for(idx=0; idx<NUM_MISSION_ICONS; idx++){
1883 Mission_icon_bitmaps[idx] = -1;
1884 Mission_icon_bitmaps[idx] = bm_load(Mission_icon_bitmap_filenames[idx]);
1888 void sim_room_unload_mission_icons()
1892 // unload all bitmaps
1893 for(idx=0; idx<NUM_MISSION_ICONS; idx++){
1894 if(Mission_icon_bitmaps[idx] >= 0){
1895 bm_unload(Mission_icon_bitmaps[idx]);
1896 Mission_icon_bitmaps[idx] = -1;