1 /* $Id: mission.c,v 1.13 2002-08-30 00:57:06 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);
321 void add_missions_to_list(char *search_name, int *count, int anarchy_mode)
324 if( !FileFindFirst( search_name, &find ) ) {
326 if (read_mission_file( find.name, *count, ML_MISSIONDIR )) {
328 if (anarchy_mode || !Mission_list[*count].anarchy_only_flag)
332 } while( !FileFindNext( &find ) && *count < MAX_MISSIONS);
334 if (*count >= MAX_MISSIONS)
335 mprintf((0, "Warning: more missions than d2x can handle\n"));
339 /* move <mission_name> to <place> on mission list, increment <place> */
340 void promote (char * mission_name, int * top_place, int num_missions)
343 char name[FILENAME_LEN], * t;
344 strcpy(name, mission_name);
345 if ((t = strchr(name,'.')) != NULL)
346 *t = 0; //kill extension
347 //printf("promoting: %s\n", name);
348 for (i = *top_place; i < num_missions; i++)
349 if (!stricmp(Mission_list[i].filename, name)) {
350 //swap mission positions
353 temp = Mission_list[*top_place];
354 Mission_list[*top_place] = Mission_list[i];
355 Mission_list[i] = temp;
363 //fills in the global list of missions. Returns the number of missions
364 //in the list. If anarchy_mode set, don't include non-anarchy levels.
366 extern char CDROM_dir[];
367 extern char AltHogDir[];
368 extern char AltHogdir_initialized;
370 int build_mission_list(int anarchy_mode)
372 static int num_missions=-1;
376 //now search for levels on disk
378 //@@Took out this code because after this routine was called once for
379 //@@a list of single-player missions, a subsequent call for a list of
380 //@@anarchy missions would not scan again, and thus would not find the
381 //@@anarchy-only missions. If we retain the minimum level of install,
382 //@@we may want to put the code back in, having it always scan for all
383 //@@missions, and have the code that uses it sort out the ones it wants.
384 //@@ if (num_missions != -1) {
385 //@@ if (Current_mission_num != 0)
386 //@@ load_mission(0); //set built-in mission as default
387 //@@ return num_missions;
390 add_builtin_mission_to_list(&count); //read built-in first
391 add_missions_to_list(MISSION_DIR "*.mn2", &count, anarchy_mode);
392 add_missions_to_list(MISSION_DIR "*.msn", &count, anarchy_mode);
394 if (AltHogdir_initialized) {
395 char search_name[PATH_MAX + 5];
396 strcpy(search_name, AltHogDir);
397 strcat(search_name, "/" MISSION_DIR "*.mn2");
398 add_missions_to_list(search_name, &count, anarchy_mode);
399 strcpy(search_name, AltHogDir);
400 strcat(search_name, "/" MISSION_DIR "*.msn");
401 add_missions_to_list(search_name, &count, anarchy_mode);
404 // move original missions (in stroy-chronological order)
405 // to top of mission list
407 promote("descent", &top_place, count); // original descent 1 mission
408 promote(Builtin_mission_filename, &top_place, count); // d2 or d2demo
409 Builtin_mission_num = top_place - 1;
410 promote("d2x", &top_place, count); // vertigo
412 if (count > top_place)
413 qsort(&Mission_list[top_place],
415 sizeof(*Mission_list),
416 (int (*)( const void *, const void * ))ml_sort_func);
419 if (count > top_place)
420 qsort(&Mission_list[top_place],
422 sizeof(*Mission_list),
423 (int (*)( const void *, const void * ))ml_sort_func);
425 //load_mission(0); //set built-in mission as default
427 num_missions = count;
432 void init_extra_robot_movie(char *filename);
434 //values for built-in mission
436 //loads the specfied mission from the mission list.
437 //build_mission_list() must have been called.
438 //Returns true if mission loaded ok, else false.
439 int load_mission(int mission_num)
444 int enhanced_mission = 0;
446 if (mission_num == Builtin_mission_num) {
447 switch (Builtin_mission_hogsize) {
448 case SHAREWARE_MISSION_HOGSIZE:
449 case MAC_SHARE_MISSION_HOGSIZE:
450 return load_mission_shareware(mission_num);
452 case OEM_MISSION_HOGSIZE:
453 return load_mission_oem(mission_num);
455 case FULL_MISSION_HOGSIZE:
461 Current_mission_num = mission_num;
463 mprintf(( 0, "Loading mission %d\n", mission_num ));
465 //read mission from file
467 switch (Mission_list[mission_num].location) {
469 strcpy(buf,MISSION_DIR);
472 strcpy(buf,CDROM_dir);
475 Int3(); //fall through
480 strcat(buf,Mission_list[mission_num].filename);
481 if (Mission_list[mission_num].descent_version == 2)
486 mfile = cfopen(buf,"rb");
488 Current_mission_num = -1;
492 //for non-builtin missions, load HOG
493 if (strcmp(Mission_list[mission_num].filename, Builtin_mission_filename)) {
495 strcpy(buf+strlen(buf)-4,".hog"); //change extension
497 found_hogfile = cfile_use_alternate_hogfile(buf);
499 #ifdef RELEASE //for release, require mission to be in hogfile
500 if (! found_hogfile) {
502 Current_mission_num = -1;
507 // for Descent 1 missions, load descent.hog
508 if (Mission_list[mission_num].descent_version == 1 && strcmp(buf, "descent.hog"))
509 if (!cfile_use_descent1_hogfile("descent.hog"))
510 Warning("descent.hog not available, this mission may be missing some files required for briefings\n");
515 Last_secret_level = 0;
516 Briefing_text_filename[0] = 0;
517 Ending_text_filename[0] = 0;
519 while (mfgets(buf,80,mfile)) {
521 if (istok(buf,"name"))
522 continue; //already have name, go to next line
523 if (istok(buf,"xname")) {
524 enhanced_mission = 1;
525 continue; //already have name, go to next line
527 if (istok(buf,"zname")) {
528 enhanced_mission = 2;
529 continue; //already have name, go to next line
531 else if (istok(buf,"type"))
532 continue; //already have name, go to next line
533 else if (istok(buf,"hog")) {
536 while (*(bufp++) != '=')
540 while (*(++bufp) == ' ')
543 cfile_use_alternate_hogfile(bufp);
544 mprintf((0, "Hog file override = [%s]\n", bufp));
546 else if (istok(buf,"briefing")) {
547 if ((v = get_value(buf)) != NULL) {
550 strcpy(Briefing_text_filename,v);
553 else if (istok(buf,"ending")) {
554 if ((v = get_value(buf)) != NULL) {
557 strcpy(Ending_text_filename,v);
560 else if (istok(buf,"num_levels")) {
562 if ((v=get_value(buf))!=NULL) {
567 for (i=0;i<n_levels && mfgets(buf,80,mfile);i++) {
570 if (strlen(buf) <= 12) {
571 strcpy(Level_names[i],buf);
580 else if (istok(buf,"num_secrets")) {
581 if ((v=get_value(buf))!=NULL) {
584 N_secret_levels = atoi(v);
586 Assert(N_secret_levels <= MAX_SECRET_LEVELS_PER_MISSION);
588 for (i=0;i<N_secret_levels && mfgets(buf,80,mfile);i++) {
592 if ((t=strchr(buf,','))!=NULL) *t++=0;
597 if (strlen(buf) <= 12) {
598 strcpy(Secret_level_names[i],buf);
599 Secret_level_table[i] = atoi(t);
600 if (Secret_level_table[i]<1 || Secret_level_table[i]>Last_level)
615 if (Last_level <= 0) {
616 Current_mission_num = -1; //no valid mission loaded
620 Current_mission_filename = Mission_list[Current_mission_num].filename;
621 Current_mission_longname = Mission_list[Current_mission_num].mission_name;
623 if (enhanced_mission) {
625 extern void bm_read_extra_robots();
626 sprintf(t,"%s.ham",Current_mission_filename);
627 bm_read_extra_robots(t,enhanced_mission);
628 strncpy(t,Current_mission_filename,6);
630 init_extra_robot_movie(t);
636 //loads the named mission if exists.
637 //Returns true if mission loaded ok, else false.
638 int load_mission_by_name(char *mission_name)
642 n = build_mission_list(1);
645 if (!stricmp(mission_name,Mission_list[i].filename))
646 return load_mission(i);
648 return 0; //couldn't find mission