X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Flevel.c;h=5f7f77b1f12f71a50065eede535eccd87e4b5e03;hb=32010751a69440b52780a4e570682f20b4ef70b2;hp=3a1a9bf9349d6c95fcaf89a2e1081de5083b6271;hpb=fd7b604752c0ba03c347bc2ef3ee5a8c0759bff8;p=vrlugburz diff --git a/src/level.c b/src/level.c index 3a1a9bf..5f7f77b 100644 --- a/src/level.c +++ b/src/level.c @@ -4,15 +4,39 @@ #include #include #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) { + int i, j; + struct cell *cell; + + 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; + + lvl->visdist = 4; + + /* assign cell coordinates */ + cell = lvl->cells; + for(i=0; ix = j; + cell->y = i; + cell++; + } + } return 0; } @@ -20,18 +44,18 @@ void destroy_level(struct level *lvl) { 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); @@ -53,6 +77,24 @@ int load_level(struct level *lvl, const char *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; @@ -67,7 +109,32 @@ int load_level(struct level *lvl, const char *fname) } 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; iheight; i++) { + for(j=0; jwidth; 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++; } } @@ -75,6 +142,7 @@ int load_level(struct level *lvl, const char *fname) return 0; } +/* TODO: save tileset info */ int save_level(struct level *lvl, const char *fname) { int i, j; @@ -93,6 +161,20 @@ int save_level(struct level *lvl, const char *fname) 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; iheight; i++) { for(j=0; jwidth; j++) { cell = lvl->cells + i * lvl->width + j; @@ -141,3 +223,150 @@ err: ts_free_tree(root); return -1; } + +#ifndef LEVEL_EDITOR + +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 */