cake
/
pixeltd
Archived
1
0
Fork 0

some basic turret placement

This commit is contained in:
Thomas Touhey 2020-12-26 16:21:03 +01:00
parent 37d2c89388
commit c192ae6e1f
6 changed files with 228 additions and 97 deletions

BIN
assets-fx/img/castle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
assets-fx/img/wall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -1,10 +1,11 @@
##################
##################
> # # x##
##### ## # # #####
## ## # # #####
#### ### # #####
########## # #####
########## #####
##################
##################
####################
####################
#> # # x##
##### ## # # #######
## ## # # #######
#### ### # #######
########## # #######
########## #######
########## # #######
####################
####################

View File

@ -13,18 +13,22 @@ def convert(input, output, params, target):
#
# Format of the map:
#
# [general data: 16 bytes]
# - width (1 byte)
# - height (1 byte)
# - camera_x (1 byte)
# - camera_y (1 byte)
# - spawn_x (1 byte), where to spawn enemies
# - spawn_y (1 byte), where to spawn enemies
# - cur_x (1 byte), default cursor pos
# - cur_y (1 byte), default cursor pos
# - number of enemy path elements (1 byte)
# - unused (9 bytes)
#
# [offsets and stuff: 16 bytes]
# - offset of grid data from file start (2 bytes, big endian)
# - offset of enemy path data from file start (2 bytes, big endian)
# - unused (12 bytes)
#
# [big data thingies]
# - grid data (variable)
# - enemy path (variable)
#
@ -33,6 +37,7 @@ def convert(input, output, params, target):
# 0x00: basic placement tile
# 0x01: basic enemy path
# 0x02: castle
# 0x03: wall
#
# every element of enemy path is:
# - delta (1 byte):
@ -43,19 +48,24 @@ def convert(input, output, params, target):
lines = open(input, "r").read().splitlines()
w, h = 18, 10
spawn_x, spawn_y = None, None
arr_x, arr_y = None, None
grid_data = b''
if len(lines) != h:
raise fxconv.FxconvError(f"should have 10 lines, has {len(lines)}")
h = len(lines)
if h <= 0:
raise fxconv.FxconvError(f"should have one or more lines")
w = None
for line_no, line in enumerate(lines):
line = line.strip()
if len(line) != w:
raise fxconv.FxconvError(f"line no. {line_no + 1} "
f"should have 18 columns, has {len(line)}")
if w is None:
w = len(line)
if w <= 0:
raise fxconv.FxconvError(f"should have one or more columns")
elif len(line) != w:
raise fxconv.FxconvError(f"inconsistent width: {w} on first line, "
f"{len(line)} on line {line_no + 1}")
for car_no, c in enumerate(line):
if c == '#':
@ -92,6 +102,8 @@ def convert(input, output, params, target):
if (x, y) == (arr_x, arr_y):
return previous + ((x, y),)
elif not x in range(w) or not y in range(h):
pass
elif grid_data[y * w + x] != 1:
pass
elif (x, y) not in previous:
@ -122,9 +134,9 @@ def convert(input, output, params, target):
return x + b'\0' * (round4len(x) - len(x))
data = int(w).to_bytes(1, 'big') + int(h).to_bytes(1, 'big')
data += int(1).to_bytes(1, 'big') + int(1).to_bytes(1, 'big')
data += int(spawn_x).to_bytes(1, 'big')
data += int(spawn_y).to_bytes(1, 'big')
data += int(1).to_bytes(1, 'big') + int(1).to_bytes(1, 'big')
data += int(len(path_data)).to_bytes(1, 'big')
data += b'\0' * 9
data += int(32).to_bytes(2, 'big')

View File

@ -2,7 +2,7 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/timer.h>
#define NENEMIES 96
#include <gint/std/stdlib.h>
/* State definition, as used throughout the main game.
*
@ -22,6 +22,8 @@
* slowed down or have various speeds, allowing some enemies to overtake
* others. */
#define NENEMIES 256
struct enemy {
int alive;
@ -34,6 +36,20 @@ struct enemy {
struct enemy *pdr; /* previous enemy to be drawn */
};
/* For each turret, the data is:
*
* - x, y: the coordinates of the turret. */
#define NTURRETS 256
struct turret {
int exists;
int x, y;
};
/* And the main state definition. */
struct state {
/* Map information:
*
@ -58,20 +74,23 @@ struct state {
int tbsp, tnsp;
int nae;
struct enemy *first_enemy;
struct enemy *enemies;
/* Turrets information:
*
* - net: number of existing turrents.
* - turrets: the turrets. */
int net;
struct turret *turrets;
/* Camera, cursor and display information:
*
* - cam_x, cam_y: camera coordinates, always displays 16x8 tiles
* - cur_x, cur_y: map coordinate for the cursor.
* - drf: draw frame. */
int cam_x, cam_y;
int cur_x, cur_y;
int drf; /* draw frame, varies from 0 to 255 and looping */
/* Raw data */
struct enemy enemies[NENEMIES];
};
static struct state state;
@ -80,6 +99,102 @@ static struct state state;
* Game functions.
* --- */
/* tile_at(x, y): return the type of the tile at coordinates (x, y).
*
* If out of bounds, a basic placement tile (id. 0) will be returned */
static inline int tile_at(int x, int y)
{
if (x < 0 || x >= state.w || y < 0 || y >= state.h)
return 3;
return state.grid[y * state.w + x];
}
/* init(map): initialize the game state. */
static void init(uint8_t const *raw)
{
int i;
/* Initialize the map information. */
state.w = raw[0];
state.h = raw[1];
state.sp_x = raw[2];
state.sp_y = raw[3];
state.nep = raw[6];
state.grid = &raw[(raw[16] << 8) | raw[17]];
state.ep = &raw[(raw[18] << 8) | raw[19]];
/* Initialize AI information */
state.tbsp = 99;
state.tnsp = state.tbsp;
state.nae = 0;
state.first_enemy = NULL;
state.enemies = malloc(NENEMIES * sizeof (struct enemy));
for (i = 0; i < NENEMIES; i++) {
state.enemies[i].alive = 0;
state.enemies[i].pdr = NULL;
}
/* Initialize turret information */
state.net = 0;
state.turrets = malloc(NTURRETS * sizeof (struct turret));
for (i = 0; i < NTURRETS; i++)
state.turrets[i].exists = 0;
/* Initialize display information */
state.cur_x = raw[4];
state.cur_y = raw[5];
state.drf = 0;
}
static void deinit()
{
free(state.enemies);
}
/* place_turret(): place a turret at the cursor position. */
static void place_turret()
{
int i;
struct turret *tp, *ntp = NULL;
/* Check if we can place a turret here. */
if (tile_at(state.cur_x, state.cur_y) != 0)
return ;
/* Check if the slot is free. */
for (i = 0; i < NTURRETS; i++) {
tp = &state.turrets[i];
if (!tp->exists) {
if (!ntp)
ntp = tp;
continue ;
}
if (tp->x != state.cur_x || tp->y != state.cur_y)
continue ;
return ;
}
/* The slot is free, let's go */
if (!ntp)
return ;
ntp->exists = 1;
ntp->x = state.cur_x;
ntp->y = state.cur_y;
}
/* tick(): tick the game engine. */
static void tick()
@ -146,7 +261,7 @@ static void tick()
/* TODO: use a given type of enemy? */
ep->nstepf = 20;
ep->nstepf = 5;
ep->nfwait = ep->nstepf;
state.nae++;
@ -154,35 +269,39 @@ static void tick()
}
}
/* tile_cam(x, y): return the type of the tile at coordinates (x, y) relative
* to the current camera position.
*
* If out of bounds, a basic placement tile (id. 0) will be returned */
static inline int tile_cam(int x, int y)
{
x += state.cam_x;
y += state.cam_y;
if (x < 0 || x >= state.w || y < 0 || y >= state.h)
return 0;
return state.grid[y * state.w + x];
}
/* draw(): basically the drawing function for everything. */
#define tile_cam(x, y) \
(tile_at((x) + state.cur_x - 7, (y) + state.cur_y - 3))
#define x_cam(x) \
((x) - ((state.cur_x - 7) << 3))
#define y_cam(y) \
((y) - ((state.cur_y - 3) << 3))
static void draw()
{
extern bopti_image_t img_enemy_base, img_castle, img_wall;
int x, y;
dclear(C_WHITE);
/* draw the grid */
/* Draw the enemy base. */
dimage(x_cam(state.sp_x << 3), y_cam(state.sp_y << 3), &img_enemy_base);
/* Draw the grid. */
for (y = 0; y < 8; y++) {
for (x = 0; x < 16; x++) {
int ox = x << 3, oy = y << 3;
int tile = tile_cam(x, y);
int ox = x * 8, oy = y * 8;
/* Get the tiles. */
if (tile == 2)
dimage(ox, oy, &img_castle);
else if (tile == 3)
dimage(ox, oy, &img_wall);
if (tile == 1 || tile == 2) {
/* above, below, left, right */
@ -215,16 +334,29 @@ static void draw()
extern bopti_image_t img_enemy;
for (ep = state.first_enemy; ep; ep = ep->pdr)
dimage(ep->x - (state.cam_x << 3), ep->y - (state.cam_y << 3),
&img_enemy);
dimage(x_cam(ep->x), y_cam(ep->y), &img_enemy);
}
/* Draw the turrets. */
{
struct turret *tp;
extern bopti_image_t img_basic_turret;
int i;
for (i = 0; i < NTURRETS; i++) {
tp = &state.turrets[i];
if (tp->exists)
dimage(x_cam(tp->x << 3), y_cam(tp->y << 3), &img_basic_turret);
}
}
/* Draw the cursor */
{
int d = state.drf & 128 ? 2 : 0;
int ox = state.cur_x - state.cam_x + 1;
int oy = state.cur_y - state.cam_y + 1;
int d = state.drf & 4 ? 2 : 0;
int ox = 7 << 3, oy = 3 << 3;
dline(ox + d, oy, ox + d + 1, oy, C_BLACK);
dline(ox + d + 4, oy, ox + d + 5, oy, C_BLACK);
@ -237,10 +369,6 @@ static void draw()
dline(ox + 7, oy + d + 4, ox + 7, oy + d + 5, C_BLACK);
}
/* Debug data. */
dprint(16, 96, C_BLACK, "state.tnsp = 0x%08X", state.tnsp);
/* okay we can update now */
dupdate();
@ -254,6 +382,10 @@ static void draw()
* It's a best-effort system, so as the default timer is 128Hz, we'll check
* each time for 54ms, which is 7/128. */
#define TIMERES_US 7813
#define TIMECNT_DI 6
#define TIMECNT_EV 4
static int timer_callback(int volatile *tick_finished)
{
*tick_finished = 1;
@ -265,56 +397,23 @@ menu_t *game(menu_t *last_menu)
extern uint8_t const map_basic[];
int timer;
int volatile tick_finished = 0;
int etickleft = 2, dtickleft = 1;
int etickleft = TIMECNT_EV, dtickleft = TIMECNT_DI;
(void)last_menu;
{
uint8_t const *raw = map_basic;
int i;
/* Initialize the map information. */
state.w = raw[0];
state.h = raw[1];
state.sp_x = raw[4];
state.sp_y = raw[5];
state.nep = raw[6];
state.grid = &raw[(raw[16] << 8) | raw[17]];
state.ep = &raw[(raw[18] << 8) | raw[19]];
/* Initialize AI information */
state.tbsp = 100;
state.tnsp = state.tbsp;
state.nae = 0;
state.first_enemy = NULL;
for (i = 0; i < NENEMIES; i++) {
state.enemies[i].alive = 0;
state.enemies[i].pdr = NULL;
}
/* Initialize display information */
state.cam_x = raw[2];
state.cam_y = raw[3];
state.cur_x = 1;
state.cur_y = 1;
state.drf = 0;
}
init(map_basic);
/* Setup the timer. */
timer = timer_setup(TIMER_ANY, 54000, &timer_callback, &tick_finished);
timer = timer_setup(TIMER_ANY, TIMERES_US, &timer_callback, &tick_finished);
timer_start(timer);
/* Main loop.
* Some event processing and ticks thingies. */
do {
key_event_t event = getkey_opt(GETKEY_MOD_SHIFT | GETKEY_BACKLIGHT,
&tick_finished);
key_event_t event = getkey_opt(GETKEY_MOD_SHIFT | GETKEY_BACKLIGHT
| GETKEY_MENU, &tick_finished);
switch (event.type) {
case KEYEV_NONE:
@ -324,12 +423,12 @@ menu_t *game(menu_t *last_menu)
tick_finished = 0;
if (!--etickleft) {
etickleft = 2;
etickleft = TIMECNT_EV;
tick();
}
if (!--dtickleft) {
dtickleft = 1;
dtickleft = TIMECNT_DI;
state.drf = (state.drf + 1) & 255;
draw();
@ -338,17 +437,36 @@ menu_t *game(menu_t *last_menu)
case KEYEV_DOWN:
/* Incredible, the player is not dead!
* Let's see what we can do to fulfill their request. */
* Let's see what we can do to fulfill their request. */
if (event.key == KEY_EXE)
goto game_end;
switch (event.key) {
case KEY_UP:
if (state.cur_y > 0)
state.cur_y--;
break;
case KEY_DOWN:
if (state.cur_y < state.h - 1)
state.cur_y++;
break;
case KEY_LEFT:
if (state.cur_x > 0)
state.cur_x--;
break;
case KEY_RIGHT:
if (state.cur_x < state.w - 1)
state.cur_x++;
break;
case KEY_XOT:
place_turret();
break;
}
break;
}
} while (1);
game_end:
/* Deinitialise things that need deinitialising. Duh. */
timer_stop(timer);
deinit();
return no_menu;
}