foo
[vrlugburz] / 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 #include "tileset.h"
8 #include "fs.h"
9
10 int init_level(struct level *lvl, int xsz, int ysz)
11 {
12         memset(lvl, 0, sizeof *lvl);
13
14         if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) {
15                 free(lvl);
16                 return -1;
17         }
18         lvl->width = xsz;
19         lvl->height = ysz;
20         lvl->cell_size = DEF_CELL_SIZE;
21         lvl->px = lvl->py = -1;
22         return 0;
23 }
24
25 void destroy_level(struct level *lvl)
26 {
27         if(!lvl) return;
28         free(lvl->cells);
29         free(lvl->fname);
30         free(lvl->dirname);
31 }
32
33 int load_level(struct level *lvl, const char *fname)
34 {
35         struct ts_node *ts, *node, *iter;
36         int i, j, sz, cx, cy;
37         struct cell *cell;
38         float *vecptr;
39
40         if(!(ts = ts_load(fname))) {
41                 fprintf(stderr, "failed to load level: %s\n", fname);
42                 return -1;
43         }
44         if(strcmp(ts->name, "dunged_level") != 0) {
45                 fprintf(stderr, "invalid or corrupted level file: %s\n", fname);
46                 ts_free_tree(ts);
47                 return -1;
48         }
49
50         if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) {
51                 sz = 32;
52         }
53
54         if(init_level(lvl, sz, sz) == -1) {
55                 fprintf(stderr, "failed to initialize a %dx%d level\n", sz, sz);
56                 ts_free_tree(ts);
57                 return -1;
58         }
59
60         lvl->fname = strdup(fname);
61         if((lvl->dirname = malloc(strlen(fname) + 1))) {
62 #ifndef LEVEL_EDITOR
63                 path_dir(lvl->fname, lvl->dirname);
64 #endif
65         }
66
67         lvl->cell_size = ts_get_attr_num(ts, "cellsize", DEF_CELL_SIZE);
68
69         if((vecptr = ts_get_attr_vec(ts, "player", 0))) {
70                 lvl->px = vecptr[0];
71                 lvl->py = vecptr[1];
72         }
73
74         iter = ts->child_list;
75         while(iter) {
76                 node = iter;
77                 iter = iter->next;
78
79                 if(strcmp(node->name, "tileset") == 0) {
80                         /* TODO */
81
82                 } else if(strcmp(node->name, "cell") == 0) {
83                         cx = ts_get_attr_int(node, "x", -1);
84                         cy = ts_get_attr_int(node, "y", -1);
85                         if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) {
86                                 fprintf(stderr, "ignoring cell with invalid or missing coordinates\n");
87                                 continue;
88                         }
89                         cell = lvl->cells + cy * sz + cx;
90                         cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK;
91
92                         /* abuse the next pointer to hang the treestore node temporarilly */
93                         cell->next = (struct cell*)node;
94                 }
95         }
96
97         /* assign wall types to all occupied cells */
98         cell = lvl->cells;
99         for(i=0; i<lvl->height; i++) {
100                 for(j=0; j<lvl->width; j++) {
101                         if(cell->type == CELL_SOLID) {
102                                 cell++;
103                                 continue;
104                         }
105
106                         /* TODO take wall choice from the level file into account */
107                         /* TODO detect corners */
108                         node = (struct ts_node*)cell->next;
109                         cell->next = 0;
110
111                         /*
112                         if(i >= lvl->height - 1 || cell[lvl->width].type == CELL_SOLID) {
113                                 cell->wall[0] = TILE_STR;
114                         }
115                         if(j >= lvl->width - 1 || cell[1].type == CELL_SOLID) {
116                                 cell->wall[1] = TILE_STR;
117                         }
118                         if(i <= 0 || cell[-lvl->width].type == CELL_SOLID) {
119                                 cell->wall[2] = TILE_STR;
120                         }
121                         if(j <= 0 || cell[-1].type == CELL_SOLID) {
122                                 cell->wall[3] = TILE_STR;
123                         }
124                         */
125
126                         cell++;
127                 }
128         }
129
130         ts_free_tree(ts);
131         return 0;
132 }
133
134 /* TODO: save tileset info */
135 int save_level(struct level *lvl, const char *fname)
136 {
137         int i, j;
138         struct ts_node *root, *node;
139         struct ts_attr *attr;
140         struct cell *cell;
141
142         if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) {
143                 goto err;
144         }
145
146         if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "size") == -1) {
147                 ts_free_attr(attr);
148                 goto err;
149         }
150         ts_set_valuei(&attr->val, lvl->width);
151         ts_add_attr(root, attr);
152
153         if(lvl->cell_size && (attr = ts_alloc_attr())) {
154                 ts_set_attr_name(attr, "cellsize");
155                 ts_set_valuef(&attr->val, lvl->cell_size);
156                 ts_add_attr(root, attr);
157         }
158
159         if(lvl->px >= 0 && lvl->px < lvl->width && lvl->py >= 0 && lvl->py < lvl->height) {
160                 if((attr = ts_alloc_attr())) {
161                         ts_set_attr_name(attr, "player");
162                         ts_set_valueiv(&attr->val, 2, lvl->px, lvl->py);
163                         ts_add_attr(root, attr);
164                 }
165         }
166
167         for(i=0; i<lvl->height; i++) {
168                 for(j=0; j<lvl->width; j++) {
169                         cell = lvl->cells + i * lvl->width + j;
170                         if(cell->type == CELL_SOLID) continue;
171
172                         if(!(node = ts_alloc_node()) || ts_set_node_name(node, "cell") == -1) {
173                                 ts_free_node(node);
174                                 goto err;
175                         }
176                         if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "x") == -1) {
177                                 ts_free_attr(attr);
178                                 goto err;
179                         }
180                         ts_set_valuei(&attr->val, j);
181                         ts_add_attr(node, attr);
182                         if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "y") == -1) {
183                                 ts_free_attr(attr);
184                                 goto err;
185                         }
186                         ts_set_valuei(&attr->val, i);
187                         ts_add_attr(node, attr);
188
189                         if(cell->type == CELL_BLOCKED) {
190                                 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "blocked") == -1) {
191                                         ts_free_attr(attr);
192                                         goto err;
193                                 }
194                                 ts_set_valuei(&attr->val, 1);
195                                 ts_add_attr(node, attr);
196                         }
197
198                         ts_add_child(root, node);
199                 }
200         }
201
202         if(ts_save(root, fname) == -1) {
203                 fprintf(stderr, "failed to save level: %s\n", fname);
204                 ts_free_tree(root);
205                 return -1;
206         }
207         ts_free_tree(root);
208         return 0;
209
210 err:
211         fprintf(stderr, "failed to construct treestore tree\n");
212         ts_free_tree(root);
213         return -1;
214 }
215
216 #ifndef LEVEL_EDITOR
217
218 int gen_cell_geom(struct level *lvl, struct cell *cell)
219 {
220 #if 0
221         int i;
222         struct meshgroup *wallgeom;
223         struct tile *tstr;
224         struct mesh *mesh, *tmesh;
225         float xform[16];
226
227         if(!(tstr = find_level_tile(lvl, TILE_STR))) {
228                 return -1;
229         }
230
231         if(!(wallgeom = malloc(sizeof *wallgeom))) {
232                 return -1;
233         }
234         init_meshgroup(wallgeom);
235
236         for(i=0; i<4; i++) {
237                 if(cell->wall[i] == TILE_STR) { /* TODO: support other wall types */
238                         cgm_mrotation_y(xform, i * M_PI / 2.0f);
239
240                         tmesh = tstr->scn.meshlist;
241                         while(tmesh) {
242                                 if(!(mesh = malloc(sizeof *mesh))) {
243                                         return -1;
244                                 }
245
246                                 /* create a copy of the tile mesh */
247                                 if(copy_mesh(mesh, tmesh) == -1) {
248                                         free(mesh);
249                                         return -1;
250                                 }
251                                 if(i) xform_mesh(mesh, xform);  /* rotate it to match the wall angle */
252
253                                 /* add it to the level meshlist */
254                                 mesh->next = lvl->meshlist;
255                                 lvl->meshlist = mesh;
256
257                                 /* add it to the meshgroup */
258                                 if(add_meshgroup_mesh(wallgeom, mesh) == -1) {
259                                         destroy_mesh(mesh);
260                                         free(mesh);
261                                         return -1;
262                                 }
263
264                                 tmesh = tmesh->next;
265                         }
266                 }
267         }
268
269         /* TODO: append to other existing meshgroups for detail objects */
270         cell->mgrp = wallgeom;
271         cell->num_mgrp = 1;
272 #endif
273         return 0;
274 }
275
276 int gen_level_geom(struct level *lvl)
277 {
278         int i, j;
279         struct cell *cell;
280
281         for(i=0; i<lvl->height; i++) {
282                 for(j=0; j<lvl->width; j++) {
283                         cell = lvl->cells + i * lvl->width + j;
284                         if(cell->type != CELL_SOLID) {
285                                 if(gen_cell_geom(lvl, cell) == -1) {
286                                         printf("failed to generate cell\n");
287                                         return -1;
288                                 }
289                         }
290                 }
291         }
292         return 0;
293 }
294
295 #endif  /* !LEVEL_EDITOR */