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.
27 /*---------------------------------------------------------------------------*/
32 static struct set set_v[MAXSET];
33 static struct level level_v[MAXLVL];
35 /*---------------------------------------------------------------------------*/
37 static void put_score(FILE *fp, const struct score *s)
41 for (j = 0; j < NSCORE; j++)
42 fprintf(fp, "%d %d %s\n", s->timer[j], s->coins[j], s->player[j]);
45 /* Store the score of the set. */
46 static void set_store_hs(void)
48 const struct set *s = &set_v[set];
51 const struct level *l;
52 char states[MAXLVL + 1];
54 if ((fout = fopen(config_user(s->user_scores), "w")))
56 for (i = 0; i < s->count; i++)
58 if (level_v[i].is_locked)
60 else if (level_v[i].is_completed)
65 states[s->count] = '\0';
66 fprintf(fout, "%s\n",states);
68 put_score(fout, &s->time_score);
69 put_score(fout, &s->coin_score);
71 for (i = 0; i < s->count; i++)
75 put_score(fout, &l->score.best_times);
76 put_score(fout, &l->score.unlock_goal);
77 put_score(fout, &l->score.most_coins);
84 static int get_score(FILE *fp, struct score *s)
89 for (j = 0; j < NSCORE && res; j++)
91 res = fscanf(fp, "%d %d %s\n",
99 /* Get the score of the set. */
100 static void set_load_hs(void)
102 struct set *s = &set_v[set];
107 const char *fn = config_user(s->user_scores);
108 char states[MAXLVL + 1];
110 if ((fin = fopen(fn, "r")))
112 res = fscanf(fin, "%s\n", states) == 1 && strlen(states) == s->count;
114 for (i = 0; i < s->count && res; i++)
119 level_v[i].is_locked = 1;
120 level_v[i].is_completed = 0;
124 level_v[i].is_locked = 0;
125 level_v[i].is_completed = 1;
129 level_v[i].is_locked = 0;
130 level_v[i].is_completed = 0;
139 get_score(fin, &s->time_score) &&
140 get_score(fin, &s->coin_score);
142 for (i = 0; i < s->count && res; i++)
145 res = get_score(fin, &l->score.best_times) &&
146 get_score(fin, &l->score.unlock_goal) &&
147 get_score(fin, &l->score.most_coins);
153 if (!res && errno != ENOENT)
156 L_("Error while loading user high-score file '%s': %s\n"),
157 fn, errno ? strerror(errno) : L_("Incorrect format"));
161 static char *strip_eol(char *str)
163 char *c = str + strlen(str) - 1;
165 while (c >= str && (*c == '\n' || *c =='\r'))
171 static int set_load(struct set *s, const char *filename)
177 fin = fopen(config_data(filename), "r");
181 fprintf(stderr, L_("Cannot load the set file '%s': %s\n"),
182 filename, strerror(errno));
186 memset(s, 0, sizeof (struct set));
188 /* Set some sane values in case the scores hs is missing. */
190 score_init_hs(&s->time_score, 359999, 0);
191 score_init_hs(&s->coin_score, 359999, 0);
193 /* Load set metadata. */
195 strcpy(s->file, filename);
197 if ((res = fgets(buf, MAXSTR, fin) != NULL))
198 strcpy(s->name, strip_eol(buf));
199 if (res && (res = fgets(buf, MAXSTR, fin) != NULL))
200 strcpy(s->desc, strip_eol(buf));
201 if (res && (res = fgets(buf, MAXSTR, fin) != NULL))
202 strcpy(s->id, strip_eol(buf));
203 if (res && (res = fgets(buf, MAXSTR, fin) != NULL))
204 strcpy(s->shot, strip_eol(buf));
205 if (res && (res = fgets(buf, MAXSTR, fin) != NULL))
206 sscanf(buf, "%d %d %d %d %d %d",
207 &s->time_score.timer[0],
208 &s->time_score.timer[1],
209 &s->time_score.timer[2],
210 &s->coin_score.coins[0],
211 &s->coin_score.coins[1],
212 &s->coin_score.coins[2]);
214 strcpy(s->user_scores, "neverballhs-");
215 strcat(s->user_scores, s->id);
221 while (s->count < MAXLVL && (fscanf(fin, "%s", buf) == 1))
226 /* Load the levels states (stored in the user high score file) */
228 s->locked = s->count;
231 if ((fin = fopen(config_user(s->user_scores), "r")))
233 char states[MAXLVL + 1];
235 if ((fscanf(fin, "%s\n", states) == 1) && (strlen(states) == s->count))
237 for (i = 0; i < s->count; i++)
239 if (states[i] == 'O')
241 else if (states[i] == 'C')
250 if (s->locked == s->count)
251 s->locked = s->count-1;
256 /*---------------------------------------------------------------------------*/
266 if ((fin = fopen(config_data(SET_FILE), "r")))
268 while (count < MAXSET && fgets(name, MAXSTR, fin))
269 if (set_load(&set_v[count], strip_eol(name)))
278 /*---------------------------------------------------------------------------*/
280 int set_exists(int i)
282 return (0 <= i && i < count);
285 const struct set *get_set(int i)
287 return set_exists(i) ? &set_v[i] : NULL;
290 /*---------------------------------------------------------------------------*/
292 int set_unlocked(const struct set *s)
294 return s->locked == 0;
297 int set_completed(const struct set *s)
299 return s->completed == s->count;
302 int set_level_exists(const struct set *s, int i)
304 return (i >= 0) && (i < s->count);
307 /*---------------------------------------------------------------------------*/
309 static void set_load_levels(void)
320 const char *roman[] = {
322 "I", "II", "III", "IV", "V",
323 "VI", "VII", "VIII", "IX", "X",
324 "XI", "XII", "XIII", "XIV", "XV",
325 "XVI", "XVII", "XVIII", "XIX", "XX",
326 "XXI", "XXII", "XXIII", "XXIV", "XXV"
329 if ((fin = fopen(config_data(set_v[set].file), "r")))
333 /* Skip the five first lines */
334 for (i = 0; i < 5; i++)
335 fgets(buf, MAXSTR, fin);
337 for (i = 0; i < set_v[set].count && res; i++)
341 res = (fscanf(fin, "%s", name) == 1);
346 /* Initialize set related info */
347 l->set = &set_v[set];
351 sprintf(l->repr, "%s", roman[bnb++]);
353 sprintf(l->repr, "%02d", nb++);
358 level_v[0].is_locked = 0; /* unlock the first level */
362 assert(i == set_v[set].count);
373 const struct set *curr_set(void)
378 const struct level *get_level(int i)
380 return (i >= 0 && i < set_v[set].count) ? &level_v[i] : NULL;
383 /*---------------------------------------------------------------------------*/
385 /* Update the level score rank according to coins and timer. */
386 static int level_score_update(struct level_game *lg, const char *player)
388 int timer = lg->timer;
389 int coins = lg->coins;
390 struct level *l = &level_v[lg->level->number];
392 lg->time_rank = score_time_insert(&l->score.best_times,
393 player, timer, coins);
395 if (lg->mode == MODE_CHALLENGE || lg->mode == MODE_NORMAL)
396 lg->goal_rank = score_time_insert(&l->score.unlock_goal,
397 player, timer, coins);
401 lg->coin_rank = score_coin_insert(&l->score.most_coins,
402 player, timer, coins);
404 return (lg->time_rank < 3 || lg->goal_rank < 3 || lg->coin_rank < 3);
407 /* Update the set score rank according to score and times. */
408 static int set_score_update(struct level_game *lg, const char *player)
410 int timer = lg->times;
411 int coins = lg->score;
412 struct set *s = &set_v[set];
414 lg->score_rank = score_time_insert(&s->time_score, player, timer, coins);
415 lg->times_rank = score_time_insert(&s->coin_score, player, timer, coins);
417 return (lg->score_rank < 3 || lg->times_rank < 3);
420 /* Update the player name for set and level high-score. */
421 void score_change_name(struct level_game *lg, const char *player)
423 struct set *s = &set_v[set];
424 struct level *l = &level_v[lg->level->number];
426 strncpy(l->score.best_times.player [lg->time_rank], player, MAXNAM);
427 strncpy(l->score.unlock_goal.player[lg->goal_rank], player, MAXNAM);
428 strncpy(l->score.most_coins.player [lg->coin_rank], player, MAXNAM);
430 strncpy(s->coin_score.player[lg->score_rank], player, MAXNAM);
431 strncpy(s->time_score.player[lg->times_rank], player, MAXNAM);
436 static struct level *next_level(int i)
438 return set_level_exists(&set_v[set], i + 1) ? &level_v[i + 1] : NULL;
441 static struct level *next_normal_level(int i)
443 for (i++; i < set_v[set].count; i++)
444 if (!level_v[i].is_bonus)
450 /*---------------------------------------------------------------------------*/
452 void set_finish_level(struct level_game *lg, const char *player)
454 struct set *s = &set_v[set];
455 int ln = lg->level->number; /* Current level number */
456 struct level *cl = &level_v[ln]; /* Current level */
457 struct level *nl = NULL; /* Next level */
458 int dirty = 0; /* Should the score be saved? */
460 assert(s == cl->set);
462 /* if no set, no next level */
465 /* if no set, return */
466 lg->next_level = NULL;
470 /* On level completed */
471 if (lg->status == GAME_GOAL)
473 /* Update level scores */
474 dirty = level_score_update(lg, player);
476 /* Complete the level */
477 if (lg->mode == MODE_CHALLENGE || lg->mode == MODE_NORMAL)
479 /* Complete the level */
480 if (!cl->is_completed)
482 cl->is_completed = 1;
489 /* On goal reached */
490 if (lg->status == GAME_GOAL)
492 /* Identify the following level */
496 /* skip bonuses if unlocked in any mode */
499 nl = next_normal_level(nl->number);
500 if(lg->mode == MODE_CHALLENGE)
506 else if (lg->mode == MODE_CHALLENGE)
509 else if (cl->is_bonus || lg->mode != MODE_CHALLENGE)
511 /* On fail, identify the next level (only in bonus for challenge) */
512 nl = next_normal_level(ln);
513 /* Next level may be unavailable */
514 if (!cl->is_bonus && nl != NULL && nl->is_locked)
516 /* Fail a bonus level but win the set! */
517 else if (nl == NULL && lg->mode == MODE_CHALLENGE)
524 /* update set score */
525 set_score_update(lg, player);
526 /* unlock all levels */
531 /* unlock the next level if needed */
532 if (nl != NULL && nl->is_locked)
534 if (lg->mode == MODE_CHALLENGE || lg->mode == MODE_NORMAL)
545 /* got the next level */
553 /*---------------------------------------------------------------------------*/
555 void level_snap(int i)
557 char filename[MAXSTR];
560 /* Convert the level name to a PNG filename. */
562 memset(filename, 0, MAXSTR);
564 ext = strrchr(level_v[i].file, '.');
565 strncpy(filename, level_v[i].file,
566 ext ? ext - level_v[i].file : strlen(level_v[i].file));
567 strcat(filename, ".png");
569 /* Initialize the game for a snapshot. */
571 if (game_init(&level_v[i], 0, 0))
573 /* Render the level and grab the screen. */
579 SDL_GL_SwapBuffers();
581 image_snap(filename);
586 /* Open each level of the current set */
590 set_v[set].locked = 0;
592 for (i = 0; i < set_v[set].count; i++)
593 level_v[i].is_locked = 0;
597 /*---------------------------------------------------------------------------*/