1 /* $Id: mission.c,v 1.8 2002-08-23 01:52:11 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Stuff for loading missions
45 mle Mission_list[MAX_MISSIONS];
47 int Current_mission_num;
48 int N_secret_levels; // Made a global by MK for scoring purposes. August 1, 1995.
49 char *Current_mission_filename,*Current_mission_longname;
51 //this stuff should get defined elsewhere
53 char Level_names[MAX_LEVELS_PER_MISSION][FILENAME_LEN];
54 char Secret_level_names[MAX_SECRET_LEVELS_PER_MISSION][FILENAME_LEN];
56 //where the missions go
58 #define MISSION_DIR "missions/"
60 #define MISSION_DIR "./"
63 #define SHAREWARE_MISSION_FILENAME "d2demo"
64 #define SHAREWARE_MISSION_NAME "Descent 2 Demo"
65 #define SHAREWARE_MISSION_HOGSIZE 2292566
66 #define MAC_SHARE_MISSION_HOGSIZE 4292746
68 #define OEM_MISSION_FILENAME "d2"
69 #define OEM_MISSION_NAME "D2 Destination:Quartzon"
70 #define OEM_MISSION_HOGSIZE 6132957
72 #define FULL_MISSION_FILENAME "d2.mn2"
73 #define FULL_MISSION_HOGSIZE 7595079
75 char *builtin_mission;
76 int builtin_mission_hogsize;
79 // Special versions of mission routines for shareware
82 int load_mission_shareware(int mission_num)
84 Current_mission_num = mission_num;
85 Current_mission_filename = Mission_list[mission_num].filename;
86 Current_mission_longname = Mission_list[mission_num].mission_name;
91 Last_secret_level = 0;
93 switch (builtin_mission_hogsize) {
94 case MAC_SHARE_MISSION_HOGSIZE:
95 // mac demo is using the regular hog and rl2 files
96 strcpy(Level_names[0],"d2leva-1.rl2");
97 strcpy(Level_names[1],"d2leva-2.rl2");
98 strcpy(Level_names[2],"d2leva-3.rl2");
101 Int3(); // fall through
102 case SHAREWARE_MISSION_HOGSIZE:
103 strcpy(Level_names[0],"d2leva-1.sl2");
104 strcpy(Level_names[1],"d2leva-2.sl2");
105 strcpy(Level_names[2],"d2leva-3.sl2");
113 // Special versions of mission routines for Diamond/S3 version
116 int load_mission_oem(int mission_num)
118 Current_mission_num = mission_num;
119 Current_mission_filename = Mission_list[mission_num].filename;
120 Current_mission_longname = Mission_list[mission_num].mission_name;
125 Last_secret_level = -2;
127 strcpy(Level_names[0],"d2leva-1.rl2");
128 strcpy(Level_names[1],"d2leva-2.rl2");
129 strcpy(Level_names[2],"d2leva-3.rl2");
130 strcpy(Level_names[3],"d2leva-4.rl2");
132 strcpy(Secret_level_names[0],"d2leva-s.rl2");
134 strcpy(Level_names[4],"d2levb-1.rl2");
135 strcpy(Level_names[5],"d2levb-2.rl2");
136 strcpy(Level_names[6],"d2levb-3.rl2");
137 strcpy(Level_names[7],"d2levb-4.rl2");
139 strcpy(Secret_level_names[1],"d2levb-s.rl2");
141 Secret_level_table[0] = 1;
142 Secret_level_table[1] = 5;
148 //strips damn newline from end of line
149 char *mfgets(char *s,int n,CFILE *f)
154 if (r && s[strlen(s)-1] == '\n')
160 //compare a string for a token. returns true if match
161 int istok(char *buf,char *tok)
163 return strnicmp(buf,tok,strlen(tok)) == 0;
167 //adds a terminating 0 after a string at the first white space
168 void add_term(char *s)
170 while (*s && !isspace(*s)) s++;
175 //returns ptr to string after '=' & white space, or NULL if no '='
176 //adds 0 after parm at first white space
177 char *get_value(char *buf)
181 t = strchr(buf,'=')+1;
184 while (*t && isspace(*t)) t++;
190 return NULL; //error!
193 //reads a line, returns ptr to value of passed parm. returns NULL if none
194 char *get_parm_value(char *parm,CFILE *f)
198 if (!mfgets(buf,80,f))
202 return get_value(buf);
207 int ml_sort_func(mle *e0,mle *e1)
209 return stricmp(e0->mission_name,e1->mission_name);
213 extern char CDROM_dir[];
214 extern int HoardEquipped();
216 //returns 1 if file read ok, else 0
217 int read_mission_file(char *filename,int count,int location)
222 printf("reading: %s\n", filename);
226 strcpy(filename2,MISSION_DIR);
230 songs_stop_redbook(); //so we can read from the CD
231 strcpy(filename2,CDROM_dir);
235 Int3(); //fall through
238 strcpy(filename2,"");
241 strcat(filename2,filename);
243 mfile = cfopen(filename2,"rb");
247 char temp[FILENAME_LEN],*t;
249 strcpy(temp,filename);
250 if ((t = strchr(temp,'.')) == NULL)
251 return 0; //missing extension
252 // look if it's .mn2 or .msn
253 Mission_list[count].descent_version = (t[3] == '2') ? 2 : 1;
254 *t = 0; //kill extension
256 strncpy( Mission_list[count].filename, temp, 9 );
257 Mission_list[count].anarchy_only_flag = 0;
258 Mission_list[count].location = location;
260 p = get_parm_value("name",mfile);
262 if (!p) { //try enhanced mission
263 cfseek(mfile,0,SEEK_SET);
264 p = get_parm_value("xname",mfile);
270 if (!p) { //try super-enhanced mission!
271 cfseek(mfile,0,SEEK_SET);
272 p = get_parm_value("zname",mfile);
279 if ((t=strchr(p,';'))!=NULL)
282 while (isspace(*t)) t--;
283 strncpy(Mission_list[count].mission_name,p,MISSION_NAME_LEN);
290 p = get_parm_value("type",mfile);
294 Mission_list[count].anarchy_only_flag = istok(p,"anarchy");
304 void add_builtin_mission_to_list(int *count)
306 builtin_mission_hogsize = cfile_size("descent2.hog");
307 if (builtin_mission_hogsize == -1)
308 builtin_mission_hogsize = cfile_size("d2demo.hog");
310 switch (builtin_mission_hogsize) {
311 case SHAREWARE_MISSION_HOGSIZE:
312 case MAC_SHARE_MISSION_HOGSIZE:
313 strcpy(Mission_list[*count].filename,SHAREWARE_MISSION_FILENAME);
314 strcpy(Mission_list[*count].mission_name,SHAREWARE_MISSION_NAME);
315 Mission_list[*count].anarchy_only_flag = 0;
317 case OEM_MISSION_HOGSIZE:
318 strcpy(Mission_list[*count].filename,OEM_MISSION_FILENAME);
319 strcpy(Mission_list[*count].mission_name,OEM_MISSION_NAME);
320 Mission_list[*count].anarchy_only_flag = 0;
323 Warning("Unknown hogsize %d, trying %s\n", builtin_mission_hogsize, FULL_MISSION_FILENAME);
324 Int3(); //fall through
325 case FULL_MISSION_HOGSIZE:
326 if (!read_mission_file(FULL_MISSION_FILENAME,0,ML_CURDIR))
327 Error("Could not find required mission file <%s>", FULL_MISSION_FILENAME);
330 builtin_mission = strdup(Mission_list[*count].filename);
335 void add_missions_to_list(char *search_name, int *count, int anarchy_mode)
338 if( !FileFindFirst( search_name, &find ) ) {
340 if (read_mission_file( find.name, *count, ML_MISSIONDIR )) {
342 if (anarchy_mode || !Mission_list[*count].anarchy_only_flag)
346 } while( !FileFindNext( &find ) && *count < MAX_MISSIONS);
348 if (*count >= MAX_MISSIONS)
349 mprintf((0, "Warning: more missions than d2x can handle\n"));
353 /* move <mission_name> to <place> on mission list, increment <place> */
354 void promote (char * mission_name, int * top_place, int num_missions) {
356 char name[FILENAME_LEN], * t;
357 strcpy(name, mission_name);
358 if ((t = strchr(name,'.')) != NULL)
359 *t = 0; //kill extension
360 printf("promoting: %s\n", name);
361 for (i = *top_place; i < num_missions; i++)
362 if (!stricmp(Mission_list[i].filename, name)) {
363 //swap mission positions
365 temp = Mission_list[*top_place];
366 Mission_list[*top_place] = Mission_list[i];
367 Mission_list[i] = temp;
375 //fills in the global list of missions. Returns the number of missions
376 //in the list. If anarchy_mode set, don't include non-anarchy levels.
378 extern char CDROM_dir[];
379 extern char AltHogDir[];
380 extern char AltHogdir_initialized;
382 int build_mission_list(int anarchy_mode)
384 static int num_missions=-1;
388 //now search for levels on disk
390 //@@Took out this code because after this routine was called once for
391 //@@a list of single-player missions, a subsequent call for a list of
392 //@@anarchy missions would not scan again, and thus would not find the
393 //@@anarchy-only missions. If we retain the minimum level of install,
394 //@@we may want to put the code back in, having it always scan for all
395 //@@missions, and have the code that uses it sort out the ones it wants.
396 //@@ if (num_missions != -1) {
397 //@@ if (Current_mission_num != 0)
398 //@@ load_mission(0); //set built-in mission as default
399 //@@ return num_missions;
402 add_builtin_mission_to_list(&count); //read built-in first
403 add_missions_to_list(MISSION_DIR "*.mn2", &count, anarchy_mode);
404 add_missions_to_list(MISSION_DIR "*.msn", &count, anarchy_mode);
406 if (AltHogdir_initialized) {
407 char search_name[PATH_MAX + 5];
408 strcpy(search_name, AltHogDir);
409 strcat(search_name, "/" MISSION_DIR "*.mn2");
410 add_missions_to_list(search_name, &count, anarchy_mode);
411 strcpy(search_name, AltHogDir);
412 strcat(search_name, "/" MISSION_DIR "*.msn");
413 add_missions_to_list(search_name, &count, anarchy_mode);
416 // move original missions (in stroy-chronological order)
417 // to top of mission list
419 promote("descent", &top_place, count); // original descent 1 mission
420 promote(builtin_mission, &top_place, count); // descent 2
421 promote("d2x", &top_place, count); // vertigo
423 if (count > top_place)
424 qsort(&Mission_list[top_place],
426 sizeof(*Mission_list),
427 (int (*)( const void *, const void * ))ml_sort_func);
430 if (count > top_place)
431 qsort(&Mission_list[top_place],
433 sizeof(*Mission_list),
434 (int (*)( const void *, const void * ))ml_sort_func);
436 //load_mission(0); //set built-in mission as default
438 num_missions = count;
443 void init_extra_robot_movie(char *filename);
445 //values for built-in mission
447 //loads the specfied mission from the mission list.
448 //build_mission_list() must have been called.
449 //Returns true if mission loaded ok, else false.
450 int load_mission(int mission_num)
455 int enhanced_mission = 0;
457 if (!strcmp(Mission_list[mission_num].filename, builtin_mission)) {
458 switch (builtin_mission_hogsize) {
459 case SHAREWARE_MISSION_HOGSIZE:
460 case MAC_SHARE_MISSION_HOGSIZE:
461 return load_mission_shareware(mission_num);
463 case OEM_MISSION_HOGSIZE:
464 return load_mission_oem(mission_num);
469 Current_mission_num = mission_num;
471 mprintf(( 0, "Loading mission %d\n", mission_num ));
473 //read mission from file
475 switch (Mission_list[mission_num].location) {
477 strcpy(buf,MISSION_DIR);
480 strcpy(buf,CDROM_dir);
483 Int3(); //fall through
488 strcat(buf,Mission_list[mission_num].filename);
489 if (Mission_list[mission_num].descent_version == 2)
494 mfile = cfopen(buf,"rb");
496 Current_mission_num = -1;
500 //for non-builtin missions, load HOG
501 if (strcmp(Mission_list[mission_num].filename, builtin_mission)) {
503 strcpy(buf+strlen(buf)-4,".hog"); //change extension
505 found_hogfile = cfile_use_alternate_hogfile(buf);
507 #ifdef RELEASE //for release, require mission to be in hogfile
508 if (! found_hogfile) {
510 Current_mission_num = -1;
518 Last_secret_level = 0;
520 while (mfgets(buf,80,mfile)) {
522 if (istok(buf,"name"))
523 continue; //already have name, go to next line
524 if (istok(buf,"xname")) {
525 enhanced_mission = 1;
526 continue; //already have name, go to next line
528 if (istok(buf,"zname")) {
529 enhanced_mission = 2;
530 continue; //already have name, go to next line
532 else if (istok(buf,"type"))
533 continue; //already have name, go to next line
534 else if (istok(buf,"hog")) {
537 while (*(bufp++) != '=')
541 while (*(++bufp) == ' ')
544 cfile_use_alternate_hogfile(bufp);
545 mprintf((0, "Hog file override = [%s]\n", bufp));
547 else if (istok(buf,"num_levels")) {
549 if ((v=get_value(buf))!=NULL) {
554 for (i=0;i<n_levels && mfgets(buf,80,mfile);i++) {
557 if (strlen(buf) <= 12) {
558 strcpy(Level_names[i],buf);
567 else if (istok(buf,"num_secrets")) {
568 if ((v=get_value(buf))!=NULL) {
571 N_secret_levels = atoi(v);
573 Assert(N_secret_levels <= MAX_SECRET_LEVELS_PER_MISSION);
575 for (i=0;i<N_secret_levels && mfgets(buf,80,mfile);i++) {
579 if ((t=strchr(buf,','))!=NULL) *t++=0;
584 if (strlen(buf) <= 12) {
585 strcpy(Secret_level_names[i],buf);
586 Secret_level_table[i] = atoi(t);
587 if (Secret_level_table[i]<1 || Secret_level_table[i]>Last_level)
602 if (Last_level <= 0) {
603 Current_mission_num = -1; //no valid mission loaded
607 Current_mission_filename = Mission_list[Current_mission_num].filename;
608 Current_mission_longname = Mission_list[Current_mission_num].mission_name;
610 if (enhanced_mission) {
612 extern void bm_read_extra_robots();
613 sprintf(t,"%s.ham",Current_mission_filename);
614 bm_read_extra_robots(t,enhanced_mission);
615 strncpy(t,Current_mission_filename,6);
617 init_extra_robot_movie(t);
623 //loads the named mission if exists.
624 //Returns true if mission loaded ok, else false.
625 int load_mission_by_name(char *mission_name)
629 n = build_mission_list(1);
632 if (!stricmp(mission_name,Mission_list[i].filename))
633 return load_mission(i);
635 return 0; //couldn't find mission