1 ///////////////////////////////////////////////
2 //
3 //  Snipe2d ludum dare 48h compo entry
4 //
5 //  Jari Komppa aka Sol
6 //  http://iki.fi/sol
7 //
8 ///////////////////////////////////////////////
9 // License
10 ///////////////////////////////////////////////
11 //
12 //     This software is provided 'as-is', without any express or implied
13 //     warranty.    In no event will the authors be held liable for any damages
14 //     arising from the use of this software.
15 //
16 //     Permission is granted to anyone to use this software for any purpose,
17 //     including commercial applications, and to alter it and redistribute it
18 //     freely, subject to the following restrictions:
19 //
20 //     1. The origin of this software must not be misrepresented; you must not
21 //        claim that you wrote the original software. If you use this software
22 //        in a product, an acknowledgment in the product documentation would be
23 //        appreciated but is not required.
24 //     2. Altered source versions must be plainly marked as such, and must not be
25 //        misrepresented as being the original software.
26 //     3. This notice may not be removed or altered from any source distribution.
27 //
28 // (eg. same as ZLIB license)
29 //
30 ///////////////////////////////////////////////
31 //
32 // Houses are taken from a satellite picture of glasgow.
33 //
34 // The sources are a mess, as I didn't even try to do anything
35 // really organized here.. and hey, it's a 48h compo =)
36 //
37 
38 #include "snipe2d.h"
39 //#include <getopt.h>
40 #include "binds.h"
41 #include <limits.h> // for PATH_MAX
42 
43 PREFS gPrefs;
44 
45 typedef struct oes_joy_t {
46   int style;    /* axis style: rel (game) or abs (mousepad) */ //not used yet
47   float scale;  /* scaling factor. */
48   int interval; /* handling interval, in milliseconds. */
49 
50   int time;  /* timestamp of last handling. */
51   int axes;  /* number of axes */
52   int buttons;  /* number of buttons. */
53   int state;    /* joy shifter state. */
54   float x;   /* X axis. */
55   float y;   /* Y axis. */
56   float z;   /* throttle? */
57   SDL_Joystick* sdljoy;  /* SDL Joystick handle. */
58 #if 0
59   /* bindings for 32 axes and 32 buttons. */
60   oesbind_t axis[32];
61   oesbind_t button[32];
62 #endif /* 0 */
63 } oes_joy_t;
64 
65 oes_joy_t oesjoy = { 0, };
66 
67 
68 struct keymarkers_t {
69   int mousex;
70   int mousey;
71   int mouse0;
72   int axis1;
73   int joy1;
74 } keymarkers;
75 
76 
77 ORBITALSNIPER Game;
78 
79 
80 //char *mediaPath;
81 
82 //int gPlaySound = 0;
83 int screen_shot_number=1;
84 char *invocation;
85 
86 #if 0
87 BUTTONS gButton;
88 #endif /* 0 */
89 
90 static const char *crosshairs_xpm[] = {
91   "    16    16        3            1",
92   "X c #000000",
93   ". c #ffffff",
94   "  c None",
95   "               ",
96   "       .       ",
97   "     .....     ",
98   "    .  .  .    ",
99   "   .   .   .   ",
100   "  .         .  ",
101   "  .         .  ",
102   " ....  .  .... ",
103   "  .         .  ",
104   "  .         .  ",
105   "   .   .   .   ",
106   "    .  .  .    ",
107   "     .....     ",
108   "       .       ",
109   "               ",
110   "               ",
111   "8,8"
112 };
113 
114 #if 0
115 //SDL_AudioSpec *gAudioSpec = NULL;
116 Mix_Chunk *gAudioZoomSample = NULL;
117 Mix_Chunk *gAudioFireSample = NULL;
118 Mix_Chunk *gAudioZoomOut = NULL;
119 Mix_Chunk *gAudioZoomIn = NULL;
120 Mix_Chunk *gAudioFire = NULL;
121 //Mix_Music *gAudioBGM = NULL;
122 int gAudioZoomSampleLen = 0;
123 int gAudioZoomOutLen = 0;
124 int gAudioZoomInLen = 0;
125 int gAudioZoomOfs = 0;
126 int gAudioFireOfs = 0;
127 int gAudioFireSampleLen = 0;
128 int gAudioFireLen = 0;
129 #endif /* 0 */
130 
131 
132 const char *usage = \
133 "Usage: %s [OPTIONS]...\n\
134 Overhead shooting game; kill red marks, protect blue marks, avoid white marks.\n\
135 \n\
136 Orbital Eunuchs Sniper recognizes the following command parameters:\n\
137   -a       | --audio             Start with sound\n\
138   -n       | --noaudio           Start without sound\n\
139   -f       | --fullscreen        Start in fullscreen mode\n\
140   -w       | --window            Start in a window\n\
141   -1       | --diff1             Difficulty 1 (Easy)\n\
142   -2       | --diff2             Difficulty 2 (Medium)\n\
143   -3       | --diff3             Difficulty 3 (Hard)\n\
144   -h       | --help              Display this help message and exit\n\
145 \n\
146 Orbital Eunuchs Sniper is licensed under the same terms as the ZLIB license.\n\
147 \n";
148 /*  -d 1|2|3 | --difficulty 1|2|3  Set difficulty level (1 is easiest)\n\ */
149 
150 
151 /* Set SDL cursor. */
152 void
oes_cursor()153 oes_cursor ()
154 {
155 	int i, row, col;
156 	Uint8 data[4*16];
157 	Uint8 mask[4*16];
158 	int hot_x, hot_y;
159 	const char **image;
160 	SDL_Cursor *cursor;
161 
162 	image = crosshairs_xpm;
163 	i = -1;
164 	for ( row=0; row<16; ++row ) {
165 		for ( col=0; col<16; ++col ) {
166 			if ( col % 8 ) {
167 				data[i] <<= 1;
168 				mask[i] <<= 1;
169 			} else {
170 				++i;
171 				data[i] = mask[i] = 0;
172 			}
173 			switch (image[4+row][col]) {
174 			case 'X':
175 				data[i] |= 0x01;
176 				mask[i] |= 0x01;
177 				break;
178 			case '.':
179 				mask[i] |= 0x01;
180 				break;
181 			case ' ':
182 				break;
183 			}
184 		}
185 	}
186 	sscanf(image[4+row], "%d,%d", &hot_x, &hot_y);
187 	cursor = SDL_CreateCursor(data, mask, 16, 16, hot_x, hot_y);
188 	SDL_SetCursor (cursor);
189 }
190 
191 
192 
193 
194 
195 
196 /********************/
197 /* Background Music */
198 /********************/
199 
200 
201 /* Function for SDL_mixer */
oes_bgm_loop()202 static void oes_bgm_loop()
203 {
204   sniperbgm_loop(Game.BGM);
205 }
206 
207 
208 sniperbgm_t *
sniperbgm_init(sniperbgm_t * self)209 sniperbgm_init (sniperbgm_t *self)
210 {
211   if (!self)
212       self = (sniperbgm_t*)calloc(1, sizeof(*self));
213   self->BGM = NULL;
214   self->playp = 0;
215   self->pausep = 0;
216   return self;
217 }
218 
219 sniperbgm_t *
sniperbgm_init_music(sniperbgm_t * self,Mix_Music * m)220 sniperbgm_init_music (sniperbgm_t *self, Mix_Music *m)
221 {
222   if ((self = sniperbgm_init(self)))
223     {
224 //      SniperBGM();
225       self->BGM = m;
226     }
227   return self;
228 }
229 
230 void
sniperbgm_delete(sniperbgm_t * self)231 sniperbgm_delete (sniperbgm_t *self)
232 {
233   sniperbgm_stop(self);  /* Don't wait for fadeout to finish. */
234   Mix_FreeMusic(self->BGM);
235   free(self);
236 }
237 
238 Mix_Music *
sniperbgm_music(sniperbgm_t * self)239 sniperbgm_music (sniperbgm_t *self)
240 {
241   return self->BGM;
242 }
243 
244 int
sniperbgm_use(sniperbgm_t * self,Mix_Music * m)245 sniperbgm_use (sniperbgm_t *self, Mix_Music *m)
246 {
247   if (!m) return 0;
248   self->BGM = m;
249   return 1;
250 }
251 
252 void
sniperbgm_start(sniperbgm_t * self)253 sniperbgm_start (sniperbgm_t *self)
254 {
255   if (self->BGM)
256     {
257       if (Mix_PlayMusic(self->BGM, 0))
258           printf("Mix_PlayMusic: %s\n", Mix_GetError());
259     }
260   Mix_HookMusicFinished(oes_bgm_loop);
261   self->playp = 1;
262   self->time_start = SDL_GetTicks();
263 }
264 
265 void
sniperbgm_stimulate(sniperbgm_t * self)266 sniperbgm_stimulate (sniperbgm_t *self)
267 {
268   if (self->playp) return;
269   if (Mix_FadeInMusic(self->BGM, 0, sniperbgm_FadeInTime))
270       printf("Mix_PlayMusic: %s\n", Mix_GetError());
271   Mix_HookMusicFinished(oes_bgm_loop);
272   self->playp = 1;
273   self->time_start = SDL_GetTicks();
274 }
275 
276 void
sniperbgm_depress(sniperbgm_t * self)277 sniperbgm_depress (sniperbgm_t *self)
278 {
279   Mix_HookMusicFinished(NULL);
280   if (!Mix_FadeOutMusic(sniperbgm_FadeOutTime))
281       Mix_HaltMusic();
282   self->playp = 0;
283 }
284 
285 void
sniperbgm_stop(sniperbgm_t * self)286 sniperbgm_stop (sniperbgm_t *self)
287 {
288   Mix_HaltMusic();
289   Mix_HookMusicFinished(NULL);
290   self->playp = 0;
291 }
292 
293 void
sniperbgm_pause(sniperbgm_t * self,int newstate)294 sniperbgm_pause (sniperbgm_t *self, int newstate)
295 {
296   switch (newstate)
297     {
298       case 0: /* pause */
299         Mix_PauseMusic();
300         self->pausep = 1;
301         break;
302       case 1: /* resume */
303         Mix_ResumeMusic();
304         self->pausep = 0;
305         break;
306       default: /* toggle */
307         if (self->pausep) Mix_ResumeMusic(); else Mix_PauseMusic();
308         self->pausep = !self->pausep;
309         break;
310     }
311 }
312 
313 void
sniperbgm_jumpto(sniperbgm_t * self,float pos)314 sniperbgm_jumpto (sniperbgm_t *self, float pos)
315 {
316   Mix_SetMusicPosition(pos);
317 }
318 
319 void
sniperbgm_rewind(sniperbgm_t * self)320 sniperbgm_rewind (sniperbgm_t *self)
321 {
322   Mix_RewindMusic();
323 }
324 
325 void
sniperbgm_loop(sniperbgm_t * self)326 sniperbgm_loop (sniperbgm_t *self)
327 {
328   sniperbgm_start(self);
329   sniperbgm_jumpto(self, sniperbgm_RepeatJumpPos);
330 }
331 
332 void
sniperbgm_release(sniperbgm_t * self)333 sniperbgm_release (sniperbgm_t *self)
334 {
335   /* Prepare for release of sound device. */
336   /* Figure out where in the BGM we currently are. */
337   self->time_stop = SDL_GetTicks();
338   self->bookmark = (self->time_stop - self->time_start) / 1000.0;
339   sniperbgm_stop(self);
340 }
341 
342 void
sniperbgm_grab(sniperbgm_t * self)343 sniperbgm_grab (sniperbgm_t *self)
344 {
345   /* Try to resume BGM after reopening sound device. */
346   sniperbgm_start(self);
347   sniperbgm_jumpto(self, self->bookmark);
348   self->time_start -= (int)(self->bookmark * 1000); /* For next pause. */
349 }
350 
351 
352 
353 
354 
355 /******************/
356 /* Options parser */
357 /******************/
358 
359 static int
parse_option(PETOPT * pp,PETOPTS * pov,const char * arg)360 parse_option (PETOPT *pp, PETOPTS *pov, const char *arg)
361 {
362 	switch (pov->s) {
363 		case 'n': // no audio
364 			gPrefs.audio = 0;
365 			break;
366 		case 'f': // fullscreen
367 			gPrefs.fullscreen = 1;
368 			break;
369 		case 'w': // window
370 			gPrefs.fullscreen = 0;
371 			break;
372 		case 'a': // audio
373 			gPrefs.audio = 1;
374 			break;
375 		case '1':
376 			gPrefs.difficulty = 1;
377 			break;
378 		case '2':
379 			gPrefs.difficulty = 2;
380 			break;
381 		case '3':
382 			gPrefs.difficulty = 3;
383 			break;
384  		case 'h':
385 			fprintf (stderr, usage, invocation);
386 			exit (0);
387 			break;
388 	}
389     return 1;
390 }
391 
parse_args(int argc,char ** argv)392 void parse_args(int argc, char **argv)
393 {
394 	int fs, au, ds, petopt_err;
395 	PETOPTS pov[] = {
396 	{ 'n',	POF_BOOL,	"noaudio",	&au,	"Disable Audio" },
397 	{ 'f',	POF_BOOL,	"fullscreen",	&fs,	"Enable Fullscreen" },
398 	{ 'w',	POF_BOOL,	"windowed",	&fs,	"Disable Fullscreen" },
399 	{ 'a',	POF_BOOL,	"audio",	&au,	"Enable Audio" },
400 	{ '1',	POF_OPT|POF_INT,"diff1",	&ds,	"Difficulty Setting 1" },
401 	{ '2',	POF_OPT|POF_INT,"diff2",	&ds,	"Difficulty Setting 2" },
402 	{ '3',	POF_OPT|POF_INT,"diff3",	&ds,	"Difficulty Setting 3" },
403 	{ 'h',	0,		"help",		NULL,	"Extended mode" },
404 	{ -1,	0,		0,		NULL,	NULL },
405 	};
406 
407 	PETOPT *pop;
408 
409 	petopt_err = petopt_setup (&pop, 0, argc, argv, pov, parse_option, NULL);
410 	if (petopt_err > 0) {
411 		fprintf (stderr, "Unable to initialise petopt: %s\n", strerror(petopt_err));
412 		exit (1);
413 	}
414 	petopt_err = petopt_parse (pop, &argc, &argv);
415 	if (petopt_err > 0) {
416 		fprintf(stderr, "petopt_parse_all: %s\n", strerror(petopt_err));
417 		exit(1);
418 	}
419 	petopt_cleanup (pop);
420 
421 	return;
422 }
423 
424 
425 
426 
427 
428 
429 /***************/
430 /* Audio stuff */
431 /***************/
432 
433 #if 0
434 void audiomixer(void *userdata, Uint8 *stream, int len)
435 {
436     int l = len / 2;
437     short * buf = (short*)stream;
438     memset(stream,0,len);
439     if (gPlaySound & (1<<1))
440     {
441         gPlaySound &= ~(1<<1);
442         Game.AudioZoom.ofs = 0;
443         Game.AudioZoom.data = Game.AudioZoomOut.data;
444         Game.AudioZoom.len = Game.AudioZoomOut.len;
445     }
446     if (gPlaySound & (1<<2))
447     {
448         gPlaySound &= ~(1<<2);
449         Game.AudioZoom.ofs = 0;
450         Game.AudioZoom.data = Game.AudioZoomIn.data;
451         Game.AudioZoom.len = Game.AudioZoomIn.len;
452     }
453     if (gPlaySound & (1<<3))
454     {
455         gPlaySound &= ~(1<<3);
456         Game.AudioFireSample.ofs = 0;
457         Game.AudioFireSample.data = Game.AudioFire.data;
458         Game.AudioFireSample.len = Game.AudioFire.len;
459     }
460     if (Game.AudioZoom.data != NULL)
461     {
462         int n = l;
463         if (n + Game.AudioZoom.ofs > Game.AudioZoom.len)
464             n = Game.AudioZoom.len - Game.AudioZoom.ofs;
465         int i;
466         for (i = 0; i < n; i++)
467             buf[i] = Game.AudioZoom.data[i + Game.AudioZoom.ofs] / 2;
468         Game.AudioZoom.ofs += n;
469         if (l != n)
470         {
471             Game.AudioZoom.data = NULL;
472         }
473     }
474     if (Game.AudioFireSample != NULL)
475     {
476         int n = l;
477         if (n + Game.AudioFireSample.ofs > Game.AudioFireSample.len)
478             n = Game.AudioFireSample.len - Game.AudioFireSample.ofs;
479         int i;
480         for (i = 0; i < n; i++)
481             buf[i] += Game.AudioFireSample.data[i + Game.AudioFireSample.ofs] / 2;
482         Game.AudioFireSample.ofs += n;
483         if (l != n)
484         {
485             Game.AudioFireSample.data = NULL;
486         }
487     }
488 }
489 #endif /* 0 */
490 
491 /* Sillily expensive, but faster. */
492 char chanuse[16];
493 
oes_sound_finish(int chan)494 void oes_sound_finish (int chan)
495 {
496   chanuse[chan] = 0;
497 }
498 
oes_sound_play(int aSound)499 void oes_sound_play (int aSound)
500 {
501     int chan;
502     if (!gPrefs.audio)
503 	return;
504 //    SDL_LockAudio();
505 //    gPlaySound |= 1 << aSound;
506 //    SDL_UnlockAudio();
507     /* Find a free channel. */
508     for (chan = 0; (chan < 16) && (chanuse[chan]); chan++);
509     if (chan >= 16) return; /* out of channels. */
510     chanuse[chan] = 1;
511     switch (aSound) {
512 	case 1:
513 	    Mix_PlayChannel(chan, Game.AudioZoomOut, 0);
514 	    break;
515 	case 2:
516 	    Mix_PlayChannel(chan, Game.AudioZoomIn, 0);
517 	    break;
518 	case 3:
519 	    Mix_PlayChannel(chan, Game.AudioFire, 0);
520 	    break;
521     }
522 }
523 
oes_audio_open()524 int oes_audio_open ()
525 {
526 #ifdef PLAY_AUDIO
527     if (gPrefs.audio)
528 	{
529 #if 1
530 	    /* XXX: take settings from prefs. */
531 	    if (Mix_OpenAudio(44100, AUDIO_S16, 2, 4096)) {
532 		printf("Mix_OpenAudio(): %s\n", Mix_GetError());
533 	    }
534 	    Mix_AllocateChannels(17);
535 	    Mix_ChannelFinished(oes_sound_finish);
536 #else
537 	    SDL_AudioSpec *as = (SDL_AudioSpec*)malloc(sizeof(SDL_AudioSpec));
538 	    as->freq = 44100;
539 	    as->format = AUDIO_S16;
540 	    as->channels = 2;
541 	    as->samples = 4096;
542 	    as->callback = audiomixer;
543 	    as->userdata = NULL;
544 	    if (SDL_OpenAudio(as, NULL) < 0)
545 		{
546 		    fprintf(stderr, "Unable to init SDL audio: %s\n", SDL_GetError());
547 		    exit(1);
548 		}
549 	    Game.sdlaudio = as;
550 #endif /* 0 */
551 	}
552 #endif
553   return 0;
554 }
555 
oes_audio_close()556 int oes_audio_close ()
557 {
558   Mix_CloseAudio();
559   return 0;
560 }
561 
562 
563 
564 
565 
566 
567 /*****************************/
568 /* Game and system resources */
569 /*****************************/
570 
571 
572 /* initialize game data. */
573 ORBITALSNIPER *
oes_game_init(ORBITALSNIPER * self)574 oes_game_init (ORBITALSNIPER *self)
575 {
576   int i;
577   int tick;
578 
579   if (!self)
580       self = (ORBITALSNIPER*)calloc(1, sizeof(ORBITALSNIPER));
581 
582   tick = SDL_GetTicks();
583   self->MouseX = 0;
584   self->MouseY = 0;
585   self->MouseZ = 1.0f;
586   self->CoordScale = 1.0f;
587   self->WobbleX = 0;
588   self->WobbleY = 0;
589   self->CenterX = 0;
590   self->CenterY = 0;
591   self->ControlState = 0;
592   self->Reloading = 0;
593   self->Score = 0;
594   self->vip.count = 0;
595   self->baddy.count = 0;
596   self->WobbleIndex = 0;
597   self->vip.goal = 0;
598   self->pedestrian.dead = 0;
599   self->baddy.dead = 0;
600   self->SightedCharacter = NULL;
601 
602   if (oesjoy.sdljoy) {
603       SDL_JoystickClose(oesjoy.sdljoy);
604       oesjoy.sdljoy = NULL;
605   }
606   oesjoy.x = 0;  oesjoy.y = 0;  oesjoy.z = 0;  oesjoy.state = 0;
607   oesjoy.axes = 0;  oesjoy.buttons = 0;
608   if (gPrefs.joystick) {
609       /* want to use joystick. */
610 //printf("Detected %d joysticks\n", SDL_NumJoysticks());
611       if ((oesjoy.sdljoy = SDL_JoystickOpen(gPrefs.joystick - 1))) { /* off-by-one */
612           oesjoy.axes = SDL_JoystickNumAxes(oesjoy.sdljoy);
613           oesjoy.buttons = SDL_JoystickNumButtons(oesjoy.sdljoy);
614       }
615   }
616 
617   for (i = 0; i < self->num_characters; i++)
618   {
619       self->characters[i].mType = -1;
620   }
621   for (i = 0; i < (int)(self->num_characters * 0.75f); i++)
622   {
623       int id = spawn_ai(2);
624       int j;
625       for (j = 0; j < 1000; j++) // Run 1000 physics loops for all pedestrians..
626           handle_ai(self->characters[id]);
627   }
628   self->vip.time = 2000;
629   self->vip.period = 20000;
630   self->baddy.time = 3000;
631   self->baddy.period = 8000;
632   self->WobbleIndex = 0;
633   self->StartTick = tick;
634   self->FrameCount = 0;
635   self->LastTick = tick;
636   self->GameState = 1;
637   self->GameStartTick = tick;
638   SDL_ShowCursor (0);
639 
640   return self;
641 }
642 
643 
644 /* One-time setup at start. */
645 int
oes_setup()646 oes_setup ()
647 {
648 /* load audio, load images, load models(?), allocate objects. */
649   int i;
650   const char *city_img = "citee2.png";
651   const char *charseq_img = "charseq.png";
652   const char *aimap_img = "aimap.png";
653   const char *font_img = "font4x6.png";
654   const char *zoomin_snd = "camera_in.wav";
655   const char *zoomout_snd = "camera_out.wav";
656   const char *boing_snd = "twang.wav";
657   const char *bgmusic = "oes.ogg";
658 
659 //  char path[ strlen(mediaPath) + 1 + 30 + 1 ];
660 //  path = (char*)calloc(strlen(mediaPath) + 1 + 30 + 1, sizeof(char));
661   char *path;
662   /* free on function exit. */
663   path = (char*)alloca((strlen(Game.mediaPath) + 1 + 30 + 1) * sizeof(char));
664 
665 
666   /* Configure difficulty. */
667   configure_difficulty();
668   /* Initialise high scores. */
669   init_hiscores();
670 
671   /* Initialise SDL */
672     //if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0 )
673 //    if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
674   if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0 )
675     {
676       fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
677       exit(1);
678     }
679 
680   atexit(SDL_Quit);
681 
682   //gScreen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
683 #ifdef OSX_SUX
684   Game.Screen = SDL_SetVideoMode(640, 480, 16, (gPrefs.fullscreen ? SDL_FULLSCREEN : 0) | SDL_SWSURFACE);
685 #else
686   Game.Screen = SDL_SetVideoMode(640, 480, 16, (gPrefs.fullscreen ? SDL_FULLSCREEN : 0) | SDL_SWSURFACE | SDL_DOUBLEBUF);
687 #endif
688   SDL_WM_SetCaption("ORBITAL EUNUCHS SNIPER", "ORBITAL_EUNUCHS_SNIPER");
689   if (Game.Screen == NULL)
690     {
691       fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
692       exit(1);
693     }
694   /* Cursor */
695   oes_cursor();
696 //  init_logoscreen();
697 
698   oes_audio_open();
699 
700 
701   Game.BGM = sniperbgm_init(Game.BGM);
702 
703   sprintf(path, "%s/%s", Game.mediaPath, city_img);
704   SDL_Surface *temp = IMG_Load(path);
705   if (!temp) {
706     fprintf(stderr, "Unable to load city map from '%s'\n",path);
707     exit(1);
708   }
709   Game.Map = SDL_ConvertSurface(temp, Game.Screen->format,SDL_SWSURFACE);
710   SDL_FreeSurface(temp);
711 
712   sprintf(path, "%s/%s", Game.mediaPath, charseq_img);
713   temp = IMG_Load(path);
714   if (!temp) {
715     fprintf(stderr, "Unable to load character image from '%s'\n",path);
716     exit(1);
717   }
718   Game.CharSprite = SDL_ConvertSurface(temp, Game.Screen->format,SDL_SWSURFACE);
719   SDL_FreeSurface(temp);
720 
721   sprintf(path, "%s/%s", Game.mediaPath, aimap_img);
722   Game.AIMap = IMG_Load(path);
723   if (!temp) {
724     fprintf(stderr, "Unable to load AI map from '%s'\n",path);
725     exit(1);
726   }
727 
728   // Okay, this is ugly. Load font several times & change the color of each.
729 
730   for (i = 0; i < 5; i++)
731   {
732       sprintf(path, "%s/%s", Game.mediaPath, font_img);
733       Game.Font[i] = IMG_Load(path);
734       if (!Game.Font[i]) {
735         fprintf(stderr, "Unable to load font %d from '%s'\n",i,path);
736         exit(1);
737       }
738       SDL_SetColorKey(Game.Font[i],SDL_SRCCOLORKEY,1); // set color index 1 (black) transparent
739   }
740   *(int*)&(Game.Font[0]->format->palette->colors[0]) = 0x000000; // black
741   *(int*)&(Game.Font[1]->format->palette->colors[0]) = 0xffffff; // white
742   *(int*)&(Game.Font[2]->format->palette->colors[0]) = 0x00ff00; // green
743   *(int*)&(Game.Font[3]->format->palette->colors[0]) = 0x00ffff; // yellow
744   *(int*)&(Game.Font[4]->format->palette->colors[0]) = 0x0000ff; // red
745 
746   precalc_ai();
747 
748   Game.num_characters = 2048;
749   Game.characters = (CHARACTER*)calloc(Game.num_characters, sizeof(CHARACTER));
750 
751 #ifdef PLAY_AUDIO
752   if (gPrefs.audio)
753     {
754       sprintf(path, "%s/%s", Game.mediaPath, zoomin_snd);
755       Game.AudioZoomIn = Mix_LoadWAV(path);
756       if (!Game.AudioZoomIn) {
757         fprintf(stderr, "Unable to load zoom in sound from '%s'\n",path);
758         exit(1);
759       }
760       sprintf(path, "%s/%s", Game.mediaPath, zoomout_snd);
761       Game.AudioZoomOut = Mix_LoadWAV(path);
762       if (!Game.AudioZoomOut) {
763         fprintf(stderr, "Unable to load zoom out sound from '%s'\n",path);
764         exit(1);
765       }
766       sprintf(path, "%s/%s", Game.mediaPath, boing_snd);
767       Game.AudioFire = Mix_LoadWAV(path);
768       if (!Game.AudioFire) {
769         fprintf(stderr, "Unable to load fire sound from '%s'\n",path);
770         exit(1);
771       }
772       sprintf(path, "%s/%s", Game.mediaPath, bgmusic);
773 //      Game.BGM = Mix_LoadMUS(path);
774       if (!sniperbgm_use(Game.BGM, Mix_LoadMUS(path))) {
775         fprintf(stderr, "Unable to load background music from '%s'\n",path);
776         exit(1);
777       }
778 
779 //      SDL_PauseAudio(0); // let it play
780     }
781 #endif
782 
783   oes_game_init(&Game);
784   return 0;
785 }
786 
787 /* One-time teardown at exit. */
788 void
oes_teardown()789 oes_teardown ()
790 {
791   if (oesjoy.sdljoy)
792     {
793       SDL_JoystickClose(oesjoy.sdljoy);
794       oesjoy.sdljoy = NULL;
795     }
796 }
797 
798 /* Temporarily release system resources. */
799 int
oes_suspend()800 oes_suspend ()
801 {
802   if (Game.GameState != OESGAME_PLAY) return 0;
803   sniperbgm_release(Game.BGM);
804   //oes_audio_close();
805   SDL_WM_GrabInput(SDL_GRAB_OFF);
806   SDL_ShowCursor(1);
807   Game.GameState = OESGAME_PAUSED;
808   return 0;
809 }
810 
811 /* Reassert system resources that were temporarily released. */
812 int
oes_resume()813 oes_resume ()
814 {
815   if (Game.GameState != OESGAME_PAUSED) return 0;
816   if (Game.GrabP)
817     {
818       SDL_ShowCursor(0);
819       SDL_WM_GrabInput(SDL_GRAB_ON);
820     }
821   //oes_audio_open();
822   sniperbgm_grab(Game.BGM);
823   Game.GameState = OESGAME_UNPAUSED;
824   return 0;
825 }
826 
827 
828 
829 
830 
831 
832 /**************/
833 /* Game logic */
834 /**************/
835 
836 #define PHYSICS_MS 10
837 // 10ms physics loops == 100 loops per sec, 'should be enough'..
838 
oes_reindeer()839 void oes_reindeer()
840 {
841     Game.SightedCharacter = NULL;
842     int tick = SDL_GetTicks();
843     Game.FrameCount++;
844     if (Game.Reloading)
845     {
846         Game.Reloading -= tick - Game.LastTick;
847         if (Game.Reloading < 0)
848             Game.Reloading = 0;
849     }
850 
851     Game.CenterX = (640.0f - 640.0f * Game.CoordScale) / 2;
852     Game.CenterY = (480.0f - 480.0f * Game.CoordScale) / 2;
853     Game.WobbleX = (float)(sin(Game.WobbleIndex * 0.000654387) +
854         sin(Game.WobbleIndex * 0.000547867)*2 +
855         sin(Game.WobbleIndex * 0.000700133)) * (WOBBLE / 4.0f);
856     Game.WobbleY = (float)(sin(Game.WobbleIndex * 0.000537234) +
857         sin(Game.WobbleIndex * 0.000732897) +
858         sin(Game.WobbleIndex * 0.000600613)*2) * (WOBBLE / 4.0f);
859 
860 
861 
862 #ifdef UNREAL_DITHER
863     zoom_unreal(Game.Map, Game.MouseX + Game.CenterX + Game.WobbleX, Game.MouseY + Game.CenterY + Game.WobbleY, Game.CoordScale);
864 #else
865     zoom(Game.Map, Game.MouseX + Game.CenterX + Game.WobbleX, Game.MouseY + Game.CenterY + Game.WobbleX, Game.CoordScale);
866 #endif
867 
868     int i;
869     int physics_loops = (tick - Game.LastTick) / PHYSICS_MS;
870     int j;
871     for (i = 0; i < Game.num_characters; i++)
872     {
873         for (j = 0; j < physics_loops; j++)
874             handle_ai(Game.characters[i]);
875         if (!Game.GameState)
876             return;
877         drawCharacter(Game.characters[i]);
878     }
879 
880     target();
881 
882     for (j = 0; j < physics_loops; j++)
883     {
884         int physicstick = Game.LastTick - Game.GameStartTick;
885         Game.WobbleIndex += PHYSICS_MS;
886 
887         // spawn VIPs
888         if (physicstick >= Game.vip.time)
889         {
890 
891             if (Game.vip.count == 2 && rand() < 2048)
892                 spawn_ai(1);
893             if (Game.vip.count == 1 && rand() < 8192)
894                 spawn_ai(1);
895             if (Game.vip.count == 0)
896                 spawn_ai(1);
897             Game.vip.time += (int)Game.vip.period;
898         }
899         // spawn baddies
900         if (physicstick >= Game.baddy.time)
901         {
902             spawn_ai(0);
903             Game.baddy.time += (int)Game.baddy.period;
904         }
905         if (((Game.LastTick / PHYSICS_MS) & 3) == 0)
906             Game.baddy.period--;
907 
908         if (Game.baddy.period < 3000)
909             Game.baddy.period = 3000; // Eventually it will be impossible to kill all bad guys.
910 
911         Game.LastTick += PHYSICS_MS;
912     }
913 
914 
915     SDL_Flip(Game.Screen);
916 }
917 
918 
oes_game_state(int newstate)919 int oes_game_state (int newstate)
920 {
921 	switch ((Game.GameState = newstate)) {
922 	case 0:
923 		/* need init */
924 		break;
925 	case 1:
926 		/* main game state. */
927 		break;
928 	case 2:
929 		/* paused state. */
930 		break;
931 	case 3:
932 		/* just unpaused.  Need re-init, transit to 1. */
933 		break;
934 	}
935     return Game.GameState;
936 }
937 
938 /*
939 Alter input grab state.
940 0 = try to release
941 1 = try to grab
942 -1 = toggle whatever it is.
943 */
oes_game_grab(int newstate)944 int oes_game_grab (int newstate)
945 {
946 	int tryGrabState;
947 
948 	if (SDL_GetVideoSurface()->flags & SDL_FULLSCREEN) {
949 		/* Don't release grab in fullscreen. */
950 		SDL_WM_GrabInput(SDL_GRAB_ON);
951 		SDL_ShowCursor(0);
952 		Game.GrabP = 1;
953 		return 0;
954 	}
955 	tryGrabState = (newstate == -1) ? !Game.GrabP : newstate;
956 	switch (tryGrabState) {
957 	case 0:
958 		SDL_WM_GrabInput(SDL_GRAB_OFF);
959 		Game.GrabP = 0;
960 		SDL_ShowCursor(1);
961 		break;
962 	case 1:
963 		SDL_ShowCursor(0);
964 		SDL_WM_GrabInput(SDL_GRAB_ON);
965 		Game.GrabP = 1;
966 		break;
967 	}
968 	return Game.GrabP;
969 }
970 
oes_game_zoom(float amt)971 int oes_game_zoom (float amt)
972 {
973 	float oldcoord = Game.CoordScale;
974 
975 	Game.MouseZ += amt;
976 	if (Game.MouseZ > 1.25) Game.MouseZ = 1.25;
977 	if (Game.MouseZ < 0.05f) Game.MouseZ = 0.05f;
978 #ifndef CAMERA_STEPS
979 	Game.CoordScale = Game.MouseZ;
980 #else /* CAMERA_STEPS */
981 	Game.CoordScale = ((int)(Game.MouseZ * 4)) / 4.0f;
982 	if (Game.CoordScale < 0.05f) Game.CoordScale = 0.05f;
983 #endif /* CAMERA_STEPS */
984 	if (oldcoord < Game.CoordScale)
985 		oes_sound_play(1);
986 	if (oldcoord > Game.CoordScale)
987 		oes_sound_play(2);
988 	return 0;
989 }
990 
991 /*
992 Set paused state.
993 0 = force play/resume
994 1 = force pause
995 -1 = toggle paused state
996 */
oes_game_pause(int newstate)997 int oes_game_pause (int newstate)
998 {
999   int tryPause;
1000   int tick;
1001 
1002   tryPause = newstate;
1003   if (newstate == -1)
1004     {
1005       if (Game.GameState == OESGAME_PAUSED)
1006           tryPause = 0;
1007       else
1008           tryPause = 1;
1009     }
1010   tick = SDL_GetTicks();
1011   switch (tryPause)
1012     {
1013       case 0:
1014         if (Game.GameState == OESGAME_PAUSED)
1015           {
1016 //printf("UNPAUSING\n");
1017             /* resume */
1018             oes_resume();  /* regain system resources. */
1019             Game.AfterPauseTick = tick;
1020             Game.GameStartTick += Game.AfterPauseTick - Game.BeforePauseTick;
1021             Game.GameState = OESGAME_PLAY;
1022             break;
1023           }
1024         break;
1025       case 1:
1026         if (Game.GameState == OESGAME_PLAY)
1027           {
1028             /* go to pause */
1029 //printf("Pausing\n");
1030             Game.BeforePauseTick = tick;
1031             oes_suspend();  /* release system resources. */
1032             Game.GameState = OESGAME_PAUSED;
1033           }
1034         break;
1035     }
1036   return tryPause;
1037 }
1038 
1039 /* Boss event. */
1040 int
oes_game_hide(int newstate)1041 oes_game_hide (int newstate)
1042 {
1043   SDL_WM_IconifyWindow();
1044   oes_game_pause(1);
1045   return 1;
1046 }
1047 
1048 
1049 
1050 
1051 
1052 
1053 /******************/
1054 /* OES Game Binds */
1055 /******************/
1056 
1057 
1058 /* No-operation */
oes_bind_nop(int val)1059 int oes_bind_nop (int val)
1060 {
1061   /* do-nothing */
1062   return 0;
1063 }
1064 
1065 
1066 /* On-release-only binds */
1067 
oes_bind_grab(int val)1068 int oes_bind_grab (int val)
1069 {
1070 	if (val) return 0;
1071 	return oes_game_grab(-1);
1072 }
1073 
1074 /* toggle fullscreen... on key release */
oes_bind_fullscreen(int val)1075 int oes_bind_fullscreen (int val)
1076 {
1077 	if (val) return 0;  /* toggle on release. */
1078 
1079 	gPrefs.fullscreen = !gPrefs.fullscreen;
1080 	if (((Game.Screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) ^ (gPrefs.fullscreen)) {
1081 		SDL_WM_ToggleFullScreen(Game.Screen);
1082 	}
1083 //	SDL_WM_ToggleFullScreen(Game.Screen);
1084 //	gPrefs.fullscreen = !gPrefs.fullscreen;
1085 	return 0;
1086 }
1087 
1088 /* Boss Key */
oes_bind_hide(int val)1089 int oes_bind_hide (int val)
1090 {
1091 	if (val) return 0; /* trigger on release */
1092 	oes_game_hide(1);
1093 	return 0;
1094 }
1095 
1096 /* Forceful end of game. */
1097 int
oes_bind_abandon(int pressed)1098 oes_bind_abandon (int pressed)
1099 {
1100 	if (pressed) return 0;
1101 	oes_resume();
1102 	Game.GameOverReason = OESREASON_AWOL;
1103 	return 0;
1104 }
1105 
1106 
1107 /* On-press binds */
1108 
1109 /* paused mode. */
oes_bind_pause(int val)1110 int oes_bind_pause (int val)
1111 {
1112 	if (!val) return 0;
1113 	return oes_game_pause(-1);
1114 }
1115 
1116 /* the extra information around the targeting reticles */
oes_bind_verbosity(int val)1117 int oes_bind_verbosity (int val)
1118 {
1119 	if (!val) return 0;
1120 	Game.verbosity = (Game.verbosity + 1) % 3;
1121 	gPrefs.verbose = Game.verbosity;
1122 	return 0;
1123 }
1124 
1125 /* save screenshot */
oes_bind_screenshot(int val)1126 int oes_bind_screenshot (int val)
1127 {
1128 	if (!val) return 0;
1129 	SDL_SaveBMP(SDL_GetVideoSurface(),"screenshot.bmp");
1130 	screen_shot_number++;
1131 	return 0;
1132 }
1133 
oes_bind_fire(int val)1134 int oes_bind_fire (int val)
1135 {
1136 	if (!val) return 0;
1137 	if (Game.GameState == OESGAME_PLAY) {
1138 		if (!Game.Reloading) {
1139 			oes_sound_play(3);
1140 			shoot();
1141 		}
1142 	} else if (Game.GameState == OESGAME_PAUSED) {
1143 		if (Game.LastTick - Game.SemiPause < 500) {
1144 //			Game.GameState = OESGAME_UNPAUSED;
1145 			oes_game_pause(0);
1146 		} else {
1147 			Game.SemiPause = Game.LastTick;
1148 		}
1149 	}
1150     return val;
1151 }
1152 
1153 /* zooming mode */
oes_bind_zoom(int val)1154 int oes_bind_zoom (int val)
1155 {
1156 	Game.ControlState = val ? 1 : 0;
1157     return Game.ControlState;
1158 }
1159 
1160 /* Zoom in */
oes_bind_zoomin(int val)1161 int oes_bind_zoomin (int val)
1162 {
1163 	if (!val) return 0;
1164 	if (Game.GameState != OESGAME_PLAY) return 1;
1165 	oes_game_zoom(-0.20f);
1166 	return val;
1167 }
1168 
1169 /* Zoom out */
oes_bind_zoomout(int val)1170 int oes_bind_zoomout (int val)
1171 {
1172 	if (!val) return 0;
1173 	if (Game.GameState != OESGAME_PLAY) return 1;
1174 	oes_game_zoom(0.20f);
1175 	return val;
1176 }
1177 
1178 
1179 
1180 /* Continuous-value binds */
1181 
1182 /* Mouse motion, horizontal */
oes_bind_mhoriz(int val)1183 int oes_bind_mhoriz (int val)
1184 {
1185 	if (!Game.GrabP) {
1186 		/* A little confusing if not grabbed... */
1187 		return 1;
1188 	}
1189 	if (Game.GameState != OESGAME_PLAY) return 1;
1190 	if (Game.ControlState == 0) {
1191 		Game.MouseX += val * Game.CoordScale;
1192 		if (Game.MouseX < -320) Game.MouseX = -320;
1193 		if (Game.MouseX > (800 -320)) Game.MouseX = (800 - 320);
1194 	} else {
1195 		/* nothing on horizontal while zoomshift */
1196 	}
1197 	return 0;
1198 }
1199 
1200 /* Mouse motion, vertical */
oes_bind_mvert(int val)1201 int oes_bind_mvert (int val)
1202 {
1203 	if (!Game.GrabP) {
1204 		/* A little confusing if not grabbed... */
1205 		return 1;
1206 	}
1207 	if (Game.GameState != OESGAME_PLAY) return 1;
1208 	if (Game.ControlState == 0) {
1209 		Game.MouseY += val * Game.CoordScale;
1210 		if (Game.MouseY < -240) Game.MouseY = -240;
1211 		if (Game.MouseY > (600 - 240)) Game.MouseY = (600 - 240);
1212 	} else {
1213 		oes_game_zoom (val * 0.005f);
1214 	}
1215 	return 0;
1216 }
1217 
1218 /* Axis, horizontal */
oes_bind_jhoriz(int val)1219 int oes_bind_jhoriz (int val)
1220 {
1221 	if (!Game.GrabP) return 1;
1222 	if (Game.GameState != OESGAME_PLAY) return 1;
1223 	oesjoy.x = (val * oesjoy.scale) / 32767.0;
1224 	return val;
1225 }
1226 
1227 /* Axis, vertical */
oes_bind_jvert(int val)1228 int oes_bind_jvert (int val)
1229 {
1230 	if (!Game.GrabP) return 1;
1231 	if (Game.GameState != OESGAME_PLAY) return 1;
1232 	oesjoy.y = (val * oesjoy.scale) / 32767.0;
1233 	return val;
1234 }
1235 
1236 /* Axis, depth (zoom) */
oes_bind_jdeep(int val)1237 int oes_bind_jdeep (int val)
1238 {
1239 	float joyz;
1240 
1241 	if (!Game.GrabP) return 1;
1242 	if (Game.GameState != OESGAME_PLAY) return 1;
1243 	oesjoy.z = val;
1244 /* XXX: what about going backwards? */
1245 	/*                    out     in  */
1246 	/* map oes.joyz from 1.25 to 0.05 */
1247 	/*                    0     32767 */
1248 	/* deltas: 1.20 : 32767 */
1249 //	joyz = (oesjoy.z * 1.20 / 32767.0) + 0.05;
1250 	joyz = 1.25 - (oesjoy.z * 1.20 / 32767.0);
1251 	Game.MouseZ = joyz;
1252 	oes_game_zoom(0);
1253 
1254 	return val;
1255 }
1256 
1257 
1258 
1259 
1260 
1261 
1262 
1263 
1264 
1265 /* After binds. */
1266 
1267 
1268 
1269 /* game binding names (from config file) */
1270 oes_xlat_t oesxlat[] = {
1271  { "mousex", oes_bind_mhoriz },
1272  { "mousey", oes_bind_mvert },
1273  { "joyx", oes_bind_jhoriz },
1274  { "joyy", oes_bind_jvert },
1275  { "joyz", oes_bind_jdeep },
1276  { "fire", oes_bind_fire },
1277  { "zoom", oes_bind_zoom },
1278  { "zoomin", oes_bind_zoomin },
1279  { "zoomout", oes_bind_zoomout },
1280  { "verbosity", oes_bind_verbosity },
1281  { "screenshot", oes_bind_screenshot },
1282  { "fullscreen", oes_bind_fullscreen },
1283  { "hide", oes_bind_hide },
1284  { "abandon", oes_bind_abandon },
1285  { "pause", oes_bind_pause },
1286  { "grab", oes_bind_grab },
1287  { 0, 0 },
1288 };
1289 
1290 
1291 
1292 
1293 /*******************/
1294 /* Events handling */
1295 /*******************/
1296 
1297 
1298 /* Called at intervals, handling joystick axes. */
oes_game_joystick(int ticks)1299 int oes_game_joystick (int ticks)
1300 {
1301 /* Joystick axes handling. */
1302 	int joyx, joyy;
1303 	if (!oesjoy.sdljoy) return 0;
1304 	if (ticks > oesjoy.time + oesjoy.interval) {
1305 //printf("JOY HANDLE\n");
1306 		joyx = (int)(oesjoy.x);
1307 		joyy = (int)(oesjoy.y);
1308 		switch (oesjoy.state) {
1309 		case 0: /* normal */
1310 			oes_bind_mhoriz(joyx);
1311 			oes_bind_mvert(joyy);
1312 			break;
1313 		case 1: /* shifted 1 */
1314 			oes_game_zoom(joyy * 0.005);
1315 			break;
1316 		}
1317 		oesjoy.time = ticks;
1318 	}
1319     return 1;
1320 }
1321 
1322 
oes_game_events()1323 int oes_game_events ()
1324 {
1325   SDL_Event event;
1326   int kmod;
1327   int oeskey;
1328   oesbind_t binding; /* function pointer */
1329 
1330   while (SDL_PollEvent(&event))
1331     {
1332       switch (event.type)
1333         {
1334           case SDL_KEYDOWN:
1335             binding = NULL;
1336             kmod = SDL_GetModState();
1337             oeskey = event.key.keysym.sym;
1338             switch (event.key.keysym.sym)
1339               {
1340                 /* Rebindable keys */
1341                 default:
1342                   binding = oeskeymap_get(&oeskeymap, oeskey);
1343                   break;
1344               }
1345             if (binding)
1346                 binding(1);
1347             break;
1348           case SDL_KEYUP:
1349             binding = NULL;
1350             kmod = SDL_GetModState();
1351             oeskey = event.key.keysym.sym;
1352             switch (event.key.keysym.sym)
1353               {
1354                 /* Hard-coded keys */
1355                 case SDLK_F12: /* failsafe */
1356                   exit(69);
1357                   break;
1358                 case SDLK_F4: /* failsafe */
1359                   if (kmod & KMOD_ALT) exit(69);
1360                   break;
1361                 case SDLK_RETURN:
1362                   if (kmod & KMOD_ALT)
1363                     {
1364                       binding = oes_bind_fullscreen;
1365                     }
1366                   break;
1367                 case SDLK_z:
1368                   if (kmod & KMOD_CTRL)
1369                     {
1370                       binding = oes_bind_hide;
1371                     }
1372                   break;
1373                 case SDLK_g:
1374                   if (kmod & KMOD_CTRL)
1375                     {
1376                       binding = oes_bind_grab;
1377                     }
1378                   break;
1379                 /* Rebindable keys */
1380                 default:
1381                   binding = oeskeymap_get(&oeskeymap, oeskey);
1382                   break;
1383               }
1384             if (binding)
1385                 binding(0);
1386             break;
1387           case SDL_MOUSEMOTION:
1388 //            binding = oeskeymap_get(&oeskeymap, oeskeymap_resolve("MOUSEX"));
1389             binding = oeskeymap_get(&oeskeymap, keymarkers.mousex);
1390             if (binding)
1391                 binding(event.motion.xrel);
1392             binding = oeskeymap_get(&oeskeymap, keymarkers.mousey);
1393             if (binding)
1394                 binding(event.motion.yrel);
1395 //            oes_bind_mhoriz(event.motion.xrel);
1396 //            oes_bind_mvert(event.motion.yrel);
1397             break;
1398           case SDL_MOUSEBUTTONDOWN:
1399 //            oeskey = oeskeymap_resolve("MOUSE0") + event.button.button;
1400             oeskey = keymarkers.mouse0 + event.button.button;
1401             binding = oeskeymap_get(&oeskeymap, oeskey);
1402             if (binding)
1403                 binding(1);
1404             break;
1405           case SDL_MOUSEBUTTONUP:
1406             oeskey = keymarkers.mouse0 + event.button.button;
1407             binding = oeskeymap_get(&oeskeymap, oeskey);
1408             if (binding)
1409                 binding(0);
1410             break;
1411           case SDL_JOYAXISMOTION:
1412 //            oeskey = oeskeymap_resolve("AXIS1") + event.jaxis.axis;
1413             oeskey = keymarkers.axis1 + event.jaxis.axis;
1414             binding = oeskeymap_get(&oeskeymap, oeskey);
1415             if (binding)
1416               {
1417                 binding(event.jaxis.value);
1418               }
1419             break;
1420           case SDL_JOYBUTTONDOWN:
1421 //            oeskey = oeskeymap_resolve("JOY1") + event.jbutton.button;
1422             oeskey = keymarkers.joy1 + event.jbutton.button;
1423             binding = oeskeymap_get(&oeskeymap, oeskey);
1424             if (binding)
1425                 binding(1);
1426             break;
1427           case SDL_JOYBUTTONUP:
1428             oeskey = keymarkers.joy1 + event.jbutton.button;
1429             binding = oeskeymap_get(&oeskeymap, oeskey);
1430             if (binding)
1431                 binding(0);
1432             break;
1433           case SDL_QUIT:
1434             Game.GameOverReason = OESREASON_QUIT;
1435             return 1;
1436             break;
1437           default:
1438             break;
1439         } //switch event.type
1440     } //while SDL_PollEvent
1441 
1442   if (Game.GameState == OESGAME_PAUSED)
1443     {  /* Don't hog CPU when paused. */
1444       SDL_Delay(100);
1445     }
1446   return 0;
1447 }
1448 
1449 
1450 /* Main game stub. */
1451 int
oes_game()1452 oes_game ()
1453 {
1454   int tick;
1455 
1456   oesjoy.time = Game.LastTick;
1457   Game.GameStartTick = SDL_GetTicks();
1458   Game.LastTick = Game.GameStartTick;
1459   sniperbgm_stimulate(Game.BGM);
1460   Game.GameOverReason = OESREASON_NONE;
1461 
1462   oes_game_grab(1);
1463   while (Game.GameOverReason == OESREASON_NONE)
1464     {
1465       tick = SDL_GetTicks();
1466       switch (Game.GameState)
1467         {
1468           case OESGAME_CHAOS:
1469             oes_game_init(&Game);
1470             sniperbgm_stimulate(Game.BGM);
1471             Game.GameState = OESGAME_PLAY;
1472             break;
1473           case OESGAME_PLAY:
1474             oes_reindeer();
1475             break;
1476           case OESGAME_PAUSED:
1477             Game.LastTick = tick;
1478             break;
1479           case OESGAME_UNPAUSED:
1480             oes_game_pause(0);
1481             break;
1482           default:
1483             Game.GameState = OESGAME_CHAOS;
1484             break;
1485         }
1486 
1487       /* SDL events. */
1488       oes_game_events();
1489       /* joystick-interval handling. */
1490       oes_game_joystick(tick);
1491     }
1492   Game.GameOverTicks = SDL_GetTicks();
1493   oes_game_grab(0);
1494   sniperbgm_depress(Game.BGM);
1495   Game.GameState = OESGAME_CHAOS;
1496 
1497   if (Game.GameOverReason == OESREASON_QUIT)
1498       return 0;
1499   return 1;
1500 }
1501 
1502 
1503 /* Launche web browser to point to a URI. */
1504 int
oes_web(const char * uri)1505 oes_web (const char *uri)
1506 {
1507   char cmd[256];
1508 
1509 /* Don't check URI protocol.  Assume browser understands all. */
1510   oes_game_hide(1);
1511   snprintf(cmd, sizeof(cmd), "%s \"%s\"", gPrefs.wwwbrowser, uri);
1512   return system(cmd);
1513 }
1514 
1515 
1516 /* Widget signal fallback (unhandled/unblocked widget signals) */
1517 //int oes_uisignal (oesui_t *gui, const char *signame)
1518 int
oes_uisignal(oesui_t * gui,oesui_signal_t * sig)1519 oes_uisignal (oesui_t *gui, oesui_signal_t *sig)
1520 {
1521   const char *signame;
1522   SDL_Rect r;
1523 
1524   signame = UISIG_NAME(sig);
1525   if (0);
1526   else if (0 == strcmp(signame, "start-game"))
1527     {
1528       oesui_event(gui, OESUI_CLOSE, 0);
1529       if (oes_game())
1530           oesui_open(gui, "gameover");
1531       else
1532           gui->retcode = 1;
1533       return 1;
1534     }
1535   else if (0 == strcmp(signame, "go-main"))
1536     {
1537       oesui_open(gui, "main");
1538       return 1;
1539     }
1540   else if (0 == strcmp(signame, "go-prefs"))
1541     {
1542       oesui_open(gui, "prefs");
1543       return 1;
1544     }
1545   else if (0 == strcmp(signame, "go-scores"))
1546     {
1547       oesui_open(gui, "highscores");
1548       return 1;
1549     }
1550   else if (0 == strcmp(signame, "frob-fullscreen"))
1551     {
1552       oes_bind_fullscreen(0);
1553       oesui_event(gui, OESUI_UPDATE, 0);
1554       return 1;
1555     }
1556   else if (0 == strcmp(signame, "frob-audio"))
1557     {
1558       gPrefs.audio = !gPrefs.audio;
1559       oesui_event(gui, OESUI_UPDATE, 0);
1560       return 1;
1561     }
1562   else if (0 == strcmp(signame, "frob-skill"))
1563     {
1564       gPrefs.difficulty++;
1565       if (gPrefs.difficulty > 3)
1566           gPrefs.difficulty = 1;
1567       oesui_event(gui, OESUI_UPDATE, 0);
1568       return 1;
1569     }
1570   else if (0 == strcmp(signame, "highscores"))
1571     {
1572       r.x = UISIG_ARG(sig, 1).i;
1573       r.y = UISIG_ARG(sig, 2).i;
1574       r.w = UISIG_ARG(sig, 3).i;
1575       r.h = UISIG_ARG(sig, 4).i;
1576       draw_hiscores(gui->screen, &r);
1577     }
1578   else if (0 == strcmp(signame, "gameover"))
1579     {
1580       r.x = UISIG_ARG(sig, 1).i;
1581       r.y = UISIG_ARG(sig, 2).i;
1582       r.w = UISIG_ARG(sig, 3).i;
1583       r.h = UISIG_ARG(sig, 4).i;
1584       draw_gameover(gui->screen, &r);
1585     }
1586   else if (0 == strcmp(signame, "quit"))
1587     {
1588       gui->retcode = 1;
1589       return 1;
1590     }
1591   else if (0 == strcmp(signame, "url-oes"))
1592     {
1593 #define WEBBROWSER mozilla
1594       /* http://www.icculus.org/oes/ */
1595       oes_web("http://www.icculus.org/oes/");
1596     }
1597   else if (0 == strcmp(signame, "url-os"))
1598     {
1599       /* http://www.iki.fi/sol/ */
1600       oes_web("http://www.iki.fi/sol/");
1601     }
1602   else if (0 == strcmp(signame, "url-td"))
1603     {
1604       /* http://www.timedoctor.org/ */
1605       oes_web("http://www.timedoctor.org/");
1606     }
1607   else if (0 == strcmp(signame, "url-io"))
1608     {
1609       /* http://www.icculus.org/ */
1610       oes_web("http://www.icculus.org/");
1611     }
1612   else if (0 == strcmp(signame, "url-ov"))
1613     {
1614       /* http://www.vorbis.com/ */
1615       oes_web("http://www.vorbis.com/");
1616     }
1617   return 0;
1618 }
1619 
1620 
1621 int
oes_binds_init()1622 oes_binds_init ()
1623 {
1624 /* TODO: bind map */
1625 /* sane joystick defaults. */
1626     oesjoy.style = 0;
1627     oesjoy.scale = 10.0f;
1628     oesjoy.interval = 20;
1629 #if 0
1630     oesjoy.axis[0] = oes_bind_jhoriz;
1631     oesjoy.axis[1] = oes_bind_jvert;
1632     oesjoy.axis[2] = oes_bind_jdeep;
1633     oesjoy.button[0] = oes_bind_fire;
1634     oesjoy.button[1] = oes_bind_zoom;
1635     oesjoy.button[2] = oes_bind_zoomout;
1636     oesjoy.button[3] = oes_bind_zoomin;
1637 #endif /* 0 */
1638 
1639   oeskeymap_init(&oeskeymap);
1640   oeskeymap_load(&oeskeymap, gPrefs.bindpath);
1641 //  oeskeymap_set(&oeskeymap, SDLK_a, oes_bind_fire); //test
1642   oeskeymap_set(&oeskeymap, SDLK_v, oes_bind_verbosity, 1);
1643   oeskeymap_set(&oeskeymap, SDLK_p, oes_bind_pause, 1);
1644   oeskeymap_set(&oeskeymap, SDLK_s, oes_bind_screenshot, 1);
1645   oeskeymap_set(&oeskeymap, SDLK_ESCAPE, oes_bind_abandon, 1);
1646   oeskeymap_set(&oeskeymap, oeskeymap_resolve("MOUSEX"), oes_bind_mhoriz, 1);
1647   oeskeymap_set(&oeskeymap, oeskeymap_resolve("MOUSEY"), oes_bind_mvert, 1);
1648   oeskeymap_set(&oeskeymap, oeskeymap_resolve("MOUSE1"), oes_bind_fire, 1);
1649   oeskeymap_set(&oeskeymap, oeskeymap_resolve("MOUSE2"), oes_bind_zoom, 1);
1650   oeskeymap_set(&oeskeymap, oeskeymap_resolve("MOUSE4"), oes_bind_zoomin, 1);
1651   oeskeymap_set(&oeskeymap, oeskeymap_resolve("MOUSE5"), oes_bind_zoomout, 1);
1652   oeskeymap_set(&oeskeymap, oeskeymap_resolve("JOY1"), oes_bind_fire, 1);
1653   oeskeymap_set(&oeskeymap, oeskeymap_resolve("JOY2"), oes_bind_zoom, 1);
1654   oeskeymap_set(&oeskeymap, oeskeymap_resolve("JOY3"), oes_bind_zoomin, 1);
1655   oeskeymap_set(&oeskeymap, oeskeymap_resolve("JOY4"), oes_bind_zoomout, 1);
1656   oeskeymap_set(&oeskeymap, oeskeymap_resolve("AXIS1"), oes_bind_jhoriz, 10);
1657   oeskeymap_set(&oeskeymap, oeskeymap_resolve("AXIS2"), oes_bind_jvert, 10);
1658   oeskeymap_set(&oeskeymap, oeskeymap_resolve("AXIS3"), oes_bind_jdeep, 10);
1659   keymarkers.mousex = oeskeymap_resolve("MOUSEX");
1660   keymarkers.mousey = oeskeymap_resolve("MOUSEY");
1661   keymarkers.mouse0 = oeskeymap_resolve("MOUSE0");
1662   keymarkers.axis1 = oeskeymap_resolve("AXIS1");
1663   keymarkers.joy1 = oeskeymap_resolve("JOY1");
1664 
1665   return 0;
1666 }
1667 
1668 
main(int argc,char * argv[])1669 int main(int argc, char *argv[])
1670 {
1671     oesui_t *gui;
1672 
1673     srand(SDL_GetTicks());
1674 
1675     /*
1676     Game.mediaPath = (char*)calloc(strlen(argv[0]), sizeof(char));
1677 //   invocation = (char*)malloc(strlen(argv[0]) + 1); memcpy(invocation, argv[0], strlen(argv[0]));
1678     invocation = strdup(argv[0]);
1679     sprintf(Game.mediaPath, "%s", dirname(invocation));
1680     free(invocation);
1681     */
1682     Game.mediaPath = strdup(GAMEDATADIR);
1683     invocation = argv[0];
1684 
1685     /* Load Preferences. */
1686     prefs_init(&gPrefs);
1687     prefs_load(&gPrefs);
1688     Game.verbosity = gPrefs.verbose;
1689 
1690     /* Parse options, which may override saved preferences. */
1691     parse_args(argc, argv);
1692 
1693     oes_binds_init();
1694     oes_setup ();  /* prefs initialized in here */
1695 
1696 
1697     gui = oesui_init_surface(NULL, Game.Screen);  /* initialise gui */
1698     oesui_load(gui, "menus.cfg");  /* Load gui data */
1699     oesui_sighandle(gui, oes_uisignal);  /* widget signal handler */
1700     oesui_open(gui, "main");  /* Main menu */
1701     oesui_loop(gui);  /* Main UI loop */
1702 
1703 
1704     oes_teardown ();
1705 //    delete[] mediaPath;
1706     free(Game.mediaPath);
1707 
1708 //    oes_audio_close();
1709     return 0;
1710 }
1711 
1712 
configure_difficulty()1713 void configure_difficulty()
1714 {
1715     gPrefs.difficulty = (gPrefs.difficulty < 1 ? 1 : gPrefs.difficulty);
1716     gPrefs.difficulty = (gPrefs.difficulty > 3 ? 3 : gPrefs.difficulty);
1717     switch (gPrefs.difficulty)
1718 	{
1719 	case 1:
1720 	    Game.ReloadTime = 1500;
1721 	    Game.ScoreMod = 1.5;
1722 	    break;
1723 	case 2:
1724 	    Game.ReloadTime = 3000;
1725 	    Game.ScoreMod = 1.0;
1726 	    break;
1727 	case 3:
1728 	    Game.ReloadTime = 4000;
1729 	    Game.ScoreMod = 0.5;
1730 	    break;
1731 	}
1732 }
1733 
1734 #if 0
1735 void draw_button (SDL_Surface *b, int x, int y)
1736 {
1737     SDL_Rect d;
1738 
1739     d.x = x;
1740     d.y = y;
1741     d.h = 32;
1742     d.w = 196;
1743 
1744     SDL_BlitSurface (b, NULL, Game.Screen, &d);
1745 }
1746 #endif /* 0 */
1747 
oes_load_img(const char * path)1748 SDL_Surface *oes_load_img (const char *path)
1749 {
1750     SDL_Surface *sfc = NULL;
1751     char lpath[PATH_MAX];
1752     snprintf (lpath, PATH_MAX, "%s/%s", Game.mediaPath, path);
1753     sfc = IMG_Load (lpath);
1754     if (!sfc) {
1755 	fprintf(stderr,"Unable to load image '%s': %s\n",lpath,SDL_GetError());
1756 	exit (1);
1757     }
1758     return sfc;
1759 }
1760 
1761 #if 0
1762 bool hovering (int x, int y, int w, int h)
1763 {
1764     int lx, ly;
1765     SDL_GetMouseState (&lx, &ly);
1766     if ((lx > x) && (ly > y) &&
1767 	(lx < x + w) && (ly < y + h))
1768 	return true;
1769     return false;
1770 }
1771 #endif /* 0 */
1772