Restored progress.c and properly gave credit for arbitrary balls
[neverball] / ball / progress.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 "progress.h"
16 #include "config.h"
17 #include "game.h"
18 #include "demo.h"
19 #include "level.h"
20 #include "set.h"
21 #include "lang.h"
22 #include "score.h"
23
24 /*---------------------------------------------------------------------------*/
25
26 static int mode = MODE_NORMAL;
27
28 static int level =  0;
29 static int next  = -1;
30 static int done  =  0;
31
32 static int balls =  2;
33 static int bonus =  0;
34
35 /* Set stats. */
36
37 static int score = 0;
38 static int times = 0;
39
40 static int score_rank = 3;
41 static int times_rank = 3;
42
43 /* Level stats. */
44
45 static int status = GAME_NONE;
46
47 static int coins = 0;
48 static int timer = 0;
49
50 static int goal   = 0; /* Current goal value. */
51 static int goal_i = 0; /* Initial goal value. */
52
53 static int time_rank = 3;
54 static int goal_rank = 3;
55 static int coin_rank = 3;
56
57 /*---------------------------------------------------------------------------*/
58
59 void progress_init(int m)
60 {
61     mode  = m;
62
63     balls = 2;
64     score = 0;
65     times = 0;
66     bonus = 0;
67
68     score_rank = times_rank = 3;
69
70     done  = 0;
71 }
72
73 int  progress_play(int i)
74 {
75     if (level_opened(i) || config_cheat())
76     {
77         level = i;
78
79         next   = -1;
80         status = GAME_NONE;
81         coins  = 0;
82         timer  = 0;
83         goal   = goal_i = level_goal(level);
84
85         time_rank = goal_rank = coin_rank = 3;
86
87         if (demo_play_init(USER_REPLAY_FILE, get_level(level), mode,
88                            level_time(level), level_goal(level),
89                            (mode != MODE_CHALLENGE && level_completed(level) &&
90                             config_get_d(CONFIG_LOCK_GOALS) == 0) || goal == 0,
91                            score, balls, times))
92         {
93             return 1;
94         }
95         else
96         {
97             demo_play_stop();
98             return 0;
99         }
100     }
101     return 0;
102 }
103
104 void progress_step(void)
105 {
106     if (goal > 0)
107     {
108         goal = goal_i - curr_coins();
109
110         if (goal <= 0)
111         {
112             game_set_goal();
113             goal = 0;
114         }
115     }
116 }
117
118 void progress_stat(int s)
119 {
120     int i, dirty = 0;
121
122     status = s;
123
124     coins = curr_coins();
125     timer = level_time(level) - curr_clock();
126
127     switch (status)
128     {
129     case GAME_GOAL:
130
131         for (i = score + 1; i <= score + coins; i++)
132             if (progress_reward_ball(i))
133                 balls++;
134
135         score += coins;
136         times += timer;
137
138         dirty = level_score_update(level, timer, coins,
139                                    &time_rank,
140                                    goal == 0 ? &goal_rank : NULL,
141                                    &coin_rank);
142
143         if (!level_completed(level))
144         {
145             level_complete(level);
146             dirty = 1;
147         }
148
149         /* Compute next level. */
150
151         if (mode == MODE_CHALLENGE)
152         {
153             for (next = level + 1; level_bonus(next); next++)
154                 if (!level_opened(next))
155                 {
156                     level_open(next);
157                     dirty = 1;
158                     bonus++;
159                 }
160         }
161         else
162         {
163             for (next = level + 1;
164                  level_bonus(next) && !level_opened(next);
165                  next++)
166                 /* Do nothing. */;
167         }
168
169         /* Complete the set or open next level. */
170
171         if (!level_exists(next))
172         {
173             if (mode == MODE_CHALLENGE)
174             {
175                 dirty = set_score_update(times, score, &score_rank, &times_rank);
176                 done  = 1;
177             }
178         }
179         else
180         {
181             level_open(next);
182             dirty = 1;
183         }
184
185         break;
186
187     case GAME_FALL:
188         /* Fall through. */
189
190     case GAME_TIME:
191         for (next = level + 1;
192              level_exists(next) && !level_opened(next);
193              next++)
194             /* Do nothing. */;
195
196         balls--;
197         break;
198     }
199
200     if (dirty)
201         set_store_hs();
202
203     demo_play_stat(status, coins, timer);
204 }
205
206 void progress_stop(void)
207 {
208     demo_play_stop();
209 }
210
211 void progress_exit(int s)
212 {
213     progress_stat(s);
214     progress_stop();
215 }
216
217 int  progress_replay(const char *filename)
218 {
219     if (demo_replay_init(filename, &goal, &mode, &balls, &score, &times))
220     {
221         goal_i = goal;
222         return 1;
223     }
224     else
225         return 0;
226 }
227
228 int  progress_next_avail(void)
229 {
230     if (mode == MODE_CHALLENGE)
231         return status == GAME_GOAL && level_exists(next);
232     else
233         return level_opened(next);
234 }
235
236 int  progress_same_avail(void)
237 {
238     switch (status)
239     {
240     case GAME_NONE:
241         return mode != MODE_CHALLENGE;
242
243     default:
244         if (mode == MODE_CHALLENGE)
245             return status != GAME_GOAL && !progress_dead();
246         else
247             return 1;
248     }
249 }
250
251 int  progress_next(void)
252 {
253     progress_stop();
254     return progress_play(next);
255 }
256
257 int  progress_same(void)
258 {
259     progress_stop();
260     return progress_play(level);
261 }
262
263 int  progress_dead(void)
264 {
265     return mode == MODE_CHALLENGE ? balls < 0 : 0;
266 }
267
268 int  progress_done(void)
269 {
270     return done;
271 }
272
273 int  progress_lvl_high(void)
274 {
275     return time_rank < 3 || goal_rank < 3 || coin_rank < 3;
276 }
277
278 int  progress_set_high(void)
279 {
280     return score_rank < 3 || times_rank < 3;
281 }
282
283 void progress_rename(void)
284 {
285     char player[MAXNAM] = "";
286
287     config_get_s(CONFIG_PLAYER, player, sizeof (player));
288
289     level_rename_player(level, time_rank, goal_rank, coin_rank, player);
290     set_rename_player  (score_rank, times_rank, player);
291
292     set_store_hs();
293 }
294
295 int  progress_reward_ball(int s)
296 {
297     return s > 0 && s % 100 == 0;
298 }
299
300 /*---------------------------------------------------------------------------*/
301
302 int curr_level(void) { return level; }
303 int curr_balls(void) { return balls; }
304 int curr_score(void) { return score; }
305 int curr_mode (void) { return mode;  }
306 int curr_bonus(void) { return bonus; }
307 int curr_goal (void) { return goal;  }
308
309 int progress_time_rank(void) { return time_rank; }
310 int progress_goal_rank(void) { return goal_rank; }
311 int progress_coin_rank(void) { return coin_rank; }
312
313 int progress_times_rank(void) { return times_rank; }
314 int progress_score_rank(void) { return score_rank; }
315
316 /*---------------------------------------------------------------------------*/
317
318 const char *mode_to_str(int m, int l)
319 {
320     switch (m)
321     {
322     case MODE_CHALLENGE: return l ? _("Challenge Mode") : _("Challenge");
323     case MODE_NORMAL:    return l ? _("Normal Mode")    : _("Normal");
324     default:             return l ? _("Unknown Mode")   : _("Unknown");
325     }
326 }
327
328 /*---------------------------------------------------------------------------*/