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