On Windows, when renaming Last to the destination filename, check if the
[neverball] / ball / st_play_end.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
17 #include "gui.h"
18 #include "set.h"
19 #include "game.h"
20 #include "util.h"
21 #include "levels.h"
22 #include "audio.h"
23 #include "config.h"
24 #include "demo.h"
25 #include "st_shared.h"
26
27 #include "st_play_end.h"
28 #include "st_save.h"
29 #include "st_over.h"
30 #include "st_done.h"
31 #include "st_start.h"
32 #include "st_level.h"
33 #include "st_name.h"
34
35 /*---------------------------------------------------------------------------*/
36
37 #define PLAY_END_NEXT 2
38 #define PLAY_END_SAME 3
39 #define PLAY_END_SAVE 4
40 #define PLAY_END_BACK 5
41 #define PLAY_END_DONE 6
42 #define PLAY_END_NAME 7
43 #define PLAY_END_OVER 8
44
45 static int balls_id;
46 static int coins_id;
47 static int score_id;
48 static int status_id;
49
50 extern struct state st_play_end_bis;
51
52 static int play_end_action(int i)
53 {
54     audio_play(AUD_MENU, 1.0f);
55
56     switch (i)
57     {
58     case PLAY_END_BACK:
59     case PLAY_END_OVER:
60         return goto_end_level();
61
62     case PLAY_END_SAVE:
63         return goto_save(&st_play_end_bis, &st_play_end_bis);
64
65     case PLAY_END_NAME:
66         return goto_name(&st_play_end_bis, &st_play_end_bis);
67
68     case PLAY_END_DONE:
69         return goto_state(&st_done);
70
71     case PLAY_END_NEXT:
72         level_next();
73         return goto_state(&st_level);
74
75     case PLAY_END_SAME:
76         return goto_state(&st_level);
77     }
78
79     return 1;
80 }
81
82 static void play_end_over(int id)
83 {
84     if (id == 0)
85         return;
86
87     switch (gui_token(id))
88     {
89         case 0:
90             break;
91
92         case PLAY_END_SAVE:
93             gui_set_label(status_id, _("Save a replay file"));
94             break;
95
96         case PLAY_END_SAVE | GUI_NULL_MASK:
97             gui_set_label(status_id, _("Replay file already saved"));
98             break;
99
100         case PLAY_END_NAME:
101             gui_set_label(status_id, _("Change the player's name"));
102             break;
103
104         case PLAY_END_DONE:
105             gui_set_label(status_id, _("You complete the set"));
106             break;
107
108         case PLAY_END_NEXT:
109             gui_set_label(status_id, _("Play the next level"));
110             break;
111
112         case PLAY_END_NEXT | GUI_NULL_MASK:
113             if (curr_lg()->mode == MODE_PRACTICE)
114                 gui_set_label(status_id, 
115                         _("Cannot unlock in practice mode"));
116             else
117                 gui_set_label(status_id, 
118                         _("Finish this level to unlock the next one"));
119             break;
120
121         case PLAY_END_SAME:
122             gui_set_label(status_id, _("Replay this level"));
123             break;
124
125         case PLAY_END_SAME | GUI_NULL_MASK:
126             gui_set_label(status_id, _("You cannot replay in challenge mode"));
127             break;
128
129         default:
130             gui_set_label(status_id, "");
131     }
132 }
133
134
135 static int play_end_init(int *gidp)
136 {
137     const struct level_game *lg = curr_lg();
138     int mode  = lg->mode;
139     int state = lg->state;
140     const struct level *l = lg->level;
141
142     int id, jd, kd;
143     int high;
144
145     high = (lg->time_rank < 3) || (lg->goal_rank < 3) || (lg->coin_rank < 3);
146
147     if ((id = gui_vstack(0)))
148     {
149         int gid;
150
151         if (state == GAME_SPEC)
152             gid = gui_label(id, _("SPECIAL GOAL"), GUI_MED, GUI_ALL,
153                             gui_blu, gui_grn);
154         else if (state == GAME_FALL)
155             gid = gui_label(id, _("Fall-out!"), GUI_MED, GUI_ALL,
156                             gui_gry, gui_red);
157         else if (state == GAME_TIME)
158             gid = gui_label(id, _("Time's Up!"), GUI_MED, GUI_ALL,
159                             gui_gry, gui_red);
160         else if (high)
161             gid = gui_label(id, _("New Record"), GUI_MED, GUI_ALL,
162                             gui_grn, gui_grn);
163         else
164             gid = gui_label(id, _("GOAL"), GUI_LRG, GUI_ALL,
165                             gui_blu, gui_grn);
166
167         gui_space(id);
168
169         if (mode == MODE_CHALLENGE &&
170             (lg->state == GAME_GOAL || lg->state == GAME_SPEC || l->is_bonus))
171         {
172             int coins = lg->coins;
173             int score = lg->score - coins;
174             int balls = lg->balls - count_extra_balls(score, coins);
175             if ((jd = gui_hstack(id)))
176             {
177                 if ((kd = gui_harray(jd)))
178                 {
179                     balls_id = gui_count(kd,  100, GUI_MED, GUI_RGT);
180                     gui_label(kd, _("Balls"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
181                 }
182                 if ((kd = gui_harray(jd)))
183                 {
184                     score_id = gui_count(kd, 1000, GUI_MED, GUI_RGT);
185                     gui_label(kd, _("Score"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
186                 }
187                 if ((kd = gui_harray(jd)))
188                 {
189                     coins_id = gui_count(kd, 100, GUI_MED, GUI_RGT);
190                     gui_label(kd, _("Coins"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
191                 }
192
193                 gui_set_count(balls_id, balls);
194                 gui_set_count(score_id, score);
195                 gui_set_count(coins_id, coins);
196             }
197         }
198         else
199         {
200             balls_id = score_id = coins_id = 0;
201         }
202
203         if (state == GAME_GOAL)
204         {
205             gui_space(id);
206             if ((jd = gui_harray(id)))
207             {
208                 gui_most_coins(jd, 1);
209                 gui_best_times(jd, 1);
210             }
211         }
212
213         gui_space(id);
214
215         if ((jd = gui_harray(id)))
216         {
217             int nlid = 0, rlid = 0;
218             int b = 0;
219
220             if (lg->win)
221                 gui_start(jd, _("Finish"), GUI_SML, PLAY_END_DONE, 0);
222             else
223                 nlid = gui_maybe(jd, _("Next Level"),  PLAY_END_NEXT,
224                                  lg->next_level != NULL);
225
226             if (lg->dead)
227                 gui_start(jd, _("Game Over"), GUI_SML, PLAY_END_OVER, 0);
228             else
229             {
230                 b = mode != MODE_CHALLENGE || ((state == GAME_FALL || state == GAME_TIME) && !lg->dead && !l->is_bonus);
231                 rlid = gui_maybe(jd, _("Retry Level"), PLAY_END_SAME, b);
232             }
233
234             gui_maybe(jd, _("Save Replay"), PLAY_END_SAVE, demo_play_saved());
235
236             /* default is next if the next level is newly unkocked */
237             if (nlid != 0 && lg->unlock)
238                  gui_focus(nlid);
239             else if (b)
240                  gui_focus(rlid);
241         }
242
243         if (high)
244             gui_state(id, _("Change Player Name"),  GUI_SML, PLAY_END_NAME, 0);
245
246         gui_space(id);
247         status_id = gui_label(id, "Neverball", GUI_SML, GUI_ALL, 0, 0);
248
249         gui_layout(id, 0, 0);
250         if (gidp) *gidp = gid;
251     }
252
253     if (state == GAME_GOAL)
254     {
255         set_most_coins(&l->score.most_coins, lg->coin_rank);
256         if (mode == MODE_CHALLENGE || mode == MODE_NORMAL)
257             set_best_times(&l->score.unlock_goal, lg->goal_rank, 1);
258         else
259             set_best_times(&l->score.best_times, lg->time_rank, 0);
260     }
261
262     config_clr_grab();
263
264     return id;
265 }
266
267 static int play_end_enter(void)
268 {
269     int gid;
270     int r;
271
272     r = play_end_init(&gid);
273
274     gui_pulse(gid, 1.2f);
275     audio_music_fade_out(2.0f);
276     return r;
277 }
278
279 static int play_end_bis_enter(void)
280 {
281     level_update_player_name();
282     return play_end_init(NULL);
283 }
284
285 static void play_end_timer(int id, float dt)
286 {
287     static float DT = 0.0f;
288
289     float gg[3] = { 0.0f, 9.8f, 0.0f };
290     float gf[3] = { 0.0f, -9.8f, 0.0f };
291     int state = curr_lg()->state;
292
293     DT += dt;
294
295     if (time_state() < 2.f)
296         game_step((state == GAME_GOAL || state == GAME_SPEC) ? gg : gf, dt, NULL);
297
298     if (time_state() > 1.f && DT > 0.05f && coins_id != 0)
299     {
300         int coins = gui_value(coins_id);
301         if (coins > 0)
302         {
303             int score = gui_value(score_id);
304             int balls = gui_value(balls_id);
305
306             gui_set_count(coins_id, coins - 1);
307             gui_pulse(coins_id, 1.1f);
308
309             gui_set_count(score_id, score + 1);
310             gui_pulse(score_id, 1.1f);
311
312             if ((score + 1) % 100 == 0)
313             {
314                 gui_set_count(balls_id, balls + 1);
315                 gui_pulse(balls_id, 2.0f);
316                 audio_play(AUD_BALL, 1.0f);
317             }
318         }
319
320         DT = 0.0f;
321     }
322
323     gui_timer(id, dt);
324     audio_timer(dt);
325 }
326
327 void play_end_stick(int id, int a, int v)
328 {
329         play_end_over(shared_stick_basic(id, a, v));
330 }
331
332 void play_end_point(int id, int x, int y, int dx, int dy)
333 {
334         play_end_over(shared_point_basic(id, x, y));
335 }
336
337 static int play_end_buttn(int b, int d)
338 {
339     if (d)
340     {
341         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
342             return play_end_action(gui_token(gui_click()));
343         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
344             return play_end_action(PLAY_END_BACK);
345     }
346     return 1;
347 }
348
349 /*---------------------------------------------------------------------------*/
350
351 struct state st_play_end = {
352     play_end_enter,
353     shared_leave,
354     shared_paint,
355     play_end_timer,
356     play_end_point,
357     play_end_stick,
358     shared_click,
359     NULL,
360     play_end_buttn,
361     1, 0
362 };
363
364 struct state st_play_end_bis = {
365     play_end_bis_enter,
366     shared_leave,
367     shared_paint,
368     shared_timer,
369     play_end_point,
370     play_end_stick,
371     shared_click,
372     NULL,
373     play_end_buttn,
374     1, 0
375 };