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];
41 static int score; /* Current coin total */
42 static int balls; /* Current life count */
44 static int level; /* Current level number */
45 static int count; /* Number of levels */
46 static int limit; /* Last opened (locked) level */
48 static int mode; /* Current play mode */
50 static int times_total;
52 static struct level level_v[MAXLVL];
53 static struct score score_v[MAXLVL];
55 static char scores_file[MAXSTR];
57 /*---------------------------------------------------------------------------*/
59 const char * mode_to_str(int m)
63 case MODE_CHALLENGE: return _("Challenge");
64 case MODE_NORMAL: return _("Normal");
65 case MODE_PRACTICE: return _("Practice");
66 case MODE_SINGLE: return _("Single");
67 default: return "???";
71 /*---------------------------------------------------------------------------*/
73 static void level_store_hs(const char *filename)
77 if ((fout = fopen(config_user(filename), "w")))
82 for (i = 0; i < limit; i++)
83 for (j = 0; j < 3; j++)
85 if (strlen(score_v[i].time_n[j]) == 0)
86 strcpy(score_v[i].time_n[j], DEFAULT_PLAYER);
87 if (strlen(score_v[i].coin_n[j]) == 0)
88 strcpy(score_v[i].coin_n[j], DEFAULT_PLAYER);
90 fprintf(fout, "%d %d %s\n",
93 score_v[i].time_n[j]);
94 fprintf(fout, "%d %d %s\n",
97 score_v[i].coin_n[j]);
104 static void level_load_hs(const char *filename)
110 if ((fin = fopen(config_user(filename), "r")))
114 for (i = 0; i < count; i++)
116 if (fscanf(fin, "%d %d %s",
117 &score_v[i].time_t[0],
118 &score_v[i].time_c[0],
119 score_v[i].time_n[0]) == 3 &&
120 fscanf(fin, "%d %d %s",
121 &score_v[i].coin_t[0],
122 &score_v[i].coin_c[0],
123 score_v[i].coin_n[0]) == 3 &&
124 fscanf(fin, "%d %d %s",
125 &score_v[i].time_t[1],
126 &score_v[i].time_c[1],
127 score_v[i].time_n[1]) == 3 &&
128 fscanf(fin, "%d %d %s",
129 &score_v[i].coin_t[1],
130 &score_v[i].coin_c[1],
131 score_v[i].coin_n[1]) == 3 &&
132 fscanf(fin, "%d %d %s",
133 &score_v[i].time_t[2],
134 &score_v[i].time_c[2],
135 score_v[i].time_n[2]) == 3 &&
136 fscanf(fin, "%d %d %s",
137 &score_v[i].coin_t[2],
138 &score_v[i].coin_c[2],
139 score_v[i].coin_n[2]) == 3)
147 /*---------------------------------------------------------------------------*/
149 static void level_init_rc(const char *filename)
160 /* Load the levels list. */
162 if ((fin = fopen(config_data(filename), "r")))
164 while (count < MAXLVL && fgets(buf, MAXSTR, fin))
166 sscanf(buf, "%s %s %s %s %d %d %s",
171 &level_v[count].time,
172 &level_v[count].goal,
173 level_v[count].song);
174 level_load(config_data(name), &level_v[count]);
181 static void level_init_hs(const char *filename)
187 /* Set some sane values in case the scores file is missing. */
189 for (i = 0; i < MAXLVL; i++)
191 strcpy(score_v[i].time_n[0], "Hard");
192 strcpy(score_v[i].time_n[1], "Medium");
193 strcpy(score_v[i].time_n[2], "Easy");
195 score_v[i].time_t[0] = i ? 59999 : 359999;
196 score_v[i].time_t[1] = i ? 59999 : 359999;
197 score_v[i].time_t[2] = i ? 59999 : 359999;
199 score_v[i].time_c[0] = 0;
200 score_v[i].time_c[1] = 0;
201 score_v[i].time_c[2] = 0;
203 strcpy(score_v[i].coin_n[0], "Hard");
204 strcpy(score_v[i].coin_n[1], "Medium");
205 strcpy(score_v[i].coin_n[2], "Easy");
207 score_v[i].coin_t[0] = i ? 59999 : 359999;
208 score_v[i].coin_t[1] = i ? 59999 : 359999;
209 score_v[i].coin_t[2] = i ? 59999 : 359999;
211 score_v[i].coin_c[0] = 0;
212 score_v[i].coin_c[1] = 0;
213 score_v[i].coin_c[2] = 0;
216 /* Load the default high scores file. */
218 if ((fin = fopen(config_data(filename), "r")))
220 for (i = 0; i < MAXLVL && fgets(buf, MAXSTR, fin); i++)
221 sscanf(buf, "%d %d %d %d %d %d",
222 &score_v[i].time_t[0], &score_v[i].coin_c[0],
223 &score_v[i].time_t[1], &score_v[i].coin_c[1],
224 &score_v[i].time_t[2], &score_v[i].coin_c[2]);
230 /*---------------------------------------------------------------------------*/
232 const char *level_shot(int i)
234 return level_v[i].shot;
237 const char *level_time_n(int i, int j)
239 return score_v[i].time_n[j];
242 const char *level_coin_n(int i, int j)
244 return score_v[i].coin_n[j];
247 /*---------------------------------------------------------------------------*/
248 /* Return the coin count for the Most Coins or Best Time score. */
250 int level_coin_c(int i, int j)
255 return score_v[i].coin_c[j];
258 int level_time_c(int i, int j)
260 return score_v[i].time_c[j];
263 /*---------------------------------------------------------------------------*/
264 /* Return the time for the Most Coins or Best Time score. */
266 int level_coin_t(int i, int j)
268 return score_v[i].coin_t[j];
271 int level_time_t(int i, int j)
274 return level_v[i].time - curr_clock();
276 return score_v[i].time_t[j];
279 /*---------------------------------------------------------------------------*/
281 void level_init(const char *init_levels,
282 const char *init_scores,
283 const char *user_scores)
285 memset(level_v, 0, sizeof (struct level) * MAXLVL);
286 memset(score_v, 0, sizeof (struct score) * MAXLVL);
288 level_init_rc(init_levels);
289 level_init_hs(init_scores);
290 level_load_hs(user_scores);
292 strncpy(scores_file, user_scores, MAXSTR);
298 void level_cheat(void)
299 /* Open each level of the set */
304 void level_free(void)
306 level_store_hs(scores_file);
310 int level_exists(int i)
312 return (0 < i && i < count);
315 int level_opened(int i)
317 return level_exists(i) && (0 < i && i < count && i <= limit);
320 int level_locked(int i)
322 return level_opened(i) && (i == limit);
325 int level_extra_bonus(int i)
327 return level_exists(i) && (i > 20);
330 int level_extra_bonus_opened(void)
332 return level_opened(21);
335 int level_set_completed(void)
337 return limit >= count;
340 static const char * names[] = {"1", "2", "3", "4", "5",
341 "6", "7", "8", "9", "10",
342 "11", "12", "13", "14", "15",
343 "16", "17", "18", "19", "20",
344 N_("B1"), N_("B2"), N_("B3"), N_("B4"), N_("B5")};
346 const char * level_number_name(i)
347 /* Return the number name of the level i */
352 /*---------------------------------------------------------------------------*/
354 int curr_times_total(void) { return times_total; }
356 int curr_count(void) { return count; }
357 int curr_score(void) { return score; }
358 int curr_balls(void) { return balls; }
359 int curr_level(void) { return level; }
361 /*---------------------------------------------------------------------------*/
363 static int score_time_comp(const struct score *S, int i, int j)
365 if (S->time_t[i] < S->time_t[j])
368 if (S->time_t[i] == S->time_t[j] &&
369 S->time_c[i] > S->time_c[j])
375 static int score_coin_comp(const struct score *S, int i, int j)
377 if (S->coin_c[i] > S->coin_c[j])
380 if (S->coin_c[i] == S->coin_c[j] &&
381 S->coin_t[i] < S->coin_t[j])
387 /*---------------------------------------------------------------------------*/
389 static void score_time_swap(struct score *S, int i, int j)
395 strncpy(n, S->time_n[i], MAXNAM);
396 strncpy(S->time_n[i], S->time_n[j], MAXNAM);
397 strncpy(S->time_n[j], n, MAXNAM);
400 S->time_t[i] = S->time_t[j];
404 S->time_c[i] = S->time_c[j];
408 static void score_coin_swap(struct score *S, int i, int j)
414 strncpy(n, S->coin_n[i], MAXNAM);
415 strncpy(S->coin_n[i], S->coin_n[j], MAXNAM);
416 strncpy(S->coin_n[j], n, MAXNAM);
419 S->coin_t[i] = S->coin_t[j];
423 S->coin_c[i] = S->coin_c[j];
427 /*---------------------------------------------------------------------------*/
429 int level_replay(const char *filename)
431 return demo_replay_init(filename, &mode, &score, &balls, ×_total);
435 int level_play_go(void)
436 /* Start to play the current level */
440 goal = (mode == MODE_PRACTICE) ? 0 : level_v[level].goal;
441 time = (mode == MODE_PRACTICE) ? 0 : level_v[level].time;
443 return demo_play_init(USER_REPLAY_FILE, &level_v[level], mode,
444 time, goal, score, balls, times_total);
447 void level_play_single(const char *filename)
448 /* Prepare to play a single level */
450 level_init("", "", "");
454 strncpy(level_v[0].file, filename, MAXSTR);
455 level_v[level].back[0] = '\0';
456 level_v[level].grad[0] = '\0';
457 level_v[level].song[0] = '\0';
458 level_v[level].shot[0] = '\0';
459 level_v[level].goal = 0;
460 level_v[level].time = 0;
463 void level_play(int i, int m)
464 /* Prepare to play a level sequence from the `i'th level */
474 /*---------------------------------------------------------------------------*/
476 int count_extra_balls(int old_score, int coins)
478 int modulo = old_score % 100;
479 int sum = modulo + coins;
483 void level_stop(int state)
484 /* Stop the current playing level */
489 coins = curr_coins();
491 /* open next level */
492 if (state == GAME_GOAL && mode != MODE_PRACTICE && mode != MODE_SINGLE && limit < level+1)
493 if (level_extra_bonus_opened() || !level_extra_bonus(level+1) || mode == MODE_CHALLENGE)
496 if (mode == MODE_CHALLENGE)
499 times_total += level_v[level].time - curr_clock();
501 /* sum coins an earn extra balls */
502 if (state == GAME_GOAL)
504 balls += count_extra_balls(score, coins);
509 if (state == GAME_TIME || state == GAME_FALL)
513 /* stop demo recording */
514 time = (mode == MODE_PRACTICE || mode == MODE_SINGLE) ? curr_clock() : level_v[level].time - curr_clock();
515 demo_play_stop(coins, time, state);
520 return (mode == MODE_CHALLENGE) && (balls <= 0);
525 return (level + 1 == count) || (level_extra_bonus(level + 1));
528 void level_next(void)
533 int level_sort(int *time_i, int *coin_i)
538 coins = curr_coins();
539 if (mode == MODE_PRACTICE || mode == MODE_SINGLE)
540 clock = curr_clock();
542 clock = level_v[level].time - curr_clock();
544 config_get_s(CONFIG_PLAYER, player, MAXNAM);
546 /* Insert the time record into the high score list. */
548 strncpy(score_v[level].time_n[3], player, MAXNAM);
549 score_v[level].time_c[3] = coins;
550 score_v[level].time_t[3] = clock;
552 for (i = 2; i >= 0 && score_time_comp(score_v + level, i + 1, i); i--)
554 score_time_swap(score_v + level, i + 1, i);
558 /* Insert the coin record into the high score list. */
560 strncpy(score_v[level].coin_n[3], player, MAXNAM);
561 score_v[level].coin_c[3] = coins;
562 score_v[level].coin_t[3] = clock;
564 for (i = 2; i >= 0 && score_coin_comp(score_v + level, i + 1, i); i--)
566 score_coin_swap(score_v + level, i + 1, i);
570 return (*time_i < 3 || *coin_i < 3);
573 int level_done(int *time_i, int *coin_i)
578 config_get_s(CONFIG_PLAYER, player, MAXNAM);
580 /* Note a global high score. */
582 strncpy(score_v[0].time_n[3], player, MAXNAM);
583 score_v[0].time_c[3] = score;
584 score_v[0].time_t[3] = times_total;
586 strncpy(score_v[0].coin_n[3], player, MAXNAM);
587 score_v[0].coin_c[3] = score;
588 score_v[0].coin_t[3] = times_total;
590 /* Insert the time record into the global high score list. */
592 for (i = 2; i >= 0 && score_time_comp(score_v, i + 1, i); i--)
594 score_time_swap(score_v, i + 1, i);
598 /* Insert the coin record into the global high score list. */
600 for (i = 2; i >= 0 && score_coin_comp(score_v, i + 1, i); i--)
602 score_coin_swap(score_v, i + 1, i);
606 return (*time_i < 3 || *coin_i < 3);
609 /*---------------------------------------------------------------------------*/
611 void level_name(int i, const char *name, int time_i, int coin_i)
613 strncpy(score_v[i].time_n[time_i], name, MAXNAM);
614 strncpy(score_v[i].coin_n[coin_i], name, MAXNAM);
617 void level_snap(int i)
619 char filename[MAXSTR];
621 /* Convert the level name to a BMP filename. */
623 memset(filename, 0, MAXSTR);
624 strncpy(filename, level_v[i].file, strcspn(level_v[i].file, "."));
625 strcat(filename, ".bmp");
627 /* Initialize the game for a snapshot. */
629 if (game_init(&level_v[i], 0, 0))
631 /* Render the level and grab the screen. */
637 SDL_GL_SwapBuffers();
639 image_snap(filename, config_get_d(CONFIG_WIDTH), config_get_d(CONFIG_HEIGHT));
643 /*---------------------------------------------------------------------------*/