1 /* $Id: mission.c,v 1.21 2003/03/14 09:17:08 btb Exp $ */
2 /*
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.
13 */
14 
15 /*
16  *
17  * Code to handle multiple missions
18  *
19  * Old Log:
20  * Revision 1.4  1995/10/31  10:21:40  allender
21  * no mission support in shareware
22  *
23  * Revision 1.3  1995/10/21  22:53:04  allender
24  * moved missions to data folder
25  *
26  * Revision 1.2  1995/09/13  08:47:29  allender
27  * made to work with Chris' direct stuff
28  *
29  * Revision 1.1  1995/05/16  15:27:48  allender
30  * Initial revision
31  *
32  * Revision 2.9  1995/05/26  16:16:32  john
33  * Split SATURN into define's for requiring cd, using cd, etc.
34  * Also started adding all the Rockwell stuff.
35  *
36  * Revision 2.8  1995/03/20  15:49:31  mike
37  * Remove eof char from comment which confused make depend, causing
38  * no mission.obj: line in makefile.  Pretty stupid tool, huh?
39  *
40  * Revision 2.7  1995/03/20  12:12:11  john
41  * Added ifdef SATURN.
42  *
43  * Revision 2.6  1995/03/15  14:32:49  john
44  * Added code to force the Descent CD-rom in the drive.
45  *
46  * Revision 2.5  1995/03/15  11:41:15  john
47  * Better Saturn CD-ROM support.
48  *
49  * Revision 2.4  1995/03/14  18:24:14  john
50  * Force Destination Saturn to use CD-ROM drive.
51  *
52  * Revision 2.3  1995/03/07  14:19:41  mike
53  * More destination saturn stuff.
54  *
55  * Revision 2.2  1995/03/06  23:09:03  mike
56  * more saturn stuff: make briefings work for saturn mission.
57  *
58  * Revision 2.1  1995/03/06  16:47:48  mike
59  * destination saturn
60  *
61  * Revision 2.0  1995/02/27  11:27:49  john
62  * New version 2.0, which has no anonymous unions, builds with
63  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
64  *
65  * Revision 1.14  1995/02/15  11:30:37  john
66  * Fixed bug with potential mem overwrite on line 160.
67  *
68  * Revision 1.13  1995/02/10  17:53:20  matt
69  * Changed mission name again
70  *
71  * Revision 1.12  1995/02/10  17:35:38  matt
72  * Changed name of built-in mission
73  *
74  * Revision 1.11  1995/02/07  17:13:51  allender
75  * removed return statement in load_mission so that built in mission will
76  * actually set the Current_mission_name and _filename
77  *
78  * Revision 1.10  1995/01/31  01:19:45  matt
79  * Made build_mission_list() sort missions by name
80  *
81  * Revision 1.9  1995/01/30  13:49:58  allender
82  * changed build_mission_list in load_mission_by_name to include
83  * anarchy levels.
84  *
85  * Revision 1.8  1995/01/30  13:03:51  matt
86  * Fixed dumb mistake
87  *
88  * Revision 1.7  1995/01/30  12:55:22  matt
89  * Added vars to point to mission names
90  *
91  * Revision 1.6  1995/01/22  18:57:28  matt
92  * Made player highest level work with missions
93  *
94  * Revision 1.5  1995/01/22  14:13:08  matt
95  * Added flag in mission list for anarchy-only missions
96  *
97  * Revision 1.4  1995/01/21  23:13:12  matt
98  * Made high scores with (not work, really) with loaded missions
99  * Don't give player high score when quit game
100  *
101  * Revision 1.3  1995/01/21  16:27:12  matt
102  * Made endlevel briefing work with missions
103  *
104  * Revision 1.2  1995/01/20  22:47:50  matt
105  * Mission system implemented, though imcompletely
106  *
107  * Revision 1.1  1995/01/20  13:42:19  matt
108  * Initial revision
109  *
110  *
111  */
112 
113 #ifdef HAVE_CONFIG_H
114 #include <conf.h>
115 #endif
116 
117 #include <stdio.h>
118 #include <stdlib.h>
119 #include <string.h>
120 #include <ctype.h>
121 #include <limits.h>
122 
123 #include "pstypes.h"
124 #include "cfile.h"
125 
126 #include "strutil.h"
127 #include "inferno.h"
128 #include "mission.h"
129 #include "gameseq.h"
130 #include "titles.h"
131 #include "songs.h"
132 #include "mono.h"
133 #include "error.h"
134 #include "findfile.h"
135 
136 mle Mission_list[MAX_MISSIONS];
137 
138 int Current_mission_num;
139 int N_secret_levels;    // Made a global by MK for scoring purposes.  August 1, 1995.
140 char *Current_mission_filename,*Current_mission_longname;
141 
142 int Builtin_mission_num;
143 char Builtin_mission_filename[9];
144 int Builtin_mission_hogsize;
145 
146 int D1_Builtin_mission_num;
147 char D1_Builtin_mission_filename[9];
148 int D1_Builtin_mission_hogsize;
149 
150 //this stuff should get defined elsewhere
151 
152 char Level_names[MAX_LEVELS_PER_MISSION][FILENAME_LEN];
153 char Secret_level_names[MAX_SECRET_LEVELS_PER_MISSION][FILENAME_LEN];
154 
155 //values for d1 built-in mission
156 #define BIM_LAST_LEVEL          27
157 #define BIM_LAST_SECRET_LEVEL   -3
158 #define BIM_BRIEFING_FILE       "briefing.tex"
159 #define BIM_ENDING_FILE         "endreg.tex"
160 
161 //
162 //  Special versions of mission routines for d1 builtins
163 //
164 
load_mission_d1(int mission_num)165 int load_mission_d1(int mission_num)
166 {
167 	int i;
168 
169 	cfile_use_descent1_hogfile("descent.hog");
170 
171 	Current_mission_num = mission_num;
172 	Current_mission_filename = Mission_list[mission_num].filename;
173 	Current_mission_longname = Mission_list[mission_num].mission_name;
174 
175 	switch (D1_Builtin_mission_hogsize) {
176 	case D1_SHAREWARE_MISSION_HOGSIZE:
177 	case D1_SHAREWARE_10_MISSION_HOGSIZE:
178 		N_secret_levels = 0;
179 
180 		Last_level = 7;
181 		Last_secret_level = 0;
182 
183 		//build level names
184 		for (i=0;i<Last_level;i++)
185 			sprintf(Level_names[i], "level%02d.sdl", i+1);
186 
187 		break;
188 	case D1_MAC_SHARE_MISSION_HOGSIZE:
189 		N_secret_levels = 0;
190 
191 		Last_level = 3;
192 		Last_secret_level = 0;
193 
194 		//build level names
195 		for (i=0;i<Last_level;i++)
196 			sprintf(Level_names[i], "level%02d.sdl", i+1);
197 
198 		break;
199 	case D1_OEM_MISSION_HOGSIZE:
200 		N_secret_levels = 1;
201 
202 		Last_level = 15;
203 		Last_secret_level = -1;
204 
205 		//build level names
206 		for (i=0; i < Last_level - 1; i++)
207 			sprintf(Level_names[i], "level%02d.rdl", i+1);
208 		sprintf(Level_names[i], "saturn%02d.rdl", i+1);
209 		for (i=0; i < -Last_secret_level; i++)
210 			sprintf(Secret_level_names[i], "levels%1d.rdl", i+1);
211 
212 		Secret_level_table[0] = 10;
213 
214 		break;
215 	default:
216 		Int3(); // fall through
217 	case D1_MISSION_HOGSIZE:
218 	case D1_10_MISSION_HOGSIZE:
219 	case D1_MAC_MISSION_HOGSIZE:
220 		N_secret_levels = 3;
221 
222 		Last_level = BIM_LAST_LEVEL;
223 		Last_secret_level = BIM_LAST_SECRET_LEVEL;
224 
225 		//build level names
226 		for (i=0;i<Last_level;i++)
227 			sprintf(Level_names[i], "level%02d.rdl", i+1);
228 		for (i=0;i<-Last_secret_level;i++)
229 			sprintf(Secret_level_names[i], "levels%1d.rdl", i+1);
230 
231 		Secret_level_table[0] = 10;
232 		Secret_level_table[1] = 21;
233 		Secret_level_table[2] = 24;
234 
235 		break;
236 	}
237 	strcpy(Briefing_text_filename,BIM_BRIEFING_FILE);
238 	strcpy(Ending_text_filename,BIM_ENDING_FILE);
239 
240 	return 1;
241 }
242 
243 
244 //
245 //  Special versions of mission routines for shareware
246 //
247 
load_mission_shareware(int mission_num)248 int load_mission_shareware(int mission_num)
249 {
250 	Current_mission_num = mission_num;
251 	Current_mission_filename = Mission_list[mission_num].filename;
252 	Current_mission_longname = Mission_list[mission_num].mission_name;
253 
254 	N_secret_levels = 0;
255 
256 	Last_level = 3;
257 	Last_secret_level = 0;
258 
259 	switch (Builtin_mission_hogsize) {
260 	case MAC_SHARE_MISSION_HOGSIZE:
261 		// mac demo is using the regular hog and rl2 files
262 		strcpy(Level_names[0],"d2leva-1.rl2");
263 		strcpy(Level_names[1],"d2leva-2.rl2");
264 		strcpy(Level_names[2],"d2leva-3.rl2");
265 		break;
266 	default:
267 		Int3(); // fall through
268 	case SHAREWARE_MISSION_HOGSIZE:
269 		strcpy(Level_names[0],"d2leva-1.sl2");
270 		strcpy(Level_names[1],"d2leva-2.sl2");
271 		strcpy(Level_names[2],"d2leva-3.sl2");
272 	}
273 
274 	return 1;
275 }
276 
277 
278 //
279 //  Special versions of mission routines for Diamond/S3 version
280 //
281 
load_mission_oem(int mission_num)282 int load_mission_oem(int mission_num)
283 {
284 	Current_mission_num = mission_num;
285 	Current_mission_filename = Mission_list[mission_num].filename;
286 	Current_mission_longname = Mission_list[mission_num].mission_name;
287 
288 	N_secret_levels = 2;
289 
290 	Last_level = 8;
291 	Last_secret_level = -2;
292 
293 	strcpy(Level_names[0],"d2leva-1.rl2");
294 	strcpy(Level_names[1],"d2leva-2.rl2");
295 	strcpy(Level_names[2],"d2leva-3.rl2");
296 	strcpy(Level_names[3],"d2leva-4.rl2");
297 
298 	strcpy(Secret_level_names[0],"d2leva-s.rl2");
299 
300 	strcpy(Level_names[4],"d2levb-1.rl2");
301 	strcpy(Level_names[5],"d2levb-2.rl2");
302 	strcpy(Level_names[6],"d2levb-3.rl2");
303 	strcpy(Level_names[7],"d2levb-4.rl2");
304 
305 	strcpy(Secret_level_names[1],"d2levb-s.rl2");
306 
307 	Secret_level_table[0] = 1;
308 	Secret_level_table[1] = 5;
309 
310 	return 1;
311 }
312 
313 
314 //strips damn newline from end of line
mfgets(char * s,int n,CFILE * f)315 char *mfgets(char *s,int n,CFILE *f)
316 {
317 	char *r;
318 
319 	r = cfgets(s,n,f);
320 	if (r && s[strlen(s)-1] == '\n')
321 		s[strlen(s)-1] = 0;
322 
323 	return r;
324 }
325 
326 //compare a string for a token. returns true if match
istok(char * buf,char * tok)327 int istok(char *buf,char *tok)
328 {
329 	return strnicmp(buf,tok,strlen(tok)) == 0;
330 
331 }
332 
333 //adds a terminating 0 after a string at the first white space
add_term(char * s)334 void add_term(char *s)
335 {
336 	while (*s && !isspace(*s)) s++;
337 
338 	*s = 0;		//terminate!
339 }
340 
341 //returns ptr to string after '=' & white space, or NULL if no '='
342 //adds 0 after parm at first white space
get_value(char * buf)343 char *get_value(char *buf)
344 {
345 	char *t;
346 
347 	t = strchr(buf,'=')+1;
348 
349 	if (t) {
350 		while (*t && isspace(*t)) t++;
351 
352 		if (*t)
353 			return t;
354 	}
355 
356 	return NULL;		//error!
357 }
358 
359 //reads a line, returns ptr to value of passed parm.  returns NULL if none
get_parm_value(char * parm,CFILE * f)360 char *get_parm_value(char *parm,CFILE *f)
361 {
362 	static char buf[80];
363 
364 	if (!mfgets(buf,80,f))
365 		return NULL;
366 
367 	if (istok(buf,parm))
368 		return get_value(buf);
369 	else
370 		return NULL;
371 }
372 
ml_sort_func(mle * e0,mle * e1)373 int ml_sort_func(mle *e0,mle *e1)
374 {
375 	return stricmp(e0->mission_name,e1->mission_name);
376 
377 }
378 
379 extern char CDROM_dir[];
380 
381 //returns 1 if file read ok, else 0
read_mission_file(char * filename,int count,int location)382 int read_mission_file(char *filename,int count,int location)
383 {
384 	char filename2[100];
385 	CFILE *mfile;
386 
387 	//printf("reading: %s\n", filename);
388 
389 	switch (location) {
390 		case ML_MISSIONDIR:
391 			strcpy(filename2,MISSION_DIR);
392 			break;
393 
394 		case ML_CDROM:
395 			songs_stop_redbook();		//so we can read from the CD
396 			strcpy(filename2,CDROM_dir);
397 			break;
398 
399 		default:
400 			Int3();		//fall through
401 
402 		case ML_CURDIR:
403 			strcpy(filename2,"");
404 			break;
405 	}
406 	strcat(filename2,filename);
407 
408 	mfile = cfopen(filename2,"rb");
409 
410 	if (mfile) {
411 		char *p;
412 		char temp[FILENAME_LEN],*t;
413 
414 		strcpy(temp,filename);
415 		if ((t = strchr(temp,'.')) == NULL)
416 			return 0;	//missing extension
417 		// look if it's .mn2 or .msn
418 		Mission_list[count].descent_version = (t[3] == '2') ? 2 : 1;
419 		*t = 0;			//kill extension
420 
421 		strncpy( Mission_list[count].filename, temp, 9 );
422 		Mission_list[count].anarchy_only_flag = 0;
423 		Mission_list[count].location = location;
424 
425 		p = get_parm_value("name",mfile);
426 
427 		if (!p) {		//try enhanced mission
428 			cfseek(mfile,0,SEEK_SET);
429 			p = get_parm_value("xname",mfile);
430 		}
431 
432 		if (!p) {       //try super-enhanced mission!
433 			cfseek(mfile,0,SEEK_SET);
434 			p = get_parm_value("zname",mfile);
435 		}
436 
437 		if (p) {
438 			char *t;
439 			if ((t=strchr(p,';'))!=NULL)
440 				*t=0;
441 			t = p + strlen(p)-1;
442 			while (isspace(*t)) t--;
443 			strncpy(Mission_list[count].mission_name,p,MISSION_NAME_LEN);
444 		}
445 		else {
446 			cfclose(mfile);
447 			return 0;
448 		}
449 
450 		p = get_parm_value("type",mfile);
451 
452 		//get mission type
453 		if (p)
454 			Mission_list[count].anarchy_only_flag = istok(p,"anarchy");
455 
456 		cfclose(mfile);
457 
458 		return 1;
459 	}
460 
461 	return 0;
462 }
463 
add_d1_builtin_mission_to_list(int * count)464 void add_d1_builtin_mission_to_list(int *count)
465 {
466 	if (!cfexist("descent.hog"))
467 		return;
468 
469 	D1_Builtin_mission_hogsize = cfile_size("descent.hog");
470 
471 	switch (D1_Builtin_mission_hogsize) {
472 	case D1_SHAREWARE_MISSION_HOGSIZE:
473 	case D1_SHAREWARE_10_MISSION_HOGSIZE:
474 	case D1_MAC_SHARE_MISSION_HOGSIZE:
475 		strcpy(Mission_list[*count].filename, D1_MISSION_FILENAME);
476 		strcpy(Mission_list[*count].mission_name, D1_SHAREWARE_MISSION_NAME);
477 		Mission_list[*count].anarchy_only_flag = 0;
478 		break;
479 	case D1_OEM_MISSION_HOGSIZE:
480 		strcpy(Mission_list[*count].filename, D1_MISSION_FILENAME);
481 		strcpy(Mission_list[*count].mission_name, D1_OEM_MISSION_NAME);
482 		Mission_list[*count].anarchy_only_flag = 0;
483 		break;
484 	default:
485 		Warning("Unknown D1 hogsize %d\n", D1_Builtin_mission_hogsize);
486 		Int3();
487 		// fall through
488 	case D1_MISSION_HOGSIZE:
489 	case D1_10_MISSION_HOGSIZE:
490 	case D1_MAC_MISSION_HOGSIZE:
491 		strcpy(Mission_list[*count].filename, D1_MISSION_FILENAME);
492 		strcpy(Mission_list[*count].mission_name, D1_MISSION_NAME);
493 		Mission_list[*count].anarchy_only_flag = 0;
494 		break;
495 	}
496 
497 	strcpy(D1_Builtin_mission_filename, Mission_list[*count].filename);
498 	Mission_list[*count].descent_version = 1;
499 	Mission_list[*count].anarchy_only_flag = 0;
500 	++(*count);
501 }
502 
503 
add_builtin_mission_to_list(int * count)504 void add_builtin_mission_to_list(int *count)
505 {
506 	Builtin_mission_hogsize = cfile_size("descent2.hog");
507 	if (Builtin_mission_hogsize == -1)
508 		Builtin_mission_hogsize = cfile_size("d2demo.hog");
509 
510 	switch (Builtin_mission_hogsize) {
511 	case SHAREWARE_MISSION_HOGSIZE:
512 	case MAC_SHARE_MISSION_HOGSIZE:
513 		strcpy(Mission_list[*count].filename,SHAREWARE_MISSION_FILENAME);
514 		strcpy(Mission_list[*count].mission_name,SHAREWARE_MISSION_NAME);
515 		Mission_list[*count].anarchy_only_flag = 0;
516 		break;
517 	case OEM_MISSION_HOGSIZE:
518 		strcpy(Mission_list[*count].filename,OEM_MISSION_FILENAME);
519 		strcpy(Mission_list[*count].mission_name,OEM_MISSION_NAME);
520 		Mission_list[*count].anarchy_only_flag = 0;
521 		break;
522 	default:
523 		Warning("Unknown hogsize %d, trying %s\n", Builtin_mission_hogsize, FULL_MISSION_FILENAME ".mn2");
524 		Int3(); //fall through
525 	case FULL_MISSION_HOGSIZE:
526 	case MAC_FULL_MISSION_HOGSIZE:
527 		if (!read_mission_file(FULL_MISSION_FILENAME ".mn2", 0, ML_CURDIR))
528 			Error("Could not find required mission file <%s>", FULL_MISSION_FILENAME ".mn2");
529 	}
530 
531 	strcpy(Builtin_mission_filename, Mission_list[*count].filename);
532 	Mission_list[*count].descent_version = 2;
533 	Mission_list[*count].anarchy_only_flag = 0;
534 	++(*count);
535 }
536 
537 
add_missions_to_list(char * search_name,int * count,int anarchy_mode)538 void add_missions_to_list(char *search_name, int *count, int anarchy_mode)
539 {
540 	FILEFINDSTRUCT find;
541 	if( !FileFindFirst( search_name, &find ) ) {
542 		do	{
543 			if (read_mission_file( find.name, *count, ML_MISSIONDIR )) {
544 
545 				if (anarchy_mode || !Mission_list[*count].anarchy_only_flag)
546 					++(*count);
547 			}
548 
549 		} while( !FileFindNext( &find ) && *count < MAX_MISSIONS);
550 		FileFindClose();
551 		if (*count >= MAX_MISSIONS)
552 			mprintf((0, "Warning: more missions than d2x can handle\n"));
553 	}
554 }
555 
556 /* move <mission_name> to <place> on mission list, increment <place> */
promote(char * mission_name,int * top_place,int num_missions)557 void promote (char * mission_name, int * top_place, int num_missions)
558 {
559 	int i;
560 	char name[FILENAME_LEN], * t;
561 	strcpy(name, mission_name);
562 	if ((t = strchr(name,'.')) != NULL)
563 		*t = 0; //kill extension
564 	//printf("promoting: %s\n", name);
565 	for (i = *top_place; i < num_missions; i++)
566 		if (!stricmp(Mission_list[i].filename, name)) {
567 			//swap mission positions
568 			mle temp;
569 
570 			temp = Mission_list[*top_place];
571 			Mission_list[*top_place] = Mission_list[i];
572 			Mission_list[i] = temp;
573 			++(*top_place);
574 			break;
575 		}
576 }
577 
578 
579 
580 //fills in the global list of missions.  Returns the number of missions
581 //in the list.  If anarchy_mode set, don't include non-anarchy levels.
582 
583 extern char CDROM_dir[];
584 extern char AltHogDir[];
585 extern char AltHogdir_initialized;
586 
build_mission_list(int anarchy_mode)587 int build_mission_list(int anarchy_mode)
588 {
589 	static int num_missions=-1;
590 	int count = 0;
591 	int top_place;
592 
593 	//now search for levels on disk
594 
595 //@@Took out this code because after this routine was called once for
596 //@@a list of single-player missions, a subsequent call for a list of
597 //@@anarchy missions would not scan again, and thus would not find the
598 //@@anarchy-only missions.  If we retain the minimum level of install,
599 //@@we may want to put the code back in, having it always scan for all
600 //@@missions, and have the code that uses it sort out the ones it wants.
601 //@@	if (num_missions != -1) {
602 //@@		if (Current_mission_num != 0)
603 //@@			load_mission(0);				//set built-in mission as default
604 //@@		return num_missions;
605 //@@	}
606 
607 	add_builtin_mission_to_list(&count);  //read built-in first
608 	add_d1_builtin_mission_to_list(&count);
609 	add_missions_to_list(MISSION_DIR "*.mn2", &count, anarchy_mode);
610 	add_missions_to_list(MISSION_DIR "*.msn", &count, anarchy_mode);
611 
612 	if (AltHogdir_initialized) {
613 		char search_name[PATH_MAX + 5];
614 		strcpy(search_name, AltHogDir);
615 		strcat(search_name, "/" MISSION_DIR "*.mn2");
616 		add_missions_to_list(search_name, &count, anarchy_mode);
617 		strcpy(search_name, AltHogDir);
618 		strcat(search_name, "/" MISSION_DIR "*.msn");
619 		add_missions_to_list(search_name, &count, anarchy_mode);
620 	}
621 
622 	// move original missions (in story-chronological order)
623 	// to top of mission list
624 	top_place = 0;
625 	promote("descent", &top_place, count); // original descent 1 mission
626 	D1_Builtin_mission_num = top_place - 1;
627 	promote(Builtin_mission_filename, &top_place, count); // d2 or d2demo
628 	Builtin_mission_num = top_place - 1;
629 	promote("d2x", &top_place, count); // vertigo
630 
631 	if (count > top_place)
632 		qsort(&Mission_list[top_place],
633 		      count - top_place,
634 		      sizeof(*Mission_list),
635  				(int (*)( const void *, const void * ))ml_sort_func);
636 
637 
638 	if (count > top_place)
639 		qsort(&Mission_list[top_place],
640 		      count - top_place,
641 		      sizeof(*Mission_list),
642 		      (int (*)( const void *, const void * ))ml_sort_func);
643 
644 	//load_mission(0);   //set built-in mission as default
645 
646 	num_missions = count;
647 
648 	return count;
649 }
650 
651 void init_extra_robot_movie(char *filename);
652 
653 //values for built-in mission
654 
655 //loads the specfied mission from the mission list.
656 //build_mission_list() must have been called.
657 //Returns true if mission loaded ok, else false.
load_mission(int mission_num)658 int load_mission(int mission_num)
659 {
660 	CFILE *mfile;
661 	char buf[80], *v;
662 	int found_hogfile;
663 	int enhanced_mission = 0;
664 
665 	if (mission_num == D1_Builtin_mission_num) {
666 		cfile_use_descent1_hogfile("descent.hog");
667 		switch (D1_Builtin_mission_hogsize) {
668 		default:
669 			Int3(); // fall through
670 		case D1_MISSION_HOGSIZE:
671 		case D1_10_MISSION_HOGSIZE:
672 		case D1_MAC_MISSION_HOGSIZE:
673 		case D1_OEM_MISSION_HOGSIZE:
674 		case D1_SHAREWARE_MISSION_HOGSIZE:
675 		case D1_SHAREWARE_10_MISSION_HOGSIZE:
676 		case D1_MAC_SHARE_MISSION_HOGSIZE:
677 			return load_mission_d1(mission_num);
678 			break;
679 		}
680 	}
681 
682 	if (mission_num == Builtin_mission_num) {
683 		switch (Builtin_mission_hogsize) {
684 		case SHAREWARE_MISSION_HOGSIZE:
685 		case MAC_SHARE_MISSION_HOGSIZE:
686 			return load_mission_shareware(mission_num);
687 			break;
688 		case OEM_MISSION_HOGSIZE:
689 			return load_mission_oem(mission_num);
690 			break;
691 		default:
692 			Int3(); // fall through
693 		case FULL_MISSION_HOGSIZE:
694 		case MAC_FULL_MISSION_HOGSIZE:
695 			// continue on... (use d2.mn2 from hogfile)
696 			break;
697 		}
698 	}
699 
700 	Current_mission_num = mission_num;
701 
702 	mprintf(( 0, "Loading mission %d\n", mission_num ));
703 
704 	//read mission from file
705 
706 	switch (Mission_list[mission_num].location) {
707 	case ML_MISSIONDIR:
708 		strcpy(buf,MISSION_DIR);
709 		break;
710 	case ML_CDROM:
711 		strcpy(buf,CDROM_dir);
712 		break;
713 	default:
714 		Int3();							//fall through
715 	case ML_CURDIR:
716 		strcpy(buf,"");
717 		break;
718 	}
719 	strcat(buf,Mission_list[mission_num].filename);
720 	if (Mission_list[mission_num].descent_version == 2)
721 		strcat(buf,".mn2");
722 	else
723 		strcat(buf,".msn");
724 
725 	mfile = cfopen(buf,"rb");
726 	if (mfile == NULL) {
727 		Current_mission_num = -1;
728 		return 0;		//error!
729 	}
730 
731 	//for non-builtin missions, load HOG
732 	if (strcmp(Mission_list[mission_num].filename, Builtin_mission_filename)) {
733 
734 		strcpy(buf+strlen(buf)-4,".hog");		//change extension
735 
736 		found_hogfile = cfile_use_alternate_hogfile(buf);
737 
738 		#ifdef RELEASE				//for release, require mission to be in hogfile
739 		if (! found_hogfile) {
740 			cfclose(mfile);
741 			Current_mission_num = -1;
742 			return 0;
743 		}
744 		#endif
745 
746 		// for Descent 1 missions, load descent.hog
747 		if (Mission_list[mission_num].descent_version == 1 && strcmp(buf, "descent.hog"))
748 			if (!cfile_use_descent1_hogfile("descent.hog"))
749 				Warning("descent.hog not available, this mission may be missing some files required for briefings\n");
750 	}
751 
752 	//init vars
753 	Last_level = 0;
754 	Last_secret_level = 0;
755 	Briefing_text_filename[0] = 0;
756 	Ending_text_filename[0] = 0;
757 
758 	while (mfgets(buf,80,mfile)) {
759 
760 		if (istok(buf,"name"))
761 			continue;						//already have name, go to next line
762 		if (istok(buf,"xname")) {
763 			enhanced_mission = 1;
764 			continue;						//already have name, go to next line
765 		}
766 		if (istok(buf,"zname")) {
767 			enhanced_mission = 2;
768 			continue;						//already have name, go to next line
769 		}
770 		else if (istok(buf,"type"))
771 			continue;						//already have name, go to next line
772 		else if (istok(buf,"hog")) {
773 			char	*bufp = buf;
774 
775 			while (*(bufp++) != '=')
776 				;
777 
778 			if (*bufp == ' ')
779 				while (*(++bufp) == ' ')
780 					;
781 
782 			cfile_use_alternate_hogfile(bufp);
783 			mprintf((0, "Hog file override = [%s]\n", bufp));
784 		}
785 		else if (istok(buf,"briefing")) {
786 			if ((v = get_value(buf)) != NULL) {
787 				add_term(v);
788 				if (strlen(v) < 13)
789 					strcpy(Briefing_text_filename,v);
790 			}
791 		}
792 		else if (istok(buf,"ending")) {
793 			if ((v = get_value(buf)) != NULL) {
794 				add_term(v);
795 				if (strlen(v) < 13)
796 					strcpy(Ending_text_filename,v);
797 			}
798 		}
799 		else if (istok(buf,"num_levels")) {
800 
801 			if ((v=get_value(buf))!=NULL) {
802 				int n_levels,i;
803 
804 				n_levels = atoi(v);
805 
806 				for (i=0;i<n_levels && mfgets(buf,80,mfile);i++) {
807 
808 					add_term(buf);
809 					if (strlen(buf) <= 12) {
810 						strcpy(Level_names[i],buf);
811 						Last_level++;
812 					}
813 					else
814 						break;
815 				}
816 
817 			}
818 		}
819 		else if (istok(buf,"num_secrets")) {
820 			if ((v=get_value(buf))!=NULL) {
821 				int i;
822 
823 				N_secret_levels = atoi(v);
824 
825 				Assert(N_secret_levels <= MAX_SECRET_LEVELS_PER_MISSION);
826 
827 				for (i=0;i<N_secret_levels && mfgets(buf,80,mfile);i++) {
828 					char *t;
829 
830 
831 					if ((t=strchr(buf,','))!=NULL) *t++=0;
832 					else
833 						break;
834 
835 					add_term(buf);
836 					if (strlen(buf) <= 12) {
837 						strcpy(Secret_level_names[i],buf);
838 						Secret_level_table[i] = atoi(t);
839 						if (Secret_level_table[i]<1 || Secret_level_table[i]>Last_level)
840 							break;
841 						Last_secret_level--;
842 					}
843 					else
844 						break;
845 				}
846 
847 			}
848 		}
849 
850 	}
851 
852 	cfclose(mfile);
853 
854 	if (Last_level <= 0) {
855 		Current_mission_num = -1;		//no valid mission loaded
856 		return 0;
857 	}
858 
859 	Current_mission_filename = Mission_list[Current_mission_num].filename;
860 	Current_mission_longname = Mission_list[Current_mission_num].mission_name;
861 
862 	if (enhanced_mission) {
863 		char t[50];
864 		extern void bm_read_extra_robots();
865 		sprintf(t,"%s.ham",Current_mission_filename);
866 		bm_read_extra_robots(t,enhanced_mission);
867 		strncpy(t,Current_mission_filename,6);
868 		strcat(t,"-l.mvl");
869 		init_extra_robot_movie(t);
870 	}
871 
872 	return 1;
873 }
874 
875 //loads the named mission if exists.
876 //Returns true if mission loaded ok, else false.
load_mission_by_name(char * mission_name)877 int load_mission_by_name(char *mission_name)
878 {
879 	int n,i;
880 
881 	n = build_mission_list(1);
882 
883 	for (i=0;i<n;i++)
884 		if (!stricmp(mission_name,Mission_list[i].filename))
885 			return load_mission(i);
886 
887 	return 0;		//couldn't find mission
888 }
889