1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <time.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8
9 #ifdef __MSW__
10 # include <windows.h>
11 #else
12 # include <sys/time.h>
13 # include <unistd.h>
14 #endif
15
16 #include <GL/gl.h>
17 #include "../include/disk.h"
18 #include "../include/strexp.h"
19 #include "../include/string.h"
20 #include "gw.h"
21
22 #include "menu.h"
23 #include "messages.h"
24 #include "textinput.h"
25 #include "sarreality.h"
26 #include "obj.h"
27 #include "simmanage.h"
28 #include "weather.h"
29 #include "gctl.h"
30 #include "sound.h"
31 #include "mission.h"
32 #include "sar.h"
33 #include "sarsplash.h"
34 #include "sarinstall.h"
35 #include "sardraw.h"
36 #include "sardrawselect.h"
37 #include "sarkey.h"
38 #include "sarscreenshot.h"
39 #include "sartime.h"
40 #include "sarmusic.h"
41 #include "optionio.h"
42 #include "playerstatio.h"
43 #include "texturelistio.h"
44 #include "sceneio.h"
45 #include "sarmenuop.h"
46 #include "sarmenucb.h"
47 #include "sarmenubuild.h"
48 #include "sarmenumanage.h"
49 #include "sarmenucodes.h"
50 #include "sarsimend.h"
51 #include "config.h"
52
53 #include "fonts/6x10.fnt"
54 #include "fonts/7x14.fnt"
55 #include "fonts/banner.fnt"
56 #include "fonts/menu.fnt"
57
58
59 void SARHandleSignal(int s);
60
61 int SARInitGCTL(sar_core_struct *core_ptr);
62
63 void SARFullScreen(sar_core_struct *core_ptr);
64 void SARResolution(gw_display_struct *display, int width, int height);
65 void SARResolutionIncrease(gw_display_struct *display);
66 void SARResolutionDecrease(gw_display_struct *display);
67
68 int SARLoadProgressCB(void *ptr, long pos, long size);
69
70 void SARTextInputCBSendMessage(const char *value, void *data);
71 void SARTextInputCBQuitSimulation(const char *value, void *data);
72
73 void SARDrawCB(int ctx_num, void *ptr);
74 void SARKeyBoardCB(void *ptr, int c, Boolean state, unsigned long t);
75 void SARPointerCB(
76 int ctx_num, void *ptr,
77 int x, int y, gw_event_type type, int btn_num, unsigned long t
78 );
79 void SARReshapeCB(int ctx_num, void *ptr, int x, int y, int width, int height);
80 void SARVisibilityCB(int ctx_num, void *ptr, gw_visibility v);
81 void SARSaveYourselfCB(int ctx_num, void *ptr);
82 void SARCloseCB(int ctx_num, void *ptr, void *data);
83 void SARResetTimmersCB(sar_core_struct *core_ptr, time_t t_new);
84
85 sar_core_struct *SARInit(int argc, char **argv);
86 void SARManage(void *ptr);
87 void SARShutdown(sar_core_struct *core_ptr);
88
89
90 #define ATOI(s) (((s) != NULL) ? atoi(s) : 0)
91 #define ATOL(s) (((s) != NULL) ? atol(s) : 0)
92 #define ATOF(s) (((s) != NULL) ? (float)atof(s) : 0.0f)
93 #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL)
94
95 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
96 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
97 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
98 #define STRLEN(s) (((s) != NULL) ? (int)strlen(s) : 0)
99 #define STRISEMPTY(s) (((s) != NULL) ? (*(s) == '\0') : 1)
100
101 #define RADTODEG(r) ((r) * 180.0 / PI)
102 #define DEGTORAD(d) ((d) * PI / 180.0)
103
104
105 static int segfault_count;
106
107
108 sar_dname_struct dname;
109 sar_fname_struct fname;
110 sar_next_struct next;
111
112 float debug_value;
113
114 int runlevel;
115
116 time_t cur_millitime,
117 cur_systime,
118 lapsed_millitime;
119
120 float time_compensation,
121 time_compression;
122
123
124 /*
125 * Records visibility of window.
126 */
127 static int is_visible = 0;
128
129
130
131
132 /*
133 * Signal handler.
134 */
SARHandleSignal(int s)135 void SARHandleSignal(int s)
136 {
137 #if defined(__MSW__)
138
139 #else
140 switch(s)
141 {
142 #ifdef SIGINT
143 case SIGINT:
144 runlevel = 1;
145 break;
146 #endif
147 #ifdef SIGTERM
148 case SIGTERM:
149 exit(0);
150 break;
151 #endif
152 #ifdef SIGQUIT
153 case SIGQUIT:
154 exit(0);
155 break;
156 #endif
157 #ifdef SIGSEGV
158 case SIGSEGV:
159 fprintf(
160 stderr,
161 PROG_NAME_FULL " triggered a segmentation fault.\n"
162 );
163 exit(1);
164 break;
165 #endif
166 }
167 #endif
168 }
169
170 /*
171 * (Re)initializes the Game Controller based on values from the
172 * current options.
173 */
SARInitGCTL(sar_core_struct * core_ptr)174 int SARInitGCTL(sar_core_struct *core_ptr)
175 {
176 int i, total_joysticks;
177 void *w, *rc;
178 gctl_js_connection js_connection;
179 gctl_struct *gctl;
180 gctl_values_struct *v;
181 gw_display_struct *display = core_ptr->display;
182 const sar_option_struct *opt = &core_ptr->option;
183
184 /* Shutdown Game Controller as needed */
185 GCtlDelete(core_ptr->gctl);
186 core_ptr->gctl = NULL;
187
188 /* Get pointers to the Window and Rendering Context of the
189 * first GL Context, this is needed by the Game Controller
190 */
191 if(GWContextGet(
192 display, GWContextCurrent(display),
193 &w, &rc,
194 NULL, NULL, NULL, NULL
195 ))
196 return(-1);
197
198 /* Check how many joysticks are specified by the options by
199 * checking if axis roles defined for each joystick in question
200 *
201 * Any joystick with one or more axis roles set means the stick
202 * is enabled
203 */
204 total_joysticks = 0;
205 if(opt->gctl_js0_axis_roles != 0)
206 total_joysticks++;
207 if(opt->gctl_js1_axis_roles != 0)
208 total_joysticks++;
209
210
211 /* Set up Game Controller Values */
212 v = GCTL_VALUES(calloc(1, sizeof(gctl_values_struct)));
213
214 /* Controllers; Keyboard, Joystick, and/or Pointer */
215 v->controllers = opt->gctl_controllers;
216
217 /* Options (none at this time) */
218 v->options = opt->gctl_options;
219
220 /* Set up Game Controller Joystick Values for each joystick
221 * that is enabled
222 */
223 v->total_joysticks = total_joysticks;
224 if(total_joysticks > 0)
225 v->joystick = (gctl_values_js_struct *)calloc(
226 total_joysticks, sizeof(gctl_values_js_struct)
227 );
228 else
229 v->joystick = NULL;
230 /* Joystick #1 */
231 i = 0;
232 js_connection = opt->js0_connection;
233 if((total_joysticks > i) && (opt->gctl_js0_axis_roles != 0))
234 {
235 gctl_values_js_struct *js_v = &v->joystick[i];
236
237 js_v->priority = opt->js_priority;
238 switch(js_connection)
239 {
240 case GCTL_JS_CONNECTION_USB:
241 js_v->device = STRDUP("/dev/input/js0");
242 break;
243 case GCTL_JS_CONNECTION_STANDARD:
244 js_v->device = STRDUP("/dev/js0");
245 break;
246 }
247 js_v->connection = js_connection;
248 js_v->window = w;
249
250 js_v->axis_role = opt->gctl_js0_axis_roles;
251
252 js_v->button_rotate = opt->js0_btn_rotate;
253 js_v->button_air_brakes = opt->js0_btn_air_brakes;
254 js_v->button_wheel_brakes = opt->js0_btn_wheel_brakes;
255 js_v->button_zoom_in = opt->js0_btn_zoom_in;
256 js_v->button_zoom_out = opt->js0_btn_zoom_out;
257 js_v->button_hoist_up = opt->js0_btn_hoist_up;
258 js_v->button_hoist_down = opt->js0_btn_hoist_down;
259 }
260 /* Joystick #2 */
261 i = 1;
262 js_connection = opt->js1_connection;
263 if((total_joysticks > i) && (opt->gctl_js1_axis_roles != 0))
264 {
265 gctl_values_js_struct *js_v = &v->joystick[i];
266
267 js_v->priority = opt->js_priority;
268 switch(js_connection)
269 {
270 case GCTL_JS_CONNECTION_USB:
271 js_v->device = STRDUP("/dev/input/js1");
272 break;
273 case GCTL_JS_CONNECTION_STANDARD:
274 js_v->device = STRDUP("/dev/js1");
275 break;
276 }
277 js_v->connection = js_connection;
278 js_v->window = w;
279
280 js_v->axis_role = opt->gctl_js1_axis_roles;
281
282 js_v->button_rotate = opt->js1_btn_rotate;
283 js_v->button_air_brakes = opt->js1_btn_air_brakes;
284 js_v->button_wheel_brakes = opt->js1_btn_wheel_brakes;
285 js_v->button_zoom_in = opt->js1_btn_zoom_in;
286 js_v->button_zoom_out = opt->js1_btn_zoom_out;
287 js_v->button_hoist_up = opt->js1_btn_hoist_up;
288 js_v->button_hoist_down = opt->js1_btn_hoist_down;
289 }
290
291
292 /* Initialize the Game Controller */
293 core_ptr->gctl = gctl = GCtlNew(v);
294
295 /* Delete Game Controller Values */
296 for(i = 0; i < v->total_joysticks; i++)
297 {
298 gctl_values_js_struct *js_v = &v->joystick[i];
299 free(js_v->device);
300 }
301 free(v->joystick);
302 free(v);
303
304
305 /* Error initializing the Game Controller? */
306 if(gctl == NULL)
307 {
308 GWOutputMessage(
309 core_ptr->display, GWOutputMessageTypeError,
310 "Error Initializing Controller",
311 GCtlGetError(),
312 "The above error was encountered when attempting\n\
313 to initialize the game controller. Please check\n\
314 if your controllers are set up properly or try\n\
315 a different game controller setting."
316 );
317 return(-1);
318 }
319 else
320 {
321 return(0);
322 }
323 }
324
325
326 /*
327 * Toggles the switching between full screen and GUI modes.
328 */
SARFullScreen(sar_core_struct * core_ptr)329 void SARFullScreen(sar_core_struct *core_ptr)
330 {
331 gw_display_struct *display = core_ptr->display;
332 sar_option_struct *opt = &core_ptr->option;
333
334 /* Currenty in full screen mode? */
335 if(GWContextIsFullScreen(display))
336 {
337 /* Currently in full screen mode, so switch back to GUI
338 * mode.
339 */
340 GWContextFullScreen(display, False);
341 opt->last_fullscreen = False;
342 }
343 else
344 {
345 /* Switch to full screen mode, first trying with the
346 * current size of the GL context.
347 */
348 int status = GWContextFullScreen(display, True);
349 if(status == 0)
350 {
351 /* Successfully switched to full screen mode */
352 opt->last_fullscreen = True;
353 }
354 else if(status == -2)
355 {
356 /* No full screen mode that matches the current size
357 * of the GL context, so use the next closest size.
358 *
359 * Here we will get a list of valid vidmode sizes (if
360 * any) and set the GL context to the size of the
361 * closest (equal or smaller vidmode size) and then
362 * switch to full screen.
363 */
364 int i, n, width, height;
365 gw_vidmode_struct *vm = GWVidModesGet(display, &n),
366 *vm_ptr;
367 int nwidth = 0, nheight = 0;
368
369 GWContextGet(
370 display, GWContextCurrent(display),
371 NULL, NULL,
372 NULL, NULL,
373 &width, &height
374 );
375
376 /* Iterate through vidmodes, finding one that is closest
377 * (equal or smaller) than the size of the GL context
378 * and store its size as nwidth and nheight.
379 */
380 for(i = 0; i < n; i++)
381 {
382 vm_ptr = &vm[i];
383 if((vm_ptr->width < width) &&
384 (vm_ptr->height < height)
385 )
386 {
387 nwidth = MAX(vm_ptr->width, nwidth);
388 nheight = MAX(vm_ptr->height, nheight);
389 }
390 }
391 GWVidModesFree(vm, n);
392
393 /* If still unable to find useable video mode then
394 * use most conservitive resolution 320x240.
395 */
396 if((nwidth == 0) || (nheight == 0))
397 {
398 nwidth = 320;
399 nheight = 240;
400 }
401 /* Adjust context to new size that is hopefully suitable
402 * for full screen mode.
403 */
404 GWContextSize(display, nwidth, nheight);
405
406 /* Attempt to switch to full screen mode with the new
407 * context size.
408 */
409 status = GWContextFullScreen(display, True);
410 if(status == 0)
411 {
412 /* Successfully switched to full screen mode */
413 opt->last_fullscreen = True;
414 }
415 else if(status == -2)
416 {
417 /* Still no full screen mode that matches the
418 * current size, so print message.
419 */
420 int width, height;
421 char *buf = (char *)malloc(4 * 80 * sizeof(char));
422 GWContextGet(
423 display, GWContextCurrent(display),
424 NULL, NULL,
425 NULL, NULL,
426 &width, &height
427 );
428 sprintf(buf,
429 "Unable to find a suitable video mode to fit a full screen\n\
430 geometry of %ix%i. Try adjusting the size of the window and\n\
431 verify that both your hardware and software can support that\n\
432 geometry.",
433 width, height
434 );
435 GWOutputMessage(
436 display,
437 GWOutputMessageTypeWarning,
438 "Full Screen Failed", buf, NULL
439 );
440 free(buf);
441 }
442 }
443 else if(status == -5)
444 {
445 /* Full screen is not supported */
446 GWOutputMessage(
447 display,
448 GWOutputMessageTypeWarning,
449 "Full Screen Failed",
450 "Full screen is not supported.",
451 NULL
452 );
453 }
454 }
455 }
456
457 /*
458 * Sets the resolution/size of the window and GL frame buffer.
459 *
460 * If there is no change in size from the current size then
461 * nothing will be done.
462 */
SARResolution(gw_display_struct * display,int width,int height)463 void SARResolution(gw_display_struct *display, int width, int height)
464 {
465 int x, y, owidth, oheight;
466
467 /* Get current size and position */
468 GWContextGet(
469 display, GWContextCurrent(display),
470 NULL, NULL,
471 &x, &y,
472 &owidth, &oheight
473 );
474
475 /* Is there a change in window size? */
476 if((width != owidth) || (height != oheight))
477 {
478 /* Adjust the window position coordinates so that the window
479 * stays in the center.
480 */
481 x += (owidth / 2) - (width / 2);
482 y += (oheight / 2) - (height / 2);
483
484 /* Make sure that the adjusted window position coordinates
485 * do not place the window completely off the root window.
486 */
487
488 /* Sanitize width */
489 if((display->root_width > 0) &&
490 ((x + width) > display->root_width)
491 )
492 x = display->root_width - width;
493 if(x < 0)
494 x = 0;
495 /* Sanitize height */
496 if((display->root_height > 0) &&
497 ((y + height) > display->root_height)
498 )
499 y = display->root_height - height;
500 if(y < 0)
501 y = 0;
502
503 /* Check if already in full screen mode */
504 if(GWContextIsFullScreen(display))
505 {
506 /* Already in full screen mode, so just adjust the
507 * size and update the full screen mode.
508 */
509 GWContextSize(display, width, height);
510 GWContextFullScreen(display, True);
511 }
512 else
513 {
514 /* In windowed mode, update both the size and the
515 * position.
516 */
517 GWContextPosition(display, x, y);
518 GWContextSize(display, width, height);
519 }
520 }
521 }
522
523 /*
524 * Increases the resolution/size of the window and GL frame buffer
525 * to the "next" resolution/size.
526 */
SARResolutionIncrease(gw_display_struct * display)527 void SARResolutionIncrease(gw_display_struct *display)
528 {
529 int width, height, new_width, new_height;
530
531 GWContextGet(
532 display, GWContextCurrent(display),
533 NULL, NULL,
534 NULL, NULL,
535 &width, &height
536 );
537
538 /* 320x240 */
539 if(width < 320)
540 {
541 new_width = 320;
542 new_height = 240;
543 }
544 /* 640x480 */
545 else if(width < 640)
546 {
547 new_width = 640;
548 new_height = 480;
549 }
550 /* 800x600 */
551 else if(width < 800)
552 {
553 new_width = 800;
554 new_height = 600;
555 }
556 /* 1024x768 */
557 else if(width < 1024)
558 {
559 new_width = 1024;
560 new_height = 768;
561 }
562 else if (width < 1280)
563 {
564 new_width = 1280;
565 new_height = 768;
566 }
567 else if (width < 1366)
568 {
569 new_width = 1366;
570 new_height = 768;
571 }
572 /* 100x70 */
573 else
574 {
575 new_width = 100;
576 new_height = 70;
577 }
578
579 /* Set new resolution */
580 SARResolution(display, new_width, new_height);
581 }
582
583 /*
584 * Decreases the resolution/size of the window and GL frame buffer
585 * to the "previous" resolution/size.
586 */
SARResolutionDecrease(gw_display_struct * display)587 void SARResolutionDecrease(gw_display_struct *display)
588 {
589 int width, height, new_width, new_height;
590
591 GWContextGet(
592 display, GWContextCurrent(display),
593 NULL, NULL,
594 NULL, NULL,
595 &width, &height
596 );
597
598 if (width > 1366)
599 {
600 new_width = 1280;
601 new_height = 768;
602 }
603 else if (width > 1280)
604 {
605 new_width = 1366;
606 new_height = 768;
607 }
608 /* 1024x768 */
609 else if(width > 1024)
610 {
611 new_width = 1024;
612 new_height = 768;
613 }
614 /* 800x600 */
615 else if(width > 800)
616 {
617 new_width = 800;
618 new_height = 600;
619 }
620 /* 640x480 */
621 else if(width > 640)
622 {
623 new_width = 640;
624 new_height = 480;
625 }
626 /* 320x240 */
627 else if(width > 320)
628 {
629 new_width = 320;
630 new_height = 240;
631 }
632 /* 100x70 */
633 else
634 {
635 new_width = 100;
636 new_height = 70;
637 }
638
639 /* Set new resolution */
640 SARResolution(display, new_width, new_height);
641 }
642
643
644 /*
645 * Loading Simulation progress callback, this updates the progress
646 * bar in the Loading Simulation menu and redraws.
647 *
648 * Returns 0 to indicate continue loading or non-zero to indicate
649 * abort load.
650 *
651 * Given input ptr must be of type sar_progress_cb_struct.
652 */
SARLoadProgressCB(void * ptr,long pos,long size)653 int SARLoadProgressCB(void *ptr, long pos, long size)
654 {
655 int i;
656 sar_core_struct *core_ptr;
657 sar_menu_struct *m;
658 void *o;
659 gw_display_struct *display;
660 sar_progress_cb_struct *cb_data = SAR_PROGRESS_CB(ptr);
661 if(cb_data == NULL)
662 return(0);
663
664 core_ptr = SAR_CORE(cb_data->core_ptr);
665 if(core_ptr == NULL)
666 return(0);
667
668 display = core_ptr->display;
669 if(display == NULL)
670 return(0);
671
672 /* Get pointer to the current menu */
673 i = core_ptr->cur_menu;
674 if((i >= 0) && (i < core_ptr->total_menus))
675 m = core_ptr->menu[i];
676 else
677 m = NULL;
678 if(m == NULL)
679 return(0);
680
681 /* Make sure that we have a positive range to indicate a
682 * progress
683 */
684 if((size > 0) && (cb_data->coeff_range > 0.0f))
685 {
686 /* Update progress bar */
687 for(i = 0; i < m->total_objects; i++)
688 {
689 o = m->object[i];
690 if(SAR_MENU_IS_PROGRESS(o))
691 {
692 GWManage(display);
693 SARMenuProgressSet(
694 display, m, i,
695 cb_data->coeff_offset +
696 ((float)pos / (float)size *
697 cb_data->coeff_range),
698 True /* Redraw */
699 );
700 break;
701 }
702 }
703 }
704
705 return(0);
706 }
707
708 /*
709 * Tempory function to handle send message callback.
710 */
SARTextInputCBSendMessage(const char * value,void * data)711 void SARTextInputCBSendMessage(const char *value, void *data)
712 {
713 sar_core_struct *core_ptr = SAR_CORE(data);
714 if((value == NULL) || (core_ptr == NULL))
715 return;
716
717 SARMessageAdd(core_ptr->scene, value);
718 }
719
720 /*
721 * Quick simulation text input callback.
722 */
SARTextInputCBQuitSimulation(const char * value,void * data)723 void SARTextInputCBQuitSimulation(const char *value, void *data)
724 {
725 sar_core_struct *core_ptr = SAR_CORE(data);
726 if((value == NULL) || (core_ptr == NULL))
727 return;
728
729 if(toupper(*value) == 'Y')
730 SARSimEnd(core_ptr);
731 }
732
733 /*
734 * Redraw callback.
735 */
SARDrawCB(int ctx_num,void * ptr)736 void SARDrawCB(int ctx_num, void *ptr)
737 {
738 int cur_menu;
739 sar_core_struct *core_ptr = SAR_CORE(ptr);
740 if(core_ptr == NULL)
741 return;
742
743 /* Get current menu number */
744 cur_menu = core_ptr->cur_menu;
745
746 /* Check if current menu is valid, if it is then that
747 * implies we are in the menus.
748 */
749 if(SARIsMenuAllocated(core_ptr, cur_menu))
750 {
751 /* Draw menus */
752 SARMenuDrawAll(
753 core_ptr->display,
754 core_ptr->menu[cur_menu]
755 );
756 SARTextInputDraw(core_ptr->text_input);
757 GWSwapBuffer(core_ptr->display);
758 }
759 else
760 {
761 /* Draw scene */
762 SARDraw(core_ptr);
763 }
764 }
765
766 /*
767 * Keyboard callback.
768 */
SARKeyBoardCB(void * ptr,int c,Boolean state,unsigned long t)769 void SARKeyBoardCB(void *ptr, int c, Boolean state, unsigned long t)
770 {
771 sar_core_struct *core_ptr = SAR_CORE(ptr);
772 gw_display_struct *display;
773 sar_menu_struct *menu_ptr;
774 Boolean alt_key_state, ctrl_key_state, shift_key_state;
775 if(core_ptr == NULL)
776 return;
777
778 display = core_ptr->display;
779 if(display == NULL)
780 return;
781
782 alt_key_state = display->alt_key_state;
783 ctrl_key_state = display->ctrl_key_state;
784 shift_key_state = display->shift_key_state;
785
786 /* First check to see if the text input prompt is mapped by
787 * checking if the text input callback function is set (not
788 * NULL).
789 */
790 if(SARTextInputIsMapped(core_ptr->text_input))
791 {
792 text_input_struct *text_input = core_ptr->text_input;
793
794 /* Pass key event to text input prompt handler */
795 SARTextInputHandleKey(text_input, c, state);
796
797 /* If we are in the menus then we need to redraw */
798 if(SARGetCurrentMenuPtr(core_ptr) != NULL)
799 {
800 SARTextInputDraw(text_input);
801 GWSwapBuffer(display);
802 }
803
804 /* Return, do not continue. This is so that the key event
805 * is not passed to any other key event handlers.
806 */
807 return;
808 }
809
810
811 /* Intercept special key combinations here before going on to
812 * to regular key handling, if any keys are handled here then
813 * they will not be passed to the regular key handler
814 */
815 /* Toggle full screen */
816 if((c == GWKeyF11) && ctrl_key_state)
817 {
818 if(!state)
819 SARFullScreen(core_ptr);
820 return;
821 }
822 /* Increase resolution */
823 if((c == ']') && ctrl_key_state)
824 {
825 if(!state)
826 SARResolutionIncrease(display);
827 return;
828 }
829 /* Decrease resolution */
830 if((c == '[') && ctrl_key_state)
831 {
832 if(!state)
833 SARResolutionDecrease(display);
834 return;
835 }
836 /* Screen shot */
837 #ifdef __MSW__
838 if((c == 'c') && ctrl_key_state)
839 #else
840 if(((c == 'c') && ctrl_key_state) || (c == GWKeySysReq))
841 #endif
842 {
843 if(!state)
844 SARScreenShot(core_ptr, NULL, 2);
845 return;
846 }
847
848 /* Get current selected menu (if any). If there is no menu
849 * currently selected then call simulation key handler,
850 * otherwise call menu key handler.
851 */
852 menu_ptr = SARGetCurrentMenuPtr(core_ptr);
853 if(menu_ptr == NULL)
854 {
855 /* In simulation ,so pass key event to simulation key
856 * handler. Note that this function will not post a
857 * redraw.
858 */
859 SARKey(core_ptr, c, state, t);
860 }
861 else
862 {
863 /* A menu is selected, call menu key handler */
864 SARMenuManageKey(core_ptr->display, menu_ptr, c, state);
865 }
866 }
867
868 /*
869 * Pointer callback.
870 */
SARPointerCB(int ctx_num,void * ptr,int x,int y,gw_event_type type,int btn_num,unsigned long t)871 void SARPointerCB(
872 int ctx_num, void *ptr,
873 int x, int y, gw_event_type type, int btn_num, unsigned long t
874 )
875 {
876 sar_core_struct *core_ptr = SAR_CORE(ptr);
877 gw_display_struct *display;
878 sar_menu_struct *menu_ptr;
879 if(core_ptr == NULL)
880 return;
881
882 display = core_ptr->display;
883 if(display == NULL)
884 return;
885
886 /* First check to see if the text input prompt is mapped, if
887 * it is then the event should be passed to it
888 */
889 if(SARTextInputIsMapped(core_ptr->text_input))
890 {
891 text_input_struct *text_input = core_ptr->text_input;
892
893 /* Pass poionter event to text input prompt handler */
894 SARTextInputHandlePointer(
895 text_input, x, y, type, btn_num
896 );
897
898 /* If we are in the menus then we need to redraw */
899 if(SARGetCurrentMenuPtr(core_ptr) != NULL)
900 {
901 SARTextInputDraw(text_input);
902 GWSwapBuffer(display);
903 }
904
905 /* Done handling the event */
906 return;
907 }
908
909 /* Get current menu (if any) */
910 menu_ptr = SARGetCurrentMenuPtr(core_ptr);
911 if(menu_ptr == NULL)
912 {
913 /* There is no current menu so it implies we are in
914 * simulation, so forward the event to game controller
915 */
916 GCtlHandlePointer(
917 display, core_ptr->gctl,
918 type, btn_num,
919 x, y, t, lapsed_millitime
920 );
921 }
922 else
923 {
924 /* There is a current menu so Forward the event to the
925 * menu pointer event handler
926 */
927 SARMenuManagePointer(
928 display, menu_ptr,
929 x, y, type, btn_num
930 );
931 }
932 }
933
934 /*
935 * Resize callback, updates the last size of the toplevel window.
936 *
937 * If width or height are less than 1 the last glViewport() setting
938 * for width or height will be called again.
939 */
SARReshapeCB(int ctx_num,void * ptr,int x,int y,int width,int height)940 void SARReshapeCB(int ctx_num, void *ptr, int x, int y, int width, int height)
941 {
942 sar_core_struct *core_ptr = SAR_CORE(ptr);
943 gw_display_struct *display;
944 sar_option_struct *opt;
945
946 if(core_ptr == NULL)
947 return;
948
949 display = core_ptr->display;
950 if(display == NULL)
951 return;
952
953 opt = &core_ptr->option;
954
955 /* Change width and height if specified */
956 if((width > 0) && (height > 0))
957 {
958 /* Update last positions of toplevel window on global
959 * options
960 */
961 opt->last_x = x;
962 opt->last_y = y;
963 opt->last_width = width;
964 opt->last_height = height;
965 }
966 else
967 {
968 /* If this function is called with width and height not
969 * positive, then it means it was called synthetically and
970 * that we should use the current size of the context on the
971 * display structure
972 */
973 GWContextGet(
974 display, ctx_num,
975 NULL, NULL,
976 NULL, NULL,
977 &width, &height
978 );
979 }
980
981 /* Set new view port dimensions */
982 if((width > 0) && (height > 0))
983 glViewport(0, 0, width, height);
984 }
985
986
987 /*
988 * Visibility change callback.
989 */
SARVisibilityCB(int ctx_num,void * ptr,gw_visibility v)990 void SARVisibilityCB(int ctx_num, void *ptr, gw_visibility v)
991 {
992 switch(v)
993 {
994 case GWVisibilityFullyObscured:
995 is_visible = 0;
996 break;
997 default:
998 is_visible = 1;
999 break;
1000 }
1001 }
1002
1003 /*
1004 * Save yourself callback.
1005 */
SARSaveYourselfCB(int ctx_num,void * ptr)1006 void SARSaveYourselfCB(int ctx_num, void *ptr)
1007 {
1008 sar_core_struct *core_ptr = SAR_CORE(ptr);
1009 if(core_ptr == NULL)
1010 return;
1011
1012
1013
1014 }
1015
1016 /*
1017 * Close window callback.
1018 */
SARCloseCB(int ctx_num,void * ptr,void * data)1019 void SARCloseCB(int ctx_num, void *ptr, void *data)
1020 {
1021 sar_core_struct *core_ptr = SAR_CORE(ptr);
1022 if(core_ptr == NULL)
1023 return;
1024
1025 /* Check if currently In a menu, implying that we are currently
1026 * in the menu system and not in simulation.
1027 */
1028 if(core_ptr->cur_menu > -1)
1029 {
1030 /* Switch global runlevel to 1, causing the program to begin
1031 * shutting down.
1032 */
1033 runlevel = 1;
1034 }
1035 else
1036 {
1037 /* Currently in simulation, so end simulation instead of
1038 * switching to runlevel 1.
1039 *
1040 * First check if the user is already being prompted for,
1041 * exit. If the user is then end simulation, otherwise
1042 * prompt for exit.
1043 */
1044 if(SARTextInputIsMapped(core_ptr->text_input))
1045 {
1046 SARTextInputUnmap(core_ptr->text_input);
1047 SARSimEnd(core_ptr);
1048 }
1049 else
1050 {
1051 if(core_ptr->mission != NULL)
1052 {
1053 /* Same as end simulation, just prompt text different */
1054 SARTextInputMap(
1055 core_ptr->text_input,
1056 "Are you sure you want to abort the mission?",
1057 NULL,
1058 SARTextInputCBQuitSimulation,
1059 core_ptr
1060 );
1061 }
1062 else
1063 {
1064 SARTextInputMap(
1065 core_ptr->text_input,
1066 "Are you sure you want to quit simulation?",
1067 NULL,
1068 SARTextInputCBQuitSimulation,
1069 core_ptr
1070 );
1071 }
1072 }
1073 }
1074 }
1075
1076 /*
1077 * Resets global timmers to zero and updates the global
1078 * variable cur_millitime to the value of t_new.
1079 *
1080 * Global variable lapsed_millitime will be reset to 0 and
1081 * time_compensation will be set to 1.0.
1082 *
1083 * Timings on core structure, scene, objects, and other related
1084 * resources will also be reset.
1085 */
SARResetTimmersCB(sar_core_struct * core_ptr,time_t t_new)1086 void SARResetTimmersCB(sar_core_struct *core_ptr, time_t t_new)
1087 {
1088 int i;
1089 sar_scene_struct *scene;
1090 sar_object_struct *obj_ptr;
1091 sar_object_aircraft_struct *obj_aircraft_ptr;
1092 sar_object_ground_struct *obj_ground_ptr;
1093 sar_object_human_struct *obj_human_ptr;
1094 sar_object_smoke_struct *obj_smoke_ptr;
1095 sar_object_fire_struct *obj_fire_ptr;
1096 sar_object_explosion_struct *obj_explosion_ptr;
1097 sar_mission_struct *mission = NULL;
1098
1099
1100 /* Set global variable cur_millitime to t_new */
1101 cur_millitime = t_new;
1102
1103 /* Reset lapsed and time compensation */
1104 lapsed_millitime = 0l;
1105 time_compensation = 1.0f;
1106
1107
1108 /* Update random seed */
1109 srand((unsigned int)cur_millitime);
1110
1111
1112 /* Reset global next timmers */
1113 memset(&next, 0x00, sizeof(sar_next_struct));
1114
1115
1116 /* Reset game controller timmers */
1117 GCtlResetTimmers(core_ptr->gctl);
1118
1119 /* Reset timings on scene */
1120 scene = core_ptr->scene;
1121 if(scene != NULL)
1122 {
1123 sar_cloud_bb_struct *cloud_bb;
1124
1125 scene->message_display_until = 0l;
1126 scene->camera_ref_title_display_until = 0l;
1127
1128 /* Cloud `billboard' objects lightening timmers */
1129 for(i = 0; i < scene->total_cloud_bbs; i++)
1130 {
1131 cloud_bb = scene->cloud_bb[i];
1132 if(cloud_bb == NULL)
1133 continue;
1134
1135 cloud_bb->lightening_next_on = 0l;
1136 cloud_bb->lightening_next_off = 0l;
1137 cloud_bb->lightening_started_on = 0l;
1138 }
1139 }
1140
1141 /* Reset timings on mission */
1142 mission = core_ptr->mission;
1143 if(mission != NULL)
1144 {
1145 mission->next_check = 0l;
1146 mission->next_log_position = 0l;
1147 }
1148
1149
1150 /* Reset timmers on objects */
1151 for(i = 0; i < core_ptr->total_objects; i++)
1152 {
1153 obj_ptr = core_ptr->object[i];
1154 if(obj_ptr == NULL)
1155 continue;
1156
1157 /* Any object with a defined life span needs to die whenever
1158 * timmers are reset
1159 *
1160 * Note that we need to reset the value to 1 instead of 0
1161 * since 0 means that the object has an infinate life span
1162 * (never dies)
1163 */
1164 if(obj_ptr->life_span > 0l)
1165 obj_ptr->life_span = 1l;
1166
1167 switch(obj_ptr->type)
1168 {
1169 case SAR_OBJ_TYPE_GARBAGE:
1170 case SAR_OBJ_TYPE_STATIC:
1171 case SAR_OBJ_TYPE_AUTOMOBILE:
1172 case SAR_OBJ_TYPE_WATERCRAFT:
1173 break;
1174 case SAR_OBJ_TYPE_AIRCRAFT:
1175 obj_aircraft_ptr = SAR_OBJ_GET_AIRCRAFT(obj_ptr);
1176 if(obj_aircraft_ptr != NULL)
1177 {
1178 obj_aircraft_ptr->next_engine_on = 0l;
1179 }
1180 break;
1181 case SAR_OBJ_TYPE_GROUND:
1182 obj_ground_ptr = SAR_OBJ_GET_GROUND(obj_ptr);
1183 break;
1184 case SAR_OBJ_TYPE_RUNWAY:
1185 case SAR_OBJ_TYPE_HELIPAD:
1186 break;
1187 case SAR_OBJ_TYPE_HUMAN:
1188 obj_human_ptr = SAR_OBJ_GET_HUMAN(obj_ptr);
1189 break;
1190 case SAR_OBJ_TYPE_SMOKE:
1191 obj_smoke_ptr = SAR_OBJ_GET_SMOKE(obj_ptr);
1192 if(obj_smoke_ptr != NULL)
1193 {
1194 obj_smoke_ptr->respawn_next = 0l;
1195 }
1196 break;
1197 case SAR_OBJ_TYPE_FIRE:
1198 obj_fire_ptr = SAR_OBJ_GET_FIRE(obj_ptr);
1199 if(obj_fire_ptr != NULL)
1200 {
1201 obj_fire_ptr->next_frame_inc = 0l;
1202 }
1203 break;
1204 case SAR_OBJ_TYPE_EXPLOSION:
1205 obj_explosion_ptr = SAR_OBJ_GET_EXPLOSION(obj_ptr);
1206 if(obj_explosion_ptr != NULL)
1207 {
1208 obj_explosion_ptr->next_frame_inc = 0l;
1209 }
1210 break;
1211 case SAR_OBJ_TYPE_CHEMICAL_SPRAY:
1212 case SAR_OBJ_TYPE_FUELTANK:
1213 case SAR_OBJ_TYPE_PREMODELED:
1214 break;
1215 }
1216
1217 /* Lights */
1218 if(obj_ptr->light != NULL)
1219 {
1220 int n;
1221 sar_light_struct *light;
1222
1223 for(n = 0; n < obj_ptr->total_lights; n++)
1224 {
1225 light = obj_ptr->light[n];
1226 if(light == NULL)
1227 continue;
1228
1229 light->next_off = 0l;
1230 light->next_on = light->int_delay_on;
1231 }
1232 }
1233
1234 /* Add other object common timing values that need to be reset here */
1235
1236 }
1237 }
1238
1239
1240 /*
1241 * SAR initialize.
1242 */
SARInit(int argc,char ** argv)1243 sar_core_struct *SARInit(int argc, char **argv)
1244 {
1245 int i, strc;
1246 const char *s, *arg;
1247 char **strv;
1248 #ifndef __MSW__
1249 const char *s2;
1250 #endif
1251 #ifdef __MSW__
1252 HINSTANCE hInst = GetModuleHandle(NULL);
1253 #endif
1254 sar_color_struct *color;
1255
1256 sar_core_struct *core_ptr;
1257 gw_display_struct *dpy;
1258 sar_option_struct *opt;
1259
1260 const char *display_address = NULL;
1261 const char *font_name = NULL;
1262 Boolean cl_direct_rendering = True;
1263 int cl_fullscreen = 0;
1264 int allow_key_repeat = True;
1265 float aspect_offset = 0.0f;
1266 Boolean startup_no_sound = False;
1267 const char *sound_server_connect_arg = NULL;
1268
1269 Boolean notify_install_local_error = False,
1270 notify_install_local_success = False;
1271
1272 char cwd[PATH_MAX];
1273 char tmp_path[PATH_MAX + NAME_MAX];
1274 char geometry_string[GW_GEOMETRY_STRING_MAX];
1275
1276
1277 /* Set signal callbacks */
1278 signal(SIGINT, SARHandleSignal);
1279 signal(SIGTERM, SARHandleSignal);
1280 signal(SIGSEGV, SARHandleSignal);
1281
1282 /* Seed randon number generator */
1283 srand((unsigned int)time(NULL));
1284
1285 /* Get current working directory */
1286 if(getcwd(cwd, PATH_MAX) != NULL)
1287 cwd[PATH_MAX - 1] = '\0';
1288 else
1289 strcpy(cwd, "/");
1290
1291 *geometry_string = '\0';
1292
1293
1294 /* Reset globals */
1295 cur_millitime = 0;
1296 lapsed_millitime = 0;
1297 time_compensation = 1.0f;
1298 time_compression = 1.0f;
1299
1300
1301 /* Allocate core structure */
1302 core_ptr = SAR_CORE(calloc(1, sizeof(sar_core_struct)));
1303 if(core_ptr == NULL)
1304 return(NULL);
1305
1306 opt = &core_ptr->option;
1307
1308 /* Reset core structure values */
1309 core_ptr->prog_file = NULL;
1310 core_ptr->prog_file_full_path = NULL;
1311
1312 core_ptr->stop_count = 0;
1313
1314 core_ptr->display = NULL;
1315 core_ptr->recorder_address = NULL;
1316 core_ptr->recorder = NULL;
1317 core_ptr->audio_mode_name = NULL;
1318 core_ptr->gctl = NULL;
1319
1320 core_ptr->cur_music_id = -1;
1321 core_ptr->music_ref = NULL;
1322 core_ptr->total_music_refs = 0;
1323 core_ptr->human_data = NULL;
1324 core_ptr->weather_data = NULL;
1325
1326 core_ptr->scene = NULL;
1327 core_ptr->mission = NULL;
1328 core_ptr->object = NULL;
1329 core_ptr->total_objects = 0;
1330
1331 core_ptr->menu = NULL;
1332 core_ptr->total_menus = 0;
1333 core_ptr->cur_menu = 0;
1334 /* Bunch of menu images that we arn't resetting, but we can get away
1335 * with not resetting them.
1336 */
1337
1338 core_ptr->texture_list = NULL;
1339 core_ptr->total_texture_list = 0;
1340
1341 core_ptr->player_stat = NULL;
1342 core_ptr->total_player_stats = 0;
1343
1344 core_ptr->cur_mission_file = NULL;
1345 core_ptr->cur_player_model_file = NULL;
1346 core_ptr->cur_scene_file = NULL;
1347
1348 core_ptr->display_help = 0;
1349
1350 core_ptr->flir = False;
1351
1352 core_ptr->drawmap_objname = NULL;
1353 core_ptr->total_drawmap_objnames = 0;
1354 core_ptr->drawmap_ghc_result = 0.0f;
1355
1356 core_ptr->text_input = NULL;
1357
1358 memset(opt, 0x00, sizeof(sar_option_struct));
1359 memset(&core_ptr->fps, 0x00, sizeof(sar_fps_struct));
1360
1361
1362 /* Reset options to defaults */
1363 opt->menu_backgrounds = True;
1364 opt->menu_change_affects = True;
1365 opt->menu_always_full_redraw = False;
1366 opt->console_quiet = False;
1367 opt->internal_debug = False;
1368 opt->runtime_debug = False;
1369 opt->prioritize_memory = False;
1370 opt->units = SAR_UNITS_ENGLISH;
1371
1372 opt->textured_ground = True;
1373 opt->textured_clouds = True;
1374 opt->textured_objects = True;
1375 opt->atmosphere = True;
1376 opt->dual_pass_depth = True;
1377 opt->prop_wash = True;
1378 opt->smoke_trails = True;
1379 opt->celestial_objects = True;
1380 opt->gl_polygon_offset_factor = -1.9f;
1381 opt->gl_shade_model = GL_SMOOTH;
1382 opt->visibility_max = 4;
1383 opt->rotor_blur_style = SAR_ROTOR_BLUR_CLOCK_RADIAL;
1384 opt->graphics_acceleration = 0.0f;
1385
1386 opt->engine_sounds = False;
1387 opt->event_sounds = False;
1388 opt->voice_sounds = False;
1389 opt->music = False;
1390
1391 opt->sound_priority = SND_PRIORITY_BACKGROUND;
1392
1393 opt->system_time_free_flight = False;
1394
1395 color = &opt->hud_color;
1396 color->a = 1.0f;
1397 color->r = 1.0f;
1398 color->g = 1.0f;
1399 color->b = 1.0f;
1400
1401 color = &opt->message_color;
1402 color->a = 1.0f;
1403 color->r = 1.0f;
1404 color->g = 1.0f;
1405 color->b = 1.0f;
1406
1407 opt->show_hud_text = True;
1408 opt->show_outside_text = True;
1409
1410 opt->explosion_frame_int = SAR_DEF_EXPLOSION_FRAME_INT;
1411 opt->splash_frame_int = SAR_DEF_SPLASH_FRAME_INT;
1412 opt->crash_explosion_life_span = SAR_DEF_CRASH_EXPLOSION_LIFE_SPAN;
1413 opt->fuel_tank_life_span = SAR_DEF_FUEL_TANK_LIFE_SPAN;
1414
1415 opt->rotor_wash_vis_coeff = (float)SAR_DEF_ROTOR_WASH_VIS_COEFF;
1416
1417 opt->gctl_controllers = GCTL_CONTROLLER_KEYBOARD |
1418 GCTL_CONTROLLER_POINTER;
1419 opt->gctl_options = 0;
1420 opt->js_priority = GCTL_JS_PRIORITY_BACKGROUND;
1421
1422 opt->js0_connection = GCTL_JS_CONNECTION_STANDARD;
1423 opt->js1_connection = GCTL_JS_CONNECTION_STANDARD;
1424
1425 opt->js0_btn_rotate = 3;
1426 opt->js0_btn_air_brakes = 6;
1427 opt->js0_btn_wheel_brakes = 0;
1428 opt->js0_btn_zoom_in = 2;
1429 opt->js0_btn_zoom_out = 1;
1430 opt->js0_btn_hoist_up = 5;
1431 opt->js0_btn_hoist_down = 4;
1432
1433 opt->js1_btn_rotate = 3;
1434 opt->js1_btn_air_brakes = 6;
1435 opt->js1_btn_wheel_brakes = 0;
1436 opt->js1_btn_zoom_in = 2;
1437 opt->js1_btn_zoom_out = 1;
1438 opt->js1_btn_hoist_up = 5;
1439 opt->js1_btn_hoist_down = 4;
1440 /*
1441 opt->gctl_js0_axis_roles = GCTL_JS_AXIS_ROLE_PITCH |
1442 GCTL_JS_AXIS_ROLE_BANK;
1443 */
1444 opt->gctl_js0_axis_roles = 0;
1445 opt->gctl_js1_axis_roles = 0;
1446 /*
1447 opt->gctl_js1_axis_roles =
1448 GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER;
1449 */
1450
1451 opt->hoist_contact_expansion_coeff = 1.0f;
1452 opt->damage_resistance_coeff = 1.0f;
1453 opt->flight_physics_level = FLIGHT_PHYSICS_REALISTIC; /* Make it hard */
1454
1455 opt->last_selected_player = 0;
1456 opt->last_selected_mission = 0;
1457 opt->last_selected_ffscene = 0;
1458 opt->last_selected_ffaircraft = 0;
1459 opt->last_selected_ffweather = 0;
1460 opt->last_x = 0;
1461 opt->last_y = 0;
1462 opt->last_width = SAR_DEF_WINDOW_WIDTH;
1463 opt->last_height = SAR_DEF_WINDOW_HEIGHT;
1464 opt->last_fullscreen = False;
1465
1466
1467 /* Set local game directory */
1468 #ifdef __MSW__
1469 strncpy(dname.local_data, cwd, PATH_MAX);
1470 #else
1471 s = getenv("HOME");
1472 if(s == NULL)
1473 s = cwd;
1474 s2 = PrefixPaths(s, SAR_DEF_LOCAL_DATA_DIR);
1475 strncpy(
1476 dname.local_data,
1477 (s2 != NULL) ? s2 : cwd,
1478 PATH_MAX
1479 );
1480 #endif
1481 dname.local_data[PATH_MAX - 1] = '\0';
1482
1483 /* Set global game directory */
1484 #if defined(__MSW__)
1485 strncpy(dname.global_data, cwd, PATH_MAX);
1486 #else
1487 s = getenv(SAR_DEF_ENV_GLOBAL_DIR);
1488 if(s != NULL)
1489 {
1490 struct stat stat_buf;
1491
1492 if(!ISPATHABSOLUTE(s))
1493 fprintf(
1494 stderr,
1495 "Warning: Environment variable \"%s\" value \"%s\" must be an absolute path.\n",
1496 SAR_DEF_ENV_GLOBAL_DIR, s
1497 );
1498 if(stat(s, &stat_buf))
1499 fprintf(
1500 stderr,
1501 "Warning: Environment variable \"%s\" value \"%s\" reffers to a non-existant object.\n",
1502 SAR_DEF_ENV_GLOBAL_DIR, s
1503 );
1504 }
1505 strncpy(
1506 dname.global_data,
1507 (s != NULL) ? s : SAR_DEF_GLOBAL_DATA_DIR,
1508 PATH_MAX
1509 );
1510 #endif
1511 dname.global_data[PATH_MAX - 1] = '\0';
1512
1513 /* Set default configuration file */
1514 s = PrefixPaths(dname.local_data, SAR_DEF_OPTIONS_FILE);
1515 strncpy(
1516 fname.options,
1517 (s != NULL) ? s : SAR_DEF_OPTIONS_FILE,
1518 PATH_MAX + NAME_MAX
1519 );
1520 fname.options[PATH_MAX + NAME_MAX - 1] = '\0';
1521
1522 /* Set default global human data presets file */
1523 s = PrefixPaths(dname.global_data, SAR_DEF_HUMAN_FILE);
1524 strncpy(
1525 fname.human,
1526 (s != NULL) ? s : SAR_DEF_HUMAN_FILE,
1527 PATH_MAX + NAME_MAX
1528 );
1529 fname.human[PATH_MAX + NAME_MAX - 1] = '\0';
1530
1531 /* Set default global music data presets file */
1532 s = PrefixPaths(dname.global_data, SAR_DEF_MUSIC_FILE);
1533 strncpy(
1534 fname.music,
1535 (s != NULL) ? s : SAR_DEF_MUSIC_FILE,
1536 PATH_MAX + NAME_MAX
1537 );
1538 fname.music[PATH_MAX + NAME_MAX - 1] = '\0';
1539
1540 /* Set default global textures list file */
1541 s = PrefixPaths(dname.global_data, SAR_DEF_TEXTURES_FILE);
1542 strncpy(
1543 fname.textures,
1544 (s != NULL) ? s : SAR_DEF_TEXTURES_FILE,
1545 PATH_MAX + NAME_MAX
1546 );
1547 fname.textures[PATH_MAX + NAME_MAX - 1] = '\0';
1548
1549 /* Set default players list file */
1550 s = PrefixPaths(dname.local_data, SAR_DEF_PLAYERS_FILE);
1551 strncpy(
1552 fname.players,
1553 (s != NULL) ? s : SAR_DEF_PLAYERS_FILE,
1554 PATH_MAX + NAME_MAX
1555 );
1556 fname.players[PATH_MAX + NAME_MAX - 1] = '\0';
1557
1558 /* Set default global weather data presets file */
1559 s = PrefixPaths(dname.global_data, SAR_DEF_WEATHER_FILE);
1560 strncpy(
1561 fname.weather,
1562 (s != NULL) ? s : SAR_DEF_WEATHER_FILE,
1563 PATH_MAX + NAME_MAX
1564 );
1565 fname.weather[PATH_MAX + NAME_MAX - 1] = '\0';
1566
1567 /* Set default path to mission log file */
1568 s = PrefixPaths(dname.local_data, SAR_DEF_MISSION_LOG_FILE);
1569 strncpy(
1570 fname.mission_log,
1571 (s != NULL) ? s : SAR_DEF_MISSION_LOG_FILE,
1572 PATH_MAX + NAME_MAX
1573 );
1574 fname.mission_log[PATH_MAX + NAME_MAX - 1] = '\0';
1575
1576
1577 /* Parse arguments */
1578 #ifdef __MSW__
1579 /* Win32 parse arguments starting from index 0 */
1580 for(i = 0; i < argc; i++)
1581 #else
1582 for(i = 1; i < argc; i++)
1583 #endif
1584 {
1585 arg = argv[i];
1586 if(arg == NULL)
1587 continue;
1588
1589 /* Run time debug */
1590 if(!strcasecmp(arg, "--runtime-debug") ||
1591 !strcasecmp(arg, "-runtime-debug") ||
1592 !strcasecmp(arg, "--runtime_debug") ||
1593 !strcasecmp(arg, "-runtime_debug")
1594 )
1595 {
1596 opt->runtime_debug = True;
1597 }
1598 /* Help */
1599 else if(!strcasecmp(arg, "--help") ||
1600 !strcasecmp(arg, "-help") ||
1601 !strcasecmp(arg, "-h") ||
1602 !strcasecmp(arg, "-?") ||
1603 !strcasecmp(arg, "/h") ||
1604 !strcasecmp(arg, "/?") ||
1605 !strcasecmp(arg, "?")
1606 )
1607 {
1608 /* Print help message */
1609 printf(PROG_USAGE_MESG);
1610 return(NULL);
1611 }
1612 /* Version */
1613 else if(!strcasecmp(arg, "--version") ||
1614 !strcasecmp(arg, "-version")
1615 )
1616 {
1617 /* Print program version and copyright */
1618 printf(
1619 PROG_NAME_FULL " Version " PROG_VERSION "\n"
1620 PROG_COPYRIGHT "\n"
1621 );
1622 return(NULL);
1623 }
1624 /* Configuration File */
1625 else if(!strcasecmp(arg, "--config") ||
1626 !strcasecmp(arg, "-config") ||
1627 !strcasecmp(arg, "--rcfile") ||
1628 !strcasecmp(arg, "-rcfile") ||
1629 !strcasecmp(arg, "-f")
1630 )
1631 {
1632 i++;
1633 arg = (i < argc) ? argv[i] : NULL;
1634 if(arg != NULL)
1635 {
1636 const char *path = PathSubHome(arg);
1637 if(path == NULL)
1638 path = arg;
1639 strncpy(tmp_path, path, PATH_MAX + NAME_MAX);
1640 tmp_path[PATH_MAX + NAME_MAX - 1] = '\0';
1641
1642 if(!ISPATHABSOLUTE(tmp_path))
1643 {
1644 path = PrefixPaths(cwd, tmp_path);
1645 if(path != NULL)
1646 {
1647 strncpy(tmp_path, path, PATH_MAX + NAME_MAX);
1648 tmp_path[PATH_MAX + NAME_MAX - 1] = '\0';
1649 }
1650 }
1651
1652 strncpy(fname.options, tmp_path, PATH_MAX + NAME_MAX);
1653 fname.options[PATH_MAX + NAME_MAX - 1] = '\0';
1654 }
1655 else
1656 {
1657 fprintf(
1658 stderr,
1659 "%s: Requires argument.\n",
1660 argv[i - 1]
1661 );
1662 }
1663 }
1664 /* Control */
1665 else if(!strcasecmp(arg, "--control") ||
1666 !strcasecmp(arg, "-control") ||
1667 !strcasecmp(arg, "-c")
1668 )
1669 {
1670 i++;
1671 arg = (i < argc) ? argv[i] : NULL;
1672 if(arg != NULL)
1673 {
1674 const char *controller = arg;
1675
1676 /* Joystick */
1677 if(strcasepfx(controller, "j"))
1678 opt->gctl_controllers = GCTL_CONTROLLER_KEYBOARD |
1679 GCTL_CONTROLLER_POINTER | GCTL_CONTROLLER_JOYSTICK;
1680 /* Keyboard */
1681 else if(strcasepfx(controller, "k"))
1682 opt->gctl_controllers = GCTL_CONTROLLER_KEYBOARD |
1683 GCTL_CONTROLLER_POINTER;
1684 else
1685 fprintf(
1686 stderr,
1687 "%s: Unsupported argument `%s'\n",
1688 argv[i - 1], controller
1689 );
1690 }
1691 else
1692 {
1693 fprintf(
1694 stderr,
1695 "%s: Requires argument.\n",
1696 argv[i - 1]
1697 );
1698 }
1699 }
1700 /* Software rendering? */
1701 else if(!strcasecmp(arg, "--software_rendering") ||
1702 !strcasecmp(arg, "-software_rendering") ||
1703 !strcasecmp(arg, "--software-rendering") ||
1704 !strcasecmp(arg, "-software-rendering") ||
1705 !strcasecmp(arg, "--softwarerendering") ||
1706 !strcasecmp(arg, "-softwarerendering") ||
1707 !strcasecmp(arg, "--software") ||
1708 !strcasecmp(arg, "-software")
1709 )
1710 {
1711 cl_direct_rendering = False;
1712 }
1713 /* Always Full Menu Redraws */
1714 else if(!strcasecmp(arg, "--full_menu_redraw") ||
1715 !strcasecmp(arg, "--full-menu-redraw") ||
1716 !strcasecmp(arg, "-full_menu_redraw") ||
1717 !strcasecmp(arg, "-full-menu-redraw")
1718 )
1719 {
1720 opt->menu_always_full_redraw = True;
1721 }
1722 /* Display (connection to X server) */
1723 else if(!strcasecmp(arg, "--display") ||
1724 !strcasecmp(arg, "-display") ||
1725 !strcasecmp(arg, "--dpy") ||
1726 !strcasecmp(arg, "-dpy")
1727 )
1728 {
1729 i++;
1730 arg = (i < argc) ? argv[i] : NULL;
1731 if(arg != NULL)
1732 {
1733 display_address = arg;
1734 }
1735 else
1736 {
1737 fprintf(
1738 stderr,
1739 "%s: Requires argument.\n",
1740 argv[i - 1]
1741 );
1742 }
1743 }
1744 /* Full screen */
1745 else if(!strcasecmp(arg, "--full_screen") ||
1746 !strcasecmp(arg, "-full_screen") ||
1747 !strcasecmp(arg, "--fullscreen") ||
1748 !strcasecmp(arg, "-fullscreen")
1749 )
1750 {
1751 cl_fullscreen = 1;
1752 }
1753 else if ( (!strcasecmp(arg, "--window") ) ||
1754 (!strcasecmp(arg, "-window") ) )
1755 {
1756 cl_fullscreen = 2;
1757 }
1758 else if ( (!strcasecmp(arg, "--no-keyrepeat") ) ||
1759 (!strcasecmp(arg, "--no-autorepeat") ) )
1760 {
1761 allow_key_repeat = False;
1762 }
1763
1764 /* Font (font name for XFonts, X only) */
1765 else if(!strcasecmp(arg, "--font") ||
1766 !strcasecmp(arg, "-font") ||
1767 !strcasecmp(arg, "--fn") ||
1768 !strcasecmp(arg, "-fn")
1769 )
1770 {
1771 i++;
1772 arg = (i < argc) ? argv[i] : NULL;
1773 if(arg != NULL)
1774 {
1775 font_name = arg;
1776 }
1777 else
1778 {
1779 fprintf(
1780 stderr,
1781 "%s: Requires argument.\n",
1782 argv[i - 1]
1783 );
1784 }
1785 }
1786 /* Geometry (position and size of toplevel window) */
1787 else if(!strcasecmp(arg, "--geometry") ||
1788 !strcasecmp(arg, "-geometry")
1789 )
1790 {
1791 i++;
1792 arg = (i < argc) ? argv[i] : NULL;
1793 if(arg != NULL)
1794 {
1795 strncpy(geometry_string, arg, GW_GEOMETRY_STRING_MAX);
1796 geometry_string[GW_GEOMETRY_STRING_MAX - 1] = '\0';
1797 }
1798 else
1799 {
1800 fprintf(
1801 stderr,
1802 "%s: Requires argument.\n",
1803 argv[i - 1]
1804 );
1805 }
1806 }
1807 /* Aspect offset */
1808 else if(!strcasecmp(arg, "--aspect_offset") ||
1809 !strcasecmp(arg, "-aspect_offset") ||
1810 !strcasecmp(arg, "--aspect-offset") ||
1811 !strcasecmp(arg, "-aspect-offset") ||
1812 !strcasecmp(arg, "--aspectoffset") ||
1813 !strcasecmp(arg, "-aspectoffset")
1814 )
1815 {
1816 i++;
1817 arg = (i < argc) ? argv[i] : NULL;
1818 if(arg != NULL)
1819 {
1820 aspect_offset = ATOF(arg);
1821 }
1822 else
1823 {
1824 fprintf(
1825 stderr,
1826 "%s: Requires argument.\n",
1827 argv[i - 1]
1828 );
1829 }
1830 }
1831 /* Recorder */
1832 else if(!strcasecmp(arg, "--recorder") ||
1833 !strcasecmp(arg, "-recorder")
1834 )
1835 {
1836 i++;
1837 arg = (i < argc) ? argv[i] : NULL;
1838 if(arg != NULL)
1839 {
1840 sound_server_connect_arg = arg;
1841 }
1842 else
1843 {
1844 fprintf(
1845 stderr,
1846 "%s: Requires argument.\n",
1847 argv[i - 1]
1848 );
1849 }
1850 }
1851 /* No sound */
1852 else if(!strcasecmp(arg, "--no_sound") ||
1853 !strcasecmp(arg, "--nosound") ||
1854 !strcasecmp(arg, "-no_sound") ||
1855 !strcasecmp(arg, "-nosound")
1856 )
1857 {
1858 startup_no_sound = True;
1859 }
1860 /* No menu backgrounds */
1861 else if(!strcasecmp(arg, "--nomenubackgrounds") ||
1862 !strcasecmp(arg, "--nomenubackground") ||
1863 !strcasecmp(arg, "--nomenubkg") ||
1864 !strcasecmp(arg, "--nomenubg") ||
1865 !strcasecmp(arg, "-nomenubackgrounds") ||
1866 !strcasecmp(arg, "-nomenubackground") ||
1867 !strcasecmp(arg, "-nomenubkg") ||
1868 !strcasecmp(arg, "-nomenubg")
1869 )
1870 {
1871 opt->menu_backgrounds = False;
1872 }
1873
1874 }
1875
1876
1877 /* Check if program has been installed globally.
1878 * Win32 note this will be the same as installed locally.
1879 */
1880 if(!SARIsInstalledGlobal(&dname, &fname))
1881 {
1882 /* Not globally installed so it is a critical error */
1883 fprintf(
1884 stderr,
1885 PROG_NAME_FULL " was unable to find the data files in:\n\
1886 \n\
1887 %s\n",
1888 dname.global_data
1889 );
1890 fprintf(
1891 stderr,
1892 "Please verify that you have installed the program properly. If you \
1893 have installed the global data files in a non-standard location, \
1894 then you should set the environment variable \"%s\" to refer to that \
1895 non-standard location.\n",
1896 SAR_DEF_ENV_GLOBAL_DIR
1897 );
1898 free(core_ptr);
1899 return(NULL);
1900 }
1901 /* Check if program is installed locally */
1902 if(!SARIsInstalledLocal(&dname, &fname))
1903 {
1904 /* Not locally installed, so install from global */
1905 if(SARDoInstallLocal(&dname, &fname, opt))
1906 {
1907 fprintf(
1908 stderr,
1909 PROG_NAME_FULL " was unable to complete the installation of local data files in:\n\
1910 \n\
1911 %s\n",
1912 dname.local_data
1913 );
1914 notify_install_local_error = True;
1915 }
1916 else
1917 {
1918 notify_install_local_success = True;
1919 }
1920 }
1921
1922 /* Load values from configuration file */
1923 if(SAROptionsLoadFromFile(opt, fname.options))
1924 {
1925 fprintf(
1926 stderr,
1927 "%s: Warning: Error occured while loading configuration.\n",
1928 fname.options
1929 );
1930 }
1931
1932 /* Record program file name */
1933 #ifdef __MSW__
1934 if(hInst != NULL)
1935 {
1936 char prog[PATH_MAX];
1937 GetModuleFileName(hInst, prog, sizeof(prog));
1938
1939 s = strrchr(prog, DIR_DELIMINATOR);
1940 if(s != NULL)
1941 s++;
1942 else
1943 s = prog;
1944
1945 free(core_ptr->prog_file_full_path);
1946 core_ptr->prog_file_full_path = STRDUP(prog);
1947
1948 free(core_ptr->prog_file);
1949 core_ptr->prog_file = STRDUP(s);
1950 }
1951 #else
1952 arg = (argc > 0) ? argv[0] : NULL;
1953 if(arg != NULL)
1954 {
1955 s = strrchr(arg, DIR_DELIMINATOR);
1956 if(s != NULL)
1957 s++;
1958 else
1959 s = arg;
1960
1961 free(core_ptr->prog_file_full_path);
1962 core_ptr->prog_file_full_path = STRDUP(arg);
1963
1964 free(core_ptr->prog_file);
1965 core_ptr->prog_file = STRDUP(s);
1966 }
1967 #endif
1968
1969 /* Set up arguments for initializing the graphics wrapper */
1970 strc = 11;
1971 strv = (char **)calloc(strc, sizeof(char *));
1972 strv[0] = STRDUP(cl_direct_rendering ?
1973 "--hardware_rendering" : "--software_rendering"
1974 );
1975 strv[1] = STRDUP("--geometry");
1976 if(*geometry_string == '\0')
1977 sprintf(
1978 geometry_string,
1979 "%ix%i%s%i%s%i",
1980 opt->last_width,
1981 opt->last_height,
1982 ((opt->last_x < 0) ? "" : "+"),
1983 opt->last_x,
1984 ((opt->last_y < 0) ? "" : "+"),
1985 opt->last_y
1986 );
1987 strv[2] = STRDUP(geometry_string);
1988 strv[3] = STRDUP("--title");
1989 strv[4] = STRDUP(PROG_NAME_FULL);
1990 strv[5] = STRDUP("--icon_path");
1991 strv[6] = STRDUP(SAR_DEF_SAR_ICON_FILE);
1992 strv[7] = STRDUP("--icon_name");
1993 strv[8] = STRDUP(PROG_NAME_FULL);
1994 if(cl_fullscreen == 1)
1995 strv[9] = STRDUP("--full_screen");
1996 else if (cl_fullscreen == 2)
1997 {
1998 strv[9] = STRDUP("--window");
1999 opt->last_fullscreen = False;
2000 }
2001 else
2002 strv[9] = STRDUP(opt->last_fullscreen ?
2003 "--fullscreen" : "--windowed"
2004 );
2005 if (! allow_key_repeat)
2006 strv[10] = STRDUP("--no-keyrepeat");
2007
2008 if(!STRISEMPTY(display_address))
2009 {
2010 int n = strc;
2011 strv = (char **)realloc(strv, strc * sizeof(char *));
2012 strv[n + 0] = STRDUP("--display");
2013 strv[n + 1] = STRDUP(display_address);
2014 }
2015 if(aspect_offset != 0.0)
2016 {
2017 int n = strc;
2018 char num_str[80];
2019 sprintf(num_str, "%f", aspect_offset);
2020 strc = n + 2;
2021 strv = (char **)realloc(strv, strc * sizeof(char *));
2022 strv[n + 0] = STRDUP("--aspect_offset");
2023 strv[n + 1] = STRDUP(num_str);
2024 }
2025 if(opt->runtime_debug)
2026 {
2027 int n = strc;
2028 strc = n + 1;
2029 strv = (char **)realloc(strv, strc * sizeof(char *));
2030 strv[n + 0] = STRDUP("--gw_debug");
2031 }
2032 if(font_name != NULL)
2033 {
2034 int n = strc;
2035 strc = n + 2;
2036 strv = (char **)realloc(strv, strc * sizeof(char *));
2037 strv[n + 0] = STRDUP("--font");
2038 strv[n + 1] = STRDUP(font_name);
2039 }
2040
2041 /* Initialize graphics erapper */
2042 core_ptr->display = GWInit(strc, strv);
2043
2044 /* Delete arguments used in initializing graphics wrapper */
2045 strlistfree(strv, strc);
2046 strv = NULL;
2047 strc = 0;
2048
2049 /* Failed to initialize graphics wrapper? */
2050 if(core_ptr->display == NULL)
2051 {
2052 SARShutdown(core_ptr);
2053 return(NULL);
2054 }
2055 dpy = core_ptr->display;
2056
2057 /* Check if we have OpenGL 1.1 or newer */
2058 if((dpy->gl_version_major < 1) ?
2059 True : ((dpy->gl_version_major == 1) ?
2060 (dpy->gl_version_minor < 1) : False)
2061 )
2062 {
2063 fprintf(
2064 stderr,
2065 PROG_NAME_FULL " requires OpenGL version 1.1 or newer, the current \
2066 version that was detected is OpenGL version %i.%i.\n",
2067 dpy->gl_version_major,
2068 dpy->gl_version_minor
2069 );
2070 }
2071
2072 /* Check if we have alpha bits */
2073 if(dpy->alpha_channel_bits <= 0)
2074 {
2075 fprintf(
2076 stderr,
2077 PROG_NAME_FULL " requires an alpha channel, the current alpha channel \
2078 that was detected is 0 bits in size.\n"
2079 );
2080 }
2081
2082 /* Set font data references */
2083 opt->hud_font = font_6x10; /* For HUD text */
2084 opt->message_font = font_7x14; /* For standard/misc messages */
2085 opt->menu_font = font_menu; /* For menus (except for menu values */
2086 opt->banner_font = font_banner; /* For the sticky banner messages */
2087
2088 /* Set graphics wrapper options */
2089 GWSetDrawCB(dpy, SARDrawCB, core_ptr);
2090 GWSetKeyboardCB(dpy, SARKeyBoardCB, core_ptr);
2091 GWSetPointerCB(dpy, SARPointerCB, core_ptr);
2092 GWSetResizeCB(dpy, SARReshapeCB, core_ptr);
2093 GWSetVisibilityCB(dpy, SARVisibilityCB, core_ptr);
2094 GWSetSaveYourselfCB(dpy, SARSaveYourselfCB, core_ptr);
2095 GWSetCloseCB(dpy, SARCloseCB, core_ptr);
2096 GWSetTimeoutCB(dpy, SARManage, core_ptr);
2097
2098
2099 /* Do splash */
2100 SARSplash(core_ptr);
2101
2102
2103 /* Set audio mode name for changing of sound server audio mode */
2104 free(core_ptr->audio_mode_name);
2105 core_ptr->audio_mode_name = STRDUP("PlayStereo11025");
2106
2107 /* Initialize sound wrapper */
2108 if (startup_no_sound) /* ||
2109 (!opt->engine_sounds &&
2110 !opt->event_sounds &&
2111 !opt->voice_sounds &&
2112 !opt->music
2113 )
2114 ) */
2115 {
2116 /* Do not initialize sound and turn all sound options off */
2117 core_ptr->recorder = NULL;
2118 opt->engine_sounds = False;
2119 opt->event_sounds = False;
2120 opt->voice_sounds = False;
2121 opt->music = False;
2122 }
2123 else
2124 {
2125 void *window;
2126 int type = SNDSERV_TYPE_NONE; // use this as default
2127
2128 #ifdef Y_H
2129 type = SNDSERV_TYPE_Y;
2130 #endif
2131 #ifdef SDL_H
2132 type = SNDSERV_TYPE_SDL; // hopefully we use this
2133 #endif
2134
2135 GWContextGet(
2136 dpy, GWContextCurrent(dpy),
2137 &window, NULL,
2138 NULL, NULL,
2139 NULL, NULL
2140 );
2141 core_ptr->recorder = SoundInit(
2142 core_ptr,
2143 type,
2144 sound_server_connect_arg, /* Connect argument */
2145 NULL, /* Start argument */
2146 window /* Toplevel window */
2147 );
2148
2149 if(core_ptr->recorder == NULL)
2150 {
2151 fprintf(
2152 stderr,
2153 PROG_NAME_FULL " could not connect to the Sound Server, please check \
2154 if the Sound Server is currently running.\n"
2155 );
2156
2157 opt->engine_sounds = False;
2158 opt->event_sounds = False;
2159 opt->voice_sounds = False;
2160 opt->music = False;
2161 }
2162 #ifdef Y_H
2163 else
2164 {
2165 /* Change Y audio mode */
2166 SoundChangeMode(
2167 core_ptr->recorder, core_ptr->audio_mode_name
2168 );
2169
2170 /* Update recorder address */
2171 if(sound_server_connect_arg != NULL)
2172 {
2173 free(core_ptr->recorder_address);
2174 core_ptr->recorder_address = STRDUP(sound_server_connect_arg);
2175 }
2176 }
2177 #endif
2178 }
2179
2180
2181 /* Initialize game controller
2182 *
2183 * Game controller options need to be set up properly prior to
2184 * this call
2185 */
2186 SARInitGCTL(core_ptr);
2187
2188
2189 /* Load global texture reference names list (these contain only
2190 * names and file names of textures to be loaded when a scene
2191 * is loaded)
2192 */
2193 SARTextureListLoadFromFile(
2194 fname.textures,
2195 &core_ptr->texture_list,
2196 &core_ptr->total_texture_list
2197 );
2198
2199 /* Initialize predefined humans list */
2200 core_ptr->human_data = SARHumanPresetsInit(core_ptr);
2201 if(core_ptr->human_data == NULL)
2202 {
2203 fprintf(
2204 stderr,
2205 "Error initializing human presets data.\n"
2206 );
2207 }
2208 /* Load predefined humans list from file */
2209 SARHumanLoadFromFile(
2210 core_ptr->human_data,
2211 fname.human
2212 );
2213
2214 /* Reset current music ID so that the music will restart after
2215 * the music list is loaded from file
2216 */
2217 core_ptr->cur_music_id = -1;
2218 /* Load music list from file */
2219 SARMusicListLoadFromFile(
2220 fname.music,
2221 &core_ptr->music_ref, &core_ptr->total_music_refs
2222 );
2223
2224 /* Initialize predefined weather conditions */
2225 core_ptr->weather_data = SARWeatherPresetsInit(core_ptr);
2226 if(core_ptr->weather_data == NULL)
2227 {
2228 fprintf(
2229 stderr,
2230 "Error initializing weather presets data.\n"
2231 );
2232 }
2233 /* Load predefined weather conditions from file */
2234 SARWeatherLoadFromFile(
2235 core_ptr->weather_data,
2236 fname.weather
2237 );
2238
2239 /* Load players list */
2240 SARPlayerStatsLoadFromFile(
2241 &core_ptr->player_stat,
2242 &core_ptr->total_player_stats,
2243 fname.players
2244 );
2245
2246
2247
2248 /* Reset GL states for menu system */
2249 SARMenuGLStateReset(core_ptr->display);
2250
2251 /* Create all menu system resources and each menu */
2252 SARBuildMenus(core_ptr);
2253
2254 /* Force select the main menu */
2255 core_ptr->cur_menu = -1;
2256 SARMenuSwitchToMenu(core_ptr, SAR_MENU_NAME_MAIN);
2257
2258 /* Text input prompt */
2259 core_ptr->text_input = SARTextInputNew(
2260 core_ptr->display, opt->message_font
2261 );
2262
2263 /* Print messages as needed */
2264 if(notify_install_local_error)
2265 {
2266 char mesg[1024];
2267
2268 sprintf(mesg,
2269 "Cannot install local data files to:\n%s",
2270 dname.local_data
2271 );
2272
2273 GWOutputMessage(
2274 dpy, GWOutputMessageTypeError,
2275 "Installation Error",
2276 mesg,
2277 "There was a problem installing local data files, make sure that\n\
2278 global data for this program has been installed properly and that\n\
2279 your home directory exists and has has write permission for this program"
2280 );
2281 }
2282 else if(notify_install_local_success)
2283 {
2284 char mesg[1024];
2285
2286 sprintf(mesg,
2287 "Local data files for this program have been\ninstalled in:\n\n%s",
2288 dname.local_data
2289 );
2290
2291 GWOutputMessage(
2292 dpy, GWOutputMessageTypeGeneral,
2293 "Local Data Files Installed",
2294 mesg,
2295 "The data files needed by this program have been installed, this\n\
2296 occured because the program needs them and they were not detected\n\
2297 to exist before."
2298 );
2299 }
2300
2301 return(core_ptr);
2302 }
2303
2304 /*
2305 * SAR management, this is called once per loop as the timeout
2306 * function.
2307 *
2308 * The graphics wrapper normally calls this function on timeouts.
2309 */
SARManage(void * ptr)2310 void SARManage(void *ptr)
2311 {
2312 int status;
2313 int cur_menu;
2314 time_t t_new;
2315 sar_scene_struct *scene;
2316 sar_core_struct *core_ptr = SAR_CORE(ptr);
2317 const sar_option_struct *opt;
2318 if(core_ptr == NULL)
2319 return;
2320
2321 opt = &core_ptr->option;
2322
2323 /* Get current time in milliseconds */
2324 t_new = SARGetCurMilliTime();
2325
2326 /* Check if the new current time has "warped" to a smaller value
2327 * than the previous current time.
2328 */
2329 if(t_new < cur_millitime)
2330 {
2331 /* Timing has cycled, so we need to reset all timmers */
2332 SARResetTimmersCB(core_ptr, t_new);
2333 }
2334 else
2335 {
2336 /* Calculate lapsed ms from last loop */
2337 lapsed_millitime = t_new - cur_millitime;
2338
2339 /* Calculate time compensation coeff */
2340 time_compensation = (float)CLIP(
2341 (float)lapsed_millitime / (float)CYCLE_LAPSE_MS,
2342 0.0, 1000.0
2343 );
2344
2345 /* Set new current time in ms */
2346 cur_millitime = t_new;
2347 }
2348
2349 /* Get current systime seconds */
2350 cur_systime = time(NULL);
2351
2352
2353 /* Get new game controller positions */
2354 GCtlUpdate(
2355 core_ptr->gctl,
2356 (Boolean)((opt->flight_physics_level != FLIGHT_PHYSICS_REALISTIC) ? True : False), /* Heading nullzone? */
2357 (Boolean)((opt->flight_physics_level == FLIGHT_PHYSICS_EASY) ? True : False), /* Pitch nullzone? */
2358 (Boolean)((opt->flight_physics_level == FLIGHT_PHYSICS_EASY) ? True : False), /* Bank nullzone? */
2359 cur_millitime, lapsed_millitime, time_compensation
2360 );
2361
2362
2363 /* Check if a current menu is allocated (hence selected) */
2364 cur_menu = core_ptr->cur_menu;
2365 if(SARIsMenuAllocated(core_ptr, cur_menu))
2366 {
2367 /* A menu is selected which implies that we are in the
2368 * menus. Get current menu to see which menu we're
2369 * currently on.
2370 */
2371 SARMenuManage(core_ptr, core_ptr->menu[cur_menu]);
2372 }
2373 else
2374 {
2375 /* No menu selected, this implies we are in game and
2376 * as such we need to handle simulation updates and
2377 * redraw.
2378 */
2379 scene = core_ptr->scene;
2380
2381 SARSimUpdateScene(core_ptr, scene);
2382 SARSimUpdateSceneObjects(core_ptr, scene);
2383
2384 if(is_visible)
2385 SARDraw(core_ptr);
2386
2387 /* Manage mission */
2388 status = SARMissionManage(core_ptr);
2389 /* Check mission manage result */
2390 switch(status)
2391 {
2392 case 1:
2393 /* Mission ended with success, end simulation and
2394 * tabulate mission results.
2395 */
2396 SARSimEnd(core_ptr);
2397 break;
2398
2399 case 2:
2400 /* Mission over and failed. Do not call SARSimEnd(),
2401 * instead let user respond to failed message and
2402 * manually end mission.
2403 */
2404 break;
2405
2406 case -1:
2407 /* Mission management error */
2408 break;
2409
2410 default:
2411 /* Nothing eventful */
2412 break;
2413 }
2414 }
2415
2416 /* Manage sound events if connected to recorder */
2417 if(core_ptr->recorder != NULL)
2418 {
2419 /* Manage sound events. If return is negative then that
2420 * means the recorder pointer is no longer valid.
2421 */
2422 status = SoundManageEvents(core_ptr->recorder);
2423 if(status < 0)
2424 core_ptr->recorder = NULL;
2425 }
2426
2427 /* Update music, checks the current run time situation and
2428 * changes the music as needed.
2429 */
2430 SARMusicUpdate(core_ptr);
2431
2432 }
2433
2434 /*
2435 * Deletes the Core.
2436 */
SARShutdown(sar_core_struct * core_ptr)2437 void SARShutdown(sar_core_struct *core_ptr)
2438 {
2439 const char *s;
2440 sar_option_struct *opt;
2441
2442 if(core_ptr == NULL)
2443 return;
2444
2445 opt = &core_ptr->option;
2446
2447 /* Save options */
2448 s = fname.options;
2449 if(!STRISEMPTY(s))
2450 {
2451 if(SAROptionsSaveToFile(opt, s))
2452 fprintf(
2453 stderr,
2454 "%s: Warning: Error occured while saving options.\n",
2455 s
2456 );
2457 }
2458 /* Save players list */
2459 s = fname.players;
2460 if(!STRISEMPTY(s))
2461 {
2462 if(SARPlayerStatsSaveToFile(
2463 core_ptr->player_stat, core_ptr->total_player_stats,
2464 s
2465 ))
2466 fprintf(
2467 stderr,
2468 "%s: Warning: Error occured while saving pilots list.\n",
2469 s
2470 );
2471 }
2472
2473
2474 /* Text input */
2475 SARTextInputDelete(core_ptr->text_input);
2476 core_ptr->text_input = NULL;
2477
2478 /* Global texture file reference list */
2479 SARTextureListDeleteAll(
2480 &core_ptr->texture_list,
2481 &core_ptr->total_texture_list
2482 );
2483
2484 /* File names */
2485 free(core_ptr->cur_mission_file);
2486 core_ptr->cur_mission_file = NULL;
2487
2488 free(core_ptr->cur_player_model_file);
2489 core_ptr->cur_player_model_file = NULL;
2490
2491 free(core_ptr->cur_scene_file);
2492 core_ptr->cur_scene_file = NULL;
2493
2494
2495 /* Menus */
2496 if(core_ptr->total_menus > 0)
2497 {
2498 int i, n;
2499 for(i = 0; i < core_ptr->total_menus; i++)
2500 {
2501 sar_menu_struct *m = core_ptr->menu[i];
2502 if(m == NULL)
2503 continue;
2504
2505 /* Iterate through each object on the menu */
2506 for(n = 0; n < m->total_objects; n++)
2507 {
2508 void *o = m->object[n];
2509 if(o == NULL)
2510 continue;
2511
2512 /* Handle by the menu object's type */
2513 switch(SAR_MENU_OBJECT_TYPE(o))
2514 {
2515 case SAR_MENU_OBJECT_TYPE_LABEL:
2516 case SAR_MENU_OBJECT_TYPE_BUTTON:
2517 case SAR_MENU_OBJECT_TYPE_PROGRESS:
2518 case SAR_MENU_OBJECT_TYPE_MESSAGE_BOX:
2519 break;
2520 case SAR_MENU_OBJECT_TYPE_LIST:
2521 {
2522 int j;
2523 sar_menu_list_struct *list = SAR_MENU_LIST(o);
2524 /* Delete list item data */
2525 for(j = 0; j < list->total_items; j++)
2526 SARDeleteListItemData(list->item[j]);
2527 }
2528 break;
2529 case SAR_MENU_OBJECT_TYPE_MDISPLAY:
2530 case SAR_MENU_OBJECT_TYPE_SWITCH:
2531 case SAR_MENU_OBJECT_TYPE_SPIN:
2532 case SAR_MENU_OBJECT_TYPE_SLIDER:
2533 case SAR_MENU_OBJECT_TYPE_MAP:
2534 case SAR_MENU_OBJECT_TYPE_OBJVIEW:
2535 break;
2536 }
2537 }
2538
2539 /* Delete this menu and all its objects */
2540 SARMenuDelete(m);
2541 }
2542 free(core_ptr->menu);
2543 core_ptr->menu = NULL;
2544 core_ptr->cur_menu = 0;
2545 core_ptr->total_menus = 0;
2546 }
2547
2548 /* Begin deleted resources used for the menus, these resources
2549 * may be shared but since all menus are deleted at this
2550 * point it is safe to delete these resources
2551 */
2552
2553 /* Images used by menus */
2554 #define DELETE_IMAGE(_i_) \
2555 { if(*(_i_) != NULL) { SARImageDelete(*(_i_)); *(_i_) = NULL; } }
2556 if(core_ptr->menu_list_bg_img != NULL)
2557 {
2558 int i;
2559 for(i = 0; i < 9; i++)
2560 DELETE_IMAGE(&core_ptr->menu_list_bg_img[i]);
2561 free(core_ptr->menu_list_bg_img);
2562 core_ptr->menu_list_bg_img = NULL;
2563 }
2564
2565 DELETE_IMAGE(&core_ptr->menu_button_armed_img);
2566 DELETE_IMAGE(&core_ptr->menu_button_unarmed_img);
2567 DELETE_IMAGE(&core_ptr->menu_button_highlighted_img);
2568 DELETE_IMAGE(&core_ptr->menu_button_label_img);
2569
2570 DELETE_IMAGE(&core_ptr->menu_label_bg_img);
2571
2572 DELETE_IMAGE(&core_ptr->menu_switch_bg_img);
2573 DELETE_IMAGE(&core_ptr->menu_switch_off_img);
2574 DELETE_IMAGE(&core_ptr->menu_switch_on_img);
2575
2576 DELETE_IMAGE(&core_ptr->menu_spin_label_img);
2577 DELETE_IMAGE(&core_ptr->menu_spin_value_img);
2578 DELETE_IMAGE(&core_ptr->menu_spin_dec_armed_img);
2579 DELETE_IMAGE(&core_ptr->menu_spin_dec_unarmed_img);
2580 DELETE_IMAGE(&core_ptr->menu_spin_inc_armed_img);
2581 DELETE_IMAGE(&core_ptr->menu_spin_inc_unarmed_img);
2582
2583 DELETE_IMAGE(&core_ptr->menu_slider_label_img);
2584 DELETE_IMAGE(&core_ptr->menu_slider_trough_img);
2585 DELETE_IMAGE(&core_ptr->menu_slider_handle_img);
2586
2587 DELETE_IMAGE(&core_ptr->menu_progress_bg_img);
2588 DELETE_IMAGE(&core_ptr->menu_progress_fg_img);
2589
2590 DELETE_IMAGE(&core_ptr->menu_button_pan_up_armed_img);
2591 DELETE_IMAGE(&core_ptr->menu_button_pan_up_unarmed_img);
2592 DELETE_IMAGE(&core_ptr->menu_button_pan_down_armed_img);
2593 DELETE_IMAGE(&core_ptr->menu_button_pan_down_unarmed_img);
2594 DELETE_IMAGE(&core_ptr->menu_button_pan_left_armed_img);
2595 DELETE_IMAGE(&core_ptr->menu_button_pan_left_unarmed_img);
2596 DELETE_IMAGE(&core_ptr->menu_button_pan_right_armed_img);
2597 DELETE_IMAGE(&core_ptr->menu_button_pan_right_unarmed_img);
2598
2599 DELETE_IMAGE(&core_ptr->menu_button_zoom_in_armed_img);
2600 DELETE_IMAGE(&core_ptr->menu_button_zoom_in_unarmed_img);
2601 DELETE_IMAGE(&core_ptr->menu_button_zoom_out_armed_img);
2602 DELETE_IMAGE(&core_ptr->menu_button_zoom_out_unarmed_img);
2603
2604 DELETE_IMAGE(&core_ptr->menumap_helipad_img);
2605 DELETE_IMAGE(&core_ptr->menumap_intercept_img);
2606 DELETE_IMAGE(&core_ptr->menumap_helicopter_img);
2607 DELETE_IMAGE(&core_ptr->menumap_victim_img);
2608 DELETE_IMAGE(&core_ptr->menumap_vessel_img);
2609 DELETE_IMAGE(&core_ptr->menumap_crash_img);
2610
2611 #undef DELETE_IMAGE
2612
2613
2614 /* Delete mission structure (if any). Note that mission should
2615 * have been properly ended and deleted before shutting down
2616 */
2617 SARMissionDelete(core_ptr->mission);
2618 core_ptr->mission = NULL;
2619
2620 /* Delete scene */
2621 SARSceneDestroy(
2622 core_ptr,
2623 core_ptr->scene,
2624 &core_ptr->object,
2625 &core_ptr->total_objects
2626 );
2627 free(core_ptr->scene);
2628 core_ptr->scene = NULL;
2629
2630 /* Draw Map Object Names List */
2631 SARDrawMapObjNameListDelete(
2632 &core_ptr->drawmap_objname,
2633 &core_ptr->total_drawmap_objnames
2634 );
2635
2636 /* Player Stats */
2637 if(core_ptr->total_player_stats > 0)
2638 {
2639 int i;
2640 for(i = 0; i < core_ptr->total_player_stats; i++)
2641 SARPlayerStatDelete(core_ptr->player_stat[i]);
2642 free(core_ptr->player_stat);
2643 core_ptr->player_stat = NULL;
2644 core_ptr->total_player_stats = 0;
2645 }
2646
2647 /* Human Data */
2648 SARHumanPresetsShutdown(core_ptr->human_data);
2649 core_ptr->human_data = NULL;
2650
2651 /* Weather Data */
2652 SARWeatherPresetsShutdown(core_ptr->weather_data);
2653 core_ptr->weather_data = NULL;
2654
2655
2656 /* Game Controller */
2657 GCtlDelete(core_ptr->gctl);
2658 core_ptr->gctl = NULL;
2659
2660 /* Music List */
2661 SARMusicListDeleteAll(&core_ptr->music_ref, &core_ptr->total_music_refs);
2662
2663 /* Sound wrapper */
2664 SoundShutdown(core_ptr->recorder);
2665 core_ptr->recorder = NULL;
2666
2667 free(core_ptr->audio_mode_name);
2668 core_ptr->audio_mode_name = NULL;
2669
2670 free(core_ptr->recorder_address);
2671 core_ptr->recorder_address = NULL;
2672
2673 /* Graphics wrapper */
2674 GWShutdown(core_ptr->display);
2675 core_ptr->display = NULL;
2676
2677 /* Program name */
2678 free(core_ptr->prog_file_full_path);
2679 core_ptr->prog_file_full_path = NULL;
2680 free(core_ptr->prog_file);
2681 core_ptr->prog_file = NULL;
2682
2683 free(core_ptr);
2684 }
2685
2686 #ifdef __MSW__
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)2687 int WINAPI WinMain(
2688 HINSTANCE hInstance, // Instance
2689 HINSTANCE hPrevInstance, // Previous Instance
2690 LPSTR lpCmdLine, // Command Line Parameters
2691 int nCmdShow // Window Show State
2692 )
2693 #else
2694 int main(int argc, char **argv)
2695 #endif
2696 {
2697 #ifdef __MSW__
2698 int argc = 0;
2699 char **argv = strexp(lpCmdLine, &argc);
2700 #endif
2701 sar_core_struct *core_ptr;
2702 const sar_option_struct *opt;
2703
2704
2705 /* Reset globals */
2706 debug_value = 0.0f;
2707 segfault_count = 0;
2708
2709 #ifdef __MSW__
2710 /* Initialize COM loaders (needed for DirectX) */
2711 CoInitialize(NULL);
2712 #endif
2713
2714 /* Initialize program core */
2715 core_ptr = SARInit(argc, argv);
2716 if(core_ptr == NULL)
2717 return(1);
2718 opt = &core_ptr->option;
2719
2720 /* Main loop */
2721 runlevel = 2;
2722 while(runlevel >= 2)
2723 {
2724 #ifdef __MSW__
2725 /* No sleeping for Windows */
2726 #else
2727 usleep(
2728 (unsigned long)CLIP(
2729 (8000 * (1.0 - opt->graphics_acceleration)), 0, 1000
2730 )
2731 );
2732 #endif
2733 GWManage(core_ptr->display);
2734 }
2735
2736 /* Shutdown program core */
2737 SARShutdown(core_ptr);
2738 core_ptr = NULL;
2739
2740 #ifdef __MSW__
2741 /* Free command line arguments */
2742 strlistfree(argv, argc);
2743
2744 /* Shutdown COM loader (needed for DirectX) */
2745 CoUninitialize();
2746 #endif
2747
2748 return(0);
2749 }
2750