10 static int detect_cell_tile(struct level *lvl, int x, int y, int *rot);
13 int init_level(struct level *lvl, int xsz, int ysz)
15 memset(lvl, 0, sizeof *lvl);
17 if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) {
23 lvl->cell_size = DEF_CELL_SIZE;
24 lvl->px = lvl->py = -1;
28 void destroy_level(struct level *lvl)
36 int load_level(struct level *lvl, const char *fname)
38 struct ts_node *ts, *node, *iter;
39 int i, j, sz, cx, cy, tiletype;
45 if(!(ts = ts_load(fname))) {
46 fprintf(stderr, "failed to load level: %s\n", fname);
49 if(strcmp(ts->name, "dunged_level") != 0) {
50 fprintf(stderr, "invalid or corrupted level file: %s\n", fname);
55 if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) {
59 if(init_level(lvl, sz, sz) == -1) {
60 fprintf(stderr, "failed to initialize a %dx%d level\n", sz, sz);
65 lvl->fname = strdup(fname);
66 if((lvl->dirname = malloc(strlen(fname) + 1))) {
67 path_dir(lvl->fname, lvl->dirname);
70 lvl->cell_size = ts_get_attr_num(ts, "cellsize", DEF_CELL_SIZE);
72 if((vecptr = ts_get_attr_vec(ts, "player", 0))) {
77 if((str = ts_get_attr_str(ts, "tileset", 0))) {
78 tset_path = alloca(strlen(str) + strlen(lvl->dirname) + 2);
79 combine_path(lvl->dirname, str, tset_path);
80 lvl->tset = get_tileset(tset_path);
83 iter = ts->child_list;
88 if(strcmp(node->name, "cell") == 0) {
89 cx = ts_get_attr_int(node, "x", -1);
90 cy = ts_get_attr_int(node, "y", -1);
91 if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) {
92 fprintf(stderr, "ignoring cell with invalid or missing coordinates\n");
95 cell = lvl->cells + cy * sz + cx;
96 cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK;
98 /* abuse the next pointer to hang the treestore node temporarilly */
99 cell->next = (struct cell*)node;
104 for(i=0; i<lvl->height; i++) {
105 for(j=0; j<lvl->width; j++) {
106 node = (struct ts_node*)cell->next;
109 if(cell->type == CELL_SOLID) {
114 if((tiletype = tile_type(ts_get_attr_str(node, "tiletype", 0))) == -1) {
115 /* no tile-type specified, try to guess */
116 tiletype = detect_cell_tile(lvl, j, i, &cell->tilerot);
120 cell->tile = get_tile(lvl->tset, tiletype);
130 /* TODO: save tileset info */
131 int save_level(struct level *lvl, const char *fname)
134 struct ts_node *root, *node;
135 struct ts_attr *attr;
138 if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) {
142 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "size") == -1) {
146 ts_set_valuei(&attr->val, lvl->width);
147 ts_add_attr(root, attr);
149 if(lvl->cell_size && (attr = ts_alloc_attr())) {
150 ts_set_attr_name(attr, "cellsize");
151 ts_set_valuef(&attr->val, lvl->cell_size);
152 ts_add_attr(root, attr);
155 if(lvl->px >= 0 && lvl->px < lvl->width && lvl->py >= 0 && lvl->py < lvl->height) {
156 if((attr = ts_alloc_attr())) {
157 ts_set_attr_name(attr, "player");
158 ts_set_valueiv(&attr->val, 2, lvl->px, lvl->py);
159 ts_add_attr(root, attr);
163 for(i=0; i<lvl->height; i++) {
164 for(j=0; j<lvl->width; j++) {
165 cell = lvl->cells + i * lvl->width + j;
166 if(cell->type == CELL_SOLID) continue;
168 if(!(node = ts_alloc_node()) || ts_set_node_name(node, "cell") == -1) {
172 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "x") == -1) {
176 ts_set_valuei(&attr->val, j);
177 ts_add_attr(node, attr);
178 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "y") == -1) {
182 ts_set_valuei(&attr->val, i);
183 ts_add_attr(node, attr);
185 if(cell->type == CELL_BLOCKED) {
186 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "blocked") == -1) {
190 ts_set_valuei(&attr->val, 1);
191 ts_add_attr(node, attr);
194 ts_add_child(root, node);
198 if(ts_save(root, fname) == -1) {
199 fprintf(stderr, "failed to save level: %s\n", fname);
207 fprintf(stderr, "failed to construct treestore tree\n");
214 static int get_cell_type(struct level *lvl, int x, int y)
216 if(x < 0 || x >= lvl->width || y < 0 || y >= lvl->height) {
219 return lvl->cells[y * lvl->width + x].type;
222 static int detect_cell_tile(struct level *lvl, int x, int y, int *rot)
225 unsigned int adj = 0;
230 if(get_cell_type(lvl, x + j - 1, y + i - 1) == CELL_SOLID) {
242 /* really we'd need a separate tile type for "all neighbors solid", but we
243 * probably never going to need that in practice, so fuck it.
257 return TILE_OPENCORNER;
271 return TILE_OPENCORNER;
285 return TILE_OPENCORNER;
299 return TILE_OPENCORNER;
301 case 0507: /* N tee */
304 case 0515: /* W tee */
307 case 0705: /* S tee */
310 case 0545: /* E tee */
313 case 0505: /* cross */
316 case 0404: /* E str2open */
317 return TILE_STR2OPEN;
318 case 0005: /* N str2open */
320 return TILE_STR2OPEN;
321 case 0101: /* W str2open */
323 return TILE_STR2OPEN;
324 case 0500: /* S str2open */
326 return TILE_STR2OPEN;
329 if((adj & 0222) == 0200) {
332 if((adj & 0222) == 0002) {
336 if((adj & 0070) == 0040) {
340 if((adj & 0070) == 0010) {
345 if((adj & 0070) == 0050) {
346 *rot = 1; /* straight N-S */
349 if((adj & 0202) == 0202) {
350 return TILE_STR; /* straight E-W */
357 #endif /* !LEVEL_EDITOR */