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 #include "game_server.h"
29 #include "game_client.h"
30 #include "game_proxy.h"
32 /*---------------------------------------------------------------------------*/
38 char *id; /* Internal set identifier */
39 char *name; /* Set name */
40 char *desc; /* Set description */
41 char *shot; /* Set screen-shot */
43 char user_scores[PATHMAX]; /* User high-score file */
45 struct score coin_score; /* Challenge score */
46 struct score time_score; /* Challenge score */
50 int count; /* Number of levels */
51 char *level_name_v[MAXLVL]; /* List of level file names */
54 static int set_state = 0;
59 static struct set set_v[MAXSET];
60 static struct level level_v[MAXLVL];
62 /*---------------------------------------------------------------------------*/
64 static void put_score(fs_file fp, const struct score *s)
68 for (j = 0; j < NSCORE; j++)
69 fs_printf(fp, "%d %d %s\n", s->timer[j], s->coins[j], s->player[j]);
72 void set_store_hs(void)
74 const struct set *s = &set_v[set];
77 const struct level *l;
78 char states[MAXLVL + 1];
80 if ((fout = fs_open(s->user_scores, "w")))
82 for (i = 0; i < s->count; i++)
84 if (level_v[i].is_locked)
86 else if (level_v[i].is_completed)
91 states[s->count] = '\0';
92 fs_printf(fout, "%s\n",states);
94 put_score(fout, &s->time_score);
95 put_score(fout, &s->coin_score);
97 for (i = 0; i < s->count; i++)
101 put_score(fout, &l->score.best_times);
102 put_score(fout, &l->score.fast_unlock);
103 put_score(fout, &l->score.most_coins);
110 static int get_score(fs_file fp, struct score *s)
116 for (j = 0; j < NSCORE && res; j++)
118 res = (fs_gets(line, sizeof (line), fp) &&
119 sscanf(line, "%d %d %s\n",
127 /* Get the score of the set. */
128 static void set_load_hs(void)
130 struct set *s = &set_v[set];
135 const char *fn = s->user_scores;
136 char states[MAXLVL + sizeof ("\n")];
138 if ((fin = fs_open(fn, "r")))
140 res = (fs_gets(states, sizeof (states), fin) &&
141 strlen(states) - 1 == s->count);
143 for (i = 0; i < s->count && res; i++)
148 level_v[i].is_locked = 1;
149 level_v[i].is_completed = 0;
153 level_v[i].is_locked = 0;
154 level_v[i].is_completed = 1;
158 level_v[i].is_locked = 0;
159 level_v[i].is_completed = 0;
168 get_score(fin, &s->time_score) &&
169 get_score(fin, &s->coin_score);
171 for (i = 0; i < s->count && res; i++)
174 res = get_score(fin, &l->score.best_times) &&
175 get_score(fin, &l->score.fast_unlock) &&
176 get_score(fin, &l->score.most_coins);
182 if (!res && errno != ENOENT)
185 L_("Error while loading user high-score file '%s': %s\n"),
186 fn, errno ? strerror(errno) : L_("Incorrect format"));
190 /*---------------------------------------------------------------------------*/
192 static int set_load(struct set *s, const char *filename)
195 char *scores, *level_name;
197 fin = fs_open(filename, "r");
201 fprintf(stderr, L_("Cannot load the set file '%s': %s\n"),
202 filename, strerror(errno));
206 memset(s, 0, sizeof (struct set));
208 /* Set some sane values in case the scores are missing. */
210 score_init_hs(&s->time_score, 359999, 0);
211 score_init_hs(&s->coin_score, 359999, 0);
213 strncpy(s->file, filename, PATHMAX - 1);
215 if (read_line(&s->name, fin) &&
216 read_line(&s->desc, fin) &&
217 read_line(&s->id, fin) &&
218 read_line(&s->shot, fin) &&
219 read_line(&scores, fin))
221 sscanf(scores, "%d %d %d %d %d %d",
222 &s->time_score.timer[0],
223 &s->time_score.timer[1],
224 &s->time_score.timer[2],
225 &s->coin_score.coins[0],
226 &s->coin_score.coins[1],
227 &s->coin_score.coins[2]);
231 strncpy(s->user_scores, "neverballhs-", PATHMAX - 1);
232 strncat(s->user_scores, s->id, PATHMAX - 1 - strlen("neverballhs-"));
236 while (s->count < MAXLVL && read_line(&level_name, fin))
238 s->level_name_v[s->count] = level_name;
268 if ((fin = fs_open(SET_FILE, "r")))
270 while (count < MAXSET && read_line(&name, fin))
272 /* Skip "Misc" set when not in dev mode. */
274 if (strcmp(name, SET_MISC) == 0 && !config_cheat())
280 if (set_load(&set_v[count], name))
297 for (i = 0; i < count; i++)
304 for (j = 0; j < set_v[i].count; j++)
305 free(set_v[i].level_name_v[j]);
311 /*---------------------------------------------------------------------------*/
313 int set_exists(int i)
315 return (0 <= i && i < count);
318 const char *set_id(int i)
320 return set_exists(i) ? set_v[i].id : NULL;
323 const char *set_name(int i)
325 return set_exists(i) ? _(set_v[i].name) : NULL;
328 const char *set_desc(int i)
330 return set_exists(i) ? _(set_v[i].desc) : NULL;
333 const char *set_shot(int i)
335 return set_exists(i) ? set_v[i].shot : NULL;
338 const struct score *set_time_score(int i)
340 return set_exists(i) ? &set_v[i].time_score : NULL;
343 const struct score *set_coin_score(int i)
345 return set_exists(i) ? &set_v[i].coin_score : NULL;
348 /*---------------------------------------------------------------------------*/
350 int set_level_exists(int s, int i)
352 return (i >= 0 && i < set_v[s].count);
355 static void set_load_levels(void)
362 const char *roman[] = {
364 "I", "II", "III", "IV", "V",
365 "VI", "VII", "VIII", "IX", "X",
366 "XI", "XII", "XIII", "XIV", "XV",
367 "XVI", "XVII", "XVIII", "XIX", "XX",
368 "XXI", "XXII", "XXIII", "XXIV", "XXV"
371 for (i = 0; i < set_v[set].count; i++)
375 level_load(set_v[set].level_name_v[i], l);
377 l->set = &set_v[set];
381 sprintf(l->name, "%s", roman[bnb++]);
383 sprintf(l->name, "%02d", nb++);
389 /* Unlock first level. */
391 level_v[0].is_locked = 0;
407 struct level *get_level(int i)
409 return (i >= 0 && i < set_v[set].count) ? &level_v[i] : NULL;
412 /*---------------------------------------------------------------------------*/
414 int set_score_update(int timer, int coins, int *score_rank, int *times_rank)
416 struct set *s = &set_v[set];
417 char player[MAXSTR] = "";
419 config_get_s(CONFIG_PLAYER, player, MAXSTR);
422 *score_rank = score_coin_insert(&s->coin_score, player, timer, coins);
425 *times_rank = score_time_insert(&s->time_score, player, timer, coins);
427 if ((score_rank && *score_rank < 3) || (times_rank && *times_rank < 3))
433 void set_rename_player(int score_rank, int times_rank, const char *player)
435 struct set *s = &set_v[set];
437 strncpy(s->coin_score.player[score_rank], player, MAXNAM);
438 strncpy(s->time_score.player[times_rank], player, MAXNAM);
441 /*---------------------------------------------------------------------------*/
443 void level_snap(int i)
445 char filename[MAXSTR];
448 /* Convert the level name to a PNG filename. */
450 memset(filename, 0, MAXSTR);
452 ext = strrchr(level_v[i].file, '.');
453 strncpy(filename, level_v[i].file,
454 ext ? ext - level_v[i].file : strlen(level_v[i].file));
455 strcat(filename, ".png");
457 /* Initialize the game for a snapshot. */
459 if (game_client_init(level_v[i].file))
463 cmd.type = CMD_GOAL_OPEN;
464 game_proxy_enq(&cmd);
466 /* Render the level and grab the screen. */
469 game_set_fly(1.f, game_client_file());
471 game_client_step(NULL);
474 image_snap(filename);
476 SDL_GL_SwapBuffers();
484 for (i = 0; i < set_v[set].count; i++)
486 level_v[i].is_locked = 0;
487 level_v[i].is_completed = 1;
491 /*---------------------------------------------------------------------------*/