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.
32 /*---------------------------------------------------------------------------*/
34 #define MAGIC 0x4E425251
35 #define DEMO_FPS_CAP 200 /* FPS replay limit, keeps size down on monster systems */
39 static char name[MAXDEMO][MAXNAM];
40 static char shot[MAXDEMO][PATHMAX];
41 static int score[MAXDEMO];
42 static int timer[MAXDEMO];
45 /*---------------------------------------------------------------------------*/
56 /* Scan the user directory for files. */
58 if ((h = FindFirstFile(config_user("*"), &d)) != INVALID_HANDLE_VALUE)
61 if ((fp = fopen(config_user(d.cFileName), FMODE_RB)))
66 /* Note the name and screen shot of each replay file. */
68 get_index(fp, &magic);
72 if (magic == MAGIC && t)
74 fread(shot[count], 1, PATHMAX, fp);
77 strncpy(name[count], d.cFileName, MAXNAM);
82 while (count < MAXDEMO && FindNextFile(h, &d));
100 /* Scan the user directory for files. */
102 if ((dp = opendir(config_user(""))))
104 while (count < MAXDEMO && (ent = readdir(dp)))
105 if ((fp = fopen(config_user(ent->d_name), FMODE_RB)))
110 /* Note the name and screen shot of each replay file. */
112 get_index(fp, &magic);
116 if (magic == MAGIC && t)
118 fread(shot[count], 1, PATHMAX, fp);
121 strncpy(name[count], ent->d_name, MAXNAM);
133 const char *demo_pick(void)
137 return (n > 0) ? name[(rand() >> 4) % n] : NULL;
140 const char *demo_name(int i)
142 return (0 <= i && i < count) ? name[i] : NULL;
145 const char *demo_shot(int i)
147 return (0 <= i && i < count) ? shot[i] : NULL;
150 int demo_coins(int i)
152 return (0 <= i && i < count) ? score[i] : 0;
155 int demo_clock(int i)
157 return (0 <= i && i < count) ? timer[i] : 0;
160 /*---------------------------------------------------------------------------*/
162 int demo_exists(char *name)
166 if ((fp = fopen(config_user(name), "r")))
174 void demo_unique(char *name)
178 /* Generate a unique name for a new replay save. */
180 for (i = 1; i < 100; i++)
182 sprintf(name, _("replay%02d"), i);
184 if (!demo_exists(name))
189 /*---------------------------------------------------------------------------*/
191 int demo_play_init(const char *name,
197 int t, int g, int s, int c, int b)
207 /* Initialize the replay file. Write the header. */
209 if (name && (demo_fp = fopen(config_user(name), FMODE_WB)))
211 put_index(demo_fp, &magic);
212 put_index(demo_fp, &zero);
213 put_index(demo_fp, &zero);
215 fwrite(shot, 1, PATHMAX, demo_fp);
216 fwrite(file, 1, PATHMAX, demo_fp);
217 fwrite(back, 1, PATHMAX, demo_fp);
218 fwrite(grad, 1, PATHMAX, demo_fp);
219 fwrite(song, 1, PATHMAX, demo_fp);
221 put_index(demo_fp, &st);
222 put_index(demo_fp, &sg);
223 put_index(demo_fp, &ss);
224 put_index(demo_fp, &sc);
225 put_index(demo_fp, &sb);
227 audio_music_fade_to(2.0f, song);
229 return game_init(file, back, grad, t, (g == 0));
234 void demo_play_step(float dt)
236 static float fps_track = 0.0f;
237 static float fps_cap = 1.0f / (float) DEMO_FPS_CAP;
242 if (fps_track > fps_cap)
244 put_float(demo_fp, &fps_track);
245 put_game_state(demo_fp);
251 void demo_play_stat(int coins, int timer)
258 /* Update the demo header using the final score and time. */
260 fseek(demo_fp, 4, SEEK_SET);
262 put_index(demo_fp, &t);
263 put_index(demo_fp, &c);
265 fseek(demo_fp, 0, SEEK_END);
269 void demo_play_stop(const char *name)
279 /* Rename the temporary replay file to its given name. */
283 strncpy(src, config_user(USER_REPLAY_FILE), PATHMAX);
284 strncpy(dst, config_user(name), PATHMAX);
291 /*---------------------------------------------------------------------------*/
293 static char demo_replay_name[MAXSTR];
295 int demo_replay_init(const char *name, int *s, int *c, int *b, int *g)
311 if ((demo_fp = fopen(config_user(name), FMODE_RB)))
313 strncpy(demo_replay_name, name, MAXSTR);
315 get_index(demo_fp, &magic);
319 get_index(demo_fp, &zero);
320 get_index(demo_fp, &zero);
322 fread(shot, 1, PATHMAX, demo_fp);
323 fread(file, 1, PATHMAX, demo_fp);
324 fread(back, 1, PATHMAX, demo_fp);
325 fread(grad, 1, PATHMAX, demo_fp);
326 fread(song, 1, PATHMAX, demo_fp);
328 get_index(demo_fp, &st);
329 get_index(demo_fp, &sg);
330 get_index(demo_fp, &ss);
331 get_index(demo_fp, &sc);
332 get_index(demo_fp, &sb);
334 if (g) *g = (int) sg;
335 if (s) *s = (int) ss;
336 if (c) *c = (int) sc;
337 if (b) *b = (int) sb;
341 audio_music_fade_to(0.5f, song);
342 return game_init(file, back, grad, st, (*g == 0));
345 return game_init(file, back, grad, st, 1);
352 int demo_replay_step(float *dt)
354 const float g[3] = { 0.0f, -9.8f, 0.0f };
358 get_float(demo_fp, dt);
360 if (feof(demo_fp) == 0)
362 /* Play out current game state for particles, clock, etc. */
364 game_step(g, *dt, 1);
366 /* Load real current game state from file. */
368 if (get_game_state(demo_fp))
375 void demo_replay_stop(int d)
382 if (d) unlink(config_user(demo_replay_name));
386 /*---------------------------------------------------------------------------*/