1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 
7 #include "../include/cfgfmt.h"
8 #include "../include/string.h"
9 #include "../include/strexp.h"
10 #include "../include/fio.h"
11 #include "../include/disk.h"
12 
13 #include "obj.h"
14 #include "mission.h"
15 #include "sartime.h"
16 #include "sarfio.h"
17 #include "config.h"
18 
19 static int SARParmSaveToFileAnyIterate(
20 	const char *filename, FILE *fp, const void *p
21 );
22 static int SARParmSaveToFileAny(
23         const char *filename, FILE *fp,
24         void **parm, int total_parms,
25         void *client_data,
26         int (*progress_func)(void *, long, long)
27 );
28 int SARParmSaveToFile(
29         const char *filename, int file_format,
30         void **parm, int total_parms,
31         void *client_data,
32         int (*progress_func)(void *, long, long)
33 );
34 
35 
36 #ifndef SAR_COMMENT_CHAR
37 # define SAR_COMMENT_CHAR       '#'
38 #endif
39 
40 #define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
41 #define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
42 #define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
43 #define STRDUP(s)       (((s) != NULL) ? strdup(s) : NULL)
44 
45 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
46 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
47 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
48 
49 #define ISCOMMENT(c)    ((c) == SAR_COMMENT_CHAR)
50 #define ISCR(c)         (((c) == '\n') || ((c) == '\r'))
51 
52 #define DEGTORAD(d)     ((d) * PI / 180)
53 #define RADTODEG(r)     ((r) * 180 / PI)
54 
55 
56 /*
57  *	Saves the given parameter to file.
58  *
59  *	Returns the number of parameters saved.
60  */
SARParmSaveToFileAnyIterate(const char * filename,FILE * fp,const void * p)61 static int SARParmSaveToFileAnyIterate(
62         const char *filename, FILE *fp, const void *p
63 )
64 {
65 	int parms_saved = 0;
66 	int type = *(int *)p;
67 
68 	/* Version. */
69 	if(type == SAR_PARM_VERSION)
70 	{
71 #define PARM_TYPE	const sar_parm_version_struct
72 	    PARM_TYPE *pv = (PARM_TYPE *)p;
73 	    fprintf(
74 		fp,
75 		"version %i %i %i%s%s\n",
76 		pv->major, pv->minor, pv->release,
77 		(pv->copyright != NULL) ? " " : "",
78 		(pv->copyright != NULL) ? pv->copyright : ""
79 	    );
80 	    parms_saved++;
81 #undef PARM_TYPE
82 	}
83 	/* Name. */
84 	else if(type == SAR_PARM_NAME)
85 	{
86 #define PARM_TYPE	const sar_parm_name_struct
87 	    PARM_TYPE *pv = (PARM_TYPE *)p;
88 	    if(pv->name != NULL)
89 	    {
90 		fprintf(
91 		    fp,
92 		    "name %s\n",
93 		    pv->name
94 		);
95 		parms_saved++;
96 	    }
97 #undef PARM_TYPE
98 	}
99         /* Description. */
100         else if(type == SAR_PARM_DESCRIPTION)
101         {
102 #define PARM_TYPE	const sar_parm_description_struct
103             PARM_TYPE *pv = (PARM_TYPE *)p;
104             if(pv->description != NULL)
105             {
106                 fprintf(
107                     fp,
108                     "description %s\n",
109                     pv->description
110                 );
111                 parms_saved++;
112             }
113 #undef PARM_TYPE
114         }
115         /* Player model file. */
116         else if(type == SAR_PARM_PLAYER_MODEL_FILE)
117         {
118 #define PARM_TYPE       const sar_parm_player_model_file_struct
119             PARM_TYPE *pv = (PARM_TYPE *)p;
120             if(pv->file != NULL)
121             {
122                 fprintf(
123                     fp,
124                     "player_model_file %s\n",
125                     pv->file
126                 );
127                 parms_saved++;
128             }
129 #undef PARM_TYPE
130         }
131         /* Weather. */
132         else if(type == SAR_PARM_WEATHER)
133         {
134 #define PARM_TYPE       const sar_parm_weather_struct
135             PARM_TYPE *pv = (PARM_TYPE *)p;
136             if(pv->weather_preset_name != NULL)
137             {
138                 fprintf(
139                     fp,
140                     "weather %s\n",
141                     pv->weather_preset_name
142                 );
143                 parms_saved++;
144             }
145 #undef PARM_TYPE
146         }
147         /* Time of day. */
148         else if(type == SAR_PARM_TIME_OF_DAY)
149         {
150 #define PARM_TYPE	const sar_parm_time_of_day_struct
151             PARM_TYPE *pv = (PARM_TYPE *)p;
152             fprintf(
153                 fp,
154                 "time_of_day %f\n",
155                 pv->tod
156             );
157             parms_saved++;
158 #undef PARM_TYPE
159         }
160         /* Registered location. */
161         else if(type == SAR_PARM_REGISTER_LOCATION)
162         {
163 #define PARM_TYPE	const sar_parm_register_location_struct
164             PARM_TYPE *pv = (PARM_TYPE *)p;
165             fprintf(
166                 fp,
167                 "register_location %f %f %f %f %f %f%s%s\n",
168                 pv->pos.x, pv->pos.y, SFMMetersToFeet(pv->pos.z),
169 		RADTODEG(pv->dir.heading),
170                 RADTODEG(pv->dir.pitch),
171                 RADTODEG(pv->dir.bank),
172 		(pv->name != NULL) ? " " : "",
173 		(pv->name != NULL) ? pv->name : ""
174 	    );
175             parms_saved++;
176 #undef PARM_TYPE
177         }
178         /* Scene GPS. */
179         else if(type == SAR_PARM_SCENE_GPS)
180         {
181 #define PARM_TYPE       const sar_parm_scene_gps_struct
182             PARM_TYPE *pv = (PARM_TYPE *)p;
183             fprintf(
184                 fp,
185                 "scene_gps %f %f %f\n",
186 		pv->dms_x_offset, pv->dms_y_offset,
187 		pv->planet_radius
188             );
189             parms_saved++;
190 #undef PARM_TYPE
191         }
192         /* Scene map. */
193         else if(type == SAR_PARM_SCENE_MAP)
194         {
195 #define PARM_TYPE       const sar_parm_scene_map_struct
196             PARM_TYPE *pv = (PARM_TYPE *)p;
197             fprintf(
198                 fp,
199                 "scene_map %f %f%s%s\n",
200                 pv->width, pv->height,
201                 (pv->file != NULL) ? " " : "",
202                 (pv->file != NULL) ? pv->file : ""
203             );
204             parms_saved++;
205 #undef PARM_TYPE
206         }
207         /* Scene elevation. */
208         else if(type == SAR_PARM_SCENE_ELEVATION)
209         {
210 #define PARM_TYPE       const sar_parm_scene_elevation_struct
211             PARM_TYPE *pv = (PARM_TYPE *)p;
212             fprintf(
213                 fp,
214                 "scene_elevation %f\n",
215                 SFMMetersToFeet(pv->elevation)
216             );
217             parms_saved++;
218 #undef PARM_TYPE
219         }
220         /* Scene CANT. */
221         else if(type == SAR_PARM_SCENE_CANT)
222         {
223 #define PARM_TYPE       const sar_parm_scene_cant_struct
224             PARM_TYPE *pv = (PARM_TYPE *)p;
225             fprintf(
226                 fp,
227                 "scene_cant %f\n",
228                 RADTODEG(pv->cant)
229             );
230             parms_saved++;
231 #undef PARM_TYPE
232         }
233         /* Scene ground flags. */
234         else if(type == SAR_PARM_SCENE_GROUND_FLAGS)
235         {
236 #define PARM_TYPE       const sar_parm_scene_ground_flags_struct
237             PARM_TYPE *pv = (PARM_TYPE *)p;
238             fprintf(fp, "scene_ground_flags");
239 	    if(pv->flags & SAR_SCENE_BASE_FLAG_IS_WATER)
240 		fprintf(fp, " is_water");
241 	    fputc('\n', fp);
242             parms_saved++;
243 #undef PARM_TYPE
244         }
245         /* Scene ground tile. */
246         else if(type == SAR_PARM_SCENE_GROUND_TILE)
247         {
248 #define PARM_TYPE       const sar_parm_scene_ground_tile_struct
249             PARM_TYPE *pv = (PARM_TYPE *)p;
250             fprintf(
251                 fp,
252                 "scene_ground_tile %i %i %f %.2f %.2f %.2f %.2f%s%s\n",
253                 pv->tile_width, pv->tile_height, pv->close_range,
254 		pv->color.r, pv->color.g, pv->color.b, pv->color.a,
255 		(pv->texture_name != NULL) ? " " : "",
256 		(pv->texture_name != NULL) ? pv->texture_name : ""
257 	    );
258             parms_saved++;
259 #undef PARM_TYPE
260         }
261         /* Texture base directory. */
262         else if(type == SAR_PARM_TEXTURE_BASE_DIRECTORY)
263         {
264 #define PARM_TYPE       const sar_parm_texture_base_directory_struct
265             PARM_TYPE *pv = (PARM_TYPE *)p;
266             fprintf(
267                 fp,
268                 "texture_base_directory%s%s\n",
269                 (pv->directory != NULL) ? " " : "",
270                 (pv->directory != NULL) ? pv->directory : ""
271             );
272             parms_saved++;
273 #undef PARM_TYPE
274         }
275         /* Texture load. */
276         else if(type == SAR_PARM_TEXTURE_LOAD)
277         {
278 #define PARM_TYPE       const sar_parm_texture_load_struct
279             PARM_TYPE *pv = (PARM_TYPE *)p;
280             fprintf(
281                 fp,
282                 "texture_load %s %s %f\n",
283                 pv->name, pv->file, pv->priority
284             );
285             parms_saved++;
286 #undef PARM_TYPE
287         }
288         /* Mission scene file. */
289         else if(type == SAR_PARM_MISSION_SCENE_FILE)
290         {
291 #define PARM_TYPE       const sar_parm_mission_scene_file_struct
292             PARM_TYPE *pv = (PARM_TYPE *)p;
293             fprintf(
294                 fp,
295                 "mission_scene_file%s%s\n",
296                 (pv->file != NULL) ? " " : "",
297                 (pv->file != NULL) ? pv->file : ""
298             );
299             parms_saved++;
300 #undef PARM_TYPE
301         }
302         /* Mission new objective. */
303         else if(type == SAR_PARM_MISSION_NEW_OBJECTIVE)
304         {
305 #define PARM_TYPE       const sar_parm_mission_new_objective_struct
306             PARM_TYPE *pv = (PARM_TYPE *)p;
307 	    fprintf(fp, "mission_objective_new");
308 	    switch(pv->objective_type)
309 	    {
310 	      case SAR_MISSION_OBJECTIVE_ARRIVE_AT:
311 		fprintf(fp, " arrive");
312 		break;
313               case SAR_MISSION_OBJECTIVE_PICK_UP_ARRIVE_AT:
314                 fprintf(fp, " pick_up_arrive");
315                 break;
316               case SAR_MISSION_OBJECTIVE_PICK_UP:
317                 fprintf(fp, " pick_up");
318                 break;
319 	    }
320 	    fputc('\n', fp);
321             parms_saved++;
322 #undef PARM_TYPE
323         }
324         /* Mission time left. */
325         else if(type == SAR_PARM_MISSION_TIME_LEFT)
326         {
327 #define PARM_TYPE	const sar_parm_mission_time_left_struct
328             PARM_TYPE *pv = (PARM_TYPE *)p;
329             fprintf(
330                 fp,
331                 "mission_objective_time_left %f\n",
332 		pv->time_left
333             );
334             parms_saved++;
335 #undef PARM_TYPE
336         }
337         /* Mission begin at. */
338         else if(type == SAR_PARM_MISSION_BEGIN_AT)
339         {
340 #define PARM_TYPE       const sar_parm_mission_begin_at_struct
341             PARM_TYPE *pv = (PARM_TYPE *)p;
342             fprintf(
343                 fp,
344                 "mission_begin_at%s%s\n",
345                 (pv->name != NULL) ? " " : "",
346                 (pv->name != NULL) ? pv->name : ""
347             );
348             parms_saved++;
349 #undef PARM_TYPE
350         }
351         /* Mission begin at position. */
352         else if(type == SAR_PARM_MISSION_BEGIN_AT_POS)
353         {
354 #define PARM_TYPE       const sar_parm_mission_begin_at_pos_struct
355             PARM_TYPE *pv = (PARM_TYPE *)p;
356             fprintf(
357                 fp,
358                 "mission_begin_at_pos %f %f %f %f %f %f\n",
359 		pv->pos.x, pv->pos.y, SFMMetersToFeet(pv->pos.z),
360 		RADTODEG(pv->dir.heading),
361                 RADTODEG(pv->dir.pitch),
362                 RADTODEG(pv->dir.bank)
363             );
364             parms_saved++;
365 #undef PARM_TYPE
366         }
367         /* Mission arrive at. */
368         else if(type == SAR_PARM_MISSION_ARRIVE_AT)
369         {
370 #define PARM_TYPE	const sar_parm_mission_arrive_at_struct
371             PARM_TYPE *pv = (PARM_TYPE *)p;
372             fprintf(
373                 fp,
374                 "mission_objective_arrive_at%s%s\n",
375                 (pv->name != NULL) ? " " : "",
376                 (pv->name != NULL) ? pv->name : ""
377             );
378             parms_saved++;
379 #undef PARM_TYPE
380         }
381         /* Mission message success. */
382         else if(type == SAR_PARM_MISSION_MESSAGE_SUCCESS)
383         {
384 #define PARM_TYPE	const sar_parm_mission_message_success_struct
385             PARM_TYPE *pv = (PARM_TYPE *)p;
386             fprintf(
387                 fp,
388                 "mission_objective_message_success%s%s\n",
389                 (pv->message != NULL) ? " " : "",
390                 (pv->message != NULL) ? pv->message : ""
391             );
392             parms_saved++;
393 #undef PARM_TYPE
394         }
395         /* Mission message fail. */
396         else if(type == SAR_PARM_MISSION_MESSAGE_FAIL)
397         {
398 #define PARM_TYPE	const sar_parm_mission_message_fail_struct
399             PARM_TYPE *pv = (PARM_TYPE *)p;
400             fprintf(
401                 fp,
402                 "mission_objective_message_fail%s%s\n",
403                 (pv->message != NULL) ? " " : "",
404                 (pv->message != NULL) ? pv->message : ""
405             );
406             parms_saved++;
407 #undef PARM_TYPE
408         }
409         /* Mission humans tally. */
410         else if(type == SAR_PARM_MISSION_HUMANS_TALLY)
411         {
412 #define PARM_TYPE	const sar_parm_mission_humans_tally_struct
413             PARM_TYPE *pv = (PARM_TYPE *)p;
414             fprintf(
415                 fp,
416                 "mission_objective_humans_tally %i %i\n",
417                 pv->humans_need_rescue, pv->total_humans
418             );
419             parms_saved++;
420 #undef PARM_TYPE
421         }
422         /* Mission add intercept. */
423         else if(type == SAR_PARM_MISSION_ADD_INTERCEPT)
424         {
425 #define PARM_TYPE	const sar_parm_mission_add_intercept_struct
426             PARM_TYPE *pv = (PARM_TYPE *)p;
427 	    switch(pv->ref_code)
428 	    {
429 	      case 3: case 2:	/* Arrive or begin at location. */
430                 fprintf(
431                     fp,
432                     "mission_add_intercept %i %f %f\n",
433 		    pv->ref_code,
434 		    pv->radius, pv->urgency
435                 );
436                 parms_saved++;
437 		break;
438 	      default:		/* Standard intercept way point. */
439                 fprintf(
440                     fp,
441                     "mission_add_intercept %i %f %f %f %f %f\n",
442                     pv->ref_code,
443 		    pv->pos.x,
444 		    pv->pos.y,
445 		    pv->pos.z,		/* In meters. */
446                     pv->radius, pv->urgency
447                 );
448                 parms_saved++;
449                 break;
450 	    }
451 #undef PARM_TYPE
452         }
453         /* Mission log header. */
454         else if(type == SAR_PARM_MISSION_LOG_HEADER)
455         {
456 #define PARM_TYPE	const sar_parm_mission_log_header_struct
457             PARM_TYPE *pv = (PARM_TYPE *)p;
458             fprintf(fp, "BeginHeader\n");
459 	    fprintf(fp, "    Version %i %i %i\n",
460 		pv->version_major, pv->version_minor, pv->version_release
461 	    );
462             if(pv->title != NULL)
463                 fprintf(fp, "    Title %s\n", pv->title);
464 	    if(pv->scene_file != NULL)
465 		fprintf(fp, "    SceneFile %s\n", pv->scene_file);
466 	    if(pv->player_stats_file != NULL)
467 		fprintf(fp, "    PlayerStatsFile %s\n", pv->player_stats_file);
468             fprintf(fp, "EndHeader\n");
469             parms_saved++;
470 #undef PARM_TYPE
471         }
472         /* Mission log event. */
473         else if(type == SAR_PARM_MISSION_LOG_EVENT)
474         {
475 #define PARM_TYPE	const sar_parm_mission_log_event_struct
476             PARM_TYPE *pv = (PARM_TYPE *)p;
477             fprintf(
478                 fp,
479                 "%i %f %f %f %f%c%s\n",
480 		pv->event_type,
481 		pv->tod,
482 		pv->pos.x,
483 		pv->pos.y,
484 		pv->pos.z,		/* In meters. */
485 		(pv->message != NULL) ? ':' : '\0',
486 		(pv->message != NULL) ? pv->message : ""
487             );
488             parms_saved++;
489 #undef PARM_TYPE
490         }
491         /* New object. */
492         else if(type == SAR_PARM_NEW_OBJECT)
493         {
494 #define PARM_TYPE	const sar_parm_new_object_struct
495             PARM_TYPE *pv = (PARM_TYPE *)p;
496             fprintf(
497                 fp,
498                 "new_object %i\n",
499 		pv->object_type
500 	    );
501             parms_saved++;
502 #undef PARM_TYPE
503         }
504         /* New helipad. */
505         else if(type == SAR_PARM_NEW_HELIPAD)
506         {
507 #define PARM_TYPE	const sar_parm_new_helipad_struct
508             PARM_TYPE *pv = (PARM_TYPE *)p;
509 	    if(pv->ref_obj_name != NULL)
510                fprintf(
511                     fp,
512 "new_helipad %s %f %f %f %s %c %c %c %c %c %s %f %f %f %f %f %f\n",
513                     pv->style,
514                     pv->length, pv->width,
515                     SFMMetersToFeet(pv->recession),
516                     (pv->label != NULL) ? pv->label : "_",
517 		(pv->flags & SAR_HELIPAD_FLAG_EDGE_LIGHTING) ? 'y' : 'n',
518 		(pv->flags & SAR_HELIPAD_FLAG_FUEL) ? 'y' : 'n',
519 		(pv->flags & SAR_HELIPAD_FLAG_REPAIR) ? 'y' : 'n',
520 		(pv->flags & SAR_HELIPAD_FLAG_DROPOFF) ? 'y' : 'n',
521 		(pv->flags & SAR_HELIPAD_FLAG_RESTART_POINT) ? 'y' : 'n',
522 		    pv->ref_obj_name,
523 		    pv->ref_offset.x, pv->ref_offset.y,
524 		    SFMMetersToFeet(pv->ref_offset.z),
525 		    RADTODEG(pv->ref_dir.heading),
526                     RADTODEG(pv->ref_dir.pitch),
527                     RADTODEG(pv->ref_dir.bank)
528                 );
529 	    else
530 		fprintf(
531 		    fp,
532 "new_helipad %s %f %f %f %s %c %c %c %c %c\n",
533 		    pv->style,
534 		    pv->length, pv->width,
535 		    SFMMetersToFeet(pv->recession),
536 		    (pv->label != NULL) ? pv->label : "_",
537 		(pv->flags & SAR_HELIPAD_FLAG_EDGE_LIGHTING) ? 'y' : 'n',
538 		(pv->flags & SAR_HELIPAD_FLAG_FUEL) ? 'y' : 'n',
539 		(pv->flags & SAR_HELIPAD_FLAG_REPAIR) ? 'y' : 'n',
540 		(pv->flags & SAR_HELIPAD_FLAG_DROPOFF) ? 'y' : 'n',
541                 (pv->flags & SAR_HELIPAD_FLAG_RESTART_POINT) ? 'y' : 'n'
542 		);
543             parms_saved++;
544 #undef PARM_TYPE
545         }
546         /* New runway. */
547         else if(type == SAR_PARM_NEW_RUNWAY)
548         {
549 #define PARM_TYPE	const sar_parm_new_runway_struct
550             PARM_TYPE *pv = (PARM_TYPE *)p;
551 	    fprintf(
552 		fp,
553 		"new_runway %f %f %f %i %i %f %s %s %f %f",
554 		pv->range, pv->length, pv->width, pv->surface_type,
555 		pv->dashes, pv->edge_light_spacing,
556 		(pv->north_label != NULL) ? pv->north_label : "_",
557 		(pv->south_label != NULL) ? pv->south_label : "_",
558 		pv->north_displaced_threshold,
559 		pv->south_displaced_threshold
560 	    );
561             if(pv->flags & SAR_RUNWAY_FLAG_THRESHOLDS)
562                 fprintf(fp, " thresholds");
563             if(pv->flags & SAR_RUNWAY_FLAG_BORDERS)
564                 fprintf(fp, " borders");
565             if(pv->flags & SAR_RUNWAY_FLAG_TD_MARKERS)
566                 fprintf(fp, " td_markers");
567             if(pv->flags & SAR_RUNWAY_FLAG_MIDWAY_MARKERS)
568                 fprintf(fp, " midway_markers");
569             if(pv->flags & SAR_RUNWAY_FLAG_NORTH_GS)
570                 fprintf(fp, " north_gs");
571             if(pv->flags & SAR_RUNWAY_FLAG_SOUTH_GS)
572                 fprintf(fp, " south_gs");
573             fputc('\n', fp);
574             parms_saved++;
575 #undef PARM_TYPE
576         }
577         /* New human. */
578         else if(type == SAR_PARM_NEW_HUMAN)
579         {
580 #define PARM_TYPE       const sar_parm_new_human_struct
581             PARM_TYPE *pv = (PARM_TYPE *)p;
582             fprintf(
583                 fp,
584                 "new_human %s",
585 		pv->type_name
586 	    );
587 	    if(pv->flags & SAR_HUMAN_FLAG_NEED_RESCUE)
588 		fprintf(fp, " need_rescue");
589             if(pv->flags & SAR_HUMAN_FLAG_SIT)
590                 fprintf(fp, " sit");
591             if(pv->flags & SAR_HUMAN_FLAG_SIT_UP)
592                 fprintf(fp, " sit_up");
593             if(pv->flags & SAR_HUMAN_FLAG_SIT_DOWN)
594                 fprintf(fp, " sit_down");
595             if(pv->flags & SAR_HUMAN_FLAG_LYING)
596                 fprintf(fp, " lying");
597             if(pv->flags & SAR_HUMAN_FLAG_ALERT)
598                 fprintf(fp, " alert");
599             if(pv->flags & SAR_HUMAN_FLAG_AWARE)
600                 fprintf(fp, " aware");
601             if(pv->flags & SAR_HUMAN_FLAG_IN_WATER)
602                 fprintf(fp, " in_water");
603 	    fputc('\n', fp);
604             parms_saved++;
605 #undef PARM_TYPE
606         }
607         /* New fire. */
608         else if(type == SAR_PARM_NEW_FIRE)
609         {
610 #define PARM_TYPE	const sar_parm_new_fire_struct
611             PARM_TYPE *pv = (PARM_TYPE *)p;
612             fprintf(
613                 fp,
614                 "new_fire %f %f\n",
615 		pv->radius, SFMMetersToFeet(pv->height)
616             );
617             parms_saved++;
618 #undef PARM_TYPE
619         }
620         /* New smoke. */
621         else if(type == SAR_PARM_NEW_SMOKE)
622         {
623 #define PARM_TYPE	const sar_parm_new_smoke_struct
624             PARM_TYPE *pv = (PARM_TYPE *)p;
625             fprintf(
626                 fp,
627                 "new_smoke %f %f %f %f %f %f %i %ld %i %i\n",
628 		pv->offset.x,
629 		pv->offset.y,
630 		pv->offset.z,		/* In meters. */
631 		pv->radius_start,
632 		pv->radius_max,
633 		pv->radius_rate,
634 		pv->hide_at_max,
635 		pv->respawn_int,
636 		pv->total_units,
637 		pv->color_code
638 	    );
639             parms_saved++;
640 #undef PARM_TYPE
641         }
642         /* New premodeled object. */
643         else if(type == SAR_PARM_NEW_PREMODELED)
644         {
645 #define PARM_TYPE	const sar_parm_new_premodeled_struct
646 	    int i;
647             PARM_TYPE *pv = (PARM_TYPE *)p;
648             fprintf(
649                 fp,
650                 "new_premodeled %s",
651 		pv->model_type
652             );
653 	    for(i = 0; i < pv->argc; i++)
654 		fprintf(fp, " %s", pv->argv[i]);
655 	    fputc('\n', fp);
656             parms_saved++;
657 #undef PARM_TYPE
658         }
659         /* Select object by name. */
660         else if(type == SAR_PARM_SELECT_OBJECT_BY_NAME)
661         {
662 #define PARM_TYPE	const sar_parm_select_object_by_name_struct
663             PARM_TYPE *pv = (PARM_TYPE *)p;
664 	    if(pv->name != NULL)
665 	    {
666 		fprintf(
667 		    fp,
668 		    "select_object_by_name %s\n",
669 		    pv->name
670 		);
671 		parms_saved++;
672 	    }
673 #undef PARM_TYPE
674         }
675         /* Model file. */
676         else if(type == SAR_PARM_MODEL_FILE)
677         {
678 #define PARM_TYPE	const sar_parm_model_file_struct
679             PARM_TYPE *pv = (PARM_TYPE *)p;
680             if(pv->file != NULL)
681             {
682                 fprintf(
683                     fp,
684                     "model_file %s\n",
685                     pv->file
686                 );
687                 parms_saved++;
688             }
689 #undef PARM_TYPE
690         }
691 	/* Range. */
692         else if(type == SAR_PARM_RANGE)
693         {
694 #define PARM_TYPE	const sar_parm_range_struct
695             PARM_TYPE *pv = (PARM_TYPE *)p;
696 	    fprintf(
697 		fp,
698 		"range %f\n",
699 		pv->range
700 	    );
701 	    parms_saved++;
702 #undef PARM_TYPE
703         }
704         /* Range far. */
705         else if(type == SAR_PARM_RANGE_FAR)
706         {
707 #define PARM_TYPE	const sar_parm_range_far_struct
708             PARM_TYPE *pv = (PARM_TYPE *)p;
709             fprintf(
710                 fp,
711                 "range_far %f\n",
712                 pv->range_far
713             );
714             parms_saved++;
715 #undef PARM_TYPE
716         }
717         /* Translate. */
718         else if(type == SAR_PARM_TRANSLATE)
719         {
720 #define PARM_TYPE	const sar_parm_translate_struct
721             PARM_TYPE *pv = (PARM_TYPE *)p;
722             fprintf(
723                 fp,
724                 "translate %f %f %f\n",
725                 pv->translate.x,
726 		pv->translate.y,
727 		SFMMetersToFeet(pv->translate.z)
728             );
729             parms_saved++;
730 #undef PARM_TYPE
731         }
732         /* Translate random. */
733         else if(type == SAR_PARM_TRANSLATE_RANDOM)
734         {
735 #define PARM_TYPE	const sar_parm_translate_random_struct
736             PARM_TYPE *pv = (PARM_TYPE *)p;
737             fprintf(
738                 fp,
739                 "translate_random %f %f\n",
740                 pv->radius_bound,
741                 pv->z_bound
742             );
743             parms_saved++;
744 #undef PARM_TYPE
745         }
746         /* Rotate. */
747         else if(type == SAR_PARM_ROTATE)
748         {
749 #define PARM_TYPE	const sar_parm_rotate_struct
750             PARM_TYPE *pv = (PARM_TYPE *)p;
751             fprintf(
752                 fp,
753                 "rotate %f %f %f\n",
754                 RADTODEG(pv->rotate.heading),
755                 RADTODEG(pv->rotate.pitch),
756                 RADTODEG(pv->rotate.bank)
757             );
758             parms_saved++;
759 #undef PARM_TYPE
760         }
761         /* No depth test. */
762         else if(type == SAR_PARM_NO_DEPTH_TEST)
763         {
764 #define PARM_TYPE	const sar_parm_no_depth_test_struct
765 /*	    PARM_TYPE *pv = (PARM_TYPE *)p; */
766             fprintf(
767                 fp,
768                 "no_depth_test\n"
769             );
770             parms_saved++;
771 #undef PARM_TYPE
772         }
773         /* Polygon offset. */
774         else if(type == SAR_PARM_POLYGON_OFFSET)
775         {
776 #define PARM_TYPE	const sar_parm_polygon_offset_struct
777             PARM_TYPE *pv = (PARM_TYPE *)p;
778             fprintf(fp, "polygon_offset");
779 	    if(pv->flags & SAR_OBJ_FLAG_POLYGON_OFFSET_REVERSE)
780 		fprintf(fp, " reverse");
781             if(pv->flags & SAR_OBJ_FLAG_POLYGON_OFFSET_WRITE_DEPTH)
782                 fprintf(fp, " write_depth");
783 	    fputc('\n', fp);
784             parms_saved++;
785 #undef PARM_TYPE
786         }
787 	/* Countact bounds spherical. */
788         else if(type == SAR_PARM_CONTACT_BOUNDS_SPHERICAL)
789         {
790 #define PARM_TYPE	const sar_parm_contact_bounds_spherical_struct
791             PARM_TYPE *pv = (PARM_TYPE *)p;
792 	    fprintf(
793 		fp,
794 		"contact_spherical %f\n",
795 		pv->radius
796 	    );
797             parms_saved++;
798 #undef PARM_TYPE
799         }
800         /* Countact bounds cylendrical. */
801         else if(type == SAR_PARM_CONTACT_BOUNDS_CYLENDRICAL)
802         {
803 #define PARM_TYPE	const sar_parm_contact_bounds_cylendrical_struct
804             PARM_TYPE *pv = (PARM_TYPE *)p;
805             fprintf(
806                 fp,
807                 "contact_cylendrical %f %f %f\n",
808                 pv->radius,
809 		pv->height_min, pv->height_max	/* In meters. */
810             );
811             parms_saved++;
812 #undef PARM_TYPE
813         }
814         /* Countact bounds rectangular. */
815         else if(type == SAR_PARM_CONTACT_BOUNDS_RECTANGULAR)
816         {
817 #define PARM_TYPE	const sar_parm_contact_bounds_rectangular_struct
818             PARM_TYPE *pv = (PARM_TYPE *)p;
819             fprintf(
820                 fp,
821                 "contact_rectangular %f %f %f %f %f %f\n",
822                 pv->x_min, pv->x_max,
823                 pv->y_min, pv->y_max,
824                 pv->z_min, pv->z_max	/* In meters. */
825             );
826             parms_saved++;
827 #undef PARM_TYPE
828         }
829         /* Ground elevation. */
830         else if(type == SAR_PARM_GROUND_ELEVATION)
831         {
832 #define PARM_TYPE	const sar_parm_ground_elevation_struct
833             PARM_TYPE *pv = (PARM_TYPE *)p;
834             fprintf(
835                 fp,
836                 "ground_elevation %f\n",
837                 SFMMetersToFeet(pv->elevation)
838             );
839             parms_saved++;
840 #undef PARM_TYPE
841         }
842         /* Object name. */
843         else if(type == SAR_PARM_OBJECT_NAME)
844         {
845 #define PARM_TYPE	const sar_parm_object_name_struct
846             PARM_TYPE *pv = (PARM_TYPE *)p;
847             fprintf(
848                 fp,
849                 "object_name%s%s\n",
850 		(pv->name != NULL) ? " " : "",
851 		(pv->name != NULL) ? pv->name : ""
852             );
853             parms_saved++;
854 #undef PARM_TYPE
855         }
856         /* Object map description. */
857         else if(type == SAR_PARM_OBJECT_MAP_DESCRIPTION)
858         {
859 #define PARM_TYPE	const sar_parm_object_map_description_struct
860             PARM_TYPE *pv = (PARM_TYPE *)p;
861             fprintf(
862                 fp,
863                 "object_map_description%s%s\n",
864                 (pv->description != NULL) ? " " : "",
865                 (pv->description != NULL) ? pv->description : ""
866             );
867             parms_saved++;
868 #undef PARM_TYPE
869         }
870         /* Object fuel. */
871         else if(type == SAR_PARM_FUEL)
872         {
873 #define PARM_TYPE       const sar_parm_fuel_struct
874             PARM_TYPE *pv = (PARM_TYPE *)p;
875             fprintf(
876                 fp,
877                 "fuel %f %f\n",
878 		pv->fuel, pv->fuel_max
879             );
880             parms_saved++;
881 #undef PARM_TYPE
882         }
883         /* Object hit points. */
884         else if(type == SAR_PARM_HITPOINTS)
885         {
886 #define PARM_TYPE	const sar_parm_hitpoints_struct
887             PARM_TYPE *pv = (PARM_TYPE *)p;
888             fprintf(
889                 fp,
890                 "hitpoints %f %f\n",
891                 pv->hitpoints, pv->hitpoints_max
892             );
893             parms_saved++;
894 #undef PARM_TYPE
895         }
896         /* Object engine state. */
897         else if(type == SAR_PARM_ENGINE_STATE)
898         {
899 #define PARM_TYPE	const sar_parm_engine_state_struct
900             PARM_TYPE *pv = (PARM_TYPE *)p;
901             fprintf(
902                 fp,
903                 "engine_state %i\n",
904                 pv->state
905             );
906             parms_saved++;
907 #undef PARM_TYPE
908         }
909         /* Object passengers. */
910         else if(type == SAR_PARM_PASSENGERS)
911         {
912 #define PARM_TYPE	const sar_parm_passengers_struct
913             PARM_TYPE *pv = (PARM_TYPE *)p;
914             fprintf(
915                 fp,
916                 "passengers %i %i\n",
917                 pv->passengers, pv->passengers_max
918             );
919             parms_saved++;
920 #undef PARM_TYPE
921         }
922         /* Runway approach lighting north. */
923         else if(type == SAR_PARM_RUNWAY_APPROACH_LIGHTING_NORTH)
924         {
925 #define PARM_TYPE       const sar_parm_runway_approach_lighting_north_struct
926             PARM_TYPE *pv = (PARM_TYPE *)p;
927             fprintf(
928                 fp,
929                 "runway_approach_lighting_north"
930             );
931             if(pv->flags & SAR_RUNWAY_APPROACH_LIGHTING_END)
932                 fprintf(fp, " end");
933             if(pv->flags & SAR_RUNWAY_APPROACH_LIGHTING_TRACER)
934                 fprintf(fp, " tracer");
935             if(pv->flags & SAR_RUNWAY_APPROACH_LIGHTING_ALIGN)
936                 fprintf(fp, " align");
937             if(pv->flags & SAR_RUNWAY_APPROACH_LIGHTING_ILS_GLIDE)
938                 fprintf(fp, " ils_glide");
939             fputc('\n', fp);
940             parms_saved++;
941 #undef PARM_TYPE
942         }
943         /* Runway approach lighting south. */
944         else if(type == SAR_PARM_RUNWAY_APPROACH_LIGHTING_SOUTH)
945         {
946 #define PARM_TYPE       const sar_parm_runway_approach_lighting_south_struct
947             PARM_TYPE *pv = (PARM_TYPE *)p;
948             fprintf(
949                 fp,
950                 "runway_approach_lighting_south"
951             );
952             if(pv->flags & SAR_RUNWAY_APPROACH_LIGHTING_END)
953                 fprintf(fp, " end");
954             if(pv->flags & SAR_RUNWAY_APPROACH_LIGHTING_TRACER)
955                 fprintf(fp, " tracer");
956             if(pv->flags & SAR_RUNWAY_APPROACH_LIGHTING_ALIGN)
957                 fprintf(fp, " align");
958             if(pv->flags & SAR_RUNWAY_APPROACH_LIGHTING_ILS_GLIDE)
959                 fprintf(fp, " ils_glide");
960             fputc('\n', fp);
961             parms_saved++;
962 #undef PARM_TYPE
963         }
964         /* Human message enter. */
965         else if(type == SAR_PARM_HUMAN_MESSAGE_ENTER)
966         {
967 #define PARM_TYPE	const sar_parm_human_message_enter_struct
968             PARM_TYPE *pv = (PARM_TYPE *)p;
969             fprintf(
970                 fp,
971                 "set_human_message_enter%s%s\n",
972                 (pv->message != NULL) ? " " : "",
973                 (pv->message != NULL) ? pv->message : ""
974             );
975             parms_saved++;
976 #undef PARM_TYPE
977         }
978         /* Human reference. */
979         else if(type == SAR_PARM_HUMAN_REFERENCE)
980         {
981 #define PARM_TYPE	const sar_parm_human_reference_struct
982             PARM_TYPE *pv = (PARM_TYPE *)p;
983 	    if(pv->reference_name != NULL)
984 	    {
985 		fprintf(fp, "human_reference %s", pv->reference_name);
986 		if(pv->flags & SAR_HUMAN_FLAG_RUN_TOWARDS)
987 		    fprintf(fp, " run_towards");
988 		if(pv->flags & SAR_HUMAN_FLAG_RUN_AWAY)
989 		    fprintf(fp, " run_away");
990 		fputc('\n', fp);
991 	    }
992             parms_saved++;
993 #undef PARM_TYPE
994         }
995 
996 
997 	return(parms_saved);
998 }
999 
1000 /*
1001  *	Saves parameters to file regardless of file format.
1002  */
SARParmSaveToFileAny(const char * filename,FILE * fp,void ** parm,int total_parms,void * client_data,int (* progress_func)(void *,long,long))1003 static int SARParmSaveToFileAny(
1004 	const char *filename, FILE *fp,
1005 	void **parm, int total_parms,
1006         void *client_data,
1007         int (*progress_func)(void *, long, long)
1008 )
1009 {
1010 	int i;
1011 	const void *p;
1012 
1013 	/* Iterate through all parameters. */
1014 	for(i = 0; i < total_parms; i++)
1015 	{
1016 	    p = parm[i];
1017 	    if(p == NULL)
1018 		continue;
1019 
1020             /* Call progress callback. */
1021             if(progress_func != NULL)
1022             {
1023                 if(progress_func(client_data, i + 1, total_parms))
1024                     break;
1025             }
1026 
1027             /* Save this parameter. */
1028             SARParmSaveToFileAnyIterate(filename, fp, p);
1029 	}
1030 
1031 	return(0);
1032 }
1033 
1034 /*
1035  *	Saves the list of parameters to file.
1036  *
1037  *      The given file_format is a hint to the file's format.
1038  *
1039  *      Returns non-zero on error.
1040  */
SARParmSaveToFile(const char * filename,int file_format,void ** parm,int total_parms,void * client_data,int (* progress_func)(void *,long,long))1041 int SARParmSaveToFile(
1042         const char *filename, int file_format,
1043         void **parm, int total_parms,
1044         void *client_data,
1045         int (*progress_func)(void *, long, long)
1046 )
1047 {
1048         int status = -1;
1049         FILE *fp;
1050 
1051 
1052         if(filename == NULL)
1053             return(status);
1054 
1055         /* Open file for writing. */
1056         fp = FOpen(filename, "wb");
1057         if(fp == NULL)
1058             return(status);
1059 
1060         /* Save by file format type. */
1061 	if(1)
1062         {
1063             status = SARParmSaveToFileAny(
1064                 filename, fp,
1065                 parm, total_parms,
1066                 client_data, progress_func
1067             );
1068         }
1069 
1070         /* Close file. */
1071         FClose(fp);
1072 
1073         return(status);
1074 }
1075