X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Flevel.c;h=c17c03abc93292e604a5926dddd2a676a583b3f5;hb=8b4c81041dbf3149c3bbdac08de63524ee2d48b4;hp=e741667a0b13ae268b2842cd833f78adc51df8bc;hpb=7a1a5aa446fcf3d2b0bb26f6f7465e4f3d116e47;p=vrlugburz diff --git a/src/level.c b/src/level.c index e741667..c17c03a 100644 --- a/src/level.c +++ b/src/level.c @@ -4,9 +4,11 @@ #include #include #include "level.h" +#include "tileset.h" #include "fs.h" -static int load_tileset(struct level *lvl, struct ts_node *tsn); +static int detect_cell_tile(struct level *lvl, int x, int y, int *rot); + int init_level(struct level *lvl, int xsz, int ysz) { @@ -34,9 +36,11 @@ void destroy_level(struct level *lvl) int load_level(struct level *lvl, const char *fname) { struct ts_node *ts, *node, *iter; - int i, j, sz, cx, cy; + int i, j, sz, cx, cy, tiletype; struct cell *cell; float *vecptr; + const char *str; + char *tset_path; if(!(ts = ts_load(fname))) { fprintf(stderr, "failed to load level: %s\n", fname); @@ -60,9 +64,7 @@ int load_level(struct level *lvl, const char *fname) lvl->fname = strdup(fname); if((lvl->dirname = malloc(strlen(fname) + 1))) { -#ifndef LEVEL_EDITOR path_dir(lvl->fname, lvl->dirname); -#endif } lvl->cell_size = ts_get_attr_num(ts, "cellsize", DEF_CELL_SIZE); @@ -72,15 +74,18 @@ int load_level(struct level *lvl, const char *fname) 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; iter = iter->next; - if(strcmp(node->name, "tileset") == 0) { - load_tileset(lvl, node); - - } else if(strcmp(node->name, "cell") == 0) { + if(strcmp(node->name, "cell") == 0) { cx = ts_get_attr_int(node, "x", -1); cy = ts_get_attr_int(node, "y", -1); if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) { @@ -95,33 +100,25 @@ int load_level(struct level *lvl, const char *fname) } } - /* assign wall types to all occupied cells */ 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; } - /* TODO take wall choice from the level file into account */ - /* TODO detect corners */ - node = (struct ts_node*)cell->next; - cell->next = 0; - - if(i >= lvl->height - 1 || cell[lvl->width].type == CELL_SOLID) { - cell->wall[0] = TILE_STRAIGHT; - } - if(j >= lvl->width - 1 || cell[1].type == CELL_SOLID) { - cell->wall[1] = TILE_STRAIGHT; - } - if(i <= 0 || cell[-lvl->width].type == CELL_SOLID) { - cell->wall[2] = TILE_STRAIGHT; - } - if(j <= 0 || cell[-1].type == CELL_SOLID) { - cell->wall[3] = TILE_STRAIGHT; + 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++; } } @@ -214,154 +211,147 @@ err: #ifndef LEVEL_EDITOR -static int load_tileset(struct level *lvl, struct ts_node *tsn) -{ - static const char *tile_types[] = { - "open", "straight", "corner", "tee", "cross", "str2open", 0 - }; - - int i; - char *path; - const char *str; - struct ts_node *node; - struct tile *tile; - - node = tsn->child_list; - while(node) { - if(strcmp(node->name, "tile") == 0) { - if(!(tile = calloc(1, sizeof *tile))) { - fprintf(stderr, "failed to allocate tile\n"); - return -1; - } - if((str = ts_get_attr_str(node, "name", 0))) { - tile->name = strdup(str); - } - if((str = ts_get_attr_str(node, "type", 0))) { - for(i=0; tile_types[i]; i++) { - if(strcmp(str, tile_types[i]) == 0) { - tile->type = i; - break; - } - } - } - if((str = ts_get_attr_str(node, "scene", 0))) { - if(lvl->dirname) { - path = alloca(strlen(lvl->dirname) + strlen(str) + 2); - combine_path(lvl->dirname, str, path); - } else { - path = (char*)str; - } - load_scenefile(&tile->scn, path); - } - - if(tile->name && tile->scn.meshlist) { /* valid tile */ - tile->next = lvl->tiles; - lvl->tiles = tile; - } else { - fprintf(stderr, "load_tileset: skipping invalid tile: %s\n", - tile->name ? tile->name : "missing tile name"); - free(tile); - } - } - node = node->next; - } - - return 0; -} - -struct tile *find_level_tile(struct level *lvl, int type) +static int get_cell_type(struct level *lvl, int x, int y) { - struct tile *tile = lvl->tiles; - while(tile) { - if(tile->type == type) { - return tile; - } - tile = tile->next; + if(x < 0 || x >= lvl->width || y < 0 || y >= lvl->height) { + return CELL_SOLID; } - return 0; + return lvl->cells[y * lvl->width + x].type; } -int gen_cell_geom(struct level *lvl, struct cell *cell) +static int detect_cell_tile(struct level *lvl, int x, int y, int *rot) { - int i; - struct meshgroup *wallgeom; - struct tile *tstr; - struct mesh *mesh, *tmesh; - float xform[16]; - - if(!(tstr = find_level_tile(lvl, TILE_STRAIGHT))) { - return -1; - } - - if(!(wallgeom = malloc(sizeof *wallgeom))) { - return -1; - } - init_meshgroup(wallgeom); - - for(i=0; i<4; i++) { - if(cell->wall[i] == TILE_STRAIGHT) { /* TODO: support other wall types */ - cgm_mrotation_y(xform, i * M_PI / 2.0f); - - tmesh = tstr->scn.meshlist; - while(tmesh) { - if(!(mesh = malloc(sizeof *mesh))) { - return -1; - } - - /* create a copy of the tile mesh */ - if(copy_mesh(mesh, tmesh) == -1) { - free(mesh); - return -1; - } - if(i) xform_mesh(mesh, xform); /* rotate it to match the wall angle */ - - /* add it to the level meshlist */ - mesh->next = lvl->meshlist; - lvl->meshlist = mesh; - - /* add it to the meshgroup */ - if(add_meshgroup_mesh(wallgeom, mesh) == -1) { - destroy_mesh(mesh); - free(mesh); - return -1; - } - - tmesh = tmesh->next; + 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++; } } - /* TODO: append to other existing meshgroups for detail objects */ - cell->mgrp = wallgeom; - cell->num_mgrp = 1; - - return 0; -} - -int gen_level_geom(struct level *lvl) -{ - int i, j; - struct cell *cell; + *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; + } - for(i=0; iheight; i++) { - for(j=0; jwidth; j++) { - cell = lvl->cells + i * lvl->width + j; - if(cell->type != CELL_SOLID) { - if(gen_cell_geom(lvl, cell) == -1) { - printf("failed to generate cell\n"); - return -1; - } - } + if((adj & 0070) == 0050) { + *rot = 1; /* straight N-S */ + return TILE_STR; + } + if((adj & 0202) == 0202) { + return TILE_STR; /* straight E-W */ } } - return 0; -} -#else - -static int load_tileset(struct level *lvl, struct ts_node *tsn) -{ - return 0; /* in the level editor we don't need tileset loading */ + return TILE_OPEN; } #endif /* !LEVEL_EDITOR */