level save/load functions
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 25 Aug 2021 00:23:24 +0000 (03:23 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 25 Aug 2021 00:23:24 +0000 (03:23 +0300)
tools/dunger/Makefile
tools/dunger/src/level.c
tools/dunger/src/level.h
tools/dunger/src/main.c

index fe42807..4e252e1 100644 (file)
@@ -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)
index 5825924..3a1a9bf 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
+#include <treestore.h>
 #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; i<lvl->height; i++) {
+               for(j=0; j<lvl->width; 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;
 }
index 7a10103..76006f3 100644 (file)
@@ -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_ */
index ed456f7..847d00c 100644 (file)
@@ -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;