Remove duplicate macro definition.
[neverball] / ball / main.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 /*---------------------------------------------------------------------------*/
16
17 #ifdef WIN32
18 #pragma comment(lib, "SDL_ttf.lib")
19 #pragma comment(lib, "SDL_mixer.lib")
20 #pragma comment(lib, "SDL_image.lib")
21 #pragma comment(lib, "SDL.lib")
22 #pragma comment(lib, "SDLmain.lib")
23 #pragma comment(lib, "opengl32.lib")
24 #endif
25
26 /*---------------------------------------------------------------------------*/
27
28 #include <SDL.h>
29 #include <SDL_image.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <errno.h>
33
34 #include "glext.h"
35 #include "config.h"
36 #include "image.h"
37 #include "audio.h"
38 #include "demo.h"
39 #include "levels.h"
40 #include "game.h"
41 #include "gui.h"
42 #include "set.h"
43
44 #include "st_conf.h"
45 #include "st_title.h"
46 #include "st_demo.h"
47 #include "st_level.h"
48
49 #define TITLE "Neverball"
50
51 /*---------------------------------------------------------------------------*/
52
53 static void shot(void)
54 {
55     static char filename[MAXSTR];
56     static int  num = 0;
57
58     sprintf(filename, _("screen%02d.png"), num++);
59
60     image_snap(filename, config_get_d(CONFIG_WIDTH),
61                config_get_d(CONFIG_HEIGHT));
62 }
63
64 /*---------------------------------------------------------------------------*/
65
66 static void toggle_wire(void)
67 {
68     static int wire = 0;
69
70     if (wire)
71     {
72         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
73         glEnable(GL_TEXTURE_2D);
74         glEnable(GL_LIGHTING);
75         wire = 0;
76     }
77     else
78     {
79         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
80         glDisable(GL_TEXTURE_2D);
81         glDisable(GL_LIGHTING);
82         wire = 1;
83     }
84 }
85
86 static void toggle_fullscreen(void)
87 {
88     int x, y;
89
90     SDL_GetMouseState(&x, &y);
91     config_mode(!config_get_d(CONFIG_FULLSCREEN), config_get_d(CONFIG_WIDTH),
92                 config_get_d(CONFIG_HEIGHT));
93     SDL_WarpMouse(x, y);
94 }
95
96 /*---------------------------------------------------------------------------*/
97
98 static int loop(void)
99 {
100     SDL_Event e;
101     int d = 1;
102
103     while (d && SDL_PollEvent(&e))
104     {
105         if (e.type == SDL_QUIT)
106             return 0;
107
108         if (e.type == SDL_KEYDOWN)
109             switch (e.key.keysym.sym)
110             {
111             case SDLK_SPACE: config_tgl_pause();        break;
112             case SDLK_F11:   toggle_fullscreen();       break;
113             case SDLK_F10:   shot();                    break;
114             case SDLK_F9:    config_tgl_d(CONFIG_FPS);  break;
115             case SDLK_F8:    config_tgl_d(CONFIG_NICE); break;
116             case SDLK_F7:    toggle_wire();             break;
117             default: break;
118             }
119
120         if (!config_get_pause())
121             switch (e.type)
122             {
123             case SDL_MOUSEMOTION:
124                 st_point(+e.motion.x,
125                          -e.motion.y + config_get_d(CONFIG_HEIGHT),
126                          +e.motion.xrel,
127                          config_get_d(CONFIG_MOUSE_INVERT)
128                          ? +e.motion.yrel : -e.motion.yrel);
129                 break;
130
131             case SDL_MOUSEBUTTONDOWN:
132                 d = st_click((e.button.button == SDL_BUTTON_LEFT) ? -1 : 1, 1);
133                 break;
134
135             case SDL_MOUSEBUTTONUP:
136                 d = st_click((e.button.button == SDL_BUTTON_LEFT) ? -1 : 1, 0);
137                 break;
138
139             case SDL_KEYDOWN:
140
141                 switch (e.key.keysym.sym)
142                 {
143
144                 case SDLK_RETURN:
145                     d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 1);
146                     break;
147                 case SDLK_ESCAPE:
148                     d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 1);
149                     break;
150                 case SDLK_LEFT:
151                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), -JOY_MAX);
152                     break;
153                 case SDLK_RIGHT:
154                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), +JOY_MAX);
155                     break;
156                 case SDLK_UP:
157                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), -JOY_MAX);
158                     break;
159                 case SDLK_DOWN:
160                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), +JOY_MAX);
161                     break;
162
163                 default:
164                     if (SDL_EnableUNICODE(-1))
165                         d = st_keybd(e.key.keysym.unicode, 1);
166                     else
167                         d = st_keybd(e.key.keysym.sym, 1);
168                 }
169                 break;
170
171             case SDL_KEYUP:
172
173                 switch (e.key.keysym.sym)
174                 {
175                 case SDLK_RETURN:
176                     d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 0);
177                     break;
178                 case SDLK_ESCAPE:
179                     d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 0);
180                     break;
181                 case SDLK_LEFT:
182                 case SDLK_RIGHT:
183                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), 1);
184                     break;
185                 case SDLK_DOWN:
186                 case SDLK_UP:
187                     st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), 1);
188                     break;
189
190                 default:
191                     d = st_keybd(e.key.keysym.sym, 0);
192                 }
193
194                 break;
195
196             case SDL_ACTIVEEVENT:
197                 if (e.active.state == SDL_APPINPUTFOCUS)
198                     if (e.active.gain == 0 && config_get_grab())
199                         config_set_pause();
200                 break;
201
202             case SDL_JOYAXISMOTION:
203                 st_stick(e.jaxis.axis, e.jaxis.value);
204                 break;
205
206             case SDL_JOYBUTTONDOWN:
207                 d = st_buttn(e.jbutton.button, 1);
208                 break;
209
210             case SDL_JOYBUTTONUP:
211                 d = st_buttn(e.jbutton.button, 0);
212                 break;
213             }
214     }
215     return d;
216 }
217
218 /*---------------------------------------------------------------------------*/
219
220 /* Option values */
221 static char *data_path    = NULL;
222 static char *replay_path  = NULL;
223 static char *level_path   = NULL;
224 static int   display_info = 0;
225
226 /* Option handling */
227
228 #define USAGE  _( \
229         "Usage: %s [options ...]\n" \
230         "-r, --replay file         play the replay 'file'.\n" \
231         "-l, --level file.sol      play the level 'file.sol'.\n" \
232         "-i, --info                display info about level or replay.\n" \
233         "    --data dir            use 'dir' as game data directory.\n" \
234         "-v, --version             show version.\n" \
235         "-h, -?, --help            show this usage message.\n")
236
237 static void parse_args(int argc, char **argv)
238 {
239 #define CASE(x) (strcmp(*argv, (x)) == 0)       /* Check current option */
240 #define MAND    !(missing = (argv[1] == NULL))  /* Argument is mandatory */
241     char *exec = *(argv++);
242     int missing; /* Argument is missing. */
243
244     while (*argv != NULL)
245     {
246         missing = 0;
247         if (CASE("-h") || CASE("-?") || CASE("--help"))
248         {
249             printf(USAGE, exec);
250             exit(0);
251         }
252         else if (CASE("-v") || CASE("--version"))
253         {
254             printf(_("%s: %s version %s\n"), exec, TITLE, VERSION);
255             exit(0);
256         }
257         else if (CASE("--data") && MAND)
258             data_path = *(++argv);
259         else if ((CASE("-r") || CASE("--replay")) && MAND)
260             replay_path = *(++argv);
261         else if ((CASE("-l") || CASE("--level")) && MAND)
262             level_path = *(++argv);
263         else if ((CASE("-i") || CASE("--info")))
264             display_info = 1;
265         else if (!missing)
266         {
267             fprintf(stderr, _("%s: unknown option %s\n"), exec, *argv);
268             fprintf(stderr, USAGE, exec);
269             exit(1);
270         }
271         else
272         {
273             fprintf(stderr, _("%s: option %s requires an argument\n"), exec,
274                     *argv);
275             fprintf(stderr, USAGE, exec);
276             exit(1);
277         }
278         argv++;
279     }
280     return;
281 }
282
283 int main(int argc, char *argv[])
284 {
285     SDL_Joystick *joy = NULL;
286     int t1, t0;               /* ticks */
287     SDL_Surface *icon;        /* WM icon */
288
289     language_init("neverball", CONFIG_LOCALE);
290
291     parse_args(argc, argv);
292
293     if (!config_data_path(data_path, SET_FILE))
294     {
295         fprintf(stderr, _("Failure to establish game data directory\n"));
296         return 1;
297     }
298
299     if (!config_user_path(NULL))
300     {
301         fprintf(stderr, _("Failure to establish config directory\n"));
302         return 1;
303     }
304
305     /* Intitialize the configuration */
306
307     config_init();
308     config_load();
309
310     /* Initialize the language */
311
312     language_set(language_from_code(config_simple_get_s(CONFIG_LANG)));
313
314     /* Prepare run without sdl */
315
316     if (replay_path != NULL)
317     {
318         if (!level_replay(replay_path))
319         {
320             fprintf(stderr, _("Replay file '%s': "), replay_path);
321             if (errno)
322                 perror(NULL);
323             else
324                 fprintf(stderr, _("Not a replay file\n"));
325             return 1;
326         }
327         else if (display_info)
328             demo_replay_dump_info();
329     }
330
331     if (level_path != NULL)
332     {
333         struct level l;
334         if (!level_load(level_path, &l))
335             return 1;
336         else if (display_info)
337             level_dump_info(&l);
338     }
339
340     if (display_info)
341     {
342         if (replay_path == NULL && level_path == NULL)
343         {
344             fprintf(stderr, _("%s: --info requires --replay or --level\n"),
345                     argv[0]);
346             return 1;
347         }
348         return 0;
349     }
350
351     /* Initialize SDL system and subsystems */
352
353     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) == -1)
354     {
355         fprintf(stderr, "%s\n", SDL_GetError());
356         return 1;
357     }
358
359     /* Initialize the joystick. */
360
361     if (SDL_NumJoysticks() > 0)
362     {
363         joy = SDL_JoystickOpen(config_get_d(CONFIG_JOYSTICK_DEVICE));
364         if (joy)
365             SDL_JoystickEventState(SDL_ENABLE);
366     }
367
368     /* Initialize the audio. */
369
370     audio_bind(AUD_MENU,   3, "snd/menu.wav");
371     audio_bind(AUD_START,  1, "snd/select.ogg");
372     audio_bind(AUD_READY,  1, "snd/ready.ogg");
373     audio_bind(AUD_SET,    1, "snd/set.ogg");
374     audio_bind(AUD_GO,     1, "snd/go.ogg");
375     audio_bind(AUD_BALL,   2, "snd/ball.ogg");
376     audio_bind(AUD_BUMP,   3, "snd/bump.ogg");
377     audio_bind(AUD_COIN,   2, "snd/coin.wav");
378     audio_bind(AUD_TICK,   4, "snd/tick.ogg");
379     audio_bind(AUD_TOCK,   4, "snd/tock.ogg");
380     audio_bind(AUD_SWITCH, 5, "snd/switch.wav");
381     audio_bind(AUD_JUMP,   5, "snd/jump.ogg");
382     audio_bind(AUD_GOAL,   5, "snd/goal.wav");
383     audio_bind(AUD_SCORE,  1, "snd/record.ogg");
384     audio_bind(AUD_FALL,   1, "snd/fall.ogg");
385     audio_bind(AUD_TIME,   1, "snd/time.ogg");
386     audio_bind(AUD_OVER,   1, "snd/over.ogg");
387
388     audio_init();
389
390     /* Require 16-bit double buffer with 16-bit depth buffer. */
391
392     SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     5);
393     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   5);
394     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    5);
395     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  16);
396     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
397
398     /* Initialize the video. */
399
400     if (!config_mode(config_get_d(CONFIG_FULLSCREEN),
401                      config_get_d(CONFIG_WIDTH), config_get_d(CONFIG_HEIGHT)))
402     {
403         fprintf(stderr, "%s\n", SDL_GetError());
404         return 1;
405     }
406
407     /* Set the WM icon */
408
409     icon = IMG_Load(config_data("icon/neverball.png"));
410     SDL_WM_SetIcon(icon, NULL);
411     SDL_WM_SetCaption(TITLE, TITLE);
412
413     /* Initialize the run state. */
414
415     init_state(&st_null);
416     if (replay_path != NULL)
417     {
418         level_replay(replay_path);
419         goto_demo_play(1);
420     }
421     else if (level_path != NULL)
422     {
423         level_play_single(level_path);
424         goto_state(&st_level);
425     }
426     else
427         goto_state(&st_title);
428
429     /* Run the main game loop. */
430
431     t0 = SDL_GetTicks();
432     while (loop())
433         if ((t1 = SDL_GetTicks()) > t0)
434         {
435             if (config_get_pause())
436             {
437                 st_paint();
438                 gui_blank();
439                 SDL_Delay(10); /* Be nice! */
440             }
441             else
442             {
443                 st_timer((t1 - t0) / 1000.f);
444                 st_paint();
445             }
446             SDL_GL_SwapBuffers();
447
448             t0 = t1;
449
450             if (config_get_d(CONFIG_NICE))
451                 SDL_Delay(1);
452         }
453
454     /* Gracefully close the game */
455
456     if (SDL_JoystickOpened(0))
457         SDL_JoystickClose(joy);
458
459     SDL_Quit();
460
461     config_save();
462
463     return 0;
464 }
465
466 /*---------------------------------------------------------------------------*/
467