#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;
}
static float uiscale = 1.0f;
#define UISPLIT 150
-int splitx;
+static int splitx;
#define FONTSZ 16
static struct dtx_font *uifont;
static utk_widget *uigrab;
static utk_widget *cbox_newsz;
-static struct level *lvl;
+static struct level lvl;
int main(int argc, char **argv)
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;
}
static void cleanup(void)
{
destroy_lview();
- free_level(lvl);
+ destroy_level(&lvl);
dtx_close_font(uifont);
utk_close(uiroot);
}
{
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;