2 * Copyright (C) 2003 Robert Kooima
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.
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.
28 /*---------------------------------------------------------------------------*/
34 char *id; /* Internal set identifier */
35 char *name; /* Set name */
36 char *desc; /* Set description */
37 char *shot; /* Set screen-shot */
39 char user_scores[PATHMAX]; /* User high-score file */
41 struct score coin_score; /* Challenge score */
42 struct score time_score; /* Challenge score */
46 int count; /* Number of levels */
47 char *level_name_v[MAXLVL]; /* List of level file names */
50 static int set_state = 0;
55 static struct set set_v[MAXSET];
56 static struct level level_v[MAXLVL];
58 /*---------------------------------------------------------------------------*/
60 static void put_score(FILE *fp, const struct score *s)
64 for (j = 0; j < NSCORE; j++)
65 fprintf(fp, "%d %d %s\n", s->timer[j], s->coins[j], s->player[j]);
68 void set_store_hs(void)
70 const struct set *s = &set_v[set];
73 const struct level *l;
74 char states[MAXLVL + 1];
76 if ((fout = fopen(config_user(s->user_scores), "w")))
78 for (i = 0; i < s->count; i++)
80 if (level_v[i].is_locked)
82 else if (level_v[i].is_completed)
87 states[s->count] = '\0';
88 fprintf(fout, "%s\n",states);
90 put_score(fout, &s->time_score);
91 put_score(fout, &s->coin_score);
93 for (i = 0; i < s->count; i++)
97 put_score(fout, &l->score.best_times);
98 put_score(fout, &l->score.unlock_goal);
99 put_score(fout, &l->score.most_coins);
106 static int get_score(FILE *fp, struct score *s)
111 for (j = 0; j < NSCORE && res; j++)
113 res = fscanf(fp, "%d %d %s\n",
121 /* Get the score of the set. */
122 static void set_load_hs(void)
124 struct set *s = &set_v[set];
129 const char *fn = config_user(s->user_scores);
130 char states[MAXLVL + 1];
132 if ((fin = fopen(fn, "r")))
134 res = fscanf(fin, "%s\n", states) == 1 && strlen(states) == s->count;
136 for (i = 0; i < s->count && res; i++)
141 level_v[i].is_locked = 1;
142 level_v[i].is_completed = 0;
146 level_v[i].is_locked = 0;
147 level_v[i].is_completed = 1;
151 level_v[i].is_locked = 0;
152 level_v[i].is_completed = 0;
161 get_score(fin, &s->time_score) &&
162 get_score(fin, &s->coin_score);
164 for (i = 0; i < s->count && res; i++)
167 res = get_score(fin, &l->score.best_times) &&
168 get_score(fin, &l->score.unlock_goal) &&
169 get_score(fin, &l->score.most_coins);
175 if (!res && errno != ENOENT)
178 L_("Error while loading user high-score file '%s': %s\n"),
179 fn, errno ? strerror(errno) : L_("Incorrect format"));
183 /*---------------------------------------------------------------------------*/
185 static int set_load(struct set *s, const char *filename)
188 char *scores, *level_name;
190 fin = fopen(config_data(filename), "r");
194 fprintf(stderr, L_("Cannot load the set file '%s': %s\n"),
195 filename, strerror(errno));
199 memset(s, 0, sizeof (struct set));
201 /* Set some sane values in case the scores are missing. */
203 score_init_hs(&s->time_score, 359999, 0);
204 score_init_hs(&s->coin_score, 359999, 0);
206 strncpy(s->file, filename, PATHMAX - 1);
208 if (read_line(&s->name, fin) &&
209 read_line(&s->desc, fin) &&
210 read_line(&s->id, fin) &&
211 read_line(&s->shot, fin) &&
212 read_line(&scores, fin))
214 sscanf(scores, "%d %d %d %d %d %d",
215 &s->time_score.timer[0],
216 &s->time_score.timer[1],
217 &s->time_score.timer[2],
218 &s->coin_score.coins[0],
219 &s->coin_score.coins[1],
220 &s->coin_score.coins[2]);
224 strncpy(s->user_scores, "neverballhs-", PATHMAX - 1);
225 strncat(s->user_scores, s->id, PATHMAX - 1 - strlen("neverballhs-"));
229 while (s->count < MAXLVL && read_line(&level_name, fin))
231 s->level_name_v[s->count] = level_name;
261 if ((fin = fopen(config_data(SET_FILE), "r")))
263 while (count < MAXSET && read_line(&name, fin))
265 if (set_load(&set_v[count], name))
282 for (i = 0; i < count; i++)
289 for (j = 0; j < set_v[i].count; j++)
290 free(set_v[i].level_name_v[j]);
296 /*---------------------------------------------------------------------------*/
298 int set_exists(int i)
300 return (0 <= i && i < count);
303 const char *set_id(int i)
305 return set_exists(i) ? set_v[i].id : NULL;
308 const char *set_name(int i)
310 return set_exists(i) ? _(set_v[i].name) : NULL;
313 const char *set_desc(int i)
315 return set_exists(i) ? _(set_v[i].desc) : NULL;
318 const char *set_shot(int i)
320 return set_exists(i) ? set_v[i].shot : NULL;
323 const struct score *set_time_score(int i)
325 return set_exists(i) ? &set_v[i].time_score : NULL;
328 const struct score *set_coin_score(int i)
330 return set_exists(i) ? &set_v[i].coin_score : NULL;
333 /*---------------------------------------------------------------------------*/
335 int set_level_exists(int s, int i)
337 return (i >= 0 && i < set_v[s].count);
340 static void set_load_levels(void)
347 const char *roman[] = {
349 "I", "II", "III", "IV", "V",
350 "VI", "VII", "VIII", "IX", "X",
351 "XI", "XII", "XIII", "XIV", "XV",
352 "XVI", "XVII", "XVIII", "XIX", "XX",
353 "XXI", "XXII", "XXIII", "XXIV", "XXV"
356 for (i = 0; i < set_v[set].count; i++)
360 level_load(set_v[set].level_name_v[i], l);
362 l->set = &set_v[set];
366 sprintf(l->name, "%s", roman[bnb++]);
368 sprintf(l->name, "%02d", nb++);
374 /* Unlock first level. */
376 level_v[0].is_locked = 0;
392 struct level *get_level(int i)
394 return (i >= 0 && i < set_v[set].count) ? &level_v[i] : NULL;
397 /*---------------------------------------------------------------------------*/
399 int set_score_update(int timer, int coins, int *score_rank, int *times_rank)
401 struct set *s = &set_v[set];
402 char player[MAXSTR] = "";
404 config_get_s(CONFIG_PLAYER, player, MAXSTR);
407 *score_rank = score_coin_insert(&s->coin_score, player, timer, coins);
410 *times_rank = score_time_insert(&s->time_score, player, timer, coins);
412 if ((score_rank && *score_rank < 3) || (times_rank && *times_rank < 3))
418 void set_rename_player(int score_rank, int times_rank, const char *player)
420 struct set *s = &set_v[set];
422 strncpy(s->coin_score.player[score_rank], player, MAXNAM);
423 strncpy(s->time_score.player[times_rank], player, MAXNAM);
426 /*---------------------------------------------------------------------------*/
428 void level_snap(int i)
430 char filename[MAXSTR];
433 /* Convert the level name to a PNG filename. */
435 memset(filename, 0, MAXSTR);
437 ext = strrchr(level_v[i].file, '.');
438 strncpy(filename, level_v[i].file,
439 ext ? ext - level_v[i].file : strlen(level_v[i].file));
440 strcat(filename, ".png");
442 /* Initialize the game for a snapshot. */
444 if (game_init(level_v[i].file, 0, 1))
446 /* Render the level and grab the screen. */
453 image_snap(filename);
455 SDL_GL_SwapBuffers();
463 for (i = 0; i < set_v[set].count; i++)
465 level_v[i].is_locked = 0;
466 level_v[i].is_completed = 1;
470 /*---------------------------------------------------------------------------*/