mirror of https://git.sr.ht/~kikoodx/momento
298 lines
7.2 KiB
C
298 lines
7.2 KiB
C
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
/* Copyright (C) 2021 KikooDX */
|
|
|
|
#include "conf.h"
|
|
#include "filepaths.h"
|
|
#include "game_state.h"
|
|
#include "input.h"
|
|
#include "level.h"
|
|
#include "levelselection.h"
|
|
#include "mainmenu.h"
|
|
#include "particles.h"
|
|
#include "pause.h"
|
|
#include "player.h"
|
|
#include "titlescreen.h"
|
|
#include "trail.h"
|
|
#include "transition.h"
|
|
#include "zxcolors.h"
|
|
#include <gint/clock.h>
|
|
#include <gint/display.h>
|
|
#include <gint/gint.h>
|
|
#include <gint/keyboard.h>
|
|
#include <gint/timer.h>
|
|
#include <gint/usb-ff-bulk.h>
|
|
|
|
#ifdef RECORDING
|
|
#define DUPDATE() \
|
|
do { \
|
|
dupdate(); \
|
|
if (usb_is_open()) \
|
|
usb_fxlink_screenshot(1); \
|
|
} while (0);
|
|
#else
|
|
#define DUPDATE() dupdate();
|
|
#endif
|
|
|
|
#define PANIC(msg) \
|
|
do { \
|
|
dclear(ZX_BLACK); \
|
|
dprint_opt(DWIDTH / 2, DHEIGHT / 2, ZX_RED, C_NONE, \
|
|
DTEXT_CENTER, DTEXT_MIDDLE, "ERROR: %s", msg); \
|
|
DUPDATE(); \
|
|
getkey(); \
|
|
return 0; \
|
|
} while (0);
|
|
#define LOAD_LEVEL() \
|
|
do { \
|
|
gint_world_switch(GINT_CALL(level_load_binary)); \
|
|
if (fatal_error == -1) \
|
|
PANIC(fatal_error_msg); \
|
|
particles_init(); \
|
|
trail_init(); \
|
|
player = player_init(); \
|
|
} while (0);
|
|
|
|
extern int level_id;
|
|
extern int fatal_error;
|
|
extern char *fatal_error_msg;
|
|
|
|
extern const font_t font_main;
|
|
|
|
static int callback(volatile int *arg);
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
int i;
|
|
int timer;
|
|
int player_return_code;
|
|
int draw_pause;
|
|
int frameskip = 0;
|
|
/* int level_pack_beaten; */
|
|
enum TransitionMode transition_previous_mode;
|
|
enum GameState game_state = TitleScreen;
|
|
volatile int has_ticked = 1;
|
|
|
|
struct Player player;
|
|
struct Input input = input_init();
|
|
struct TitleScreen titlescreen = titlescreen_init();
|
|
struct LevelSelection levelselection = levelselection_init();
|
|
struct MainMenu mainmenu = mainmenu_init();
|
|
struct Pause pause = pause_init();
|
|
struct Transition transition;
|
|
particles_init();
|
|
|
|
#ifdef RECORDING
|
|
/* open usb for screenshots */
|
|
usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL};
|
|
usb_open(interfaces, GINT_CALL_NULL);
|
|
#endif
|
|
|
|
/* set font */
|
|
dfont(&font_main);
|
|
|
|
init_level_binaries();
|
|
|
|
/* load level */
|
|
level_id = 0;
|
|
gint_world_switch(GINT_CALL(level_load_binary));
|
|
if (fatal_error == -1)
|
|
PANIC(fatal_error_msg);
|
|
/* timer setup */
|
|
timer = timer_configure(TIMER_ANY, 1000000 / TARGET_FPS,
|
|
GINT_CALL(callback, &has_ticked));
|
|
if (timer == -1)
|
|
PANIC("timer_configure failed");
|
|
timer_start(timer);
|
|
|
|
/* initialize the player (has to be done after level loading */
|
|
player = player_init();
|
|
|
|
/* main game loop */
|
|
while (1) {
|
|
/* skip render frames */
|
|
i = 1 + frameskip;
|
|
while (i-- > 0) {
|
|
#ifndef RECORDING
|
|
/* frameskip adjustement */
|
|
if (has_ticked - 1 > frameskip)
|
|
frameskip = has_ticked - 1;
|
|
#endif
|
|
|
|
/* speed limiter */
|
|
while (!has_ticked)
|
|
sleep();
|
|
while (has_ticked)
|
|
has_ticked = 0;
|
|
|
|
/* update */
|
|
input_update(&input);
|
|
|
|
switch (game_state) {
|
|
case TitleScreen:
|
|
if (titlescreen_update(&titlescreen, input))
|
|
game_state = MainMenu;
|
|
break;
|
|
case MainMenu:
|
|
if (mainmenu_update(&mainmenu, input))
|
|
game_state = LevelSelection;
|
|
break;
|
|
case LevelSelection:
|
|
if (levelselection_update(&levelselection,
|
|
input)) {
|
|
game_state = Playing;
|
|
/* set level according to
|
|
* selected pack */
|
|
level_id = levelselection.pack_cursor *
|
|
LVL_PER_PACK;
|
|
LOAD_LEVEL();
|
|
transition = transition_init(
|
|
H_TRANS_SPD, ZX_BLUE,
|
|
TransitionHIn);
|
|
}
|
|
break;
|
|
case Playing:
|
|
if (transition.mode == TransitionNone) {
|
|
trail_update(player);
|
|
particles_update();
|
|
player_return_code =
|
|
player_update(&player, input);
|
|
switch (player_return_code) {
|
|
case -1:
|
|
game_state = GamePause;
|
|
break;
|
|
case 1:
|
|
level_id += 1;
|
|
transition = transition_init(
|
|
H_TRANS_SPD, ZX_BLUE,
|
|
TransitionHOut);
|
|
break;
|
|
case 2:
|
|
transition = transition_init(
|
|
V_TRANS_SPD, ZX_RED,
|
|
TransitionVOut);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
transition_previous_mode =
|
|
transition_update(&transition);
|
|
if (transition_previous_mode !=
|
|
transition.mode &&
|
|
transition_previous_mode !=
|
|
TransitionNone) {
|
|
switch (transition_previous_mode) {
|
|
case TransitionNone:
|
|
break;
|
|
case TransitionHIn:
|
|
break;
|
|
case TransitionHOut:
|
|
/* end level pack */
|
|
if (level_id % 4 == 0) {
|
|
game_state = PackDone;
|
|
/* level_pack_beaten =
|
|
level_id / 4; */
|
|
}
|
|
LOAD_LEVEL();
|
|
transition = transition_init(
|
|
transition.speed,
|
|
transition.color,
|
|
TransitionHIn);
|
|
break;
|
|
case TransitionVIn:
|
|
break;
|
|
case TransitionVOut:
|
|
LOAD_LEVEL();
|
|
transition = transition_init(
|
|
transition.speed,
|
|
transition.color,
|
|
TransitionVIn);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case GamePause:
|
|
if (pause_update(&pause, input)) {
|
|
game_state = Playing;
|
|
/* pause draw takes is _very_ slow,
|
|
* reset frameskip to compensate */
|
|
frameskip = 0;
|
|
has_ticked = 0;
|
|
}
|
|
break;
|
|
case PackDone:
|
|
game_state = LevelSelection;
|
|
break;
|
|
default:
|
|
PANIC("missing game_state case (update)");
|
|
break;
|
|
}
|
|
}
|
|
/* draw */
|
|
draw_pause = 0;
|
|
dclear(ZX_BLACK);
|
|
switch (game_state) {
|
|
case TitleScreen:
|
|
titlescreen_draw(titlescreen);
|
|
break;
|
|
case MainMenu:
|
|
mainmenu_draw(mainmenu);
|
|
break;
|
|
case LevelSelection:
|
|
levelselection_draw(levelselection);
|
|
break;
|
|
case GamePause:
|
|
draw_pause = 1;
|
|
/* fallthrough */
|
|
case Playing:
|
|
level_draw();
|
|
trail_draw();
|
|
particles_draw();
|
|
trail_draw();
|
|
player_draw(player);
|
|
transition_draw(transition);
|
|
if (!draw_pause)
|
|
break;
|
|
/* GamePause */
|
|
pause_draw(pause);
|
|
break;
|
|
case PackDone:
|
|
break;
|
|
default:
|
|
PANIC("missing game_state case (draw)");
|
|
break;
|
|
}
|
|
DUPDATE();
|
|
|
|
/* return to main menu */
|
|
/* TODO don't hardcode this */
|
|
if (keydown(KEY_MENU)) {
|
|
#ifdef RECORDING
|
|
if (usb_is_open())
|
|
usb_close();
|
|
#endif
|
|
gint_osmenu();
|
|
if (game_state == Playing)
|
|
game_state = GamePause;
|
|
}
|
|
}
|
|
|
|
timer_stop(timer);
|
|
#ifdef RECORDING
|
|
if (usb_is_open())
|
|
usb_close();
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
callback(volatile int *arg)
|
|
{
|
|
*arg += 1;
|
|
return 0;
|
|
}
|