9 static int load_tileset(struct level *lvl, struct ts_node *tsn);
11 int init_level(struct level *lvl, int xsz, int ysz)
13 memset(lvl, 0, sizeof *lvl);
15 if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) {
21 lvl->cell_size = DEF_CELL_SIZE;
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 lvl->fname = strdup(fname);
41 if((lvl->dirname = malloc(strlen(fname) + 1))) {
43 path_dir(lvl->fname, lvl->dirname);
47 if(!(ts = ts_load(fname))) {
48 fprintf(stderr, "failed to load level: %s\n", fname);
51 if(strcmp(ts->name, "dunged_level") != 0) {
52 fprintf(stderr, "invalid or corrupted level file: %s\n", fname);
57 if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) {
61 if(init_level(lvl, sz, sz) == -1) {
62 fprintf(stderr, "failed to initialize a %dx%d level\n", sz, sz);
66 lvl->cell_size = ts_get_attr_num(ts, "cellsize", DEF_CELL_SIZE);
68 if((vecptr = ts_get_attr_vec(ts, "player", 0))) {
73 iter = ts->child_list;
78 if(strcmp(node->name, "tileset") == 0) {
79 load_tileset(lvl, node);
81 } else if(strcmp(node->name, "cell") == 0) {
82 cx = ts_get_attr_int(node, "x", -1);
83 cy = ts_get_attr_int(node, "y", -1);
84 if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) {
85 fprintf(stderr, "ignoring cell with invalid or missing coordinates\n");
88 cell = lvl->cells + cy * sz + cx;
89 cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK;
91 /* abuse the next pointer to hang the treestore node temporarilly */
92 cell->next = (struct cell*)node;
96 /* assign wall types to all occupied cells */
98 for(i=0; i<lvl->height; i++) {
99 for(j=0; j<lvl->width; j++) {
100 if(cell->type == CELL_SOLID) {
105 /* TODO take wall choice from the level file into account */
106 /* TODO detect corners */
107 node = (struct ts_node*)cell->next;
110 if(j <= 0 || cell[-1].type == CELL_SOLID) {
111 cell->wall[0] = TILE_STRAIGHT;
113 if(i <= 0 || cell[-lvl->width].type == CELL_SOLID) {
114 cell->wall[1] = TILE_STRAIGHT;
116 if(j >= lvl->width - 1 || cell[1].type == CELL_SOLID) {
117 cell->wall[2] = TILE_STRAIGHT;
119 if(i >= lvl->height - 1 || cell[lvl->width].type == CELL_SOLID) {
120 cell->wall[3] = TILE_STRAIGHT;
131 /* TODO: save tileset info */
132 int save_level(struct level *lvl, const char *fname)
135 struct ts_node *root, *node;
136 struct ts_attr *attr;
139 if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) {
143 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "size") == -1) {
147 ts_set_valuei(&attr->val, lvl->width);
148 ts_add_attr(root, attr);
150 for(i=0; i<lvl->height; i++) {
151 for(j=0; j<lvl->width; j++) {
152 cell = lvl->cells + i * lvl->width + j;
153 if(cell->type == CELL_SOLID) continue;
155 if(!(node = ts_alloc_node()) || ts_set_node_name(node, "cell") == -1) {
159 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "x") == -1) {
163 ts_set_valuei(&attr->val, j);
164 ts_add_attr(node, attr);
165 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "y") == -1) {
169 ts_set_valuei(&attr->val, i);
170 ts_add_attr(node, attr);
172 if(cell->type == CELL_BLOCKED) {
173 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "blocked") == -1) {
177 ts_set_valuei(&attr->val, 1);
178 ts_add_attr(node, attr);
181 ts_add_child(root, node);
185 if(ts_save(root, fname) == -1) {
186 fprintf(stderr, "failed to save level: %s\n", fname);
194 fprintf(stderr, "failed to construct treestore tree\n");
201 static int load_tileset(struct level *lvl, struct ts_node *tsn)
203 static const char *tile_types[] = {"empty", "straight", "corner", "door", 0};
208 struct ts_node *node;
211 node = tsn->child_list;
213 if(strcmp(node->name, "tile") == 0) {
214 if(!(tile = calloc(1, sizeof *tile))) {
215 fprintf(stderr, "failed to allocate tile\n");
218 if((str = ts_get_attr_str(node, "name", 0))) {
219 tile->name = strdup(str);
221 if((str = ts_get_attr_str(node, "type", 0))) {
222 for(i=0; tile_types[i]; i++) {
223 if(strcmp(str, tile_types[i]) == 0) {
229 if((str = ts_get_attr_str(node, "scene", 0))) {
231 path = alloca(strlen(lvl->dirname) + strlen(str) + 2);
232 combine_path(lvl->dirname, str, path);
236 load_scenefile(&tile->scn, path);
239 if(tile->name && tile->scn.meshlist) { /* valid tile */
240 tile->next = lvl->tiles;
243 fprintf(stderr, "load_tileset: skipping invalid tile: %s\n",
244 tile->name ? tile->name : "missing tile name");
254 struct tile *find_level_tile(struct level *lvl, int type)
256 struct tile *tile = lvl->tiles;
258 if(tile->type == type) {
266 int gen_cell_geom(struct level *lvl, struct cell *cell)
269 struct meshgroup *wallgeom;
271 struct mesh *mesh, *tmesh;
274 if(!(tstr = find_level_tile(lvl, TILE_STRAIGHT))) {
278 if(!(wallgeom = malloc(sizeof *wallgeom))) {
281 init_meshgroup(wallgeom);
284 if(cell->wall[i] == TILE_STRAIGHT) { /* TODO: support other wall types */
285 cgm_mrotation_y(xform, i * M_PI / 2.0f);
287 tmesh = tstr->scn.meshlist;
289 if(!(mesh = malloc(sizeof *mesh))) {
293 /* create a copy of the tile mesh */
294 if(copy_mesh(mesh, tmesh) == -1) {
298 if(i) xform_mesh(mesh, xform); /* rotate it to match the wall angle */
300 /* add it to the level meshlist */
301 mesh->next = lvl->meshlist;
302 lvl->meshlist = mesh;
304 /* add it to the meshgroup */
305 if(add_meshgroup_mesh(wallgeom, mesh) == -1) {
316 /* TODO: append to other existing meshgroups for detail objects */
317 cell->mgrp = wallgeom;
323 int gen_level_geom(struct level *lvl)
328 for(i=0; i<lvl->height; i++) {
329 for(j=0; j<lvl->width; j++) {
330 cell = lvl->cells + i * lvl->width + j;
331 if(cell->type != CELL_SOLID) {
332 if(gen_cell_geom(lvl, cell) == -1) {
333 printf("failed to generate cell\n");
344 static int load_tileset(struct level *lvl, struct ts_node *tsn)
346 return 0; /* in the level editor we don't need tileset loading */
349 #endif /* !LEVEL_EDITOR */