10 int init_level(struct level *lvl, int xsz, int ysz)
12 memset(lvl, 0, sizeof *lvl);
14 if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) {
20 lvl->cell_size = DEF_CELL_SIZE;
21 lvl->px = lvl->py = -1;
25 void destroy_level(struct level *lvl)
33 int load_level(struct level *lvl, const char *fname)
35 struct ts_node *ts, *node, *iter;
40 if(!(ts = ts_load(fname))) {
41 fprintf(stderr, "failed to load level: %s\n", fname);
44 if(strcmp(ts->name, "dunged_level") != 0) {
45 fprintf(stderr, "invalid or corrupted level file: %s\n", fname);
50 if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) {
54 if(init_level(lvl, sz, sz) == -1) {
55 fprintf(stderr, "failed to initialize a %dx%d level\n", sz, sz);
60 lvl->fname = strdup(fname);
61 if((lvl->dirname = malloc(strlen(fname) + 1))) {
63 path_dir(lvl->fname, lvl->dirname);
67 lvl->cell_size = ts_get_attr_num(ts, "cellsize", DEF_CELL_SIZE);
69 if((vecptr = ts_get_attr_vec(ts, "player", 0))) {
74 iter = ts->child_list;
79 if(strcmp(node->name, "tileset") == 0) {
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");
89 cell = lvl->cells + cy * sz + cx;
90 cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK;
92 /* abuse the next pointer to hang the treestore node temporarilly */
93 cell->next = (struct cell*)node;
97 /* assign wall types to all occupied cells */
99 for(i=0; i<lvl->height; i++) {
100 for(j=0; j<lvl->width; j++) {
101 if(cell->type == CELL_SOLID) {
106 /* TODO take wall choice from the level file into account */
107 /* TODO detect corners */
108 node = (struct ts_node*)cell->next;
112 if(i >= lvl->height - 1 || cell[lvl->width].type == CELL_SOLID) {
113 cell->wall[0] = TILE_STR;
115 if(j >= lvl->width - 1 || cell[1].type == CELL_SOLID) {
116 cell->wall[1] = TILE_STR;
118 if(i <= 0 || cell[-lvl->width].type == CELL_SOLID) {
119 cell->wall[2] = TILE_STR;
121 if(j <= 0 || cell[-1].type == CELL_SOLID) {
122 cell->wall[3] = TILE_STR;
134 /* TODO: save tileset info */
135 int save_level(struct level *lvl, const char *fname)
138 struct ts_node *root, *node;
139 struct ts_attr *attr;
142 if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) {
146 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "size") == -1) {
150 ts_set_valuei(&attr->val, lvl->width);
151 ts_add_attr(root, attr);
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);
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);
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;
172 if(!(node = ts_alloc_node()) || ts_set_node_name(node, "cell") == -1) {
176 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "x") == -1) {
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) {
186 ts_set_valuei(&attr->val, i);
187 ts_add_attr(node, attr);
189 if(cell->type == CELL_BLOCKED) {
190 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "blocked") == -1) {
194 ts_set_valuei(&attr->val, 1);
195 ts_add_attr(node, attr);
198 ts_add_child(root, node);
202 if(ts_save(root, fname) == -1) {
203 fprintf(stderr, "failed to save level: %s\n", fname);
211 fprintf(stderr, "failed to construct treestore tree\n");
218 int gen_cell_geom(struct level *lvl, struct cell *cell)
222 struct meshgroup *wallgeom;
224 struct mesh *mesh, *tmesh;
227 if(!(tstr = find_level_tile(lvl, TILE_STR))) {
231 if(!(wallgeom = malloc(sizeof *wallgeom))) {
234 init_meshgroup(wallgeom);
237 if(cell->wall[i] == TILE_STR) { /* TODO: support other wall types */
238 cgm_mrotation_y(xform, i * M_PI / 2.0f);
240 tmesh = tstr->scn.meshlist;
242 if(!(mesh = malloc(sizeof *mesh))) {
246 /* create a copy of the tile mesh */
247 if(copy_mesh(mesh, tmesh) == -1) {
251 if(i) xform_mesh(mesh, xform); /* rotate it to match the wall angle */
253 /* add it to the level meshlist */
254 mesh->next = lvl->meshlist;
255 lvl->meshlist = mesh;
257 /* add it to the meshgroup */
258 if(add_meshgroup_mesh(wallgeom, mesh) == -1) {
269 /* TODO: append to other existing meshgroups for detail objects */
270 cell->mgrp = wallgeom;
276 int gen_level_geom(struct level *lvl)
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");
295 #endif /* !LEVEL_EDITOR */