#include <errno.h>
#include <treestore.h>
#include "level.h"
+#include "tileset.h"
+#include "fs.h"
+
+static int detect_cell_tile(struct level *lvl, int x, int y, int *rot);
+
int init_level(struct level *lvl, int xsz, int ysz)
{
+ memset(lvl, 0, sizeof *lvl);
+
if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) {
free(lvl);
return -1;
}
lvl->width = xsz;
lvl->height = ysz;
+ lvl->cell_size = DEF_CELL_SIZE;
+ lvl->px = lvl->py = -1;
return 0;
}
{
if(!lvl) return;
free(lvl->cells);
+ free(lvl->fname);
+ free(lvl->dirname);
}
int load_level(struct level *lvl, const char *fname)
{
- FILE *fp;
struct ts_node *ts, *node, *iter;
- int sz, cx, cy;
+ int i, j, sz, cx, cy, tiletype;
struct cell *cell;
-
- if(!(fp = fopen(fname, "rb"))) {
- return -1;
- }
+ float *vecptr;
+ const char *str;
+ char *tset_path;
if(!(ts = ts_load(fname))) {
fprintf(stderr, "failed to load level: %s\n", fname);
return -1;
}
+ lvl->fname = strdup(fname);
+ if((lvl->dirname = malloc(strlen(fname) + 1))) {
+ path_dir(lvl->fname, lvl->dirname);
+ }
+
+ lvl->cell_size = ts_get_attr_num(ts, "cellsize", DEF_CELL_SIZE);
+
+ if((vecptr = ts_get_attr_vec(ts, "player", 0))) {
+ lvl->px = vecptr[0];
+ lvl->py = vecptr[1];
+ }
+
+ if((str = ts_get_attr_str(ts, "tileset", 0))) {
+ tset_path = alloca(strlen(str) + strlen(lvl->dirname) + 2);
+ combine_path(lvl->dirname, str, tset_path);
+ lvl->tset = get_tileset(tset_path);
+ }
+
iter = ts->child_list;
while(iter) {
node = iter;
}
cell = lvl->cells + cy * sz + cx;
cell->type = ts_get_attr_int(node, "blocked", 0) ? CELL_BLOCKED : CELL_WALK;
- /* TODO wall tiles and detail objects */
+
+ /* abuse the next pointer to hang the treestore node temporarilly */
+ cell->next = (struct cell*)node;
+ }
+ }
+
+ cell = lvl->cells;
+ for(i=0; i<lvl->height; i++) {
+ for(j=0; j<lvl->width; j++) {
+ node = (struct ts_node*)cell->next;
+ cell->next = 0;
+
+ if(cell->type == CELL_SOLID) {
+ cell++;
+ continue;
+ }
+
+ if((tiletype = tile_type(ts_get_attr_str(node, "tiletype", 0))) == -1) {
+ /* no tile-type specified, try to guess */
+ tiletype = detect_cell_tile(lvl, j, i, &cell->tilerot);
+ }
+
+ if(lvl->tset) {
+ cell->tile = get_tile(lvl->tset, tiletype);
+ }
+ cell++;
}
}
return 0;
}
+/* TODO: save tileset info */
int save_level(struct level *lvl, const char *fname)
{
int i, j;
ts_set_valuei(&attr->val, lvl->width);
ts_add_attr(root, attr);
+ if(lvl->cell_size && (attr = ts_alloc_attr())) {
+ ts_set_attr_name(attr, "cellsize");
+ ts_set_valuef(&attr->val, lvl->cell_size);
+ ts_add_attr(root, attr);
+ }
+
+ if(lvl->px >= 0 && lvl->px < lvl->width && lvl->py >= 0 && lvl->py < lvl->height) {
+ if((attr = ts_alloc_attr())) {
+ ts_set_attr_name(attr, "player");
+ ts_set_valueiv(&attr->val, 2, lvl->px, lvl->py);
+ ts_add_attr(root, attr);
+ }
+ }
+
for(i=0; i<lvl->height; i++) {
for(j=0; j<lvl->width; j++) {
cell = lvl->cells + i * lvl->width + j;
ts_free_tree(root);
return -1;
}
+
+#ifndef LEVEL_EDITOR
+
+static int get_cell_type(struct level *lvl, int x, int y)
+{
+ if(x < 0 || x >= lvl->width || y < 0 || y >= lvl->height) {
+ return CELL_SOLID;
+ }
+ return lvl->cells[y * lvl->width + x].type;
+}
+
+static int detect_cell_tile(struct level *lvl, int x, int y, int *rot)
+{
+ int i, j, bit;
+ unsigned int adj = 0;
+
+ bit = 0;
+ for(i=0; i<3; i++) {
+ for(j=0; j<3; j++) {
+ if(get_cell_type(lvl, x + j - 1, y + i - 1) == CELL_SOLID) {
+ adj |= 1 << bit;
+ }
+ bit++;
+ }
+ }
+
+ *rot = 0;
+
+ switch(adj) {
+ case 0:
+ case 0757:
+ /* really we'd need a separate tile type for "all neighbors solid", but we
+ * probably never going to need that in practice, so fuck it.
+ */
+ return TILE_OPEN;
+
+ case 0745:
+ case 0645:
+ case 0741:
+ case 0641:
+ return TILE_CORNER;
+
+ case 0744:
+ case 0644:
+ case 0740:
+ case 0640:
+ return TILE_OPENCORNER;
+
+ case 0715:
+ case 0315:
+ case 0714:
+ case 0314:
+ *rot = 1;
+ return TILE_CORNER;
+
+ case 0711:
+ case 0311:
+ case 0710:
+ case 0310:
+ *rot = 1;
+ return TILE_OPENCORNER;
+
+ case 0547:
+ case 0147:
+ case 0546:
+ case 0146:
+ *rot = 3;
+ return TILE_CORNER;
+
+ case 0447:
+ case 0047:
+ case 0446:
+ case 0046:
+ *rot = 3;
+ return TILE_OPENCORNER;
+
+ case 0517:
+ case 0417:
+ case 0513:
+ case 0413:
+ *rot = 2;
+ return TILE_CORNER;
+
+ case 0117:
+ case 0017:
+ case 0113:
+ case 0013:
+ *rot = 2;
+ return TILE_OPENCORNER;
+
+ case 0507: /* N tee */
+ *rot = 3;
+ return TILE_TEE;
+ case 0515: /* W tee */
+ *rot = 2;
+ return TILE_TEE;
+ case 0705: /* S tee */
+ *rot = 1;
+ return TILE_TEE;
+ case 0545: /* E tee */
+ return TILE_TEE;
+
+ case 0505: /* cross */
+ return TILE_CROSS;
+
+ case 0404: /* E str2open */
+ return TILE_STR2OPEN;
+ case 0005: /* N str2open */
+ *rot = 1;
+ return TILE_STR2OPEN;
+ case 0101: /* W str2open */
+ *rot = 2;
+ return TILE_STR2OPEN;
+ case 0500: /* S str2open */
+ *rot = 3;
+ return TILE_STR2OPEN;
+
+ default:
+ if((adj & 0222) == 0200) {
+ return TILE_STROPEN;
+ }
+ if((adj & 0222) == 0002) {
+ *rot = 2;
+ return TILE_STROPEN;
+ }
+ if((adj & 0070) == 0040) {
+ *rot = 3;
+ return TILE_STROPEN;
+ }
+ if((adj & 0070) == 0010) {
+ *rot = 1;
+ return TILE_STROPEN;
+ }
+
+ if((adj & 0070) == 0050) {
+ *rot = 1; /* straight N-S */
+ return TILE_STR;
+ }
+ if((adj & 0202) == 0202) {
+ return TILE_STR; /* straight E-W */
+ }
+ }
+
+ return TILE_OPEN;
+}
+
+#endif /* !LEVEL_EDITOR */