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.2 2002/06/09 04:41:22 relnev
19 * added copyright header
21 * Revision 1.1.1.1 2002/05/03 03:28:09 root
25 * 5 7/20/99 1:49p Dave
26 * Peter Drake build. Fixed some release build warnings.
28 * 4 10/13/98 9:28a Dave
29 * Started neatening up freespace.h. Many variables renamed and
30 * reorganized. Added AlphaColors.[h,cpp]
32 * 3 10/07/98 6:27p Dave
33 * Globalized mission and campaign file extensions. Removed Silent Threat
34 * special code. Moved \cache \players and \multidata into the \data
37 * 2 10/07/98 10:53a Dave
40 * 1 10/07/98 10:49a Dave
42 * 102 5/19/98 1:19p Allender
43 * new low level reliable socket reading code. Make all missions/campaign
44 * load/save to data missions folder (i.e. we are rid of the player
47 * 101 5/10/98 10:05p Allender
48 * only show cutscenes which have been seen before. Made Fred able to
49 * write missions anywhere, defaulting to player misison folder, not data
50 * mission folder. Fix FreeSpace code to properly read missions from
53 * 100 4/30/98 4:53p John
54 * Restructured and cleaned up cfile code. Added capability to read off
55 * of CD-ROM drive and out of multiple pack files.
57 * 99 2/23/98 6:55p Lawrance
58 * Rip out obsolete code.
60 * 98 2/23/98 8:53a John
61 * String externalization
63 * 97 1/19/98 9:37p Allender
64 * Great Compiler Warning Purge of Jan, 1998. Used pragma's in a couple
65 * of places since I was unsure of what to do with code.
67 * 96 1/17/98 8:49p Hoffoss
68 * Fixed mission_load() calls to handle failure correctly.
70 * 95 12/28/97 1:34p John
71 * Fixed yet another mission filename bug
73 * 94 12/28/97 12:42p John
74 * Put in support for reading archive files; Made missionload use the
75 * cf_get_file_list function. Moved demos directory out of data tree.
77 * 93 12/27/97 2:39p John
78 * Took out the outdated ui_getfilelist functions. Made the mission load
79 * screen use cf_get_filelist instead. Fixed a bug in mission load that
80 * crashed the program if there are no missions available.
82 * 92 12/23/97 12:00p Allender
83 * change write_pilot_file to *not* take is_single as a default parameter.
84 * causing multiplayer pilots to get written to the single player folder
86 * 91 11/11/97 4:57p Dave
87 * Put in support for single vs. multiplayer pilots. Began work on
88 * multiplayer campaign saving. Put in initial player select screen
90 * 90 10/31/97 11:27a John
91 * appended path for j:\tmp missions
93 * 89 10/31/97 11:19a John
94 * added filter catagory for j:\tmp\*.fsm
96 * 88 10/12/97 5:22p Lawrance
97 * have ESC back out of mission load screen
99 * 87 9/18/97 10:19p Lawrance
100 * Add a mission campaign filter to the load screen
102 * 86 9/16/97 2:41p Allender
103 * beginning of code to change way player starts are handled. Reordered
104 * some code when missions loading since player ship is now created at
105 * mission load time instead of before misison load
107 * 85 8/25/97 5:47p Mike
108 * Increase number of missions supported in mission load list (outside
109 * campaign) to 256 and Assert() if there are more than 256.
111 * 84 8/20/97 5:19p Hoffoss
112 * Fixed bug where creating a new pilot causes the mission load mission
113 * list box to be empty.
115 * 83 7/28/97 10:53a Lawrance
116 * initialize a timestamp
118 * 82 7/17/97 4:25p John
119 * First, broken, stage of changing config stuff
121 * 81 7/05/97 1:47p Lawrance
122 * write pilot file when a mission is loaded
124 * 80 6/26/97 5:53p Lawrance
125 * save recently played missions, allow player to choose from list
127 * 79 6/12/97 12:39p John
128 * made ui use freespace colors
130 * 78 6/12/97 11:35a John
131 * more menu backgrounds
133 * 77 5/14/97 1:33p Allender
134 * remmoved extern declaration
136 * 76 5/12/97 4:59p Allender
137 * move the rest of the mission initialization functions into
138 * game_level_init(). All mission loading now going through this
141 * 75 5/12/97 3:21p Allender
142 * re-ordered mission load code into single function in Freespace.
143 * Simulation part now runs as seperate thread
145 * 74 5/12/97 12:27p John
146 * Restructured Graphics Library to add support for multiple renderers.
148 * 73 4/28/97 5:43p Lawrance
149 * allow hotkey assignment screen to work from ship selection
151 * 72 4/25/97 11:31a Allender
152 * Campaign state now saved in campaign save file in player directory.
153 * Made some global variables follow naming convention. Solidified
154 * continuing campaigns based on new structure
156 * 71 4/23/97 4:46p Allender
159 * 70 4/23/97 3:21p Allender
160 * more campaign stuff -- mission branching through campaign file now
163 * 69 4/22/97 10:44a Allender
164 * more campaign stuff. Info about multiple campaigns now stored in
165 * player file -- not saving some player information in save games.
167 * 68 4/18/97 9:59a Allender
168 * more campaign stuff. All campaign related varaibles now stored in
171 * 67 4/17/97 9:02p Allender
172 * new campaign stuff. all campaign related material stored in external
173 * file. Continuing campaign won't work at this time
175 * 66 4/15/97 4:37p Lawrance
176 * removed unused variables
180 #include "missionload.h"
181 #include "missiongoals.h"
182 #include "missionparse.h"
183 #include "missionshipchoice.h"
184 #include "missionlog.h"
185 #include "missionmessage.h"
193 #include "managepilot.h"
195 #include "freespace.h"
201 #include "linklist.h"
204 #include "gamesequence.h"
207 #include "missionhotkey.h"
208 #include "missioncampaign.h"
209 #include "cfilesystem.h"
210 #include "alphacolors.h"
213 extern mission The_mission; // need to send this info to the briefing
214 extern int shifted_ascii_table[];
215 extern int ascii_table[];
217 // -----------------------------------------------
218 // For recording most recent missions played
219 // -----------------------------------------------
220 char Recent_missions[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN];
221 int Num_recent_missions;
224 // -----------------------------------------------------
225 // ml_update_recent_missions()
227 // Update the Recent_missions[][] array
229 void ml_update_recent_missions(char *filename)
231 char tmp[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN], *p;
235 for ( i = 0; i < Num_recent_missions; i++ ) {
236 strcpy( tmp[i], Recent_missions[i] );
239 // get a pointer to just the basename of the filename (including extension)
240 p = strrchr(filename, '\\');
247 Assert(strlen(p) < MAX_FILENAME_LEN);
248 strcpy( Recent_missions[0], p );
251 for ( i = 0; i < Num_recent_missions; i++ ) {
252 if ( stricmp(Recent_missions[0], tmp[i]) ) {
253 strcpy(Recent_missions[j++], tmp[i]);
254 if ( j >= MAX_RECENT_MISSIONS ) {
260 Num_recent_missions = j;
261 Assert(Num_recent_missions <= MAX_RECENT_MISSIONS);
264 // Mission_load takes no parameters.
265 // It expects the following global variables to be set correctly:
266 // Game_current_mission_filename
268 // returns -1 if failed, 0 if successful
271 char filename[128], *ext;
273 mprintf(("MISSION LOAD: '%s'\n", Game_current_mission_filename));
275 strncpy(filename, Game_current_mission_filename, 127);
276 ext = strchr(filename, '.');
278 mprintf(( "Hmmm... Extension passed to mission_load...\n" ));
279 *ext = 0; // remove any extension!
282 strcat(filename, FS_MISSION_FILE_EXT);
284 // does the magical mission parsing
285 // creates all objects, except for the player object
286 // save the player object later since the player may get
287 // to choose the type of ship that he is to fly
288 // return value of 0 indicates success, other is failure.
290 if ( parse_main(filename) )
293 if (Select_default_ship) {
295 ret = create_default_player_ship();
299 ml_update_recent_missions(Game_current_mission_filename); // update recently played missions list
304 //====================================
305 // Mission Load Menu stuff
306 #define MLM_MAX_MISSIONS 256
308 UI_WINDOW mlm_window;
309 UI_LISTBOX mlm_mission_list;
310 UI_LISTBOX recent_mission_list;
311 UI_LISTBOX campaign_filter;
313 UI_BUTTON mlm_ok, mlm_cancel;
314 char * mlm_missions[MLM_MAX_MISSIONS];
315 char * recent_missions[MAX_RECENT_MISSIONS];
316 char * campaign_names[MAX_CAMPAIGNS+2];
317 char * campaign_missions[MAX_CAMPAIGN_MISSIONS];
319 static int last_recent_current = -1;
320 static int last_mlm_current = -1;
321 static int Campaign_filter_index;
323 char * jtmp_missions[MLM_MAX_MISSIONS];
327 void ml_change_listbox()
329 if ( !Num_recent_missions || !mlm_nfiles )
332 if ( mlm_mission_list.current() != -1 ) {
333 mlm_mission_list.set_current(-1);
334 last_mlm_current = -1;
335 recent_mission_list.set_focus();
336 recent_mission_list.set_current(0);
340 if ( recent_mission_list.current() != -1 ) {
341 recent_mission_list.set_current(-1);
342 last_recent_current = -1;
343 mlm_mission_list.set_focus();
344 mlm_mission_list.set_current(0);
349 static char Campaign_missions[MAX_CAMPAIGN_MISSIONS][NAME_LENGTH];
350 static char Campaign_name_list[MAX_CAMPAIGNS+2][NAME_LENGTH];
351 static int Num_campaign_missions;
353 // get the mission filenames that make up a campaign
354 extern int mission_campaign_get_filenames(char *filename, char dest[][NAME_LENGTH], int *num);
356 void mission_load_menu_init()
360 Assert( mlm_active == 0 );
363 memset(wild_card, 0, 256);
364 strcpy(wild_card, NOX("*"));
365 strcat(wild_card, FS_MISSION_FILE_EXT);
366 mlm_nfiles = cf_get_file_list( MLM_MAX_MISSIONS, mlm_missions, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME );
369 Assert(mlm_nfiles <= MLM_MAX_MISSIONS);
371 mlm_window.create( 100,100,500,300, 0 ); //WIN_DIALOG
373 mlm_ok.create( &mlm_window, NOX("Ok"), 125, 420, 80, 40 );
374 mlm_cancel.create( &mlm_window, NOX("Cancel"), 250, 420, 80, 40 );
375 mlm_cancel.set_hotkey( KEY_ESC );
377 mlm_mission_list.create( &mlm_window, 450, 150, 150, 200, mlm_nfiles, mlm_missions );
379 for ( i = 0; i < Num_recent_missions; i++ ) {
380 recent_missions[i] = Recent_missions[i];
382 recent_mission_list.create( &mlm_window, 250, 150, 150, 200, Num_recent_missions, recent_missions );
384 mlm_mission_list.set_focus();
385 mlm_mission_list.set_current(0);
388 mission_campaign_build_list(0);
389 for ( i = 0; i < Num_campaigns; i++ ) {
390 strcpy(Campaign_name_list[i+1], Campaign_names[i]);
392 strcpy(Campaign_name_list[0], NOX("All campaigns"));
393 strcpy(Campaign_name_list[1], NOX("Player Missions"));
395 for ( i = 0; i < Num_campaigns+2; i++ ) {
396 campaign_names[i] = Campaign_name_list[i];
399 campaign_filter.create( &mlm_window, 50, 150, 150, 200, Num_campaigns+2, campaign_names );
400 Campaign_filter_index = 0;
401 campaign_filter.set_current(Campaign_filter_index);
404 void mission_load_menu_do()
406 int selected, key_in, recent_current, mlm_current, use_recent_flag, i;
409 Assert( mlm_active == 1 );
411 key_in = mlm_window.process();
415 switch ( key_in & KEY_MASK ) {
432 gameseq_post_event(GS_EVENT_MAIN_MENU);
442 if ( campaign_filter.current() != Campaign_filter_index ) {
443 Campaign_filter_index = campaign_filter.current();
445 if ( Campaign_filter_index > 1 ) {
446 mission_campaign_get_filenames(Campaign_file_names[Campaign_filter_index-2], Campaign_missions, &Num_campaign_missions);
448 for ( i = 0; i < Num_campaign_missions; i++ ) {
449 campaign_missions[i] = Campaign_missions[i];
451 mlm_mission_list.set_new_list(Num_campaign_missions, campaign_missions);
452 } else if ( Campaign_filter_index == 0 ) {
453 mlm_mission_list.set_new_list(mlm_nfiles, mlm_missions);
454 } else if ( Campaign_filter_index == 1 ) {
455 mlm_mission_list.set_new_list(jtmp_nfiles, jtmp_missions);
460 mlm_current = mlm_mission_list.current();
461 recent_current = recent_mission_list.current();
463 if ( mlm_current != last_mlm_current ) {
464 recent_mission_list.set_current(-1);
465 last_recent_current = -1;
467 last_mlm_current = mlm_current;
469 if ( recent_current != last_recent_current ) {
470 mlm_mission_list.set_current(-1);
471 last_mlm_current = -1;
473 last_recent_current = recent_current;
475 if (mlm_cancel.pressed())
476 gameseq_post_event(GS_EVENT_MAIN_MENU);
478 // Check if they hit OK, if so, use the current listbox
482 if (mlm_ok.pressed()) {
483 selected = mlm_mission_list.current();
484 if ( selected == -1 ) {
485 selected = recent_mission_list.current();
489 // If they didn't hit OK, then check for a double-click on
491 selected = mlm_mission_list.selected();
492 if ( selected == -1 ) {
493 selected = recent_mission_list.selected();
498 char mission_name_final[512] = "";
500 if ( selected > -1 ) {
501 Campaign.current_mission = -1;
502 if ( use_recent_flag ) {
503 strncpy( mission_name_final, recent_missions[selected], MAX_FILENAME_LEN );
505 char mission_name[NAME_LENGTH];
506 if ( Campaign_filter_index == 0 ) {
507 strcpy(mission_name, mlm_missions[selected]);
508 } else if (Campaign_filter_index == 1 ) {
509 strcpy( mission_name, jtmp_missions[selected]);
511 strcpy(mission_name, Campaign_missions[selected]);
513 strncpy( mission_name_final, mission_name, MAX_FILENAME_LEN );
519 if((game_find_builtin_mission(mission_name_final) != NULL) || strstr(mission_name_final, "peterdrake")){
520 strcpy(Game_current_mission_filename, mission_name_final);
521 mprintf(( "Selected '%s'\n", Game_current_mission_filename ));
522 gameseq_post_event(GS_EVENT_START_GAME);
525 strcpy(Game_current_mission_filename, mission_name_final);
526 mprintf(( "Selected '%s'\n", Game_current_mission_filename ));
527 gameseq_post_event(GS_EVENT_START_GAME);
532 gr_set_color_fast( &Color_bright );
533 gr_printf( 0x8000, 10, NOX("Select Mission") );
535 gr_printf( 50, 135, NOX("Campaign Filter"));
536 gr_printf( 250, 135, NOX("Recently Played"));
537 gr_printf( 450, 135, NOX("Mission List"));
543 void mission_load_menu_close()
547 Assert( mlm_active == 1 );
550 for (i=0; i<mlm_nfiles; i++ ) {
551 if (mlm_missions[i] ) {
552 free(mlm_missions[i]);
553 mlm_missions[i] = NULL;
557 for (i=0; i<jtmp_nfiles; i++ ) {
558 if (jtmp_missions[i] ) {
559 free(jtmp_missions[i]);
560 jtmp_missions[i] = NULL;
565 mlm_window.destroy();