201 lines
5.3 KiB
C
201 lines
5.3 KiB
C
#include <gint/display.h>
|
|
#include <gint/keyboard.h>
|
|
#include <gint/timer.h>
|
|
#include <gint/gint.h>
|
|
#include <gint/cpu.h>
|
|
#include <gint/drivers/r61524.h>
|
|
|
|
#include <fxlibc/printf.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "duet.h"
|
|
|
|
/* Game state */
|
|
typedef enum {
|
|
State_Playing,
|
|
State_Dead,
|
|
State_Rewind,
|
|
State_Transition,
|
|
State_EpisodeCard,
|
|
State_Finale,
|
|
} state_t;
|
|
|
|
void load_level(game_t *game, level_t const *lv)
|
|
{
|
|
game->level = lv;
|
|
game->time = -10.0;
|
|
|
|
game->rects = realloc(game->rects, lv->block_count * sizeof *game->rects);
|
|
if(!game->rects)
|
|
exit(1);
|
|
for(int i = 0; i < lv->block_count; i++) {
|
|
game->rects[i].meta = &lv->blocks[i];
|
|
rect_load(&game->rects[i], &lv->blocks[i]);
|
|
}
|
|
game->rect_count = lv->block_count;
|
|
}
|
|
|
|
int strcount(char const *str, int c)
|
|
{
|
|
int count = 0;
|
|
for(int i = 0; str[i]; i++)
|
|
count += (str[i] == c);
|
|
return count;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
__printf_enable_fp();
|
|
|
|
/* Azur trickz for less tearing */
|
|
r61524_set(0x010, 0x0010);
|
|
|
|
level_t const *story_levels[] = {
|
|
&level1, &level2, &level3, &level4, &level5, &level6, &level7,
|
|
&level8, &level9, &level10, NULL,
|
|
};
|
|
int story_position = main_menu();
|
|
|
|
game_t game;
|
|
load_level(&game, story_levels[story_position]);
|
|
|
|
state_t state = State_Playing;
|
|
|
|
/* Direction of time (with a factor regulating game speed) */
|
|
float const time_direction_forward = 2.7;
|
|
float const time_direction_rewind = -40;
|
|
|
|
volatile int need_frame = 1;
|
|
int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame));
|
|
timer_start(timer);
|
|
|
|
while (1) {
|
|
level_t const *lv = game.level;
|
|
|
|
while (need_frame == 0) sleep();
|
|
need_frame = 0;
|
|
|
|
/* Time management */
|
|
|
|
float time_direction = lv->tempo * time_direction_forward;
|
|
if(state == State_Rewind)
|
|
time_direction = time_direction_rewind;
|
|
|
|
if(state == State_Dead) {
|
|
game.time_dead += (1.0 / 30);
|
|
if(game.time_dead >= 1.0) {
|
|
game.time_dead = 0;
|
|
game.forced_player_rota = game.player_rota / (game.time + 5.0);
|
|
state = State_Rewind;
|
|
}
|
|
continue;
|
|
}
|
|
if(state == State_Transition) {
|
|
time_direction = 1.0;
|
|
game.time_transition += (1.0 / 30);
|
|
if(game.time_transition >= 1.0) {
|
|
game.time_transition = 0;
|
|
game.player_rota = 0;
|
|
game.forced_player_rota = 0;
|
|
state = State_Playing;
|
|
}
|
|
}
|
|
|
|
float dt = (1.0 / 30) * time_direction;
|
|
game.time += dt;
|
|
|
|
/* Input analysis */
|
|
|
|
bool rotate_left=false, rotate_right=false;
|
|
|
|
key_event_t e;
|
|
while ((e = pollevent()).type != KEYEV_NONE) {
|
|
if (e.type == KEYEV_DOWN && e.key == KEY_MENU)
|
|
gint_osmenu();
|
|
}
|
|
if (keydown(KEY_7)) {
|
|
rotate_left = true;
|
|
}
|
|
if (keydown(KEY_0)) {
|
|
rotate_right = true;
|
|
}
|
|
|
|
/* Level transitions */
|
|
|
|
// End of level
|
|
if(state == State_Playing &&
|
|
game.time >= lv->blocks[lv->block_count-1].time + 5) {
|
|
if(story_levels[++story_position] == NULL)
|
|
break;
|
|
|
|
load_level(&game, story_levels[story_position]);
|
|
|
|
state = State_Transition;
|
|
game.time_transition = 0;
|
|
game.forced_player_rota = -game.player_rota / 1.0;
|
|
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;
|
|
state = State_Playing;
|
|
continue;
|
|
}
|
|
|
|
/* Physics */
|
|
|
|
if(state == State_Playing && player_collision(&game)) {
|
|
state = State_Dead;
|
|
game.time_dead = 0;
|
|
continue;
|
|
}
|
|
|
|
for(int i = 0; i < game.rect_count; i++) {
|
|
rect_physics(&game.rects[i], game.rects[i].meta, game.time);
|
|
}
|
|
|
|
if(game.forced_player_rota)
|
|
game.player_rota += game.forced_player_rota * dt;
|
|
else {
|
|
if(state == State_Playing && rotate_left)
|
|
game.player_rota += 1.57 * dt;
|
|
if(state == State_Playing && rotate_right)
|
|
game.player_rota -= 1.57 * dt;
|
|
}
|
|
if(game.player_rota > M_PI)
|
|
game.player_rota -= 2 * M_PI;
|
|
if(game.player_rota < -M_PI)
|
|
game.player_rota += 2 * M_PI;
|
|
|
|
/* Rendering */
|
|
|
|
dclear(C_BLACK);
|
|
|
|
if(game.time < -5.0 && lv->message != NULL) {
|
|
int x = DWIDTH/2 + 8 * (strcount(lv->message, '\n') + 1);
|
|
|
|
/* Split at newlines */
|
|
char const *str = lv->message;
|
|
while(*str) {
|
|
char const *end = strchrnul(str, '\n');
|
|
duet_text_opt(x, DHEIGHT/2, C_WHITE, C_NONE, DTEXT_CENTER,
|
|
DTEXT_MIDDLE, str, end - str);
|
|
x -= 16;
|
|
str = end + (*end != 0);
|
|
}
|
|
}
|
|
|
|
render_player(PLAYER_X, DHEIGHT/2, game.player_rota);
|
|
for(int i = 0; i < game.rect_count; i++)
|
|
drectoid(&game.rects[i], C_WHITE);
|
|
dupdate();
|
|
}
|
|
|
|
timer_stop(timer);
|
|
return (1);
|
|
}
|