Merged source:branches/pause (revisions 954:1064) into trunk (replace the old pause...
[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 #include "st_pause.h"
49
50 #define TITLE "Neverball"
51
52 /*---------------------------------------------------------------------------*/
53
54 static void shot(void)
55 {
56     static char filename[MAXSTR];
57     static int  num = 0;
58
59     sprintf(filename, "screen%02d.png", num++);
60
61     image_snap(filename);
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     int c;
103
104     while (d && SDL_PollEvent(&e))
105     {
106         switch (e.type)
107         {
108         case SDL_QUIT:
109             return 0;
110
111         case SDL_MOUSEMOTION:
112             st_point(+e.motion.x,
113                      -e.motion.y + config_get_d(CONFIG_HEIGHT),
114                      +e.motion.xrel,
115                      config_get_d(CONFIG_MOUSE_INVERT)
116                      ? +e.motion.yrel : -e.motion.yrel);
117             break;
118
119         case SDL_MOUSEBUTTONDOWN:
120             d = st_click((e.button.button == SDL_BUTTON_LEFT) ? -1 : 1, 1);
121             break;
122
123         case SDL_MOUSEBUTTONUP:
124             d = st_click((e.button.button == SDL_BUTTON_LEFT) ? -1 : 1, 0);
125             break;
126
127         case SDL_KEYDOWN:
128
129             c = e.key.keysym.sym;
130
131             if (config_tst_d(CONFIG_KEY_FORWARD, c))
132                 st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), -JOY_MAX);
133
134             else if (config_tst_d(CONFIG_KEY_BACKWARD, c))
135                 st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), +JOY_MAX);
136
137             else if (config_tst_d(CONFIG_KEY_LEFT, c))
138                 st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), -JOY_MAX);
139
140             else if (config_tst_d(CONFIG_KEY_RIGHT, c))
141                 st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), +JOY_MAX);
142
143             else switch (c)
144             {
145             case SDLK_F11:   toggle_fullscreen();       break;
146             case SDLK_F10:   shot();                    break;
147             case SDLK_F9:    config_tgl_d(CONFIG_FPS);  break;
148             case SDLK_F8:    config_tgl_d(CONFIG_NICE); break;
149
150             case SDLK_F7:
151                 if (config_get_cheat())
152                     toggle_wire();
153                 break;
154
155             case SDLK_RETURN:
156                 d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 1);
157                 break;
158             case SDLK_ESCAPE:
159                 d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 1);
160                 break;
161
162             default:
163                 if (SDL_EnableUNICODE(-1))
164                     d = st_keybd(e.key.keysym.unicode, 1);
165                 else
166                     d = st_keybd(e.key.keysym.sym, 1);
167             }
168
169             break;
170
171         case SDL_KEYUP:
172
173             c = e.key.keysym.sym;
174
175             if (config_tst_d(CONFIG_KEY_FORWARD, c))
176                 st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), 1);
177
178             else if (config_tst_d(CONFIG_KEY_BACKWARD, c))
179                 st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), 1);
180
181             else if (config_tst_d(CONFIG_KEY_LEFT, c))
182                 st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), 1);
183
184             else if (config_tst_d(CONFIG_KEY_RIGHT, c))
185                 st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), 1);
186
187             else switch (c)
188             {
189             case SDLK_RETURN:
190                 d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 0);
191                 break;
192             case SDLK_ESCAPE:
193                 d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 0);
194                 break;
195
196             default:
197                 d = st_keybd(e.key.keysym.sym, 0);
198             }
199
200         case SDL_ACTIVEEVENT:
201             if (e.active.state == SDL_APPINPUTFOCUS)
202                 if (e.active.gain == 0 && config_get_grab())
203                     goto_pause();
204             break;
205
206         case SDL_JOYAXISMOTION:
207             st_stick(e.jaxis.axis, e.jaxis.value);
208             break;
209
210         case SDL_JOYBUTTONDOWN:
211             d = st_buttn(e.jbutton.button, 1);
212             break;
213
214         case SDL_JOYBUTTONUP:
215             d = st_buttn(e.jbutton.button, 0);
216             break;
217         }
218     }
219     return d;
220 }
221
222 /*---------------------------------------------------------------------------*/
223
224 /* Option values */
225
226 static char *data_path    = NULL;
227 static char *replay_path  = NULL;
228 static int   display_info = 0;
229
230 /* Option handling */
231
232 static void parse_args(int argc, char **argv)
233 {
234     char *exec = *(argv++);
235     int missing;
236
237     const char *usage = _(
238         "Usage: %s [options ...]\n"
239         "-r, --replay file         play the replay 'file'.\n"
240         "-i, --info                display info about a replay.\n"
241         "    --data dir            use 'dir' as game data directory.\n"
242         "-v, --version             show version.\n"
243         "-h, -?, --help            show this usage message.\n"
244     );
245
246 #   define CASE(x) (strcmp(*argv, (x)) == 0)       /* Check current option */
247 #   define MAND    !(missing = (argv[1] == NULL))  /* Argument is mandatory */
248
249     while (*argv != NULL)
250     {
251         missing = 0;
252         if (CASE("-h") || CASE("-?") || CASE("--help"))
253         {
254             printf(usage, exec);
255             exit(0);
256         }
257         else if (CASE("-v") || CASE("--version"))
258         {
259             printf("%s\n", VERSION);
260             exit(0);
261         }
262         else if (CASE("--data") && MAND)
263             data_path = *(++argv);
264         else if ((CASE("-r") || CASE("--replay")) && MAND)
265             replay_path = *(++argv);
266         else if ((CASE("-i") || CASE("--info")))
267             display_info = 1;
268         else if (!missing)
269         {
270             fprintf(stderr, _("%s: unknown option %s\n"), exec, *argv);
271             fprintf(stderr, usage, exec);
272             exit(1);
273         }
274         else
275         {
276             fprintf(stderr, _("%s: option %s requires an argument\n"), exec,
277                     *argv);
278             fprintf(stderr, usage, exec);
279             exit(1);
280         }
281         argv++;
282     }
283
284 #   undef CASE
285 #   undef MAND
286
287     return;
288 }
289
290 int main(int argc, char *argv[])
291 {
292     SDL_Joystick *joy = NULL;
293     SDL_Surface *icon;
294
295     int t1, t0;
296
297     language_init("neverball", CONFIG_LOCALE);
298
299     parse_args(argc, argv);
300
301     if (!config_data_path(data_path, SET_FILE))
302     {
303         fprintf(stderr, _("Failure to establish game data directory\n"));
304         return 1;
305     }
306
307     if (!config_user_path(NULL))
308     {
309         fprintf(stderr, _("Failure to establish config directory\n"));
310         return 1;
311     }
312
313     /* Initialize SDL system and subsystems */
314
315     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) == -1)
316     {
317         fprintf(stderr, "%s\n", SDL_GetError());
318         return 1;
319     }
320
321     /* Intitialize the configuration */
322
323     config_init();
324     config_load();
325
326     /* Initialize the language */
327
328     language_set(language_from_code(config_simple_get_s(CONFIG_LANG)));
329
330     /* Prepare run without GUI */
331
332     if (replay_path)
333     {
334         if (!level_replay(replay_path))
335         {
336             fprintf(stderr, _("Replay file '%s': %s\n"), replay_path,
337                     errno ? strerror(errno) : _("Not a replay file"));
338             return 1;
339         }
340         else if (display_info)
341             demo_replay_dump_info();
342     }
343
344     if (display_info)
345     {
346         if (replay_path == NULL)
347         {
348             fprintf(stderr, _("%s: --info requires --replay\n"),
349                     argv[0]);
350             return 1;
351         }
352         return 0;
353     }
354
355     /* Initialize the joystick. */
356
357     if (SDL_NumJoysticks() > 0)
358     {
359         joy = SDL_JoystickOpen(config_get_d(CONFIG_JOYSTICK_DEVICE));
360         if (joy)
361             SDL_JoystickEventState(SDL_ENABLE);
362     }
363
364     /* Initialize the audio. */
365
366     audio_bind(AUD_MENU,   3, "snd/menu.wav");
367     audio_bind(AUD_START,  1, _("snd/select.ogg"));
368     audio_bind(AUD_READY,  1, _("snd/ready.ogg"));
369     audio_bind(AUD_SET,    1, _("snd/set.ogg"));
370     audio_bind(AUD_GO,     1, _("snd/go.ogg"));
371     audio_bind(AUD_BALL,   2, "snd/ball.ogg");
372     audio_bind(AUD_BUMPS,  3, "snd/bumplil.ogg");
373     audio_bind(AUD_BUMPM,  3, "snd/bump.ogg");
374     audio_bind(AUD_BUMPL,  3, "snd/bumpbig.ogg");
375     audio_bind(AUD_COIN,   2, "snd/coin.wav");
376     audio_bind(AUD_TICK,   4, "snd/tick.ogg");
377     audio_bind(AUD_TOCK,   4, "snd/tock.ogg");
378     audio_bind(AUD_SWITCH, 5, "snd/switch.wav");
379     audio_bind(AUD_JUMP,   5, "snd/jump.ogg");
380     audio_bind(AUD_GOAL,   5, "snd/goal.wav");
381     audio_bind(AUD_SCORE,  1, _("snd/record.ogg"));
382     audio_bind(AUD_FALL,   1, _("snd/fall.ogg"));
383     audio_bind(AUD_TIME,   1, _("snd/time.ogg"));
384     audio_bind(AUD_OVER,   1, _("snd/over.ogg"));
385     audio_bind(AUD_GROW,   5, "snd/grow.ogg");
386     audio_bind(AUD_SHRINK, 5, "snd/shrink.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     /* Set the WM icon */
399
400     icon = IMG_Load(config_data("icon/neverball.png"));
401
402     if (icon)
403     {
404         SDL_WM_SetIcon(icon, NULL);
405         SDL_FreeSurface(icon);
406     }
407
408     /* Initialize the video. */
409
410     if (!config_mode(config_get_d(CONFIG_FULLSCREEN),
411                      config_get_d(CONFIG_WIDTH), config_get_d(CONFIG_HEIGHT)))
412     {
413         fprintf(stderr, "%s\n", SDL_GetError());
414         return 1;
415     }
416
417     SDL_WM_SetCaption(TITLE, TITLE);
418
419     /* Initialize the run state. */
420
421     init_state(&st_null);
422
423     if (replay_path)
424     {
425         level_replay(replay_path);
426         demo_play_goto(1);
427         goto_state(&st_demo_play);
428     }
429     else
430         goto_state(&st_title);
431
432     /* Run the main game loop. */
433
434     t0 = SDL_GetTicks();
435     while (loop())
436         if ((t1 = SDL_GetTicks()) > t0)
437         {
438             st_timer((t1 - t0) / 1000.f);
439             st_paint();
440             SDL_GL_SwapBuffers();
441
442             t0 = t1;
443
444             if (config_get_d(CONFIG_NICE))
445                 SDL_Delay(1);
446         }
447
448     /* Gracefully close the game */
449
450     if (SDL_JoystickOpened(0))
451         SDL_JoystickClose(joy);
452
453     SDL_Quit();
454
455     config_save();
456
457     return 0;
458 }
459
460 /*---------------------------------------------------------------------------*/
461