]> icculus.org git repositories - taylor/freespace2.git/blob - src/mission/missionload.cpp
Initial revision
[taylor/freespace2.git] / src / mission / missionload.cpp
1 /*
2  * $Logfile: /Freespace2/code/Mission/MissionLoad.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * C source module for mission loading
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 5     7/20/99 1:49p Dave
15  * Peter Drake build. Fixed some release build warnings.
16  * 
17  * 4     10/13/98 9:28a Dave
18  * Started neatening up freespace.h. Many variables renamed and
19  * reorganized. Added AlphaColors.[h,cpp]
20  * 
21  * 3     10/07/98 6:27p Dave
22  * Globalized mission and campaign file extensions. Removed Silent Threat
23  * special code. Moved \cache \players and \multidata into the \data
24  * directory.
25  * 
26  * 2     10/07/98 10:53a Dave
27  * Initial checkin.
28  * 
29  * 1     10/07/98 10:49a Dave
30  * 
31  * 102   5/19/98 1:19p Allender
32  * new low level reliable socket reading code.  Make all missions/campaign
33  * load/save to data missions folder (i.e. we are rid of the player
34  * missions folder)
35  * 
36  * 101   5/10/98 10:05p Allender
37  * only show cutscenes which have been seen before.  Made Fred able to
38  * write missions anywhere, defaulting to player misison folder, not data
39  * mission folder.  Fix FreeSpace code to properly read missions from
40  * correct locations
41  * 
42  * 100   4/30/98 4:53p John
43  * Restructured and cleaned up cfile code.  Added capability to read off
44  * of CD-ROM drive and out of multiple pack files.
45  * 
46  * 99    2/23/98 6:55p Lawrance
47  * Rip out obsolete code.
48  * 
49  * 98    2/23/98 8:53a John
50  * String externalization
51  * 
52  * 97    1/19/98 9:37p Allender
53  * Great Compiler Warning Purge of Jan, 1998.  Used pragma's in a couple
54  * of places since I was unsure of what to do with code.
55  * 
56  * 96    1/17/98 8:49p Hoffoss
57  * Fixed mission_load() calls to handle failure correctly.
58  * 
59  * 95    12/28/97 1:34p John
60  * Fixed yet another mission filename bug
61  * 
62  * 94    12/28/97 12:42p John
63  * Put in support for reading archive files; Made missionload use the
64  * cf_get_file_list function.   Moved demos directory out of data tree.
65  * 
66  * 93    12/27/97 2:39p John
67  * Took out the outdated ui_getfilelist functions.  Made the mission load
68  * screen use cf_get_filelist instead.  Fixed a bug in mission load that
69  * crashed the program if there are no missions available.
70  * 
71  * 92    12/23/97 12:00p Allender
72  * change write_pilot_file to *not* take is_single as a default parameter.
73  * causing multiplayer pilots to get written to the single player folder
74  * 
75  * 91    11/11/97 4:57p Dave
76  * Put in support for single vs. multiplayer pilots. Began work on
77  * multiplayer campaign saving. Put in initial player select screen
78  * 
79  * 90    10/31/97 11:27a John
80  * appended path for j:\tmp missions
81  * 
82  * 89    10/31/97 11:19a John
83  * added filter catagory for j:\tmp\*.fsm
84  * 
85  * 88    10/12/97 5:22p Lawrance
86  * have ESC back out of mission load screen
87  * 
88  * 87    9/18/97 10:19p Lawrance
89  * Add a mission campaign filter to the load screen
90  * 
91  * 86    9/16/97 2:41p Allender
92  * beginning of code to change way player starts are handled.  Reordered
93  * some code when missions loading since player ship is now created at
94  * mission load time instead of before misison load
95  * 
96  * 85    8/25/97 5:47p Mike
97  * Increase number of missions supported in mission load list (outside
98  * campaign) to 256 and Assert() if there are more than 256.
99  * 
100  * 84    8/20/97 5:19p Hoffoss
101  * Fixed bug where creating a new pilot causes the mission load mission
102  * list box to be empty.
103  * 
104  * 83    7/28/97 10:53a Lawrance
105  * initialize a timestamp
106  * 
107  * 82    7/17/97 4:25p John
108  * First, broken, stage of changing config stuff
109  * 
110  * 81    7/05/97 1:47p Lawrance
111  * write pilot file when a mission is loaded
112  * 
113  * 80    6/26/97 5:53p Lawrance
114  * save recently played missions, allow player to choose from list
115  * 
116  * 79    6/12/97 12:39p John
117  * made ui use freespace colors
118  * 
119  * 78    6/12/97 11:35a John
120  * more menu backgrounds
121  * 
122  * 77    5/14/97 1:33p Allender
123  * remmoved extern declaration
124  * 
125  * 76    5/12/97 4:59p Allender
126  * move the rest of the mission initialization functions into
127  * game_level_init().  All mission loading now going through this
128  * fucntion.
129  * 
130  * 75    5/12/97 3:21p Allender
131  * re-ordered mission load code into single function in Freespace.
132  * Simulation part now runs as seperate thread
133  * 
134  * 74    5/12/97 12:27p John
135  * Restructured Graphics Library to add support for multiple renderers.
136  * 
137  * 73    4/28/97 5:43p Lawrance
138  * allow hotkey assignment screen to work from ship selection
139  * 
140  * 72    4/25/97 11:31a Allender
141  * Campaign state now saved in campaign save file in player directory.
142  * Made some global variables follow naming convention.  Solidified
143  * continuing campaigns based on new structure
144  * 
145  * 71    4/23/97 4:46p Allender
146  * remove unused code
147  * 
148  * 70    4/23/97 3:21p Allender
149  * more campaign stuff -- mission branching through campaign file now
150  * works!!!!
151  * 
152  * 69    4/22/97 10:44a Allender
153  * more campaign stuff.  Info about multiple campaigns now stored in
154  * player file -- not saving some player information in save games.
155  * 
156  * 68    4/18/97 9:59a Allender
157  * more campaign stuff.  All campaign related varaibles now stored in
158  * campaign structure
159  * 
160  * 67    4/17/97 9:02p Allender
161  * new campaign stuff.  all campaign related material stored in external
162  * file.  Continuing campaign won't work at this time
163  * 
164  * 66    4/15/97 4:37p Lawrance
165  * removed unused variables
166  *
167 */
168
169 #include "missionload.h"
170 #include "missiongoals.h"
171 #include "missionparse.h"    
172 #include "missionshipchoice.h"
173 #include "missionlog.h"
174 #include "missionmessage.h"
175 #include "cfile.h"
176 #include "osapi.h"
177 #include "vecmat.h"
178 #include "player.h"
179 #include "object.h"
180 #include "ship.h"
181 #include "ailocal.h"
182 #include "managepilot.h"
183 #include "hud.h"
184 #include "freespace.h"
185 #include "key.h"
186 #include "2d.h"
187 #include "line.h"
188 #include "timer.h"
189 #include "math.h"
190 #include "linklist.h"
191 #include "mouse.h"
192 #include "weapon.h"
193 #include "gamesequence.h"
194 #include "ui.h"
195 #include "sexp.h"
196 #include "missionhotkey.h"
197 #include "missioncampaign.h"
198 #include "cfilesystem.h"
199 #include "alphacolors.h"
200
201
202 extern mission The_mission;  // need to send this info to the briefing
203 extern int shifted_ascii_table[];
204 extern int ascii_table[];
205
206 // -----------------------------------------------
207 // For recording most recent missions played
208 // -----------------------------------------------
209 char    Recent_missions[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN];
210 int     Num_recent_missions;
211
212
213 // -----------------------------------------------------
214 // ml_update_recent_missions()
215 //
216 //      Update the Recent_missions[][] array
217 //
218 void ml_update_recent_missions(char *filename)
219 {
220         char    tmp[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN], *p;
221         int     i,j;
222         
223
224         for ( i = 0; i < Num_recent_missions; i++ ) {
225                 strcpy( tmp[i], Recent_missions[i] );
226         }
227
228         // get a pointer to just the basename of the filename (including extension)
229         p = strrchr(filename, '\\');
230         if ( p == NULL ) {
231                 p = filename;
232         } else {
233                 p++;
234         }
235
236         Assert(strlen(p) < MAX_FILENAME_LEN);
237         strcpy( Recent_missions[0], p );
238
239         j = 1;
240         for ( i = 0; i < Num_recent_missions; i++ ) {
241                 if ( stricmp(Recent_missions[0], tmp[i]) ) {
242                         strcpy(Recent_missions[j++], tmp[i]);
243                         if ( j >= MAX_RECENT_MISSIONS ) {
244                                 break;
245                         }
246                 }
247         }
248
249         Num_recent_missions = j;
250         Assert(Num_recent_missions <= MAX_RECENT_MISSIONS);
251 }
252
253 // Mission_load takes no parameters.
254 // It expects the following global variables to be set correctly:
255 //   Game_current_mission_filename
256
257 // returns -1 if failed, 0 if successful
258 int mission_load()
259 {
260         char filename[128], *ext;       
261
262         mprintf(("MISSION LOAD: '%s'\n", Game_current_mission_filename));
263
264         strncpy(filename, Game_current_mission_filename, 127);
265         ext = strchr(filename, '.');
266         if (ext) {
267                 mprintf(( "Hmmm... Extension passed to mission_load...\n" ));
268                 *ext = 0;                               // remove any extension!
269         }
270
271         strcat(filename, FS_MISSION_FILE_EXT);
272
273         // does the magical mission parsing
274         // creates all objects, except for the player object
275         // save the player object later since the player may get
276         // to choose the type of ship that he is to fly
277         // return value of 0 indicates success, other is failure.
278
279         if ( parse_main(filename) )
280                 return -1;
281
282         if (Select_default_ship) {
283                 int ret;
284                 ret = create_default_player_ship();
285                 Assert(!ret);
286         }
287
288         ml_update_recent_missions(Game_current_mission_filename);  // update recently played missions list
289         write_pilot_file();
290         return 0;
291 }
292
293 //====================================
294 // Mission Load Menu stuff
295 #define MLM_MAX_MISSIONS 256
296 int mlm_active=0;
297 UI_WINDOW mlm_window;
298 UI_LISTBOX mlm_mission_list;
299 UI_LISTBOX recent_mission_list;
300 UI_LISTBOX campaign_filter;
301
302 UI_BUTTON mlm_ok, mlm_cancel;
303 char * mlm_missions[MLM_MAX_MISSIONS];
304 char * recent_missions[MAX_RECENT_MISSIONS];
305 char * campaign_names[MAX_CAMPAIGNS+2];
306 char * campaign_missions[MAX_CAMPAIGN_MISSIONS];
307 int mlm_nfiles = 0;
308 static int      last_recent_current = -1;
309 static int      last_mlm_current = -1;
310 static int      Campaign_filter_index;
311
312 char * jtmp_missions[MLM_MAX_MISSIONS];
313 int jtmp_nfiles = 0;
314
315
316 void ml_change_listbox()
317 {
318         if ( !Num_recent_missions       || !mlm_nfiles )
319                 return;
320
321         if ( mlm_mission_list.current() != -1 ) {
322                 mlm_mission_list.set_current(-1);
323                 last_mlm_current = -1;
324                 recent_mission_list.set_focus();
325                 recent_mission_list.set_current(0);
326                 return;
327         }
328
329         if ( recent_mission_list.current() != -1 ) {
330                 recent_mission_list.set_current(-1);
331                 last_recent_current = -1;
332                 mlm_mission_list.set_focus();
333                 mlm_mission_list.set_current(0);
334                 return;
335         }
336 }
337
338 static char Campaign_missions[MAX_CAMPAIGN_MISSIONS][NAME_LENGTH];
339 static char Campaign_name_list[MAX_CAMPAIGNS+2][NAME_LENGTH];
340 static int      Num_campaign_missions;
341
342 // get the mission filenames that make up a campaign
343 extern int mission_campaign_get_filenames(char *filename, char dest[][NAME_LENGTH], int *num);
344
345 void mission_load_menu_init()
346 {
347         int i;
348         char wild_card[256];
349         Assert( mlm_active == 0 );
350         mlm_active = 1;
351
352         memset(wild_card, 0, 256);
353         strcpy(wild_card, NOX("*"));
354         strcat(wild_card, FS_MISSION_FILE_EXT);
355         mlm_nfiles = cf_get_file_list( MLM_MAX_MISSIONS, mlm_missions, CF_TYPE_MISSIONS, wild_card, CF_SORT_NAME );
356         jtmp_nfiles = 0;        
357                 
358         Assert(mlm_nfiles <= MLM_MAX_MISSIONS);
359
360         mlm_window.create( 100,100,500,300, 0 );        //WIN_DIALOG
361
362         mlm_ok.create( &mlm_window, NOX("Ok"), 125, 420, 80, 40 );
363         mlm_cancel.create( &mlm_window, NOX("Cancel"), 250, 420, 80, 40 );
364         mlm_cancel.set_hotkey( KEY_ESC );
365
366         mlm_mission_list.create( &mlm_window, 450, 150, 150, 200, mlm_nfiles, mlm_missions );
367
368         for ( i = 0; i < Num_recent_missions; i++ ) {
369                 recent_missions[i] = Recent_missions[i];
370         }
371         recent_mission_list.create( &mlm_window, 250, 150, 150, 200, Num_recent_missions, recent_missions );
372
373         mlm_mission_list.set_focus();   
374         mlm_mission_list.set_current(0);
375
376
377         mission_campaign_build_list(0);
378         for ( i = 0; i < Num_campaigns; i++ ) {
379                 strcpy(Campaign_name_list[i+1], Campaign_names[i]);
380         }
381         strcpy(Campaign_name_list[0], NOX("All campaigns"));
382         strcpy(Campaign_name_list[1], NOX("Player Missions"));
383
384         for ( i = 0; i < Num_campaigns+2; i++ ) {
385                 campaign_names[i] = Campaign_name_list[i];
386         }
387
388         campaign_filter.create( &mlm_window, 50, 150, 150, 200, Num_campaigns+2, campaign_names );
389         Campaign_filter_index = 0;
390         campaign_filter.set_current(Campaign_filter_index);
391 }
392
393 void mission_load_menu_do()
394 {
395         int     selected, key_in, recent_current, mlm_current, use_recent_flag, i;
396         
397
398         Assert( mlm_active == 1 );
399
400         key_in = mlm_window.process();
401
402         if ( key_in ) {
403
404                 switch ( key_in & KEY_MASK ) {
405
406                 case KEY_UP:
407                 case KEY_DOWN:
408                 case KEY_HOME:
409                 case KEY_END:
410                 case KEY_PAGEUP:
411                 case KEY_PAGEDOWN:
412                 case KEY_ENTER:
413                         break;
414
415                 case KEY_RIGHT:
416                 case KEY_LEFT:
417                         ml_change_listbox();
418                         break;
419
420                 case KEY_ESC:
421                         gameseq_post_event(GS_EVENT_MAIN_MENU);
422                         break;
423
424                 default:
425                         break;
426
427                 } // end switch
428
429         }
430
431         if ( campaign_filter.current() != Campaign_filter_index ) {
432                 Campaign_filter_index = campaign_filter.current();
433
434                 if ( Campaign_filter_index > 1 ) {
435                         mission_campaign_get_filenames(Campaign_file_names[Campaign_filter_index-2], Campaign_missions, &Num_campaign_missions);
436
437                         for ( i = 0; i < Num_campaign_missions; i++ ) {
438                                 campaign_missions[i] = Campaign_missions[i];
439                         }
440                         mlm_mission_list.set_new_list(Num_campaign_missions, campaign_missions);
441                 } else if ( Campaign_filter_index == 0 ) {
442                         mlm_mission_list.set_new_list(mlm_nfiles, mlm_missions);
443                 } else if ( Campaign_filter_index == 1 ) {
444                         mlm_mission_list.set_new_list(jtmp_nfiles, jtmp_missions); 
445                 }
446                 mlm_current = 0;
447         }
448
449         mlm_current = mlm_mission_list.current();
450         recent_current = recent_mission_list.current();
451
452         if ( mlm_current != last_mlm_current ) {
453                 recent_mission_list.set_current(-1);
454                 last_recent_current = -1;
455         }
456         last_mlm_current = mlm_current;
457
458         if ( recent_current != last_recent_current ) {
459                 mlm_mission_list.set_current(-1);
460                 last_mlm_current = -1;
461         }
462         last_recent_current = recent_current;
463
464         if (mlm_cancel.pressed())
465                 gameseq_post_event(GS_EVENT_MAIN_MENU);
466
467         // Check if they hit OK, if so, use the current listbox
468         // selection.
469         selected = -1;
470         use_recent_flag = 0;
471         if (mlm_ok.pressed())   {
472                 selected = mlm_mission_list.current();
473                 if ( selected == -1 ) {
474                         selected = recent_mission_list.current();
475                         use_recent_flag = 1;
476                 }
477         } else  {
478                 // If they didn't hit OK, then check for a double-click on
479                 // a list box item.
480                 selected = mlm_mission_list.selected();
481                 if ( selected == -1 ) {
482                         selected = recent_mission_list.selected();
483                         use_recent_flag = 1;
484                 }
485         }
486
487         char mission_name_final[512] = "";
488
489         if ( selected > -1  )   {
490                 Campaign.current_mission = -1;
491                 if ( use_recent_flag ) {
492                         strncpy( mission_name_final, recent_missions[selected], MAX_FILENAME_LEN );
493                 } else {
494                         char mission_name[NAME_LENGTH];
495                         if ( Campaign_filter_index == 0 )       {
496                                 strcpy(mission_name, mlm_missions[selected]);
497                         } else if (Campaign_filter_index == 1 ) {
498                                 strcpy( mission_name, jtmp_missions[selected]);
499                         } else {
500                                 strcpy(mission_name, Campaign_missions[selected]);
501                         }
502                         strncpy( mission_name_final, mission_name, MAX_FILENAME_LEN );
503                 }
504
505                 // go
506 #ifdef PD_BUILD
507                 // if this valid
508                 if((game_find_builtin_mission(mission_name_final) != NULL) || strstr(mission_name_final, "peterdrake")){
509                         strcpy(Game_current_mission_filename, mission_name_final);
510                         mprintf(( "Selected '%s'\n", Game_current_mission_filename ));
511                         gameseq_post_event(GS_EVENT_START_GAME);                        
512                 }
513 #else
514                 strcpy(Game_current_mission_filename, mission_name_final);
515                 mprintf(( "Selected '%s'\n", Game_current_mission_filename ));
516                 gameseq_post_event(GS_EVENT_START_GAME);                        
517 #endif
518         }
519
520         gr_clear();
521         gr_set_color_fast( &Color_bright );
522         gr_printf( 0x8000, 10, NOX("Select Mission") );
523
524         gr_printf( 50, 135, NOX("Campaign Filter"));
525         gr_printf( 250, 135, NOX("Recently Played"));
526         gr_printf( 450, 135, NOX("Mission List"));
527         mlm_window.draw();
528
529         gr_flip();
530 }
531
532 void mission_load_menu_close()
533 {
534         int i;
535
536         Assert( mlm_active == 1 );
537         mlm_active = 0;
538
539         for (i=0; i<mlm_nfiles; i++ )   {
540                 if (mlm_missions[i] )   {
541                         free(mlm_missions[i]);
542                         mlm_missions[i] = NULL;
543                 }
544         }
545
546         for (i=0; i<jtmp_nfiles; i++ )  {
547                 if (jtmp_missions[i] )  {
548                         free(jtmp_missions[i]);
549                         jtmp_missions[i] = NULL;
550                 }
551         }
552
553
554         mlm_window.destroy();
555
556 }
557