1 /* $Id: mission.c,v 1.15 2002-12-24 06:09:05 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
46 mle Mission_list[MAX_MISSIONS];
48 int Current_mission_num, Builtin_mission_num;
49 int N_secret_levels; // Made a global by MK for scoring purposes. August 1, 1995.
50 char *Current_mission_filename,*Current_mission_longname;
52 char Builtin_mission_filename[9];
53 int Builtin_mission_hogsize;
55 //this stuff should get defined elsewhere
57 char Level_names[MAX_LEVELS_PER_MISSION][FILENAME_LEN];
58 char Secret_level_names[MAX_SECRET_LEVELS_PER_MISSION][FILENAME_LEN];
60 //where the missions go
62 #define MISSION_DIR "missions/"
64 #define MISSION_DIR "./"
68 // Special versions of mission routines for shareware
71 int load_mission_shareware(int mission_num)
73 Current_mission_num = mission_num;
74 Current_mission_filename = Mission_list[mission_num].filename;
75 Current_mission_longname = Mission_list[mission_num].mission_name;
80 Last_secret_level = 0;
82 switch (Builtin_mission_hogsize) {
83 case MAC_SHARE_MISSION_HOGSIZE:
84 // mac demo is using the regular hog and rl2 files
85 strcpy(Level_names[0],"d2leva-1.rl2");
86 strcpy(Level_names[1],"d2leva-2.rl2");
87 strcpy(Level_names[2],"d2leva-3.rl2");
90 Int3(); // fall through
91 case SHAREWARE_MISSION_HOGSIZE:
92 strcpy(Level_names[0],"d2leva-1.sl2");
93 strcpy(Level_names[1],"d2leva-2.sl2");
94 strcpy(Level_names[2],"d2leva-3.sl2");
102 // Special versions of mission routines for Diamond/S3 version
105 int load_mission_oem(int mission_num)
107 Current_mission_num = mission_num;
108 Current_mission_filename = Mission_list[mission_num].filename;
109 Current_mission_longname = Mission_list[mission_num].mission_name;
114 Last_secret_level = -2;
116 strcpy(Level_names[0],"d2leva-1.rl2");
117 strcpy(Level_names[1],"d2leva-2.rl2");
118 strcpy(Level_names[2],"d2leva-3.rl2");
119 strcpy(Level_names[3],"d2leva-4.rl2");
121 strcpy(Secret_level_names[0],"d2leva-s.rl2");
123 strcpy(Level_names[4],"d2levb-1.rl2");
124 strcpy(Level_names[5],"d2levb-2.rl2");
125 strcpy(Level_names[6],"d2levb-3.rl2");
126 strcpy(Level_names[7],"d2levb-4.rl2");
128 strcpy(Secret_level_names[1],"d2levb-s.rl2");
130 Secret_level_table[0] = 1;
131 Secret_level_table[1] = 5;
137 //strips damn newline from end of line
138 char *mfgets(char *s,int n,CFILE *f)
143 if (r && s[strlen(s)-1] == '\n')
149 //compare a string for a token. returns true if match
150 int istok(char *buf,char *tok)
152 return strnicmp(buf,tok,strlen(tok)) == 0;
156 //adds a terminating 0 after a string at the first white space
157 void add_term(char *s)
159 while (*s && !isspace(*s)) s++;
164 //returns ptr to string after '=' & white space, or NULL if no '='
165 //adds 0 after parm at first white space
166 char *get_value(char *buf)
170 t = strchr(buf,'=')+1;
173 while (*t && isspace(*t)) t++;
179 return NULL; //error!
182 //reads a line, returns ptr to value of passed parm. returns NULL if none
183 char *get_parm_value(char *parm,CFILE *f)
187 if (!mfgets(buf,80,f))
191 return get_value(buf);
196 int ml_sort_func(mle *e0,mle *e1)
198 return stricmp(e0->mission_name,e1->mission_name);
202 extern char CDROM_dir[];
204 //returns 1 if file read ok, else 0
205 int read_mission_file(char *filename,int count,int location)
210 //printf("reading: %s\n", filename);
214 strcpy(filename2,MISSION_DIR);
218 songs_stop_redbook(); //so we can read from the CD
219 strcpy(filename2,CDROM_dir);
223 Int3(); //fall through
226 strcpy(filename2,"");
229 strcat(filename2,filename);
231 mfile = cfopen(filename2,"rb");
235 char temp[FILENAME_LEN],*t;
237 strcpy(temp,filename);
238 if ((t = strchr(temp,'.')) == NULL)
239 return 0; //missing extension
240 // look if it's .mn2 or .msn
241 Mission_list[count].descent_version = (t[3] == '2') ? 2 : 1;
242 *t = 0; //kill extension
244 strncpy( Mission_list[count].filename, temp, 9 );
245 Mission_list[count].anarchy_only_flag = 0;
246 Mission_list[count].location = location;
248 p = get_parm_value("name",mfile);
250 if (!p) { //try enhanced mission
251 cfseek(mfile,0,SEEK_SET);
252 p = get_parm_value("xname",mfile);
257 if (!p) { //try super-enhanced mission!
258 cfseek(mfile,0,SEEK_SET);
259 p = get_parm_value("zname",mfile);
265 if ((t=strchr(p,';'))!=NULL)
268 while (isspace(*t)) t--;
269 strncpy(Mission_list[count].mission_name,p,MISSION_NAME_LEN);
276 p = get_parm_value("type",mfile);
280 Mission_list[count].anarchy_only_flag = istok(p,"anarchy");
290 void add_builtin_mission_to_list(int *count)
292 Builtin_mission_hogsize = cfile_size("descent2.hog");
293 if (Builtin_mission_hogsize == -1)
294 Builtin_mission_hogsize = cfile_size("d2demo.hog");
296 switch (Builtin_mission_hogsize) {
297 case SHAREWARE_MISSION_HOGSIZE:
298 case MAC_SHARE_MISSION_HOGSIZE:
299 strcpy(Mission_list[*count].filename,SHAREWARE_MISSION_FILENAME);
300 strcpy(Mission_list[*count].mission_name,SHAREWARE_MISSION_NAME);
301 Mission_list[*count].anarchy_only_flag = 0;
303 case OEM_MISSION_HOGSIZE:
304 strcpy(Mission_list[*count].filename,OEM_MISSION_FILENAME);
305 strcpy(Mission_list[*count].mission_name,OEM_MISSION_NAME);
306 Mission_list[*count].anarchy_only_flag = 0;
309 Warning("Unknown hogsize %d, trying %s\n", Builtin_mission_hogsize, FULL_MISSION_FILENAME ".mn2");
310 Int3(); //fall through
311 case FULL_MISSION_HOGSIZE:
312 if (!read_mission_file(FULL_MISSION_FILENAME ".mn2", 0, ML_CURDIR))
313 Error("Could not find required mission file <%s>", FULL_MISSION_FILENAME ".mn2");
316 strcpy(Builtin_mission_filename, Mission_list[*count].filename);
317 Mission_list[*count].descent_version = 2;
318 Mission_list[*count].anarchy_only_flag = 0;
323 void add_missions_to_list(char *search_name, int *count, int anarchy_mode)
326 if( !FileFindFirst( search_name, &find ) ) {
328 if (read_mission_file( find.name, *count, ML_MISSIONDIR )) {
330 if (anarchy_mode || !Mission_list[*count].anarchy_only_flag)
334 } while( !FileFindNext( &find ) && *count < MAX_MISSIONS);
336 if (*count >= MAX_MISSIONS)
337 mprintf((0, "Warning: more missions than d2x can handle\n"));
341 /* move <mission_name> to <place> on mission list, increment <place> */
342 void promote (char * mission_name, int * top_place, int num_missions)
345 char name[FILENAME_LEN], * t;
346 strcpy(name, mission_name);
347 if ((t = strchr(name,'.')) != NULL)
348 *t = 0; //kill extension
349 //printf("promoting: %s\n", name);
350 for (i = *top_place; i < num_missions; i++)
351 if (!stricmp(Mission_list[i].filename, name)) {
352 //swap mission positions
355 temp = Mission_list[*top_place];
356 Mission_list[*top_place] = Mission_list[i];
357 Mission_list[i] = temp;
365 //fills in the global list of missions. Returns the number of missions
366 //in the list. If anarchy_mode set, don't include non-anarchy levels.
368 extern char CDROM_dir[];
369 extern char AltHogDir[];
370 extern char AltHogdir_initialized;
372 int build_mission_list(int anarchy_mode)
374 static int num_missions=-1;
378 //now search for levels on disk
380 //@@Took out this code because after this routine was called once for
381 //@@a list of single-player missions, a subsequent call for a list of
382 //@@anarchy missions would not scan again, and thus would not find the
383 //@@anarchy-only missions. If we retain the minimum level of install,
384 //@@we may want to put the code back in, having it always scan for all
385 //@@missions, and have the code that uses it sort out the ones it wants.
386 //@@ if (num_missions != -1) {
387 //@@ if (Current_mission_num != 0)
388 //@@ load_mission(0); //set built-in mission as default
389 //@@ return num_missions;
392 add_builtin_mission_to_list(&count); //read built-in first
393 add_missions_to_list(MISSION_DIR "*.mn2", &count, anarchy_mode);
394 add_missions_to_list(MISSION_DIR "*.msn", &count, anarchy_mode);
396 if (AltHogdir_initialized) {
397 char search_name[PATH_MAX + 5];
398 strcpy(search_name, AltHogDir);
399 strcat(search_name, "/" MISSION_DIR "*.mn2");
400 add_missions_to_list(search_name, &count, anarchy_mode);
401 strcpy(search_name, AltHogDir);
402 strcat(search_name, "/" MISSION_DIR "*.msn");
403 add_missions_to_list(search_name, &count, anarchy_mode);
406 // move original missions (in story-chronological order)
407 // to top of mission list
409 promote("descent", &top_place, count); // original descent 1 mission
410 promote(Builtin_mission_filename, &top_place, count); // d2 or d2demo
411 Builtin_mission_num = top_place - 1;
412 promote("d2x", &top_place, count); // vertigo
414 if (count > top_place)
415 qsort(&Mission_list[top_place],
417 sizeof(*Mission_list),
418 (int (*)( const void *, const void * ))ml_sort_func);
421 if (count > top_place)
422 qsort(&Mission_list[top_place],
424 sizeof(*Mission_list),
425 (int (*)( const void *, const void * ))ml_sort_func);
427 //load_mission(0); //set built-in mission as default
429 num_missions = count;
434 void init_extra_robot_movie(char *filename);
436 //values for built-in mission
438 //loads the specfied mission from the mission list.
439 //build_mission_list() must have been called.
440 //Returns true if mission loaded ok, else false.
441 int load_mission(int mission_num)
446 int enhanced_mission = 0;
448 if (mission_num == Builtin_mission_num) {
449 switch (Builtin_mission_hogsize) {
450 case SHAREWARE_MISSION_HOGSIZE:
451 case MAC_SHARE_MISSION_HOGSIZE:
452 return load_mission_shareware(mission_num);
454 case OEM_MISSION_HOGSIZE:
455 return load_mission_oem(mission_num);
457 case FULL_MISSION_HOGSIZE:
463 Current_mission_num = mission_num;
465 mprintf(( 0, "Loading mission %d\n", mission_num ));
467 //read mission from file
469 switch (Mission_list[mission_num].location) {
471 strcpy(buf,MISSION_DIR);
474 strcpy(buf,CDROM_dir);
477 Int3(); //fall through
482 strcat(buf,Mission_list[mission_num].filename);
483 if (Mission_list[mission_num].descent_version == 2)
488 mfile = cfopen(buf,"rb");
490 Current_mission_num = -1;
494 //for non-builtin missions, load HOG
495 if (strcmp(Mission_list[mission_num].filename, Builtin_mission_filename)) {
497 strcpy(buf+strlen(buf)-4,".hog"); //change extension
499 found_hogfile = cfile_use_alternate_hogfile(buf);
501 #ifdef RELEASE //for release, require mission to be in hogfile
502 if (! found_hogfile) {
504 Current_mission_num = -1;
509 // for Descent 1 missions, load descent.hog
510 if (Mission_list[mission_num].descent_version == 1 && strcmp(buf, "descent.hog"))
511 if (!cfile_use_descent1_hogfile("descent.hog"))
512 Warning("descent.hog not available, this mission may be missing some files required for briefings\n");
517 Last_secret_level = 0;
518 Briefing_text_filename[0] = 0;
519 Ending_text_filename[0] = 0;
521 while (mfgets(buf,80,mfile)) {
523 if (istok(buf,"name"))
524 continue; //already have name, go to next line
525 if (istok(buf,"xname")) {
526 enhanced_mission = 1;
527 continue; //already have name, go to next line
529 if (istok(buf,"zname")) {
530 enhanced_mission = 2;
531 continue; //already have name, go to next line
533 else if (istok(buf,"type"))
534 continue; //already have name, go to next line
535 else if (istok(buf,"hog")) {
538 while (*(bufp++) != '=')
542 while (*(++bufp) == ' ')
545 cfile_use_alternate_hogfile(bufp);
546 mprintf((0, "Hog file override = [%s]\n", bufp));
548 else if (istok(buf,"briefing")) {
549 if ((v = get_value(buf)) != NULL) {
552 strcpy(Briefing_text_filename,v);
555 else if (istok(buf,"ending")) {
556 if ((v = get_value(buf)) != NULL) {
559 strcpy(Ending_text_filename,v);
562 else if (istok(buf,"num_levels")) {
564 if ((v=get_value(buf))!=NULL) {
569 for (i=0;i<n_levels && mfgets(buf,80,mfile);i++) {
572 if (strlen(buf) <= 12) {
573 strcpy(Level_names[i],buf);
582 else if (istok(buf,"num_secrets")) {
583 if ((v=get_value(buf))!=NULL) {
586 N_secret_levels = atoi(v);
588 Assert(N_secret_levels <= MAX_SECRET_LEVELS_PER_MISSION);
590 for (i=0;i<N_secret_levels && mfgets(buf,80,mfile);i++) {
594 if ((t=strchr(buf,','))!=NULL) *t++=0;
599 if (strlen(buf) <= 12) {
600 strcpy(Secret_level_names[i],buf);
601 Secret_level_table[i] = atoi(t);
602 if (Secret_level_table[i]<1 || Secret_level_table[i]>Last_level)
617 if (Last_level <= 0) {
618 Current_mission_num = -1; //no valid mission loaded
622 Current_mission_filename = Mission_list[Current_mission_num].filename;
623 Current_mission_longname = Mission_list[Current_mission_num].mission_name;
625 if (enhanced_mission) {
627 extern void bm_read_extra_robots();
628 sprintf(t,"%s.ham",Current_mission_filename);
629 bm_read_extra_robots(t,enhanced_mission);
630 strncpy(t,Current_mission_filename,6);
632 init_extra_robot_movie(t);
638 //loads the named mission if exists.
639 //Returns true if mission loaded ok, else false.
640 int load_mission_by_name(char *mission_name)
644 n = build_mission_list(1);
647 if (!stricmp(mission_name,Mission_list[i].filename))
648 return load_mission(i);
650 return 0; //couldn't find mission