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;
44 if(!(ts = ts_load(fname))) {
45 fprintf(stderr, "failed to load level: %s\n", fname);
48 if(strcmp(ts->name, "dunged_level") != 0) {
49 fprintf(stderr, "invalid or corrupted level file: %s\n", fname);
54 if((sz = ts_get_attr_int(ts, "size", 0)) <= 0) {
58 if(init_level(lvl, sz, sz) == -1) {
59 fprintf(stderr, "failed to initialize a %dx%d level\n", sz, sz);
64 lvl->fname = strdup(fname);
65 if((lvl->dirname = malloc(strlen(fname) + 1))) {
67 path_dir(lvl->fname, lvl->dirname);
71 lvl->cell_size = ts_get_attr_num(ts, "cellsize", DEF_CELL_SIZE);
73 if((vecptr = ts_get_attr_vec(ts, "player", 0))) {
78 if((str = ts_get_attr_str(ts, "tileset", 0))) {
79 lvl->tset = get_tileset(str);
82 iter = ts->child_list;
87 if(strcmp(node->name, "cell") == 0) {
88 cx = ts_get_attr_int(node, "x", -1);
89 cy = ts_get_attr_int(node, "y", -1);
90 if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) {
91 fprintf(stderr, "ignoring cell with invalid or missing coordinates\n");
94 cell = lvl->cells + cy * sz + cx;
95 cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK;
97 /* abuse the next pointer to hang the treestore node temporarilly */
98 cell->next = (struct cell*)node;
103 for(i=0; i<lvl->height; i++) {
104 for(j=0; j<lvl->width; j++) {
105 if(cell->type == CELL_SOLID) {
110 node = (struct ts_node*)cell->next;
113 if((tiletype = tile_type(ts_get_attr_str(node, "tiletype", 0))) == -1) {
114 /* no tile-type specified, try to guess */
115 tiletype = detect_cell_tile(lvl, j, i, &cell->tilerot);
118 cell->tile = get_tile(lvl->tset, tiletype);
128 /* TODO: save tileset info */
129 int save_level(struct level *lvl, const char *fname)
132 struct ts_node *root, *node;
133 struct ts_attr *attr;
136 if(!(root = ts_alloc_node()) || ts_set_node_name(root, "dunged_level") == -1) {
140 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "size") == -1) {
144 ts_set_valuei(&attr->val, lvl->width);
145 ts_add_attr(root, attr);
147 if(lvl->cell_size && (attr = ts_alloc_attr())) {
148 ts_set_attr_name(attr, "cellsize");
149 ts_set_valuef(&attr->val, lvl->cell_size);
150 ts_add_attr(root, attr);
153 if(lvl->px >= 0 && lvl->px < lvl->width && lvl->py >= 0 && lvl->py < lvl->height) {
154 if((attr = ts_alloc_attr())) {
155 ts_set_attr_name(attr, "player");
156 ts_set_valueiv(&attr->val, 2, lvl->px, lvl->py);
157 ts_add_attr(root, attr);
161 for(i=0; i<lvl->height; i++) {
162 for(j=0; j<lvl->width; j++) {
163 cell = lvl->cells + i * lvl->width + j;
164 if(cell->type == CELL_SOLID) continue;
166 if(!(node = ts_alloc_node()) || ts_set_node_name(node, "cell") == -1) {
170 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "x") == -1) {
174 ts_set_valuei(&attr->val, j);
175 ts_add_attr(node, attr);
176 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "y") == -1) {
180 ts_set_valuei(&attr->val, i);
181 ts_add_attr(node, attr);
183 if(cell->type == CELL_BLOCKED) {
184 if(!(attr = ts_alloc_attr()) || ts_set_attr_name(attr, "blocked") == -1) {
188 ts_set_valuei(&attr->val, 1);
189 ts_add_attr(node, attr);
192 ts_add_child(root, node);
196 if(ts_save(root, fname) == -1) {
197 fprintf(stderr, "failed to save level: %s\n", fname);
205 fprintf(stderr, "failed to construct treestore tree\n");
212 static int get_cell_type(struct level *lvl, int x, int y)
214 if(x < 0 || x >= lvl->width || y < 0 || y >= lvl->height) {
217 return lvl->cells[y * lvl->width + x].type;
220 static int detect_cell_tile(struct level *lvl, int x, int y, int *rot)
223 unsigned int adj = 0;
228 if(i == 1 && j == 1) continue;
229 if(get_cell_type(lvl, x + j - 1, y + i - 1) == CELL_SOLID) {
241 /* really we'd need a separate tile type for "all neighbors solid", but we
242 * probably never going to need that in practice, so fuck it.
246 case 0555: /* N-S corridor */
248 case 0707: /* W-E corridor */
251 case 0745: /* S-E corner */
253 case 0715: /* S-W corner */
255 case 0547: /* N-E corner */
258 case 0517: /* N-W corner */
262 case 0507: /* N tee */
264 case 0515: /* W tee */
266 case 0705: /* S tee */
269 case 0545: /* E tee */
273 case 0505: /* cross */
276 case 0700: /* S stropen */
280 case 0444: /* E stropen */
285 case 0007: /* N stropen */
290 case 0111: /* W stropen */
296 case 0404: /* E str2open */
297 return TILE_STR2OPEN;
298 case 0005: /* N str2open */
300 return TILE_STR2OPEN;
301 case 0101: /* W str2open */
303 return TILE_STR2OPEN;
304 case 0500: /* S str2open */
306 return TILE_STR2OPEN;
312 #endif /* !LEVEL_EDITOR */