1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <limits.h>
5 #include <ctype.h>
6 #include <sys/stat.h>
7 #include <math.h>
8 
9 #include "../include/fio.h"
10 #include "../include/string.h"
11 #include "../include/strexp.h"
12 #include "../include/disk.h"
13 
14 #include "sfm.h"
15 
16 #include "obj.h"
17 #include "objutils.h"
18 #include "objio.h"
19 #include "menu.h"
20 #include "sarreality.h"
21 #include "weather.h"
22 #include "mission.h"
23 #include "simutils.h"
24 #include "sar.h"
25 #include "sarfio.h"
26 #include "sceneio.h"
27 #include "missionio.h"
28 #include "config.h"
29 
30 
31 static int SARMissionGetInterceptNameFromScene(
32 	const char *filename,
33 	const char *obj_name,
34 	sar_intercept_struct *intercept
35 );
36 static int SARMissionLoadSceneMapToMenuMap(
37 	sar_core_struct *core_ptr, sar_menu_struct *m,
38 	sar_menu_map_struct *map_ptr,
39 	const char *filename                    /* Scene file */
40 );
41 static int SARMissionLoadSceneMapToMenuMapMarkings(
42 	sar_core_struct *core_ptr,
43 	sar_menu_struct *m, sar_menu_map_struct *map_ptr,
44 	const char *scene_filename, const char *mission_filename
45 );
46 
47 char *SARMissionLoadDescription(const char *filename);
48 void SARMissionLoadSceneToMenuMap(
49 	sar_core_struct *core_ptr,
50 	sar_menu_struct *m,
51 	const char *filename		/* Mission file name */
52 );
53 void SARMissionLoadMissionLogToMenuMap(
54 	sar_core_struct *core_ptr,
55 	sar_menu_struct *m,
56 	const char *filename            /* Mission log file name */
57 );
58 
59 sar_mission_struct *SARMissionLoadFromFile(
60 	sar_core_struct *core_ptr,
61 	const char *filename,
62 	void *client_data,
63 	int (*progress_func)(void *, long, long)
64 );
65 
66 void SARMissionLogReset(
67 	sar_core_struct *core_ptr, sar_mission_struct *mission,
68 	const char *filename		/* Mission log file name */
69 );
70 void SARMissionLogEvent(
71 	sar_core_struct *core_ptr, sar_mission_struct *mission,
72 	int event_type,			/* One of SAR_LOG_EVENT_* */
73 	float tod,			/* Time of day in seconds since midnight */
74 	sar_position_struct *pos,	/* Position of event */
75 	const float *value,		/* Additional values */
76 	int total_values,		/* Total number of additional values */
77 	const char *message,		/* The message */
78 	const char *filename            /* Mission log file name */
79 );
80 
81 
82 #define ATOI(s)		(((s) != NULL) ? atoi(s) : 0)
83 #define ATOL(s)		(((s) != NULL) ? atol(s) : 0)
84 #define ATOF(s)		(((s) != NULL) ? (float)atof(s) : 0.0f)
85 #define STRDUP(s)	(((s) != NULL) ? strdup(s) : NULL)
86 
87 #define MAX(a,b)	(((a) > (b)) ? (a) : (b))
88 #define MIN(a,b)	(((a) < (b)) ? (a) : (b))
89 #define CLIP(a,l,h)	(MIN(MAX((a),(l)),(h)))
90 #define STRLEN(s)	(((s) != NULL) ? (int)strlen(s) : 0)
91 #define STRISEMPTY(s)	(((s) != NULL) ? (*(s) == '\0') : 1)
92 
93 #define RADTODEG(r)	((r) * 180.0 / PI)
94 #define DEGTORAD(d)	((d) * PI / 180.0)
95 
96 #define ISCOMMENT(c)    ((c) == SAR_COMMENT_CHAR)
97 #define ISCR(c)         (((c) == '\n') || ((c) == '\r'))
98 
99 
100 /*
101  *	Load intercept by name from scene file, returns 0 on success
102  *	or -1 on no match.
103  */
SARMissionGetInterceptNameFromScene(const char * filename,const char * obj_name,sar_intercept_struct * intercept)104 static int SARMissionGetInterceptNameFromScene(
105 	const char *filename, const char *obj_name,
106 	sar_intercept_struct *intercept
107 )
108 {
109 	int i, status, ptype, total_parms;
110 	char *cur_obj_name = NULL;
111 	void *p, **parm;
112 	sar_parm_version_struct *p_version;
113 	sar_parm_object_name_struct *p_object_name;
114 	sar_parm_translate_struct *p_translate;
115 	sar_parm_rotate_struct *p_rotate;
116 	Boolean matched_translate = False, matched_rotate = False;
117 
118 	if(STRISEMPTY(filename) || STRISEMPTY(obj_name) ||
119 	   (intercept == NULL)
120 	)
121 	    return(-1);
122 
123 	/* Load parms from scene file */
124 	status = SARParmLoadFromFile(
125 	    filename, SAR_FILE_FORMAT_SCENE,
126 	    &parm, &total_parms,
127 	    -1,
128 	    NULL, NULL
129 	);
130 	if(status)
131 	    return(-1);
132 
133 	/* Iterate through loaded parms */
134 	for(i = 0; i < total_parms; i++)
135 	{
136 	    p = parm[i];
137 	    if(p == NULL)
138 		continue;
139 
140 	    /* Handle by parm type */
141 	    ptype = *(int *)p;
142 	    switch(ptype)
143 	    {
144 	      case SAR_PARM_VERSION:
145 		p_version = (sar_parm_version_struct *)p;
146 		if((p_version->major > PROG_VERSION_MAJOR) ||
147 		   (p_version->minor > PROG_VERSION_MINOR) ||
148 		   (p_version->release > PROG_VERSION_RELEASE)
149 		)
150 		{
151 		    int need_warn = 0;
152 		    if(p_version->major > PROG_VERSION_MAJOR)
153 			need_warn = 1;
154 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
155 			    (p_version->minor > PROG_VERSION_MINOR)
156 		    )
157 			need_warn = 1;
158 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
159 			    (p_version->minor == PROG_VERSION_MINOR) &&
160 			    (p_version->release == PROG_VERSION_RELEASE)
161 		    )
162 			need_warn = 1;
163 		    if(need_warn)
164 			fprintf(
165 			    stderr,
166 "%s: Warning: File format version %i.%i.%i is newer than program\
167  version %i.%i.%i.\n",
168 			    filename,
169 			    p_version->major, p_version->minor,
170 			    p_version->release, PROG_VERSION_MAJOR,
171 			    PROG_VERSION_MINOR, PROG_VERSION_RELEASE
172 			);
173 		}
174 		break;
175 
176 	      case SAR_PARM_OBJECT_NAME:
177 		p_object_name = (sar_parm_object_name_struct *)p;
178 	        /* Update current object name */
179 		free(cur_obj_name);
180 		cur_obj_name = STRDUP(p_object_name->name);
181 		/* Reset all other context values */
182 		matched_translate = False;
183 		matched_rotate = False;
184 		break;
185 
186 	      case SAR_PARM_TRANSLATE:
187 		p_translate = (sar_parm_translate_struct *)p;
188 		if((cur_obj_name != NULL) && !matched_translate)
189 		{
190 		    if(!strcasecmp(cur_obj_name, obj_name))
191 		    {
192 			intercept->x = p_translate->translate.x;
193 			intercept->y = p_translate->translate.y;
194 			intercept->z = p_translate->translate.z;
195 
196 			intercept->radius = 40;	/* Explicitly set */
197 
198 			matched_translate = True;
199 		    }
200 		}
201 		break;
202 
203 	      case SAR_PARM_ROTATE:
204 		p_rotate = (sar_parm_rotate_struct *)p;
205 		if((cur_obj_name != NULL) && !matched_rotate)
206 		{
207 		    if(!strcasecmp(cur_obj_name, obj_name))
208 		    {
209 /* TODO, not really needed right now */
210 
211 			matched_rotate = True;
212 		    }
213 		}
214 		break;
215 	    }
216 	}
217 
218 	/* Delete all loaded parms */
219 	SARParmDeleteAll(&parm, &total_parms);
220 
221 	free(cur_obj_name);
222 
223 	return(0);
224 }
225 
226 /*
227  *	Loads the scene map of the given scene specified by filename
228  *	to the given map object as a texture. Any existing texture already
229  *	loaded on the given map object will be unloaded first.
230  *
231  *	Returns -1 on error or 0 on success.
232  *
233  *      This function is intended to be called by
234  *	SARMissionLoadMissionLogToMenuMap().
235  */
SARMissionLoadSceneMapToMenuMap(sar_core_struct * core_ptr,sar_menu_struct * m,sar_menu_map_struct * map_ptr,const char * filename)236 static int SARMissionLoadSceneMapToMenuMap(
237 	sar_core_struct *core_ptr, sar_menu_struct *m,
238 	sar_menu_map_struct *map_ptr,
239 	const char *filename                    /* Scene file */
240 )
241 {
242 	int i, status, ptype, total_parms;
243 	const char *img_path;
244 	void *p, **parm;
245 	sar_parm_version_struct *p_version;
246 	sar_parm_name_struct *p_name;
247 	sar_parm_scene_map_struct *p_scene_map;
248 
249 
250 	if(STRISEMPTY(filename) || (map_ptr == NULL))
251 	    return(-1);
252 
253 	/* Load parms from scene file */
254 	status = SARParmLoadFromFile(
255 	    filename, SAR_FILE_FORMAT_SCENE,
256 	    &parm, &total_parms,
257 	    -1,
258 	    NULL, NULL
259 	);
260 	if(status)
261 	    return(-1);
262 
263 	/* Iterate through loaded parms */
264 	for(i = 0; i < total_parms; i++)
265 	{
266 	    p = parm[i];
267 	    if(p == NULL)
268 		continue;
269 
270 	    /* Handle by parm type */
271 	    ptype = *(int *)p;
272 	    switch(ptype)
273 	    {
274 	      case SAR_PARM_VERSION:
275 		p_version = (sar_parm_version_struct *)p;
276 		if((p_version->major > PROG_VERSION_MAJOR) ||
277 		   (p_version->minor > PROG_VERSION_MINOR) ||
278 		   (p_version->release > PROG_VERSION_RELEASE)
279 		)
280 		{
281 		    int need_warn = 0;
282 		    if(p_version->major > PROG_VERSION_MAJOR)
283 			need_warn = 1;
284 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
285 			    (p_version->minor > PROG_VERSION_MINOR)
286 		    )
287 			need_warn = 1;
288 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
289 			    (p_version->minor == PROG_VERSION_MINOR) &&
290 			    (p_version->release == PROG_VERSION_RELEASE)
291 		    )
292 			need_warn = 1;
293 		    if(need_warn)
294 			fprintf(
295 			    stderr,
296 "%s: Warning: File format version %i.%i.%i is newer than program\
297  version %i.%i.%i.\n",
298 			    filename,
299 			    p_version->major, p_version->minor,
300 			    p_version->release, PROG_VERSION_MAJOR,
301 			    PROG_VERSION_MINOR, PROG_VERSION_RELEASE
302 			);
303 		}
304 		break;
305 
306 	      case SAR_PARM_NAME:
307 		p_name = (sar_parm_name_struct *)p;
308 		free(map_ptr->title);
309 		map_ptr->title = STRDUP(p_name->name);
310 		break;
311 
312 	      case SAR_PARM_SCENE_MAP:
313 		p_scene_map = (sar_parm_scene_map_struct *)p;
314 		/* Width and height in meters */
315 		map_ptr->bg_tex_width = (float)MAX(p_scene_map->width, 10.0);
316 		map_ptr->bg_tex_height = (float)MAX(p_scene_map->height, 10.0);
317 
318 		/* Texture image path */
319 		img_path = p_scene_map->file;
320 		if(!STRISEMPTY(img_path))
321 		{
322 		    char *dpath;
323 
324 		    if(ISPATHABSOLUTE(img_path))
325 		    {
326 			dpath = STRDUP(img_path);
327 		    }
328 		    else
329 		    {
330 			struct stat stat_buf;
331 			const char *s = PrefixPaths(dname.local_data, img_path);
332 			if((s != NULL) ? stat(s, &stat_buf) : True)
333 			    s = PrefixPaths(
334 				dname.global_data, img_path
335 			    );
336 			dpath = STRDUP(s);
337 		    }
338 
339 		    /* Unload menu map's background texture as needed */
340 		    V3DTextureDestroy(map_ptr->bg_tex);
341 
342 		    /* Load new texture for menu map's background */
343 		    map_ptr->bg_tex = V3DTextureLoadFromFile2DPreempt(
344 			dpath,
345 			"mission_map_tex",	/* Not used */
346 			V3D_TEX_FORMAT_RGB	/* Destination format */
347 		    );
348 		    V3DTexturePriority(map_ptr->bg_tex, 0.95f);
349 
350 		    free(dpath);
351 		}
352 		break;
353 
354 	    }   /* Handle by parm type */
355 	}       /* Iterate through loaded parms */
356 
357 	/* Delete all loaded parms */
358 	SARParmDeleteAll(&parm, &total_parms);
359 
360 	return(0);
361 }
362 
363 /*
364  *	Called by SARMissionLoadSceneMapToMenuMap().
365  *
366  *	Loads the scene map and markings of the given scene specified by
367  *	filename to the map object as a texture
368  *
369  *	Intercept points are not loaded.
370  */
SARMissionLoadSceneMapToMenuMapMarkings(sar_core_struct * core_ptr,sar_menu_struct * m,sar_menu_map_struct * map_ptr,const char * scene_filename,const char * mission_filename)371 static int SARMissionLoadSceneMapToMenuMapMarkings(
372 	sar_core_struct *core_ptr,
373 	sar_menu_struct *m, sar_menu_map_struct *map_ptr,
374 	const char *scene_filename, const char *mission_filename
375 )
376 {
377 	int i, n, pass, ptype, total_parms;
378 	const char *img_path;
379 	void *p, **parm;
380 	sar_menu_color_struct fg_color;
381 	sar_menu_map_marking_struct *marking_ptr;
382 	Boolean	got_translate,
383 		got_rotate,
384 		got_object_name,
385 		got_object_map_desc;
386 	sar_parm_version_struct *p_version;
387 	sar_parm_name_struct *p_name;
388 	sar_parm_scene_map_struct *p_scene_map;
389 	sar_parm_new_object_struct *p_new_object;
390 	sar_parm_new_helipad_struct *p_new_helipad;
391 	sar_parm_new_runway_struct *p_new_runway;
392 	sar_parm_new_human_struct *p_new_human;
393 	sar_parm_new_premodeled_struct *p_new_premodeled;
394 	sar_parm_translate_struct *p_translate;
395 	sar_parm_rotate_struct *p_rotate;
396 	sar_parm_object_name_struct *p_object_name;
397 	sar_parm_object_map_description_struct *p_object_map_desc;
398 
399 	if((m == NULL) || (map_ptr == NULL))
400 	    return(-1);
401 
402 	/* Load parms from scene file */
403 	if(SARParmLoadFromFile(
404 	    scene_filename, SAR_FILE_FORMAT_SCENE,
405 	    &parm, &total_parms,
406 	    -1,
407 	    NULL, NULL
408 	))
409 	    return(-1);
410 
411 	/* Iterate through loaded parms */
412 	for(i = 0; i < total_parms; i++)
413 	{
414 	    p = parm[i];
415 	    if(p == NULL)
416 		continue;
417 
418 	    /* Handle by parm type */
419 	    ptype = *(int *)p;
420 	    switch(ptype)
421 	    {
422 	      case SAR_PARM_VERSION:
423 		p_version = (sar_parm_version_struct *)p;
424 		if((p_version->major > PROG_VERSION_MAJOR) ||
425 		   (p_version->minor > PROG_VERSION_MINOR) ||
426 		   (p_version->release > PROG_VERSION_RELEASE)
427 		)
428 		{
429 		    int need_warn = 0;
430 		    if(p_version->major > PROG_VERSION_MAJOR)
431 			need_warn = 1;
432 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
433 			    (p_version->minor > PROG_VERSION_MINOR)
434 		    )
435 			need_warn = 1;
436 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
437 			    (p_version->minor == PROG_VERSION_MINOR) &&
438 			    (p_version->release == PROG_VERSION_RELEASE)
439 		    )
440 			need_warn = 1;
441 		    if(need_warn)
442 			fprintf(
443 			    stderr,
444 "%s: Warning: File format version %i.%i.%i is newer than program\
445  version %i.%i.%i.\n",
446 			    scene_filename,
447 			    p_version->major, p_version->minor,
448 			    p_version->release, PROG_VERSION_MAJOR,
449 			    PROG_VERSION_MINOR, PROG_VERSION_RELEASE
450 			);
451 		}
452 		break;
453 
454 	      case SAR_PARM_NAME:
455 		p_name = (sar_parm_name_struct *)p;
456 		free(map_ptr->title);
457 		map_ptr->title = STRDUP(p_name->name);
458 		break;
459 
460 	      case SAR_PARM_SCENE_MAP:
461 		p_scene_map = (sar_parm_scene_map_struct *)p;
462 		/* Width and height in meters */
463 		map_ptr->bg_tex_width = (float)MAX(p_scene_map->width, 10.0);
464 		map_ptr->bg_tex_height = (float)MAX(p_scene_map->height, 10.0);
465 
466 		/* Texture image path */
467 		img_path = p_scene_map->file;
468 		if(!STRISEMPTY(img_path))
469 		{
470 		    char *dpath;
471 
472 		    if(ISPATHABSOLUTE(img_path))
473 		    {
474 			dpath = STRDUP(img_path);
475 		    }
476 		    else
477 		    {
478 			struct stat stat_buf;
479 			const char *s = PrefixPaths(dname.local_data, img_path);
480 			if((s != NULL) ? stat(s, &stat_buf) : True)
481 			    s = PrefixPaths(
482 				dname.global_data, img_path
483 			    );
484 			dpath = STRDUP(s);
485 		    }
486 
487 		    /* Unload menu map's background texture as needed */
488 		    V3DTextureDestroy(map_ptr->bg_tex);
489 
490 		    /* Load new texture for menu map's background */
491 		    map_ptr->bg_tex = V3DTextureLoadFromFile2DPreempt(
492 			dpath,
493 			"mission_map_tex",	/* Not used */
494 			V3D_TEX_FORMAT_RGB	/* Destination format */
495 		    );
496 		    V3DTexturePriority(map_ptr->bg_tex, 0.95f);
497 
498 		    free(dpath);
499 		}
500 		break;
501 
502 	    }	/* Handle by parm type */
503 	}	/* Iterate through loaded parms */
504 
505 
506 /* Resets all local contexts pointers */
507 #define RESET_CONTEXTS	{		\
508  marking_ptr = NULL;			\
509  got_translate = False;			\
510  got_rotate = False;			\
511  got_object_name = False;		\
512  got_object_map_desc = False;		\
513 }
514 
515 	/* Reset local contexts */
516 	RESET_CONTEXTS
517 
518 	/* Perform two iterations, the first on the existing loaded
519 	 * parms and then reload the parms from the mission file
520 	 * and load from them. This will ensure that we get map markings
521 	 * from first the scene file and then the mission file.
522 	 */
523 	for(pass = 0; pass < 2; pass++)
524 	{
525 	    /* Iterate through loaded parms (second time around) */
526 	    for(i = 0; i < total_parms; i++)
527 	    {
528 		p = parm[i];
529 		if(p == NULL)
530 		    continue;
531 
532 		/* Handle by parm type */
533 		ptype = *(int *)p;
534 		switch(ptype)
535 		{
536 		  case SAR_PARM_NEW_OBJECT:
537 		    p_new_object = (sar_parm_new_object_struct *)p;
538 		    /* Reset local contexts */
539 		    RESET_CONTEXTS
540 /* Ignore for now */
541 		    break;
542 
543 		  case SAR_PARM_NEW_HELIPAD:
544 		    p_new_helipad = (sar_parm_new_helipad_struct *)p;
545 		    /* Reset local contexts */
546 		    RESET_CONTEXTS
547 		    /* Set foreground color */
548 		    fg_color.a = 1.0f;
549 		    fg_color.r = 0.0f;
550 		    fg_color.g = 1.0f;
551 		    fg_color.b = 0.0f;
552 		    /* Allocate new marking on map for intercept */
553 		    n = SARMenuMapAppendMarking(
554 			map_ptr, SAR_MENU_MAP_MARKING_TYPE_ICON,
555 			&fg_color, 0.0, 0.0, 0.0, 0.0,
556 			core_ptr->menumap_helipad_img,
557 			NULL
558 		    );
559 		    marking_ptr = (n > -1) ? map_ptr->marking[n] : NULL;
560 		    break;
561 
562 		  case SAR_PARM_NEW_RUNWAY:
563 		    p_new_runway = (sar_parm_new_runway_struct *)p;
564 		    /* Reset local contexts */
565 		    RESET_CONTEXTS
566 /* Ignore for now */
567 		    break;
568 
569 	          case SAR_PARM_NEW_HUMAN:
570 		    p_new_human = (sar_parm_new_human_struct *)p;
571 		    /* Reset local contexts */
572 		    RESET_CONTEXTS
573 /* Ignore for now */
574 		    break;
575 
576 		  case SAR_PARM_NEW_PREMODELED:
577 		    p_new_premodeled = (sar_parm_new_premodeled_struct *)p;
578 		    /* Reset local contexts */
579 		    RESET_CONTEXTS
580 /* Ignore for now */
581 		    break;
582 
583 		  case SAR_PARM_TRANSLATE:
584 		    p_translate = (sar_parm_translate_struct *)p;
585 		    if((marking_ptr != NULL) && !got_translate)
586 		    {
587 		        marking_ptr->x = p_translate->translate.x;
588 		        marking_ptr->y = p_translate->translate.y;
589 		        got_translate = True;
590 		    }
591 		    break;
592 
593 		  case SAR_PARM_ROTATE:
594 		    p_rotate = (sar_parm_rotate_struct *)p;
595 		    if((marking_ptr != NULL) && !got_rotate)
596 		    {
597 /* Ignore for now */
598 		        got_rotate = True;
599 		    }
600 		    break;
601 
602 		  case SAR_PARM_OBJECT_NAME:
603 		    p_object_name = (sar_parm_object_name_struct *)p;
604 		    if((marking_ptr != NULL) && !got_object_name)
605 		    {
606 /* Ignore for now */
607 		        got_object_name = True;
608 		    }
609 		    break;
610 
611 	          case SAR_PARM_OBJECT_MAP_DESCRIPTION:
612 		    p_object_map_desc =
613 			(sar_parm_object_map_description_struct *)p;
614 		    if((marking_ptr != NULL) && !got_object_map_desc)
615 		    {
616 		        free(marking_ptr->desc);
617 		        marking_ptr->desc = STRDUP(
618 			    p_object_map_desc->description
619 			);
620 			got_object_map_desc = True;
621 		    }
622 		    break;
623 
624 		}	/* Handle by parm type */
625 	    }	/* Iterate through loaded parms (second time around) */
626 
627 	    if(pass >= 1)
628 		break;
629 
630 	    /* Delete loaded parms and then load parms from mission file */
631 	    SARParmDeleteAll(&parm, &total_parms);
632 	    if(SARParmLoadFromFile(
633 		mission_filename, SAR_FILE_FORMAT_MISSION,
634 		&parm, &total_parms,
635 		-1,
636 		NULL, NULL
637 	    ))
638 		break;
639 
640 	    RESET_CONTEXTS
641 	}
642 
643 	/* Delete loaded parms */
644 	SARParmDeleteAll(&parm, &total_parms);
645 
646 #undef RESET_CONTEXTS
647 
648 	return(0);
649 }
650 
651 
652 /*
653  *	Returns a pointer to a dynamically allocated description fetched
654  *	from the specified mission file.
655  *
656  *	The calling function needs to deallocate the returned string.
657  */
SARMissionLoadDescription(const char * filename)658 char *SARMissionLoadDescription(const char *filename)
659 {
660 	int i, status, ptype, total_parms;
661 	void *p, **parm;
662 	sar_parm_description_struct *p_desc;
663 	char *desc = NULL;
664 
665 	if(STRISEMPTY(filename))
666 	    return(desc);
667 
668 	/* Load parms from mission file */
669 	status = SARParmLoadFromFile(
670 	    filename, SAR_FILE_FORMAT_MISSION,
671 	    &parm, &total_parms,
672 	    SAR_PARM_DESCRIPTION,
673 	    NULL, NULL
674 	);
675 	if(status)
676 	    return(desc);
677 
678 	/* Iterate through loaded parms */
679 	for(i = 0; i < total_parms; i++)
680 	{
681 	    p = parm[i];
682 	    if(p == NULL)
683 		continue;
684 
685 	    ptype = *(int *)p;
686 	    switch(ptype)
687 	    {
688 	      case SAR_PARM_DESCRIPTION:
689 		p_desc = (sar_parm_description_struct *)p;
690 		free(desc);
691 		desc = STRDUP(p_desc->description);
692 		break;
693 	    }
694 	}
695 
696 	/* Delete loaded parms */
697 	SARParmDeleteAll(&parm, &total_parms);
698 
699 	return(desc);
700 }
701 
702 /*
703  *	Loads the scene specified by filename to the map object on the
704  *	menu.
705  *
706  *	All relivent objects specified in the scene will be loaded
707  *	as markings on the map object.
708  */
SARMissionLoadSceneToMenuMap(sar_core_struct * core_ptr,sar_menu_struct * m,const char * filename)709 void SARMissionLoadSceneToMenuMap(
710 	sar_core_struct *core_ptr,
711 	sar_menu_struct *m,
712 	const char *filename		/* Mission file name */
713 )
714 {
715 	int i, n, status, ptype, total_parms;
716 	void *p, **parm;
717 	sar_parm_version_struct *p_version;
718 	sar_parm_mission_scene_file_struct *p_mission_scene_file;
719 	sar_parm_mission_begin_at_struct *p_mission_begin_at;
720 	sar_parm_mission_begin_at_pos_struct *p_mission_begin_at_pos;
721 	sar_parm_mission_arrive_at_struct *p_mission_arrive_at;
722 	sar_parm_mission_add_intercept_struct *p_mission_add_intercept;
723 	int map_num = -1;
724 	sar_menu_map_struct *map_ptr = NULL;
725 	const char *s;
726 	Boolean begin_at_set = False;
727 	char	*scene_filename = NULL,
728 		*arrive_at_name = NULL,
729 		*begin_at_name = NULL;
730 	sar_menu_map_marking_struct	*marking_ptr = NULL,
731 					*intercept_marking_ptr = NULL;
732 	int intercepts_set = 0;
733 
734 	if(m == NULL)
735 	    return;
736 
737 	/* Get first map object on the menu */
738 	for(i = 0; i < m->total_objects; i++)
739 	{
740 	    p = m->object[i];
741 	    if(p == NULL)
742 		continue;
743 
744 	    ptype = (*(int *)p);
745 	    if(ptype == SAR_MENU_OBJECT_TYPE_MAP)
746 	    {
747 		map_num = i;
748 		map_ptr = SAR_MENU_MAP(p);
749 		break;
750 	    }
751 	}
752 	if(map_ptr == NULL)
753 	    return;
754 
755 	/* Delete all markings on menu's map object */
756 	SARMenuMapDeleteAllMarkings(map_ptr);
757 
758 	/* If no filename was given then only delete map markings */
759 	if(STRISEMPTY(filename))
760 	    return;
761 
762 	/* Note that order of which parameters appear in the mission
763 	 * file is important!
764 	 *
765 	 * We expect to parse certain parameters before others
766 	 */
767 
768 	/* Load parms from mission file */
769 	status = SARParmLoadFromFile(
770 	    filename, SAR_FILE_FORMAT_MISSION,
771 	    &parm, &total_parms,
772 	    -1,
773 	    NULL, NULL
774 	);
775 	if(status)
776 	    return;
777 
778 	/* Iterate through loaded parms */
779 	for(i = 0; i < total_parms; i++)
780 	{
781 	    p = parm[i];
782 	    if(p == NULL)
783 		continue;
784 
785 	    /* Handle by parm type */
786 	    ptype = *(int *)p;
787 	    switch(ptype)
788 	    {
789 	      case SAR_PARM_VERSION:
790 		p_version = (sar_parm_version_struct *)p;
791 		if((p_version->major > PROG_VERSION_MAJOR) ||
792 		   (p_version->minor > PROG_VERSION_MINOR) ||
793 		   (p_version->release > PROG_VERSION_RELEASE)
794 		)
795 		{
796 		    int need_warn = 0;
797 		    if(p_version->major > PROG_VERSION_MAJOR)
798 			need_warn = 1;
799 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
800 			    (p_version->minor > PROG_VERSION_MINOR)
801 		    )
802 			need_warn = 1;
803 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
804 			    (p_version->minor == PROG_VERSION_MINOR) &&
805 			    (p_version->release == PROG_VERSION_RELEASE)
806 		    )
807 			need_warn = 1;
808 		    if(need_warn)
809 			fprintf(
810 			    stderr,
811 "%s: Warning: File format version %i.%i.%i is newer than program\
812  version %i.%i.%i.\n",
813 			    filename,
814 			    p_version->major, p_version->minor,
815 			    p_version->release, PROG_VERSION_MAJOR,
816 			    PROG_VERSION_MINOR, PROG_VERSION_RELEASE
817 			);
818 		}
819 		break;
820 
821 	      case SAR_PARM_MISSION_SCENE_FILE:
822 		p_mission_scene_file = (sar_parm_mission_scene_file_struct *)p;
823 		s = p_mission_scene_file->file;
824 		if(!STRISEMPTY(s))
825 		{
826 		    if(ISPATHABSOLUTE(s))
827 		    {
828 			free(scene_filename);
829 			scene_filename = STRDUP(s);
830 		    }
831 		    else
832 		    {
833 			struct stat stat_buf;
834 			char *s2 = PrefixPaths(dname.local_data, s);
835 			if((s2 != NULL) ? stat(s2, &stat_buf) : True)
836 			    s2 = PrefixPaths(dname.global_data, s);
837 			if(s2 != NULL)
838 			{
839 			    free(scene_filename);
840 			    scene_filename = STRDUP(s2);
841 			}
842 		    }
843 
844 		    /* Load information from scene file which are
845 		     * relivent to the mission map (such as map
846 		     * background texture file and landmarks)
847 		     */
848 		    SARMissionLoadSceneMapToMenuMapMarkings(
849 			core_ptr, m, map_ptr,
850 			scene_filename,	/* Scene file */
851 			filename	/* Mission file */
852 		    );
853 		}
854 		break;
855 
856 	      case SAR_PARM_MISSION_BEGIN_AT:
857 		p_mission_begin_at = (sar_parm_mission_begin_at_struct *)p;
858 		if(p_mission_begin_at->name != NULL)
859 		{
860 		    sar_menu_color_struct fg_color;
861 		    sar_intercept_struct intercept;
862 		    memset(&intercept, 0x00, sizeof(sar_intercept_struct));
863 
864 		    /* Update begin at name */
865 		    free(begin_at_name);
866 		    begin_at_name = STRDUP(p_mission_begin_at->name);
867 
868 		    /* Match intercept by name and set begin at location (only
869 		     * if the begin at location has not been set yet)
870 		     */
871 		    if(!SARMissionGetInterceptNameFromScene(
872 			scene_filename, begin_at_name, &intercept
873 		    ) && !begin_at_set)
874 		    {
875 			fg_color.a = 1.0;
876 			fg_color.r = 0.0;
877 			fg_color.g = 1.0;
878 			fg_color.b = 0.0;
879 
880 			/* Allocate new marking on map for intercept */
881 			n = SARMenuMapAppendMarking(
882 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_INTERCEPT_LINE,
883 			    &fg_color,
884 			    intercept.x, intercept.y,
885 			    0.0, 0.0,
886 			    NULL, NULL
887 			);
888 			marking_ptr = ((n >= 0) ? map_ptr->marking[n] : NULL);
889 			intercept_marking_ptr = marking_ptr;
890 			if(marking_ptr != NULL)
891 			{
892 			    intercepts_set++;
893 
894 			    /* Reset meters to pixels coeff zoom */
895 			    map_ptr->m_to_pixels_coeff = (float)SAR_MAP_DEF_MTOP_COEFF;
896 
897 			    /* Set initial scroll position on map with
898 			     * respect to the begin at location
899 			     */
900 			    map_ptr->scroll_x = (int)(-intercept.x *
901 				map_ptr->m_to_pixels_coeff);
902 			    map_ptr->scroll_y = (int)(-intercept.y *
903 				map_ptr->m_to_pixels_coeff);
904 
905 			    /* Reset selected_marking on menu map */
906 			    map_ptr->selected_marking = -1;
907 			}
908 
909 			begin_at_set = True;
910 		    }
911 		}
912 		break;
913 
914 	     case SAR_PARM_MISSION_BEGIN_AT_POS:
915 		p_mission_begin_at_pos = (sar_parm_mission_begin_at_pos_struct *)p;
916 		if(!begin_at_set)
917 		{
918 		    sar_menu_color_struct fg_color;
919 		    sar_position_struct *ipos = &p_mission_begin_at_pos->pos;
920 
921 		    fg_color.a = 1.0f;
922 		    fg_color.r = 0.0f;
923 		    fg_color.g = 1.0f;
924 		    fg_color.b = 0.0f;
925 
926 		    /* Allocate new marking on map for intercept */
927 		    n = SARMenuMapAppendMarking(
928 			map_ptr, SAR_MENU_MAP_MARKING_TYPE_INTERCEPT_LINE,
929 			&fg_color,
930 			ipos->x, ipos->y,
931 			0.0f, 0.0f,
932 			NULL, NULL
933 		    );
934 		    marking_ptr = (n > -1) ? map_ptr->marking[n] : NULL;
935 		    intercept_marking_ptr = marking_ptr;
936 		    if(marking_ptr != NULL)
937 		    {
938 			intercepts_set++;
939 
940 			/* Reset meters to pixels coeff zoom */
941 			map_ptr->m_to_pixels_coeff = (float)SAR_MAP_DEF_MTOP_COEFF;
942 
943 			/* Set initial scroll position on map with
944 			 * respect to the begin at location
945 			 */
946 			map_ptr->scroll_x = (int)(-ipos->x *
947 			    map_ptr->m_to_pixels_coeff);
948 			map_ptr->scroll_y = (int)(-ipos->y *
949 			    map_ptr->m_to_pixels_coeff);
950 
951 			/* Reset selected_marking on menu map */
952 			map_ptr->selected_marking = -1;
953 		    }
954 
955 		    begin_at_set = True;
956 		}
957 		break;
958 
959 	      case SAR_PARM_MISSION_ARRIVE_AT:
960 		p_mission_arrive_at = (sar_parm_mission_arrive_at_struct *)p;
961 		if(p_mission_arrive_at->name)
962 		{
963 		    free(arrive_at_name);
964 		    arrive_at_name = STRDUP(p_mission_arrive_at->name);
965 		}
966 		break;
967 
968 	      case SAR_PARM_MISSION_ADD_INTERCEPT:
969 		p_mission_add_intercept = (sar_parm_mission_add_intercept_struct *)p;
970 		if(1)
971 		{
972 		    sar_intercept_struct intercept;
973 		    memset(&intercept, 0x00, sizeof(sar_intercept_struct));
974 
975 		    /* Set intercept by reference code */
976 		    switch(p_mission_add_intercept->ref_code)
977 		    {
978 		      case 3:		/* Arrive at location */
979 			SARMissionGetInterceptNameFromScene(
980 			    scene_filename, arrive_at_name,
981 			    &intercept
982 			);
983 			break;
984 
985 		      case 2:		/* Begin at location */
986 			SARMissionGetInterceptNameFromScene(
987 			    scene_filename, begin_at_name,
988 			    &intercept
989 			);
990 			break;
991 
992 		      default:		/* Standard intercept */
993 			intercept.x = p_mission_add_intercept->pos.x;
994 			intercept.y = p_mission_add_intercept->pos.y;
995 			intercept.z = p_mission_add_intercept->pos.z;
996 			intercept.radius = p_mission_add_intercept->radius;
997 			intercept.urgency = p_mission_add_intercept->urgency;
998 			break;
999 		    }
1000 
1001 		    /* Allocate new map marking structure, note previous
1002 		     * marking structure should already be allocated from
1003 		     * another add intercept parameter or begin at name
1004 		     * parameter
1005 		     */
1006 		    if((marking_ptr != NULL) &&
1007 		       (intercept_marking_ptr != NULL)
1008 		    )
1009 		    {
1010 			sar_menu_map_marking_struct *new_ptr;
1011 
1012 			/* Allocate new intercept marking structure and
1013 			 * copy over end position values from previous
1014 			 * marking structure
1015 			 */
1016 			n = SARMenuMapAppendMarking(
1017 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_INTERCEPT_LINE,
1018 			    NULL, 0.0f, 0.0f, 0.0f, 0.0f,
1019 			    NULL, NULL
1020 			);
1021 			new_ptr = (n > -1) ? map_ptr->marking[n] : NULL;
1022 
1023 			/* Set end position on last marking structure */
1024 			marking_ptr->x_end = intercept.x;
1025 			marking_ptr->y_end = intercept.y;
1026 
1027 			intercepts_set++;
1028 
1029 			/* New marking structure allocated successfully? */
1030 			if(new_ptr != NULL)
1031 			{
1032 			    /* Copy over fg color from previous marking */
1033 			    memcpy(
1034 			        &new_ptr->fg_color,
1035 			        &marking_ptr->fg_color,
1036 			        sizeof(sar_menu_color_struct)
1037 			    );
1038 			    new_ptr->x = intercept.x;
1039 			    new_ptr->y = intercept.y;
1040 
1041 			    intercepts_set++;
1042 
1043 			    intercept_marking_ptr = new_ptr;
1044 			    marking_ptr = new_ptr;
1045 		        }
1046 			else
1047 			{
1048 			    intercept_marking_ptr = NULL;
1049 			    marking_ptr = NULL;
1050 			}
1051 
1052 			/* Allocate another marking structure to represent
1053 			 * way point icon
1054 			 */
1055 			n = SARMenuMapAppendMarking(
1056 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_ICON,
1057 			    NULL,
1058 			    intercept.x, intercept.y,
1059 			    0.0f, 0.0f,
1060 			    core_ptr->menumap_intercept_img, NULL
1061 			);
1062 			new_ptr = ((n >= 0) ? map_ptr->marking[n] : NULL);
1063 		    }
1064 		}
1065 		break;
1066 	    }	/* Handle parm by type */
1067 	}	/* Iterate through loaded parms */
1068 
1069 
1070 	/* Delete loaded parms */
1071 	SARParmDeleteAll(&parm, &total_parms);
1072 
1073 
1074 	/* Delete local context names */
1075 	free(scene_filename);
1076 	scene_filename = NULL;
1077 
1078 	free(arrive_at_name);
1079 	arrive_at_name = NULL;
1080 
1081 	free(begin_at_name);
1082 	begin_at_name = NULL;
1083 
1084 
1085 	/* If the number of intercepts set on the map is an odd number,
1086 	 * then that implies that the last intercept line marking is
1087 	 * extraneous
1088 	 */
1089 	if(intercepts_set & 1)
1090 	{
1091 	    /* Delete the last marking pointer of type
1092 	     * SAR_MENU_MAP_MARKING_TYPE_INTERCEPT_LINE
1093 	     *
1094 	     * Iterate from last to first of all markings on the map
1095 	     */
1096 	    for(i = map_ptr->total_markings - 1; i >= 0; i--)
1097 	    {
1098 		marking_ptr = map_ptr->marking[i];
1099 		if(marking_ptr == NULL)
1100 		    continue;
1101 
1102 		/* Check marking type */
1103 		if(marking_ptr->type == SAR_MENU_MAP_MARKING_TYPE_INTERCEPT_LINE)
1104 		{
1105 		    /* Need to delete this marking on the map, set the
1106 		     * pointer to NULL after deleting it
1107 		     */
1108 		    free(marking_ptr);
1109 		    map_ptr->marking[i] = NULL;
1110 
1111 		    /* Do not delete any more markings */
1112 		    break;
1113 		}
1114 	    }
1115 	}
1116 
1117 }
1118 
1119 /*
1120  *	Procedure to load the mission log specified by filename to the
1121  *	map object on the given menu.
1122  */
SARMissionLoadMissionLogToMenuMap(sar_core_struct * core_ptr,sar_menu_struct * m,const char * filename)1123 void SARMissionLoadMissionLogToMenuMap(
1124 	sar_core_struct *core_ptr,
1125 	sar_menu_struct *m,
1126 	const char *filename		/* Mission log file name */
1127 )
1128 {
1129 	int i, ptype, status, total_parms;
1130 	void *p, **parm;
1131 	sar_position_struct *pos;
1132 	sar_parm_version_struct *p_version;
1133 	sar_parm_mission_log_header_struct *p_mission_log_header;
1134 	sar_parm_mission_log_event_struct *p_mission_log_event;
1135 	int map_num = -1;
1136 	sar_menu_map_struct *map_ptr = NULL;
1137 	Boolean handled_header = False;
1138 	char	*title = NULL,
1139 		*scene_filename = NULL,
1140 		*player_stats_filename = NULL;
1141 	sar_menu_map_marking_struct *last_intercept_marking = NULL;
1142 	int total_intercept_markings = 0;
1143 	int total_events = 0;
1144 
1145 	if(m == NULL)
1146 	    return;
1147 
1148 	/* Get first map object on the menu */
1149 	for(i = 0; i < m->total_objects; i++)
1150 	{
1151 	    p = m->object[i];
1152 	    if(p == NULL)
1153 		continue;
1154 
1155 	    ptype = (*(int *)p);
1156 	    if(ptype == SAR_MENU_OBJECT_TYPE_MAP)
1157 	    {
1158 		map_num = i;
1159 		map_ptr = SAR_MENU_MAP(p);
1160 		break;
1161 	    }
1162 	}
1163 	if(map_ptr == NULL)
1164 	    return;
1165 
1166 	/* Delete all markings on menu's map object */
1167 	SARMenuMapDeleteAllMarkings(map_ptr);
1168 
1169 	/* If no filename was given then only delete map markings */
1170 	if(STRISEMPTY(filename))
1171 	    return;
1172 
1173 	/* Load parms from mission log file */
1174 	status = SARParmLoadFromFile(
1175 	    filename, SAR_FILE_FORMAT_MISSION_LOG,
1176 	    &parm, &total_parms,
1177 	    -1,
1178 	    NULL, NULL
1179 	);
1180 	if(status)
1181 	    return;
1182 
1183 
1184 	/* Iterate through loaded parms */
1185 	for(i = 0; i < total_parms; i++)
1186 	{
1187 	    p = parm[i];
1188 	    if(p == NULL)
1189 		continue;
1190 
1191 	    /* Handle by parm type */
1192 	    ptype = *(int *)p;
1193 	    switch(ptype)
1194 	    {
1195 	      case SAR_PARM_VERSION:
1196 		p_version = (sar_parm_version_struct *)p;
1197 		if((p_version->major > PROG_VERSION_MAJOR) ||
1198 		   (p_version->minor > PROG_VERSION_MINOR) ||
1199 		   (p_version->release > PROG_VERSION_RELEASE)
1200 		)
1201 		{
1202 		    int need_warn = 0;
1203 		    if(p_version->major > PROG_VERSION_MAJOR)
1204 			need_warn = 1;
1205 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
1206 			    (p_version->minor > PROG_VERSION_MINOR)
1207 		    )
1208 			need_warn = 1;
1209 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
1210 			    (p_version->minor == PROG_VERSION_MINOR) &&
1211 			    (p_version->release == PROG_VERSION_RELEASE)
1212 		    )
1213 			need_warn = 1;
1214 		    if(need_warn)
1215 			fprintf(
1216 			    stderr,
1217 "%s: Warning: File format version %i.%i.%i is newer than program\
1218  version %i.%i.%i.\n",
1219 			    filename,
1220 			    p_version->major, p_version->minor,
1221 			    p_version->release, PROG_VERSION_MAJOR,
1222 			    PROG_VERSION_MINOR, PROG_VERSION_RELEASE
1223 			);
1224 		}
1225 		break;
1226 
1227 	      case SAR_PARM_MISSION_LOG_HEADER:
1228 		p_mission_log_header = (sar_parm_mission_log_header_struct *)p;
1229 
1230 		free(title);
1231 		title = STRDUP(p_mission_log_header->title);
1232 
1233 		free(scene_filename);
1234 		scene_filename = STRDUP(p_mission_log_header->scene_file);
1235 
1236 		free(player_stats_filename);
1237 		player_stats_filename = STRDUP(p_mission_log_header->player_stats_file);
1238 
1239 		/* Handle this header if we have not yet handled the
1240 		 * header earlier
1241 		 */
1242 		if(!handled_header)
1243 		{
1244 		    /* Got scene file name from reading the log file? */
1245 		    if(scene_filename != NULL)
1246 			SARMissionLoadSceneMapToMenuMap(
1247 			    core_ptr, m, map_ptr, scene_filename
1248 			);
1249 
1250 		    /* Reset map */
1251 		    map_ptr->m_to_pixels_coeff = (float)SAR_MAP_DEF_MTOP_COEFF;
1252 		    /* Reset initial scroll position */
1253 		    map_ptr->scroll_x = (int)(
1254 			0.0f * map_ptr->m_to_pixels_coeff
1255 		    );
1256 		    map_ptr->scroll_y = (int)(
1257 			0.0f * map_ptr->m_to_pixels_coeff
1258 		    );
1259 		    /* Reset selected_marking on menu map */
1260 		    map_ptr->selected_marking = -1;
1261 
1262 		    /* Title needs to be set after calling
1263 		     * SARMissionLoadSceneMapToMenuMap() since it will
1264 		     * set the title
1265 		     */
1266 		    free(map_ptr->title);
1267 		    map_ptr->title = STRDUP(title);
1268 
1269 		    /* Mark that we handled the header */
1270 		    handled_header = True;
1271 		}
1272 		break;
1273 
1274 	      case SAR_PARM_MISSION_LOG_EVENT:
1275 		p_mission_log_event = (sar_parm_mission_log_event_struct *)p;
1276 		pos = &p_mission_log_event->pos;
1277 		if(True)
1278 		{
1279 		    int n;
1280 		    sar_menu_color_struct fg_color;
1281 
1282 		    fg_color.a = 1.0f;
1283 		    fg_color.r = 0.0f;
1284 		    fg_color.g = 1.0f;
1285 		    fg_color.b = 0.0f;
1286 
1287 		    /* Handle mission log event by its type */
1288 		    switch(p_mission_log_event->event_type)
1289 		    {
1290 		      case SAR_MISSION_LOG_EVENT_COMMENT:
1291 			SARMenuMapAppendMarking(
1292 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_ICON,
1293 			    &fg_color,
1294 			    pos->x, pos->y,
1295 			    0.0f, 0.0f,
1296 			    NULL,		/* No icon */
1297 			    p_mission_log_event->message
1298 			);
1299 			break;
1300 
1301 		      case SAR_MISSION_LOG_EVENT_POSITION:
1302 			/* Was there a prior intercept marking? */
1303 			if(last_intercept_marking != NULL)
1304 			{
1305 			    /* Set last intercept marking's end position
1306 			     * to the position specified by this log event
1307 			     */
1308 			    last_intercept_marking->x_end = pos->x;
1309 			    last_intercept_marking->y_end = pos->y;
1310 			}
1311 			/* Create a new intercept line marking */
1312 			n = SARMenuMapAppendMarking(
1313 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_INTERCEPT_LINE,
1314 			    &fg_color,
1315 			    pos->x, pos->y,
1316 			    pos->x, pos->y,
1317 			    NULL,	/* No icon */
1318 			    NULL	/* No message */
1319 			);
1320 			/* Record pointer to this intercept line marking */
1321 			last_intercept_marking = (n > -1) ?
1322 			    map_ptr->marking[n] : NULL;
1323 			/* Increment total number of intercept markings */
1324 			total_intercept_markings++;
1325 			break;
1326 
1327 		      case SAR_MISSION_LOG_EVENT_TAKEOFF:
1328 			SARMenuMapAppendMarking(
1329 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_ICON,
1330 			    &fg_color,
1331 			    pos->x, pos->y,
1332 			    0.0f, 0.0f,
1333 			    core_ptr->menumap_helicopter_img,
1334 			    p_mission_log_event->message
1335 			);
1336 			break;
1337 
1338 		      case SAR_MISSION_LOG_EVENT_LAND:
1339 			SARMenuMapAppendMarking(
1340 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_ICON,
1341 			    &fg_color,
1342 			    pos->x, pos->y,
1343 			    0.0f, 0.0f,
1344 			    core_ptr->menumap_helicopter_img,
1345 			    p_mission_log_event->message
1346 			);
1347 			break;
1348 
1349 		      case SAR_MISSION_LOG_EVENT_CRASH:
1350 			SARMenuMapAppendMarking(
1351 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_ICON,
1352 			    &fg_color,
1353 			    pos->x, pos->y,
1354 			    0.0f, 0.0f,
1355 			    core_ptr->menumap_crash_img,
1356 			    p_mission_log_event->message
1357 			);
1358 			break;
1359 
1360 		      case SAR_MISSION_LOG_EVENT_PICKUP:
1361 			SARMenuMapAppendMarking(
1362 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_ICON,
1363 			    &fg_color,
1364 			    pos->x, pos->y,
1365 			    0.0f, 0.0f,
1366 			    core_ptr->menumap_victim_img,
1367 			    p_mission_log_event->message
1368 			);
1369 			break;
1370 
1371 		      case SAR_MISSION_LOG_EVENT_DROPOFF:
1372 			SARMenuMapAppendMarking(
1373 			    map_ptr, SAR_MENU_MAP_MARKING_TYPE_ICON,
1374 			    &fg_color,
1375 			    pos->x, pos->y,
1376 			    0.0f, 0.0f,
1377 			    core_ptr->menumap_helicopter_img,
1378 			    p_mission_log_event->message
1379 			);
1380 			break;
1381 		    }
1382 		}
1383 
1384 		/* If this is the first event then set map's scroll
1385 		 * position to it
1386 		 */
1387 		if(total_events == 0)
1388 		{
1389 		    map_ptr->scroll_x = (int)(
1390 			-pos->x * map_ptr->m_to_pixels_coeff
1391 		    );
1392 		    map_ptr->scroll_y = (int)(
1393 			-pos->y * map_ptr->m_to_pixels_coeff
1394 		    );
1395 		    map_ptr->selected_marking = 0;
1396 		}
1397 
1398 		total_events++;
1399 
1400 		break;
1401 	    }
1402 	}
1403 
1404 	/* Delete loaded parms */
1405 	SARParmDeleteAll(&parm, &total_parms);
1406 
1407 	free(title);
1408 	free(scene_filename);
1409 	free(player_stats_filename);
1410 }
1411 
1412 /*
1413  *	Loads a new mission
1414  *
1415  *	Note that the scene structure in the core structure must be
1416  *	allocated and with all values reset.
1417  */
SARMissionLoadFromFile(sar_core_struct * core_ptr,const char * filename,void * client_data,int (* progress_func)(void *,long,long))1418 sar_mission_struct *SARMissionLoadFromFile(
1419 	sar_core_struct *core_ptr, const char *filename,
1420 	void *client_data,
1421 	int (*progress_func)(void *, long, long)
1422 )
1423 {
1424 	int i, status, ptype, total_parms;
1425 	void *p, **parm;
1426 	sar_parm_version_struct *p_version;
1427 	sar_parm_name_struct *p_name;
1428 	sar_parm_description_struct *p_desc;
1429 	sar_parm_player_model_file_struct *p_player_model_file;
1430 	sar_parm_weather_struct *p_weather;
1431 	sar_parm_time_of_day_struct *p_time_of_day;
1432 	sar_parm_texture_base_directory_struct *p_texture_base_directory;
1433 	sar_parm_texture_load_struct *p_texture_load;
1434 	sar_parm_mission_new_objective_struct *p_mission_new_objective;
1435 	sar_parm_mission_scene_file_struct *p_mission_scene_file;
1436 	sar_parm_mission_time_left_struct *p_mission_time_left;
1437 	sar_parm_mission_begin_at_struct *p_mission_begin_at;
1438 	sar_parm_mission_begin_at_pos_struct *p_mission_begin_at_pos;
1439 	sar_parm_mission_arrive_at_struct *p_mission_arrive_at;
1440 	sar_parm_mission_message_success_struct *p_mission_message_success;
1441 	sar_parm_mission_message_fail_struct *p_mission_message_fail;
1442 	sar_parm_mission_humans_tally_struct *p_mission_humans_tally;
1443 	sar_parm_mission_add_intercept_struct *p_mission_add_intercept;
1444 	sar_parm_new_object_struct *p_new_object;
1445 	sar_parm_new_helipad_struct *p_new_helipad;
1446 	sar_parm_new_runway_struct *p_new_runway;
1447 	sar_parm_new_human_struct *p_new_human;
1448 	sar_parm_new_fire_struct *p_new_fire;
1449 	sar_parm_new_smoke_struct *p_new_smoke;
1450 	sar_parm_new_premodeled_struct *p_new_premodeled;
1451 	sar_parm_model_file_struct *p_model_file;
1452 	sar_parm_translate_struct *p_translate;
1453 	sar_parm_translate_random_struct *p_translate_random;
1454 	sar_parm_rotate_struct *p_rotate;
1455 	sar_parm_no_depth_test_struct *p_no_depth_test;
1456 	sar_parm_polygon_offset_struct *p_polygon_offset;
1457 	sar_parm_object_name_struct *p_object_name;
1458 	sar_parm_runway_approach_lighting_north_struct *p_runway_applight_n;
1459 	sar_parm_runway_approach_lighting_south_struct *p_runway_applight_s;
1460 	sar_parm_human_message_enter_struct *p_human_message_enter;
1461 	sar_parm_human_reference_struct *p_human_reference;
1462 
1463 	Boolean loaded_scene = False;
1464 	sar_mission_struct *mission;
1465 	int objective_num = -1;
1466 	sar_mission_objective_struct *objective = NULL;
1467 
1468 	int humans_need_rescue = 0;
1469 	char	*begin_at_name = NULL,
1470 		*arrive_at_name = NULL,
1471 		*weather_preset_name = NULL;
1472 
1473 	int obj_num = -1;
1474 	sar_object_struct *obj_ptr = NULL;
1475 	sar_object_aircraft_struct *obj_aircraft_ptr = NULL;
1476 	sar_object_ground_struct *obj_ground_ptr = NULL;
1477 	sar_object_helipad_struct *obj_helipad_ptr = NULL;
1478 	sar_object_runway_struct *obj_runway_ptr = NULL;
1479 	sar_object_human_struct *obj_human_ptr = NULL;
1480 	sar_object_smoke_struct *obj_smoke_ptr = NULL;
1481 	sar_object_fire_struct *obj_fire_ptr = NULL;
1482 	Boolean begin_at_set = False;
1483 	sar_position_struct begin_pos;
1484 	sar_direction_struct begin_dir;
1485 
1486 	sar_scene_struct *scene = core_ptr->scene;
1487 	sar_object_struct ***ptr = &core_ptr->object;
1488 	int *total = &core_ptr->total_objects;
1489 	const sar_option_struct *opt = &core_ptr->option;
1490 	if((scene == NULL) || (filename == NULL))
1491 	    return(NULL);
1492 
1493 /* Regets object substructure pointers from the specified object */
1494 #define CONTEXT_REGET_SUBSTRUCTURE_PTRS(_o_) {		\
1495  if((_o_) != NULL) {					\
1496   obj_aircraft_ptr = SAR_OBJ_GET_AIRCRAFT(_o_);		\
1497   obj_ground_ptr = SAR_OBJ_GET_GROUND(_o_);		\
1498   obj_helipad_ptr = SAR_OBJ_GET_HELIPAD(_o_);		\
1499   obj_runway_ptr = SAR_OBJ_GET_RUNWAY(_o_);		\
1500   obj_human_ptr = SAR_OBJ_GET_HUMAN(_o_);		\
1501   obj_smoke_ptr = SAR_OBJ_GET_SMOKE(_o_);		\
1502   obj_fire_ptr = SAR_OBJ_GET_FIRE(_o_);			\
1503  }							\
1504 }
1505 
1506 	/* Note, order of which parameters appear in the mission file
1507 	 * is important! We expect to parse certain parameters before
1508 	 * others in this function.
1509 	 */
1510 
1511 	/* Load parms from mission file */
1512 	status = SARParmLoadFromFile(
1513 	    filename, SAR_FILE_FORMAT_MISSION,
1514 	    &parm, &total_parms,
1515 	    -1,
1516 	    NULL, NULL
1517 	);
1518 	if(status)
1519 	    return(NULL);
1520 
1521 	if(opt->runtime_debug)
1522 	    printf(
1523 "SARMissionLoadFromFile(): Creating new mission...\n"
1524 	    );
1525 
1526 	/* Allocate a new mission structure */
1527 	mission = (sar_mission_struct *)calloc(
1528 	    1, sizeof(sar_mission_struct)
1529 	);
1530 	if(mission == NULL)
1531 	{
1532 	    SARParmDeleteAll(&parm, &total_parms);
1533 	    return(NULL);
1534 	}
1535 
1536 	/* Set up default mission values */
1537 	mission->state = MISSION_STATE_IN_PROGRESS;
1538 	mission->title = NULL;
1539 	mission->description = NULL;
1540 	mission->start_location_name = NULL;
1541 	mission->scene_file = NULL;
1542 	mission->player_model_file = NULL;
1543 	mission->player_stats_file = NULL;
1544 	mission->objective = NULL;
1545 	mission->total_objectives = 0;
1546 	mission->cur_objective = 0;		/* Always start on first objective */
1547 	mission->time_spent = 0.0f;
1548 	mission->check_int = 1000;		/* In milliseconds */
1549 	mission->next_check = cur_millitime + mission->check_int;
1550 	mission->log_position_int = 10000;
1551 	mission->next_log_position = cur_millitime + mission->log_position_int;
1552 
1553 	/* Iterate through loaded parms */
1554 	for(i = 0; i < total_parms; i++)
1555 	{
1556 	    p = parm[i];
1557 	    if(p == NULL)
1558 		continue;
1559 
1560 	    /* Handle by parm type */
1561 	    ptype = *(int *)p;
1562 	    switch(ptype)
1563 	    {
1564 	      case SAR_PARM_VERSION:
1565 		p_version = (sar_parm_version_struct *)p;
1566 		if((p_version->major > PROG_VERSION_MAJOR) ||
1567 		   (p_version->minor > PROG_VERSION_MINOR) ||
1568 		   (p_version->release > PROG_VERSION_RELEASE)
1569 		)
1570 		{
1571 		    int need_warn = 0;
1572 		    if(p_version->major > PROG_VERSION_MAJOR)
1573 			need_warn = 1;
1574 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
1575 			    (p_version->minor > PROG_VERSION_MINOR)
1576 		    )
1577 			need_warn = 1;
1578 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
1579 			    (p_version->minor == PROG_VERSION_MINOR) &&
1580 			    (p_version->release == PROG_VERSION_RELEASE)
1581 		    )
1582 			need_warn = 1;
1583 		    if(need_warn)
1584 			fprintf(
1585 			    stderr,
1586 "%s: Warning: File format version %i.%i.%i is newer than program\
1587  version %i.%i.%i.\n",
1588 			    filename,
1589 			    p_version->major, p_version->minor,
1590 			    p_version->release, PROG_VERSION_MAJOR,
1591 			    PROG_VERSION_MINOR, PROG_VERSION_RELEASE
1592 			);
1593 		}
1594 		break;
1595 
1596 	      case SAR_PARM_NAME:
1597 		p_name = (sar_parm_name_struct *)p;
1598 		free(mission->title);
1599 		mission->title = STRDUP(p_name->name);
1600 		break;
1601 
1602 	      case SAR_PARM_DESCRIPTION:
1603 		p_desc = (sar_parm_description_struct *)p;
1604 		free(mission->description);
1605 		mission->description = STRDUP(p_desc->description);
1606 		break;
1607 
1608 	      case SAR_PARM_PLAYER_MODEL_FILE:
1609 		p_player_model_file = (sar_parm_player_model_file_struct *)p;
1610 		if(loaded_scene)
1611 		{
1612 		    const char *player_file = p_player_model_file->file;
1613 		    char *full_path;
1614 
1615 		    /* Complete path */
1616 		    if(ISPATHABSOLUTE(player_file))
1617 		    {
1618 			full_path = STRDUP(player_file);
1619 		    }
1620 		    else
1621 		    {
1622 			struct stat stat_buf;
1623 			full_path = STRDUP(PrefixPaths(
1624 			    dname.local_data, player_file
1625 			));
1626 			if((full_path != NULL) ? stat(full_path, &stat_buf) : True)
1627 			{
1628 			    free(full_path);
1629 			    full_path = STRDUP(PrefixPaths(
1630 				dname.global_data, player_file
1631 			    ));
1632 			}
1633 		    }
1634 		    if(full_path == NULL)
1635 			fprintf(
1636 			    stderr,
1637 "%s: Warning: Unable to complete path \"%s\".\n",
1638 			    filename, player_file
1639 			);
1640 
1641 		    /* Update player model file name on mission and
1642 		     * core structures.
1643 		     */
1644 		    free(mission->player_model_file);
1645 		    mission->player_model_file = STRDUP(full_path);
1646 
1647 		    free(core_ptr->cur_player_model_file);
1648 		    core_ptr->cur_player_model_file = STRDUP(full_path);
1649 
1650 		    /* Create the player object since the model file is
1651 		     * now known
1652 		     */
1653 		    SARSceneAddPlayerObject(
1654 			core_ptr, scene,
1655 			full_path,
1656 			&begin_pos, &begin_dir
1657 		    );
1658 
1659 		    /* Update object context pointers */
1660 		    obj_num = scene->player_obj_num;
1661 		    obj_ptr = scene->player_obj_ptr;
1662 		    CONTEXT_REGET_SUBSTRUCTURE_PTRS(obj_ptr)
1663 
1664 		    free(full_path);
1665 		}
1666 		else
1667 		{
1668 		    fprintf(
1669 			stderr,
1670  "%s: \"player_model_file\" may not be specified before \"mission_scene_file\".\n",
1671 			filename
1672 		    );
1673 		}
1674 		break;
1675 
1676 	      case SAR_PARM_WEATHER:
1677 		p_weather = (sar_parm_weather_struct *)p;
1678 		if(loaded_scene)
1679 		{
1680 		    fprintf(
1681 			stderr,
1682  "%s: \"weather\" may not be specified after \"mission_scene_file\".\n",
1683 			filename
1684 		    );
1685 		}
1686 		else
1687 		{
1688 		    free(weather_preset_name);
1689 		    weather_preset_name = STRDUP(p_weather->weather_preset_name);
1690 		}
1691 		break;
1692 
1693 	      case SAR_PARM_TIME_OF_DAY:
1694 		p_time_of_day = (sar_parm_time_of_day_struct *)p;
1695 		if(loaded_scene)
1696 		{
1697 		    scene->tod = p_time_of_day->tod;
1698 #if 0
1699 /* The tod_code is updated in SARSimUpdateScene() */
1700 		    scene->tod_code = SAR_TOD_CODE_UNDEFINED;
1701 #endif
1702 		}
1703 		else
1704 		{
1705 		    fprintf(
1706 			stderr,
1707  "%s: \"time_of_day\" may not be specified before \"mission_scene_file\".\n",
1708 			filename
1709 		    );
1710 		}
1711 		break;
1712 
1713 	      case SAR_PARM_TEXTURE_BASE_DIRECTORY:
1714 		p_texture_base_directory = (sar_parm_texture_base_directory_struct *)p;
1715 		break;
1716 
1717 	      case SAR_PARM_TEXTURE_LOAD:
1718 		p_texture_load = (sar_parm_texture_load_struct *)p;
1719 		SARObjLoadTexture(
1720 		    core_ptr, scene, p_texture_load
1721 		);
1722 		break;
1723 
1724 	      case SAR_PARM_MISSION_SCENE_FILE:
1725 		p_mission_scene_file = (sar_parm_mission_scene_file_struct *)p;
1726 		if(loaded_scene)
1727 		{
1728 		    fprintf(
1729 			stderr,
1730 "%s: Warning: Redefination of \"mission_scene_file\" ignored.\n",
1731 			filename
1732 		    );
1733 		}
1734 		else
1735 		{
1736 		    const char *scene_file = p_mission_scene_file->file;
1737 		    char *full_path;
1738 
1739 		    /* Complete path */
1740 		    if(ISPATHABSOLUTE(scene_file))
1741 		    {
1742 			full_path = STRDUP(scene_file);
1743 		    }
1744 		    else
1745 		    {
1746 			struct stat stat_buf;
1747 			full_path = STRDUP(PrefixPaths(
1748 			    dname.local_data, scene_file
1749 			));
1750 			if((full_path != NULL) ? stat(full_path, &stat_buf) : True)
1751 			{
1752 			    free(full_path);
1753 			    full_path = STRDUP(PrefixPaths(
1754 				dname.global_data, scene_file
1755 			    ));
1756 			}
1757 		    }
1758 		    if(full_path == NULL)
1759 			fprintf(
1760 			    stderr,
1761 "%s: Warning: Unable to complete path \"%s\".\n",
1762 			    filename, scene_file
1763 			);
1764 
1765 		    /* Set new scene file on mission structure */
1766 		    free(mission->scene_file);
1767 		    mission->scene_file = STRDUP(full_path);
1768 		    free(full_path);
1769 
1770 		    /* Load scene */
1771 		    status = SARSceneLoadFromFile(
1772 			core_ptr, scene,
1773 			mission->scene_file,
1774 			weather_preset_name,
1775 			client_data, progress_func
1776 		    );
1777 		    if(status)
1778 		    {
1779 			/* Failed to load scene */
1780 			fprintf(
1781 			    stderr,
1782  "%s: Error occured while loading scene \"%s\".\n",
1783 			    filename, mission->scene_file
1784 			);
1785 			SARSceneDestroy(
1786 			    core_ptr, scene,
1787 			    ptr, total
1788 			);
1789 			SARMissionDelete(mission);
1790 			mission = NULL;
1791 
1792 			break;
1793 		    }
1794 		    else
1795 		    {
1796 			loaded_scene = True;
1797 		    }
1798 		}
1799 		break;
1800 
1801 	     case SAR_PARM_MISSION_NEW_OBJECTIVE:
1802 		p_mission_new_objective = (sar_parm_mission_new_objective_struct *)p;
1803 		/* Create a new objective */
1804 		objective_num = mission->total_objectives;
1805 		mission->total_objectives = objective_num + 1;
1806 		mission->objective = (sar_mission_objective_struct *)realloc(
1807 		    mission->objective,
1808 		    mission->total_objectives * sizeof(sar_mission_objective_struct)
1809 		);
1810 		if(mission->objective == NULL)
1811 		{
1812 		    mission->total_objectives = 0;
1813 		    objective_num = -1;
1814 		    objective = NULL;
1815 		}
1816 		else
1817 		{
1818 		    objective = &mission->objective[objective_num];
1819 
1820 		    /* Clear and then set default objective structure values */
1821 		    memset(objective, 0x00, sizeof(sar_mission_objective_struct));
1822 		    objective->type = p_mission_new_objective->objective_type;
1823 		    objective->state = SAR_MISSION_OBJECTIVE_STATE_INCOMPLETE;
1824 		    objective->time_left = 0.0f;
1825 		    objective->humans_need_rescue = 0;
1826 		    objective->total_humans = 0;
1827 		    objective->arrive_at_name = NULL;
1828 		    objective->message_success = NULL;
1829 		    objective->message_fail = NULL;
1830 
1831 		    if(opt->runtime_debug)
1832 			printf(
1833 "SARMissionLoadFromFile(): Creating new mission objective of type %i.\n",
1834 			    p_mission_new_objective->objective_type
1835 			);
1836 		}
1837 		break;
1838 
1839 	      case SAR_PARM_MISSION_TIME_LEFT:
1840 		p_mission_time_left = (sar_parm_mission_time_left_struct *)p;
1841 		if(objective != NULL)
1842 		{
1843 		    objective->time_left = p_mission_time_left->time_left;
1844 		}
1845 		break;
1846 
1847 	      case SAR_PARM_MISSION_BEGIN_AT:
1848 		p_mission_begin_at = (sar_parm_mission_begin_at_struct *)p;
1849 		if(p_mission_begin_at->name != NULL)
1850 		{
1851 		    sar_object_struct *begin_obj_ptr;
1852 
1853 		    /* Update mission begin at name */
1854 		    free(begin_at_name);
1855 		    begin_at_name = STRDUP(p_mission_begin_at->name);
1856 
1857 		    free(mission->start_location_name);
1858 		    mission->start_location_name = STRDUP(p_mission_begin_at->name);
1859 
1860 		    if(!begin_at_set)
1861 		    {
1862 			/* Match the object with the name specified by
1863 			 * begin_at_name.
1864 			 */
1865 			begin_obj_ptr = SARObjMatchPointerByName(
1866 			    scene, *ptr, *total,
1867 			    begin_at_name, NULL
1868 			);
1869 			/* Got match? */
1870 			if(begin_obj_ptr != NULL)
1871 			{
1872 			    /* Record begin at position and direction */
1873 			    memcpy(
1874 				&begin_pos, &begin_obj_ptr->pos,
1875 				sizeof(sar_position_struct)
1876 			    );
1877 /* TODO Need to work on getting begin_dir based on location of matched
1878  * begin_at_name object
1879  */
1880 			    memcpy(
1881 				&begin_dir, &begin_obj_ptr->dir,
1882 				sizeof(sar_direction_struct)
1883 			    );
1884 			}
1885 			else
1886 			{
1887 			    fprintf(
1888 				stderr,
1889 "%s: Warning: \"mission_begin_at\" object name \"%s\" not found.\n",
1890 				filename, begin_at_name
1891 			    );
1892 			}
1893 
1894 			begin_at_set = True;
1895 		    }
1896 		}
1897 		break;
1898 
1899 	      case SAR_PARM_MISSION_BEGIN_AT_POS:
1900 		p_mission_begin_at_pos = (sar_parm_mission_begin_at_pos_struct *)p;
1901 		if(!begin_at_set)
1902 		{
1903 		    /* Record begin at position and direction */
1904 		    memcpy(
1905 			&begin_pos, &p_mission_begin_at_pos->pos,
1906 			sizeof(sar_position_struct)
1907 		    );
1908 		    memcpy(
1909 			&begin_dir, &p_mission_begin_at_pos->dir,
1910 			sizeof(sar_direction_struct)
1911 		    );
1912 		    begin_at_set = True;
1913 		}
1914 		break;
1915 
1916 	      case SAR_PARM_MISSION_ARRIVE_AT:
1917 		p_mission_arrive_at = (sar_parm_mission_arrive_at_struct *)p;
1918 		if(p_mission_arrive_at->name != NULL)
1919 		{
1920 		    sar_object_struct *arrive_obj_ptr;
1921 
1922 		    /* Update arrive_at_name context */
1923 		    free(arrive_at_name);
1924 		    arrive_at_name = STRDUP(p_mission_arrive_at->name);
1925 
1926 		    /* Update arrive_at_name on current objective (if any) */
1927 		    if(objective != NULL)
1928 		    {
1929 			free(objective->arrive_at_name);
1930 			objective->arrive_at_name = STRDUP(p_mission_arrive_at->name);
1931 		    }
1932 
1933 		    /* Match arrive at object (just to verify) */
1934 		    arrive_obj_ptr = SARObjMatchPointerByName(
1935 			scene, *ptr, *total,
1936 			arrive_at_name, NULL
1937 		    );
1938 		    if(arrive_obj_ptr == NULL)
1939 		    {
1940 			fprintf(
1941 			    stderr,
1942 "%s: Warning: \"mission_arrive_at\" object name \"%s\" not found.\n",
1943 			    filename, arrive_at_name
1944 			);
1945 		    }
1946 		}
1947 		break;
1948 
1949 	      case SAR_PARM_MISSION_MESSAGE_SUCCESS:
1950 		p_mission_message_success = (sar_parm_mission_message_success_struct *)p;
1951 		if(p_mission_message_success->message != NULL)
1952 		{
1953 		    /* Update message_success on current objective (if any) */
1954 		    if(objective != NULL)
1955 		    {
1956 			free(objective->message_success);
1957 			objective->message_success = STRDUP(p_mission_message_success->message);
1958 		    }
1959 		}
1960 		break;
1961 
1962 	      case SAR_PARM_MISSION_MESSAGE_FAIL:
1963 		p_mission_message_fail = (sar_parm_mission_message_fail_struct *)p;
1964 		if(p_mission_message_fail->message != NULL)
1965 		{
1966 		    /* Update message_fail on current objective (if any) */
1967 		    if(objective != NULL)
1968 		    {
1969 			free(objective->message_fail);
1970 			objective->message_fail = STRDUP(p_mission_message_fail->message);
1971 		    }
1972 		}
1973 		break;
1974 
1975 	      case SAR_PARM_MISSION_HUMANS_TALLY:
1976 		p_mission_humans_tally = (sar_parm_mission_humans_tally_struct *)p;
1977 		if(objective != NULL)
1978 		{
1979 		    objective->humans_need_rescue =
1980 			p_mission_humans_tally->humans_need_rescue;
1981 		    objective->total_humans =
1982 			p_mission_humans_tally->total_humans;
1983 
1984 		    /* Initial value humans_need_rescue cannot be
1985 		     * greater than total_humans.
1986 		     */
1987 		    if(objective->humans_need_rescue > objective->total_humans)
1988 			objective->humans_need_rescue = objective->total_humans;
1989 		}
1990 		break;
1991 
1992 	      case SAR_PARM_MISSION_ADD_INTERCEPT:
1993 		p_mission_add_intercept = (sar_parm_mission_add_intercept_struct *)p;
1994 		if(obj_ptr != NULL)
1995 		{
1996 		    sar_intercept_struct intercept;
1997 		    sar_object_struct *tar_obj_ptr;
1998 
1999 
2000 		    /* Reset intercept structure */
2001 		    memset(&intercept, 0x00, sizeof(sar_intercept_struct));
2002 
2003 		    /* Handle by intercept reference code */
2004 		    switch(p_mission_add_intercept->ref_code)
2005 		    {
2006 		      case 3:   /* Intercept arrive at location */
2007 			tar_obj_ptr = SARObjMatchPointerByName(
2008 			    scene,
2009 			    *ptr, *total,
2010 			    arrive_at_name, NULL
2011 			);
2012 			if(tar_obj_ptr != NULL)
2013 			{
2014 			    intercept.x = tar_obj_ptr->pos.x;
2015 			    intercept.y = tar_obj_ptr->pos.y;
2016 			    intercept.z = tar_obj_ptr->pos.z;
2017 			    intercept.radius = p_mission_add_intercept->radius;
2018 			    intercept.urgency = p_mission_add_intercept->urgency;
2019 			}
2020 			break;
2021 
2022 		      case 2:   /* Intercept begin at location */
2023 			tar_obj_ptr = SARObjMatchPointerByName(
2024 			    scene,
2025 			    *ptr, *total,
2026 			    begin_at_name, NULL
2027 			);
2028 			if(tar_obj_ptr != NULL)
2029 			{
2030 			    intercept.x = tar_obj_ptr->pos.x;
2031 			    intercept.y = tar_obj_ptr->pos.y;
2032 			    intercept.z = tar_obj_ptr->pos.z;
2033 			    intercept.radius = p_mission_add_intercept->radius;
2034 			    intercept.urgency = p_mission_add_intercept->urgency;
2035 			}
2036 			break;
2037 
2038 		      default:  /* Standard intercept */
2039 			intercept.x = p_mission_add_intercept->pos.x;
2040 			intercept.y = p_mission_add_intercept->pos.y;
2041 			intercept.z = p_mission_add_intercept->pos.z;
2042 			intercept.radius = p_mission_add_intercept->radius;
2043 			intercept.urgency = p_mission_add_intercept->urgency;
2044 			break;
2045 		    }
2046 
2047 		    /* Allocate new intercept structure on object */
2048 		    if(obj_aircraft_ptr != NULL)
2049 		    {
2050 			SARObjInterceptNew(
2051 			    scene,
2052 			    &obj_aircraft_ptr->intercept,
2053 			    &obj_aircraft_ptr->total_intercepts,
2054 			    intercept.flags,
2055 			    intercept.x, intercept.y, intercept.z,
2056 			    intercept.radius, intercept.urgency,
2057 			    intercept.name
2058 			);
2059 		    }
2060 		}
2061 		break;
2062 
2063 	      case SAR_PARM_NEW_OBJECT:
2064 		p_new_object = (sar_parm_new_object_struct *)p;
2065 		/* Create new object of the specified type */
2066 		obj_num = SARObjNew(
2067 		    scene, ptr, total,
2068 		    p_new_object->object_type
2069 		);
2070 		/* Update object context pointers */
2071 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
2072 		CONTEXT_REGET_SUBSTRUCTURE_PTRS(obj_ptr)
2073 		break;
2074 
2075 	      case SAR_PARM_NEW_HELIPAD:
2076 		p_new_helipad = (sar_parm_new_helipad_struct *)p;
2077 		/* Create new helipad */
2078 		obj_num = SARObjLoadHelipad(
2079 		    core_ptr, scene, p_new_helipad
2080 		);
2081 		/* Update object context pointers */
2082 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
2083 		CONTEXT_REGET_SUBSTRUCTURE_PTRS(obj_ptr)
2084 		break;
2085 
2086 	      case SAR_PARM_NEW_RUNWAY:
2087 		p_new_runway = (sar_parm_new_runway_struct *)p;
2088 		/* Create new runway */
2089 		obj_num = SARObjLoadRunway(
2090 		    core_ptr, scene, p_new_runway
2091 		);
2092 		/* Update object context pointers */
2093 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
2094 		CONTEXT_REGET_SUBSTRUCTURE_PTRS(obj_ptr)
2095 		break;
2096 
2097 	      case SAR_PARM_NEW_HUMAN:
2098 		p_new_human = (sar_parm_new_human_struct *)p;
2099 		/* Create new human */
2100 		obj_num = SARObjLoadHuman(
2101 		    core_ptr, scene, p_new_human
2102 		);
2103 		/* Update object context pointers */
2104 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
2105 		CONTEXT_REGET_SUBSTRUCTURE_PTRS(obj_ptr)
2106 		if((obj_ptr != NULL) && (obj_human_ptr != NULL))
2107 		{
2108 		    /* Increment number of humans that need rescue that
2109 		     * this mission file has specified.
2110 		     */
2111 		    if(obj_human_ptr->flags & SAR_HUMAN_FLAG_NEED_RESCUE)
2112 			humans_need_rescue++;
2113 		}
2114 		break;
2115 
2116 	      case SAR_PARM_NEW_FIRE:
2117 		p_new_fire = (sar_parm_new_fire_struct *)p;
2118 		/* Create new fire object */
2119 		obj_num = SARObjLoadFire(
2120 		    core_ptr, scene, p_new_fire
2121 		);
2122 		/* Update object context pointers */
2123 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
2124 		CONTEXT_REGET_SUBSTRUCTURE_PTRS(obj_ptr)
2125 		break;
2126 
2127 	      case SAR_PARM_NEW_SMOKE:
2128 		p_new_smoke = (sar_parm_new_smoke_struct *)p;
2129 		/* Create new smoke trails object */
2130 		obj_num = SARObjLoadSmoke(
2131 		    core_ptr, scene, p_new_smoke
2132 		);
2133 		/* Update object context pointers */
2134 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
2135 		CONTEXT_REGET_SUBSTRUCTURE_PTRS(obj_ptr)
2136 		break;
2137 
2138 	      case SAR_PARM_NEW_PREMODELED:
2139 		p_new_premodeled = (sar_parm_new_premodeled_struct *)p;
2140 		/* Create new premodeled object */
2141 		obj_num = SARObjPremodeledNew(
2142 		    core_ptr, scene,
2143 		    p_new_premodeled->model_type,
2144 		    p_new_premodeled->argc,
2145 		    p_new_premodeled->argv
2146 		);
2147 		/* Reget object context pointers */
2148 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
2149 		CONTEXT_REGET_SUBSTRUCTURE_PTRS(obj_ptr)
2150 		break;
2151 
2152 	      case SAR_PARM_MODEL_FILE:
2153 		p_model_file = (sar_parm_model_file_struct *)p;
2154 		if((p_model_file->file != NULL) && (obj_ptr != NULL))
2155 		    SARObjLoadFromFile(core_ptr, obj_num, p_model_file->file);
2156 		break;
2157 
2158 #if 0
2159 	      case SAR_PARM_SELECT_OBJECT_BY_NAME:
2160 		p_select_object_by_name = (sar_parm_select_object_by_name_struct *)p;
2161 		if(p_select_object_by_name->name != NULL)
2162 		{
2163 		    obj_ptr = SARObjMatchPointerByName(
2164 			scene,
2165 			core_ptr->object, core_ptr->total_objects,
2166 			p_select_object_by_name->name, &obj_num
2167 		    );
2168 		}
2169 		break;
2170 #endif
2171 	      case SAR_PARM_TRANSLATE:
2172 		p_translate = (sar_parm_translate_struct *)p;
2173 	        SARObjLoadTranslate(
2174 		    core_ptr, scene,
2175 		    obj_ptr, p_translate
2176 		);
2177 		break;
2178 
2179 	      case SAR_PARM_TRANSLATE_RANDOM:
2180 		p_translate_random = (sar_parm_translate_random_struct *)p;
2181 		SARObjLoadTranslateRandom(
2182 		    core_ptr, scene,
2183 		    obj_ptr, p_translate_random
2184 		);
2185 		break;
2186 
2187 	      case SAR_PARM_ROTATE:
2188 		p_rotate = (sar_parm_rotate_struct *)p;
2189 		if(obj_ptr != NULL)
2190 		    SARSimWarpObject(
2191 			scene, obj_ptr,
2192 			NULL, &p_rotate->rotate
2193 		    );
2194 		break;
2195 
2196 	      case SAR_PARM_NO_DEPTH_TEST:
2197 		p_no_depth_test = (sar_parm_no_depth_test_struct *)p;
2198 		if(obj_ptr != NULL)
2199 		{
2200 		    obj_ptr->flags |= SAR_OBJ_FLAG_NO_DEPTH_TEST;
2201 		}
2202 		break;
2203 
2204 	      case SAR_PARM_POLYGON_OFFSET:
2205 		p_polygon_offset = (sar_parm_polygon_offset_struct *)p;
2206 		if(obj_ptr != NULL)
2207 		{
2208 		    obj_ptr->flags |= p_polygon_offset->flags;
2209 		}
2210 		break;
2211 
2212 	      case SAR_PARM_OBJECT_NAME:
2213 		p_object_name = (sar_parm_object_name_struct *)p;
2214 		if(obj_ptr != NULL)
2215 		{
2216 		    free(obj_ptr->name);
2217 		    obj_ptr->name = STRDUP(p_object_name->name);
2218 		}
2219 		break;
2220 
2221 	      case SAR_PARM_RUNWAY_APPROACH_LIGHTING_NORTH:
2222 		p_runway_applight_n =
2223 		    (sar_parm_runway_approach_lighting_north_struct *)p;
2224 		if((obj_ptr != NULL) && (obj_runway_ptr != NULL))
2225 		{
2226 		    obj_runway_ptr->north_approach_lighting_flags =
2227 			p_runway_applight_n->flags;
2228 		}
2229 		break;
2230 
2231 	      case SAR_PARM_RUNWAY_APPROACH_LIGHTING_SOUTH:
2232 		p_runway_applight_s =
2233 		    (sar_parm_runway_approach_lighting_south_struct *)p;
2234 		if((obj_ptr != NULL) && (obj_runway_ptr != NULL))
2235 		{
2236 		    obj_runway_ptr->south_approach_lighting_flags =
2237 			p_runway_applight_s->flags;
2238 		}
2239 		break;
2240 
2241 	      case SAR_PARM_HUMAN_MESSAGE_ENTER:
2242 		p_human_message_enter = (sar_parm_human_message_enter_struct *)p;
2243 		if((obj_ptr != NULL) && (obj_human_ptr != NULL))
2244 		{
2245 		    free(obj_human_ptr->mesg_enter);
2246 		    obj_human_ptr->mesg_enter = STRDUP(
2247 			p_human_message_enter->message
2248 		    );
2249 		}
2250 		break;
2251 
2252 	      case SAR_PARM_HUMAN_REFERENCE:
2253 		p_human_reference = (sar_parm_human_reference_struct *)p;
2254 		if((obj_ptr != NULL) && (obj_human_ptr != NULL) &&
2255 		   (p_human_reference->reference_name != NULL)
2256 		)
2257 		{
2258 		    int human_ref_obj_num = -1;
2259 		    const char *ref_name = p_human_reference->reference_name;
2260 
2261 		    /* Run towards? */
2262 		    if(p_human_reference->flags & SAR_HUMAN_FLAG_RUN_TOWARDS)
2263 		    {
2264 			obj_human_ptr->flags |= SAR_HUMAN_FLAG_RUN_TOWARDS;
2265 		    }
2266 		    /* Run away? */
2267 		    else if(p_human_reference->flags & SAR_HUMAN_FLAG_RUN_AWAY)
2268 		    {
2269 			obj_human_ptr->flags |= SAR_HUMAN_FLAG_RUN_AWAY;
2270 		    }
2271 
2272 		    /* Handle reference object name */
2273 		    if(!strcasecmp(ref_name, "player"))
2274 		    {
2275 			/* Set special intercept code to intercept the player */
2276 			obj_human_ptr->intercepting_object = -2;
2277 		    }
2278 		    else
2279 		    {
2280 			/* All else match by object name */
2281 			SARObjMatchPointerByName(
2282 			    scene, *ptr, *total,
2283 			    ref_name, &human_ref_obj_num
2284 			);
2285 			obj_human_ptr->intercepting_object = human_ref_obj_num;
2286 		    }
2287 		}
2288 		break;
2289 
2290 	      default:
2291 		break;
2292 
2293 	    }	/* Handle by parm type */
2294 
2295 
2296 	    /* If we lost the mission structure then we need to
2297 	     * give up, there was probably some fatal error
2298 	     * encountered above
2299 	     */
2300 	    if(mission == NULL)
2301 		break;
2302 
2303 	}	/* Iterate through loaded parms */
2304 
2305 
2306 	/* Delete loaded parms */
2307 	SARParmDeleteAll(&parm, &total_parms);
2308 
2309 	if(opt->runtime_debug)
2310 	    printf(
2311 "SARMissionLoadFromFile():\
2312  Loaded new mission with %i objectives.\n",
2313 		mission->total_objectives
2314 	    );
2315 
2316 	free(begin_at_name);
2317 	free(arrive_at_name);
2318 	free(weather_preset_name);
2319 
2320 #undef CONTEXT_REGET_SUBSTRUCTURE_PTRS
2321 
2322 	return(mission);
2323 }
2324 
2325 /*
2326  *	Resets the mission log file specified by filename and rewrites
2327  *	its header with the information given by the mission structure.
2328  *
2329  *	This will overwrite the previous log file (if any) specified
2330  *	by filename.
2331  */
SARMissionLogReset(sar_core_struct * core_ptr,sar_mission_struct * mission,const char * filename)2332 void SARMissionLogReset(
2333 	sar_core_struct *core_ptr, sar_mission_struct *mission,
2334 	const char *filename            /* Mission log file name */
2335 )
2336 {
2337 	void *p, **parm = NULL;
2338 	int total_parms = 0;
2339 
2340 	if((mission == NULL) || STRISEMPTY(filename))
2341 	    return;
2342 
2343 	/* Begin generating parameters for writing mission log */
2344 	p = SARParmNewAppend(
2345 	    SAR_PARM_MISSION_LOG_HEADER,
2346 	    &parm, &total_parms
2347 	);
2348 	if(p != NULL)
2349 	{
2350 	    sar_parm_mission_log_header_struct *pv =
2351 		(sar_parm_mission_log_header_struct *)p;
2352 	    pv->version_major = PROG_VERSION_MAJOR;
2353 	    pv->version_minor = PROG_VERSION_MINOR;
2354 	    pv->version_release = PROG_VERSION_RELEASE;
2355 	    free(pv->title);
2356 	    pv->title = STRDUP(mission->title);
2357 	    free(pv->scene_file);
2358 	    pv->scene_file = STRDUP(mission->scene_file);
2359 	    free(pv->player_stats_file);
2360 	    pv->player_stats_file = STRDUP(mission->player_stats_file);
2361 	}
2362 
2363 	/* Write mission log file, this will overwrite the existing
2364 	 * mission log file (if any).
2365 	 */
2366 	SARParmSaveToFile(
2367 	    filename, SAR_FILE_FORMAT_MISSION_LOG,
2368 	    parm, total_parms,
2369 	    NULL, NULL
2370 	);
2371 
2372 	/* Delete loaded parms */
2373 	SARParmDeleteAll(&parm, &total_parms);
2374 }
2375 
2376 /*
2377  *	Appends a log entry to the given log file, the log file will be
2378  *	opened for writing (append) and then closed during this call.
2379  *
2380  *	The event_type must be given and cannot be -1.
2381  *
2382  *	The tod (time of day) can be either a valid time or -1.0 to indicate
2383  *	use current time on core's scene structure.
2384  *
2385  *	The given file name must reffer to valid file which is writeable.
2386  *
2387  *	All other inputs are optional.
2388  */
SARMissionLogEvent(sar_core_struct * core_ptr,sar_mission_struct * mission,int event_type,float tod,sar_position_struct * pos,const float * value,int total_values,const char * message,const char * filename)2389 void SARMissionLogEvent(
2390 	sar_core_struct *core_ptr, sar_mission_struct *mission,
2391 	int event_type,                 /* One of SAR_LOG_EVENT_* */
2392 	float tod,			/* Time of day in seconds since midnight */
2393 	sar_position_struct *pos,       /* Position of event */
2394 	const float *value,		/* Additional values */
2395 	int total_values,               /* Total number of additional values */
2396 	const char *message,		/* The message */
2397 	const char *filename            /* Mission log file name */
2398 )
2399 {
2400 	int i;
2401 	FILE *fp;
2402 	sar_scene_struct *scene = core_ptr->scene;
2403 	if((scene == NULL) || (mission == NULL) ||
2404 	   STRISEMPTY(filename)
2405 	)
2406 	    return;
2407 
2408 	/* Open mission log file for append writing */
2409 	fp = FOpen(filename, "ab");
2410 	if(fp == NULL)
2411 	    return;
2412 
2413 	/* Write event type, time and coordinates */
2414 	fprintf(
2415 	    fp,
2416 	    "%i %f %f %f %f%s",
2417 	    event_type,
2418 	    (tod < 0.0f) ? scene->tod : tod,
2419 	    (pos != NULL) ? pos->x : 0.0f,
2420 	    (pos != NULL) ? pos->y : 0.0f,
2421 	    (pos != NULL) ? pos->z : 0.0f,
2422 	    (total_values > 0) ? " " : ""
2423 	);
2424 
2425 	/* Write any additional arguments */
2426 	for(i = 0; i < total_values; i++)
2427 	    fprintf(
2428 		fp,
2429 		"%f%s",
2430 		value[i],
2431 		(i < (total_values - 1)) ? " " : ""
2432 	    );
2433 
2434 	/* Write values and message deliminator character */
2435 	fputc(':', fp);
2436 
2437 	/* Write message? */
2438 	if(message != NULL)
2439 	    fputs(message, fp);
2440 
2441 	/* End this log event line with a newline character */
2442 	fputc('\n', fp);
2443 
2444 	/* Close mission log file */
2445 	FClose(fp);
2446 }
2447