Add a "idle" method to the state structure
[neverball] / ball / st_conf.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 #include "gui.h"
16 #include "hud.h"
17 #include "geom.h"
18 #include "item.h"
19 #include "ball.h"
20 #include "part.h"
21 #include "audio.h"
22 #include "config.h"
23 #include "video.h"
24 #include "common.h"
25
26 #include "game_common.h"
27 #include "game_client.h"
28 #include "game_server.h"
29
30 #include "st_conf.h"
31 #include "st_title.h"
32 #include "st_resol.h"
33 #include "st_name.h"
34 #include "st_ball.h"
35 #include "st_shared.h"
36
37 extern const char TITLE[];
38 extern const char ICON[];
39
40 /*---------------------------------------------------------------------------*/
41
42 static void conf_slider(int id, const char *text,
43                         int token, int value,
44                         int *ids, int num)
45 {
46     int jd, kd, i;
47
48     if ((jd = gui_harray(id)) && (kd = gui_harray(jd)))
49     {
50         /* A series of empty buttons forms a "slider". */
51
52         for (i = num - 1; i >= 0; i--)
53             ids[i] = gui_state(kd, NULL, GUI_SML, token + i, (i == value));
54
55         gui_label(jd, text, GUI_SML, GUI_ALL, 0, 0);
56     }
57 }
58
59 static int conf_state(int id, const char *label, const char *text, int token)
60 {
61     int jd, kd, rd = 0;
62
63     if ((jd = gui_harray(id)) && (kd = gui_harray(jd)))
64     {
65         rd = gui_state(kd, text, GUI_SML, token, 0);
66         gui_label(jd, label, GUI_SML, GUI_ALL, 0, 0);
67     }
68
69     return rd;
70 }
71
72 static void conf_toggle(int id, const char *label, int value,
73                         const char *text1, int token1, int value1,
74                         const char *text0, int token0, int value0)
75 {
76     int jd, kd;
77
78     if ((jd = gui_harray(id)) && (kd = gui_harray(jd)))
79     {
80         gui_state(kd, text0, GUI_SML, token0, (value == value0));
81         gui_state(kd, text1, GUI_SML, token1, (value == value1));
82
83         gui_label(jd, label, GUI_SML, GUI_ALL, 0, 0);
84     }
85 }
86
87 static void conf_header(int id, const char *text, int token)
88 {
89     int jd;
90
91     if ((jd = gui_harray(id)))
92     {
93         gui_label(jd, text, GUI_SML, GUI_ALL, 0, 0);
94         gui_space(jd);
95         gui_start(jd, _("Back"), GUI_SML, token, 0);
96     }
97
98     gui_space(id);
99 }
100
101 /*---------------------------------------------------------------------------*/
102
103 #define CONF_SHARED_BACK 1              /* Shared GUI token.                 */
104
105 static int (*conf_shared_action)(int i);
106
107 static void conf_shared_init(int (*action_fn)(int))
108 {
109     conf_shared_action = action_fn;
110
111     game_client_free(NULL);
112     back_init("back/gui.png");
113     audio_music_fade_to(0.5f, "bgm/inter.ogg");
114 }
115
116 static void conf_shared_leave(struct state *st, struct state *next, int id)
117 {
118     back_free();
119     gui_delete(id);
120 }
121
122 static void conf_shared_paint(int id, float t)
123 {
124     video_push_persp((float) config_get_d(CONFIG_VIEW_FOV), 0.1f, FAR_DIST);
125     {
126         back_draw_easy();
127     }
128     video_pop_matrix();
129     gui_paint(id);
130 }
131
132 static int conf_shared_buttn(int b, int d)
133 {
134     if (d)
135     {
136         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
137             return conf_shared_action(gui_token(gui_click()));
138         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
139             return conf_shared_action(CONF_SHARED_BACK);
140     }
141     return 1;
142 }
143
144 /*---------------------------------------------------------------------------*/
145
146 enum
147 {
148     CONF_BACK = CONF_SHARED_BACK,
149     CONF_VIDEO,
150     CONF_PLAYER,
151     CONF_BALL
152 };
153
154 static int music_id[11];
155 static int sound_id[11];
156
157 static int conf_action(int i)
158 {
159     int s = config_get_d(CONFIG_SOUND_VOLUME);
160     int m = config_get_d(CONFIG_MUSIC_VOLUME);
161     int r = 1;
162
163     audio_play(AUD_MENU, 1.0f);
164
165     switch (i)
166     {
167     case CONF_BACK:
168         goto_state(&st_title);
169         break;
170
171     case CONF_VIDEO:
172         goto_state(&st_conf_video);
173         break;
174
175     case CONF_PLAYER:
176         goto_name(&st_conf, &st_conf, 1);
177         break;
178
179     case CONF_BALL:
180         goto_state(&st_ball);
181         break;
182
183     default:
184         if (100 <= i && i <= 110)
185         {
186             int n = i - 100;
187
188             config_set_d(CONFIG_SOUND_VOLUME, n);
189             audio_volume(n, m);
190             audio_play(AUD_BUMPM, 1.f);
191
192             gui_toggle(sound_id[n]);
193             gui_toggle(sound_id[s]);
194         }
195         if (200 <= i && i <= 210)
196         {
197             int n = i - 200;
198
199             config_set_d(CONFIG_MUSIC_VOLUME, n);
200             audio_volume(s, n);
201             audio_play(AUD_BUMPM, 1.f);
202
203             gui_toggle(music_id[n]);
204             gui_toggle(music_id[m]);
205         }
206     }
207
208     return r;
209 }
210
211 static int conf_gui(void)
212 {
213     int id;
214
215     /* Initialize the configuration GUI. */
216
217     if ((id = gui_vstack(0)))
218     {
219         int s = config_get_d(CONFIG_SOUND_VOLUME);
220         int m = config_get_d(CONFIG_MUSIC_VOLUME);
221
222         const char *player = config_get_s(CONFIG_PLAYER);
223         const char *ball   = config_get_s(CONFIG_BALL_FILE);
224
225         int name_id = 0, ball_id = 0;
226
227         conf_header(id, _("Options"), CONF_BACK);
228
229         conf_state(id, _("Video"), _("Configure"), CONF_VIDEO);
230
231         gui_space(id);
232
233         conf_slider(id, _("Sound Volume"), 100, s,
234                     sound_id, ARRAYSIZE(sound_id));
235         conf_slider(id, _("Music Volume"), 200, m,
236                     music_id, ARRAYSIZE(music_id));
237
238         gui_space(id);
239
240         name_id = conf_state(id, _("Player Name"), " ", CONF_PLAYER);
241         ball_id = conf_state(id, _("Ball Model"), " ", CONF_BALL);
242
243         gui_layout(id, 0, 0);
244
245         gui_set_trunc(name_id, TRUNC_TAIL);
246         gui_set_trunc(ball_id, TRUNC_TAIL);
247
248         gui_set_label(name_id, player);
249         gui_set_label(ball_id, base_name(ball));
250     }
251
252     return id;
253 }
254
255 static int conf_enter(struct state *st, struct state *prev)
256 {
257     conf_shared_init(conf_action);
258     return conf_gui();
259 }
260
261 /*---------------------------------------------------------------------------*/
262
263 enum
264 {
265     CONF_VIDEO_BACK = CONF_SHARED_BACK,
266     CONF_VIDEO_WIN,
267     CONF_VIDEO_FULL,
268     CONF_VIDEO_RES,
269     CONF_VIDEO_TEXLO,
270     CONF_VIDEO_TEXHI,
271     CONF_VIDEO_REFOF,
272     CONF_VIDEO_REFON,
273     CONF_VIDEO_BACOF,
274     CONF_VIDEO_BACON,
275     CONF_VIDEO_SHDOF,
276     CONF_VIDEO_SHDON
277 };
278
279 static int conf_video_action(int i)
280 {
281     int w = config_get_d(CONFIG_WIDTH);
282     int h = config_get_d(CONFIG_HEIGHT);
283     int r = 1;
284
285     audio_play(AUD_MENU, 1.0f);
286
287     switch (i)
288     {
289     case CONF_VIDEO_FULL:
290         goto_state(&st_null);
291         r = video_mode(1, w, h);
292         goto_state(&st_conf_video);
293         break;
294
295     case CONF_VIDEO_WIN:
296         goto_state(&st_null);
297         r = video_mode(0, w, h);
298         goto_state(&st_conf_video);
299         break;
300
301     case CONF_VIDEO_TEXHI:
302         goto_state(&st_null);
303         config_set_d(CONFIG_TEXTURES, 1);
304         goto_state(&st_conf_video);
305         break;
306
307     case CONF_VIDEO_TEXLO:
308         goto_state(&st_null);
309         config_set_d(CONFIG_TEXTURES, 2);
310         goto_state(&st_conf_video);
311         break;
312
313     case CONF_VIDEO_REFON:
314         goto_state(&st_null);
315         config_set_d(CONFIG_REFLECTION, 1);
316         r = video_init(TITLE, ICON);
317         goto_state(&st_conf_video);
318         break;
319
320     case CONF_VIDEO_REFOF:
321         goto_state(&st_null);
322         config_set_d(CONFIG_REFLECTION, 0);
323         goto_state(&st_conf_video);
324         break;
325
326     case CONF_VIDEO_BACON:
327         goto_state(&st_null);
328         config_set_d(CONFIG_BACKGROUND, 1);
329         goto_state(&st_conf_video);
330         break;
331
332     case CONF_VIDEO_BACOF:
333         goto_state(&st_null);
334         config_set_d(CONFIG_BACKGROUND, 0);
335         goto_state(&st_conf_video);
336         break;
337
338     case CONF_VIDEO_SHDON:
339         goto_state(&st_null);
340         config_set_d(CONFIG_SHADOW, 1);
341         goto_state(&st_conf_video);
342         break;
343
344     case CONF_VIDEO_SHDOF:
345         goto_state(&st_null);
346         config_set_d(CONFIG_SHADOW, 0);
347         goto_state(&st_conf_video);
348         break;
349
350     case CONF_VIDEO_BACK:
351         goto_state(&st_conf);
352         break;
353
354     case CONF_VIDEO_RES:
355         goto_state(&st_resol);
356         break;
357     }
358
359     return r;
360 }
361
362 static int conf_video_gui(void)
363 {
364     int id;
365
366     if ((id = gui_vstack(0)))
367     {
368         int f = config_get_d(CONFIG_FULLSCREEN);
369         int t = config_get_d(CONFIG_TEXTURES);
370         int r = config_get_d(CONFIG_REFLECTION);
371         int b = config_get_d(CONFIG_BACKGROUND);
372         int s = config_get_d(CONFIG_SHADOW);
373
374         char resolution[sizeof ("12345678 x 12345678")];
375
376         sprintf(resolution, "%d x %d",
377                 config_get_d(CONFIG_WIDTH),
378                 config_get_d(CONFIG_HEIGHT));
379
380         conf_header(id, _("Video Options"), CONF_VIDEO_BACK);
381
382         conf_toggle(id, _("Fullscreen"), f,
383                     _("Yes"), CONF_VIDEO_FULL, 1,
384                     _("No"), CONF_VIDEO_WIN,  0);
385
386         conf_state(id, _("Resolution"), resolution, CONF_VIDEO_RES);
387
388         gui_space(id);
389
390         conf_toggle(id, _("Textures"), t,
391                     _("High"), CONF_VIDEO_TEXHI, 1,
392                     _("Low"), CONF_VIDEO_TEXLO, 2);
393
394         conf_toggle(id, _("Reflection"), r,
395                     _("On"), CONF_VIDEO_REFON, 1,
396                     _("Off"), CONF_VIDEO_REFOF, 0);
397
398         conf_toggle(id, _("Background"), b,
399                     _("On"), CONF_VIDEO_BACON, 1,
400                     _("Off"), CONF_VIDEO_BACOF, 0);
401
402         conf_toggle(id, _("Shadow"), s,
403                     _("On"), CONF_VIDEO_SHDON, 1,
404                     _("Off"), CONF_VIDEO_SHDOF, 0);
405
406         gui_layout(id, 0, 0);
407     }
408
409     return id;
410 }
411
412 static int conf_video_enter(struct state *st, struct state *prev)
413 {
414     conf_shared_init(conf_video_action);
415     return conf_video_gui();
416 }
417
418 /*---------------------------------------------------------------------------*/
419
420 static int null_enter(struct state *st, struct state *prev)
421 {
422     hud_free();
423     gui_free();
424     geom_free();
425     item_free();
426     ball_free();
427     shad_free();
428     part_free();
429
430     return 0;
431 }
432
433 static void null_leave(struct state *st, struct state *next, int id)
434 {
435     part_init();
436     shad_init();
437     ball_init();
438     item_init();
439     geom_init();
440     gui_init();
441     hud_init();
442 }
443
444 /*---------------------------------------------------------------------------*/
445
446 struct state st_conf = {
447     conf_enter,
448     conf_shared_leave,
449     conf_shared_paint,
450     shared_timer,
451     shared_point,
452     shared_stick,
453     shared_angle,
454     shared_click,
455     NULL,
456     conf_shared_buttn,
457     NULL
458 };
459
460 struct state st_conf_video = {
461     conf_video_enter,
462     conf_shared_leave,
463     conf_shared_paint,
464     shared_timer,
465     shared_point,
466     shared_stick,
467     shared_angle,
468     shared_click,
469     NULL,
470     conf_shared_buttn,
471     NULL
472 };
473
474 struct state st_null = {
475     null_enter,
476     null_leave,
477     NULL,
478     NULL,
479     NULL,
480     NULL,
481     NULL,
482     NULL,
483     NULL,
484     NULL,
485     NULL
486 };