ball/demo.o \
ball/demo_dir.o \
ball/util.o \
+ ball/speed.o \
ball/st_conf.o \
ball/st_demo.o \
ball/st_save.o \
#include "level.h"
#include "array.h"
#include "dir.h"
+#include "speed.h"
#include "game_server.h"
#include "game_client.h"
}
}
+void demo_speed_set(int speed)
+{
+ if (SPEED_NONE <= speed && speed < SPEED_MAX)
+ {
+ /*
+ * I am torn between the desire to fix the division by zero
+ * when speed is SPEED_NONE and the knowledge that, on all
+ * modern architectures, the result will be an infinity, which
+ * seems well suited for our purposes.
+ */
+ lockstep_scl(&update_step, 1.0f / SPEED_FACTORS[speed]);
+ }
+}
+
/*---------------------------------------------------------------------------*/
const char *curr_demo(void);
+void demo_speed_set(int);
+
/*---------------------------------------------------------------------------*/
extern fs_file demo_fp;
void lockstep_clr(struct lockstep *ls)
{
ls->at = 0;
+ ls->ts = 1.0f;
}
void lockstep_run(struct lockstep *ls, float dt)
{
ls->at += dt;
- while (ls->at >= ls->dt)
+ while (ls->at >= ls->dt * ls->ts)
{
ls->step(ls->dt);
- ls->at -= ls->dt;
+ ls->at -= ls->dt * ls->ts;
}
}
+void lockstep_scl(struct lockstep *ls, float ts)
+{
+ /*
+ * Depending on the size of the previous time scale, there may be
+ * a lot of time left in the accumulator. Mind-blowing hack: just
+ * reset the accumulator.
+ */
+ ls->at = 0;
+ ls->ts = ts;
+}
+
/*---------------------------------------------------------------------------*/
float dt; /* Time step length */
float at; /* Accumulator */
+ float ts; /* Time scale factor */
};
void lockstep_clr(struct lockstep *);
void lockstep_run(struct lockstep *, float);
+void lockstep_scl(struct lockstep *, float);
/*---------------------------------------------------------------------------*/
#include "config.h"
#include "video.h"
#include "audio.h"
+#include "speed.h"
#include "game_common.h"
#include "game_client.h"
static int view_id;
static int fps_id;
+static int speed_id;
+static int speed_ids[SPEED_MAX];
+
+static const char *speed_labels[SPEED_MAX] = {
+ "", "8", "4", "2", "1", "2", "4", "8"
+};
+
static float view_timer;
+static float speed_timer;
static void hud_fps(void)
{
if ((fps_id = gui_count(0, 1000, GUI_SML, GUI_SE)))
gui_layout(fps_id, -1, 1);
+
+ if ((speed_id = gui_varray(0)))
+ {
+ int i;
+
+ for (i = SPEED_MAX - 1; i > SPEED_NONE; i--)
+ {
+ int rect = 0;
+
+ if (i == SPEED_MAX - 1)
+ rect = GUI_NW;
+ if (i == SPEED_NONE + 1)
+ rect = GUI_SW;
+
+ speed_ids[i] = gui_label(speed_id, speed_labels[i],
+ GUI_SML, rect, 0, 0);
+ }
+
+ gui_layout(speed_id, +1, 0);
+ }
}
void hud_free(void)
gui_paint(fps_id);
hud_view_paint();
+ hud_speed_paint();
}
void hud_update(int pulse)
gui_pulse(ball_id, 0.f);
gui_pulse(time_id, 0.f);
gui_pulse(coin_id, 0.f);
+
+ speed_timer = 0.0f;
}
/* time and tick-tock */
void hud_timer(float dt)
{
-
hud_update(1);
gui_timer(Rhud_id, dt);
gui_timer(time_id, dt);
hud_view_timer(dt);
+ hud_speed_timer(dt);
}
/*---------------------------------------------------------------------------*/
}
/*---------------------------------------------------------------------------*/
+
+void hud_speed_pulse(int speed)
+{
+ int i;
+
+ for (i = SPEED_NONE + 1; i < SPEED_MAX; i++)
+ {
+ const GLfloat *c = gui_gry;
+
+ if (i > SPEED_NORMAL && i <= speed)
+ c = gui_grn;
+ else if (i < SPEED_NORMAL && i >= speed)
+ c = gui_red;
+ else if (i == SPEED_NORMAL)
+ c = gui_wht;
+
+ gui_set_color(speed_ids[i], c, c);
+
+ if (i == speed)
+ gui_pulse(speed_ids[i], 1.2f);
+ }
+
+ speed_timer = 2.0f;
+}
+
+void hud_speed_timer(float dt)
+{
+ speed_timer -= dt;
+ gui_timer(speed_id, dt);
+}
+
+void hud_speed_paint(void)
+{
+ if (speed_timer > 0.0f)
+ gui_paint(speed_id);
+}
+
+/*---------------------------------------------------------------------------*/
void hud_view_timer(float);
void hud_view_paint();
+void hud_speed_pulse(int);
+void hud_speed_timer(float);
+void hud_speed_paint();
+
/*---------------------------------------------------------------------------*/
#endif
--- /dev/null
+#include "speed.h"
+
+float SPEED_FACTORS[SPEED_MAX] = {
+ 0.0f,
+ 1.0f / 8,
+ 1.0f / 4,
+ 1.0f / 2,
+ 1.0f,
+ 1.0f * 2,
+ 1.0f * 4,
+ 1.0f * 8
+};
--- /dev/null
+#ifndef SPEED_H
+#define SPEED_H
+
+enum
+{
+ SPEED_NONE = 0,
+
+ SPEED_SLOWEST,
+ SPEED_SLOWER,
+ SPEED_SLOW,
+ SPEED_NORMAL,
+ SPEED_FAST,
+ SPEED_FASTER,
+ SPEED_FASTEST,
+
+ SPEED_MAX
+};
+
+extern float SPEED_FACTORS[];
+
+#define SPEED_UP(s) MIN((s) + 1, SPEED_MAX - 1)
+#define SPEED_DN(s) MAX((s) - 1, SPEED_NONE)
+
+#endif
#include "util.h"
#include "common.h"
#include "demo_dir.h"
+#include "speed.h"
#include "game_common.h"
#include "game_server.h"
static int demo_paused;
static int show_hud;
static int check_compat;
+static int speed;
static float prelude;
prelude = 1.0f;
+ speed = SPEED_NORMAL;
+ demo_speed_set(speed);
+
show_hud = 1;
hud_update(0);
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)
+{
+ if (!STICK_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)
demo_play_paint,
demo_play_timer,
NULL,
+ demo_play_stick,
NULL,
- NULL,
- NULL,
+ demo_play_click,
demo_play_keybd,
demo_play_buttn,
1, 0