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.
30 #include "game_common.h"
31 #include "game_server.h"
32 #include "game_client.h"
36 #include "st_shared.h"
38 /*---------------------------------------------------------------------------*/
49 static int last_viewed = 0;
51 /*---------------------------------------------------------------------------*/
53 static int demo_action(int i)
55 audio_play(AUD_MENU, 1.0f);
60 return goto_state(&st_title);
64 return goto_state(&st_demo);
69 return goto_state(&st_demo);
77 if (progress_replay(DIR_ITEM_GET(items, i)->path))
81 return goto_state(&st_demo_play);
88 /*---------------------------------------------------------------------------*/
97 static int gui_demo_thumbs(int id)
99 int w = config_get_d(CONFIG_WIDTH);
100 int h = config_get_d(CONFIG_HEIGHT);
107 if ((jd = gui_varray(id)))
108 for (i = first; i < first + DEMO_STEP; i += DEMO_LINE)
109 if ((kd = gui_harray(jd)))
111 for (j = i + DEMO_LINE - 1; j >= i; j--)
113 thumb = &thumbs[j % DEMO_STEP];
119 if ((ld = gui_vstack(kd)))
123 thumb->shot = gui_image(ld, " ", w / 6, h / 6);
124 thumb->name = gui_state(ld, " ", GUI_SML, j, 0);
126 gui_set_trunc(thumb->name, TRUNC_TAIL);
128 gui_active(ld, j, 0);
144 static void gui_demo_update_thumbs(void)
146 struct dir_item *item;
150 for (i = 0; i < ARRAYSIZE(thumbs) && thumbs[i].shot && thumbs[i].name; i++)
152 item = DIR_ITEM_GET(items, thumbs[i].item);
155 gui_set_image(thumbs[i].shot, demo ? demo->shot : "");
156 gui_set_label(thumbs[i].name, demo ? demo->name : base_name(item->path));
164 static int status_id;
165 static int player_id;
167 static int gui_demo_status(int id)
173 /* Find the longest status string. */
175 for (status = "", s = GAME_NONE; s < GAME_MAX; s++)
176 if (strlen(status_to_str(s)) > strlen(status))
177 status = status_to_str(s);
179 /* Build info bar with dummy values. */
181 if ((jd = gui_hstack(id)))
185 if ((kd = gui_hstack(jd)))
187 if ((ld = gui_vstack(kd)))
191 time_id = gui_clock(ld, 35000, GUI_SML, GUI_NE);
192 coin_id = gui_count(ld, 100, GUI_SML, 0);
193 status_id = gui_label(ld, status, GUI_SML, GUI_SE,
199 if ((ld = gui_vstack(kd)))
203 gui_label(ld, _("Time"), GUI_SML, GUI_NW, gui_wht, gui_wht);
204 gui_label(ld, _("Coins"), GUI_SML, 0, gui_wht, gui_wht);
205 gui_label(ld, _("Status"), GUI_SML, GUI_SW, gui_wht, gui_wht);
213 if ((kd = gui_vstack(jd)))
217 name_id = gui_label(kd, " ", GUI_SML, GUI_NE, 0, 0);
218 player_id = gui_label(kd, " ", GUI_SML, 0, 0, 0);
219 date_id = gui_label(kd, date_to_str(time(NULL)),
220 GUI_SML, GUI_SE, 0, 0);
224 gui_set_trunc(name_id, TRUNC_TAIL);
225 gui_set_trunc(player_id, TRUNC_TAIL);
228 if ((kd = gui_vstack(jd)))
232 gui_label(kd, _("Replay"), GUI_SML, GUI_NW, gui_wht, gui_wht);
233 gui_label(kd, _("Player"), GUI_SML, 0, gui_wht, gui_wht);
234 gui_label(kd, _("Date"), GUI_SML, GUI_SW, gui_wht, gui_wht);
245 static void gui_demo_update_status(int i)
247 const struct demo *d;
252 d = DEMO_GET(items, i < total ? i : 0);
257 gui_set_label(name_id, d->name);
258 gui_set_label(date_id, date_to_str(d->date));
259 gui_set_label(player_id, d->player);
261 if (d->status == GAME_GOAL)
262 gui_set_color(status_id, gui_grn, gui_grn);
264 gui_set_color(status_id, gui_red, gui_red);
266 gui_set_label(status_id, status_to_str(d->status));
267 gui_set_count(coin_id, d->coins);
268 gui_set_clock(time_id, d->timer);
271 /*---------------------------------------------------------------------------*/
273 static int demo_gui(void)
281 if ((jd = gui_hstack(id)))
284 gui_label(jd, _("Select Replay"), GUI_SML, GUI_ALL, 0,0);
286 gui_navig(jd, first > 0, first + DEMO_STEP < total);
293 gui_layout(id, 0, 0);
295 gui_demo_update_thumbs();
296 gui_demo_update_status(last_viewed);
300 gui_label(id, _("No Replays"), GUI_MED, GUI_ALL, 0, 0);
301 gui_layout(id, 0, 0);
307 static int demo_enter(struct state *st, struct state *prev)
309 if (!items || (prev == &st_demo_del))
313 demo_dir_free(items);
317 items = demo_dir_scan();
318 total = array_len(items);
321 first = first < total ? first : 0;
322 last = MIN(first + DEMO_STEP - 1, total - 1);
323 last_viewed = MIN(MAX(first, last_viewed), last);
326 demo_dir_load(items, first, last);
328 audio_music_fade_to(0.5f, "bgm/inter.ogg");
333 static void demo_leave(struct state *st, struct state *next, int id)
335 if (next == &st_title)
337 demo_dir_free(items);
344 static void demo_timer(int id, float dt)
346 if (total == 0 && time_state() > 4.0f)
347 goto_state(&st_title);
352 static void demo_point(int id, int x, int y, int dx, int dy)
354 int jd = shared_point_basic(id, x, y);
355 int i = gui_token(jd);
357 if (jd && i >= 0 && !GUI_ISMSK(i))
358 gui_demo_update_status(i);
361 static void demo_stick(int id, int a, float v, int bump)
363 int jd = shared_stick_basic(id, a, v, bump);
364 int i = gui_token(jd);
366 if (jd && i >= 0 && !GUI_ISMSK(i))
367 gui_demo_update_status(i);
370 static int demo_buttn(int b, int d)
374 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
375 return demo_action(total ? gui_token(gui_click()) : GUI_BACK);
376 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
377 return demo_action(GUI_BACK);
382 /*---------------------------------------------------------------------------*/
384 static int standalone;
385 static int demo_paused;
387 static int check_compat;
390 static float prelude;
392 void demo_play_goto(int s)
398 static int demo_play_gui(void)
402 if ((id = gui_vstack(0)))
404 gui_label(id, _("Replay"), GUI_LRG, GUI_ALL, gui_blu, gui_grn);
405 gui_layout(id, 0, 0);
412 static int demo_play_enter(struct state *st, struct state *prev)
418 audio_music_fade_in(0.5f);
423 * Post-1.5.1 replays include view data in the first update, this
424 * line is currently left in for compatibility with older replays.
426 game_client_fly(0.0f);
428 if (check_compat && !game_compat_map)
430 goto_state(&st_demo_compat);
436 speed = SPEED_NORMAL;
437 demo_speed_set(speed);
442 return demo_play_gui();
445 static void demo_play_paint(int id, float t)
447 game_client_draw(0, t);
452 if (time_state() < prelude)
456 static void demo_play_timer(int id, float dt)
462 /* Pause briefly before starting playback. */
464 if (time_state() < prelude)
467 if (!demo_replay_step(dt))
470 goto_state(&st_demo_end);
476 static void set_speed(int d)
478 if (d > 0) speed = SPEED_UP(speed);
479 if (d < 0) speed = SPEED_DN(speed);
481 demo_speed_set(speed);
482 hud_speed_pulse(speed);
485 static void demo_play_stick(int id, int a, float v, int bump)
490 if (config_tst_d(CONFIG_JOYSTICK_AXIS_Y, a))
492 if (v < 0) set_speed(+1);
493 if (v > 0) set_speed(-1);
497 static int demo_play_click(int b, int d)
501 if (b == SDL_BUTTON_WHEELUP) set_speed(+1);
502 if (b == SDL_BUTTON_WHEELDOWN) set_speed(-1);
508 static int demo_play_keybd(int c, int d)
512 if (config_tst_d(CONFIG_KEY_PAUSE, c))
515 return goto_state(&st_demo_end);
519 show_hud = !show_hud;
524 static int demo_play_buttn(int b, int d)
528 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
530 if (config_tst_d(CONFIG_KEY_PAUSE, SDLK_ESCAPE))
533 return goto_state(&st_demo_end);
539 /*---------------------------------------------------------------------------*/
544 #define DEMO_REPLAY 3
545 #define DEMO_CONTINUE 4
547 static int demo_end_action(int i)
549 audio_play(AUD_MENU, 1.0f);
555 return goto_state(&st_demo_del);
559 return goto_state(&st_demo);
565 progress_replay(curr_demo());
566 return goto_state(&st_demo_play);
568 return goto_state(&st_demo_play);
573 static int demo_end_gui(void)
577 if ((id = gui_vstack(0)))
580 kd = gui_label(id, _("Replay Paused"), GUI_LRG, GUI_ALL,
583 kd = gui_label(id, _("Replay Ends"), GUI_LRG, GUI_ALL,
586 if ((jd = gui_harray(id)))
592 start_id = gui_start(jd, _("Quit"), GUI_SML, DEMO_QUIT, 1);
596 start_id = gui_start(jd, _("Keep"), GUI_SML, DEMO_KEEP, 1);
597 gui_state(jd, _("Delete"), GUI_SML, DEMO_DEL, 0);
602 gui_start(jd, _("Continue"), GUI_SML, DEMO_CONTINUE, 1);
603 gui_toggle(start_id);
606 gui_state(jd, _("Repeat"), GUI_SML, DEMO_REPLAY, 0);
610 gui_layout(id, 0, 0);
616 static int demo_end_enter(struct state *st, struct state *prev)
618 audio_music_fade_out(demo_paused ? 0.2f : 2.0f);
620 return demo_end_gui();
623 static void demo_end_paint(int id, float t)
625 game_client_draw(0, t);
632 static int demo_end_keybd(int c, int d)
636 if (demo_paused && config_tst_d(CONFIG_KEY_PAUSE, c))
637 return demo_end_action(DEMO_CONTINUE);
642 static int demo_end_buttn(int b, int d)
646 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
647 return demo_end_action(gui_token(gui_click()));
649 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
652 return demo_end_action(DEMO_CONTINUE);
654 return demo_end_action(standalone ? DEMO_QUIT : DEMO_KEEP);
660 /*---------------------------------------------------------------------------*/
662 static int demo_del_action(int i)
664 audio_play(AUD_MENU, 1.0f);
665 demo_replay_stop(i == DEMO_DEL);
666 return goto_state(&st_demo);
669 static int demo_del_gui(void)
673 if ((id = gui_vstack(0)))
675 kd = gui_label(id, _("Delete Replay?"), GUI_MED, GUI_ALL, gui_red, gui_red);
677 if ((jd = gui_harray(id)))
679 gui_start(jd, _("No"), GUI_SML, DEMO_KEEP, 1);
680 gui_state(jd, _("Yes"), GUI_SML, DEMO_DEL, 0);
684 gui_layout(id, 0, 0);
690 static int demo_del_enter(struct state *st, struct state *prev)
692 audio_music_fade_out(2.0f);
694 return demo_del_gui();
697 static int demo_del_buttn(int b, int d)
701 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
702 return demo_del_action(gui_token(gui_click()));
703 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
704 return demo_del_action(DEMO_KEEP);
709 /*---------------------------------------------------------------------------*/
711 static int demo_compat_gui(void)
715 if ((id = gui_vstack(0)))
717 gui_label(id, _("Warning!"), GUI_MED, GUI_ALL, 0, 0);
719 gui_multi(id, _("The current replay was recorded with a\\"
720 "different (or unknown) version of this level.\\"
721 "Be prepared to encounter visual errors.\\"),
722 GUI_SML, GUI_ALL, gui_wht, gui_wht);
724 gui_layout(id, 0, 0);
730 static int demo_compat_enter(struct state *st, struct state *prev)
734 return demo_compat_gui();
737 static void demo_compat_timer(int id, float dt)
743 static int demo_compat_buttn(int b, int d)
747 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
748 return goto_state(&st_demo_play);
749 if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
750 return goto_state(&st_demo_end);
755 /*---------------------------------------------------------------------------*/
757 struct state st_demo = {
770 struct state st_demo_play = {
783 struct state st_demo_end = {
796 struct state st_demo_del = {
809 struct state st_demo_compat = {