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_name(int i)
305 return set_exists(i) ? _(set_v[i].name) : NULL;
308 const char *set_desc(int i)
310 return set_exists(i) ? _(set_v[i].desc) : NULL;
313 const char *set_shot(int i)
315 return set_exists(i) ? set_v[i].shot : NULL;
318 const struct score *set_time_score(int i)
320 return set_exists(i) ? &set_v[i].time_score : NULL;
323 const struct score *set_coin_score(int i)
325 return set_exists(i) ? &set_v[i].coin_score : NULL;
328 /*---------------------------------------------------------------------------*/
330 int set_level_exists(int s, int i)
332 return (i >= 0 && i < set_v[s].count);
335 static void set_load_levels(void)
342 const char *roman[] = {
344 "I", "II", "III", "IV", "V",
345 "VI", "VII", "VIII", "IX", "X",
346 "XI", "XII", "XIII", "XIV", "XV",
347 "XVI", "XVII", "XVIII", "XIX", "XX",
348 "XXI", "XXII", "XXIII", "XXIV", "XXV"
351 for (i = 0; i < set_v[set].count; i++)
355 level_load(set_v[set].level_name_v[i], l);
357 l->set = &set_v[set];
361 sprintf(l->repr, "%s", roman[bnb++]);
363 sprintf(l->repr, "%02d", nb++);
369 /* Unlock first level. */
371 level_v[0].is_locked = 0;
387 struct level *get_level(int i)
389 return (i >= 0 && i < set_v[set].count) ? &level_v[i] : NULL;
392 /*---------------------------------------------------------------------------*/
394 int set_score_update(int timer, int coins, int *score_rank, int *times_rank)
396 struct set *s = &set_v[set];
397 char player[MAXSTR] = "";
399 config_get_s(CONFIG_PLAYER, player, MAXSTR);
402 *score_rank = score_coin_insert(&s->coin_score, player, timer, coins);
405 *times_rank = score_time_insert(&s->time_score, player, timer, coins);
407 if ((score_rank && *score_rank < 3) || (times_rank && *times_rank < 3))
413 void set_rename_player(int score_rank, int times_rank, const char *player)
415 struct set *s = &set_v[set];
417 strncpy(s->coin_score.player[score_rank], player, MAXNAM);
418 strncpy(s->time_score.player[times_rank], player, MAXNAM);
421 /*---------------------------------------------------------------------------*/
423 void level_snap(int i)
425 char filename[MAXSTR];
428 /* Convert the level name to a PNG filename. */
430 memset(filename, 0, MAXSTR);
432 ext = strrchr(level_v[i].file, '.');
433 strncpy(filename, level_v[i].file,
434 ext ? ext - level_v[i].file : strlen(level_v[i].file));
435 strcat(filename, ".png");
437 /* Initialize the game for a snapshot. */
439 if (game_init(level_v[i].file, 0, 1))
441 /* Render the level and grab the screen. */
447 SDL_GL_SwapBuffers();
449 image_snap(filename);
457 for (i = 0; i < set_v[set].count; i++)
458 level_v[i].is_locked = 0;
461 /*---------------------------------------------------------------------------*/