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)
18 memset(lvl, 0, sizeof *lvl);
20 if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) {
26 lvl->cell_size = DEF_CELL_SIZE;
27 lvl->px = lvl->py = -1;
31 /* assign cell coordinates */
33 for(i=0; i<ysz; i++) {
34 for(j=0; j<xsz; j++) {
43 void destroy_level(struct level *lvl)
51 int load_level(struct level *lvl, const char *fname)
53 struct ts_node *ts, *node, *iter;
54 int i, j, sz, cx, cy, tiletype;
60 if(!(ts = ts_load(fname))) {
61 fprintf(stderr, "failed to load level: %s\n", fname);
64 if(strcmp(ts->name, "dunged_level") != 0) {
65 fprintf(stderr, "invalid or corrupted level file: %s\n", fname);
70 if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) {
74 if(init_level(lvl, sz, sz) == -1) {
75 fprintf(stderr, "failed to initialize a %dx%d level\n", sz, sz);
80 lvl->fname = strdup(fname);
81 if((lvl->dirname = malloc(strlen(fname) + 1))) {
82 path_dir(lvl->fname, lvl->dirname);
85 lvl->cell_size = ts_get_attr_num(ts, "cellsize", DEF_CELL_SIZE);
87 if((vecptr = ts_get_attr_vec(ts, "player", 0))) {
92 if((str = ts_get_attr_str(ts, "tileset", 0))) {
93 tset_path = alloca(strlen(str) + strlen(lvl->dirname) + 2);
94 combine_path(lvl->dirname, str, tset_path);
95 lvl->tset = get_tileset(tset_path);
98 iter = ts->child_list;
103 if(strcmp(node->name, "cell") == 0) {
104 cx = ts_get_attr_int(node, "x", -1);
105 cy = ts_get_attr_int(node, "y", -1);
106 if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) {
107 fprintf(stderr, "ignoring cell with invalid or missing coordinates\n");
110 cell = lvl->cells + cy * sz + cx;
111 cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK;
113 /* abuse the next pointer to hang the treestore node temporarilly */
114 cell->next = (struct cell*)node;
119 for(i=0; i<lvl->height; i++) {
120 for(j=0; j<lvl->width; j++) {
121 node = (struct ts_node*)cell->next;
124 if(cell->type == CELL_SOLID) {
129 if((tiletype = tile_type(ts_get_attr_str(node, "tiletype", 0))) == -1) {
130 /* no tile-type specified, try to guess */
131 tiletype = detect_cell_tile(lvl, j, i, &cell->tilerot);
135 cell->tile = get_tile(lvl->tset, tiletype);
145 /* TODO: save tileset info */
146 int save_level(struct level *lvl, const char *fname)
149 struct ts_node *root, *node;
150 struct ts_attr *attr;
153 if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) {
157 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "size") == -1) {
161 ts_set_valuei(&attr->val, lvl->width);
162 ts_add_attr(root, attr);
164 if(lvl->cell_size && (attr = ts_alloc_attr())) {
165 ts_set_attr_name(attr, "cellsize");
166 ts_set_valuef(&attr->val, lvl->cell_size);
167 ts_add_attr(root, attr);
170 if(lvl->px >= 0 && lvl->px < lvl->width && lvl->py >= 0 && lvl->py < lvl->height) {
171 if((attr = ts_alloc_attr())) {
172 ts_set_attr_name(attr, "player");
173 ts_set_valueiv(&attr->val, 2, lvl->px, lvl->py);
174 ts_add_attr(root, attr);
178 for(i=0; i<lvl->height; i++) {
179 for(j=0; j<lvl->width; j++) {
180 cell = lvl->cells + i * lvl->width + j;
181 if(cell->type == CELL_SOLID) continue;
183 if(!(node = ts_alloc_node()) || ts_set_node_name(node, "cell") == -1) {
187 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "x") == -1) {
191 ts_set_valuei(&attr->val, j);
192 ts_add_attr(node, attr);
193 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "y") == -1) {
197 ts_set_valuei(&attr->val, i);
198 ts_add_attr(node, attr);
200 if(cell->type == CELL_BLOCKED) {
201 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "blocked") == -1) {
205 ts_set_valuei(&attr->val, 1);
206 ts_add_attr(node, attr);
209 ts_add_child(root, node);
213 if(ts_save(root, fname) == -1) {
214 fprintf(stderr, "failed to save level: %s\n", fname);
222 fprintf(stderr, "failed to construct treestore tree\n");
229 int get_cell_type(struct level *lvl, int x, int y)
231 if(x < 0 || x >= lvl->width || y < 0 || y >= lvl->height) {
234 return lvl->cells[y * lvl->width + x].type;
237 static int detect_cell_tile(struct level *lvl, int x, int y, int *rot)
240 unsigned int adj = 0;
245 if(get_cell_type(lvl, x + j - 1, y + i - 1) == CELL_SOLID) {
257 /* really we'd need a separate tile type for "all neighbors solid", but we
258 * probably never going to need that in practice, so fuck it.
272 return TILE_OPENCORNER;
286 return TILE_OPENCORNER;
300 return TILE_OPENCORNER;
314 return TILE_OPENCORNER;
316 case 0507: /* N tee */
319 case 0515: /* W tee */
322 case 0705: /* S tee */
325 case 0545: /* E tee */
328 case 0505: /* cross */
331 case 0404: /* E str2open */
332 return TILE_STR2OPEN;
333 case 0005: /* N str2open */
335 return TILE_STR2OPEN;
336 case 0101: /* W str2open */
338 return TILE_STR2OPEN;
339 case 0500: /* S str2open */
341 return TILE_STR2OPEN;
344 if((adj & 0222) == 0200) {
347 if((adj & 0222) == 0002) {
351 if((adj & 0070) == 0040) {
355 if((adj & 0070) == 0010) {
360 if((adj & 0070) == 0050) {
361 *rot = 1; /* straight N-S */
364 if((adj & 0202) == 0202) {
365 return TILE_STR; /* straight E-W */
372 #endif /* !LEVEL_EDITOR */