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 balls; /* Current life count */
57 static int level; /* Current level number */
58 static int count; /* Number of levels */
59 static int limit; /* Last opened (locked) level */
61 static int mode; /* Current play mode */
63 static int times_total;
65 static struct level level_v[MAXLVL];
66 static struct score score_v[MAXLVL];
68 static char scores_file[MAXSTR];
70 /*---------------------------------------------------------------------------*/
72 const char * mode_to_str(int m)
76 case MODE_CHALLENGE: return _("Challenge");
77 case MODE_NORMAL: return _("Normal");
78 case MODE_PRACTICE: return _("Practice");
79 default: return "???";
83 /*---------------------------------------------------------------------------*/
85 static void level_store_hs(const char *filename)
89 if ((fout = fopen(config_user(filename), "w")))
94 for (i = 0; i < limit; i++)
95 for (j = 0; j < 3; j++)
97 if (strlen(score_v[i].time_n[j]) == 0)
98 strcpy(score_v[i].time_n[j], DEFAULT_PLAYER);
99 if (strlen(score_v[i].coin_n[j]) == 0)
100 strcpy(score_v[i].coin_n[j], DEFAULT_PLAYER);
102 fprintf(fout, "%d %d %s\n",
103 score_v[i].time_t[j],
104 score_v[i].time_c[j],
105 score_v[i].time_n[j]);
106 fprintf(fout, "%d %d %s\n",
107 score_v[i].coin_t[j],
108 score_v[i].coin_c[j],
109 score_v[i].coin_n[j]);
116 static void level_load_hs(const char *filename)
122 if ((fin = fopen(config_user(filename), "r")))
126 for (i = 0; i < count; i++)
128 if (fscanf(fin, "%d %d %s",
129 &score_v[i].time_t[0],
130 &score_v[i].time_c[0],
131 score_v[i].time_n[0]) == 3 &&
132 fscanf(fin, "%d %d %s",
133 &score_v[i].coin_t[0],
134 &score_v[i].coin_c[0],
135 score_v[i].coin_n[0]) == 3 &&
136 fscanf(fin, "%d %d %s",
137 &score_v[i].time_t[1],
138 &score_v[i].time_c[1],
139 score_v[i].time_n[1]) == 3 &&
140 fscanf(fin, "%d %d %s",
141 &score_v[i].coin_t[1],
142 &score_v[i].coin_c[1],
143 score_v[i].coin_n[1]) == 3 &&
144 fscanf(fin, "%d %d %s",
145 &score_v[i].time_t[2],
146 &score_v[i].time_c[2],
147 score_v[i].time_n[2]) == 3 &&
148 fscanf(fin, "%d %d %s",
149 &score_v[i].coin_t[2],
150 &score_v[i].coin_c[2],
151 score_v[i].coin_n[2]) == 3)
159 /*---------------------------------------------------------------------------*/
161 static void level_init_rc(const char *filename)
171 /* Load the levels list. */
173 if ((fin = fopen(config_data(filename), "r")))
175 while (count < MAXLVL && fgets(buf, MAXSTR, fin))
177 sscanf(buf, "%s %s %s %s %d %d %s",
182 &level_v[count].time,
183 &level_v[count].goal,
184 level_v[count].song);
191 static void level_init_hs(const char *filename)
197 /* Set some sane values in case the scores file is missing. */
199 for (i = 0; i < MAXLVL; i++)
201 strcpy(score_v[i].time_n[0], "Hard");
202 strcpy(score_v[i].time_n[1], "Medium");
203 strcpy(score_v[i].time_n[2], "Easy");
205 score_v[i].time_t[0] = i ? 59999 : 359999;
206 score_v[i].time_t[1] = i ? 59999 : 359999;
207 score_v[i].time_t[2] = i ? 59999 : 359999;
209 score_v[i].time_c[0] = 0;
210 score_v[i].time_c[1] = 0;
211 score_v[i].time_c[2] = 0;
213 strcpy(score_v[i].coin_n[0], "Hard");
214 strcpy(score_v[i].coin_n[1], "Medium");
215 strcpy(score_v[i].coin_n[2], "Easy");
217 score_v[i].coin_t[0] = i ? 59999 : 359999;
218 score_v[i].coin_t[1] = i ? 59999 : 359999;
219 score_v[i].coin_t[2] = i ? 59999 : 359999;
221 score_v[i].coin_c[0] = 0;
222 score_v[i].coin_c[1] = 0;
223 score_v[i].coin_c[2] = 0;
226 /* Load the default high scores file. */
228 if ((fin = fopen(config_data(filename), "r")))
230 for (i = 0; i < MAXLVL && fgets(buf, MAXSTR, fin); i++)
231 sscanf(buf, "%d %d %d %d %d %d",
232 &score_v[i].time_t[0], &score_v[i].coin_c[0],
233 &score_v[i].time_t[1], &score_v[i].coin_c[1],
234 &score_v[i].time_t[2], &score_v[i].coin_c[2]);
240 /*---------------------------------------------------------------------------*/
242 const char *level_shot(int i)
244 return level_v[i].shot;
247 const char *level_time_n(int i, int j)
249 return score_v[i].time_n[j];
252 const char *level_coin_n(int i, int j)
254 return score_v[i].coin_n[j];
257 /*---------------------------------------------------------------------------*/
258 /* Return the coin count for the Most Coins or Best Time score. */
260 int level_coin_c(int i, int j)
265 return score_v[i].coin_c[j];
268 int level_time_c(int i, int j)
270 return score_v[i].time_c[j];
273 /*---------------------------------------------------------------------------*/
274 /* Return the time for the Most Coins or Best Time score. */
276 int level_coin_t(int i, int j)
278 return score_v[i].coin_t[j];
281 int level_time_t(int i, int j)
284 return level_v[i].time - curr_clock();
286 return score_v[i].time_t[j];
289 /*---------------------------------------------------------------------------*/
291 void level_init(const char *init_levels,
292 const char *init_scores,
293 const char *user_scores)
295 memset(level_v, 0, sizeof (struct level) * MAXLVL);
296 memset(score_v, 0, sizeof (struct score) * MAXLVL);
298 level_init_rc(init_levels);
299 level_init_hs(init_scores);
300 level_load_hs(user_scores);
302 strncpy(scores_file, user_scores, MAXSTR);
308 void level_cheat(void)
309 /* Open each level of the set */
314 void level_free(void)
318 level_store_hs(scores_file);
320 for (i = 0; i < count; i++)
321 if (glIsTexture(level_v[i].text))
322 glDeleteTextures(1, &level_v[i].text);
327 int level_exists(int i)
329 return (0 < i && i < count);
332 int level_opened(int i)
334 return level_exists(i) && (0 < i && i < count && i <= limit);
337 int level_locked(int i)
339 return level_opened(i) && (i == limit);
342 int level_extra_bonus(int i)
344 return level_exists(i) && (i > 20);
347 int level_extra_bonus_opened(void)
349 return level_opened(21);
352 int level_set_completed(void)
354 return limit >= count;
357 static const char * names[] = {"1", "2", "3", "4", "5",
358 "6", "7", "8", "9", "10",
359 "11", "12", "13", "14", "15",
360 "16", "17", "18", "19", "20",
361 N_("B1"), N_("B2"), N_("B3"), N_("B4"), N_("B5")};
363 const char * level_number_name(i)
364 /* Return the number name of the level i */
369 /*---------------------------------------------------------------------------*/
371 int curr_times_total(void) { return times_total; }
373 int curr_count(void) { return count; }
374 int curr_score(void) { return score; }
375 int curr_balls(void) { return balls; }
376 int curr_level(void) { return level; }
378 /*---------------------------------------------------------------------------*/
380 static int score_time_comp(const struct score *S, int i, int j)
382 if (S->time_t[i] < S->time_t[j])
385 if (S->time_t[i] == S->time_t[j] &&
386 S->time_c[i] > S->time_c[j])
392 static int score_coin_comp(const struct score *S, int i, int j)
394 if (S->coin_c[i] > S->coin_c[j])
397 if (S->coin_c[i] == S->coin_c[j] &&
398 S->coin_t[i] < S->coin_t[j])
404 /*---------------------------------------------------------------------------*/
406 static void score_time_swap(struct score *S, int i, int j)
412 strncpy(n, S->time_n[i], MAXNAM);
413 strncpy(S->time_n[i], S->time_n[j], MAXNAM);
414 strncpy(S->time_n[j], n, MAXNAM);
417 S->time_t[i] = S->time_t[j];
421 S->time_c[i] = S->time_c[j];
425 static void score_coin_swap(struct score *S, int i, int j)
431 strncpy(n, S->coin_n[i], MAXNAM);
432 strncpy(S->coin_n[i], S->coin_n[j], MAXNAM);
433 strncpy(S->coin_n[j], n, MAXNAM);
436 S->coin_t[i] = S->coin_t[j];
440 S->coin_c[i] = S->coin_c[j];
444 /*---------------------------------------------------------------------------*/
446 int level_replay(const char *filename)
448 return demo_replay_init(filename, &mode, &score, &balls, ×_total);
451 int level_play_go(void)
452 /* Start to play the current level */
456 goal = (mode == MODE_PRACTICE) ? 0 : level_v[level].goal;
457 time = (mode == MODE_PRACTICE) ? 0 : level_v[level].time;
459 return demo_play_init(USER_REPLAY_FILE,
467 score, balls, times_total);
470 void level_play(int i, int m)
471 /* Prepare to play a level sequence from the `i'th level */
481 /*---------------------------------------------------------------------------*/
483 int count_extra_balls(int old_score, int coins)
485 int modulo = old_score % 100;
486 int sum = modulo + coins;
490 void level_stop(int state)
491 /* Stop the current playing level */
496 coins = curr_coins();
498 /* open next level */
499 if (state == GAME_GOAL && mode != MODE_PRACTICE && limit < level+1)
500 if (level_extra_bonus_opened() || !level_extra_bonus(level+1) || mode == MODE_CHALLENGE)
503 if (mode == MODE_CHALLENGE)
506 times_total += level_v[level].time - curr_clock();
508 /* sum coins an earn extra balls */
509 if (state == GAME_GOAL)
511 balls += count_extra_balls(score, coins);
516 if (state == GAME_TIME || state == GAME_FALL)
520 /* stop demo recording */
521 time = (mode == MODE_PRACTICE) ? curr_clock() : level_v[level].time - curr_clock();
522 demo_play_stop(coins, time, state);
527 return (mode == MODE_CHALLENGE) && (balls <= 0);
532 return (level + 1 == count) || (level_extra_bonus(level + 1));
535 void level_next(void)
540 int level_sort(int *time_i, int *coin_i)
545 coins = curr_coins();
546 if (mode == MODE_PRACTICE)
547 clock = curr_clock();
549 clock = level_v[level].time - curr_clock();
551 config_get_s(CONFIG_PLAYER, player, MAXNAM);
553 /* Insert the time record into the high score list. */
555 strncpy(score_v[level].time_n[3], player, MAXNAM);
556 score_v[level].time_c[3] = coins;
557 score_v[level].time_t[3] = clock;
559 for (i = 2; i >= 0 && score_time_comp(score_v + level, i + 1, i); i--)
561 score_time_swap(score_v + level, i + 1, i);
565 /* Insert the coin record into the high score list. */
567 strncpy(score_v[level].coin_n[3], player, MAXNAM);
568 score_v[level].coin_c[3] = coins;
569 score_v[level].coin_t[3] = clock;
571 for (i = 2; i >= 0 && score_coin_comp(score_v + level, i + 1, i); i--)
573 score_coin_swap(score_v + level, i + 1, i);
577 return (*time_i < 3 || *coin_i < 3);
580 int level_done(int *time_i, int *coin_i)
585 config_get_s(CONFIG_PLAYER, player, MAXNAM);
587 /* Note a global high score. */
589 strncpy(score_v[0].time_n[3], player, MAXNAM);
590 score_v[0].time_c[3] = score;
591 score_v[0].time_t[3] = times_total;
593 strncpy(score_v[0].coin_n[3], player, MAXNAM);
594 score_v[0].coin_c[3] = score;
595 score_v[0].coin_t[3] = times_total;
597 /* Insert the time record into the global high score list. */
599 for (i = 2; i >= 0 && score_time_comp(score_v, i + 1, i); i--)
601 score_time_swap(score_v, i + 1, i);
605 /* Insert the coin record into the global high score list. */
607 for (i = 2; i >= 0 && score_coin_comp(score_v, i + 1, i); i--)
609 score_coin_swap(score_v, i + 1, i);
613 return (*time_i < 3 || *coin_i < 3);
616 /*---------------------------------------------------------------------------*/
618 void level_name(int i, const char *name, int time_i, int coin_i)
620 strncpy(score_v[i].time_n[time_i], name, MAXNAM);
621 strncpy(score_v[i].coin_n[coin_i], name, MAXNAM);
624 void level_snap(int i)
626 char filename[MAXSTR];
628 /* Convert the level name to a BMP filename. */
630 memset(filename, 0, MAXSTR);
631 strncpy(filename, level_v[i].file, strcspn(level_v[i].file, "."));
632 strcat(filename, ".bmp");
634 /* Initialize the game for a snapshot. */
636 if (game_init(level_v[i].file, level_v[i].back, level_v[i].grad, 0, 0))
638 /* Render the level and grab the screen. */
644 SDL_GL_SwapBuffers();
646 image_snap(filename, config_get_d(CONFIG_WIDTH), config_get_d(CONFIG_HEIGHT));
650 /*---------------------------------------------------------------------------*/