Correct logic of BSP back/front tests
[neverball] / ball / st_start.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 "set.h"
17 #include "util.h"
18 #include "game.h"
19 #include "progress.h"
20 #include "audio.h"
21 #include "config.h"
22 #include "st_shared.h"
23
24 #include "st_set.h"
25 #include "st_over.h"
26 #include "st_level.h"
27 #include "st_start.h"
28 #include "st_title.h"
29
30 /*---------------------------------------------------------------------------*/
31
32 #define START_BACK        -1
33 #define START_CHALLENGE   -2
34 #define START_OPEN_GOALS  -3
35 #define START_LOCK_GOALS  -4
36
37 static int shot_id;
38 static int file_id;
39 static int challenge_id;
40
41 /*---------------------------------------------------------------------------*/
42
43 /* Create a level selector button based upon its existence and status. */
44
45 static void gui_level(int id, int i)
46 {
47     const GLfloat *fore = 0, *back = 0;
48
49     int jd;
50
51     if (!level_exists(i))
52     {
53         gui_label(id, " ", GUI_SML, GUI_ALL, gui_blk, gui_blk);
54         return;
55     }
56
57     if (level_opened(i))
58     {
59         fore = level_bonus(i)     ? gui_grn : gui_wht;
60         back = level_completed(i) ? fore    : gui_yel;
61     }
62
63     jd = gui_label(id, level_name(i), GUI_SML, GUI_ALL, back, fore);
64
65     if (level_opened(i) || config_cheat())
66         gui_active(jd, i, 0);
67 }
68
69 static void start_over_level(int i)
70 {
71     if (level_opened(i) || config_cheat())
72     {
73         gui_set_image(shot_id, level_shot(i));
74
75         set_score_board(&get_level(i)->score.most_coins,  -1,
76                         &get_level(i)->score.best_times,  -1,
77                         &get_level(i)->score.unlock_goal, -1);
78
79         if (file_id)
80             gui_set_label(file_id, level_file(i));
81     }
82 }
83
84 static void start_over(int id, int pulse)
85 {
86     int i;
87
88     if (id == 0)
89         return;
90
91     if (pulse)
92         gui_pulse(id, 1.2f);
93
94     i = gui_token(id);
95
96     if (i == START_CHALLENGE || i == START_BACK)
97     {
98         gui_set_image(shot_id, set_shot(curr_set()));
99
100         set_score_board(set_coin_score(curr_set()), -1,
101                         set_time_score(curr_set()), -1,
102                         set_time_score(curr_set()), -1);
103     }
104
105     if (i >= 0 && !GUI_ISMSK(i))
106         start_over_level(i);
107 }
108
109 /*---------------------------------------------------------------------------*/
110
111 static int start_action(int i)
112 {
113     audio_play(AUD_MENU, 1.0f);
114
115     switch (i)
116     {
117     case START_BACK:
118         return goto_state(&st_set);
119
120     case START_CHALLENGE:
121         if (config_cheat())
122         {
123             progress_init(curr_mode() == MODE_CHALLENGE ?
124                           MODE_NORMAL : MODE_CHALLENGE);
125             gui_toggle(challenge_id);
126             return 1;
127         }
128         else
129         {
130             progress_init(MODE_CHALLENGE);
131             return start_action(0);
132         }
133         break;
134
135     case GUI_MOST_COINS:
136     case GUI_BEST_TIMES:
137     case GUI_UNLOCK_GOAL:
138         gui_score_set(i);
139         return goto_state(&st_start);
140
141     case START_OPEN_GOALS:
142         config_set_d(CONFIG_LOCK_GOALS, 0);
143         return goto_state(&st_start);
144
145     case START_LOCK_GOALS:
146         config_set_d(CONFIG_LOCK_GOALS, 1);
147         return goto_state(&st_start);
148
149     default:
150         if (progress_play(i))
151             return goto_state(&st_level);
152         break;
153     }
154
155     return 1;
156 }
157
158 static int start_enter(void)
159 {
160     int w = config_get_d(CONFIG_WIDTH);
161     int h = config_get_d(CONFIG_HEIGHT);
162     int i, j;
163
164     int id, jd, kd, ld;
165
166     progress_init(MODE_NORMAL);
167
168     if ((id = gui_vstack(0)))
169     {
170         if ((jd = gui_hstack(id)))
171         {
172
173             gui_label(jd, set_name(curr_set()), GUI_SML, GUI_ALL,
174                       gui_yel, gui_red);
175             gui_filler(jd);
176             gui_start(jd, _("Back"),  GUI_SML, START_BACK, 0);
177         }
178
179         if ((jd = gui_harray(id)))
180         {
181             if (config_cheat())
182             {
183                 if ((kd = gui_vstack(jd)))
184                 {
185                     shot_id = gui_image(kd, set_shot(curr_set()),
186                                         7 * w / 16, 7 * h / 16);
187                     file_id = gui_label(kd, " ", GUI_SML, GUI_ALL,
188                                         gui_yel, gui_red);
189                 }
190             }
191             else
192             {
193                 shot_id = gui_image(jd, set_shot(curr_set()),
194                                     7 * w / 16, 7 * h / 16);
195             }
196
197             if ((kd = gui_varray(jd)))
198             {
199                 for (i = 0; i < 5; i++)
200                     if ((ld = gui_harray(kd)))
201                         for (j = 4; j >= 0; j--)
202                             gui_level(ld, i * 5 + j);
203
204                 challenge_id = gui_state(kd, _("Challenge"),
205                                          GUI_SML, START_CHALLENGE,
206                                          curr_mode() == MODE_CHALLENGE);
207             }
208         }
209         gui_space(id);
210
211         if ((jd = gui_hstack(id)))
212             gui_score_board(jd, GUI_MOST_COINS |
213                                 GUI_BEST_TIMES |
214                                 GUI_UNLOCK_GOAL, 0, 0);
215
216         gui_space(id);
217
218         if ((jd = gui_hstack(id)))
219         {
220             gui_filler(jd);
221
222             if ((kd = gui_harray(jd)))
223             {
224                 /* TODO, replace the whitespace hack with something sane. */
225
226                 gui_state(kd,
227                           /* Translators: adjust the amount of whitespace here
228                            * as necessary for the buttons to look good. */
229                           _("   No   "), GUI_SML, START_OPEN_GOALS,
230                           config_get_d(CONFIG_LOCK_GOALS) == 0);
231
232                 gui_state(kd, _("Yes"), GUI_SML, START_LOCK_GOALS,
233                           config_get_d(CONFIG_LOCK_GOALS) == 1);
234             }
235
236             gui_space(jd);
237
238             gui_label(jd, _("Lock Goals of Completed Levels?"),
239                       GUI_SML, GUI_ALL, 0, 0);
240
241             gui_filler(jd);
242         }
243
244         gui_layout(id, 0, 0);
245
246         set_score_board(NULL, -1, NULL, -1, NULL, -1);
247     }
248
249     audio_music_fade_to(0.5f, "bgm/inter.ogg");
250
251     return id;
252 }
253
254 static void start_point(int id, int x, int y, int dx, int dy)
255 {
256     start_over(gui_point(id, x, y), 1);
257 }
258
259 static void start_stick(int id, int a, int v)
260 {
261     int x = (config_tst_d(CONFIG_JOYSTICK_AXIS_X, a)) ? v : 0;
262     int y = (config_tst_d(CONFIG_JOYSTICK_AXIS_Y, a)) ? v : 0;
263
264     start_over(gui_stick(id, x, y), 1);
265 }
266
267 static int start_keybd(int c, int d)
268 {
269     if (d)
270     {
271         if (c == SDLK_c && config_cheat())
272         {
273             set_cheat();
274             return goto_state(&st_start);
275         }
276         else if (c == SDLK_F12 && config_cheat())
277         {
278             int i;
279
280             /* Iterate over all levels, taking a screenshot of each. */
281
282             for (i = 0; i < MAXLVL; i++)
283                 if (level_exists(i))
284                     level_snap(i);
285         }
286         else if (config_tst_d(CONFIG_KEY_SCORE_NEXT, c))
287         {
288             int active = gui_click();
289
290             if (start_action(gui_score_next(gui_score_get())))
291             {
292                 /* HACK ALERT
293                  *
294                  * This assumes that 'active' is a valid widget ID even after
295                  * the above start_action has recreated the entire widget
296                  * hierarchy.  Maybe it is.  Maybe it isn't.
297                  */
298                 gui_focus(active);
299                 start_over(active, 0);
300
301                 return 1;
302             }
303             else
304                 return 0;
305         }
306     }
307
308     return 1;
309 }
310
311 static int start_buttn(int b, int d)
312 {
313     if (d)
314     {
315         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
316             return start_action(gui_token(gui_click()));
317         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
318             return start_action(START_BACK);
319     }
320     return 1;
321 }
322
323 /*---------------------------------------------------------------------------*/
324
325 struct state st_start = {
326     start_enter,
327     shared_leave,
328     shared_paint,
329     shared_timer,
330     start_point,
331     start_stick,
332     shared_angle,
333     shared_click,
334     start_keybd,
335     start_buttn,
336     1, 0
337 };