Call the standalone level 00, not 99
[neverball] / ball / level.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 <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19 #include <assert.h>
20
21 #include "common.h"
22 #include "solid.h"
23 #include "config.h"
24 #include "level.h"
25 #include "set.h"
26
27 /*---------------------------------------------------------------------------*/
28
29 static void scan_level_attribs(struct level *l, const struct s_file *fp)
30 {
31     int i;
32
33     int have_goal = 0;
34     int have_time = 0;
35
36     int need_time_easy = 0;
37     int need_goal_easy = 0;
38     int need_coin_easy = 0;
39
40     for (i = 0; i < fp->dc; i++)
41     {
42         char *k = fp->av + fp->dv[i].ai;
43         char *v = fp->av + fp->dv[i].aj;
44
45         if (strcmp(k, "message") == 0)
46             SAFECPY(l->message, v);
47         else if (strcmp(k, "song") == 0)
48             SAFECPY(l->song, v);
49         else if (strcmp(k, "shot") == 0)
50             SAFECPY(l->shot, v);
51         else if (strcmp(k, "goal") == 0)
52         {
53             l->goal = atoi(v);
54             have_goal = 1;
55         }
56         else if (strcmp(k, "time") == 0)
57         {
58             l->time = atoi(v);
59             have_time = 1;
60         }
61         else if (strcmp(k, "time_hs") == 0)
62         {
63             switch (sscanf(v, "%d %d %d",
64                            &l->scores[SCORE_TIME].timer[RANK_HARD],
65                            &l->scores[SCORE_TIME].timer[RANK_MEDM],
66                            &l->scores[SCORE_TIME].timer[RANK_EASY]))
67             {
68             case 2: need_time_easy = 1; break;
69             case 3: break;
70             }
71         }
72         else if (strcmp(k, "goal_hs") == 0)
73         {
74             switch (sscanf(v, "%d %d %d",
75                            &l->scores[SCORE_GOAL].timer[RANK_HARD],
76                            &l->scores[SCORE_GOAL].timer[RANK_MEDM],
77                            &l->scores[SCORE_GOAL].timer[RANK_EASY]))
78             {
79             case 2: need_goal_easy = 1; break;
80             case 3: break;
81             }
82         }
83         else if (strcmp(k, "coin_hs") == 0)
84         {
85             switch (sscanf(v, "%d %d %d",
86                            &l->scores[SCORE_COIN].coins[RANK_HARD],
87                            &l->scores[SCORE_COIN].coins[RANK_MEDM],
88                            &l->scores[SCORE_COIN].coins[RANK_EASY]))
89             {
90             case 2: need_coin_easy = 1; break;
91             case 3: break;
92             }
93         }
94         else if (strcmp(k, "version") == 0)
95             SAFECPY(l->version, v);
96         else if (strcmp(k, "author") == 0)
97             SAFECPY(l->author, v);
98         else if (strcmp(k, "bonus") == 0)
99             l->is_bonus = atoi(v) ? 1 : 0;
100     }
101
102     if (have_goal)
103     {
104         if (need_coin_easy)
105             l->scores[SCORE_COIN].coins[RANK_EASY] = l->goal;
106
107         l->scores[SCORE_GOAL].coins[RANK_HARD] = l->goal;
108         l->scores[SCORE_GOAL].coins[RANK_MEDM] = l->goal;
109         l->scores[SCORE_GOAL].coins[RANK_EASY] = l->goal;
110     }
111
112     if (have_time)
113     {
114         if (need_time_easy)
115             l->scores[SCORE_TIME].timer[RANK_EASY] = l->time;
116         if (need_goal_easy)
117             l->scores[SCORE_GOAL].timer[RANK_EASY] = l->time;
118
119         l->scores[SCORE_COIN].timer[RANK_HARD] = l->time;
120         l->scores[SCORE_COIN].timer[RANK_MEDM] = l->time;
121         l->scores[SCORE_COIN].timer[RANK_EASY] = l->time;
122     }
123 }
124
125 int level_load(const char *filename, struct level *level)
126 {
127     struct s_file sol;
128
129     memset(level, 0, sizeof (struct level));
130     memset(&sol,  0, sizeof (sol));
131
132     if (!sol_load_only_head(&sol, filename))
133     {
134         fprintf(stderr, L_("Failure to load level file '%s'\n"), filename);
135         return 0;
136     }
137
138     SAFECPY(level->file, filename);
139     SAFECPY(level->name, "00");
140
141     score_init_hs(&level->scores[SCORE_TIME], 59999, 0);
142     score_init_hs(&level->scores[SCORE_GOAL], 59999, 0);
143     score_init_hs(&level->scores[SCORE_COIN], 59999, 0);
144
145     scan_level_attribs(level, &sol);
146
147     sol_free(&sol);
148
149     return 1;
150 }
151
152 /*---------------------------------------------------------------------------*/
153
154 int level_exists(int i)
155 {
156     return !!get_level(i);
157 }
158
159 void level_open(struct level *level)
160 {
161     level->is_locked = 0;
162 }
163
164 int level_opened(const struct level *level)
165 {
166     return !level->is_locked;
167 }
168
169 void level_complete(struct level *level)
170 {
171     level->is_completed = 1;
172 }
173
174 int level_completed(const struct level *level)
175 {
176     return level->is_completed;
177 }
178
179 int level_time(const struct level *level)
180 {
181     return level->time;
182 }
183
184 int level_goal(const struct level *level)
185 {
186     return level->goal;
187 }
188
189 int  level_bonus(const struct level *level)
190 {
191     return level->is_bonus;
192 }
193
194 const char *level_shot(const struct level *level)
195 {
196     return level->shot;
197 }
198
199 const char *level_file(const struct level *level)
200 {
201     return level->file;
202 }
203
204 const char *level_song(const struct level *level)
205 {
206     return level->song;
207 }
208
209 const char *level_name(const struct level *level)
210 {
211     return level->name;
212 }
213
214 const char *level_msg(const struct level *level)
215 {
216     if (strlen(level->message) > 0)
217         return _(level->message);
218     return "";
219 }
220
221 const struct score *level_score(struct level *level, int s)
222 {
223     return &level->scores[s];
224 }
225
226 /*---------------------------------------------------------------------------*/
227
228 int level_score_update(struct level *l,
229                        int timer,
230                        int coins,
231                        int *time_rank,
232                        int *goal_rank,
233                        int *coin_rank)
234 {
235     const char *player =  config_get_s(CONFIG_PLAYER);
236
237     score_time_insert(&l->scores[SCORE_TIME], time_rank, player, timer, coins);
238     score_time_insert(&l->scores[SCORE_GOAL], goal_rank, player, timer, coins);
239     score_coin_insert(&l->scores[SCORE_COIN], coin_rank, player, timer, coins);
240
241     if ((time_rank && *time_rank < 3) ||
242         (goal_rank && *goal_rank < 3) ||
243         (coin_rank && *coin_rank < 3))
244         return 1;
245     else
246         return 0;
247 }
248
249 void level_rename_player(struct level *l,
250                          int time_rank,
251                          int goal_rank,
252                          int coin_rank,
253                          const char *player)
254 {
255     SAFECPY(l->scores[SCORE_TIME].player[time_rank], player);
256     SAFECPY(l->scores[SCORE_GOAL].player[goal_rank], player);
257     SAFECPY(l->scores[SCORE_COIN].player[coin_rank], player);
258 }
259
260 /*---------------------------------------------------------------------------*/
261