load levels
[vrlugburz] / tools / dunger / src / level.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <treestore.h>
6 #include "level.h"
7
8 int init_level(struct level *lvl, int xsz, int ysz)
9 {
10         if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) {
11                 free(lvl);
12                 return -1;
13         }
14         lvl->width = xsz;
15         lvl->height = ysz;
16         return 0;
17 }
18
19 void destroy_level(struct level *lvl)
20 {
21         if(!lvl) return;
22         free(lvl->cells);
23 }
24
25 int load_level(struct level *lvl, const char *fname)
26 {
27         FILE *fp;
28         struct ts_node *ts, *node, *iter;
29         int sz, cx, cy;
30         struct cell *cell;
31
32         if(!(fp = fopen(fname, "rb"))) {
33                 return -1;
34         }
35
36         if(!(ts = ts_load(fname))) {
37                 fprintf(stderr, "failed to load level: %s\n", fname);
38                 return -1;
39         }
40         if(strcmp(ts->name, "dunged_level") != 0) {
41                 fprintf(stderr, "invalid or corrupted level file: %s\n", fname);
42                 ts_free_tree(ts);
43                 return -1;
44         }
45
46         if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) {
47                 sz = 32;
48         }
49
50         if(init_level(lvl, sz, sz) == -1) {
51                 fprintf(stderr, "failed to initialize a %dx%d level\n", sz, sz);
52                 ts_free_tree(ts);
53                 return -1;
54         }
55
56         iter = ts->child_list;
57         while(iter) {
58                 node = iter;
59                 iter = iter->next;
60
61                 if(strcmp(node->name, "cell") == 0) {
62                         cx = ts_get_attr_int(node, "x", -1);
63                         cy = ts_get_attr_int(node, "y", -1);
64                         if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) {
65                                 fprintf(stderr, "ignoring cell with invalid or missing coordinates\n");
66                                 continue;
67                         }
68                         cell = lvl->cells + cy * sz + cx;
69                         cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK;
70                         /* TODO wall tiles and detail objects */
71                 }
72         }
73
74         ts_free_tree(ts);
75         return 0;
76 }
77
78 int save_level(struct level *lvl, const char *fname)
79 {
80         int i, j;
81         struct ts_node *root, *node;
82         struct ts_attr *attr;
83         struct cell *cell;
84
85         if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) {
86                 goto err;
87         }
88
89         if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "size") == -1) {
90                 ts_free_attr(attr);
91                 goto err;
92         }
93         ts_set_valuei(&attr->val, lvl->width);
94         ts_add_attr(root, attr);
95
96         for(i=0; i<lvl->height; i++) {
97                 for(j=0; j<lvl->width; j++) {
98                         cell = lvl->cells + i * lvl->width + j;
99                         if(cell->type == CELL_SOLID) continue;
100
101                         if(!(node = ts_alloc_node()) || ts_set_node_name(node, "cell") == -1) {
102                                 ts_free_node(node);
103                                 goto err;
104                         }
105                         if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "x") == -1) {
106                                 ts_free_attr(attr);
107                                 goto err;
108                         }
109                         ts_set_valuei(&attr->val, j);
110                         ts_add_attr(node, attr);
111                         if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "y") == -1) {
112                                 ts_free_attr(attr);
113                                 goto err;
114                         }
115                         ts_set_valuei(&attr->val, i);
116                         ts_add_attr(node, attr);
117
118                         if(cell->type == CELL_BLOCKED) {
119                                 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "blocked") == -1) {
120                                         ts_free_attr(attr);
121                                         goto err;
122                                 }
123                                 ts_set_valuei(&attr->val, 1);
124                                 ts_add_attr(node, attr);
125                         }
126
127                         ts_add_child(root, node);
128                 }
129         }
130
131         if(ts_save(root, fname) == -1) {
132                 fprintf(stderr, "failed to save level: %s\n", fname);
133                 ts_free_tree(root);
134                 return -1;
135         }
136         ts_free_tree(root);
137         return 0;
138
139 err:
140         fprintf(stderr, "failed to construct treestore tree\n");
141         ts_free_tree(root);
142         return -1;
143 }