Duet/src/main.c

276 lines
7.5 KiB
C
Raw Normal View History

2021-08-21 11:48:06 +02:00
#include <gint/display.h>
#include <gint/keyboard.h>
2021-08-21 14:00:35 +02:00
#include <gint/timer.h>
#include <gint/gint.h>
#include <gint/cpu.h>
#include <gint/drivers/r61524.h>
2021-08-21 14:00:35 +02:00
#include <fxlibc/printf.h>
#include <string.h>
2021-08-21 20:57:56 +02:00
#include <stdlib.h>
2021-08-21 14:00:35 +02:00
#include "duet.h"
2021-08-21 11:48:06 +02:00
2021-08-21 20:57:56 +02:00
/* Game state */
typedef enum {
State_Playing,
State_Dead,
State_Rewind,
2021-08-21 21:48:47 +02:00
State_Transition,
2021-08-22 00:41:42 +02:00
State_EpisodeTransition,
2021-08-21 20:57:56 +02:00
State_Finale,
} state_t;
2021-08-21 12:11:24 +02:00
2021-08-21 23:46:47 +02:00
/* All levels, classified by episode */
episode_t episodes[] = {
{
.name = "ignorance",
.level_count = 5,
.levels = (level_t *[]){
&level1, &level2, &level3, &level4, &level5
},
},
{
.name = "denial",
.level_count = 6,
.levels = (level_t *[]){
&level6, &level7, &level8, &level9, &level10,
&level11,
},
},
{
.name = "anger",
.level_count = 5,
.levels = (level_t *[]){
&level12, &level13, &level14, &level15, &level16,
},
},
{
.name = "bargaining",
.level_count = 6,
.levels = (level_t *[]){
&level17, &level18, &level19, &level20, &level21,
&level22,
},
},
};
int episode_count = 4;
void load_level(game_t *game, level_t const *lv)
{
game->level = lv;
game->time = -10.0;
2021-08-21 20:57:56 +02:00
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;
}
2021-08-21 11:48:06 +02:00
int main(void)
{
2021-08-21 14:08:53 +02:00
__printf_enable_fp();
2021-08-21 14:00:35 +02:00
2021-08-21 20:57:56 +02:00
/* Azur trickz for less tearing */
r61524_set(0x010, 0x0010);
2021-08-21 23:46:47 +02:00
int current_episode = 0;
int current_level = 0;
main_menu(&current_episode, &current_level);
2021-08-21 22:52:08 +02:00
game_t game;
2021-08-21 23:12:08 +02:00
memset(&game, 0x00, sizeof game);
2021-08-21 23:46:47 +02:00
load_level(&game, episodes[current_episode].levels[current_level]);
2021-08-21 14:49:01 +02:00
2021-08-21 20:57:56 +02:00
state_t state = State_Playing;
2021-08-22 00:41:42 +02:00
if(current_level == 0) {
state = State_EpisodeTransition;
game.time_episode_transition = 0;
game.time = -13.0;
}
2021-08-21 20:57:56 +02:00
/* Direction of time (with a factor regulating game speed) */
float const time_direction_forward = 2.7;
2021-08-21 21:28:14 +02:00
float const time_direction_rewind = -40;
2021-08-21 20:57:56 +02:00
volatile int need_frame = 1;
int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame));
2021-08-21 23:12:08 +02:00
if(timer >= 0) timer_start(timer);
2021-08-21 14:49:01 +02:00
2021-08-21 14:08:53 +02:00
while (1) {
level_t const *lv = game.level;
2021-08-21 14:49:01 +02:00
while (need_frame == 0) sleep();
need_frame = 0;
2021-08-21 21:28:14 +02:00
/* Time management */
2021-08-21 20:57:56 +02:00
float time_direction = lv->tempo * time_direction_forward;
if(state == State_Rewind)
time_direction = time_direction_rewind;
2021-08-21 21:28:14 +02:00
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;
}
2021-08-21 21:48:47 +02:00
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;
}
}
2021-08-22 00:41:42 +02:00
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.forced_player_rota = 0;
}
if(game.time_episode_transition >= 3.0) {
game.time_episode_transition = 0;
state = State_Playing;
}
}
2021-08-21 21:28:14 +02:00
2021-08-21 20:57:56 +02:00
float dt = (1.0 / 30) * time_direction;
game.time += dt;
2021-08-21 14:00:35 +02:00
2021-08-21 14:49:01 +02:00
/* Input analysis */
bool rotate_left=false, rotate_right=false;
2021-08-21 14:08:53 +02:00
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)) {
2021-08-21 14:49:01 +02:00
rotate_left = true;
2021-08-21 14:08:53 +02:00
}
if (keydown(KEY_0)) {
2021-08-21 14:49:01 +02:00
rotate_right = true;
2021-08-21 14:08:53 +02:00
}
2021-08-21 14:00:35 +02:00
2021-08-21 20:57:56 +02:00
/* Level transitions */
2021-08-21 14:49:01 +02:00
// End of level
2021-08-21 21:28:14 +02:00
if(state == State_Playing &&
game.time >= lv->blocks[lv->block_count-1].time + 5) {
2021-08-22 00:41:42 +02:00
bool changed_episode = false;
2021-08-21 23:46:47 +02:00
current_level++;
if(current_level >= episodes[current_episode].level_count) {
current_episode++;
current_level = 0;
2021-08-22 00:41:42 +02:00
changed_episode = true;
2021-08-21 23:46:47 +02:00
}
if(current_episode >= episode_count)
break;
2021-08-21 23:46:47 +02:00
load_level(&game, episodes[current_episode].levels[current_level]);
2021-08-21 21:48:47 +02:00
2021-08-22 00:41:42 +02:00
if(changed_episode) {
state = State_EpisodeTransition;
game.time_episode_transition = 0;
game.forced_player_rota = -game.player_rota / 1.0;
game.time = -13.0;
continue;
}
else {
state = State_Transition;
game.time_transition = 0;
game.forced_player_rota = -game.player_rota / 1.0;
continue;
}
}
2021-08-21 21:28:14 +02:00
// 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;
}
2021-08-21 14:49:01 +02:00
/* Physics */
2021-08-21 14:00:35 +02:00
2021-08-21 21:28:14 +02:00
if(state == State_Playing && player_collision(&game)) {
state = State_Dead;
game.time_dead = 0;
continue;
}
2021-08-21 14:49:01 +02:00
2021-08-21 20:57:56 +02:00
for(int i = 0; i < game.rect_count; i++) {
rect_physics(&game.rects[i], game.rects[i].meta, game.time);
2021-08-21 14:49:01 +02:00
}
2021-08-21 21:28:14 +02:00
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;
2021-08-21 14:49:01 +02:00
/* Rendering */
2021-08-21 21:28:14 +02:00
dclear(C_BLACK);
2021-08-21 14:00:35 +02:00
2021-08-22 00:41:42 +02:00
if(state == State_Playing && game.time < -5.0 && lv->message) {
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);
}
}
2021-08-22 00:41:42 +02:00
if(state == State_EpisodeTransition) {
duet_text_opt(DWIDTH/2, DHEIGHT/2, C_WHITE, C_NONE, DTEXT_CENTER,
DTEXT_MIDDLE, episodes[current_episode].name, -1);
}
2021-08-21 22:32:22 +02:00
render_player(PLAYER_X, DHEIGHT/2, game.player_rota);
2021-08-21 20:57:56 +02:00
for(int i = 0; i < game.rect_count; i++)
drectoid(&game.rects[i], C_WHITE);
2021-08-21 14:49:01 +02:00
dupdate();
2021-08-21 14:08:53 +02:00
}
2021-08-21 14:49:01 +02:00
timer_stop(timer);
2021-08-21 14:08:53 +02:00
return (1);
2021-08-21 11:48:06 +02:00
}