diff --git a/TODO b/TODO new file mode 100644 index 0000000..d145526 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +* Tighter than the original? +* Count number of turns, with optimal +* Add performance counters +* Check if level tempo is accounted for diff --git a/assets-cg/levels.png b/assets-cg/levels.png index 0144b47..a97e0e2 100644 Binary files a/assets-cg/levels.png and b/assets-cg/levels.png differ diff --git a/src/duet.h b/src/duet.h index 6d09b50..8e68075 100644 --- a/src/duet.h +++ b/src/duet.h @@ -10,7 +10,7 @@ #include //--- -// Level strucutres +// Level structures //--- typedef enum { @@ -149,7 +149,8 @@ extern level_t level5, level6, level7, level8; extern level_t level9, level10, level11, level12; extern level_t level13, level14, level15, level16; extern level_t level17, level18, level19, level20; -extern level_t level21, level22; +extern level_t level21, level22, level23, level24; +extern level_t level25, level26, level27, level28; extern episode_t episodes[]; extern int episode_count; diff --git a/src/main.c b/src/main.c index debbc37..a5ec4c1 100644 --- a/src/main.c +++ b/src/main.c @@ -54,8 +54,15 @@ episode_t episodes[] = { &level22, }, }, + { + .name = "guilt", + .level_count = 1, + .levels = (level_t *[]) { + &level22, // TODO + }, + }, }; -int episode_count = 4; +int episode_count = sizeof(episodes) / sizeof(episodes[0]); void load_level(game_t *game, level_t const *lv) { @@ -80,6 +87,20 @@ int strcount(char const *str, int c) return count; } +/* Round player rotation to closest multiple of M_PI */ +float rpr(float rota) +{ + if(fabs(rota) <= M_PI_2) + return 0; + return (rota < 0) ? -M_PI : M_PI; +} + +/* Forced player rotation to go back to an even position */ +float fpr(float rota, float duration) +{ + return (rpr(rota) - rota) / duration; +} + void game_loop(int current_episode, int current_level) { game_t game; @@ -89,19 +110,34 @@ void game_loop(int current_episode, int current_level) state_t state = State_Playing; - if(current_level == 0) { - state = State_EpisodeTransition; - game.time_episode_transition = 0; - game.time = -14.0; - } - /* Direction of time (with a factor regulating game speed) */ float const time_direction_forward = 2.7; float const time_direction_rewind = -25; + /* Level time to start (negative to leave time before blocks arrive) */ + float const LEVEL_START = -14.0; + /* Level time until which message is shown */ + float const MESSAGE_END = -5.0; + /* Duration of death pause (seconds) */ + float const DEATH_PAUSE_DURATION = 0.7; + /* Level time to restarting playing at after rewind */ + float const REWIND_END = -5.0; + /* Duration of level transitions (seconds) */ + float const TRANSITION_DURATION = 1.0; + /* Duration of episode transitions (seconds) + Warning: overlaps with pre-level, will lock player if too long x_x */ + float const EPISODE_TRANSITION_DURATION = 3.0; volatile int need_frame = 1; int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame)); if(timer >= 0) timer_start(timer); + /* Frame duration in real time */ + float const FRAME_DURATION = 1.0 / 30; + + if(current_level == 0) { + state = State_EpisodeTransition; + game.time_episode_transition = 0; + game.time = LEVEL_START; + } while (1) { level_t const *lv = game.level; @@ -116,38 +152,37 @@ void game_loop(int current_episode, int current_level) time_direction = time_direction_rewind; if(state == State_Dead) { - game.time_dead += (1.0 / 30); - if(game.time_dead >= 0.7) { + game.time_dead += FRAME_DURATION; + if(game.time_dead >= DEATH_PAUSE_DURATION) { game.time_dead = 0; - game.forced_player_rota = game.player_rota / (game.time + 5.0); + game.forced_player_rota = fpr(game.player_rota, + REWIND_END - game.time); state = State_Rewind; } - continue; + continue; /* Pause effect */ } if(state == State_Transition) { time_direction = 1.0; - game.time_transition += (1.0 / 30); - if(game.time_transition >= 1.0) { + game.time_transition += FRAME_DURATION; + if(game.time_transition >= TRANSITION_DURATION) { game.time_transition = 0; - game.player_rota = 0; game.forced_player_rota = 0; state = State_Playing; } } if(state == State_EpisodeTransition) { time_direction = 1.0; - game.time_episode_transition += (1.0 / 30); - if(game.time_episode_transition >= 1.0) { - game.player_rota = 0; + game.time_episode_transition += FRAME_DURATION; + if(game.time_episode_transition >= TRANSITION_DURATION) { game.forced_player_rota = 0; } - if(game.time_episode_transition >= 3.0) { + if(game.time_episode_transition >= EPISODE_TRANSITION_DURATION) { game.time_episode_transition = 0; state = State_Playing; } } - float dt = (1.0 / 30) * time_direction; + float dt = FRAME_DURATION * time_direction; game.time += dt; /* Input analysis */ @@ -193,23 +228,24 @@ void game_loop(int current_episode, int current_level) if(changed_episode) { state = State_EpisodeTransition; game.time_episode_transition = 0; - game.forced_player_rota = -game.player_rota / 1.0; - game.time = -13.0; + game.forced_player_rota = fpr(game.player_rota, + TRANSITION_DURATION); + game.time = LEVEL_START; continue; } else { state = State_Transition; game.time_transition = 0; - game.forced_player_rota = -game.player_rota / 1.0; + game.forced_player_rota = fpr(game.player_rota, + TRANSITION_DURATION); continue; } } // End of rewind - if(state == State_Rewind && game.time <= -5.0) { - game.time = -5.0; - game.player_rota = 0.0; - game.forced_player_rota = 0.0; + if(state == State_Rewind && game.time <= REWIND_END) { + game.time = REWIND_END; + game.forced_player_rota = 0; state = State_Playing; continue; } @@ -255,7 +291,7 @@ void game_loop(int current_episode, int current_level) dma_memcpy(gint_vram + 396*(40*j), gint_vram, 396*2*lines); } - if(state == State_Playing && game.time < -4.0 && lv->message) { + if(state == State_Playing && game.time < MESSAGE_END && lv->message) { int x = DWIDTH/2 + 8 * (strcount(lv->message, '\n') + 1); /* Split at newlines */ diff --git a/src/physics.c b/src/physics.c index 12a5338..58d91db 100644 --- a/src/physics.c +++ b/src/physics.c @@ -136,6 +136,9 @@ void rect_physics(rect_t *r, rectmeta_t const *meta, float absolute_time) float speeding_period = fminf(2.0, fmaxf(0.0, time + 6.0)); r->x -= RECT_SPEED * speeding_period; } + else if(meta->action == Action_FadeOut) { + // TODO + } else if(meta->action == Action_OuterRotateLeft) { float vr = 0.7; /* rad/tempo */ r->r = time * vr; @@ -144,4 +147,14 @@ void rect_physics(rect_t *r, rectmeta_t const *meta, float absolute_time) float vr = 0.7; /* rad/tempo */ r->r = -time * vr; } + else if(meta->action == Action_Slide) { + // TODO + } + else if(meta->action == Action_Speed2) { + /* Double speed permanently */ + // TODO + } + else if(meta->action == Action_Speed3) { + // TODO + } }