Implement game state interpolation (WIP)
[neverball] / ball / st_demo.c
index 9156a00..7e388dc 100644 (file)
 #include "demo.h"
 #include "progress.h"
 #include "audio.h"
-#include "solid.h"
 #include "config.h"
-#include "st_shared.h"
 #include "util.h"
 #include "common.h"
 #include "demo_dir.h"
+#include "speed.h"
 
 #include "game_common.h"
 #include "game_server.h"
@@ -33,6 +32,7 @@
 
 #include "st_demo.h"
 #include "st_title.h"
+#include "st_shared.h"
 
 /*---------------------------------------------------------------------------*/
 
@@ -43,6 +43,7 @@ static Array items;
 
 static int first = 0;
 static int total = 0;
+static int last  = 0;
 
 static int last_viewed = 0;
 
@@ -72,7 +73,7 @@ static int demo_action(int i)
         break;
 
     default:
-        if (progress_replay(DEMO_GET(items, i)->filename))
+        if (progress_replay(DIR_ITEM_GET(items, i)->path))
         {
             last_viewed = i;
             demo_play_goto(0);
@@ -141,12 +142,17 @@ static int gui_demo_thumbs(int id)
 
 static void gui_demo_update_thumbs(void)
 {
+    struct dir_item *item;
+    struct demo *demo;
     int i;
 
     for (i = 0; i < ARRAYSIZE(thumbs) && thumbs[i].shot && thumbs[i].name; i++)
     {
-        gui_set_image(thumbs[i].shot, DEMO_GET(items, thumbs[i].item)->shot);
-        gui_set_label(thumbs[i].name, DEMO_GET(items, thumbs[i].item)->name);
+        item = DIR_ITEM_GET(items, thumbs[i].item);
+        demo = item->data;
+
+        gui_set_image(thumbs[i].shot, demo ? demo->shot : "");
+        gui_set_label(thumbs[i].name, demo ? demo->name : base_name(item->path));
     }
 }
 
@@ -239,9 +245,12 @@ static void gui_demo_update_status(int i)
 {
     const struct demo *d;
 
-    if (total > 0)
-        d = DEMO_GET(items, i < total ? i : 0);
-    else
+    if (!total)
+        return;
+
+    d = DEMO_GET(items, i < total ? i : 0);
+
+    if (!d)
         return;
 
     gui_set_label(name_id,   d->name);
@@ -296,17 +305,41 @@ static int demo_gui(void)
 
 static int demo_enter(struct state *st, struct state *prev)
 {
-    if (items)
-        demo_dir_free(items);
+    if (!items || (prev == &st_demo_del))
+    {
+        if (items)
+        {
+            demo_dir_free(items);
+            items = NULL;
+        }
 
-    items = demo_dir_scan();
-    total = array_len(items);
+        items = demo_dir_scan();
+        total = array_len(items);
+    }
+
+    first       = first < total ? first : 0;
+    last        = MIN(first + DEMO_STEP - 1, total - 1);
+    last_viewed = MIN(MAX(first, last_viewed), last);
+
+    if (total)
+        demo_dir_load(items, first, last);
 
     audio_music_fade_to(0.5f, "bgm/inter.ogg");
 
     return demo_gui();
 }
 
+static void demo_leave(struct state *st, struct state *next, int id)
+{
+    if (next == &st_title)
+    {
+        demo_dir_free(items);
+        items = NULL;
+    }
+
+    gui_delete(id);
+}
+
 static void demo_timer(int id, float dt)
 {
     if (total == 0 && time_state() > 4.0f)
@@ -324,9 +357,9 @@ static void demo_point(int id, int x, int y, int dx, int dy)
         gui_demo_update_status(i);
 }
 
-static void demo_stick(int id, int a, int v)
+static void demo_stick(int id, int a, float v, int bump)
 {
-    int jd = shared_stick_basic(id, a, v);
+    int jd = shared_stick_basic(id, a, v, bump);
     int i  = gui_token(jd);
 
     if (jd && i >= 0 && !GUI_ISMSK(i))
@@ -351,6 +384,7 @@ static int standalone;
 static int demo_paused;
 static int show_hud;
 static int check_compat;
+static int speed;
 
 static float prelude;
 
@@ -398,6 +432,9 @@ static int demo_play_enter(struct state *st, struct state *prev)
 
     prelude = 1.0f;
 
+    speed = SPEED_NORMAL;
+    demo_speed_set(speed);
+
     show_hud = 1;
     hud_update(0);
 
@@ -406,7 +443,7 @@ static int demo_play_enter(struct state *st, struct state *prev)
 
 static void demo_play_paint(int id, float t)
 {
-    game_client_draw(0, t);
+    game_client_draw(0, t, demo_play_blend());
 
     if (show_hud)
         hud_paint();
@@ -435,6 +472,38 @@ static void demo_play_timer(int id, float dt)
         progress_step();
 }
 
+static void set_speed(int d)
+{
+    if (d > 0) speed = SPEED_UP(speed);
+    if (d < 0) speed = SPEED_DN(speed);
+
+    demo_speed_set(speed);
+    hud_speed_pulse(speed);
+}
+
+static void demo_play_stick(int id, int a, float v, int bump)
+{
+    if (!bump)
+        return;
+
+    if (config_tst_d(CONFIG_JOYSTICK_AXIS_Y, a))
+    {
+        if (v < 0) set_speed(+1);
+        if (v > 0) set_speed(-1);
+    }
+}
+
+static int demo_play_click(int b, int d)
+{
+    if (d)
+    {
+        if (b == SDL_BUTTON_WHEELUP)   set_speed(+1);
+        if (b == SDL_BUTTON_WHEELDOWN) set_speed(-1);
+    }
+
+    return 1;
+}
+
 static int demo_play_keybd(int c, int d)
 {
     if (d)
@@ -492,7 +561,7 @@ static int demo_end_action(int i)
         return 0;
     case DEMO_REPLAY:
         demo_replay_stop(0);
-        progress_replay(curr_demo_replay()->filename);
+        progress_replay(curr_demo());
         return goto_state(&st_demo_play);
     case DEMO_CONTINUE:
         return goto_state(&st_demo_play);
@@ -552,7 +621,7 @@ static int demo_end_enter(struct state *st, struct state *prev)
 
 static void demo_end_paint(int id, float t)
 {
-    game_client_draw(0, t);
+    game_client_draw(0, t, demo_play_blend());
     gui_paint(id);
 
     if (demo_paused)
@@ -592,7 +661,6 @@ static int demo_end_buttn(int b, int d)
 static int demo_del_action(int i)
 {
     audio_play(AUD_MENU, 1.0f);
-
     demo_replay_stop(i == DEMO_DEL);
     return goto_state(&st_demo);
 }
@@ -687,7 +755,7 @@ static int demo_compat_buttn(int b, int d)
 
 struct state st_demo = {
     demo_enter,
-    shared_leave,
+    demo_leave,
     shared_paint,
     demo_timer,
     demo_point,
@@ -695,8 +763,7 @@ struct state st_demo = {
     shared_angle,
     shared_click,
     NULL,
-    demo_buttn,
-    1, 0
+    demo_buttn
 };
 
 struct state st_demo_play = {
@@ -705,12 +772,11 @@ struct state st_demo_play = {
     demo_play_paint,
     demo_play_timer,
     NULL,
+    demo_play_stick,
     NULL,
-    NULL,
-    NULL,
+    demo_play_click,
     demo_play_keybd,
-    demo_play_buttn,
-    1, 0
+    demo_play_buttn
 };
 
 struct state st_demo_end = {
@@ -723,8 +789,7 @@ struct state st_demo_end = {
     shared_angle,
     shared_click,
     demo_end_keybd,
-    demo_end_buttn,
-    1, 0
+    demo_end_buttn
 };
 
 struct state st_demo_del = {
@@ -737,8 +802,7 @@ struct state st_demo_del = {
     shared_angle,
     shared_click,
     NULL,
-    demo_del_buttn,
-    1, 0
+    demo_del_buttn
 };
 
 struct state st_demo_compat = {
@@ -751,6 +815,5 @@ struct state st_demo_compat = {
     shared_angle,
     shared_click,
     NULL,
-    demo_compat_buttn,
-    1, 0
+    demo_compat_buttn
 };