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 level_total
;
66 static int coins_total
;
67 static int times_total
;
69 static struct level level_v
[MAXLVL
];
70 static struct score score_v
[MAXLVL
];
72 static char scores_file
[MAXSTR
];
74 /*---------------------------------------------------------------------------*/
76 static void level_store_hs(const char *filename
)
80 if ((fout
= fopen(config_user(filename
), "w")))
85 for (i
= 0; i
< limit
; i
++)
86 for (j
= 0; j
< 3; j
++)
88 if (strlen(score_v
[i
].time_n
[j
]) == 0)
89 strcpy(score_v
[i
].time_n
[j
], DEFAULT_PLAYER
);
90 if (strlen(score_v
[i
].coin_n
[j
]) == 0)
91 strcpy(score_v
[i
].coin_n
[j
], DEFAULT_PLAYER
);
93 fprintf(fout
, "%d %d %s\n",
96 score_v
[i
].time_n
[j
]);
97 fprintf(fout
, "%d %d %s\n",
100 score_v
[i
].coin_n
[j
]);
107 static void level_load_hs(const char *filename
)
113 if ((fin
= fopen(config_user(filename
), "r")))
117 for (i
= 0; i
< count
; i
++)
119 if (fscanf(fin
, "%d %d %s",
120 &score_v
[i
].time_t[0],
121 &score_v
[i
].time_c
[0],
122 score_v
[i
].time_n
[0]) == 3 &&
123 fscanf(fin
, "%d %d %s",
124 &score_v
[i
].coin_t
[0],
125 &score_v
[i
].coin_c
[0],
126 score_v
[i
].coin_n
[0]) == 3 &&
127 fscanf(fin
, "%d %d %s",
128 &score_v
[i
].time_t[1],
129 &score_v
[i
].time_c
[1],
130 score_v
[i
].time_n
[1]) == 3 &&
131 fscanf(fin
, "%d %d %s",
132 &score_v
[i
].coin_t
[1],
133 &score_v
[i
].coin_c
[1],
134 score_v
[i
].coin_n
[1]) == 3 &&
135 fscanf(fin
, "%d %d %s",
136 &score_v
[i
].time_t[2],
137 &score_v
[i
].time_c
[2],
138 score_v
[i
].time_n
[2]) == 3 &&
139 fscanf(fin
, "%d %d %s",
140 &score_v
[i
].coin_t
[2],
141 &score_v
[i
].coin_c
[2],
142 score_v
[i
].coin_n
[2]) == 3)
150 /*---------------------------------------------------------------------------*/
152 static void level_init_rc(const char *filename
)
163 /* Load the levels list. */
165 if ((fin
= fopen(config_data(filename
), "r")))
167 while (count
< MAXLVL
&& fgets(buf
, MAXSTR
, fin
))
169 sscanf(buf
, "%s %s %s %s %d %d %s",
174 &level_v
[count
].time
,
175 &level_v
[count
].goal
,
176 level_v
[count
].song
);
183 static void level_init_hs(const char *filename
)
189 /* Set some sane values in case the scores file is missing. */
191 for (i
= 0; i
< MAXLVL
; i
++)
193 strcpy(score_v
[i
].time_n
[0], "Hard");
194 strcpy(score_v
[i
].time_n
[1], "Medium");
195 strcpy(score_v
[i
].time_n
[2], "Easy");
197 score_v
[i
].time_t[0] = i
? 59999 : 359999;
198 score_v
[i
].time_t[1] = i
? 59999 : 359999;
199 score_v
[i
].time_t[2] = i
? 59999 : 359999;
201 score_v
[i
].time_c
[0] = 0;
202 score_v
[i
].time_c
[1] = 0;
203 score_v
[i
].time_c
[2] = 0;
205 strcpy(score_v
[i
].coin_n
[0], "Hard");
206 strcpy(score_v
[i
].coin_n
[1], "Medium");
207 strcpy(score_v
[i
].coin_n
[2], "Easy");
209 score_v
[i
].coin_t
[0] = i
? 59999 : 359999;
210 score_v
[i
].coin_t
[1] = i
? 59999 : 359999;
211 score_v
[i
].coin_t
[2] = i
? 59999 : 359999;
213 score_v
[i
].coin_c
[0] = 0;
214 score_v
[i
].coin_c
[1] = 0;
215 score_v
[i
].coin_c
[2] = 0;
218 /* Load the default high scores file. */
220 if ((fin
= fopen(config_data(filename
), "r")))
222 for (i
= 0; i
< MAXLVL
&& fgets(buf
, MAXSTR
, fin
); i
++)
223 sscanf(buf
, "%d %d %d %d %d %d",
224 &score_v
[i
].time_t[0], &score_v
[i
].coin_c
[0],
225 &score_v
[i
].time_t[1], &score_v
[i
].coin_c
[1],
226 &score_v
[i
].time_t[2], &score_v
[i
].coin_c
[2]);
232 /*---------------------------------------------------------------------------*/
234 const char *level_shot(int i
)
236 return level_v
[i
].shot
;
239 const char *level_time_n(int i
, int j
)
241 return score_v
[i
].time_n
[j
];
244 const char *level_coin_n(int i
, int j
)
246 return score_v
[i
].coin_n
[j
];
249 /*---------------------------------------------------------------------------*/
250 /* Return the coin count for the Most Coins or Best Time score. */
252 int level_coin_c(int i
, int j
)
257 return score_v
[i
].coin_c
[j
];
260 int level_time_c(int i
, int j
)
262 return score_v
[i
].time_c
[j
];
265 /*---------------------------------------------------------------------------*/
266 /* Return the time for the Most Coins or Best Time score. */
268 int level_coin_t(int i
, int j
)
270 return score_v
[i
].coin_t
[j
];
273 int level_time_t(int i
, int j
)
276 return level_v
[i
].time
- curr_clock();
278 return score_v
[i
].time_t[j
];
281 /*---------------------------------------------------------------------------*/
283 void level_init(const char *init_levels
,
284 const char *init_scores
,
285 const char *user_scores
)
287 memset(level_v
, 0, sizeof (struct level
) * MAXLVL
);
288 memset(score_v
, 0, sizeof (struct score
) * MAXLVL
);
290 level_init_rc(init_levels
);
291 level_init_hs(init_scores
);
292 level_load_hs(user_scores
);
294 strncpy(scores_file
, user_scores
, MAXSTR
);
307 level_store_hs(user_scores
);
311 void level_free(void)
315 level_store_hs(scores_file
);
317 for (i
= 0; i
< count
; i
++)
318 if (glIsTexture(level_v
[i
].text
))
319 glDeleteTextures(1, &level_v
[i
].text
);
324 int level_exists(int i
)
326 return (0 < i
&& i
< count
);
329 int level_opened(int i
)
331 return level_exists(i
) && (0 < i
&& i
< count
&& i
<= limit
);
334 int level_locked(int i
)
336 return level_opened(i
) && (i
== limit
) && (level_v
[i
].goal
> 0);
339 /*---------------------------------------------------------------------------*/
341 int curr_times_total(void) { return times_total
; }
342 int curr_coins_total(void) { return coins_total
; }
344 int curr_count(void) { return count
; }
345 int curr_score(void) { return score
; }
346 int curr_coins(void) { return coins
; }
347 int curr_balls(void) { return balls
; }
348 int curr_level(void) { return level
; }
349 int curr_goal (void) { return goal
; }
351 /*---------------------------------------------------------------------------*/
353 static int score_time_comp(const struct score
*S
, int i
, int j
)
355 if (S
->time_t[i
] < S
->time_t[j
])
358 if (S
->time_t[i
] == S
->time_t[j
] &&
359 S
->time_c
[i
] > S
->time_c
[j
])
365 static int score_coin_comp(const struct score
*S
, int i
, int j
)
367 if (S
->coin_c
[i
] > S
->coin_c
[j
])
370 if (S
->coin_c
[i
] == S
->coin_c
[j
] &&
371 S
->coin_t
[i
] < S
->coin_t
[j
])
377 /*---------------------------------------------------------------------------*/
379 static void score_time_swap(struct score
*S
, int i
, int j
)
385 strncpy(n
, S
->time_n
[i
], MAXNAM
);
386 strncpy(S
->time_n
[i
], S
->time_n
[j
], MAXNAM
);
387 strncpy(S
->time_n
[j
], n
, MAXNAM
);
390 S
->time_t[i
] = S
->time_t[j
];
394 S
->time_c
[i
] = S
->time_c
[j
];
398 static void score_coin_swap(struct score
*S
, int i
, int j
)
404 strncpy(n
, S
->coin_n
[i
], MAXNAM
);
405 strncpy(S
->coin_n
[i
], S
->coin_n
[j
], MAXNAM
);
406 strncpy(S
->coin_n
[j
], n
, MAXNAM
);
409 S
->coin_t
[i
] = S
->coin_t
[j
];
413 S
->coin_c
[i
] = S
->coin_c
[j
];
417 /*---------------------------------------------------------------------------*/
419 int level_replay(const char *filename
)
423 return demo_replay_init(filename
, &score
, &coins
, &balls
, &goal
);
426 int level_play(const char *filename
, int i
)
433 goal
= (level
== limit
) ? level_v
[level
].goal
: 0;
435 return demo_play_init(USER_REPLAY_FILE
,
442 goal
, score
, coins
, balls
);
445 /*---------------------------------------------------------------------------*/
447 void level_stat(int s
)
449 if ((status
= s
) == GAME_GOAL
)
451 coins_total
+= coins
;
455 demo_play_stat(curr_coins(), level_v
[level
].time
- curr_clock());
465 return (level
+ 1 == count
);
468 int level_exit(const char *filename
, int next
)
470 times_total
+= level_v
[level
].time
- curr_clock();
472 demo_play_stop(filename
);
481 level_store_hs(scores_file
);
490 /* Load the next level. */
492 if (status
&& level
< count
&& balls
>= 0)
494 goal
= (level
== limit
) ? level_v
[level
].goal
: 0;
498 return demo_play_init(USER_REPLAY_FILE
,
505 goal
, score
, coins
, balls
);
511 int level_sort(int *time_i
, int *coin_i
)
513 int i
, clock
= level_v
[level
].time
- curr_clock();
516 config_get_s(CONFIG_PLAYER
, player
, MAXNAM
);
518 /* Insert the time record into the high score list. */
520 strncpy(score_v
[level
].time_n
[3], player
, MAXNAM
);
521 score_v
[level
].time_c
[3] = coins
;
522 score_v
[level
].time_t[3] = clock
;
524 for (i
= 2; i
>= 0 && score_time_comp(score_v
+ level
, i
+ 1, i
); i
--)
526 score_time_swap(score_v
+ level
, i
+ 1, i
);
530 /* Insert the coin record into the high score list. */
532 strncpy(score_v
[level
].coin_n
[3], player
, MAXNAM
);
533 score_v
[level
].coin_c
[3] = coins
;
534 score_v
[level
].coin_t
[3] = clock
;
536 for (i
= 2; i
>= 0 && score_coin_comp(score_v
+ level
, i
+ 1, i
); i
--)
538 score_coin_swap(score_v
+ level
, i
+ 1, i
);
542 return (*time_i
< 3 || *coin_i
< 3);
545 int level_done(int *time_i
, int *coin_i
)
550 config_get_s(CONFIG_PLAYER
, player
, MAXNAM
);
552 /* Note a global high score. */
554 strncpy(score_v
[0].time_n
[3], player
, MAXNAM
);
555 score_v
[0].time_c
[3] = coins_total
;
556 score_v
[0].time_t[3] = times_total
;
558 strncpy(score_v
[0].coin_n
[3], player
, MAXNAM
);
559 score_v
[0].coin_c
[3] = coins_total
;
560 score_v
[0].coin_t
[3] = times_total
;
562 if (level
== count
&& level_total
== count
- 1)
564 /* Insert the time record into the global high score list. */
566 for (i
= 2; i
>= 0 && score_time_comp(score_v
, i
+ 1, i
); i
--)
568 score_time_swap(score_v
, i
+ 1, i
);
572 /* Insert the coin record into the global high score list. */
574 for (i
= 2; i
>= 0 && score_coin_comp(score_v
, i
+ 1, i
); i
--)
576 score_coin_swap(score_v
, i
+ 1, i
);
581 return (*time_i
< 3 || *coin_i
< 3);
584 int level_score(int n
)
586 int sound
= AUD_COIN
;
591 /* Pulse the coin counter based on the value of the grabbed coin. */
593 if (n
>= 10) hud_coin_pulse(2.00f
);
594 else if (n
>= 5) hud_coin_pulse(1.50f
);
595 else hud_coin_pulse(1.25f
);
597 /* Check for goal open. */
601 if (n
>= 10) hud_goal_pulse(2.00f
);
602 else if (n
>= 5) hud_goal_pulse(1.50f
);
603 else hud_goal_pulse(1.25f
);
609 hud_goal_pulse(2.0f
);
612 goal
= (goal
> n
) ? (goal
- n
) : 0;
615 audio_play(sound
, 1.f
);
619 int level_count(void)
626 if (score
% 100 == 0)
629 audio_play(AUD_BALL
, 1.0f
);
636 /*---------------------------------------------------------------------------*/
638 void level_name(int i
, const char *name
, int time_i
, int coin_i
)
640 strncpy(score_v
[i
].time_n
[time_i
], name
, MAXNAM
);
641 strncpy(score_v
[i
].coin_n
[coin_i
], name
, MAXNAM
);
644 void level_snap(int i
)
646 char filename
[MAXSTR
];
648 /* Convert the level name to a BMP filename. */
650 memset(filename
, 0, MAXSTR
);
651 strncpy(filename
, level_v
[i
].file
, strcspn(level_v
[i
].file
, "."));
652 strcat(filename
, ".bmp");
654 /* Initialize the game for a snapshot. */
656 if (game_init(level_v
[i
].file
, level_v
[i
].back
, level_v
[i
].grad
, 0, 1))
658 /* Render the level and grab the screen. */
664 SDL_GL_SwapBuffers();
666 image_snap(filename
);