dynamic tiles, tile animations, door logic, spawn and victory
This commit is contained in:
parent
0a9a3a9fae
commit
c2178fd2b0
|
@ -11,9 +11,9 @@ find_package(Gint 2.1 REQUIRED)
|
|||
|
||||
set(SOURCES
|
||||
src/animation.c
|
||||
src/main.c
|
||||
src/engine.c
|
||||
# ...
|
||||
src/game.c
|
||||
src/main.c
|
||||
)
|
||||
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
|
||||
set(ASSETS
|
||||
|
@ -22,6 +22,7 @@ set(ASSETS
|
|||
set(ASSETS_fx
|
||||
assets-fx/levels.png
|
||||
assets-fx/lv1.png
|
||||
assets-fx/tilesheet.png
|
||||
assets-fx/title.png
|
||||
assets-fx/spritesheet.png
|
||||
assets-fx/font_mystere.png
|
||||
|
|
BIN
MystNB.g1a
BIN
MystNB.g1a
Binary file not shown.
|
@ -1,10 +1,10 @@
|
|||
##### #####
|
||||
# ##### #
|
||||
# a a #
|
||||
##A### ###A##
|
||||
# a a #
|
||||
# b a #
|
||||
## ### ### ##
|
||||
# a b #
|
||||
# ~ ##### @ #
|
||||
##### #####
|
||||
|
||||
a: #.
|
||||
A: #.
|
||||
b: .#
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 860 B |
|
@ -24,6 +24,13 @@ struct sheet const anim_player = {
|
|||
.frame_h = 16,
|
||||
};
|
||||
|
||||
extern bopti_image_t img_tilesheet;
|
||||
struct sheet const anim_tiles = {
|
||||
.img = &img_tilesheet,
|
||||
.frame_w = 10,
|
||||
.frame_h = 20,
|
||||
};
|
||||
|
||||
/* anim_frame(): Get a frame from a sheet */
|
||||
static struct anim_frame anim_frame(struct sheet const *sheet, int col,int row)
|
||||
{
|
||||
|
@ -44,7 +51,7 @@ void dframe(int x, int y, struct anim_frame const frame)
|
|||
}
|
||||
|
||||
//---
|
||||
// Animation functions
|
||||
// Player animation functions
|
||||
//---
|
||||
|
||||
int anim_player_idle(struct anim_data *data, int init)
|
||||
|
@ -101,3 +108,75 @@ int anim_player_walking(struct anim_data *data, int init)
|
|||
data->img = anim_frame(&anim_player, data->dir + 4, data->frame / 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//---
|
||||
// Tile animation functions
|
||||
//---
|
||||
|
||||
int anim_tile_start(struct anim_data *data, int init)
|
||||
{
|
||||
data->function = anim_tile_start;
|
||||
data->frame = init ? 0 : (data->frame + 1) % 5;
|
||||
data->duration = (data->frame == 0 ? 1000 : 150);
|
||||
data->img = anim_frame(&anim_tiles, data->frame, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int anim_tile_end(struct anim_data *data, int init)
|
||||
{
|
||||
data->function = anim_tile_end;
|
||||
data->frame = init ? 0 : (data->frame + 1) % 5;
|
||||
data->duration = (data->frame == 0 ? 1000 : 150);
|
||||
data->img = anim_frame(&anim_tiles, data->frame, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int anim_door_closed(struct anim_data *data, GUNUSED int init)
|
||||
{
|
||||
/* Init takes [data->dir] as input */
|
||||
data->function = anim_door_closed;
|
||||
data->frame = 0 + 16 * (data->dir == DIR_LEFT);
|
||||
data->duration = 1000;
|
||||
data->img = anim_frame(&anim_tiles, data->frame & 15,
|
||||
2 + (data->frame >= 16));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int anim_door_opening(struct anim_data *data, int init)
|
||||
{
|
||||
data->function = anim_door_opening;
|
||||
data->frame = init ? 1 + 16 * (data->dir == DIR_LEFT): data->frame + 1;
|
||||
|
||||
if((data->frame & 15) == 6)
|
||||
return anim_door_open(data, 1);
|
||||
|
||||
data->duration = 75;
|
||||
data->img = anim_frame(&anim_tiles, data->frame & 15,
|
||||
2 + (data->frame >= 16));
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int anim_door_open(struct anim_data *data, GUNUSED int init)
|
||||
{
|
||||
data->function = anim_door_open;
|
||||
data->frame = 6 + 16 * (data->dir == DIR_LEFT);
|
||||
data->duration = 1000;
|
||||
data->img = anim_frame(&anim_tiles, data->frame & 15,
|
||||
2 + (data->frame >= 16));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int anim_door_closing(struct anim_data *data, int init)
|
||||
{
|
||||
data->function = anim_door_closing;
|
||||
data->frame = init ? 7 + 16 * (data->dir == DIR_LEFT): data->frame + 1;
|
||||
|
||||
if((data->frame & 15) == 11)
|
||||
return anim_door_closed(data, 1);
|
||||
|
||||
data->duration = 75;
|
||||
data->img = anim_frame(&anim_tiles, data->frame & 15,
|
||||
2 + (data->frame >= 16));
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -7,9 +7,17 @@ struct anim_data;
|
|||
|
||||
/* anim_function_t: Update function for each animation */
|
||||
typedef int (anim_function_t)(struct anim_data *data, int init);
|
||||
|
||||
anim_function_t anim_player_idle;
|
||||
anim_function_t anim_player_walking;
|
||||
|
||||
anim_function_t anim_tile_start;
|
||||
anim_function_t anim_tile_end;
|
||||
anim_function_t anim_door_closed;
|
||||
anim_function_t anim_door_opening;
|
||||
anim_function_t anim_door_open;
|
||||
anim_function_t anim_door_closing;
|
||||
|
||||
/* struct anim_frame: Subrectangle of an animation sheet */
|
||||
struct anim_frame
|
||||
{
|
||||
|
|
245
src/engine.c
245
src/engine.c
|
@ -1,29 +1,201 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/std/string.h>
|
||||
#include "engine.h"
|
||||
|
||||
#define CELL_X(x) (-2 + 10 * (x))
|
||||
#define CELL_Y(y) (-3 + 10 * (y))
|
||||
|
||||
//---
|
||||
// Utilities
|
||||
//---
|
||||
|
||||
|
||||
/* Determine the cycle pattern for a certain door */
|
||||
static char const *map_door_cycle(struct map const *map, int x, int y)
|
||||
{
|
||||
int door = map->tiles[y * map->w + x];
|
||||
int cycle_id = -1;
|
||||
|
||||
if(door >= TILE_VDOOR && door < TILE_VDOOR + 8)
|
||||
cycle_id = door - TILE_VDOOR;
|
||||
else if(door >= TILE_HDOOR && door < TILE_HDOOR + 8)
|
||||
cycle_id = door - TILE_HDOOR + 8;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
return map->door_cycle + map->door_cycle_index[cycle_id];
|
||||
}
|
||||
|
||||
/* Check whether a cell of the map is walkable */
|
||||
static bool map_walkable(struct game const *game, int x, int y)
|
||||
{
|
||||
/* Refuse to walk on walls */
|
||||
int tile = game->map->tiles[y * game->map->w + x];
|
||||
if(tile == TILE_WALL) return false;
|
||||
|
||||
/* Refuse to walk on closed doors */
|
||||
for(int t = 0; t < game->dynamic_tile_count; t++)
|
||||
{
|
||||
struct dynamic_tile const *dt = &game->dynamic_tiles[t];
|
||||
if(dt->x != x || dt->y != y) continue;
|
||||
|
||||
char const *cycle = map_door_cycle(game->map, x, y);
|
||||
if(!dt->state2 && cycle[dt->state] == '#')
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---
|
||||
// Map loading
|
||||
//---
|
||||
|
||||
void engine_load(struct game *game, struct map const *map)
|
||||
{
|
||||
game->map = map;
|
||||
game->time = 0;
|
||||
|
||||
for(int p = 0; p < PLAYER_COUNT + 1; p++)
|
||||
game->players[p] = NULL;
|
||||
|
||||
memset(&game->dynamic_tiles, 0,
|
||||
MAP_DYNAMIC_TILES * sizeof(struct dynamic_tile));
|
||||
|
||||
/* Create dynamic tiles for suitable tiles in the map */
|
||||
int t = 0;
|
||||
|
||||
for(int y = 0; y < map->h && t < MAP_DYNAMIC_TILES; y++)
|
||||
for(int x = 0; x < map->w && t < MAP_DYNAMIC_TILES; x++)
|
||||
{
|
||||
int tile = map->tiles[y*map->w + x];
|
||||
struct dynamic_tile *dt = &game->dynamic_tiles[t];
|
||||
|
||||
dt->y = y;
|
||||
dt->x = x;
|
||||
dt->state = 0;
|
||||
|
||||
int is_dynamic = 1;
|
||||
|
||||
if(tile == TILE_START)
|
||||
{
|
||||
dt->idle = !anim_tile_start(&dt->anim, 1);
|
||||
}
|
||||
else if(tile == TILE_END)
|
||||
{
|
||||
dt->idle = !anim_tile_end(&dt->anim, 1);
|
||||
}
|
||||
else if(tile >= TILE_KEY && tile < TILE_KEY + 8)
|
||||
{
|
||||
/* TODO: Initial keys' dynamic tile information */
|
||||
}
|
||||
else if((tile >= TILE_VDOOR && tile < TILE_VDOOR + 8) ||
|
||||
(tile >= TILE_HDOOR && tile < TILE_HDOOR + 8))
|
||||
{
|
||||
dt->anim.dir = (tile < TILE_HDOOR) ? DIR_UP : DIR_LEFT;
|
||||
char const *cycle = map_door_cycle(map, x, y);
|
||||
|
||||
if(cycle[dt->state] == '#')
|
||||
dt->idle = !anim_door_closed(&dt->anim, 1);
|
||||
else
|
||||
dt->idle = !anim_door_open(&dt->anim, 1);
|
||||
|
||||
}
|
||||
else is_dynamic = 0;
|
||||
|
||||
t += is_dynamic;
|
||||
}
|
||||
|
||||
game->dynamic_tile_count = t;
|
||||
}
|
||||
|
||||
void engine_spawn(struct game *game)
|
||||
{
|
||||
struct map const *map = game->map;
|
||||
int p = 0;
|
||||
|
||||
for(int y = 0; y < map->h && game->players[p]; y++)
|
||||
for(int x = 0; x < map->w && game->players[p]; x++)
|
||||
{
|
||||
/* Try to spawn a player at (x,y) */
|
||||
if(map->tiles[y*map->w + x] == TILE_START)
|
||||
{
|
||||
struct player *player = game->players[p];
|
||||
|
||||
player->y = y;
|
||||
player->x = x;
|
||||
player->dir = DIR_DOWN;
|
||||
player->anim.dir = DIR_DOWN;
|
||||
player->idle = !anim_player_idle(&player->anim, 1);
|
||||
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool engine_all_players_idle(struct game *game)
|
||||
{
|
||||
for(int p = 0; game->players[p]; p++)
|
||||
{
|
||||
if(!game->players[p]->idle) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool engine_all_dynamic_tiles_idle(struct game *game)
|
||||
{
|
||||
for(int t = 0; t < game->dynamic_tile_count; t++)
|
||||
{
|
||||
if(!game->dynamic_tiles[t].idle) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool engine_wins(struct game *game, struct player *player)
|
||||
{
|
||||
/* First check that the player is participating in this game */
|
||||
bool found = false;
|
||||
for(int p = 0; game->players[p] && !found; p++)
|
||||
{
|
||||
if(game->players[p] == player) found = true;
|
||||
}
|
||||
if(!found) return false;
|
||||
|
||||
int tile = game->map->tiles[player->y * game->map->w + player->x];
|
||||
return (tile == TILE_END);
|
||||
}
|
||||
|
||||
//---
|
||||
// Animations
|
||||
//---
|
||||
|
||||
void engine_tick(struct game *game, int dt)
|
||||
void engine_tick(struct game *game, int delta_time)
|
||||
{
|
||||
game->time += dt;
|
||||
game->time += delta_time;
|
||||
|
||||
/* Update the animations for every player */
|
||||
for(int p = 0; game->players[p]; p++)
|
||||
{
|
||||
struct player *player = game->players[p];
|
||||
|
||||
player->anim.duration -= dt;
|
||||
player->anim.duration -= delta_time;
|
||||
if(player->anim.duration > 0) continue;
|
||||
|
||||
/* Call the animation function to generate the next frame */
|
||||
player->idle = !player->anim.function(&player->anim, 0);
|
||||
}
|
||||
|
||||
/* Update animations for dynamic tiles */
|
||||
for(int t = 0; t < game->dynamic_tile_count; t++)
|
||||
{
|
||||
struct dynamic_tile *dt = &game->dynamic_tiles[t];
|
||||
|
||||
dt->anim.duration -= delta_time;
|
||||
if(dt->anim.duration > 0) continue;
|
||||
|
||||
dt->idle = !dt->anim.function(&dt->anim, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -37,11 +209,24 @@ static void engine_draw_player(struct player const *player)
|
|||
player->anim.img);
|
||||
}
|
||||
|
||||
static void engine_draw_dynamic_tile(struct dynamic_tile const *dt)
|
||||
{
|
||||
/* The -10 is hardcoded to suit the format of the tilesheet */
|
||||
dframe(CELL_X(dt->x) + dt->anim.dx,
|
||||
CELL_Y(dt->y) + dt->anim.dy - 10,
|
||||
dt->anim.img);
|
||||
}
|
||||
|
||||
void engine_draw(struct game const *game)
|
||||
{
|
||||
dclear(C_WHITE);
|
||||
dimage(0, 0, game->map->img);
|
||||
|
||||
for(int t = 0; t < game->dynamic_tile_count; t++)
|
||||
{
|
||||
engine_draw_dynamic_tile(&game->dynamic_tiles[t]);
|
||||
}
|
||||
|
||||
for(int p = 0; game->players[p]; p++)
|
||||
{
|
||||
engine_draw_player(game->players[p]);
|
||||
|
@ -52,13 +237,6 @@ void engine_draw(struct game const *game)
|
|||
// Physics
|
||||
//---
|
||||
|
||||
/* Check whether a cell of the map is walkable */
|
||||
static int map_walkable(struct map const *map, int x, int y)
|
||||
{
|
||||
int tile = map->tiles[y * map->w + x];
|
||||
return (tile != TILE_WALL);
|
||||
}
|
||||
|
||||
int engine_move(struct game *game, struct player *player, int dir)
|
||||
{
|
||||
int dx = (dir == DIR_RIGHT) - (dir == DIR_LEFT);
|
||||
|
@ -73,7 +251,7 @@ int engine_move(struct game *game, struct player *player, int dir)
|
|||
player->anim.dir = dir;
|
||||
|
||||
/* Only move the player if the destination is walkable */
|
||||
if(!map_walkable(game->map, player->x + dx, player->y + dy))
|
||||
if(!map_walkable(game, player->x + dx, player->y + dy))
|
||||
{
|
||||
/* If not, set the new idle animation */
|
||||
if(dir != olddir)
|
||||
|
@ -91,3 +269,48 @@ int engine_move(struct game *game, struct player *player, int dir)
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void engine_finish_turn(struct game *game)
|
||||
{
|
||||
/* TODO: Have players pick up keys and open corresponding doors */
|
||||
|
||||
/* Update door cycles */
|
||||
for(int t = 0; t < game->dynamic_tile_count; t++)
|
||||
{
|
||||
struct dynamic_tile *dt = &game->dynamic_tiles[t];
|
||||
char const *cycle = map_door_cycle(game->map, dt->x, dt->y);
|
||||
if(!cycle) continue;
|
||||
|
||||
/* Determine current open/closed status */
|
||||
int current_status = dt->state2 ? '.' : cycle[dt->state];
|
||||
|
||||
/* Move to next cycle state */
|
||||
dt->state++;
|
||||
if(cycle[dt->state] == ' ' || cycle[dt->state] == 0)
|
||||
dt->state = 0;
|
||||
dt->state2 = 0;
|
||||
|
||||
/* Determine next open/closed status (this might be different
|
||||
from the cycle state if a player standing in the door
|
||||
prevents if from closing) */
|
||||
int new_status = cycle[dt->state];
|
||||
|
||||
for(int p = 0; game->players[p]; p++)
|
||||
{
|
||||
struct player *player = game->players[p];
|
||||
if(player->x == dt->x && player->y == dt->y)
|
||||
{
|
||||
new_status = '.';
|
||||
dt->state2 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(new_status == current_status) continue;
|
||||
|
||||
/* Set animations when changing status */
|
||||
if(new_status == '#')
|
||||
dt->idle = !anim_door_closing(&dt->anim, 1);
|
||||
else if(new_status == '.')
|
||||
dt->idle = !anim_door_opening(&dt->anim, 1);
|
||||
}
|
||||
}
|
||||
|
|
44
src/engine.h
44
src/engine.h
|
@ -2,12 +2,16 @@
|
|||
#define _MYSTNB_ENGINE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <gint/display.h>
|
||||
#include "animation.h"
|
||||
|
||||
/* Maximum number of players */
|
||||
#define PLAYER_COUNT 1
|
||||
|
||||
/* Maximum number of dynamic tiles on the map */
|
||||
#define MAP_DYNAMIC_TILES 32
|
||||
|
||||
/* Time per engine tick (ms) */
|
||||
#define ENGINE_TICK 25
|
||||
|
||||
|
@ -24,7 +28,7 @@ struct player
|
|||
int x, y;
|
||||
/* Direction currently facing */
|
||||
int dir;
|
||||
/* Whether playing is currently idle (ie. can move) */
|
||||
/* Whether player is currently idle (ie. can move) */
|
||||
int idle;
|
||||
/* Current animation function and data */
|
||||
struct anim_data anim;
|
||||
|
@ -63,17 +67,50 @@ enum map_tile
|
|||
TILE_HDOOR = 32,
|
||||
};
|
||||
|
||||
/* struct dynamic_tile: Dynamic tile information */
|
||||
struct dynamic_tile
|
||||
{
|
||||
/* Position */
|
||||
int x, y;
|
||||
/* Current state */
|
||||
int state;
|
||||
int state2;
|
||||
/* Whether animation is idle */
|
||||
int idle;
|
||||
/* Current animation */
|
||||
struct anim_data anim;
|
||||
};
|
||||
|
||||
/* struct game: A running game with a map and some players */
|
||||
struct game
|
||||
{
|
||||
/* Current map */
|
||||
struct map *map;
|
||||
struct map const *map;
|
||||
/* Players */
|
||||
struct player *players[PLAYER_COUNT + 1];
|
||||
/* Current game time (ms) */
|
||||
int time;
|
||||
/* Dynamic tiles */
|
||||
struct dynamic_tile dynamic_tiles[MAP_DYNAMIC_TILES];
|
||||
/* Number of dynamic tiles */
|
||||
int dynamic_tile_count;
|
||||
};
|
||||
|
||||
/* Load map with no players */
|
||||
void engine_load(struct game *game, struct map const *map);
|
||||
|
||||
/* Spawn all the players on the map */
|
||||
void engine_spawn(struct game *game);
|
||||
|
||||
/* Check whether all players are idle */
|
||||
bool engine_all_players_idle(struct game *game);
|
||||
|
||||
/* Check whether all dynamic tiles are idle */
|
||||
bool engine_all_dynamic_tiles_idle(struct game *game);
|
||||
|
||||
/* Check whether a player stands on the exit */
|
||||
bool engine_wins(struct game *game, struct player *player);
|
||||
|
||||
/* Update animations */
|
||||
void engine_tick(struct game *game, int dt);
|
||||
|
||||
|
@ -84,4 +121,7 @@ void engine_draw(struct game const *game);
|
|||
0 otherwise (collisions or out-of-bounds moves) */
|
||||
int engine_move(struct game *game, struct player *player, int direction);
|
||||
|
||||
/* Process automatic actions at the end of a turn */
|
||||
void engine_finish_turn(struct game *game);
|
||||
|
||||
#endif /* _MYSTNB_ENGINE_H */
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
#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_configure(TIMER_ANY, ENGINE_TICK*1000,
|
||||
GINT_CALL(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;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _MYSTNB_GAME_H
|
||||
#define _MYSTNB_GAME_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Play the level, returns whether player completed the level */
|
||||
bool play_level(int level);
|
||||
|
||||
#endif /* _MYSTNB_GAME_H */
|
83
src/main.c
83
src/main.c
|
@ -1,8 +1,8 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/timer.h>
|
||||
#include <gint/clock.h>
|
||||
#include <gint/gint.h>
|
||||
|
||||
#include "game.h"
|
||||
#include "engine.h"
|
||||
|
||||
static void draw_menu(int selected)
|
||||
|
@ -54,88 +54,19 @@ static int main_menu(void)
|
|||
selected--;
|
||||
if(key == KEY_RIGHT && selected < 8)
|
||||
selected++;
|
||||
if(key == KEY_EXIT)
|
||||
gint_osmenu();
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
static int callback_tick(volatile int *tick)
|
||||
{
|
||||
*tick = 1;
|
||||
return TIMER_CONTINUE;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GUNUSED int level = main_menu();
|
||||
|
||||
struct player singleplayer = {
|
||||
.x = 2,
|
||||
.y = 3,
|
||||
.dir = DIR_DOWN,
|
||||
.anim.function = anim_player_idle,
|
||||
.anim.dir = DIR_DOWN,
|
||||
};
|
||||
singleplayer.idle = !anim_player_idle(&singleplayer.anim, 1);
|
||||
|
||||
extern struct map map_lv1;
|
||||
|
||||
struct game game = {
|
||||
.map = &map_lv1,
|
||||
.players = { &singleplayer, NULL },
|
||||
.time = 0,
|
||||
};
|
||||
|
||||
/* Global tick clock */
|
||||
static volatile int tick = 1;
|
||||
|
||||
int t = timer_configure(TIMER_ANY, ENGINE_TICK*1000,
|
||||
GINT_CALL(callback_tick, &tick));
|
||||
if(t >= 0) timer_start(t);
|
||||
|
||||
int level_finished = 0;
|
||||
while(!level_finished)
|
||||
while(1)
|
||||
{
|
||||
while(!tick) sleep();
|
||||
tick = 0;
|
||||
|
||||
engine_draw(&game);
|
||||
dupdate();
|
||||
|
||||
int dir = get_inputs();
|
||||
int turn_finished = 0;
|
||||
|
||||
if(dir >= 0)
|
||||
{
|
||||
turn_finished = engine_move(&game, &singleplayer, dir);
|
||||
}
|
||||
if(turn_finished)
|
||||
{
|
||||
/* Update doors, etc */
|
||||
}
|
||||
|
||||
engine_tick(&game, ENGINE_TICK);
|
||||
GUNUSED int level = main_menu();
|
||||
play_level(1);
|
||||
}
|
||||
|
||||
if(t >= 0) timer_stop(t);
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue