mystnb/src/game.c

116 lines
2.2 KiB
C
Raw Normal View History

#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/timer.h>
#include <gint/clock.h>
#include "game.h"
#include "engine.h"
/* All maps */
extern struct map map_lv1;
struct map *maps[] = {
&map_lv1,
};
/* Phases of a turn in the game */
enum turn_phase
{
PHASE_IDLE = 0,
PHASE_MOVE = 1,
PHASE_UPDATE = 2,
};
/* Returns a direction to move in */
static int get_inputs(void)
{
int opt = GETKEY_DEFAULT & ~GETKEY_REP_ARROWS;
int timeout = 1;
while(1)
{
key_event_t ev = getkey_opt(opt, &timeout);
if(ev.type == KEYEV_NONE) return -1;
int key = ev.key;
if(key == KEY_DOWN) return DIR_DOWN;
if(key == KEY_RIGHT) return DIR_RIGHT;
if(key == KEY_UP) return DIR_UP;
if(key == KEY_LEFT) return DIR_LEFT;
}
}
/* Notify play_level() that the next frame is due soon */
static int callback_tick(volatile int *tick)
{
*tick = 1;
return TIMER_CONTINUE;
}
bool play_level(int level)
{
if(level < 1 || level > 8) return false;
/* Load the map */
struct game game;
engine_load(&game, maps[level-1]);
/* Create and spawn a solo player */
struct player singleplayer;
game.players[0] = &singleplayer;
engine_spawn(&game);
/* Start the frame timer */
static volatile int tick = 1;
int t = timer_setup(TIMER_ANY, ENGINE_TICK*1000, callback_tick, &tick);
if(t < 0) return false;
timer_start(t);
enum turn_phase phase = PHASE_IDLE;
bool succeeded = false;
while(1)
{
while(!tick) sleep();
tick = 0;
engine_draw(&game);
dupdate();
int dir = get_inputs();
/* If the player inputs a control during IDLE, move them */
if(phase == PHASE_IDLE && dir >= 0)
{
if(engine_move(&game, &singleplayer, dir))
phase = PHASE_MOVE;
}
/* When the move is finished, perform a map update */
else if(phase == PHASE_MOVE && engine_all_players_idle(&game))
{
/* TODO: Winning condition */
if(engine_wins(&game, &singleplayer))
{
succeeded = true;
break;
}
phase = PHASE_UPDATE;
engine_finish_turn(&game);
}
/* When update finishes, start another turn */
else if(phase == PHASE_UPDATE &&
engine_all_dynamic_tiles_idle(&game))
{
phase = PHASE_IDLE;
}
engine_tick(&game, ENGINE_TICK);
}
timer_stop(t);
return succeeded;
}