Replace forgettable view numbers with symbols and clean up view name lookup
[neverball] / ball / st_title.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 <string.h>
16 #include <assert.h>
17
18 #include "gui.h"
19 #include "vec3.h"
20 #include "demo.h"
21 #include "audio.h"
22 #include "config.h"
23 #include "st_shared.h"
24 #include "cmd.h"
25 #include "demo_dir.h"
26
27 #include "game_common.h"
28 #include "game_server.h"
29 #include "game_client.h"
30 #include "game_proxy.h"
31
32 #include "st_title.h"
33 #include "st_help.h"
34 #include "st_demo.h"
35 #include "st_conf.h"
36 #include "st_set.h"
37 #include "st_name.h"
38
39 /*---------------------------------------------------------------------------*/
40
41 static int init_title_level(void)
42 {
43     if (game_client_init("map-medium/title.sol"))
44     {
45         union cmd cmd;
46
47         cmd.type = CMD_GOAL_OPEN;
48         game_proxy_enq(&cmd);
49
50         game_client_step(NULL);
51
52         return 1;
53     }
54     return 0;
55 }
56
57 static const char *pick_demo(Array items)
58 {
59     struct dir_item *item;
60     return (item = array_rnd(items)) ? item->path : NULL;
61 }
62
63 /*---------------------------------------------------------------------------*/
64
65 static float real_time = 0.0f;
66 static int   mode      = 0;
67
68 static Array items;
69
70 static int play_id = 0;
71
72 #define TITLE_PLAY 1
73 #define TITLE_HELP 2
74 #define TITLE_DEMO 3
75 #define TITLE_CONF 4
76 #define TITLE_EXIT 5
77
78 static int title_action(int i)
79 {
80     static const char keyphrase[] = "CHEAT";
81     static char queue[sizeof (keyphrase)] = "";
82
83     size_t queue_len = strlen(queue);
84
85     char player[MAXNAM];
86
87     audio_play(AUD_MENU, 1.0f);
88
89     switch (i)
90     {
91     case TITLE_PLAY:
92         config_get_s(CONFIG_PLAYER, player, MAXNAM);
93
94         if (strlen(player) == 0)
95             return goto_name(&st_set, &st_title, 0);
96         else
97             return goto_state(&st_set);
98
99         break;
100
101     case TITLE_HELP: return goto_state(&st_help); break;
102     case TITLE_DEMO: return goto_state(&st_demo); break;
103     case TITLE_CONF: return goto_state(&st_conf); break;
104     case TITLE_EXIT: return 0;                    break;
105
106     default:
107
108         /* Let the queue fill up. */
109
110         if (queue_len < sizeof (queue) - 1)
111         {
112             queue[queue_len]     = (char) i;
113             queue[queue_len + 1] = '\0';
114         }
115
116         /* Advance the queue before adding the new element. */
117
118         else
119         {
120             int k;
121
122             for (k = 1; k < queue_len; k++)
123                 queue[k - 1] = queue[k];
124
125             queue[queue_len - 1] = (char) i;
126         }
127
128         if (strcmp(queue, keyphrase) == 0)
129         {
130             config_set_cheat();
131             gui_set_label(play_id, sgettext("menu^Cheat"));
132             gui_pulse(play_id, 1.2f);
133         }
134         else if (config_cheat())
135         {
136             config_clr_cheat();
137             gui_set_label(play_id, sgettext("menu^Play"));
138             gui_pulse(play_id, 1.2f);
139         }
140
141         break;
142     }
143     return 1;
144 }
145
146 static int title_enter(void)
147 {
148     int id, jd, kd;
149
150     /* Build the title GUI. */
151
152     if ((id = gui_vstack(0)))
153     {
154         gui_label(id, "Neverball", GUI_LRG, GUI_ALL, 0, 0);
155
156         gui_space(id);
157
158         if ((jd = gui_harray(id)))
159         {
160             gui_filler(jd);
161
162             if ((kd = gui_varray(jd)))
163             {
164                 if (config_cheat())
165                     play_id = gui_start(kd, sgettext("menu^Cheat"),
166                                         GUI_MED, TITLE_PLAY, 1);
167                 else
168                     play_id = gui_start(kd, sgettext("menu^Play"),
169                                         GUI_MED, TITLE_PLAY, 1);
170
171                 gui_state(kd, sgettext("menu^Replay"),  GUI_MED, TITLE_DEMO, 0);
172                 gui_state(kd, sgettext("menu^Help"),    GUI_MED, TITLE_HELP, 0);
173                 gui_state(kd, sgettext("menu^Options"), GUI_MED, TITLE_CONF, 0);
174                 gui_state(kd, sgettext("menu^Exit"),    GUI_MED, TITLE_EXIT, 0);
175             }
176
177             gui_filler(jd);
178         }
179         gui_layout(id, 0, 0);
180     }
181
182     /* Start the title screen music. */
183
184     audio_music_fade_to(0.5f, "bgm/title.ogg");
185
186     /* Initialize the title level for display. */
187
188     init_title_level();
189
190     real_time = 0.0f;
191     mode = 0;
192
193     SDL_EnableUNICODE(1);
194
195     return id;
196 }
197
198 static void title_leave(int id)
199 {
200     if (items)
201     {
202         demo_dir_free(items);
203         items = NULL;
204     }
205
206     SDL_EnableUNICODE(0);
207     demo_replay_stop(0);
208     gui_delete(id);
209 }
210
211 static void title_timer(int id, float dt)
212 {
213     static const char *demo = NULL;
214
215     real_time += dt;
216
217     switch (mode)
218     {
219     case 0: /* Mode 0: Pan across title level. */
220
221         if (real_time <= 20.0f)
222         {
223             game_set_fly(fcosf(V_PI * real_time / 20.0f),
224                          game_client_file());
225             game_client_step(NULL);
226         }
227         else
228         {
229             game_fade(+1.0f);
230             real_time = 0.0f;
231             mode = 1;
232         }
233         break;
234
235     case 1: /* Mode 1: Fade out.  Load demo level. */
236
237         if (real_time > 1.0f)
238         {
239             if (!items)
240                 items = demo_dir_scan();
241
242             if ((demo = pick_demo(items)))
243             {
244                 demo_replay_init(demo, NULL, NULL, NULL, NULL, NULL);
245                 game_set_fly(0.0f, game_client_file());
246                 game_client_step(NULL);
247                 real_time = 0.0f;
248                 mode = 2;
249             }
250             else
251             {
252                 game_fade(-1.0f);
253                 real_time = 0.0f;
254                 mode = 0;
255             }
256         }
257         break;
258
259     case 2: /* Mode 2: Run demo. */
260
261         if (!demo_replay_step(dt))
262         {
263             demo_replay_stop(0);
264             game_fade(+1.0f);
265             real_time = 0.0f;
266             mode = 3;
267         }
268         break;
269
270     case 3: /* Mode 3: Fade out.  Load title level. */
271
272         if (real_time > 1.0f)
273         {
274             init_title_level();
275
276             real_time = 0.0f;
277             mode = 0;
278         }
279         break;
280     }
281
282     gui_timer(id, dt);
283     game_step_fade(dt);
284 }
285
286 static int title_keybd(int c, int d)
287 {
288     if (d && (c & 0xFF80) == 0 && c > ' ')
289         return title_action(c);
290     return 1;
291 }
292
293 static int title_buttn(int b, int d)
294 {
295     if (d)
296     {
297         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
298             return title_action(gui_token(gui_click()));
299         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
300             return 0;
301     }
302     return 1;
303 }
304
305 /*---------------------------------------------------------------------------*/
306
307 struct state st_title = {
308     title_enter,
309     title_leave,
310     shared_paint,
311     title_timer,
312     shared_point,
313     shared_stick,
314     shared_angle,
315     shared_click,
316     title_keybd,
317     title_buttn,
318     1, 0
319 };
320