summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/entity.h11
-rw-r--r--src/funsinit.c3
-rw-r--r--src/loader.c2
-rw-r--r--src/loader.h7
-rw-r--r--src/main.c290
-rw-r--r--src/main.h19
-rw-r--r--src/player.c12
-rw-r--r--src/warp.c62
8 files changed, 313 insertions, 93 deletions
diff --git a/src/entity.h b/src/entity.h
index 354fbc1..fe76feb 100644
--- a/src/entity.h
+++ b/src/entity.h
@@ -9,6 +9,7 @@ struct entity {
int (*update)(struct entity *self);
int (*hurt)(struct entity *self, int damage);
int (*draw)(struct entity *self, int camx, int camy);
+ void (*free)(struct entity *self);
int x, y; // unsigned results in a bunch of weird edge cases
struct velocity {
signed x, y;
@@ -29,3 +30,13 @@ struct entity {
void *texture;
void *ext;
};
+
+struct warp {
+ int (*update)(struct warp *);
+ unsigned x, y;
+ unsigned w, h;
+ unsigned tox, toy;
+ struct hitbox hitbox;
+ unsigned timer;
+ void *ext;
+};
diff --git a/src/funsinit.c b/src/funsinit.c
index 5d15cc4..25ba630 100644
--- a/src/funsinit.c
+++ b/src/funsinit.c
@@ -2,6 +2,9 @@
#include "loader.h"
#include "main.h"
+void *warp_new(struct entities *entities);
+int warp_property(void *const restrict entity, char const *const restrict property, char const *const restrict value);
void funs_init(void) {
+ res_push_fun(warp_new, warp_property, "warp");
}
diff --git a/src/loader.c b/src/loader.c
index f132b7a..2382246 100644
--- a/src/loader.c
+++ b/src/loader.c
@@ -226,7 +226,7 @@ void res_push_collision(struct blob *blob, name_T name) {
collisions = res_push_blob(blob, name, collisions, blob_free_func);
}
-void res_push_fun(struct entity *(*newfun)(void), int (*setfun)(struct entity *const restrict self, char const *const restrict key, char const *const restrict value), name_T name) {
+void res_push_fun(void *(*newfun)(struct entities *entities), int (*setfun)(void *const restrict self, char const *const restrict key, char const *const restrict value), name_T name) {
int found;
struct fun_item new = {.funs = {.newfun = newfun, .setfun = setfun}, .name = name};
struct fun_item *dst = bsearchinsertposition(&new, funs.items, funs.count, sizeof (struct fun_item), res_compare_funs, &found);
diff --git a/src/loader.h b/src/loader.h
index 61f9e3c..b16fd28 100644
--- a/src/loader.h
+++ b/src/loader.h
@@ -2,6 +2,7 @@
#include <stddef.h>
#include "entity.h"
+#include "main.h"
typedef char * name_T;
@@ -11,8 +12,8 @@ struct blob {
};
struct funs {
- struct entity *(*newfun)(void);
- int (*setfun)(struct entity *const restrict self, char const *const restrict key, char const *const restrict value);
+ void *(*newfun)(struct entities *entities);
+ int (*setfun)(void *const restrict self, char const *const restrict key, char const *const restrict value);
};
void res_init(void);
@@ -30,7 +31,7 @@ void res_free_collision(void);
struct blob res_get_collision(name_T const name);
void res_free_fun(void);
-void res_push_fun(struct entity *(*newfun)(void), int (*setfun)(struct entity *const restrict self, char const *const restrict key, char const *const restrict value), name_T name);
+void res_push_fun(void *(*newfun)(struct entities *entities), int (*setfun)(void *const restrict self, char const *const restrict key, char const *const restrict value), name_T name);
struct funs res_get_fun(name_T const name);
int loadResources(char *filename);
diff --git a/src/main.c b/src/main.c
index 2d3e89d..c48deef 100644
--- a/src/main.c
+++ b/src/main.c
@@ -19,6 +19,8 @@
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
+enum game_state game_state = STATE_PLAYING;
+char *game_next_level;
#define WINDOW_WIDTH 160
#define WINDOW_HEIGHT 90
@@ -34,13 +36,134 @@ SDL_Scancode keybinds[] = {
SDL_SCANCODE_S,
};
-struct entity player[1] = {0};
+struct entities entities = {{{0}}, {{0}}, 0, {{0}}, 0}, next_entities = {{{0}}, {{0}}, 0, {{0}}, 0};
-struct entity *player_new(void);
-int player_property(struct entity *const restrict entity, char const *const restrict property, char const *const restrict value);
+void *player_new(struct entities *entities);
+int player_property(void *const restrict entity, char const *const restrict property, char const *const restrict value);
void funs_init(void);
+void entities_free(struct entities *entities) {
+ for (int i = 0, e = 0; i < 64 && e < entities->enemies; i++) {
+ if (entities->enemy[i].state) {
+ e++;
+ if (entities->enemy[i].free != NULL) {
+ entities->enemy[i].free(entities->enemy + i);
+ }
+ }
+ }
+ entities->enemies = 0;
+ #if 0
+ for (int i = 0; i < entities.warps; i++) {
+ entities.warp[i].update(entities.warp + i);
+ }
+ #endif
+ entities->warps = 0;
+}
+
+int entities_load(struct entities *entities, char *data, size_t size, size_t input_bytes) {
+ entities->enemies = 0;
+ entities->warps = 0;
+ data += input_bytes;
+ size -= input_bytes;
+ while (size) {
+ size_t len;
+ if ((len = strnlen(data, size)) == size) {
+ return 1;
+ }
+ char *name = data;
+ struct funs fun = res_get_fun(name);
+ data += len + 1;
+ size -= len + 1;
+ if (fun.newfun) {
+ struct entity *entity = fun.newfun(&next_entities);
+ while (1) {
+ if ((len = strnlen(data, size)) == size) {
+ return 1;
+ } else if (len == 0) {
+ data++;
+ size--;
+ break;
+ }
+ char *key = data;
+ data += len + 1;
+ size -= len + 1;
+ if ((len = strnlen(data, size)) == size) {
+ return 1;
+ }
+ char *value = data;
+ data += len + 1;
+ size -= len + 1;
+ if (fun.setfun(entity, key, value)) {
+ puts(key); puts(value);
+ return 1;
+ }
+ }
+ } else {
+ fprintf(stderr, "warn: unknown entity %s\n", name);
+ while (1) {
+ if ((len = strnlen(data, size)) == size) {
+ return 1;
+ } else if (len == 0) {
+ data++;
+ size--;
+ break;
+ }
+ data += len + 1;
+ size -= len + 1;
+ if ((len = strnlen(data, size)) == size) {
+ return 1;
+ }
+ data += len + 1;
+ size -= len + 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int game_update(void) {
+ if (entities.player[0].update(entities.player)) {
+ return 1;
+ }
+
+ for (int i = 0, e = 0; i < 64 && e < entities.enemies; i++) {
+ if (entities.enemy[i].state) {
+ e++;
+ entities.enemy[i].update(entities.enemy + i);
+ }
+ }
+
+ for (int i = 0; i < entities.warps; i++) {
+ entities.warp[i].update(entities.warp + i);
+ }
+
+ return 0;
+}
+
+void game_render(SDL_Texture *framebuffer, int x, int y) {
+ SDL_SetRenderTarget(renderer, framebuffer);
+ tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
+ entities.player[0].draw(entities.player, x, y);
+ for (int i = 0, e = 0; i < 64 && e < entities.enemies; i++) {
+ if (entities.enemy[i].state) {
+ e++;
+ entities.enemy[i].draw(entities.enemy + i, x, y);
+ }
+ }
+ tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
+ //SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
+}
+
+void game_render_flush(SDL_Texture *framebuffer) {
+ SDL_SetRenderTarget(renderer, NULL);
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+ // then we wait for the next video frame
+ SDL_RenderPresent(renderer);
+}
+
int main(int const argc, char *const *const argv) {
struct option opts[] = {
{"help", 0, NULL, 'h'},
@@ -176,60 +299,19 @@ int main(int const argc, char *const *const argv) {
optind++;
}
}
- struct blob map = res_get_map("untitled");
- tilemap = tilemap_load(map.data, map.size);
- char *a = (char *) map.data + tilemap->input_bytes;
- map.size -= tilemap->input_bytes;
- while (map.size) {
- size_t len;
- if ((len = strnlen(a, map.size)) == map.size) {
- return 1; // hack
- }
- char *name = a;
- puts(name);
- struct funs fun = res_get_fun(name);
- a += len + 1;
- map.size -= len + 1;
- if (fun.newfun) {
- struct entity *entity = fun.newfun();
- while (1) {
- if ((len = strnlen(a, map.size)) == map.size) {
- return 1; // hack
- } else if (len == 0) {
- a++;
- map.size--;
- break;
- }
- char *key = a;
- a += len + 1;
- map.size -= len + 1;
- if ((len = strnlen(a, map.size)) == map.size) {
- return 1; // hack
- }
- char *value = a;
- a += len + 1;
- map.size -= len + 1;
- if (fun.setfun(entity, key, value)) {
- return 1; // hack
- }
- }
- } else {
- while (1) { // hack
- if ((len = strnlen(a, map.size)) == map.size) { // hack
- return 1; // hack
- } else if (len == 0) {
- a++;
- map.size--;
- break;
- }
- a += len + 1;
- map.size -= len + 1;
- }
- }
+
+ struct blob blob = res_get_map("untitled");
+ next_tilemap = tilemap_load(blob.data, blob.size);
+ if (next_tilemap == NULL) {
+ fputs("failed to load initial tilemap\n", stderr);
+ goto end;
}
- //memmem(map.data + tilemap->byte_count, map.size - tilemap->byte_count, (char []) {0, 0}, 2);
- printf("load_tilemap %p\n", (void *) tilemap);
- SDL_SetRenderTarget(renderer, NULL);
+ if (entities_load(&entities, blob.data, blob.size, next_tilemap->input_bytes)) {
+ tilemap_free(next_tilemap);
+ fputs("failed to load initial tilemap\n", stderr);
+ goto end;
+ }
+ tilemap = next_tilemap;
}
/* unsigned error; // identical variable is declared higher up */
@@ -251,10 +333,11 @@ int main(int const argc, char *const *const argv) {
SDL_ShowWindow(window);
- int x = 0, y = 0;
- player_new();
- player_property(player, "x", "40");
- player_property(player, "y", "64");
+ int x = 0, y = 0, fade = 0;
+ player_new(&next_entities);
+ player_property(next_entities.player, "x", "40");
+ player_property(next_entities.player, "y", "64");
+ memcpy(&entities, &next_entities, sizeof (entities));
while (1) {
SDL_Event evt;
while (SDL_PollEvent(&evt)) {
@@ -352,29 +435,72 @@ int main(int const argc, char *const *const argv) {
}
}
- //SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
- if (player[0].update(player)) {
- break; // TODO: game over state
+ switch (game_state) {
+ case STATE_PLAYING:
+ //SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
+ if (game_update()) {
+ goto end; // TODO: game over state
+ }
+
+ x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
+ y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
+ if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
+ if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+
+ game_render(framebuffer, x, y);
+ game_render_flush(framebuffer);
+ break;
+
+ case STATE_FADE_IN:
+ fade += 15;
+ SDL_SetRenderTarget(renderer, NULL);
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, fade);
+ SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+ SDL_RenderPresent(renderer);
+ if (fade == 255) {
+ struct blob blob = res_get_map(game_next_level);
+ next_tilemap = tilemap_load(blob.data, blob.size);
+ if (next_tilemap != NULL) {
+ if (entities_load(&next_entities, blob.data, blob.size, next_tilemap->input_bytes)) {
+ tilemap_free(next_tilemap);
+ } else {
+ tilemap_free(tilemap);
+ tilemap = next_tilemap;
+ entities_free(&entities);
+ memcpy(&entities, &next_entities, sizeof (entities));
+ }
+ }
+ game_state = STATE_FADE_OUT;
+
+ x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
+ y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
+ if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
+ if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+
+ game_render(framebuffer, x, y);
+ SDL_SetRenderTarget(renderer, NULL);
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+ SDL_RenderClear(renderer);
+ }
+ break;
+
+ case STATE_FADE_OUT:
+ fade -= 15;
+ SDL_SetRenderTarget(renderer, NULL);
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, fade);
+ SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+ SDL_RenderPresent(renderer);
+ if (fade == 0) {
+ game_state = STATE_PLAYING;
+ }
+ break;
}
-
- //x += input_right(input_now) - input_left(input_now);
- //y += input_down(input_now) - input_up(input_now);
- x = (player[0].x / 16) - (WINDOW_WIDTH / 2);
- y = (player[0].y / 16) - (WINDOW_HEIGHT / 2);
- if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
- if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
-
- SDL_SetRenderTarget(renderer, framebuffer);
- tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
- player[0].draw(player, x, y);
- tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
- //SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
- SDL_SetRenderTarget(renderer, NULL);
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
- // then we wait for the next video frame
- SDL_RenderPresent(renderer);
}
end:
diff --git a/src/main.h b/src/main.h
index ad0951f..d743ce7 100644
--- a/src/main.h
+++ b/src/main.h
@@ -7,4 +7,21 @@ extern SDL_Renderer *renderer;
extern unsigned input_now;
-extern struct entity player[1];
+extern struct entities {
+ struct entity player[1];
+ struct entity enemy[64];
+ unsigned enemies;
+ struct warp warp[16];
+ unsigned warps;
+} entities, next_entities;
+
+extern enum game_state {
+ STATE_PLAYING,
+ STATE_FADE_IN,
+ STATE_FADE_OUT,
+} game_state;
+
+extern char *game_next_level;
+
+void entities_free(struct entities *entities);
+int entities_load(struct entities *entities, char *data, size_t size, size_t input_bytes);
diff --git a/src/player.c b/src/player.c
index b23b2f0..0f0025e 100644
--- a/src/player.c
+++ b/src/player.c
@@ -114,7 +114,7 @@ static int move(struct entity *self) {
return on_ground;
}
-void anim(struct entity *self, unsigned anim) {
+static void anim(struct entity *self, unsigned anim) {
self->anim = player_anims[anim];
}
@@ -210,8 +210,8 @@ static int player_draw(struct entity *self, int camX, int camY) {
return 0;
}
-struct entity *player_new(void) {
- player[0] = (struct entity) {
+struct entity *player_new(struct entities *entities) {
+ entities->player[0] = (struct entity) {
.update = player_update,
.hurt = player_hurt,
.draw = player_draw,
@@ -228,9 +228,9 @@ struct entity *player_new(void) {
.texture = NULL,
.ext = NULL,
};
- anim(player, PLAYER_A_IDLE);
- player[0].texture = res_get_texture("fywi").data;
- return player + 0;
+ anim(entities->player, PLAYER_A_IDLE);
+ entities->player[0].texture = res_get_texture("fywi").data;
+ return entities->player + 0;
}
int player_property(struct entity *const restrict self, char const *const restrict property, char const *const restrict value) {
diff --git a/src/warp.c b/src/warp.c
new file mode 100644
index 0000000..f36b716
--- /dev/null
+++ b/src/warp.c
@@ -0,0 +1,62 @@
+#include "main.h"
+#include "entity.h"
+#include "loader.h"
+#include "tilemap.h"
+
+static int warp_update(struct warp *self) {
+ if (
+ self->hitbox.left < entities.player[0].hitbox.right &&
+ self->hitbox.right > entities.player[0].hitbox.left &&
+ self->hitbox.top < entities.player[0].hitbox.bottom &&
+ self->hitbox.bottom > entities.player[0].hitbox.top
+ ) {
+ if (self->ext == NULL) {
+ return 0;
+ }
+ game_next_level = self->ext;
+ memcpy(next_entities.player, entities.player, sizeof (entities.player));
+ next_entities.player[0].x = self->tox * 16;
+ next_entities.player[0].y = self->toy * 16;
+ game_state = STATE_FADE_IN;
+ self->ext = NULL;
+ return 0;
+ }
+ return 0;
+}
+
+struct warp *warp_new(struct entities *entities) {
+ entities->warp[entities->warps] = (struct warp) {
+ .update = warp_update,
+ .x = 0, .y = 0,
+ .w = 0, .h = 0,
+ .tox = 0, .toy = 0,
+ .hitbox = {
+ 0, 0, 0, 0,
+ },
+ .timer = 0,
+ .ext = NULL,
+ };
+ return entities->warp + entities->warps++;
+}
+
+int warp_property(struct warp *const restrict self, char const *const restrict property, char const *const restrict value) {
+ if (strcmp(property, "x") == 0) {
+ self->x = atoi(value);
+ } else if (strcmp(property, "y") == 0) {
+ self->y = atoi(value);
+ } else if (strcmp(property, "width") == 0) {
+ self->w = atoi(value);
+ } else if (strcmp(property, "height") == 0) {
+ self->h = atoi(value);
+ } else if (strcmp(property, "tox") == 0) {
+ self->tox = atoi(value);
+ } else if (strcmp(property, "toy") == 0) {
+ self->toy = atoi(value);
+ } else if (strcmp(property, "map") == 0) {
+ self->ext = value;
+ } else {
+ return 1;
+ }
+ self->hitbox = (struct hitbox) {.left = self->x, .top = self->y, .right = self->x + self->w, .bottom = self->y + self->h};
+ return 0;
+}