From 8d36df2b04dfa5d747dd21ae2ddf7d349524674a Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 25 Aug 2021 03:23:24 +0300 Subject: [PATCH] level save/load functions --- tools/dunger/Makefile | 2 +- tools/dunger/src/level.c | 136 ++++++++++++++++++++++++++++++++++++++++++---- tools/dunger/src/level.h | 7 ++- tools/dunger/src/main.c | 18 +++--- 4 files changed, 141 insertions(+), 22 deletions(-) diff --git a/tools/dunger/Makefile b/tools/dunger/Makefile index fe42807..4e252e1 100644 --- a/tools/dunger/Makefile +++ b/tools/dunger/Makefile @@ -4,7 +4,7 @@ dep = $(src:.c=.d) bin = dunger CFLAGS = -pedantic -Wall -g -LDFLAGS = -lGL -lGLU -lglut -lutk -ldrawtext +LDFLAGS = -lGL -lGLU -lglut -lutk -ldrawtext -ltreestore $(bin): $(obj) $(CC) -o $@ $(obj) $(LDFLAGS) diff --git a/tools/dunger/src/level.c b/tools/dunger/src/level.c index 5825924..3a1a9bf 100644 --- a/tools/dunger/src/level.c +++ b/tools/dunger/src/level.c @@ -1,27 +1,143 @@ #include #include #include +#include +#include #include "level.h" -struct level *create_level(int xsz, int ysz) +int init_level(struct level *lvl, int xsz, int ysz) { - struct level *lvl; - - if(!(lvl = malloc(sizeof *lvl))) { - return 0; - } if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) { free(lvl); - return 0; + return -1; } lvl->width = xsz; lvl->height = ysz; - return lvl; + return 0; } -void free_level(struct level *lvl) +void destroy_level(struct level *lvl) { if(!lvl) return; free(lvl->cells); - free(lvl); +} + +int load_level(struct level *lvl, const char *fname) +{ + FILE *fp; + struct ts_node *ts, *node, *iter; + int sz, cx, cy; + struct cell *cell; + + if(!(fp = fopen(fname, "rb"))) { + return -1; + } + + if(!(ts = ts_load(fname))) { + fprintf(stderr, "failed to load level: %s\n", fname); + return -1; + } + if(strcmp(ts->name, "dunged_level") != 0) { + fprintf(stderr, "invalid or corrupted level file: %s\n", fname); + ts_free_tree(ts); + return -1; + } + + if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) { + sz = 32; + } + + if(init_level(lvl, sz, sz) == -1) { + fprintf(stderr, "failed to initialize a %dx%d level\n", sz, sz); + ts_free_tree(ts); + return -1; + } + + iter = ts->child_list; + while(iter) { + node = iter; + iter = iter->next; + + if(strcmp(node->name, "cell") == 0) { + cx = ts_get_attr_int(node, "x", -1); + cy = ts_get_attr_int(node, "y", -1); + if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) { + fprintf(stderr, "ignoring cell with invalid or missing coordinates\n"); + continue; + } + cell = lvl->cells + cy * sz + cx; + cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK; + /* TODO wall tiles and detail objects */ + } + } + + ts_free_tree(ts); + return 0; +} + +int save_level(struct level *lvl, const char *fname) +{ + int i, j; + struct ts_node *root, *node; + struct ts_attr *attr; + struct cell *cell; + + if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) { + goto err; + } + + if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "size") == -1) { + ts_free_attr(attr); + goto err; + } + ts_set_valuei(&attr->val, lvl->width); + ts_add_attr(root, attr); + + for(i=0; iheight; i++) { + for(j=0; jwidth; j++) { + cell = lvl->cells + i * lvl->width + j; + if(cell->type == CELL_SOLID) continue; + + if(!(node = ts_alloc_node()) || ts_set_node_name(node, "cell") == -1) { + ts_free_node(node); + goto err; + } + if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "x") == -1) { + ts_free_attr(attr); + goto err; + } + ts_set_valuei(&attr->val, j); + ts_add_attr(node, attr); + if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "y") == -1) { + ts_free_attr(attr); + goto err; + } + ts_set_valuei(&attr->val, i); + ts_add_attr(node, attr); + + if(cell->type == CELL_BLOCKED) { + if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "blocked") == -1) { + ts_free_attr(attr); + goto err; + } + ts_set_valuei(&attr->val, 1); + ts_add_attr(node, attr); + } + + ts_add_child(root, node); + } + } + + if(ts_save(root, fname) == -1) { + fprintf(stderr, "failed to save level: %s\n", fname); + ts_free_tree(root); + return -1; + } + ts_free_tree(root); + return 0; + +err: + fprintf(stderr, "failed to construct treestore tree\n"); + ts_free_tree(root); + return -1; } diff --git a/tools/dunger/src/level.h b/tools/dunger/src/level.h index 7a10103..76006f3 100644 --- a/tools/dunger/src/level.h +++ b/tools/dunger/src/level.h @@ -19,7 +19,10 @@ struct level { }; -struct level *create_level(int xsz, int ysz); -void free_level(struct level *lvl); +int init_level(struct level *lvl, int xsz, int ysz); +void destroy_level(struct level *lvl); + +int load_level(struct level *lvl, const char *fname); +int save_level(struct level *lvl, const char *fname); #endif /* LEVEL_H_ */ diff --git a/tools/dunger/src/main.c b/tools/dunger/src/main.c index ed456f7..847d00c 100644 --- a/tools/dunger/src/main.c +++ b/tools/dunger/src/main.c @@ -47,7 +47,7 @@ int mousex, mousey, clickx, clicky; static float uiscale = 1.0f; #define UISPLIT 150 -int splitx; +static int splitx; #define FONTSZ 16 static struct dtx_font *uifont; @@ -55,7 +55,7 @@ static utk_widget *uiroot, *uiwin_new; static utk_widget *uigrab; static utk_widget *cbox_newsz; -static struct level *lvl; +static struct level lvl; int main(int argc, char **argv) @@ -141,11 +141,11 @@ static int init(void) utk_set_size(uiwin_new, utk_get_width(vbox) + pad * 2.0f, utk_get_height(vbox) + pad * 2.0f); - if(!(lvl = create_level(32, 32))) { + if(init_level(&lvl, 32, 32) == -1) { fprintf(stderr, "failed to create level\n"); return -1; } - if(init_lview(lvl) == -1) { + if(init_lview(&lvl) == -1) { return -1; } @@ -159,7 +159,7 @@ static int init(void) static void cleanup(void) { destroy_lview(); - free_level(lvl); + destroy_level(&lvl); dtx_close_font(uifont); utk_close(uiroot); } @@ -316,21 +316,21 @@ static void cb_new_ok(utk_event *ev, void *data) { static int levsz[] = {16, 24, 32}; int sz; - struct level *newlvl; + struct level newlvl; sz = levsz[utk_get_selected(cbox_newsz)]; - if(!(newlvl = create_level(sz, sz))) { + if(init_level(&newlvl, sz, sz) == -1) { utk_message_dialog("failed to create new level", UTK_MSG_TYPE_ERROR, UTK_MSG_BN_OK, cb_cancel, 0); return; } - free_level(lvl); + destroy_level(&lvl); destroy_lview(); lvl = newlvl; - init_lview(newlvl); + init_lview(&lvl); utk_hide(uiwin_new); uigrab = 0; -- 1.7.10.4