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 /*---------------------------------------------------------------------------*/
32 char time_n[4][MAXNAM];
36 char coin_n[4][MAXNAM];
54 static int score; /* Current coin total */
55 static int coins; /* Current coin count */
56 static int balls; /* Current life count */
58 static int level; /* Current level number */
59 static int count; /* Number of levels */
60 static int limit; /* Last opened (locked) level */
62 static int mode; /* Current play mode */
64 static int times_total;
66 static struct level level_v[MAXLVL];
67 static struct score score_v[MAXLVL];
69 static char scores_file[MAXSTR];
71 /*---------------------------------------------------------------------------*/
73 const char * mode_to_str(int m)
77 case MODE_CHALLENGE: return _("Challenge");
78 case MODE_NORMAL: return _("Normal");
79 case MODE_PRACTICE: return _("Practice");
80 default: return "???";
84 /*---------------------------------------------------------------------------*/
86 static void level_store_hs(const char *filename)
90 if ((fout = fopen(config_user(filename), "w")))
95 for (i = 0; i < limit; i++)
96 for (j = 0; j < 3; j++)
98 if (strlen(score_v[i].time_n[j]) == 0)
99 strcpy(score_v[i].time_n[j], DEFAULT_PLAYER);
100 if (strlen(score_v[i].coin_n[j]) == 0)
101 strcpy(score_v[i].coin_n[j], DEFAULT_PLAYER);
103 fprintf(fout, "%d %d %s\n",
104 score_v[i].time_t[j],
105 score_v[i].time_c[j],
106 score_v[i].time_n[j]);
107 fprintf(fout, "%d %d %s\n",
108 score_v[i].coin_t[j],
109 score_v[i].coin_c[j],
110 score_v[i].coin_n[j]);
117 static void level_load_hs(const char *filename)
123 if ((fin = fopen(config_user(filename), "r")))
127 for (i = 0; i < count; i++)
129 if (fscanf(fin, "%d %d %s",
130 &score_v[i].time_t[0],
131 &score_v[i].time_c[0],
132 score_v[i].time_n[0]) == 3 &&
133 fscanf(fin, "%d %d %s",
134 &score_v[i].coin_t[0],
135 &score_v[i].coin_c[0],
136 score_v[i].coin_n[0]) == 3 &&
137 fscanf(fin, "%d %d %s",
138 &score_v[i].time_t[1],
139 &score_v[i].time_c[1],
140 score_v[i].time_n[1]) == 3 &&
141 fscanf(fin, "%d %d %s",
142 &score_v[i].coin_t[1],
143 &score_v[i].coin_c[1],
144 score_v[i].coin_n[1]) == 3 &&
145 fscanf(fin, "%d %d %s",
146 &score_v[i].time_t[2],
147 &score_v[i].time_c[2],
148 score_v[i].time_n[2]) == 3 &&
149 fscanf(fin, "%d %d %s",
150 &score_v[i].coin_t[2],
151 &score_v[i].coin_c[2],
152 score_v[i].coin_n[2]) == 3)
160 /*---------------------------------------------------------------------------*/
162 static void level_init_rc(const char *filename)
173 /* Load the levels list. */
175 if ((fin = fopen(config_data(filename), "r")))
177 while (count < MAXLVL && fgets(buf, MAXSTR, fin))
179 sscanf(buf, "%s %s %s %s %d %d %s",
184 &level_v[count].time,
185 &level_v[count].goal,
186 level_v[count].song);
193 static void level_init_hs(const char *filename)
199 /* Set some sane values in case the scores file is missing. */
201 for (i = 0; i < MAXLVL; i++)
203 strcpy(score_v[i].time_n[0], "Hard");
204 strcpy(score_v[i].time_n[1], "Medium");
205 strcpy(score_v[i].time_n[2], "Easy");
207 score_v[i].time_t[0] = i ? 59999 : 359999;
208 score_v[i].time_t[1] = i ? 59999 : 359999;
209 score_v[i].time_t[2] = i ? 59999 : 359999;
211 score_v[i].time_c[0] = 0;
212 score_v[i].time_c[1] = 0;
213 score_v[i].time_c[2] = 0;
215 strcpy(score_v[i].coin_n[0], "Hard");
216 strcpy(score_v[i].coin_n[1], "Medium");
217 strcpy(score_v[i].coin_n[2], "Easy");
219 score_v[i].coin_t[0] = i ? 59999 : 359999;
220 score_v[i].coin_t[1] = i ? 59999 : 359999;
221 score_v[i].coin_t[2] = i ? 59999 : 359999;
223 score_v[i].coin_c[0] = 0;
224 score_v[i].coin_c[1] = 0;
225 score_v[i].coin_c[2] = 0;
228 /* Load the default high scores file. */
230 if ((fin = fopen(config_data(filename), "r")))
232 for (i = 0; i < MAXLVL && fgets(buf, MAXSTR, fin); i++)
233 sscanf(buf, "%d %d %d %d %d %d",
234 &score_v[i].time_t[0], &score_v[i].coin_c[0],
235 &score_v[i].time_t[1], &score_v[i].coin_c[1],
236 &score_v[i].time_t[2], &score_v[i].coin_c[2]);
242 /*---------------------------------------------------------------------------*/
244 const char *level_shot(int i)
246 return level_v[i].shot;
249 const char *level_time_n(int i, int j)
251 return score_v[i].time_n[j];
254 const char *level_coin_n(int i, int j)
256 return score_v[i].coin_n[j];
259 /*---------------------------------------------------------------------------*/
260 /* Return the coin count for the Most Coins or Best Time score. */
262 int level_coin_c(int i, int j)
267 return score_v[i].coin_c[j];
270 int level_time_c(int i, int j)
272 return score_v[i].time_c[j];
275 /*---------------------------------------------------------------------------*/
276 /* Return the time for the Most Coins or Best Time score. */
278 int level_coin_t(int i, int j)
280 return score_v[i].coin_t[j];
283 int level_time_t(int i, int j)
286 return level_v[i].time - curr_clock();
288 return score_v[i].time_t[j];
291 /*---------------------------------------------------------------------------*/
293 void level_init(const char *init_levels,
294 const char *init_scores,
295 const char *user_scores)
297 memset(level_v, 0, sizeof (struct level) * MAXLVL);
298 memset(score_v, 0, sizeof (struct score) * MAXLVL);
300 level_init_rc(init_levels);
301 level_init_hs(init_scores);
302 level_load_hs(user_scores);
304 strncpy(scores_file, user_scores, MAXSTR);
310 void level_cheat(void)
311 /* Open each level of the set */
316 void level_free(void)
320 level_store_hs(scores_file);
322 for (i = 0; i < count; i++)
323 if (glIsTexture(level_v[i].text))
324 glDeleteTextures(1, &level_v[i].text);
329 int level_exists(int i)
331 return (0 < i && i < count);
334 int level_opened(int i)
336 return level_exists(i) && (0 < i && i < count && i <= limit);
339 int level_locked(int i)
341 return level_opened(i) && (i == limit);
344 int level_extra_bonus(int i)
346 return level_exists(i) && (i > 20);
349 int level_extra_bonus_opened(void)
351 return level_opened(21);
354 int level_set_completed(void)
356 return limit >= count;
359 static const char * names[] = {"1", "2", "3", "4", "5",
360 "6", "7", "8", "9", "10",
361 "11", "12", "13", "14", "15",
362 "16", "17", "18", "19", "20",
363 N_("B1"), N_("B2"), N_("B3"), N_("B4"), N_("B5")};
365 const char * level_number_name(i)
366 /* Return the number name of the level i */
371 /*---------------------------------------------------------------------------*/
373 int curr_times_total(void) { return times_total; }
375 int curr_count(void) { return count; }
376 int curr_score(void) { return score; }
377 int curr_balls(void) { return balls; }
378 int curr_level(void) { return level; }
380 /*---------------------------------------------------------------------------*/
382 static int score_time_comp(const struct score *S, int i, int j)
384 if (S->time_t[i] < S->time_t[j])
387 if (S->time_t[i] == S->time_t[j] &&
388 S->time_c[i] > S->time_c[j])
394 static int score_coin_comp(const struct score *S, int i, int j)
396 if (S->coin_c[i] > S->coin_c[j])
399 if (S->coin_c[i] == S->coin_c[j] &&
400 S->coin_t[i] < S->coin_t[j])
406 /*---------------------------------------------------------------------------*/
408 static void score_time_swap(struct score *S, int i, int j)
414 strncpy(n, S->time_n[i], MAXNAM);
415 strncpy(S->time_n[i], S->time_n[j], MAXNAM);
416 strncpy(S->time_n[j], n, MAXNAM);
419 S->time_t[i] = S->time_t[j];
423 S->time_c[i] = S->time_c[j];
427 static void score_coin_swap(struct score *S, int i, int j)
433 strncpy(n, S->coin_n[i], MAXNAM);
434 strncpy(S->coin_n[i], S->coin_n[j], MAXNAM);
435 strncpy(S->coin_n[j], n, MAXNAM);
438 S->coin_t[i] = S->coin_t[j];
442 S->coin_c[i] = S->coin_c[j];
446 /*---------------------------------------------------------------------------*/
448 int level_replay(const char *filename)
451 return demo_replay_init(filename, &mode, &score, &balls, ×_total);
454 int level_play_go(void)
455 /* Start to play the current level */
460 goal = (mode == MODE_PRACTICE) ? 0 : level_v[level].goal;
461 time = (mode == MODE_PRACTICE) ? 0 : level_v[level].time;
463 return demo_play_init(USER_REPLAY_FILE,
471 score, balls, times_total);
474 void level_play(int i, int m)
475 /* Prepare to play a level sequence from the `i'th level */
485 /*---------------------------------------------------------------------------*/
487 int count_extra_balls(int old_score, int coins)
489 int modulo = old_score % 100;
490 int sum = modulo + coins;
494 void level_stop(int state)
495 /* Stop the current playing level */
500 coins = curr_coins();
502 /* open next level */
503 if (state == GAME_GOAL && mode != MODE_PRACTICE && limit < level+1)
504 if (level_extra_bonus_opened() || !level_extra_bonus(level+1) || mode == MODE_CHALLENGE)
507 if (mode == MODE_CHALLENGE)
510 times_total += level_v[level].time - curr_clock();
512 /* sum coins an earn extra balls */
513 if (state == GAME_GOAL)
515 balls += count_extra_balls(score, coins);
520 if (state == GAME_TIME || state == GAME_FALL)
524 /* stop demo recording */
525 time = (mode == MODE_PRACTICE) ? curr_clock() : level_v[level].time - curr_clock();
526 demo_play_stop(coins, time, state);
531 return (mode == MODE_CHALLENGE) && (balls <= 0);
536 return (level + 1 == count) || (level_extra_bonus(level + 1));
539 void level_next(void)
544 int level_sort(int *time_i, int *coin_i)
549 coins = curr_coins();
550 if (mode == MODE_PRACTICE)
551 clock = curr_clock();
553 clock = level_v[level].time - curr_clock();
555 config_get_s(CONFIG_PLAYER, player, MAXNAM);
557 /* Insert the time record into the high score list. */
559 strncpy(score_v[level].time_n[3], player, MAXNAM);
560 score_v[level].time_c[3] = coins;
561 score_v[level].time_t[3] = clock;
563 for (i = 2; i >= 0 && score_time_comp(score_v + level, i + 1, i); i--)
565 score_time_swap(score_v + level, i + 1, i);
569 /* Insert the coin record into the high score list. */
571 strncpy(score_v[level].coin_n[3], player, MAXNAM);
572 score_v[level].coin_c[3] = coins;
573 score_v[level].coin_t[3] = clock;
575 for (i = 2; i >= 0 && score_coin_comp(score_v + level, i + 1, i); i--)
577 score_coin_swap(score_v + level, i + 1, i);
581 return (*time_i < 3 || *coin_i < 3);
584 int level_done(int *time_i, int *coin_i)
589 config_get_s(CONFIG_PLAYER, player, MAXNAM);
591 /* Note a global high score. */
593 strncpy(score_v[0].time_n[3], player, MAXNAM);
594 score_v[0].time_c[3] = score;
595 score_v[0].time_t[3] = times_total;
597 strncpy(score_v[0].coin_n[3], player, MAXNAM);
598 score_v[0].coin_c[3] = score;
599 score_v[0].coin_t[3] = times_total;
601 /* Insert the time record into the global high score list. */
603 for (i = 2; i >= 0 && score_time_comp(score_v, i + 1, i); i--)
605 score_time_swap(score_v, i + 1, i);
609 /* Insert the coin record into the global high score list. */
611 for (i = 2; i >= 0 && score_coin_comp(score_v, i + 1, i); i--)
613 score_coin_swap(score_v, i + 1, i);
617 return (*time_i < 3 || *coin_i < 3);
620 /*---------------------------------------------------------------------------*/
622 void level_name(int i, const char *name, int time_i, int coin_i)
624 strncpy(score_v[i].time_n[time_i], name, MAXNAM);
625 strncpy(score_v[i].coin_n[coin_i], name, MAXNAM);
628 void level_snap(int i)
630 char filename[MAXSTR];
632 /* Convert the level name to a BMP filename. */
634 memset(filename, 0, MAXSTR);
635 strncpy(filename, level_v[i].file, strcspn(level_v[i].file, "."));
636 strcat(filename, ".bmp");
638 /* Initialize the game for a snapshot. */
640 if (game_init(level_v[i].file, level_v[i].back, level_v[i].grad, 0, 0))
642 /* Render the level and grab the screen. */
648 SDL_GL_SwapBuffers();
650 image_snap(filename);
654 /*---------------------------------------------------------------------------*/