Import from neverball-1.3.1.tar.gz
[neverball-archive.git] / ball / demo.c
blobe5571de64fd9476c7e34ebbc72463788b9083956
1 /*
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.
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
19 #ifndef _WIN32
20 #include <unistd.h>
21 #endif
23 #include "set.h"
24 #include "demo.h"
25 #include "game.h"
26 #include "level.h"
27 #include "audio.h"
28 #include "solid.h"
29 #include "config.h"
30 #include "binary.h"
32 /*---------------------------------------------------------------------------*/
34 #define MAGIC 0x4E425250
36 static FILE *demo_fp;
38 static char name[MAXDEMO][MAXNAM];
39 static char shot[MAXDEMO][PATHMAX];
40 static short score[MAXDEMO];
41 static short clock[MAXDEMO];
42 static int count;
44 /*---------------------------------------------------------------------------*/
45 #ifdef _WIN32
47 int demo_scan(void)
49 WIN32_FIND_DATA d;
50 HANDLE h;
51 FILE *fp;
53 count = 0;
55 /* Scan the user directory for files. */
57 if ((h = FindFirstFile(config_user("*"), &d)) != INVALID_HANDLE_VALUE)
60 if ((fp = fopen(config_user(d.cFileName), FMODE_RB)))
62 int magic;
63 short t, c;
65 /* Note the name and screen shot of each replay file. */
67 get_int (fp, &magic);
68 get_short(fp, &t);
69 get_short(fp, &c);
71 if (magic == MAGIC && t)
73 fread(shot[count], 1, PATHMAX, fp);
74 clock[count] = t;
75 score[count] = c;
76 strncpy(name[count], d.cFileName, MAXNAM);
77 count++;
79 fclose(fp);
81 while (count < MAXDEMO && FindNextFile(h, &d));
83 FindClose(h);
85 return count;
88 #else /* _WIN32 */
89 #include <dirent.h>
91 int demo_scan(void)
93 struct dirent *ent;
94 FILE *fp;
95 DIR *dp;
97 count = 0;
99 /* Scan the user directory for files. */
101 if ((dp = opendir(config_user(""))))
103 while (count < MAXDEMO && (ent = readdir(dp)))
104 if ((fp = fopen(config_user(ent->d_name), FMODE_RB)))
106 int magic;
107 short t, c;
109 /* Note the name and screen shot of each replay file. */
111 get_int (fp, &magic);
112 get_short(fp, &t);
113 get_short(fp, &c);
115 if (magic == MAGIC && t)
117 fread(shot[count], 1, PATHMAX, fp);
118 clock[count] = t;
119 score[count] = c;
120 strncpy(name[count], ent->d_name, MAXNAM);
121 count++;
123 fclose(fp);
126 closedir(dp);
128 return count;
130 #endif /* _WIN32 */
132 const char *demo_pick(void)
134 int n = demo_scan();
136 return (n > 0) ? name[(rand() >> 4) % n] : NULL;
139 const char *demo_name(int i)
141 return (0 <= i && i < count) ? name[i] : NULL;
144 const char *demo_shot(int i)
146 return (0 <= i && i < count) ? shot[i] : NULL;
149 int demo_coins(int i)
151 return (0 <= i && i < count) ? score[i] : 0;
154 int demo_clock(int i)
156 return (0 <= i && i < count) ? clock[i] : 0;
159 /*---------------------------------------------------------------------------*/
161 int demo_exists(char *name)
163 FILE *fp;
165 if ((fp = fopen(config_user(name), "r")))
167 fclose(fp);
168 return 1;
170 return 0;
173 void demo_unique(char *name)
175 int i;
177 /* Generate a unique name for a new replay save. */
179 for (i = 1; i < 100; i++)
181 sprintf(name, "replay%02d", i);
183 if (!demo_exists(name))
184 return;
188 /*---------------------------------------------------------------------------*/
190 int demo_play_init(const char *name,
191 const char *file,
192 const char *back,
193 const char *grad,
194 const char *song,
195 const char *shot,
196 int t, int g, int s, int c, int b)
198 int magic = MAGIC;
199 short zero = 0;
200 short st = t;
201 short sg = g;
202 short ss = s;
203 short sc = c;
204 short sb = b;
206 /* Initialize the replay file. Write the header. */
208 if (name && (demo_fp = fopen(config_user(name), FMODE_WB)))
210 put_int(demo_fp, &magic);
212 put_short(demo_fp, &zero);
213 put_short(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_short(demo_fp, &st);
222 put_short(demo_fp, &sg);
223 put_short(demo_fp, &ss);
224 put_short(demo_fp, &sc);
225 put_short(demo_fp, &sb);
227 audio_music_fade_to(2.0f, song);
229 return game_init(file, back, grad, t, (g == 0));
231 return 0;
234 void demo_play_step(float dt)
236 if (demo_fp)
238 put_float(demo_fp, &dt);
239 put_game_state(demo_fp);
243 void demo_play_stat(int coins, int clock)
245 short c = coins;
246 short t = clock;
248 if (demo_fp)
250 /* Update the demo header using the final score and time. */
252 fseek(demo_fp, 4, SEEK_SET);
254 put_short(demo_fp, &t);
255 put_short(demo_fp, &c);
257 fseek(demo_fp, 0, SEEK_END);
261 void demo_play_stop(const char *name)
263 char src[PATHMAX];
264 char dst[PATHMAX];
266 if (demo_fp)
268 fclose(demo_fp);
269 demo_fp = NULL;
271 /* Rename the temporary replay file to its given name. */
273 if (name)
275 strncpy(src, config_user(USER_REPLAY_FILE), PATHMAX);
276 strncpy(dst, config_user(name), PATHMAX);
278 rename(src, dst);
283 /*---------------------------------------------------------------------------*/
285 static char demo_replay_name[MAXSTR];
287 int demo_replay_init(const char *name, int *s, int *c, int *b, int *g)
289 char shot[PATHMAX];
290 char file[PATHMAX];
291 char back[PATHMAX];
292 char grad[PATHMAX];
293 char song[PATHMAX];
295 int magic;
296 short zero;
297 short st;
298 short sg;
299 short ss;
300 short sc;
301 short sb;
303 if ((demo_fp = fopen(config_user(name), FMODE_RB)))
305 strncpy(demo_replay_name, name, MAXSTR);
307 get_int(demo_fp, &magic);
309 if (magic == MAGIC)
311 get_short(demo_fp, &zero);
312 get_short(demo_fp, &zero);
314 fread(shot, 1, PATHMAX, demo_fp);
315 fread(file, 1, PATHMAX, demo_fp);
316 fread(back, 1, PATHMAX, demo_fp);
317 fread(grad, 1, PATHMAX, demo_fp);
318 fread(song, 1, PATHMAX, demo_fp);
320 get_short(demo_fp, &st);
321 get_short(demo_fp, &sg);
322 get_short(demo_fp, &ss);
323 get_short(demo_fp, &sc);
324 get_short(demo_fp, &sb);
326 if (g) *g = (int) sg;
327 if (s) *s = (int) ss;
328 if (c) *c = (int) sc;
329 if (b) *b = (int) sb;
331 if (g)
333 audio_music_fade_to(0.5f, song);
334 return game_init(file, back, grad, st, (*g == 0));
336 else
337 return game_init(file, back, grad, st, 1);
339 fclose(demo_fp);
341 return 0;
344 int demo_replay_step(float *dt)
346 const float g[3] = { 0.0f, -9.8f, 0.0f };
348 if (demo_fp)
350 get_float(demo_fp, dt);
352 if (feof(demo_fp) == 0)
354 /* Play out current game state for particles, clock, etc. */
356 game_step(g, *dt, 1);
358 /* Load real current game state from file. */
360 if (get_game_state(demo_fp))
361 return 1;
364 return 0;
367 void demo_replay_stop(int d)
369 if (demo_fp)
371 fclose(demo_fp);
372 demo_fp = NULL;
374 if (d) unlink(config_user(demo_replay_name));
378 /*---------------------------------------------------------------------------*/