level save/load functions
[vrlugburz] / tools / dunger / src / level.c
index 1e88b5c..3a1a9bf 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <GL/gl.h>
+#include <errno.h>
+#include <treestore.h>
 #include "level.h"
 
-extern int view_width, view_height;
-extern float view_panx, view_pany, view_zoom;
-
-extern int mousex, mousey, splitx;
-
-static int cellsz;
-static struct cell *selcell;
-
-
-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);
 }
 
-void cell_to_pos(struct level *lvl, int cx, int cy, float *px, float *py)
+int load_level(struct level *lvl, const char *fname)
 {
-       if(px) *px = (cx - lvl->width / 2.0f) * cellsz - view_panx + view_width / 2.0f;
-       if(py) *py = (cy - lvl->height / 2.0f) * cellsz - view_pany + view_height / 2.0f;
-}
-
-struct cell *pos_to_cell(struct level *lvl, float px, float py, int *cx, int *cy)
-{
-       int col, row;
-
-       col = (px + view_panx - view_width / 2.0f) / cellsz + lvl->width / 2.0f;
-       row = (py + view_pany - view_height / 2.0f) / cellsz + lvl->height / 2.0f;
-
-       if(cx) *cx = col;
-       if(cy) *cy = row;
+       FILE *fp;
+       struct ts_node *ts, *node, *iter;
+       int sz, cx, cy;
+       struct cell *cell;
 
-       if(col >= 0 && col < lvl->width && row >= 0 && row < lvl->height) {
-               return lvl->cells + row * lvl->width + col;
+       if(!(fp = fopen(fname, "rb"))) {
+               return -1;
        }
-       return 0;
-}
 
-#define LTHICK 0.5f
-static void draw_cell(struct level *lvl, struct cell *cell)
-{
-       int cidx, row, col;
-       float x, y, hsz;
-       static const float colors[][3] = {{0, 0, 0}, {0.6, 0.6, 0.6}, {0.4, 0.2, 0.1}};
-
-       hsz = cellsz * 0.5f;
+       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;
+       }
 
-       cidx = cell - lvl->cells;
-       row = cidx / lvl->width;
-       col = cidx % lvl->width;
+       if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) {
+               sz = 32;
+       }
 
-       cell_to_pos(lvl, col, row, &x, &y);
-       /*printf("c->p: %d,%d -> %f,%f\n", col, row, x, y);
-       pos_to_cell(lvl, x, y, &col, &row);
-       printf("p->c: %f,%f -> %d,%d\n", x, y, col, row);*/
+       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;
+       }
 
-       if(selcell == cell) {
-               glColor3f(0.4, 1.0f, 0.4);
-       } else {
-               glColor3f(0.5f, 0.5f, 0.5f);
+       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 */
+               }
        }
-       glVertex2f(x - hsz, y - hsz);
-       glVertex2f(x + hsz, y - hsz);
-       glVertex2f(x + hsz, y + hsz);
-       glVertex2f(x - hsz, y + hsz);
-
-       x += LTHICK / 2.0f;
-       y += LTHICK / 2.0f;
-       hsz -= LTHICK * 2.0f;
-
-       glColor3fv(colors[cell->type]);
-       glVertex2f(x - hsz, y - hsz);
-       glVertex2f(x + hsz, y - hsz);
-       glVertex2f(x + hsz, y + hsz);
-       glVertex2f(x - hsz, y + hsz);
+
+       ts_free_tree(ts);
+       return 0;
 }
 
-void draw_level(struct level *lvl)
+int save_level(struct level *lvl, const char *fname)
 {
        int i, j;
-       float xsz, ysz, hsz;
+       struct ts_node *root, *node;
+       struct ts_attr *attr;
        struct cell *cell;
 
-       xsz = view_zoom * view_width / lvl->width;
-       ysz = view_zoom * view_height / lvl->height;
-       cellsz = xsz > ysz ? ysz : xsz;
-       hsz = cellsz / 2.0f;
+       if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) {
+               goto err;
+       }
 
-       selcell = pos_to_cell(lvl, mousex + hsz - splitx, view_height - mousey + hsz, 0, 0);
+       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);
 
-       glBegin(GL_QUADS);
-       cell = lvl->cells;
        for(i=0; i<lvl->height; i++) {
                for(j=0; j<lvl->width; j++) {
-                       draw_cell(lvl, cell++);
+                       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);
                }
        }
-       glEnd();
+
+       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;
 }