1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <time.h>
6 
7 #ifdef __MSW__
8 # include <windows.h>
9 #else
10 # include <sys/time.h>
11 # include <unistd.h>
12 #endif
13 
14 #include "gw.h"
15 #include "messages.h"
16 #include "sarreality.h"
17 #include "obj.h"
18 #include "mission.h"
19 #include "sar.h"
20 #include "sartime.h"
21 #include "sarmusic.h"
22 #include "scenesound.h"
23 #include "objio.h"
24 #include "missionio.h"
25 #include "sceneio.h"
26 #include "sarmenuop.h"
27 #include "sarmenucodes.h"
28 #include "sarsimbegin.h"
29 
30 
31 static void SARSimBeginResetOptions(sar_core_struct *core_ptr);
32 
33 int SARSimBeginMission(
34 	sar_core_struct *core_ptr,
35 	const char *mission_file
36 );
37 int SARSimBeginFreeFlight(
38 	sar_core_struct *core_ptr,
39 	const char *scene_file,
40 	const char *player_file,                /* Player aircraft. */
41 	sar_position_struct *start_pos,
42 	sar_direction_struct *start_dir,
43 	const char *weather_preset_name,
44 	Boolean free_flight_system_time
45 );
46 
47 
48 #define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
49 #define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
50 #define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
51 #define STRDUP(s)       (((s) != NULL) ? strdup(s) : NULL)
52 
53 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
54 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
55 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
56 #define STRLEN(s)       (((s) != NULL) ? ((int)strlen(s)) : 0)
57 
58 
59 /*
60  *	Resets options for simulation.
61  */
SARSimBeginResetOptions(sar_core_struct * core_ptr)62 static void SARSimBeginResetOptions(sar_core_struct *core_ptr)
63 {
64 	sar_option_struct *opt = &core_ptr->option;
65 
66 	core_ptr->display_help = 0;
67 	core_ptr->flir = False;
68 
69 	opt->show_hud_text = True;
70 	opt->show_outside_text = True;
71 
72 	time_compression = 1.0f;
73 }
74 
75 /*
76  *      Enters mission simulation from the menu system.
77  *
78  *      Returns 0 on success or -1 on failure. On failure this function
79  *      will return the menu system.
80  */
SARSimBeginMission(sar_core_struct * core_ptr,const char * mission_file)81 int SARSimBeginMission(
82 	sar_core_struct *core_ptr,
83 	const char *mission_file
84 )
85 {
86 	gw_display_struct *display;
87 	sar_scene_struct *scene;
88 	sar_mission_struct *mission;
89 	sar_progress_cb_struct *cb_data;
90 	const sar_option_struct *opt;
91 
92 
93 	if(core_ptr == NULL)
94 	    return(-1);
95 
96 	display = core_ptr->display;
97 	if(display == NULL)
98 	    return(-1);
99 
100 	opt = &core_ptr->option;
101 
102 	/* Check inputs */
103 	if(mission_file == NULL)
104 	{
105 	    GWOutputMessage(
106 		display,
107 		GWOutputMessageTypeWarning,
108 		"Missing Information",
109 		"No mission selected",
110 		"You need to select a mission"
111 	    );
112 	    return(-1);
113 	}
114 
115 
116 	/* Begin switching from menus to mission simulation */
117 
118 	/* Switch to load simulation progress menu */
119 	SARMenuSwitchToMenu(
120 	    core_ptr, SAR_MENU_NAME_LOADING_SIMULATION
121 	);
122 	/* Check if music needs to be updated and update it as needed.
123 	 * This will detect that the current menu is the loading
124 	 * simulation menu and switch to the loading simulation music.
125 	 */
126 	SARMusicUpdate(core_ptr);
127 
128 	GWSetInputBusy(display);
129 
130 	core_ptr->stop_count = 0;
131 
132 	/* Allocate scene structure as needed */
133 	if(core_ptr->scene == NULL)
134 	{
135 	    core_ptr->scene = (sar_scene_struct *)calloc(
136 		1, sizeof(sar_scene_struct)
137 	    );
138 	    if(core_ptr->scene == NULL)
139 	    {
140 		/* Scene allocation failed, switch back to main menu,
141 		 * mark input as ready, and return
142 		 */
143 		SARMenuSwitchToMenu(
144 		    core_ptr, SAR_MENU_NAME_MAIN
145 		);
146 		GWSetInputReady(display);
147 		return(-1);
148 	    }
149 	}
150 	scene = core_ptr->scene;
151 
152 	/* Unload mission (in case it's already loaded) */
153 	SARMissionDelete(core_ptr->mission);
154 	core_ptr->mission = NULL;
155 
156 	/* Unload scene (in case it's already loaded) */
157 	SARSceneDestroy(
158 	    core_ptr, scene,
159 	    &core_ptr->object, &core_ptr->total_objects
160 	);
161 
162 	/* Reset game controller values */
163 	GCtlResetValues(core_ptr->gctl);
164 
165 	/* Set up load progress callback data */
166 	cb_data = SAR_PROGRESS_CB(calloc(1, sizeof(sar_progress_cb_struct)));
167 	cb_data->core_ptr = core_ptr;
168 	cb_data->coeff_offset = 0.0f;
169 	cb_data->coeff_range = 1.0f;
170 	cb_data->can_abort = False;
171 
172 	/* Load mission */
173 	core_ptr->mission = mission = SARMissionLoadFromFile(
174 	    core_ptr, mission_file,
175 	    cb_data, SARLoadProgressCB
176 	);
177 
178 	/* Failed to load mission? */
179 	if(mission == NULL)
180 	{
181 	    /* Failed to load mission */
182 	    SARMissionDelete(mission);
183 	    core_ptr->mission = mission = NULL;
184 
185 	    SARSceneDestroy(
186 		core_ptr, scene,
187 		&core_ptr->object, &core_ptr->total_objects
188 	    );
189 	    free(core_ptr->scene);
190 	    core_ptr->scene = scene = NULL;
191 
192 	    free(cb_data);
193 
194 	    SARMenuSwitchToMenu(
195 		core_ptr, SAR_MENU_NAME_MAIN
196 	    );
197 	    GWSetInputReady(display);
198 	    return(-1);
199 	}
200 	else
201 	{
202 	    char *s;
203 	    const char *name;
204 	    sar_player_stat_struct *pstat = SARPlayerStatCurrent(core_ptr, NULL);
205 	    sar_object_struct *player_obj_ptr = scene->player_obj_ptr;
206 
207 	    if(pstat != NULL)
208 		name = pstat->name;
209 	    else
210 		name = (player_obj_ptr != NULL) ? player_obj_ptr->name : NULL;
211 
212 	    /* Reset mission log file, erasing the old log file and
213 	     * generating a new one with a header based on the values
214 	     * from the specified mission
215 	     */
216 	    SARMissionLogReset(
217 		core_ptr, mission,
218 		fname.mission_log
219 	    );
220 
221 	    /* Log mission start event */
222 	    s = (char *)malloc(
223 		(80 + STRLEN(name) +
224 		    STRLEN(mission->start_location_name)
225 		) * sizeof(char)
226 	    );
227 	    sprintf(
228 		s,
229 		"%s took off at %s",
230 		name,
231 		mission->start_location_name
232 	    );
233 	    SARMissionLogEvent(
234 		core_ptr, core_ptr->mission,
235 		SAR_MISSION_LOG_EVENT_TAKEOFF,
236 		-1.0,
237 		(player_obj_ptr != NULL) ? &player_obj_ptr->pos : NULL,
238 		NULL, 0,
239 		s,
240 		fname.mission_log
241 	    );
242 	    free(s);
243 
244 	    /* Update message text color and hud color based on the
245 	     * initial time of day set on the scene
246 	     */
247 	    SARSetGlobalTextColorBrightness(
248 		core_ptr,
249 		(float)(
250 		    (scene->tod > 43200.0f) ?
251 		    MAX(1.0 - ((scene->tod - 43200.0) / 43200.0), 0.4) :
252 		    MAX(scene->tod / 43200.0, 0.4)
253 		)
254 	    );
255 
256 	    /* Switch off menus */
257 	    SARMenuSwitchToMenu(core_ptr, NULL);
258 
259 	    /* Update sound on scene */
260 	    SARSceneSoundUpdate(
261 		core_ptr,
262 		opt->engine_sounds,
263 		opt->event_sounds,
264 		opt->voice_sounds,
265 		opt->music
266 	    );
267 	}
268 
269 	/* Need to reset timmers since the loading may have consumed
270 	 * long amount of time and if the lapsed_millitime is too long
271 	 * simulations and other timings can get out of sync
272 	 */
273 	SARResetTimmersCB(core_ptr, SARGetCurMilliTime());
274 
275 	/* Reset option values before starting simulation */
276 	SARSimBeginResetOptions(core_ptr);
277 
278 	GWSetInputReady(display);
279 
280 	/* Hide pointer cursor */
281 	GWHideCursor(display);
282 
283 	free(cb_data);
284 
285 	return(0);
286 }
287 
288 /*
289  *	Enters free flight simulation from the menu system.
290  *
291  *	Returns 0 on success or -1 on failure. On failure this function
292  *	will return the menu system.
293  */
SARSimBeginFreeFlight(sar_core_struct * core_ptr,const char * scene_file,const char * player_file,sar_position_struct * start_pos,sar_direction_struct * start_dir,const char * weather_preset_name,Boolean free_flight_system_time)294 int SARSimBeginFreeFlight(
295 	sar_core_struct *core_ptr,
296 	const char *scene_file,
297 	const char *player_file,                /* Player aircraft. */
298 	sar_position_struct *start_pos,
299 	sar_direction_struct *start_dir,
300 	const char *weather_preset_name,
301 	Boolean free_flight_system_time
302 )
303 {
304 	gw_display_struct *display;
305 	sar_scene_struct *scene;
306 	sar_progress_cb_struct *cb_data;
307 	const sar_option_struct *opt;
308 
309 	if(core_ptr == NULL)
310 	    return(-1);
311 
312 	display = core_ptr->display;
313 	if(display == NULL)
314 	    return(-1);
315 
316 	opt = &core_ptr->option;
317 
318 	/* Check inputs */
319 	if(player_file == NULL)
320 	{
321 	    GWOutputMessage(
322 		display,
323 		GWOutputMessageTypeWarning,
324 		"Missing Information",
325 		"No aircraft selected",
326 		"You need to select an aircraft for free flight"
327 	    );
328 	    return(-1);
329 	}
330 	if(scene_file == NULL)
331 	{
332 	    GWOutputMessage(
333 		display,
334 		GWOutputMessageTypeWarning,
335 		"Missing Information",
336 		"No scenery selected",
337 		"You need to select a scenery to fly in"
338 	    );
339 	    return(-1);
340 	}
341 
342 
343 	/* Begin switching from menus to free flight simulation */
344 
345 	/* Switch to load simulation progress menu */
346 	SARMenuSwitchToMenu(
347 	    core_ptr, SAR_MENU_NAME_LOADING_SIMULATION
348 	);
349 	/* Check if music needs to be updated and update it as needed.
350 	 * This will detect that the current menu is the loading
351 	 * simulation menu and switch to the loading simulation music.
352 	 */
353 	SARMusicUpdate(core_ptr);
354 
355 	GWSetInputBusy(display);
356 
357 	core_ptr->stop_count = 0;
358 
359 	/* Allocate scene structure as needed. */
360 	if(core_ptr->scene == NULL)
361 	{
362 	    core_ptr->scene = (sar_scene_struct *)calloc(
363 		1, sizeof(sar_scene_struct)
364 	    );
365 	    if(core_ptr->scene == NULL)
366 	    {
367 		SARMenuSwitchToMenu(
368 		    core_ptr, SAR_MENU_NAME_MAIN
369 		);
370 		GWSetInputReady(display);
371 		return(-1);
372 	    }
373 	}
374 	scene = core_ptr->scene;
375 
376 	/* Unload scene (incase it's already loaded/allocated). */
377 	SARSceneDestroy(
378 	    core_ptr, scene,
379 	    &core_ptr->object,
380 	    &core_ptr->total_objects
381 	);
382 
383 	/* Reset game controller values. */
384 	GCtlResetValues(core_ptr->gctl);
385 
386 	/* Set up load progress callback data. */
387 	cb_data = SAR_PROGRESS_CB(calloc(1, sizeof(sar_progress_cb_struct)));
388 	cb_data->core_ptr = core_ptr;
389 	cb_data->coeff_offset = 0.0f;
390 	cb_data->coeff_range = 0.9f;
391 	cb_data->can_abort = False;
392 
393 	/* Load scene */
394 	if(SARSceneLoadFromFile(
395 	    core_ptr, scene, scene_file,
396 	    weather_preset_name,
397 	    cb_data, SARLoadProgressCB
398 	))
399 	{
400 	    /* Failed to load scene
401 	     *
402 	     * Delete any loaded portions of the scene, switch back to
403 	     * the menus, and return indicating error
404 	     */
405 	    SARSceneDestroy(
406 		core_ptr, scene,
407 		&core_ptr->object, &core_ptr->total_objects
408 	    );
409 	    free(scene);
410 	    core_ptr->scene = scene = NULL;
411 
412 	    free(cb_data);
413 
414 	    SARMenuSwitchToMenu(
415 		core_ptr, SAR_MENU_NAME_MAIN
416 	    );
417 	    GWSetInputReady(display);
418 	    return(-1);
419 	}
420 	else
421 	{
422 	    /* Successfully loaded scene */
423 
424 	    /* Add player object to scene */
425 	    cb_data->coeff_offset = 0.9f;
426 	    cb_data->coeff_range = 0.1f;
427 	    SARLoadProgressCB(cb_data, 0, 1);
428 	    SARSceneAddPlayerObject(
429 		core_ptr, scene, player_file,
430 		start_pos, start_dir
431 	    );
432 	    SARLoadProgressCB(cb_data, 1, 1);
433 
434 	    /* Set free flight time from system time? */
435 	    if(free_flight_system_time)
436 	    {
437 		time_t t = time(NULL);
438 		struct tm *tm_ptr = localtime(&t);
439 		if(tm_ptr != NULL)
440 		{
441 		    scene->tod = (float)(
442 			(tm_ptr->tm_hour * 3600) +
443 			(tm_ptr->tm_min * 60) +
444 			(tm_ptr->tm_sec)
445 		    );
446 		}
447 	    }
448 
449 	    /* Update message text color and hud color based on the
450 	     * initial time of day set on the scene
451 	     */
452 	    SARSetGlobalTextColorBrightness(
453 		core_ptr,
454 		(float)(
455 		    (scene->tod > 43200.0f) ?
456 		    MAX(1.0 - ((scene->tod - 43200.0) / 43200.0), 0.4) :
457 		    MAX(scene->tod / 43200.0, 0.4)
458 		)
459 	    );
460 
461 	    /* Switch off menus */
462 	    SARMenuSwitchToMenu(core_ptr, NULL);
463 
464 	    /* Update sound on scene */
465 	    SARSceneSoundUpdate(
466 		core_ptr,
467 		opt->engine_sounds,
468 		opt->event_sounds,
469 		opt->voice_sounds,
470 		opt->music
471 	    );
472 	}
473 
474 	/* Need to reset timmers since the loading may have consumed
475 	 * long amount of time and if the lapsed_millitime is too long
476 	 * simulations and other timings can get out of sync
477 	 */
478 	SARResetTimmersCB(core_ptr, SARGetCurMilliTime());
479 
480 	/* Reset option values before starting simulation */
481 	SARSimBeginResetOptions(core_ptr);
482 
483 	GWSetInputReady(display);
484 
485 	/* Hide pointer cursor */
486 	GWHideCursor(display);
487 
488 	free(cb_data);
489 
490 	return(0);
491 }
492