#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "defs.h" #include "flag.h" #include "io.h" #include "move.h" #include "nexus.h" #include "lf.h" #include "map.h" #include "objects.h" #include "text.h" #include "vault.h" vault_t *firstvault = NULL, *lastvault = NULL; extern lifeform_t *player; extern enum GAMEMODE gamemode; vlegend_t *addlegend(vault_t *v, int ch, enum VAULTTHING tt, int pct, char *what, enum VAULTTHING tt2, char *what2) { vlegend_t *l; // add to the end of the list if (v->legend == NULL) { v->legend = malloc(sizeof(vlegend_t)); l = v->legend; l->prev = NULL; } else { // go to end of list l = v->lastlegend; l->next = malloc(sizeof(vlegend_t)); l->next->prev = l; l = l->next; } v->lastlegend = l; l->next = NULL; l->vault = v; // props l->ch = ch; l->tt = tt; l->pct = pct; l->what = strdup(what); // alternatives... l->tt2 = tt2; if (what2) { l->what2 = strdup(what2); } else { l->what2 = strdup(""); } return l; } vault_t *addvault(void) { vault_t *v; if (firstvault == NULL) { firstvault = malloc(sizeof(vault_t)); v = firstvault; v->prev = NULL; } else { // go to end of list v = lastvault; v->next = malloc(sizeof(vault_t)); v->next->prev = v; v = v->next; } lastvault = v; v->next = NULL; // props v->filename = NULL; // will be filled in during load. v->id = NULL; if (v == firstvault) { v->numid = 0; } else { v->numid = lastvault->numid+1; } v->valid = B_TRUE; v->state = VS_ALLOCATED; v->flags = addflagpile(NULL, NULL); v->legend = NULL; v->lastlegend = NULL; v->map[0].mlen = 0; v->map[0].w = 0; v->map[0].h = 0; v->nmaps = 0; return v; } // add content to vault based on legend void addvaultcellcontents(cell_t *c, vault_t *v, int x, int y, int rotation) { char ch; vlegend_t *l; // set cell's vault id before adding anything // this is needed for things like shopkeepers // and shop items. c->room->vault = v; ch = getvaultchar(v, x, y, rotation, NULL); // does this char give us a monster/object? for (l = v->legend ; l ; l = l->next) { if (l->ch == ch) { if (rnd(1,100) <= l->pct) { addvaultthing(c, v, l->tt, l->what); } else if (l->tt2 != VT_NONE) { addvaultthing(c, v, l->tt2, l->what2); } } } } // add vault contents based on flags void addvaultcontents(map_t *m, vault_t *v, int minx, int miny, int maxx, int maxy, int rotation) { flag_t *f; char buf[BUFLEN]; int db = B_FALSE; int x,y,b; cell_t *c; if (db) dblog("addvaultcontenets started for vaulttype %s, version %d",v->id, rotation); foreach_bucket(b) { for (f = v->flags->first[b] ; f ; f = f->next) { if ((f->id == F_VAULTATOB) || (f->id == F_VAULTATLF) || (f->id == F_VAULTATCELL)) { if (rnd(1,100) <= f->val[2]) { cell_t *c; int x,y; getadjustedcoords(v, f->val[0], f->val[1], minx, miny, maxx, maxy, rotation, &x, &y); c = getcellat(m, x, y); if (c) { enum VAULTTHING vt; switch (f->id) { default: case F_VAULTATOB: vt = VT_OB; break; case F_VAULTATLF: vt = VT_LF; break; case F_VAULTATCELL: vt = VT_CELL; break; } addvaultthing(c, v, vt, f->text); } } } else if (f->id == F_VAULTATONEOF) { if (rnd(1,100) <= f->val[1]) { int x[10],y[10]; int nposs = 0,sel; int selx,sely; char *p; enum VAULTTHING vt; // get a list of all of the possible locations for this object p = f->text; while (*p == '(') { // go past '(' p++; // get x p = readuntil(buf, p, ','); x[nposs] = atoi(buf); // get y p = readuntil(buf, p, ')'); y[nposs] = atoi(buf); nposs++; } // go past whitespace - we'll end up on the thing name while (isspace(*p)) p++; // select random position sel = rnd(0,nposs-1); getadjustedcoords(v, x[sel], y[sel], minx, miny, maxx, maxy, rotation, &selx, &sely); c = getcellat(m, selx, sely); // get thing type vt = f->val[0]; // add thing addvaultthing(c, v, vt, p); } } else if (f->id == F_VAULTEXIT) { cell_t *c; int x,y; getadjustedcoords(v, f->val[0], f->val[1], minx, miny, maxx, maxy, rotation, &x, &y); c = getcellat(m, x, y); if (c) { addflag(c->map->flags, F_ROOMEXIT, getroomid(c), c->x, c->y, "from f_vaultexit"); } } else if ( (f->id == F_VAULTBOX) && (rnd(1,100) <= f->val[1]) ) { char *p; char thingname[BUFLEN]; int x1,y1,x2,y2,x,y; // get relative range p = f->text; p = readuntil(buf, p, ','); x1 = atoi(buf); p = readuntil(buf, p, ','); y1 = atoi(buf); /* if (x1 < 0) x1 = maxx + x1 + 1; else x1 += minx; if (y1 < 0) y1 = maxy + y1 + 1; else y1 += miny; */ getadjustedcoords(v, x1, y1, minx, miny, maxx, maxy, rotation, &x1, &y1); p = readuntil(buf, p, ','); x2 = atoi(buf); p = readuntil(buf, p, ','); y2 = atoi(buf); /* if (x2 < 0) x2 = maxx + x2 + 1; else x2 += minx; if (y2 < 0) y2 = maxy + y2 + 1; else y2 += miny; */ getadjustedcoords(v, x2, y2, minx, miny, maxx, maxy, rotation, &x2, &y2); // now figure out the top left and bottom right..... getboundingbox(x1, y1, x2, y2, &x1, &y1, &x2, &y2); p = readuntil(buf, p, ','); strcpy(thingname,buf); // fill in for (y = y1; y <= y2; y++) { for (x = x1; x <= x2; x++) { int doit = B_FALSE; if (f->val[2] == B_TRUE) { // ie. fill doit = B_TRUE; } else { // ie. box if ((x == x1) || (x == x2) || (y == y1) || (y == y2)) { doit = B_TRUE; } } if (doit) { cell_t *c; c = getcellat(m, x, y); if (c) { // add the thing addvaultthing(c, v, f->val[0], thingname); } } } } // end foreach x/y } else if ( (f->id == F_VAULTSCATTER) && (rnd(1,100) <= f->val[1]) ) { char *p; char thingname[BUFLEN]; cell_t *poss[MAXCANDIDATES]; // TODO: should be maxroomsize int nposs = 0; int totcells = 0; int i,nplaced; int x1,y1,x2,y2,x,y; int countmin,countmax,count; if (db) dblog("room is %d,%d-%d,%d (%dx%d)",minx,miny,maxx,maxy,maxx-minx,maxy-miny); // get relative range p = f->text; p = readuntil(buf, p, ','); x1 = atoi(buf); p = readuntil(buf, p, ','); y1 = atoi(buf); /* if (x1 < 0) x1 = maxx + x1 + 1; else x1 += minx; if (y1 < 0) y1 = maxy + y1 + 1; else y1 += miny; */ getadjustedcoords(v, x1, y1, minx, miny, maxx, maxy, rotation, &x1, &y1); p = readuntil(buf, p, ','); x2 = atoi(buf); p = readuntil(buf, p, ','); y2 = atoi(buf); /* if (x2 < 0) x2 = maxx + x2 + 1; else x2 += minx; if (y2 < 0) y2 = maxy + y2 + 1; else y2 += miny; */ getadjustedcoords(v, x2, y2, minx, miny, maxx, maxy, rotation, &x2, &y2); p = readuntil(buf, p, '-'); countmin = atoi(buf); p = readuntil(buf, p, ','); countmax = atoi(buf); p = readuntil(buf, p, ','); strcpy(thingname,buf); // now figure out the top left and bottom right..... getboundingbox(x1, y1, x2, y2, &x1, &y1, &x2, &y2); if (db) dblog("subregion is %d,%d-%d,%d (%dx%d)",x1,y1,x2,y2,x2-x1,y2-y1); // get list of cells nposs = 0; totcells = 0; for (y = y1; y <= y2; y++) { for (x = x1; x <= x2; x++) { cell_t *c; c = getcellat(m, x, y); if (c) { int valid = B_TRUE; totcells++; if (c->locked) { valid = B_FALSE; } else if (f->val[0] == VT_LF) { // make sure it's walkable if (!cellwalkable(NULL, c, NULL)) valid = B_FALSE; } else if (f->val[0] == VT_OB) { // make sure it's not solid if (c->type->solid) valid = B_FALSE; } if (valid) { poss[nposs++] = c; } } } } // end foreach x/y if (db) dblog("cells counted=%d, valid=%d",totcells,nposs); if (totcells == 0) { dblog("PROBLEM: couldn't find place to put vaultscatter thing!"); msg("PROBLEM: couldn't find place to put vaultscatter thing!"); } // figure out how many to place if (countmax == PCT) { count = pctof(countmin, nposs); } else { count = rnd(countmin, countmax); } if (db) dblog("nposs=%d, count=%d\n", nposs,count); // now fill in the right amount nplaced = 0; for (i = 0; (i < count) && (nposs > 0); i++) { cell_t *c; int sel,n; // get random cell sel = rnd(0,nposs-1); c = poss[sel]; // put the thing there addvaultthing(c, v, f->val[0], thingname); nplaced++; // remove this cell for (n = sel; n < nposs-1; n++) { poss[n] = poss[n+1]; } nposs--; } if (db) dblog("placed %d\n", nplaced); } } } // set vault id for each cell (except for ones which were // previously marked as reusable via RT_REUSABLE) for (y = miny; y <= maxy; y++) { for (x = minx; x <= maxx; x++) { c = getcellat(m, x, y); if (c && c->room) { c->room->vault = v; } } } } int addvaultthing(cell_t *c, vault_t *v, enum VAULTTHING vt, char *what) { celltype_t *ct; object_t *o; lifeform_t *lf; int rv = B_FALSE; switch (vt) { case VT_EXIT: // mark this position as a room exit addflag(c->map->flags, F_ROOMEXIT, getroomid(c), c->x, c->y, "from addvaultthing"); break; case VT_REUSABLE: // this cell doesn't count as part of the room/vault c->room = NULL; c->locked = B_FALSE; break; case VT_OB: if (streq(what, "random")) { o = addrandomob(c); if (!o) { rv = B_TRUE; } } else { int placeob = B_TRUE; // special case: ot_playerstart will only be placed if: // - game is not already in progress // - there isn't currently one on the level if (streq(what, "playerstart")) { if ((gamemode == GM_GAMESTARTED) || findobinmap(c->map, OT_PLAYERSTART)) { placeob = B_FALSE; } } if (placeob) { o = addob(c->obpile, what); if (!o) { rv = B_TRUE; } } } break; case VT_LF: lf = addmonster(c, R_SPECIFIED, what, B_TRUE, 1, B_TRUE, B_NOEXTRA, NULL); /*if (!lf) { dblog("invalid racename '%s' in vault %s", what, v->id); msg("invalid racename '%s' in vault %s", what, v->id); raise(SIGINT); rv = B_TRUE; }*/ // first lifeform in a shop is the shopkeeper /* if (lf && hasflag(v->flags, F_VAULTISSHOP)) { if (!findshopkeeper(c->map, getroomid(c))) { givejob(lf, J_SHOPKEEPER); } } */ if (lf && hasflag(v->flags, F_MONSTERSSTAY)) { if (!lfhasflag(lf, F_STAYINROOM)) { addflag(lf->flags, F_STAYINROOM, getroomid(c), B_MAYCHASE, NA, NULL); } } break; case VT_CELL: if (streq(what, "EMPTY")) { ct = findcelltype(getmapempty(c->map)); } else if (streq(what, "SOLID")) { ct = findcelltype(getmapsolid(c->map)); } else { ct = findcelltypebyname(what); } setcelltype(c, ct ? ct->id : getmapempty(c->map)); break; default: break; } return rv; } void dumpvault(char *name, int rotation) { int x,y; char buf[BUFLEN]; char *p; vault_t *v; v = findvault(name); if (v) { if (rotation >= v->nmaps) { dblog("vault dump for '%s' failed. vault exists but no such rotation %d (nmaps=%d).",name, rotation, v->nmaps); } dblog("start vault dump(%s,rot=%d):",v->id, rotation); /* // build up a temp map for (y = 0; y < v->map[0].h; y++) { for (x = 0; x < v->map[0].w; x++) { int offset; int ch; ch = getvaultchar(v, x, y, rotation, &offset); temp[offset] = ch; } } // dump the temp map x = 0; y = 0; strcpy(buf, ""); p = buf; for (i = 0; i < v->map[rotation].mlen; i++) { *p = temp[i]; x++; p++; if (x >= v->map[rotation].w) { x = 0; y++; *p = '\0'; dblog("%s",buf); strcpy(buf, ""); p = buf; } } */ strcpy(buf, ""); p = buf; for (y = 0; y < v->map[rotation].h; y++) { for (x = 0; x < v->map[rotation].w; x++) { *p = getvaultchar(v, x, y, rotation, NULL); p++; } *p = '\0'; dblog("%s",buf); strcpy(buf, ""); p = buf; } dblog("end vault dump"); } else { dblog("vault dump for '%s' failed. no such vault.",name); } } vault_t *findvault(char *id) { vault_t *v; for (v = firstvault ; v ; v = v->next) { if (!v->valid) continue; if (streq(v->id, id)) return v; } return NULL; } vault_t *findvaultbyid(int id) { vault_t *v; for (v = firstvault ; v ; v = v->next) { if (!v->valid) continue; if (v->numid == id) return v; } return NULL; } // return a random vault with the given flag. // don't care about rarity. vault_t *findvaultwithflag(enum FLAG fid) { vault_t *v; vault_t *poss[MAXCANDIDATES]; int nposs = 0; for (v = firstvault ; v ; v = v->next) { if (!v->valid) continue; if (hasflag(v->flags, fid)) poss[nposs++] = v; } if (nposs) { v = poss[rnd(0,nposs-1)]; } else { v = NULL; } return v; } // return a random vault with the given tag (ie. f_vaulttag "xxx"). // don't care about rarity. vault_t *findvaultwithtag(char *tag) { vault_t *v; vault_t *poss[MAXCANDIDATES]; int nposs = 0; for (v = firstvault ; v ; v = v->next) { if (!v->valid) continue; if (hasflagval(v->flags, F_VAULTTAG, NA, NA, NA, tag)) poss[nposs++] = v; } if (nposs) { v = poss[rnd(0,nposs-1)]; } else { v = NULL; } return v; } // generate vault map 1 as x-flipped map0. // remember offsets into map[0] void generatevaultflipsx(vault_t *v) { int x,y; v->map[1].mlen = 0; for (y = 0 ; y < v->map[0].h; y++) { for (x = v->map[0].w-1; x >= 0; x--) { int offset; getvaultchar(v, x, y, 0, &offset); v->map[1].data[v->map[1].mlen] = offset; v->map[1].mlen++; } } v->map[1].w = v->map[0].w; v->map[1].h = v->map[0].h; v->nmaps = 2; } // generate vault map 1 as y-flipped map0. // remember offsets into map[0] void generatevaultflipsy(vault_t *v) { int x,y; v->map[1].mlen = 0; for (y = v->map[0].h-1; y >= 0; y--) { for (x = 0 ; x < v->map[0].w; x++) { int offset; getvaultchar(v, x, y, 0, &offset); v->map[1].data[v->map[1].mlen] = offset; v->map[1].mlen++; } } v->map[1].w = v->map[0].w; v->map[1].h = v->map[0].h; v->nmaps = 2; } // generate vault maps 1-3 with offsets into map[0] void generatevaultrotations(vault_t *v) { int i; int x,y; for (i = 1; i <= 3; i++) { // rotate 90degrees from previous v->map[i].mlen = 0; for (x = 0; x < v->map[i-1].w; x++) { for (y = v->map[i-1].h-1; y >= 0; y--) { if (i == 1) { // ie. first rotation int offset; getvaultchar(v, x, y, 0, &offset); v->map[i].data[v->map[i].mlen] = offset; } else { v->map[i].data[v->map[i].mlen] = v->map[i-1].data[ y * v->map[i-1].w + x ]; } v->map[i].mlen++; } } v->map[i].w = v->map[i-1].h; v->map[i].h = v->map[i-1].w; v->nmaps++; } assert(v->nmaps == 4); } void getadjustedcoords(vault_t *v, int origx, int origy, int minx, int miny, int maxx, int maxy, int rotation, int *retx, int *rety) { int x,y; int db = B_FALSE; int w,h; if (v->map[0].w) { w = v->map[0].w; } else { w = maxx - minx + 1; } if (v->map[0].h) { h = v->map[0].h; } else { h = maxy - miny + 1; } if (db) dblog("adjustcoords: %d,%d with mapcoord base %d,%d",origx,origy,minx,miny); // first get coords if this was map #0 (unrotated). if (origx >= 0) { x = origx; } else { // offset from right. -1 is rightmost. x = w + origx; } if (origy >= 0) { y = origy; } else { // offset from bottom. -1 is bottommost. y = h + origy; } if (db) dblog("adjustcoords: %d,%d translates to vaultcoords %d,%d (vault w=%d,h=%d)",origx,origy,x,y, w, h); // now rotate them rotatecoords(&x, &y, v, rotation, NULL); if (db) dblog("adjustcoords: -> rotated to vaultcoords %d,%d (rotation=%d)",x, y,rotation ); // now change them to map coords rather than vault coords x += minx; y += miny; if (db) dblog("adjustcoords: -> translated to mapcoords %d,%d",x, y); // return values *retx = x; *rety = y; } void getboundingbox(int x1, int y1, int x2, int y2, int *retleft, int *rettop, int *retright, int *retbottom) { int left,right,top,bottom; if (x1 < x2) { left = x1; right = x2; } else { left = x2; right = x1; } if (y1 < y2) { top = y1; bottom = y2; } else { top = y2; bottom = y1; } if (retleft) *retleft = left; if (retright) *retright = right; if (rettop) *rettop = top; if (retbottom) *retbottom = bottom; } enum RARITY getvaultrarity(vault_t *v) { flag_t *f; f = hasflag(v->flags, F_VAULTRARITY); if (f) { return f->val[0]; } return RR_COMMON; } void getvaultwh(vault_t *v, int *w, int *h, int rotation) { assert(rotation < v->nmaps); *w = v->map[rotation].w; *h = v->map[rotation].h; } char *getvstatename(enum VAULTSTATE vs) { switch (vs) { case VS_ALLOCATED: return "allocated"; case VS_NOID: return "no ID"; case VS_LOADING: return "loading (toplevel)"; case VS_LOADINGMAP: return "loading map"; case VS_LOADINGLEGEND: return "loading legend"; case VS_LOADINGFLAGS: return "loading flags"; default: break; } return "?unknown?"; } celltype_t *getvaultcelltype(vault_t *v, int x, int y, int rotation) { char ch; celltype_t *ct = NULL; vlegend_t *l; ch = getvaultchar(v, x, y, rotation, NULL); // does this char give us a cell? for (l = v->legend ; l ; l = l->next) { if ((l->ch == ch) && (l->tt == VT_CELL)) { ct = findcelltypebyname(l->what); break; } } return ct; } // return that character at position x/y on give map rotation char getvaultchar(vault_t *v, int x, int y, int rotation, int *map0offset) { char ch; int offset; //rotatecoords(&x, &y, v, rotation, &offset); assert(rotation < v->nmaps); offset = y * v->map[rotation].w + x; if (rotation == 0) { ch = v->map[0].data[offset]; } else { ch = v->map[0].data[v->map[rotation].data[offset]]; } if (map0offset) *map0offset = offset; return ch; } // select a random vault type for the given map vault_t *getvaulttype(map_t *m) { vault_t *v; vault_t *poss[MAXCANDIDATES]; int nposs = 0; enum RARITY rr = RR_COMMON; // select random rarity rr = pickrr(TT_VAULT, NA); while (!nposs) { for (v = firstvault ; v ; v = v->next) { if (!v->valid) continue; if (hasflag(v->flags, F_NORANDOM)) continue; if (getvaultrarity(v) != rr) continue; // can this vault go in this map? if (vaultokformap(v, m)) { poss[nposs++] = v; } } if (nposs > 0) { return poss[rnd(0,nposs-1)]; } // if we have no possibilities, lower rarity and try again if (rr == RR_FREQUENT) { // give up. break; } else { rr--; } } return NULL; } int handleline(vault_t *v, char *line) { int ok = B_FALSE; char localline[BUFLEN]; char *command = NULL,*temp; char *dummy; char *arg[MAXVAULTARGS]; int nargs = 0; int i; int hasfire = B_FALSE; if (!strlen(line)) return B_FALSE; if (line[0] == '!') return B_FALSE; strcpy(localline, line); if (v->state == VS_LOADINGMAP) { if (streq(localline, "@end")) { // go to toplevel loading state v->state = VS_LOADING; ok = B_TRUE; } else if (strstarts(localline, "random(")) { char *p; int minw,minh; p = localline + 7; if (*p) { char buf[BUFLEN]; p = readuntil(buf, p, ','); minw = atoi(buf); p = readuntil(buf, p, ')'); minh = atoi(buf); addflag(v->flags, F_VAULTRANDOMMAP, minw, minh, NA, NULL); } else { dblog("error - random() map data is missing minw/minh values."); return B_TRUE; } addflag(v->flags, F_VAULTRANDOMMAP, minw, minh, NA, NULL); ok = B_TRUE; } else { // map line definition if (hasflag(v->flags, F_VAULTRANDOMMAP)) { dblog("error - map data found after randommap."); return B_TRUE; } // check length if ((v->map[0].w != 0) && (strlen(localline) != v->map[0].w)) { dblog("incorrect map line length! %d != %d", strlen(localline), v->map[0].w); } else { char *p; // read a new map line. we already read into map[0]. // the others will be populated automatically if/when we // add f_vaultmayrotate for (p = localline ; *p; p++) { v->map[0].data[v->map[0].mlen] = *p; v->map[0].mlen++; } ok = B_TRUE; // increase width/height if (!v->map[0].w) { v->map[0].w = strlen(localline); } v->map[0].h++; } } } else { // split into command and args if (strchr(localline, ':')) { temp = strtok_r(localline, ":", &dummy); command = strdup(temp); temp = strtok_r(NULL, ":", &dummy); while (temp) { arg[nargs] = strdup(temp); nargs++; temp = strtok_r(NULL, ":", &dummy); } } else { command = strdup(localline); nargs = 0; } // process command and args if (v->state == VS_NOID) { // haven't for our id yet if (streq(command, "@id")) { if (!v->id) { if (nargs == 1) { if (strchr(arg[0], ' ')) { dblog("Vault names may not contain spaces: '%s'.", arg[0]); return B_TRUE; } else if (findvault(arg[0])) { dblog("Duplicate vault id %s", arg[0]); return B_TRUE; } v->id = strdup(arg[0]); v->state = VS_LOADING; ok = B_TRUE; } else { dblog("invalid syntax for @id"); } } else { dblog("@id command found but we already have an id"); } } } else if (v->state == VS_LOADING) { // toplevel if (streq(line, "@map")) { v->nmaps = 1; v->state = VS_LOADINGMAP; ok = B_TRUE; } else if (streq(line, "@legend")) { v->state = VS_LOADINGLEGEND; ok = B_TRUE; } else if (streq(line, "@flags")) { v->state = VS_LOADINGFLAGS; ok = B_TRUE; } } else if (v->state == VS_LOADINGLEGEND) { if (streq(line, "@end")) { v->state = VS_LOADING; ok = B_TRUE; } else { // legend definition if (nargs >= 2) { int pct; enum VAULTTHING tt,tt2; char what[BUFLEN],what2[BUFLEN]; // default is no alternative tt2 = VT_NONE; strcpy(what2, ""); // get ob specification tt = strtovt(arg[0]); strcpy(what, arg[1]); if (nargs >= 3) { // ie have a percentage pct = atoi(arg[2]); } else { pct = 100; } if (nargs == 5) { // have alternative value if percentage fails tt2 = strtovt(arg[3]); strcpy(what2, arg[4]); } if (nargs == 4) { dblog("alternative obtype given but no alternative ob text"); } else if (tt == VT_NONE) { dblog("invalid type in legend definition"); } else { int error = B_FALSE; if (!real_vaultthingok(tt, what, &hasfire)) { dblog("invalid legend definition: '%s'", line); error = B_TRUE; } if ((tt2 != VT_NONE) && !real_vaultthingok(tt2,what2, &hasfire)) { dblog("invalid legend alternative definition: '%s' (what2='%s')", line,what2); error = B_TRUE; } if (!error) { // validated ok. addlegend(v, command[0], tt, pct, what, tt2, what2); ok = B_TRUE; } } } else { // special legend types... if (streq(arg[0], "exit")) { addlegend(v, command[0], VT_EXIT, 100, "", VT_NONE, NULL); ok = B_TRUE; } else if (streq(arg[0], "reusable")) { addlegend(v, command[0], VT_REUSABLE, 100, "", VT_NONE, NULL); ok = B_TRUE; } else { dblog("invalid syntax for legend value"); } } } } else if (v->state == VS_LOADINGFLAGS) { if (streq(line, "@end")) { v->state = VS_LOADING; ok = B_TRUE; } else { // handle flags if (strstarts(line, "at(")) { // at(x,y) type:what[:pct] int x,y; enum FLAG flagtype; char *p; char buf[BUFLEN]; char thingname[BUFLEN]; enum VAULTTHING vt = VT_NONE; int pct; // get x p = line + 3; p = readuntil(buf, p, ','); x = atoi(buf); // get y p = readuntil(buf, p, ')'); y = atoi(buf); // go past whitespace while (isspace(*p)) p++; // get type p = readuntil(buf, p, ':'); if (streq(buf, "ob")) { vt = VT_OB; flagtype = F_VAULTATOB; } else if (streq(buf, "mon") || streq(buf, "lf")) { vt = VT_LF; flagtype = F_VAULTATLF; } else { // ie. cell vt = VT_CELL; flagtype = F_VAULTATCELL; } // get thing name p = readuntil(buf, p, ':'); strcpy(thingname, buf); // optional percent chance if (*p) { p = readuntil(buf, p, ':'); pct = atoi(buf); } else { pct = 100; } if (real_vaultthingok(vt, thingname, &hasfire)) { addflag(v->flags, flagtype, x, y, pct, thingname); ok = B_TRUE; } else { dblog("invalid at() definition: '%s'", line); } } else if (strstarts(line, "atoneof(")) { // atoneof(x,y)(x,y)(x,y)...(x,y) type:what[:pct] // can have up to 10 x,y pairs. int x[10],y[10]; int nposs = 0; char *p; char buf[BUFLEN]; char thingname[BUFLEN]; enum VAULTTHING vt = VT_NONE; int pct; p = line + 7; while (*p == '(') { // go past '(' p++; // get x p = readuntil(buf, p, ','); x[nposs] = atoi(buf); // get y p = readuntil(buf, p, ')'); y[nposs] = atoi(buf); nposs++; } // go past whitespace while (isspace(*p)) p++; // get type p = readuntil(buf, p, ':'); if (streq(buf, "ob")) { vt = VT_OB; } else if (streq(buf, "mon") || streq(buf, "lf")) { vt = VT_LF; } else { // ie. cell vt = VT_CELL; } // get thing name p = readuntil(buf, p, ':'); strcpy(thingname, buf); // optional percent chance if (*p) { p = readuntil(buf, p, ':'); pct = atoi(buf); } else { pct = 100; } if (nposs) { if (real_vaultthingok(vt, thingname, &hasfire)) { int i; char locbuf[BUFLEN]; // construct string for all the possible positions strcpy(buf, ""); for (i = 0; i < nposs; i++) { snprintf(locbuf, BUFLEN, "(%d,%d)",x[i],y[i]); strcat(buf, locbuf); } snprintf(locbuf, BUFLEN, " %s",thingname); strcat(buf, locbuf); addflag(v->flags, F_VAULTATONEOF, vt, pct, NA, buf); ok = B_TRUE; } else { dblog("invalid vaultthing in atoneof() definition: '%s'", line); } } else { dblog("no x/y coords found in atoneof() definition: '%s'", line); } } else if (strstarts(line, "exitat(")) { // mark a vault exit // exitat(x,y) int x,y; char *p; char buf[BUFLEN]; // get x p = line + 3; p = readuntil(buf, p, ','); x = atoi(buf); // get y p = readuntil(buf, p, ')'); y = atoi(buf); addflag(v->flags, F_VAULTEXIT, x, y, NA, NULL); ok = B_TRUE; } else if (strstarts(line, "box(")) { // outline region // box(x,y,x2,y2) type:what[:pct] // if x2/y2 are negative, count back from w/h. ie x=-1 means 'rightmost cell' int x1,y1,x2,y2; enum VAULTTHING thingtype; char *p; char buf[BUFLEN]; char thingname[BUFLEN]; int pct; p = line + 4; // get x/y p = readuntil(buf, p, ','); x1 = atoi(buf); p = readuntil(buf, p, ','); y1 = atoi(buf); // get x2/y2 p = readuntil(buf, p, ','); x2 = atoi(buf); p = readuntil(buf, p, ')'); y2 = atoi(buf); // go past whitespace while (isspace(*p)) p++; // get type p = readuntil(buf, p, ':'); if (streq(buf, "ob")) { thingtype = VT_OB; } else if (streq(buf, "mon") || streq(buf, "lf")) { thingtype = VT_LF; } else { // ie. cell thingtype = VT_CELL; } // get thing name p = readuntil(buf, p, ':'); strcpy(thingname, buf); // optional percent chance if (*p) { p = readuntil(buf, p, ':'); pct = atoi(buf); } else { pct = 100; } if (real_vaultthingok(thingtype, thingname, &hasfire)) { snprintf(buf, BUFLEN, "%d,%d,%d,%d,%s",x1,y1,x2,y2,thingname); addflag(v->flags, F_VAULTBOX, thingtype, pct, B_FALSE, buf); ok = B_TRUE; } else { dblog("thingok() failed in box definition: '%s'", line); } } else if (strstarts(line, "fill(")) { // fill region // fill(x,y,x2,y2) type:what[:pct] // if x2/y2 are negative, count back from w/h. ie x=-1 means 'rightmost cell' int x1,y1,x2,y2; enum VAULTTHING thingtype; char *p; char buf[BUFLEN]; char thingname[BUFLEN]; int pct; p = line + 5; // get x/y p = readuntil(buf, p, ','); x1 = atoi(buf); p = readuntil(buf, p, ','); y1 = atoi(buf); // get x2/y2 p = readuntil(buf, p, ','); x2 = atoi(buf); p = readuntil(buf, p, ')'); y2 = atoi(buf); // go past whitespace while (isspace(*p)) p++; // get type p = readuntil(buf, p, ':'); if (streq(buf, "ob")) { thingtype = VT_OB; } else if (streq(buf, "mon") || streq(buf, "lf")) { thingtype = VT_LF; } else { // ie. cell thingtype = VT_CELL; } // get thing name p = readuntil(buf, p, ':'); strcpy(thingname, buf); // optional percent chance if (*p) { p = readuntil(buf, p, ':'); pct = atoi(buf); } else { pct = 100; } if (real_vaultthingok(thingtype, thingname, &hasfire)) { snprintf(buf, BUFLEN, "%d,%d,%d,%d,%s",x1,y1,x2,y2,thingname); addflag(v->flags, F_VAULTBOX, thingtype, pct, B_TRUE, buf); ok = B_TRUE; } else { dblog("thingok failed in fill() definition: '%s'", line); dblog("failed thingname: '%s'", thingname); } } else if (strstarts(line, "scatter(")) { // fill region // scatter(x,y,x2,y2) type:what:howmany[:pct] // if x2/y2 are negative, count back from w/h. ie x=-1 means 'rightmost cell' int x1,y1,x2,y2; enum VAULTTHING thingtype; char *p; char buf[BUFLEN]; char thingname[BUFLEN]; int pct; int countmin,countmax; p = line + 8; // get x/y p = readuntil(buf, p, ','); x1 = atoi(buf); p = readuntil(buf, p, ','); y1 = atoi(buf); // get x2/y2 p = readuntil(buf, p, ','); x2 = atoi(buf); p = readuntil(buf, p, ')'); y2 = atoi(buf); // go past whitespace while (isspace(*p)) p++; // get type p = readuntil(buf, p, ':'); if (streq(buf, "ob")) { thingtype = VT_OB; } else if (streq(buf, "mon") || streq(buf, "lf")) { thingtype = VT_LF; } else { // ie. cell thingtype = VT_CELL; } // get thing name p = readuntil(buf, p, ':'); strcpy(thingname, buf); // get count p = readuntil(buf, p, ':'); // is this a range? if (strchr(buf, '-') && strchr(buf, '%')) { dblog("error - scatter() count contains both range and percentage."); return B_TRUE; } else if (strchr(buf, '-')) { char *p2; char buf2[BUFLENSMALL]; p2 = readuntil(buf2, buf, '-'); countmin = atoi(buf2); p2 = readuntil(buf2, p2, ':'); countmax = atoi(buf2); } else if (strchr(buf, '%')) { char *p2; p2 = strchr(buf, '%'); // replace % with nul *p2 = '\0'; countmin = atoi(buf); countmax = PCT; } else { countmin = atoi(buf); countmax = countmin; } // optional percent chance if (*p) { p = readuntil(buf, p, ':'); pct = atoi(buf); } else { pct = 100; } if (real_vaultthingok(thingtype, thingname, &hasfire)) { snprintf(buf, BUFLEN, "%d,%d,%d,%d,%d-%d,%s",x1,y1,x2,y2,countmin,countmax,thingname); addflag(v->flags, F_VAULTSCATTER, thingtype, pct, NA, buf); ok = B_TRUE; } else { dblog("invalid scatter() definition: '%s' (thing='%s',min-max=%d-%d,pct=%d)" , line, thingname,countmin,countmax,pct); } } else if (strstarts(line, "autodoors")) { char *p; int pct = 100; p = line + 9; if (*p == ':') { char buf[BUFLEN]; p++; p = readuntil(buf, p, ','); // really jsut want EOL pct = atoi(buf); } addflag(v->flags, F_AUTODOORS, pct, NA, NA, NULL); ok = B_TRUE; } else if (streq(line, "autopop")) { addflag(v->flags, F_AUTOPOPULATE, B_TRUE, NA, NA, NULL); ok = B_TRUE; } else if (strstarts(line, "cellempty")) { char *p; p = line + strlen("cellempty"); if (*p == ':') { char buf[BUFLEN]; celltype_t *ct; p++; p = readuntil(buf, p, ','); // eol // validate celltype name ct = findcelltypebyname(buf); if (ct) { addflag(v->flags, F_CELLTYPEEMPTY, ct->id, NA, NA, NULL); ok = B_TRUE; } else { dblog("invalid celltype specified in cellempty definition: '%s'", line); } } else { dblog("syntax error in cellempty definition: '%s'", line); } } else if (strstarts(line, "cellsolid")) { char *p; p = line + strlen("cellsolid"); if (*p == ':') { char buf[BUFLEN]; celltype_t *ct; p++; p = readuntil(buf, p, ','); // eol // validate celltype name ct = findcelltypebyname(buf); if (ct) { addflag(v->flags, F_CELLTYPESOLID, ct->id, NA, NA, NULL); ok = B_TRUE; } else { dblog("invalid celltype specified in cellsolid definition: '%s'", line); } } else { dblog("syntax error in cellsolid definition: '%s'", line); } } else if (strstarts(line, "dlevmax")) { // dlevmax:max char *p; p = line + 7; if (*p == ':') { int lev; char buf[BUFLEN]; p++; p = readuntil(buf, p, ','); // eol lev = atoi(buf); addflag(v->flags, F_VAULTDLEVMAX, lev, NA, NA, NULL); ok = B_TRUE; } else { dblog("invalid dlevmax definition: '%s'", line); } } else if (strstarts(line, "dlevmin")) { // dlevmin:min char *p; p = line + 7; if (*p == ':') { int lev; char buf[BUFLEN]; p++; p = readuntil(buf, p, ','); // eol lev = atoi(buf); addflag(v->flags, F_VAULTDLEVMIN, lev, NA, NA, NULL); ok = B_TRUE; } else { dblog("invalid dlevmin definition: '%s'", line); } } else if (strstarts(line, "entertext")) { char *p; p = line + 9; if (*p == ':') { char buf[BUFLEN]; p++; p = readuntil(buf, p, ','); // really jsut want EOL if (strlen(buf)) { addflag(v->flags, F_VAULTENTERTEXT, NA, NA, NA, buf); ok = B_TRUE; } else { dblog("invalid entertext definition: '%s' (arglen is 0)",line); } } else { dblog("missing entertext definition: '%s'", line); } } else if (strstarts(line, "goesin")) { char *p; p = line + 6; if (*p == ':') { habitat_t *h; char buf[BUFLEN]; p++; p = readuntil(buf, p, ','); // really jsut want EOL h = findhabitatbyname(buf); if (h) { addflag(v->flags, F_VAULTGOESIN, h->id, NA, NA, NULL); ok = B_TRUE; } else { dblog("invalid goesin() definition: '%s' [BAD HABITAT]", line); } } else { dblog("invalid goesin() definition: '%s'", line); } } else if (streq(line, "keepmonsinroom")) { addflag(v->flags, F_STAYINROOM, NA, B_MAYCHASE, NA, NULL); ok = B_TRUE; } else if (streq(line, "maintainedge")) { addflag(v->flags, F_MAINTAINEDGE, B_TRUE, NA, NA, NULL); ok = B_TRUE; } else if (strstarts(line, "nostairs")) { addflag(v->flags, F_NOSTAIRS, B_TRUE, NA, NA, NULL); ok = B_TRUE; } else if (strstarts(line, "margin")) { char *p; p = line + 6; if (*p == ':') { char buf[BUFLEN]; int xmargin,ymargin; p++; p = readuntil(buf, p, ','); xmargin = atoi(buf); p = readuntil(buf, p, ','); // really EOL ymargin = atoi(buf); addflag(v->flags, F_KEEPMARGIN, xmargin, ymargin, NA, NULL); ok = B_TRUE; } else { dblog("invalid margin flag: '%s'", line); } } else if (streq(line, "mayrotate")) { if (hasflag(v->flags, F_VAULTMAYFLIPX) || hasflag(v->flags, F_VAULTMAYFLIPY)) { dblog("vault can only have one of mayrotate / mayflipx / mayflipy."); } else if (v->nmaps == 1) { addflag(v->flags, F_VAULTMAYROTATE, B_TRUE, NA, NA, NULL); // now generate rotated versions generatevaultrotations(v); ok = B_TRUE; } else { dblog("vault flag mayrotate isnt valid for vaults with random maps."); } } else if (streq(line, "mayflipx")) { if (hasflag(v->flags, F_VAULTMAYROTATE) || hasflag(v->flags, F_VAULTMAYFLIPY)) { dblog("vault can only have one of mayrotate / mayflipx / mayflipy."); } else if (v->nmaps == 1) { addflag(v->flags, F_VAULTMAYFLIPX, B_TRUE, NA, NA, NULL); // now generate rotated versions generatevaultflipsx(v); ok = B_TRUE; } else { dblog("vault flag mayflipx isnt valid for vaults with random maps."); } } else if (streq(line, "mayflipy")) { if (hasflag(v->flags, F_VAULTMAYROTATE) || hasflag(v->flags, F_VAULTMAYFLIPX)) { dblog("vault can only have one of mayrotate / mayflipx / mayflipy."); } else if (v->nmaps == 1) { addflag(v->flags, F_VAULTMAYFLIPY, B_TRUE, NA, NA, NULL); // now generate rotated versions generatevaultflipsy(v); ok = B_TRUE; } else { dblog("vault flag mayflipy isnt valid for vaults with random maps."); } } else if (streq(line, "monstersstay")) { addflag(v->flags, F_MONSTERSSTAY, B_TRUE, NA, NA, NULL); ok = B_TRUE; } else if (streq(line, "nolink")) { addflag(v->flags, F_VAULTNOLINK, B_TRUE, NA, NA, NULL); ok = B_TRUE; } else if (streq(line, "norandom")) { addflag(v->flags, F_NORANDOM, B_TRUE, NA, NA, NULL); addflag(v->flags, F_VAULTRARITY, RR_NEVER, NA, NA, NULL); ok = B_TRUE; } else if (strstarts(line, "rarity")) { char *p; p = line + 6; if (*p == ':') { char buf[BUFLEN]; p++; p = readuntil(buf, p, ','); // really EOL if (streq(buf, "frequent")) { addflag(v->flags, F_VAULTRARITY, RR_FREQUENT, NA, NA, NULL); ok = B_TRUE; } else if (streq(buf, "common")) { addflag(v->flags, F_VAULTRARITY, RR_COMMON, NA, NA, NULL); ok = B_TRUE; } else if (streq(buf, "uncommon")) { addflag(v->flags, F_VAULTRARITY, RR_UNCOMMON, NA, NA, NULL); ok = B_TRUE; } else if (streq(buf, "rare")) { addflag(v->flags, F_VAULTRARITY, RR_RARE, NA, NA, NULL); ok = B_TRUE; } else if (streq(buf, "vrare") || streq(buf, "veryrare")) { addflag(v->flags, F_VAULTRARITY, RR_VERYRARE, NA, NA, NULL); ok = B_TRUE; } else if (streq(buf, "never")) { addflag(v->flags, F_VAULTRARITY, RR_NEVER, NA, NA, NULL); ok = B_TRUE; } else { dblog("invalid rarity value: '%s'", line); } } else { dblog("invalid rarity flag: '%s'", line); } } else if (streq(line, "playerstart")) { addflag(v->flags, F_VAULTISPLAYERSTART, B_TRUE, NA, NA, NULL); ok = B_TRUE; /* } else if (streq(line, "shop")) { addflag(v->flags, F_VAULTISSHOP, B_TRUE, NA, NA, NULL); ok = B_TRUE; */ } else if (strstarts(line, "tag:")) { char *p; p = line + 4; addflag(v->flags, F_VAULTTAG, B_TRUE, NA, NA, p); ok = B_TRUE; } else if (strstarts(line, "usehabitat")) { char *p; p = line + strlen("usehabitat"); if (*p == ':') { habitat_t *h; char buf[BUFLEN]; p++; p = readuntil(buf, p, ','); // really jsut want EOL h = findhabitatbyname(buf); if (h) { if (hasflag(v->flags, F_VAULTHABITAT)) { dblog("multiple usehabitat definitions found: '%s'", line); } else { addflag(v->flags, F_VAULTHABITAT, h->id, NA, NA, NULL); ok = B_TRUE; } } else { dblog("invalid usehabitat() definition: '%s' [BAD HABITAT]", line); } } else { dblog("invalid usehabitat() definition: '%s'", line); } } } } } // free args if (command) free(command); for (i = 0; i < nargs; i++) { free(arg[i]); } if (ok) { // remember if the vault has objects made of fire if (hasfire && !hasflag(v->flags, F_VAULTHASFIRE)) { addflag(v->flags, F_VAULTHASFIRE, B_TRUE, NA, NA, NULL); } } else { dblog("[vault:%s/%s] Invalid line: [%s]", (v->state == VS_NOID) ? "no_id" : v->id, getvstatename(v->state), line); return B_TRUE; } return B_FALSE; } void killlegend(vlegend_t *l) { vlegend_t *nextone,*lastone; if (l->what) free(l->what); if (l->what2) free(l->what2); // deallocate nextone = l->next; if (nextone != NULL) { nextone->prev = l->prev; } else { /* last */ l->vault->lastlegend = l->prev; } if (l->prev == NULL) { /* first */ nextone = l->next; l->vault->legend = nextone; free(l); } else { lastone = l->prev; free (lastone->next ); lastone->next = nextone; } } void killvault(vault_t *v) { vault_t *nextone,*lastone; if (!v) return; if (v->id) free(v->id); if (v->filename) free(v->filename); while (v->legend) { killlegend(v->legend); } killflagpile(v->flags); v->flags = NULL; // deallocate nextone = v->next; if (nextone != NULL) { nextone->prev = v->prev; } else { /* last */ lastvault = v->prev; } if (v->prev == NULL) { /* first */ nextone = v->next; firstvault = nextone; free(v); } else { lastone = v->prev; free (lastone->next ); lastone->next = nextone; } } vault_t *loadvault(char *dir, char *filename) { FILE *f; vault_t *v; char line[BUFLEN]; char fullname[BUFLEN]; int goterrors = B_FALSE; snprintf(fullname, BUFLEN, "%s/%s", dir, filename); dblog("Loading vault file '%s'", fullname); f = fopen(fullname,"rt"); if (!f) { dblog("error opening vault file '%s/%s'", dir,fullname); return NULL; } v = addvault(); if (!v) { dblog("error allocating new vault"); return NULL; } asprintf(&v->filename, "%s/%s",dir,filename); v->state = VS_NOID; // init line. bzero(line, BUFLEN); // read a line fgets(line, BUFLEN, f); while (!feof(f)) { if (strlen(line)) { // strip newline line[strlen(line)-1] = '\0'; // strip trailing spaces while (strlen(line) && line[strlen(line)-1] == ' ') { line[strlen(line)-1] = '\0'; } } // anything left? if (strlen(line)) { // handle it if (handleline(v, line)) { goterrors = B_TRUE; break; } } // read next line fgets(line, BUFLEN, f); } fclose(f); if (goterrors && v) { // mark vault as invalid v->valid = B_FALSE; v = NULL; } else { //dumpvault(v); } return v; } void loadvaults(void) { char *vaultdir[2]; int i; // vaultdir[0] = strdup(VAULTDIR); vaultdir[1] = strdup(BONESDIR); for (i = 0; i < 2; i++) { int nvaults = 0; DIR *dir; struct dirent *ent; dir = opendir(vaultdir[i]); if (!dir) { dblog("Could not open vault directory '%s'",vaultdir[i]); return; } nvaults = 0; while ((ent = readdir(dir)) != NULL) { char *p; // ie. start of 4 char prefix p = ent->d_name + strlen(ent->d_name) - 4; if (!strcmp(p, ".vlt") ) { if (loadvault(vaultdir[i], ent->d_name)) { nvaults++; } else { dblog("Errors found in vaultfile %s - loading cancelled.",ent->d_name); } } } closedir(dir); if (nvaults) { dblog("Successfully loaded %d %s definition%s.", nvaults, (i == 0) ? "fixed vault" : "bones vault", (nvaults == 1) ? "" : "s"); } else { dblog("No (valid) vault definitions found.", nvaults); } } free(vaultdir[0]); free(vaultdir[1]); // debugging //dumpvault("jimbos_lair", 0); //dumpvault("jimbos_lair", 1); //dumpvault("jimbos_lair", 2); //dumpvault("jimbos_lair", 3); } // translate coords on map0 into coords of the same position on map1-3 void rotatecoords(int *x, int *y, vault_t *v, int rotation, int *retoffset) { int offset,newoffset; // get offset in map 0 offset = (*y * (v->map[0].w) + *x); if (hasflag(v->flags, F_VAULTRANDOMMAP)) { // don't need to rotate in random maps if (retoffset) *retoffset = offset; return; } if (rotation == 0) { // leave offset (and therefore x/y) unchanged newoffset = offset; } else { int i; newoffset = -1; // find translated offset for (i = 0; i < v->map[rotation].mlen; i++) { if (v->map[rotation].data[i] == offset) { newoffset = i; break; } } assert(newoffset != -1); } // get new x/y *x = newoffset % v->map[rotation].w; *y = newoffset / v->map[rotation].w; if (retoffset) *retoffset = newoffset; } int vaultthingok(enum VAULTTHING vt, char *what) { return real_vaultthingok(vt, what, NULL); } int real_vaultthingok(enum VAULTTHING vt, char *what, int *hasfire) { celltype_t *ct; object_t *o; race_t *r; obpile_t *op; // default if (hasfire) *hasfire = B_FALSE; switch (vt) { case VT_LF: if (streq(what, "random")) { return B_TRUE; } else { r = findracebyname(what, NULL); if (r) { if (r->material->id == MT_FIRE) { *hasfire = B_TRUE; } return B_TRUE; } else { enum RACE rid; condset_t cs; rid = parserace(what, NULL, &cs, NULL, NULL); if (rid) { if (hasfire) { r = findrace(rid); if (r && (r->material->id == MT_FIRE)) { *hasfire = B_TRUE; } } return B_TRUE; } } } break; case VT_OB: if (streq(what, "random")) { return B_TRUE; } else { op = addobpile(NULL, NULL, NULL); // disable linking of holes o = addobject(op, what, B_TRUE, B_FALSE, OT_NONE); if (o) { if (o->material->id == MT_FIRE) { *hasfire = B_TRUE; } killobpile(op); return B_TRUE; } killobpile(op); } break; case VT_CELL: if (streq(what, "EMPTY") || streq(what, "SOLID")) { return B_TRUE; } ct = findcelltypebyname(what); if (ct) return B_TRUE; break; default: // ie. exit, reusable return B_TRUE; break; } return B_FALSE; } int vaultokformap(vault_t *v, map_t *m) { flag_t *f; celltype_t *floortype; int b; // check HABITAT if (hasflag(v->flags, F_VAULTGOESIN)) { int ok = B_FALSE; // check which habitats are valid foreach_bucket(b) { for (f = v->flags->first[b] ; f ; f = f->next) { if (f->id == F_VAULTGOESIN) { if (f->val[0] == m->habitat->id) { ok = B_TRUE; break; } } } } if (!ok) return B_FALSE; } f = hasflag(v->flags, F_VAULTDLEVMIN); if (f && (getmapdifficulty(m) < f->val[0])) { return B_FALSE; } f = hasflag(v->flags, F_VAULTDLEVMAX); if (f && (getmapdifficulty(m) > f->val[0])) { return B_FALSE; } // if the map's floor is flammable don't make vaults which have objects made of fire floortype = findcelltype(getmapempty(m)); if (hasflag(floortype->material->flags, F_FLAMMABLE)) { if (hasflag(v->flags, F_VAULTHASFIRE)) { return B_FALSE; } } // dont make bones vaults while debugging. if ((gamemode == GM_GAMESTARTED) && hasjob(player, J_GOD)) { if (hasflagval(v->flags, F_VAULTTAG, NA, NA, NA, "bones")) { return B_FALSE; } } return B_TRUE; }