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.
29 /*---------------------------------------------------------------------------*/
33 char time_n[4][MAXNAM];
37 char coin_n[4][MAXNAM];
55 static int score; /* Current coin total */
56 static int coins; /* Current coin count */
57 static int balls; /* Current life count */
58 static int goal; /* Current goal count */
60 static int level; /* Current level number */
61 static int count; /* Number of levels */
62 static int limit; /* Last opened (locked) level */
63 static int status; /* Status of current level */
65 static int mode; /* Current play mode */
67 static int coins_total;
68 static int times_total;
70 static struct level level_v[MAXLVL];
71 static struct score score_v[MAXLVL];
73 static char scores_file[MAXSTR];
75 /*---------------------------------------------------------------------------*/
77 static void level_store_hs(const char *filename)
81 if ((fout = fopen(config_user(filename), "w")))
86 for (i = 0; i < limit; i++)
87 for (j = 0; j < 3; j++)
89 if (strlen(score_v[i].time_n[j]) == 0)
90 strcpy(score_v[i].time_n[j], DEFAULT_PLAYER);
91 if (strlen(score_v[i].coin_n[j]) == 0)
92 strcpy(score_v[i].coin_n[j], DEFAULT_PLAYER);
94 fprintf(fout, "%d %d %s\n",
97 score_v[i].time_n[j]);
98 fprintf(fout, "%d %d %s\n",
100 score_v[i].coin_c[j],
101 score_v[i].coin_n[j]);
108 static void level_load_hs(const char *filename)
114 if ((fin = fopen(config_user(filename), "r")))
118 for (i = 0; i < count; i++)
120 if (fscanf(fin, "%d %d %s",
121 &score_v[i].time_t[0],
122 &score_v[i].time_c[0],
123 score_v[i].time_n[0]) == 3 &&
124 fscanf(fin, "%d %d %s",
125 &score_v[i].coin_t[0],
126 &score_v[i].coin_c[0],
127 score_v[i].coin_n[0]) == 3 &&
128 fscanf(fin, "%d %d %s",
129 &score_v[i].time_t[1],
130 &score_v[i].time_c[1],
131 score_v[i].time_n[1]) == 3 &&
132 fscanf(fin, "%d %d %s",
133 &score_v[i].coin_t[1],
134 &score_v[i].coin_c[1],
135 score_v[i].coin_n[1]) == 3 &&
136 fscanf(fin, "%d %d %s",
137 &score_v[i].time_t[2],
138 &score_v[i].time_c[2],
139 score_v[i].time_n[2]) == 3 &&
140 fscanf(fin, "%d %d %s",
141 &score_v[i].coin_t[2],
142 &score_v[i].coin_c[2],
143 score_v[i].coin_n[2]) == 3)
151 /*---------------------------------------------------------------------------*/
153 static void level_init_rc(const char *filename)
164 /* Load the levels list. */
166 if ((fin = fopen(config_data(filename), "r")))
168 while (count < MAXLVL && fgets(buf, MAXSTR, fin))
170 sscanf(buf, "%s %s %s %s %d %d %s",
175 &level_v[count].time,
176 &level_v[count].goal,
177 level_v[count].song);
184 static void level_init_hs(const char *filename)
190 /* Set some sane values in case the scores file is missing. */
192 for (i = 0; i < MAXLVL; i++)
194 strcpy(score_v[i].time_n[0], "Hard");
195 strcpy(score_v[i].time_n[1], "Medium");
196 strcpy(score_v[i].time_n[2], "Easy");
198 score_v[i].time_t[0] = i ? 59999 : 359999;
199 score_v[i].time_t[1] = i ? 59999 : 359999;
200 score_v[i].time_t[2] = i ? 59999 : 359999;
202 score_v[i].time_c[0] = 0;
203 score_v[i].time_c[1] = 0;
204 score_v[i].time_c[2] = 0;
206 strcpy(score_v[i].coin_n[0], "Hard");
207 strcpy(score_v[i].coin_n[1], "Medium");
208 strcpy(score_v[i].coin_n[2], "Easy");
210 score_v[i].coin_t[0] = i ? 59999 : 359999;
211 score_v[i].coin_t[1] = i ? 59999 : 359999;
212 score_v[i].coin_t[2] = i ? 59999 : 359999;
214 score_v[i].coin_c[0] = 0;
215 score_v[i].coin_c[1] = 0;
216 score_v[i].coin_c[2] = 0;
219 /* Load the default high scores file. */
221 if ((fin = fopen(config_data(filename), "r")))
223 for (i = 0; i < MAXLVL && fgets(buf, MAXSTR, fin); i++)
224 sscanf(buf, "%d %d %d %d %d %d",
225 &score_v[i].time_t[0], &score_v[i].coin_c[0],
226 &score_v[i].time_t[1], &score_v[i].coin_c[1],
227 &score_v[i].time_t[2], &score_v[i].coin_c[2]);
233 /*---------------------------------------------------------------------------*/
235 const char *level_shot(int i)
237 return level_v[i].shot;
240 const char *level_time_n(int i, int j)
242 return score_v[i].time_n[j];
245 const char *level_coin_n(int i, int j)
247 return score_v[i].coin_n[j];
250 /*---------------------------------------------------------------------------*/
251 /* Return the coin count for the Most Coins or Best Time score. */
253 int level_coin_c(int i, int j)
258 return score_v[i].coin_c[j];
261 int level_time_c(int i, int j)
263 return score_v[i].time_c[j];
266 /*---------------------------------------------------------------------------*/
267 /* Return the time for the Most Coins or Best Time score. */
269 int level_coin_t(int i, int j)
271 return score_v[i].coin_t[j];
274 int level_time_t(int i, int j)
277 return level_v[i].time - curr_clock();
279 return score_v[i].time_t[j];
282 /*---------------------------------------------------------------------------*/
284 void level_init(const char *init_levels,
285 const char *init_scores,
286 const char *user_scores)
288 memset(level_v, 0, sizeof (struct level) * MAXLVL);
289 memset(score_v, 0, sizeof (struct score) * MAXLVL);
291 level_init_rc(init_levels);
292 level_init_hs(init_scores);
293 level_load_hs(user_scores);
295 strncpy(scores_file, user_scores, MAXSTR);
301 void level_cheat(void)
302 /* Open each level of the set */
307 void level_free(void)
311 level_store_hs(scores_file);
313 for (i = 0; i < count; i++)
314 if (glIsTexture(level_v[i].text))
315 glDeleteTextures(1, &level_v[i].text);
320 int level_exists(int i)
322 return (0 < i && i < count);
325 int level_opened(int i)
327 return level_exists(i) && (0 < i && i < count && i <= limit);
330 int level_locked(int i)
332 return level_opened(i) && (i == limit) && (level_v[i].goal > 0);
335 /*---------------------------------------------------------------------------*/
337 int curr_times_total(void) { return times_total; }
338 int curr_coins_total(void) { return coins_total; }
340 int curr_count(void) { return count; }
341 int curr_score(void) { return score; }
342 int curr_coins(void) { return coins; }
343 int curr_balls(void) { return balls; }
344 int curr_level(void) { return level; }
345 int curr_goal (void) { return goal; }
347 /*---------------------------------------------------------------------------*/
349 static int score_time_comp(const struct score *S, int i, int j)
351 if (S->time_t[i] < S->time_t[j])
354 if (S->time_t[i] == S->time_t[j] &&
355 S->time_c[i] > S->time_c[j])
361 static int score_coin_comp(const struct score *S, int i, int j)
363 if (S->coin_c[i] > S->coin_c[j])
366 if (S->coin_c[i] == S->coin_c[j] &&
367 S->coin_t[i] < S->coin_t[j])
373 /*---------------------------------------------------------------------------*/
375 static void score_time_swap(struct score *S, int i, int j)
381 strncpy(n, S->time_n[i], MAXNAM);
382 strncpy(S->time_n[i], S->time_n[j], MAXNAM);
383 strncpy(S->time_n[j], n, MAXNAM);
386 S->time_t[i] = S->time_t[j];
390 S->time_c[i] = S->time_c[j];
394 static void score_coin_swap(struct score *S, int i, int j)
400 strncpy(n, S->coin_n[i], MAXNAM);
401 strncpy(S->coin_n[i], S->coin_n[j], MAXNAM);
402 strncpy(S->coin_n[j], n, MAXNAM);
405 S->coin_t[i] = S->coin_t[j];
409 S->coin_c[i] = S->coin_c[j];
413 /*---------------------------------------------------------------------------*/
415 int level_replay(const char *filename)
419 return demo_replay_init(filename, &score, &coins, &balls, &goal);
422 static int level_play_go(void)
423 /* Start to play the current level */
427 goal = level_v[level].goal;
429 return demo_play_init(USER_REPLAY_FILE,
436 level_auto_opened() ? 0 : goal, score, coins, balls);
439 int level_play(const char *filename, int i, int m)
440 /* Start to play a level sequence from the `i'th level */
450 return level_play_go();
453 /*---------------------------------------------------------------------------*/
455 void level_stat(int s)
457 if ((status = s) == GAME_GOAL)
459 coins_total += coins;
462 demo_play_stat(curr_coins(), level_v[level].time - curr_clock());
472 return (level + 1 == count);
475 int level_auto_opened(void)
476 /* Is the level automatically opened */
478 return mode != MODE_CHALLENGE && level != limit;
481 int level_exit(const char *filename, int next)
483 times_total += level_v[level].time - curr_clock();
485 demo_play_stop(filename);
494 level_store_hs(scores_file);
500 if (mode == MODE_CHALLENGE)
505 /* Load the next level. */
507 if (status && level < count && balls >= 0)
508 return level_play_go();
513 int level_sort(int *time_i, int *coin_i)
515 int i, clock = level_v[level].time - curr_clock();
518 config_get_s(CONFIG_PLAYER, player, MAXNAM);
520 /* Insert the time record into the high score list. */
522 strncpy(score_v[level].time_n[3], player, MAXNAM);
523 score_v[level].time_c[3] = coins;
524 score_v[level].time_t[3] = clock;
526 for (i = 2; i >= 0 && score_time_comp(score_v + level, i + 1, i); i--)
528 score_time_swap(score_v + level, i + 1, i);
532 /* Insert the coin record into the high score list. */
534 strncpy(score_v[level].coin_n[3], player, MAXNAM);
535 score_v[level].coin_c[3] = coins;
536 score_v[level].coin_t[3] = clock;
538 for (i = 2; i >= 0 && score_coin_comp(score_v + level, i + 1, i); i--)
540 score_coin_swap(score_v + level, i + 1, i);
544 return (*time_i < 3 || *coin_i < 3);
547 int level_done(int *time_i, int *coin_i)
552 config_get_s(CONFIG_PLAYER, player, MAXNAM);
554 /* Note a global high score. */
556 strncpy(score_v[0].time_n[3], player, MAXNAM);
557 score_v[0].time_c[3] = coins_total;
558 score_v[0].time_t[3] = times_total;
560 strncpy(score_v[0].coin_n[3], player, MAXNAM);
561 score_v[0].coin_c[3] = coins_total;
562 score_v[0].coin_t[3] = times_total;
566 /* Insert the time record into the global high score list. */
568 for (i = 2; i >= 0 && score_time_comp(score_v, i + 1, i); i--)
570 score_time_swap(score_v, i + 1, i);
574 /* Insert the coin record into the global high score list. */
576 for (i = 2; i >= 0 && score_coin_comp(score_v, i + 1, i); i--)
578 score_coin_swap(score_v, i + 1, i);
583 return (*time_i < 3 || *coin_i < 3);
586 int level_score(int n)
588 int sound = AUD_COIN;
589 int value = level_auto_opened();
593 /* Pulse the coin counter based on the value of the grabbed coin. */
595 if (n >= 10) hud_coin_pulse(2.00f);
596 else if (n >= 5) hud_coin_pulse(1.50f);
597 else hud_coin_pulse(1.25f);
599 /* Check for goal open. */
603 if (n >= 10) hud_goal_pulse(2.00f);
604 else if (n >= 5) hud_goal_pulse(1.50f);
605 else hud_goal_pulse(1.25f);
611 hud_goal_pulse(2.0f);
614 goal = (goal > n) ? (goal - n) : 0;
617 audio_play(sound, 1.f);
621 int level_count(void)
623 if (mode != MODE_CHALLENGE)
630 if (score % 100 == 0)
633 audio_play(AUD_BALL, 1.0f);
640 /*---------------------------------------------------------------------------*/
642 void level_name(int i, const char *name, int time_i, int coin_i)
644 strncpy(score_v[i].time_n[time_i], name, MAXNAM);
645 strncpy(score_v[i].coin_n[coin_i], name, MAXNAM);
648 void level_snap(int i)
650 char filename[MAXSTR];
652 /* Convert the level name to a BMP filename. */
654 memset(filename, 0, MAXSTR);
655 strncpy(filename, level_v[i].file, strcspn(level_v[i].file, "."));
656 strcat(filename, ".bmp");
658 /* Initialize the game for a snapshot. */
660 if (game_init(level_v[i].file, level_v[i].back, level_v[i].grad, 0, 1))
662 /* Render the level and grab the screen. */
668 SDL_GL_SwapBuffers();
670 image_snap(filename);
674 /*---------------------------------------------------------------------------*/