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/Mission/MissionLoad.cpp $
15 * C source module for mission loading
18 * Revision 1.3 2005/03/31 00:04:25 taylor
19 * fix directory separator (thanks Pierre\!)
21 * Revision 1.2 2002/06/09 04:41:22 relnev
22 * added copyright header
24 * Revision 1.1.1.1 2002/05/03 03:28:09 root
28 * 5 7/20/99 1:49p Dave
29 * Peter Drake build. Fixed some release build warnings.
31 * 4 10/13/98 9:28a Dave
32 * Started neatening up freespace.h. Many variables renamed and
33 * reorganized. Added AlphaColors.[h,cpp]
35 * 3 10/07/98 6:27p Dave
36 * Globalized mission and campaign file extensions. Removed Silent Threat
37 * special code. Moved \cache \players and \multidata into the \data
40 * 2 10/07/98 10:53a Dave
43 * 1 10/07/98 10:49a Dave
45 * 102 5/19/98 1:19p Allender
46 * new low level reliable socket reading code. Make all missions/campaign
47 * load/save to data missions folder (i.e. we are rid of the player
50 * 101 5/10/98 10:05p Allender
51 * only show cutscenes which have been seen before. Made Fred able to
52 * write missions anywhere, defaulting to player misison folder, not data
53 * mission folder. Fix FreeSpace code to properly read missions from
56 * 100 4/30/98 4:53p John
57 * Restructured and cleaned up cfile code. Added capability to read off
58 * of CD-ROM drive and out of multiple pack files.
60 * 99 2/23/98 6:55p Lawrance
61 * Rip out obsolete code.
63 * 98 2/23/98 8:53a John
64 * String externalization
66 * 97 1/19/98 9:37p Allender
67 * Great Compiler Warning Purge of Jan, 1998. Used pragma's in a couple
68 * of places since I was unsure of what to do with code.
70 * 96 1/17/98 8:49p Hoffoss
71 * Fixed mission_load() calls to handle failure correctly.
73 * 95 12/28/97 1:34p John
74 * Fixed yet another mission filename bug
76 * 94 12/28/97 12:42p John
77 * Put in support for reading archive files; Made missionload use the
78 * cf_get_file_list function. Moved demos directory out of data tree.
80 * 93 12/27/97 2:39p John
81 * Took out the outdated ui_getfilelist functions. Made the mission load
82 * screen use cf_get_filelist instead. Fixed a bug in mission load that
83 * crashed the program if there are no missions available.
85 * 92 12/23/97 12:00p Allender
86 * change write_pilot_file to *not* take is_single as a default parameter.
87 * causing multiplayer pilots to get written to the single player folder
89 * 91 11/11/97 4:57p Dave
90 * Put in support for single vs. multiplayer pilots. Began work on
91 * multiplayer campaign saving. Put in initial player select screen
93 * 90 10/31/97 11:27a John
94 * appended path for j:\tmp missions
96 * 89 10/31/97 11:19a John
97 * added filter catagory for j:\tmp\*.fsm
99 * 88 10/12/97 5:22p Lawrance
100 * have ESC back out of mission load screen
102 * 87 9/18/97 10:19p Lawrance
103 * Add a mission campaign filter to the load screen
105 * 86 9/16/97 2:41p Allender
106 * beginning of code to change way player starts are handled. Reordered
107 * some code when missions loading since player ship is now created at
108 * mission load time instead of before misison load
110 * 85 8/25/97 5:47p Mike
111 * Increase number of missions supported in mission load list (outside
112 * campaign) to 256 and Assert() if there are more than 256.
114 * 84 8/20/97 5:19p Hoffoss
115 * Fixed bug where creating a new pilot causes the mission load mission
116 * list box to be empty.
118 * 83 7/28/97 10:53a Lawrance
119 * initialize a timestamp
121 * 82 7/17/97 4:25p John
122 * First, broken, stage of changing config stuff
124 * 81 7/05/97 1:47p Lawrance
125 * write pilot file when a mission is loaded
127 * 80 6/26/97 5:53p Lawrance
128 * save recently played missions, allow player to choose from list
130 * 79 6/12/97 12:39p John
131 * made ui use freespace colors
133 * 78 6/12/97 11:35a John
134 * more menu backgrounds
136 * 77 5/14/97 1:33p Allender
137 * remmoved extern declaration
139 * 76 5/12/97 4:59p Allender
140 * move the rest of the mission initialization functions into
141 * game_level_init(). All mission loading now going through this
144 * 75 5/12/97 3:21p Allender
145 * re-ordered mission load code into single function in Freespace.
146 * Simulation part now runs as seperate thread
148 * 74 5/12/97 12:27p John
149 * Restructured Graphics Library to add support for multiple renderers.
151 * 73 4/28/97 5:43p Lawrance
152 * allow hotkey assignment screen to work from ship selection
154 * 72 4/25/97 11:31a Allender
155 * Campaign state now saved in campaign save file in player directory.
156 * Made some global variables follow naming convention. Solidified
157 * continuing campaigns based on new structure
159 * 71 4/23/97 4:46p Allender
162 * 70 4/23/97 3:21p Allender
163 * more campaign stuff -- mission branching through campaign file now
166 * 69 4/22/97 10:44a Allender
167 * more campaign stuff. Info about multiple campaigns now stored in
168 * player file -- not saving some player information in save games.
170 * 68 4/18/97 9:59a Allender
171 * more campaign stuff. All campaign related varaibles now stored in
174 * 67 4/17/97 9:02p Allender
175 * new campaign stuff. all campaign related material stored in external
176 * file. Continuing campaign won't work at this time
178 * 66 4/15/97 4:37p Lawrance
179 * removed unused variables
183 #include "missionload.h"
184 #include "missiongoals.h"
185 #include "missionparse.h"
186 #include "missionshipchoice.h"
187 #include "missionlog.h"
188 #include "missionmessage.h"
196 #include "managepilot.h"
198 #include "freespace.h"
204 #include "linklist.h"
207 #include "gamesequence.h"
210 #include "missionhotkey.h"
211 #include "missioncampaign.h"
212 #include "cfilesystem.h"
213 #include "alphacolors.h"
216 extern mission The_mission; // need to send this info to the briefing
217 extern int shifted_ascii_table[];
218 extern int ascii_table[];
220 // -----------------------------------------------
221 // For recording most recent missions played
222 // -----------------------------------------------
223 char Recent_missions[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN];
224 int Num_recent_missions;
227 // -----------------------------------------------------
228 // ml_update_recent_missions()
230 // Update the Recent_missions[][] array
232 void ml_update_recent_missions(char *filename)
234 char tmp[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN], *p;
238 for ( i = 0; i < Num_recent_missions; i++ ) {
239 strcpy( tmp[i], Recent_missions[i] );
242 // get a pointer to just the basename of the filename (including extension)
243 p = strrchr(filename, DIR_SEPARATOR_CHAR);
250 Assert(strlen(p) < MAX_FILENAME_LEN);
251 strcpy( Recent_missions[0], p );
254 for ( i = 0; i < Num_recent_missions; i++ ) {
255 if ( stricmp(Recent_missions[0], tmp[i]) ) {
256 strcpy(Recent_missions[j++], tmp[i]);
257 if ( j >= MAX_RECENT_MISSIONS ) {
263 Num_recent_missions = j;
264 Assert(Num_recent_missions <= MAX_RECENT_MISSIONS);
267 // Mission_load takes no parameters.
268 // It expects the following global variables to be set correctly:
269 // Game_current_mission_filename
271 // returns -1 if failed, 0 if successful
274 char filename[128], *ext;
276 mprintf(("MISSION LOAD: '%s'\n", Game_current_mission_filename));
278 strncpy(filename, Game_current_mission_filename, 127);
279 ext = strchr(filename, '.');
281 mprintf(( "Hmmm... Extension passed to mission_load...\n" ));
282 *ext = 0; // remove any extension!
285 strcat(filename, FS_MISSION_FILE_EXT);
287 // does the magical mission parsing
288 // creates all objects, except for the player object
289 // save the player object later since the player may get
290 // to choose the type of ship that he is to fly
291 // return value of 0 indicates success, other is failure.
293 if ( parse_main(filename) )
296 if (Select_default_ship) {
298 ret = create_default_player_ship();
302 ml_update_recent_missions(Game_current_mission_filename); // update recently played missions list
307 //====================================
308 // Mission Load Menu stuff
309 #define MLM_MAX_MISSIONS 256
311 UI_WINDOW mlm_window;
312 UI_LISTBOX mlm_mission_list;
313 UI_LISTBOX recent_mission_list;
314 UI_LISTBOX campaign_filter;
316 UI_BUTTON mlm_ok, mlm_cancel;
317 char * mlm_missions[MLM_MAX_MISSIONS];
318 char * recent_missions[MAX_RECENT_MISSIONS];
319 char * campaign_names[MAX_CAMPAIGNS+2];
320 char * campaign_missions[MAX_CAMPAIGN_MISSIONS];
322 static int last_recent_current = -1;
323 static int last_mlm_current = -1;
324 static int Campaign_filter_index;
326 char * jtmp_missions[MLM_MAX_MISSIONS];
330 void ml_change_listbox()
332 if ( !Num_recent_missions || !mlm_nfiles )
335 if ( mlm_mission_list.current() != -1 ) {
336 mlm_mission_list.set_current(-1);
337 last_mlm_current = -1;
338 recent_mission_list.set_focus();
339 recent_mission_list.set_current(0);
343 if ( recent_mission_list.current() != -1 ) {
344 recent_mission_list.set_current(-1);
345 last_recent_current = -1;
346 mlm_mission_list.set_focus();
347 mlm_mission_list.set_current(0);
352 static char Campaign_missions[MAX_CAMPAIGN_MISSIONS][NAME_LENGTH];
353 static char Campaign_name_list[MAX_CAMPAIGNS+2][NAME_LENGTH];
354 static int Num_campaign_missions;
356 // get the mission filenames that make up a campaign
357 extern int mission_campaign_get_filenames(const char *filename, char dest[][NAME_LENGTH], int *num);
359 void mission_load_menu_init()
363 Assert( mlm_active == 0 );
366 memset(wild_card, 0, 256);
367 strcpy(wild_card, NOX("*"));
368 strcat(wild_card, FS_MISSION_FILE_EXT);
369 mlm_nfiles = cf_get_file_list( MLM_MAX_MISSIONS, mlm_missions, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME );
372 Assert(mlm_nfiles <= MLM_MAX_MISSIONS);
374 mlm_window.create( 100,100,500,300, 0 ); //WIN_DIALOG
376 mlm_ok.create( &mlm_window, NOX("Ok"), 125, 420, 80, 40 );
377 mlm_cancel.create( &mlm_window, NOX("Cancel"), 250, 420, 80, 40 );
378 mlm_cancel.set_hotkey( KEY_ESC );
380 mlm_mission_list.create( &mlm_window, 450, 150, 150, 200, mlm_nfiles, mlm_missions );
382 for ( i = 0; i < Num_recent_missions; i++ ) {
383 recent_missions[i] = Recent_missions[i];
385 recent_mission_list.create( &mlm_window, 250, 150, 150, 200, Num_recent_missions, recent_missions );
387 mlm_mission_list.set_focus();
388 mlm_mission_list.set_current(0);
391 mission_campaign_build_list(0);
392 for ( i = 0; i < Num_campaigns; i++ ) {
393 strcpy(Campaign_name_list[i+1], Campaign_names[i]);
395 strcpy(Campaign_name_list[0], NOX("All campaigns"));
396 strcpy(Campaign_name_list[1], NOX("Player Missions"));
398 for ( i = 0; i < Num_campaigns+2; i++ ) {
399 campaign_names[i] = Campaign_name_list[i];
402 campaign_filter.create( &mlm_window, 50, 150, 150, 200, Num_campaigns+2, campaign_names );
403 Campaign_filter_index = 0;
404 campaign_filter.set_current(Campaign_filter_index);
407 void mission_load_menu_do()
409 int selected, key_in, recent_current, mlm_current, use_recent_flag, i;
412 Assert( mlm_active == 1 );
414 key_in = mlm_window.process();
418 switch ( key_in & KEY_MASK ) {
435 gameseq_post_event(GS_EVENT_MAIN_MENU);
445 if ( campaign_filter.current() != Campaign_filter_index ) {
446 Campaign_filter_index = campaign_filter.current();
448 if ( Campaign_filter_index > 1 ) {
449 mission_campaign_get_filenames(Campaign_file_names[Campaign_filter_index-2], Campaign_missions, &Num_campaign_missions);
451 for ( i = 0; i < Num_campaign_missions; i++ ) {
452 campaign_missions[i] = Campaign_missions[i];
454 mlm_mission_list.set_new_list(Num_campaign_missions, campaign_missions);
455 } else if ( Campaign_filter_index == 0 ) {
456 mlm_mission_list.set_new_list(mlm_nfiles, mlm_missions);
457 } else if ( Campaign_filter_index == 1 ) {
458 mlm_mission_list.set_new_list(jtmp_nfiles, jtmp_missions);
463 mlm_current = mlm_mission_list.current();
464 recent_current = recent_mission_list.current();
466 if ( mlm_current != last_mlm_current ) {
467 recent_mission_list.set_current(-1);
468 last_recent_current = -1;
470 last_mlm_current = mlm_current;
472 if ( recent_current != last_recent_current ) {
473 mlm_mission_list.set_current(-1);
474 last_mlm_current = -1;
476 last_recent_current = recent_current;
478 if (mlm_cancel.pressed())
479 gameseq_post_event(GS_EVENT_MAIN_MENU);
481 // Check if they hit OK, if so, use the current listbox
485 if (mlm_ok.pressed()) {
486 selected = mlm_mission_list.current();
487 if ( selected == -1 ) {
488 selected = recent_mission_list.current();
492 // If they didn't hit OK, then check for a double-click on
494 selected = mlm_mission_list.selected();
495 if ( selected == -1 ) {
496 selected = recent_mission_list.selected();
501 char mission_name_final[512] = "";
503 if ( selected > -1 ) {
504 Campaign.current_mission = -1;
505 if ( use_recent_flag ) {
506 strncpy( mission_name_final, recent_missions[selected], MAX_FILENAME_LEN );
508 char mission_name[NAME_LENGTH];
509 if ( Campaign_filter_index == 0 ) {
510 strcpy(mission_name, mlm_missions[selected]);
511 } else if (Campaign_filter_index == 1 ) {
512 strcpy( mission_name, jtmp_missions[selected]);
514 strcpy(mission_name, Campaign_missions[selected]);
516 strncpy( mission_name_final, mission_name, MAX_FILENAME_LEN );
522 if((game_find_builtin_mission(mission_name_final) != NULL) || strstr(mission_name_final, "peterdrake")){
523 strcpy(Game_current_mission_filename, mission_name_final);
524 mprintf(( "Selected '%s'\n", Game_current_mission_filename ));
525 gameseq_post_event(GS_EVENT_START_GAME);
528 strcpy(Game_current_mission_filename, mission_name_final);
529 mprintf(( "Selected '%s'\n", Game_current_mission_filename ));
530 gameseq_post_event(GS_EVENT_START_GAME);
535 gr_set_color_fast( &Color_bright );
536 gr_printf( 0x8000, 10, NOX("Select Mission") );
538 gr_printf( 50, 135, NOX("Campaign Filter"));
539 gr_printf( 250, 135, NOX("Recently Played"));
540 gr_printf( 450, 135, NOX("Mission List"));
546 void mission_load_menu_close()
550 Assert( mlm_active == 1 );
553 for (i=0; i<mlm_nfiles; i++ ) {
554 if (mlm_missions[i] ) {
555 free(mlm_missions[i]);
556 mlm_missions[i] = NULL;
560 for (i=0; i<jtmp_nfiles; i++ ) {
561 if (jtmp_missions[i] ) {
562 free(jtmp_missions[i]);
563 jtmp_missions[i] = NULL;
568 mlm_window.destroy();