aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-06-25 22:44:23 +0100
committerJuan J. Martinez <jjm@usebox.net>2023-06-25 22:44:23 +0100
commit6bd6757583510ba3edf75451309e4b8ec8c9b0f1 (patch)
treee63f401238e4118ff6d1670ea86508f0181c19ea
parent2d7fbc07acf0c5766d662d2629e72600b65f744b (diff)
downloadgold-mine-run-6bd6757583510ba3edf75451309e4b8ec8c9b0f1.tar.gz
gold-mine-run-6bd6757583510ba3edf75451309e4b8ec8c9b0f1.zip
Add entity system, add new enemy (snake)
-rw-r--r--TODO.md3
-rw-r--r--data/stage.json114
-rw-r--r--src/Makefile2
-rw-r--r--src/entities.c72
-rw-r--r--src/entities.h34
-rw-r--r--src/game.c6
-rw-r--r--src/map.c45
-rw-r--r--src/map.h5
-rw-r--r--src/player.c17
-rw-r--r--src/player.h1
-rw-r--r--src/snake.c69
-rw-r--r--src/snake.h7
-rwxr-xr-xtools/map.py2
13 files changed, 358 insertions, 19 deletions
diff --git a/TODO.md b/TODO.md
index 556dfb2..792c458 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,7 +1,5 @@
# TODO
-- entity system
- - free/used lists
- pick ups
- extra time
- bonuses
@@ -9,7 +7,6 @@
- key / doors
- end of stage
- enemies
- - pattern (snake)
- flying (bat)
- free
- tracker
diff --git a/data/stage.json b/data/stage.json
index 2ae131e..9095400 100644
--- a/data/stage.json
+++ b/data/stage.json
@@ -41,6 +41,118 @@
"width":16,
"x":16,
"y":128
+ },
+ {
+ "height":16,
+ "id":2,
+ "name":"Snake",
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":216,
+ "y":128
+ },
+ {
+ "height":16,
+ "id":3,
+ "name":"Snake",
+ "properties":[
+ {
+ "name":"dir",
+ "type":"string",
+ "value":"left"
+ }],
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":288,
+ "y":128
+ },
+ {
+ "height":16,
+ "id":4,
+ "name":"Snake",
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":184,
+ "y":152
+ },
+ {
+ "height":16,
+ "id":5,
+ "name":"Snake",
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":32,
+ "y":152
+ },
+ {
+ "height":16,
+ "id":6,
+ "name":"Snake",
+ "properties":[
+ {
+ "name":"dir",
+ "type":"string",
+ "value":"left"
+ }],
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":280,
+ "y":152
+ },
+ {
+ "height":16,
+ "id":7,
+ "name":"Snake",
+ "properties":[
+ {
+ "name":"dir",
+ "type":"string",
+ "value":"left"
+ }],
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":112,
+ "y":152
+ },
+ {
+ "height":16,
+ "id":8,
+ "name":"Snake",
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":144,
+ "y":32
+ },
+ {
+ "height":16,
+ "id":9,
+ "name":"Snake",
+ "properties":[
+ {
+ "name":"dir",
+ "type":"string",
+ "value":"left"
+ }],
+ "rotation":0,
+ "type":"",
+ "visible":true,
+ "width":16,
+ "x":112,
+ "y":80
}],
"opacity":1,
"type":"objectgroup",
@@ -49,7 +161,7 @@
"y":0
}],
"nextlayerid":4,
- "nextobjectid":2,
+ "nextobjectid":10,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.7.2",
diff --git a/src/Makefile b/src/Makefile
index 8f3c13a..4c26b5b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,6 +1,6 @@
BIN := ../game.exe
CC := i586-pc-msdosdjgpp-gcc
-CFLAGS := -I. -c -Wall -Werror -pedantic -O2 -march=i386
+CFLAGS := -I. -c -Wall -Werror -pedantic -O2 -march=i386 -DDEBUG
LDFLAGS := -s
IMGS := $(wildcard ../data/*.png)
diff --git a/src/entities.c b/src/entities.c
new file mode 100644
index 0000000..be976ea
--- /dev/null
+++ b/src/entities.c
@@ -0,0 +1,72 @@
+#include <stdint.h>
+#include <string.h>
+
+#include "vga.h"
+#include "map.h"
+#include "data.h"
+
+#include "entities.h"
+
+#define MAX_ENTITY 32
+
+static Entity entities[MAX_ENTITY];
+static uint8_t last;
+
+void entities_init()
+{
+ memset(entities, 0, sizeof(Entity) * MAX_ENTITY);
+ last = 0;
+}
+
+Entity *entities_new()
+{
+ for (uint8_t i = 0; i < MAX_ENTITY; i++)
+ {
+ if (entities[i].used == 0)
+ {
+ memset(&entities[i], 0, sizeof(Entity));
+ entities[i].used = 1;
+
+ if (i >= last)
+ last = i + 1;
+
+ return &entities[i];
+ }
+ }
+
+ return NULL;
+}
+
+void entities_update()
+{
+ Entity *e = entities;
+
+ for (uint8_t i = 0; i < last; i++, e++)
+ if (e->used)
+ e->update(e);
+}
+
+void entities_erase()
+{
+ Entity *e = entities + last - 1;
+
+ for (uint8_t i = 0; i < last; i++, e--)
+ if (e->used)
+ {
+ Rect dst = { e->x, e->y + MAP_OFFS_Y, 16, 16 };
+ blit(e->bg, &dst);
+ }
+}
+
+void entities_draw()
+{
+ Entity *e = entities;
+
+ for (uint8_t i = 0; i < last; i++, e++)
+ if (e->used)
+ {
+ Rect dst = { e->x, e->y + MAP_OFFS_Y, 16, 16 };
+ read_buffer(e->bg, &dst);
+ blitrc(binary_sprites_start, &e->frames[e->dir * 4 + e->frame], &dst);
+ }
+}
diff --git a/src/entities.h b/src/entities.h
new file mode 100644
index 0000000..e553390
--- /dev/null
+++ b/src/entities.h
@@ -0,0 +1,34 @@
+#ifndef _ENTITIES_H
+#define _ENTITIES_H
+
+#define DIR_RIGHT 0
+#define DIR_LEFT 1
+
+#define WALK_DELAY 8
+
+typedef struct entity_s
+{
+ uint8_t used;
+ uint16_t x;
+ uint16_t y;
+ uint8_t dir;
+ uint8_t frame;
+ uint8_t delay;
+ uint8_t gravity;
+ uint8_t flag;
+ uint8_t bg[16 * 16];
+ /* expected to be 2 directions per 4 frames max; 8 Rect */
+ const Rect *frames;
+ void (*update)(struct entity_s *e);
+} Entity;
+
+void entities_init();
+
+Entity *entities_new();
+
+void entities_update();
+
+void entities_erase();
+void entities_draw();
+
+#endif /* _ENTITIES_H */
diff --git a/src/game.c b/src/game.c
index c489417..001ce21 100644
--- a/src/game.c
+++ b/src/game.c
@@ -7,6 +7,7 @@
#include "map.h"
#include "data.h"
#include "timer.h"
+#include "entities.h"
#include "player.h"
@@ -114,6 +115,7 @@ void run_game()
map_init(binary_stage_start);
map_render();
+ entities_draw();
player_draw();
timer_start(GAME_TIME_MAX, &clock_updated);
@@ -129,10 +131,14 @@ void run_game()
if (hud)
hud_render();
+ /* erase first the last we draw */
player_erase();
+ entities_erase();
player_update();
+ entities_update();
+ entities_draw();
player_draw();
wait_vsync();
diff --git a/src/map.c b/src/map.c
index 4c5390f..c62c5c1 100644
--- a/src/map.c
+++ b/src/map.c
@@ -1,18 +1,33 @@
#include <stdint.h>
+#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include "vga.h"
#include "data.h"
+#include "entities.h"
#include "player.h"
+#include "snake.h"
#include "map.h"
+typedef enum
+{
+ Player = 0,
+ Snake,
+} EntityType;
+
/* current map; set via map_init */
static const uint8_t *cmap;
static uint8_t gold[MAP_W * MAP_H];
static uint8_t total_gold;
+static void (* const init[])(Entity *) =
+{
+ snake_init,
+};
+
void map_init(const uint8_t map[])
{
cmap = map;
@@ -27,18 +42,40 @@ void map_init(const uint8_t map[])
if (gold[i] != 0xff)
total_gold++;
+ entities_init();
+
+ Entity *e;
+
/* spawn entities, 0xff is the list terminator */
for (
const uint8_t *ent = map + MAP_W * MAP_H * 2;
*ent != 0xff;
ent += 4
)
- switch (*ent)
+ {
+ /* the player is not part of the entity system */
+ if (*ent == Player)
{
- case Player:
- player_init(ent[1] * MAP_TILE_W, ent[2] * MAP_TILE_H, ent[3] & 1);
- break;
+ player_init(ent[1] * MAP_TILE_W, ent[2] * MAP_TILE_H, ent[3] & 1);
+ continue;
}
+
+ e = entities_new();
+#ifdef DEBUG
+ if (!e)
+ {
+ set_mode(3);
+ fprintf(stderr, "ERROR: run out of entities\n");
+ exit(1);
+ }
+#endif
+
+ e->x = ent[1] * MAP_TILE_W;
+ e->y = ent[2] * MAP_TILE_H;
+ e->dir = ent[3] & 1;
+
+ init[*ent - 1](e);
+ }
}
void map_render()
diff --git a/src/map.h b/src/map.h
index 992c982..42f8da7 100644
--- a/src/map.h
+++ b/src/map.h
@@ -14,11 +14,6 @@
#define MAP_FIRST_BLOCKED 40
#define MAP_FIRST_DEADLY 100
-typedef enum
-{
- Player = 0,
-} EntityType;
-
void map_init(const uint8_t map[]);
void map_render();
diff --git a/src/player.c b/src/player.c
index 856cafd..ae50348 100644
--- a/src/player.c
+++ b/src/player.c
@@ -6,17 +6,14 @@
#include "data.h"
#include "game.h"
+#include "entities.h"
#include "player.h"
-#define DIR_RIGHT 0
-#define DIR_LEFT 1
-
#define FRAME_STANDING 0
#define FRAME_JUMPING 4
#define FRAME_DYING 5
#define WALK_CYCLE_FRAMES 4
-#define WALK_DELAY 8
#define GRAVITY_OFF 0
/* XXX: subtract 1 to get the value from gravity_seq */
@@ -298,6 +295,18 @@ void player_draw()
blitrc(binary_sprites_start, &frames[dir][frame], &dst);
}
+uint8_t player_collision(Entity *e)
+{
+ if (invuln || dying)
+ return 0;
+
+ if (y < e->y + 16 && e->y < y + 16
+ && x < e->x + 8 && e->x < x + 8)
+ return 1;
+
+ return 0;
+}
+
void player_hit()
{
/* TODO: pickaxe */
diff --git a/src/player.h b/src/player.h
index 9767fbe..104bfee 100644
--- a/src/player.h
+++ b/src/player.h
@@ -7,6 +7,7 @@ void player_update();
void player_erase();
void player_draw();
+uint8_t player_collision(Entity *e);
void player_hit();
#endif /* _PLAYER_H */
diff --git a/src/snake.c b/src/snake.c
new file mode 100644
index 0000000..e81a1c8
--- /dev/null
+++ b/src/snake.c
@@ -0,0 +1,69 @@
+#include <stdint.h>
+
+#include <vga.h>
+#include "map.h"
+#include "entities.h"
+
+#include "player.h"
+
+#include "snake.h"
+
+static const Rect frames[2 * 4] =
+{
+ /* right */
+ { 0, 32, 144, 144 },
+ { 16, 32, 144, 144 },
+ /* not used */
+ { 0, 0, 144, 144 },
+ { 0, 0, 144, 144 },
+
+ /* left */
+ { 32, 32, 144, 144 },
+ { 48, 32, 144, 144 },
+ /* not used */
+ { 0, 0, 144, 144 },
+ { 0, 0, 144, 144 }
+};
+
+void snake_init(Entity *e)
+{
+ e->frames = (const Rect *)frames;
+ e->update = snake_update;
+}
+
+void snake_update(Entity *e)
+{
+ if (e->delay & 1)
+ {
+ if (e->dir == DIR_RIGHT)
+ {
+ if (map_is_blocked(e->x + 16, e->y + 15)
+ || !map_is_blocked(e->x + 16, e->y + 16))
+ e->dir = DIR_LEFT;
+ else
+ e->x++;
+ }
+ else
+ {
+ /* dir is LEFT */
+ if (map_is_blocked(e->x - 1, e->y + 15)
+ || !map_is_blocked(e->x - 1, e->y + 16))
+ e->dir = DIR_RIGHT;
+ else
+ e->x--;
+ }
+ }
+
+ if (player_collision(e))
+ {
+ player_hit();
+ /* change direction */
+ e->dir ^= 1;
+ }
+
+ if (e->delay++ == WALK_DELAY + 4)
+ {
+ e->delay = 0;
+ e->frame ^= 1;
+ }
+}
diff --git a/src/snake.h b/src/snake.h
new file mode 100644
index 0000000..48f22e9
--- /dev/null
+++ b/src/snake.h
@@ -0,0 +1,7 @@
+#ifndef _SNAKE_H
+#define _SNAKE_H
+
+void snake_init(Entity *e);
+void snake_update(Entity *e);
+
+#endif /* _SNAKE_H */
diff --git a/tools/map.py b/tools/map.py
index 7e0210f..8464c28 100755
--- a/tools/map.py
+++ b/tools/map.py
@@ -10,7 +10,7 @@ __version__ = "1.0"
ld = os.environ.get("LD", "i586-pc-msdosdjgpp-ld")
strip = os.environ.get("STRIP", "i586-pc-msdosdjgpp-strip")
-entity_types = ("Player",)
+entity_types = ("Player", "Snake")
def get_layer(data, name):