]> icculus.org git repositories - taylor/freespace2.git/blob - src/mission/missionload.cpp
SDL2 port - stage 2
[taylor/freespace2.git] / src / mission / missionload.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Mission/MissionLoad.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C source module for mission loading
16  *
17  * $Log$
18  * Revision 1.3  2005/03/31 00:04:25  taylor
19  * fix directory separator (thanks Pierre\!)
20  *
21  * Revision 1.2  2002/06/09 04:41:22  relnev
22  * added copyright header
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:09  root
25  * Initial import.
26  *
27  * 
28  * 5     7/20/99 1:49p Dave
29  * Peter Drake build. Fixed some release build warnings.
30  * 
31  * 4     10/13/98 9:28a Dave
32  * Started neatening up freespace.h. Many variables renamed and
33  * reorganized. Added AlphaColors.[h,cpp]
34  * 
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
38  * directory.
39  * 
40  * 2     10/07/98 10:53a Dave
41  * Initial checkin.
42  * 
43  * 1     10/07/98 10:49a Dave
44  * 
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
48  * missions folder)
49  * 
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
54  * correct locations
55  * 
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.
59  * 
60  * 99    2/23/98 6:55p Lawrance
61  * Rip out obsolete code.
62  * 
63  * 98    2/23/98 8:53a John
64  * String externalization
65  * 
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.
69  * 
70  * 96    1/17/98 8:49p Hoffoss
71  * Fixed mission_load() calls to handle failure correctly.
72  * 
73  * 95    12/28/97 1:34p John
74  * Fixed yet another mission filename bug
75  * 
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.
79  * 
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.
84  * 
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
88  * 
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
92  * 
93  * 90    10/31/97 11:27a John
94  * appended path for j:\tmp missions
95  * 
96  * 89    10/31/97 11:19a John
97  * added filter catagory for j:\tmp\*.fsm
98  * 
99  * 88    10/12/97 5:22p Lawrance
100  * have ESC back out of mission load screen
101  * 
102  * 87    9/18/97 10:19p Lawrance
103  * Add a mission campaign filter to the load screen
104  * 
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
109  * 
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.
113  * 
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.
117  * 
118  * 83    7/28/97 10:53a Lawrance
119  * initialize a timestamp
120  * 
121  * 82    7/17/97 4:25p John
122  * First, broken, stage of changing config stuff
123  * 
124  * 81    7/05/97 1:47p Lawrance
125  * write pilot file when a mission is loaded
126  * 
127  * 80    6/26/97 5:53p Lawrance
128  * save recently played missions, allow player to choose from list
129  * 
130  * 79    6/12/97 12:39p John
131  * made ui use freespace colors
132  * 
133  * 78    6/12/97 11:35a John
134  * more menu backgrounds
135  * 
136  * 77    5/14/97 1:33p Allender
137  * remmoved extern declaration
138  * 
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
142  * fucntion.
143  * 
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
147  * 
148  * 74    5/12/97 12:27p John
149  * Restructured Graphics Library to add support for multiple renderers.
150  * 
151  * 73    4/28/97 5:43p Lawrance
152  * allow hotkey assignment screen to work from ship selection
153  * 
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
158  * 
159  * 71    4/23/97 4:46p Allender
160  * remove unused code
161  * 
162  * 70    4/23/97 3:21p Allender
163  * more campaign stuff -- mission branching through campaign file now
164  * works!!!!
165  * 
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.
169  * 
170  * 68    4/18/97 9:59a Allender
171  * more campaign stuff.  All campaign related varaibles now stored in
172  * campaign structure
173  * 
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
177  * 
178  * 66    4/15/97 4:37p Lawrance
179  * removed unused variables
180  *
181 */
182
183 #include "missionload.h"
184 #include "missiongoals.h"
185 #include "missionparse.h"    
186 #include "missionshipchoice.h"
187 #include "missionlog.h"
188 #include "missionmessage.h"
189 #include "cfile.h"
190 #include "osapi.h"
191 #include "vecmat.h"
192 #include "player.h"
193 #include "object.h"
194 #include "ship.h"
195 #include "ailocal.h"
196 #include "managepilot.h"
197 #include "hud.h"
198 #include "freespace.h"
199 #include "key.h"
200 #include "2d.h"
201 #include "line.h"
202 #include "timer.h"
203 #include "math.h"
204 #include "linklist.h"
205 #include "mouse.h"
206 #include "weapon.h"
207 #include "gamesequence.h"
208 #include "ui.h"
209 #include "sexp.h"
210 #include "missionhotkey.h"
211 #include "missioncampaign.h"
212 #include "cfilesystem.h"
213 #include "alphacolors.h"
214
215
216 extern mission The_mission;  // need to send this info to the briefing
217
218 // -----------------------------------------------
219 // For recording most recent missions played
220 // -----------------------------------------------
221 char    Recent_missions[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN];
222 int     Num_recent_missions;
223
224
225 // -----------------------------------------------------
226 // ml_update_recent_missions()
227 //
228 //      Update the Recent_missions[][] array
229 //
230 void ml_update_recent_missions(char *filename)
231 {
232         char    tmp[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN], *p;
233         int     i,j;
234         
235
236         for ( i = 0; i < Num_recent_missions; i++ ) {
237                 strcpy( tmp[i], Recent_missions[i] );
238         }
239
240         // get a pointer to just the basename of the filename (including extension)
241         p = strrchr(filename, DIR_SEPARATOR_CHAR);
242         if ( p == NULL ) {
243                 p = filename;
244         } else {
245                 p++;
246         }
247
248         Assert(strlen(p) < MAX_FILENAME_LEN);
249         strcpy( Recent_missions[0], p );
250
251         j = 1;
252         for ( i = 0; i < Num_recent_missions; i++ ) {
253                 if ( stricmp(Recent_missions[0], tmp[i]) ) {
254                         strcpy(Recent_missions[j++], tmp[i]);
255                         if ( j >= MAX_RECENT_MISSIONS ) {
256                                 break;
257                         }
258                 }
259         }
260
261         Num_recent_missions = j;
262         Assert(Num_recent_missions <= MAX_RECENT_MISSIONS);
263 }
264
265 // Mission_load takes no parameters.
266 // It expects the following global variables to be set correctly:
267 //   Game_current_mission_filename
268
269 // returns -1 if failed, 0 if successful
270 int mission_load()
271 {
272         char filename[128], *ext;       
273
274         mprintf(("MISSION LOAD: '%s'\n", Game_current_mission_filename));
275
276         strncpy(filename, Game_current_mission_filename, 127);
277         ext = strchr(filename, '.');
278         if (ext) {
279                 mprintf(( "Hmmm... Extension passed to mission_load...\n" ));
280                 *ext = 0;                               // remove any extension!
281         }
282
283         strcat(filename, FS_MISSION_FILE_EXT);
284
285         // does the magical mission parsing
286         // creates all objects, except for the player object
287         // save the player object later since the player may get
288         // to choose the type of ship that he is to fly
289         // return value of 0 indicates success, other is failure.
290
291         if ( parse_main(filename) )
292                 return -1;
293
294         if (Select_default_ship) {
295                 int ret;
296                 ret = create_default_player_ship();
297                 Assert(!ret);
298         }
299
300         ml_update_recent_missions(Game_current_mission_filename);  // update recently played missions list
301         write_pilot_file();
302         return 0;
303 }
304
305 //====================================
306 // Mission Load Menu stuff
307 #define MLM_MAX_MISSIONS 256
308 int mlm_active=0;
309 UI_WINDOW mlm_window;
310 UI_LISTBOX mlm_mission_list;
311 UI_LISTBOX recent_mission_list;
312 UI_LISTBOX campaign_filter;
313
314 UI_BUTTON mlm_ok, mlm_cancel;
315 char * mlm_missions[MLM_MAX_MISSIONS];
316 char * recent_missions[MAX_RECENT_MISSIONS];
317 char * campaign_names[MAX_CAMPAIGNS+2];
318 char * campaign_missions[MAX_CAMPAIGN_MISSIONS];
319 int mlm_nfiles = 0;
320 static int      last_recent_current = -1;
321 static int      last_mlm_current = -1;
322 static int      Campaign_filter_index;
323
324 char * jtmp_missions[MLM_MAX_MISSIONS];
325 int jtmp_nfiles = 0;
326
327
328 void ml_change_listbox()
329 {
330         if ( !Num_recent_missions       || !mlm_nfiles )
331                 return;
332
333         if ( mlm_mission_list.current() != -1 ) {
334                 mlm_mission_list.set_current(-1);
335                 last_mlm_current = -1;
336                 recent_mission_list.set_focus();
337                 recent_mission_list.set_current(0);
338                 return;
339         }
340
341         if ( recent_mission_list.current() != -1 ) {
342                 recent_mission_list.set_current(-1);
343                 last_recent_current = -1;
344                 mlm_mission_list.set_focus();
345                 mlm_mission_list.set_current(0);
346                 return;
347         }
348 }
349
350 static char Campaign_missions[MAX_CAMPAIGN_MISSIONS][NAME_LENGTH];
351 static char Campaign_name_list[MAX_CAMPAIGNS+2][NAME_LENGTH];
352 static int      Num_campaign_missions;
353
354 // get the mission filenames that make up a campaign
355 extern int mission_campaign_get_filenames(const char *filename, char dest[][NAME_LENGTH], int *num);
356
357 void mission_load_menu_init()
358 {
359         int i;
360         char wild_card[256];
361         Assert( mlm_active == 0 );
362         mlm_active = 1;
363
364         memset(wild_card, 0, 256);
365         strcpy(wild_card, NOX("*"));
366         strcat(wild_card, FS_MISSION_FILE_EXT);
367         mlm_nfiles = cf_get_file_list( MLM_MAX_MISSIONS, mlm_missions, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME );
368         jtmp_nfiles = 0;        
369                 
370         Assert(mlm_nfiles <= MLM_MAX_MISSIONS);
371
372         mlm_window.create( 100,100,500,300, 0 );        //WIN_DIALOG
373
374         mlm_ok.create( &mlm_window, NOX("Ok"), 125, 420, 80, 40 );
375         mlm_cancel.create( &mlm_window, NOX("Cancel"), 250, 420, 80, 40 );
376         mlm_cancel.set_hotkey( SDLK_ESCAPE );
377
378         mlm_mission_list.create( &mlm_window, 450, 150, 150, 200, mlm_nfiles, mlm_missions );
379
380         for ( i = 0; i < Num_recent_missions; i++ ) {
381                 recent_missions[i] = Recent_missions[i];
382         }
383         recent_mission_list.create( &mlm_window, 250, 150, 150, 200, Num_recent_missions, recent_missions );
384
385         mlm_mission_list.set_focus();   
386         mlm_mission_list.set_current(0);
387
388
389         mission_campaign_build_list(0);
390         for ( i = 0; i < Num_campaigns; i++ ) {
391                 strcpy(Campaign_name_list[i+1], Campaign_names[i]);
392         }
393         strcpy(Campaign_name_list[0], NOX("All campaigns"));
394         strcpy(Campaign_name_list[1], NOX("Player Missions"));
395
396         for ( i = 0; i < Num_campaigns+2; i++ ) {
397                 campaign_names[i] = Campaign_name_list[i];
398         }
399
400         campaign_filter.create( &mlm_window, 50, 150, 150, 200, Num_campaigns+2, campaign_names );
401         Campaign_filter_index = 0;
402         campaign_filter.set_current(Campaign_filter_index);
403 }
404
405 void mission_load_menu_do()
406 {
407         int     selected, key_in, recent_current, mlm_current, use_recent_flag, i;
408         
409
410         Assert( mlm_active == 1 );
411
412         key_in = mlm_window.process();
413
414         if ( key_in ) {
415
416                 switch ( key_in & KEY_MASK ) {
417
418                 case SDLK_UP:
419                 case SDLK_DOWN:
420                 case SDLK_HOME:
421                 case SDLK_END:
422                 case SDLK_PAGEUP:
423                 case SDLK_PAGEDOWN:
424                 case SDLK_RETURN:
425                         break;
426
427                 case SDLK_RIGHT:
428                 case SDLK_LEFT:
429                         ml_change_listbox();
430                         break;
431
432                 case SDLK_ESCAPE:
433                         gameseq_post_event(GS_EVENT_MAIN_MENU);
434                         break;
435
436                 default:
437                         break;
438
439                 } // end switch
440
441         }
442
443         if ( campaign_filter.current() != Campaign_filter_index ) {
444                 Campaign_filter_index = campaign_filter.current();
445
446                 if ( Campaign_filter_index > 1 ) {
447                         mission_campaign_get_filenames(Campaign_file_names[Campaign_filter_index-2], Campaign_missions, &Num_campaign_missions);
448
449                         for ( i = 0; i < Num_campaign_missions; i++ ) {
450                                 campaign_missions[i] = Campaign_missions[i];
451                         }
452                         mlm_mission_list.set_new_list(Num_campaign_missions, campaign_missions);
453                 } else if ( Campaign_filter_index == 0 ) {
454                         mlm_mission_list.set_new_list(mlm_nfiles, mlm_missions);
455                 } else if ( Campaign_filter_index == 1 ) {
456                         mlm_mission_list.set_new_list(jtmp_nfiles, jtmp_missions); 
457                 }
458                 mlm_current = 0;
459         }
460
461         mlm_current = mlm_mission_list.current();
462         recent_current = recent_mission_list.current();
463
464         if ( mlm_current != last_mlm_current ) {
465                 recent_mission_list.set_current(-1);
466                 last_recent_current = -1;
467         }
468         last_mlm_current = mlm_current;
469
470         if ( recent_current != last_recent_current ) {
471                 mlm_mission_list.set_current(-1);
472                 last_mlm_current = -1;
473         }
474         last_recent_current = recent_current;
475
476         if (mlm_cancel.pressed())
477                 gameseq_post_event(GS_EVENT_MAIN_MENU);
478
479         // Check if they hit OK, if so, use the current listbox
480         // selection.
481         selected = -1;
482         use_recent_flag = 0;
483         if (mlm_ok.pressed())   {
484                 selected = mlm_mission_list.current();
485                 if ( selected == -1 ) {
486                         selected = recent_mission_list.current();
487                         use_recent_flag = 1;
488                 }
489         } else  {
490                 // If they didn't hit OK, then check for a double-click on
491                 // a list box item.
492                 selected = mlm_mission_list.selected();
493                 if ( selected == -1 ) {
494                         selected = recent_mission_list.selected();
495                         use_recent_flag = 1;
496                 }
497         }
498
499         char mission_name_final[512] = "";
500
501         if ( selected > -1  )   {
502                 Campaign.current_mission = -1;
503                 if ( use_recent_flag ) {
504                         strncpy( mission_name_final, recent_missions[selected], MAX_FILENAME_LEN );
505                 } else {
506                         char mission_name[NAME_LENGTH];
507                         if ( Campaign_filter_index == 0 )       {
508                                 strcpy(mission_name, mlm_missions[selected]);
509                         } else if (Campaign_filter_index == 1 ) {
510                                 strcpy( mission_name, jtmp_missions[selected]);
511                         } else {
512                                 strcpy(mission_name, Campaign_missions[selected]);
513                         }
514                         strncpy( mission_name_final, mission_name, MAX_FILENAME_LEN );
515                 }
516
517                 // go
518 #ifdef PD_BUILD
519                 // if this valid
520                 if((game_find_builtin_mission(mission_name_final) != NULL) || strstr(mission_name_final, "peterdrake")){
521                         strcpy(Game_current_mission_filename, mission_name_final);
522                         mprintf(( "Selected '%s'\n", Game_current_mission_filename ));
523                         gameseq_post_event(GS_EVENT_START_GAME);                        
524                 }
525 #else
526                 strcpy(Game_current_mission_filename, mission_name_final);
527                 mprintf(( "Selected '%s'\n", Game_current_mission_filename ));
528                 gameseq_post_event(GS_EVENT_START_GAME);                        
529 #endif
530         }
531
532         gr_clear();
533         gr_set_color_fast( &Color_bright );
534         gr_printf( 0x8000, 10, NOX("Select Mission") );
535
536         gr_printf( 50, 135, NOX("Campaign Filter"));
537         gr_printf( 250, 135, NOX("Recently Played"));
538         gr_printf( 450, 135, NOX("Mission List"));
539         mlm_window.draw();
540
541         gr_flip();
542 }
543
544 void mission_load_menu_close()
545 {
546         int i;
547
548         Assert( mlm_active == 1 );
549         mlm_active = 0;
550
551         for (i=0; i<mlm_nfiles; i++ )   {
552                 if (mlm_missions[i] )   {
553                         free(mlm_missions[i]);
554                         mlm_missions[i] = NULL;
555                 }
556         }
557
558         for (i=0; i<jtmp_nfiles; i++ )  {
559                 if (jtmp_missions[i] )  {
560                         free(jtmp_missions[i]);
561                         jtmp_missions[i] = NULL;
562                 }
563         }
564
565
566         mlm_window.destroy();
567
568 }
569