#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" extern map_t *firstmap,*lastmap; extern int viewx,viewy,vieww,viewh; extern lifeform_t *player; extern glyph_t tempglyph; extern enum OBCLASS sortorder[]; cell_t *addcell(map_t *m, int x, int y) { cell_t *cell; m->cell[(y*m->w)+x] = malloc(sizeof(cell_t)); cell = m->cell[(y*m->w)+x]; cell->map = m; cell->x = x; cell->y = y; setcelltype(cell, CT_WALL); cell->visited = B_FALSE; cell->obpile = addobpile(NOOWNER, cell); cell->lf = NULL; cell->roomid = -1; cell->lit = L_NOTLIT; cell->origlit = L_NOTLIT; cell->littimer = 0; cell->origlittimer = 0; cell->writing = NULL; cell->known = B_FALSE; return cell; } map_t *addmap(void) { map_t *a; int id; int i; // is there already a map? if (lastmap) { id = lastmap->id + 1; } else { id = 0; } // add to the end of the list if (firstmap == NULL) { firstmap = malloc(sizeof(map_t)); a = firstmap; a->prev = NULL; } else { // go to end of list a = lastmap; a->next = malloc(sizeof(map_t)); a->next->prev = a; a = a->next; } lastmap = a; a->next = NULL; // props a->id = id; a->lf = NULL; for (i = 0; i < MAXDIR_ORTH; i++) { a->nextmap[i] = -1; } a->beingcreated = B_TRUE; return a; } lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { lifeform_t *lf = NULL; race_t *r; int db = B_FALSE; // ie. don't create mosnters on closed doors! if (!cellwalkable(NULL, c, NULL)) { return NULL; } if ((raceid == R_NONE) || (raceid == R_RANDOM)) { r = getrandomrace(c->map, 0); } else { r = findrace(raceid); } assert(r); if (db) dblog("adding rand lf %s to cell %d,%d",r->name,c->x,c->y); if (r) { //lf = addlf(c, r->id, getrandommonlevel(c->map->depth)); lf = addlf(c, r->id, 1); if (lf) { flag_t *f; lf->born = B_FALSE; if (jobok) { // has a job? f = hasflag(lf->flags, F_STARTJOB); if (f) { if (rnd(1,100) <= f->val[0]) { givejob(lf, f->val[1]); } } } if (lf->cell->map->beingcreated) { // sometimes start off asleep in new maps if (!lfhasflag(lf, F_DEAF)) { // TODO: base this on the time, and whether monster is nocturnal if (rnd(1,2) == 1) { addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); } } } // appears in groups? f = hasflag(lf->flags, F_NUMAPPEAR); if (f) { // override amount amt = rnd(f->val[0], f->val[1]); } if (amt > 1) { cell_t *adjcell; amt--; // we've already added one //adjcell = c; for ( ; amt > 0; amt--) { lifeform_t *newlf; // find an adjacent cell to one of the newly added monsters, // starting with the first one adjcell = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND); // did we find one? if (!adjcell) break; newlf = addlf(adjcell, r->id, 1); if (!newlf) { break; } newlf->born = B_FALSE; if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); newlf->born = B_TRUE; } } // minons? f = hasflag(lf->flags, F_MINIONS); if (f) { if (rnd(1,100) <= f->val[0]) { int n; cell_t *adjcell; int nminions; // override amount nminions = rnd(f->val[1], f->val[2]); for (n = 0; n < nminions; n++) { lifeform_t *newlf; race_t *newr; adjcell = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND); if (!adjcell) break; newr = findracebyname(f->text); if (!newr) break; newlf = addlf(adjcell, newr->id, 1); if (!newlf) break; newlf->born = B_FALSE; if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); newlf->born = B_TRUE; } } } // sometimes give the lf random objects (extra monsters through // 'numappears' don't get them. if (lfhasflag(lf, F_HUMANOID) && !lfhasflag(lf, F_NOPACK)) { if (rnd(1,3) == 1) { int nobs = rnd(1,3); char buf[BUFLEN]; int i; for (i = 0; i < nobs; i++) { if (getrandomob(c->map, buf)) addob(lf->pack, buf); } } } lf->born = B_TRUE; } // end if lf } return lf; } void addrandomob(cell_t *c) { char buf[BUFLEN]; int db = B_FALSE; if (c->type->solid) { return; } if (getrandomob(c->map, buf)) { if (db) dblog("adding rand obj %s to cell %d,%d",buf,c->x,c->y); addob(c->obpile, buf); } } void addrandomthing(cell_t *c, int obchance) { // if there's already someone there, // then add an object. if (c->lf || (rnd(1,100) <= obchance)) { // object addrandomob(c); } else { // monster addmonster(c, R_RANDOM, B_TRUE, 1); } } int cellhaslos(cell_t *c1, cell_t *dest) { int deltax, deltay; int numpixels; int d; int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2; int xinc,yinc,dinc; int i; int x1,y1; int x; int y; //int wentuphill = B_FALSE; //int origheight; //int shopwall; int x2,y2; map_t *map; if (!dest) return B_FALSE; // let the player see when dead, otherwise the screen wil // go black when "You die" appears. map = c1->map; x1 = c1->x; y1 = c1->y; x2 = dest->x; y2 = dest->y; deltax = (x2 - x1); if (deltax < 0) deltax = -deltax; deltay = (y2 - y1); if (deltay < 0) deltay = -deltay; // can always see your own cell if ((deltax == 0) && (deltay == 0)) { return B_TRUE; } if (deltax >= deltay) { numpixels = deltax + 1; d = (deltay*2) - deltax; dinc1 = deltay << 1; dinc2 = (deltay-deltax) << 1; xinc1 = 1; xinc2 = 1; yinc1 = 0; yinc2 = 1; } else { numpixels = deltay + 1; d = (deltax*2) - deltay; dinc1 = deltax << 1; dinc2 = (deltax - deltay) << 1; xinc1 = 0; xinc2 = 1; yinc1 = 1; yinc2 = 1; } if (x1 > x2) { xinc1 = - xinc1; xinc2 = - xinc2; } if (y1 > y2) { yinc1 = - yinc1; yinc2 = - yinc2; } x = x1; y = y1; for (i = 0; i < numpixels ; i++) { cell_t *cell; // don't need to move out of the last one if ((x == x2) && (y == y2)) { break; } if (d < 0) { xinc = xinc1; yinc = yinc1; dinc = dinc1; } else { xinc = xinc2; yinc = yinc2; dinc = dinc2; } // you can always see your own cell if (i != 0) { // solid cells stop los - but if you are standing on a solid // cell you can still see out. cell = getcellat(map, x, y); if (!cell->type->transparent) { return B_FALSE; } /* // check for smoke if ((x != x1) || (y != y1)) { // if not in first cell if (hasopaqueobject(viewer, x,y,z) && (getheight(x,y,z) >= origheight)) { if (!hasproplf(viewer, P_SEEINSMOKE)) { return B_FALSE; } } } */ // check for objects which block view if (hasobwithflag(cell->obpile, F_BLOCKSVIEW)) { return B_FALSE; } } // move to next cell d += dinc; x += xinc; y += yinc; } // made it to the target cell! return B_TRUE; } cell_t *getcellat(map_t *map, int x, int y) { if (!isonmap(map, x, y)) return NULL; return map->cell[y*map->w + x]; } int getcelldist(cell_t *src, cell_t *dst) { double xd,yd; // use pythag xd = abs(dst->x - src->x); yd = abs(dst->y - src->y); return (int)sqrt(xd*xd + yd*yd); } int getcelldistorth(cell_t *src, cell_t *dst) { // add x/y return abs(dst->x - src->x) + abs(dst->y - src->y); } //populates 'g' with the contects of cell 'c', as seen by 'viewer' // if we can't see anything there, set g->ch to NUL. void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) { glyph_t tempgl; // default g->ch = '\0'; if (haslos(viewer, c)) { // show cell contents //drawcellwithcontents(cell, x-viewx, y-viewy); if (c->lf && cansee(viewer, c->lf)) { // lifeform here which we can see // draw the lf's race glyph *g = *(getlfglyph(c->lf)); return; } else { // we can see the floor here void *thing; // scanned lf here? if (isinscanrange(c, &thing, NULL, &tempgl) == TT_MONSTER) { *g = tempgl; //mvwprintw(gamewin, y-viewy, x-viewx, "%c", glyph); //drawglyph(&glyph, x, y); return; } } // objects here? if ((countobs(c->obpile) > 0)) { object_t *o; // draw highest object in sort order o = gettopobject(c); if (o) { *g = *(getglyph(o)); } else { // should never happen. if it does, just show the // first object dblog("Warn: sorted object glyph drawing matching nothing!"); //mvwprintw(gamewin, y, x, "%c", cell->obpile->first->type->obclass->glyph); //drawglyph(&cell->obpile->first->type->obclass->glyph, x, y); *g = c->obpile->first->type->obclass->glyph; } } else { // draw cell normally //drawcell(cell, x, y); *g = c->type->glyph; } } else { // can't see the cell void *thing; //drawscannedcell(cell, x-viewx, y-viewy); switch (isinscanrange(c, &thing, NULL, &tempgl)) { case TT_MONSTER: case TT_OBJECT: *g = tempgl; break; default: if (c->known) { //drawunviscell(cell, x-viewx, y-viewy); object_t *o; // copy from cell *g = c->type->glyph; if (g->ch == '.') { g->ch = ' '; } // show staircases... o = hasobwithflag(c->obpile, F_CLIMBABLE); if (o) { *g = *(getglyph(o)); } // show dungeon features o = hasobofclass(c->obpile, OC_DFEATURE); if (o) { *g = *(getglyph(o)); } } break; } } } enum CELLTYPE getemptycelltype(enum HABITAT hab) { switch (hab) { case H_DUNGEON: return CT_CORRIDOR; default: break; } return CT_CORRIDOR; } object_t *gettopobject(cell_t *where) { object_t *o; int c; // draw highest object in sort order c = 0; while (sortorder[c] != OC_NULL) { // check each object against this ob class // count backwards so more recently dropped objects // appear first. for (o = where->obpile->last ; o ; o = o->prev) { if (o->type->obclass->id == sortorder[c]) { return o; } } c++; } return NULL; } void calclight(map_t *map) { int x,y; cell_t *c; for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { c = getcellat(map, x,y); //if (c && (c->lit == L_PERMLIGHT) && (c->lit != L_PERMDARK)) c->lit = B_FALSE; if (c && (c->lit != L_PERMLIGHT) && (c->lit != L_PERMDARK)) c->lit = B_FALSE; } } for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { c = getcellat(map, x,y); if (c) { int radius; object_t *o; // lit based on depth if ((map->depth <= 5) && (c->lit != L_PERMDARK)) { c->lit = L_PERMLIGHT; } // TODO: has dark producing lf? // TODO: has dark producing object? // has lightproducing lf? (ie.hasflag f_produceslight) if (c->lf) { if (lfhasflag(c->lf, F_PRODUCESLIGHT)) { sumflags(c->lf->flags, F_PRODUCESLIGHT, &radius, NULL, NULL); makelitradius(c, radius, L_TEMP, -1); } // objects in hands or on body... for (o = c->lf->pack->first ; o ; o = o->next) { if (isequipped(o)) { radius = obproduceslight(o); if (radius) { makelitradius(c, radius, L_TEMP, -1); } } } } // has light-producing object on ground? for (o = c->obpile->first ; o ; o = o->next) { radius = obproduceslight(o); if (radius) { makelitradius(c, radius, L_TEMP, -1); } } } } } } int calcroompos(map_t *map, int w, int h, int *bx, int *by) { int x,y; int bestx = -1, besty = -1; int valid = B_FALSE; int bestscore = 9999; cell_t *cell; // try placing room at all positions for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { // would the room fit here? if ( ((x + (w-1)) <= (map->w-1)) && ((y + (h-1)) <= (map->h-1))) { int score = 0; int rx,ry; int notpossible = B_FALSE; valid = B_FALSE; // calculate score based on cells in room for (ry = y; (ry < y+h) && (!notpossible); ry++) { for (rx = x; (rx < x+w) && (!notpossible); rx++) { cell = getcellat(map, rx,ry); // is this cell adjacent to an empty cell and not a // corner (ie. a valid door location) if (countcellexits(cell)) { score++; if ( ((ry == y) && (rx == x)) || ((ry == y) && (rx == (x+w-1))) || ((ry == y+h-1) && (rx == x)) || ((ry == y+h-1) && (rx == (x+w-1))) ) { // corner. } else { // not corner valid = B_TRUE; } } // is this cell empty itself? if (!cell->type->solid) score += 3; // avoid being adjacent to other room walls if (countcellexits(cell)) score++; score += (countadjcellsoftype(cell, CT_ROOMWALL)*3); // overlapping another room? if (cell->type->id == CT_ROOM) { valid = B_FALSE; notpossible = B_TRUE; } if (cell->type->id == CT_ROOMWALL) { valid = B_FALSE; notpossible = B_TRUE; } } } if (valid && (score != 0) && (score < bestscore)) { bestscore = score; bestx = x; besty = y; } } } } *bx = bestx; *by = besty; if ((bestx == -1) || (besty == -1)) { return B_TRUE; } return B_FALSE; } int countadjcellswithflag(cell_t *cell, enum FLAG fid) { int d; int count = 0; cell_t *newcell; for (d = D_N; d < MAXDIR_ORTH; d++) { newcell = getcellindir(cell, d); if (newcell && hasobwithflag(cell->obpile, fid)) { count++; } } return count; } int countadjcellsoftype(cell_t *cell, int id) { int d; int count = 0; cell_t *newcell; for (d = D_N; d < MAXDIR_ORTH; d++) { newcell = getcellindir(cell, d); if (newcell && newcell->type->id == id) { count++; } } return count; } int countcellexits(cell_t *cell) { int d; int exits = 0; cell_t *newcell; assert(cell); for (d = D_N; d < MAXDIR_ORTH; d++) { newcell = getcellindir(cell, d); if (newcell && !newcell->type->solid) { exits++; } } return exits; } /* seed = random number seed turnpct = percentage change of a corridor turning sparseness = how many times to chop off dead ends looppct = percentage change of turning dead-end into loop maxrooms = max # of rooms */ void createmap(map_t *map, int depth, int habitat) { char buf[BUFLEN]; int wantrooms = B_TRUE; int x,y; int d; int i; int done,unused; int dir; int lastdir; int numrooms = 0; int roomw[MAXROOMS],roomh[MAXROOMS]; //int roomspecial[MAX_MAPROOMS]; int minroomw = MIN_ROOMW; int minroomh = MIN_ROOMH; int maxroomw = MAX_ROOMW; int maxroomh = MAX_ROOMH; int bestx,besty; int w,h; //int startdir,forcex,forcey,ntries; cell_t *cell, *c; object_t *o; int db = B_FALSE; // parameters int turnpct = DEF_TURNPCT; int sparseness = DEF_SPARSENESS; int looppct = DEF_LOOPPCT; int minrooms = MINROOMS; int maxrooms = MAXROOMS; int moved = 0; enum CELLTYPE emptycell; //int db = B_TRUE; map->beingcreated = B_TRUE; sprintf(buf, "Map %d",map->id); map->name = strdup(buf); map->habitat = habitat; for (i = 0; i < MAXDIR_ORTH; i++) { map->nextmap[i] = -1; } map->w = MAX_MAPW; map->h = MAX_MAPH; // map depth? map->depth = depth; // rememebr seed //map->seed = 11734; map->seed = rand() % 65535; srand(map->seed); // fill entire maze with walls for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { addcell(map, x, y); } } // what kind of cells will 'empty' ones be? emptycell = getemptycelltype(map->habitat); // pick initial random spot cell = getrandomcell(map); setcelltype(cell, emptycell); cell->visited = B_TRUE; //if (db) printf("- Starting (%d,%d)\n",cell->x, cell->y); lastdir = D_UNKNOWN; done = B_FALSE; dir = D_NONE; while (!done) { // get random direction based on turnpct dir = D_NONE; while (dir == D_NONE) { int badcount; //if (db) printf("- At (%d,%d), moved %d, finding new direction...\n",cell->x, cell->y, moved); dir = getnewdigdir(cell, lastdir, (moved < 2) ? 0 : turnpct, &moved); badcount = 0; while (dir == D_NONE) { badcount++; if (badcount > 10) { // finish! done = B_TRUE; break; } // pick new EMPTY random spot cell = getrandomcell(map); while (!isempty(cell)) { cell = getrandomcell(map); } //if (db) printf("--- Couldn't find a valid direction. Jumped to (%d,%d).\n",cell->x, cell->y); // pick a new random dir dir = getnewdigdir(cell, lastdir, turnpct, &moved); } if (!done) { //if (db) printf("- Digging %s from (%d,%d).\n",getdirname(dir),cell->x, cell->y); } } if (!done) { // move to adjacent cell in the given direction cell = getcellindir(cell, dir); //if (db) printf("- Now at (%d,%d)\n",cell->x, cell->y); moved++; // blank it setcelltype(cell,emptycell); cell->visited = B_TRUE; // mark surrounding cells as visited for (d = DC_N; d < MAXDIR_COMPASS; d++) { cell_t *thiscell; thiscell = getcellindir(cell, d); if (thiscell) { //if (db) printf("* Marking surrounding cell in dir %d (%d,%d) as visited.\n",d, thiscell->x, thiscell->y); thiscell->visited = B_TRUE; } } // remember last direction lastdir = dir; // check if we have visited all valid cells unused = 0; for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { cell_t *thiscell; thiscell = getcellat(map, x, y); if (!thiscell->visited) { unused++; } } } if (!unused) { done = B_TRUE; } } //printf("%d unused cell(s)\n",unused); //dumpmap(map); //getchar(); } // use sparseness to cut down dead ends for (i = 0; i < sparseness; i++) { for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { cell = getcellat(map, x,y); if (countcellexits(cell) == 1) { // erase this cell setcelltype(cell, CT_WALL); } } } } // introduce loops for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { cell = getcellat(map, x, y); if (!cell->type->solid && countcellexits(cell) == 1) { // dead end - maybe make loop from here if (rnd(1,100) <= looppct) { int connected = B_FALSE; int loopok = B_TRUE; int dir; // pick a random directory dir = getnewdigdir(cell, D_UNKNOWN,100, &moved); if (dir == D_NONE) { // can't make a loop from here. loopok = B_FALSE; } else { int tries = 0; // if we go this dir, will we hit a // corridor? while (!isloopdirok(cell, dir)) { tries++; // tried every direction? if (tries >= MAXDIR_ORTH) { loopok = B_FALSE; break; } // turn... if (++dir >= MAXDIR_ORTH) { dir = 0; } } } if (loopok) { // keep digging until we hit another corridor while (!connected) { cell_t *newcell; // find adjacent cell in the given direction newcell = getcellindir(cell, dir); if (!newcell) { connected = B_TRUE; } else { // have we hit another corridor yet? if (!newcell->type->solid) { connected = B_TRUE; } else { // blank adjacent cell setcelltype(newcell, emptycell); newcell->visited = B_TRUE; } cell = newcell; } } } } } } } // create rooms if (wantrooms) { numrooms = rnd(minrooms, maxrooms); //printf("using %d rooms\n",numrooms); //dblog("Adding %d rooms...\n",numrooms); for (i = 0; i < numrooms; i++) { // select random width/height w = rnd(minroomw, maxroomw); h = rnd(minroomh, maxroomh); roomw[i] = w; roomh[i] = h; if (calcroompos(map, w, h, &bestx, &besty)) { //printf("** couldn't make room!\n"); } else { // we now have the room position - fill it in createroom(map, bestx,besty, w,h, i); /* // maybe make it a special room if (getrand(1,100) <= CH_SPECIALROOM) { int curpos; int roomid; roomid = getrandomspecialroom(wreck->mazelev[curz].type); for (y = besty; y <= (besty + (h-1)); y++) { for (x = bestx; x <= (bestx + (w-1)); x++) { curpos = y*MAZEW+x; wreck->mazelev[curz].maze[curpos].floorver = roomid; } } roomspecial[i] = roomid; } else { roomspecial[i] = B_FALSE; } */ } } } // add staircases for (i = 0; i < 3; i++) { // add up stairs c = NULL; while (!c || !isempty(c) || countobs(c->obpile)) { c = getrandomroomcell(map, ANYROOM); } o = addob(c->obpile, "staircase going up"); linkstairs(o); c = NULL; while (!c || !isempty(c) || countobs(c->obpile)) { c = getrandomroomcell(map, ANYROOM); } o = addob(c->obpile, "staircase going down"); linkstairs(o); } /* void around map // N if (wreck->mazelev[0].type == W_WRECK) { for (x = 0; x < MAZEW; x++) { y = 0; while (getfloor(x,y,curz) == C_SOLID) { // change to void wreck->mazelev[curz].maze[y*MAZEW+x].floor = C_VOID; wreck->mazelev[curz].maze[y*MAZEW+x].floorver = rand() % MAXVOIDVER; // make exits breakable or remove them. for (d = D_NORTH ; d <= D_WEST; d++) { int extype = getexit(x,y,curz,d); int newx,newy; newx = x + dirtox(d); newy = y + dirtoy(d); if (isonmap(newx, newy, curz)) { if (issolid(newx,newy,curz)) { // remove it setexit(x,y,curz,d,EX_CORRIDOR); } else { object_t *o; // make it vulnerable if (isbreakableexit(extype)) { setexit(x,y,curz,d,extype); } // add warning sign o = addobject(&wreck->mazelev[curz].maze[newy*MAZEW+newx].floorobs, O_SIGNWARNING); o->dir = diropposite(d); } } } y++; } } // S for (x = 0; x < MAZEW; x++) { y = MAZEH-1; while (getfloor(x,y,curz) == C_SOLID) { // change to void wreck->mazelev[curz].maze[y*MAZEW+x].floor = C_VOID; wreck->mazelev[curz].maze[y*MAZEW+x].floorver = rand() % MAXVOIDVER; // make exits breakable. for (d = D_NORTH ; d <= D_WEST; d++) { int extype = getexit(x,y,curz,d); int newx,newy; newx = x + dirtox(d); newy = y + dirtoy(d); if (isonmap(newx, newy, curz)) { if (issolid(newx,newy,curz)) { // remove it setexit(x,y,curz,d,EX_CORRIDOR); } else { object_t *o; // make it vulnerable if (isbreakableexit(extype)) { setexit(x,y,curz,d,extype); } // add warning sign o = addobject(&wreck->mazelev[curz].maze[newy*MAZEW+newx].floorobs, O_SIGNWARNING); o->dir = diropposite(d); } } } y--; } } // E for (y = 0; y < MAZEH; y++) { x = 0; while (getfloor(x,y,curz) == C_SOLID) { // change to void wreck->mazelev[curz].maze[y*MAZEW+x].floor = C_VOID; wreck->mazelev[curz].maze[y*MAZEW+x].floorver = rand() % MAXVOIDVER; // make exits breakable. for (d = D_NORTH ; d <= D_WEST; d++) { int extype = getexit(x,y,curz,d); int newx,newy; newx = x + dirtox(d); newy = y + dirtoy(d); if (isonmap(newx, newy, curz)) { if (issolid(newx,newy,curz)) { // remove it setexit(x,y,curz,d,EX_CORRIDOR); } else { object_t *o; // make it vulnerable if (isbreakableexit(extype)) { setexit(x,y,curz,d,extype); } // add warning sign o = addobject(&wreck->mazelev[curz].maze[newy*MAZEW+newx].floorobs, O_SIGNWARNING); o->dir = diropposite(d); } } } x++; } } // W for (y = 0; y < MAZEH; y++) { x = MAZEW-1; while (getfloor(x,y,curz) == C_SOLID) { // change to void wreck->mazelev[curz].maze[y*MAZEW+x].floor = C_VOID; wreck->mazelev[curz].maze[y*MAZEW+x].floorver = rand() % MAXVOIDVER; // make exits breakable. for (d = D_NORTH ; d <= D_WEST; d++) { int extype = getexit(x,y,curz,d); int newx,newy; newx = x + dirtox(d); newy = y + dirtoy(d); if (isonmap(newx, newy, curz)) { if (issolid(newx,newy,curz)) { // remove it setexit(x,y,curz,d,EX_CORRIDOR); } else { object_t *o; // make it vulnerable if (isbreakableexit(extype)) { setexit(x,y,curz,d,extype); } // add warning sign o = addobject(&wreck->mazelev[curz].maze[newy*MAZEW+newx].floorobs, O_SIGNWARNING); o->dir = diropposite(d); } } } x--; } } } */ /* // add windows to map for (y = 0; y < MAZEH; y++) { for (x = 0; x < MAZEW; x++) { int dir,chance = windowchance; // increase chance for adjacent windows for (dir = D_NORTH ; dir <= D_WEST ; dir++) { int adjx,adjy; adjx = x + dirtox(dir); adjy = y + dirtoy(dir); if (isonmap(adjx,adjy,curz)) { // extra chance per adjacent window chance += (hasexitoftype(adjx,adjy,curz,EX_WINDOW)*10); } } for (dir = D_NORTH ; dir <= D_WEST ; dir++) { int etype,newx,newy,thisfloor,newfloor; etype = getexit(x,y,curz,dir); newx = x + dirtox(dir); newy = y + dirtoy(dir); if (isonmap(newx,newy,curz)) { thisfloor = wreck->mazelev[curz].maze[y*MAZEW+x].floor; newfloor = wreck->mazelev[curz].maze[newy*MAZEW+newx].floor; if ((etype == EX_WALL) && canhavewindow(thisfloor) && canhavewindow(newfloor)) { if (getrand(1,100) <= chance) { setexit(x,y,curz,dir,EX_WINDOW); } } } } } } */ // add objects and monsters to dead ends for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { cell_t *c; c = getcellat(map, x, y); if (c && isempty(c)) { if (rnd(1,100) <= getobchance(map->habitat)) { addrandomthing(c, 50); } } } } if (wantrooms && (numrooms > 0)) { // add pillars & objects & monsters to rooms for (i = 0; i < numrooms; i++) { int numobsmin,numobsmax,numobs,n; int maxpillars; //dblog("Adding obs to room %d/%d",i+1,numrooms); maxpillars = (roomw[i] / 4) + (roomh[i] / 4); // add pillars first if ((maxpillars > 0) && (rnd(1,100) <= CH_PILLAR)) { int n; int numpillars; numpillars = rnd(1,maxpillars); if (db) dblog("--> Will add %d pillars",numpillars); for (n = 0; n < numpillars;n++ ) { //dblog("----> Adding pillar %d/%d",n+1,numpillars); cell_t *c; c = getrandomroomcell(map, i); if (c && isempty(c) && !countobs(c->obpile)) { setcelltype(cell, CT_WALL); } } } /* if (roomspecial[i]) { // chance is increased numobsmin = (roomw[i]*roomh[i]) / 4 ; numobsmax = (roomw[i]*roomh[i]) / 2 ; } else { */ numobsmin = 0; //numobsmax = MAXOF(roomw[i],roomh[i]) / 2; numobsmax = MAXOF(roomw[i],roomh[i]); //} // then objects/monsters if (numobsmax <= numobsmin) { numobs = numobsmin; } else { numobs = rnd(numobsmin,numobsmax); } if (db) dblog("--> Will add %d objects to room %d (of %d)",numobs,i,numrooms); for (n = 0 ; n < numobs; n++) { int ntries = 0; cell_t *c; done = B_FALSE; while (!done) { c = getrandomroomcell(map, i); // if nothing there if (c && isempty(c) && !countobs(c->obpile)) { /* if (roomspecial[i]) { if (getrand(1,4) == 1) { // less chance of monster addlifeform(x, y, curz,getrandommonster(curz), getrand(1,curz+1), C_AI, B_FALSE, B_TRUE); } else { //add objects based on room type if (roomspecial[i] == SP_MEDLAB) { addspecialroomob(x, y, curz, SP_MEDLAB, OR, 3, OP_AI_HEALS, OP_REVIVES); } else if (roomspecial[i] == SP_COMPLAB) { addspecialroomob(x, y, curz, SP_COMPLAB, OR, 0); } else if (roomspecial[i] == SP_ALIENNEST) { addspecialroomob(x, y, curz, SP_ALIENNEST, OR, 0); } } } else { */ // slightly more chance of objects in rooms addrandomthing(c,60); done = B_TRUE; //dblog("----> Success ob at (%d,%d).",c->x,c->y); } else { ntries++; //dblog("----> Failed, now at retry #%d/%d",ntries, numobs); } if (ntries >= numobs) { break; } } } } } if (db) dblog("Finished adding objects."); /* // some extra monsters in corridors for (i = 0; i < getrand(3,8); i++) { int x,y; lifeform_t *lf; lf = addlifeform(rand() % MAZEW, rand() % MAZEH,curz,getrandommonster(curz), getrand(1,curz+1), C_AI, B_FALSE, B_TRUE); done = B_FALSE; while (!done) { getrandomcell(&x, &y, curz,C_EMPTY ); if (isempty(x,y,curz)) { lf->x = x; lf->y = y; lf->z = curz; done = B_TRUE; } } } */ /* // add a fixed revival booth done = B_FALSE; while (!done) { getrandomcell(&x,&y, curz,C_ROOM); // get a random cell in a room if (isempty(x,y,curz)) { if (!cellhasobject(x,y,curz)) { done = B_TRUE; } } } addobject(&wreck->mazelev[curz].maze[y*MAZEW+x].floorobs, O_REVIVAL); // emergency lighting for (y = 0; y < MAZEH; y++) { for (x = 0; x < MAZEW; x++) { if (getfloor(x,y,curz) == C_EMPTY) { if (isempty(x,y,curz) && !hasdangerousobject(NULL,x,y,curz)) { // chance of a light... int lightchance = 5; int roll = getrand(1,100); if (roll <= lightchance) { addobject(&wreck->mazelev[curz].maze[y*MAZEW+x].floorobs, O_EMERGLIGHT); } } } } } // add the reactor done = B_FALSE; while (!done) { getrandomcell(&x,&y, curz,C_ROOM); // get a random cell in a room if (getdistance(x,y,wreck->dockpos.x,wreck->dockpos.y) >= 20) { if (isempty(x,y,curz)) { if (!cellhasobject(x,y,curz)) { done = B_TRUE; } } } } wreck->mazelev[curz].reactorpos.x = x; wreck->mazelev[curz].reactorpos.y = y; addobject(&wreck->mazelev[curz].maze[y*MAZEW+x].floorobs, O_REACTOR); wreck->mazelev[curz].powered = B_TRUE; wreck->mazelev[curz].lightlevel = getrand(50,100); //printf("reactor at %d,%d,%d\n",x,y,curz); // all empty cells around it change for (cury = y-2 ; cury <= y+2; cury++) { for (curx = x-2 ; curx <= x+2; curx++) { if (isonmap(curx,cury,curz)) { if (!issolid(curx,cury,curz)) { wreck->mazelev[curz].maze[cury*MAZEW+curx].floor = C_EMPTYHAZARD; } } } } // calculate level difficulty wreck->mazelev[curz].mondifficulty = 0; wreck->mazelev[curz].mapdifficulty = 0; // monsters for (lf = wreck->mazelev[curz].lifeform ; lf ; lf = lf->next) { if (lf->controller != C_HUMAN) { wreck->mazelev[curz].mondifficulty += (getrdifficulty(lf->race)); } } // maze layout & objects for (y = 0; y < MAZEH; y++) { for (x = 0; x < MAZEW; x++) { switch (numexits(x,y,curz)) { case 2: // corner wreck->mazelev[curz].mapdifficulty += 0.5; break; case 1: // dead end wreck->mazelev[curz].mapdifficulty += 1; break; } if (containerhasobject(&wreck->mazelev[curz].maze[y*MAZEW+x].floorobs, O_SPAWNPIT)) { wreck->mazelev[curz].mondifficulty += DF_SPAWNPIT; } } } // fix exithp for (y = 0; y < MAZEH; y++) { for (x = 0; x < MAZEW; x++) { int d; for (d = D_NORTH ; d <= D_WEST; d++) { int extype = getexit(x,y,curz,d); if (isbreakableexit(getexit(x,y,curz,d))) { // using setexit will make sure the hp is right setexit(x,y,curz,d,extype); } } } } */ //printf("*** Level difficulty is %0.2f\n", getmazedifficulty(curz)); map->beingcreated = B_FALSE; } void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) { int x,y; int poss[MAXOF(MAX_MAPW,MAX_MAPH)]; int npossible; cell_t *cell, *newcell; int maxx,maxy; //printf("trying to create room at (%d,%d) w=%d,h=%d\n", minx, miny, w, h); maxx = minx + (w-1); maxy = miny + (h-1); for (y = miny; y <= maxy; y++) { for (x = minx; x <= maxx; x++) { cell = getcellat(map, x, y); // make it a border or room if ((y == miny) || (y == maxy) || (x == minx) || (x == maxx)) { if (cell->type->solid) { setcelltype(cell, CT_ROOMWALL); } } else { setcelltype(cell, CT_ROOM); } cell->roomid = roomid; } } // for each side, make list of all possible door locations // then pick one randomly. // BUT if the nearby corridor only has one exit, always // place a door. // N npossible = 0; y = miny; for (x = minx+1; x <= maxx-1; x++) { cell = getcellat(map, x, y); newcell = getcellindir(cell, D_N); if (newcell && !newcell->type->solid) { int doorcount; doorcount = countadjcellswithflag(cell, F_DOOR); if (doorcount == 0) { if ((countcellexits(newcell) == 1) && (iswallindir(newcell,D_E)) && (iswallindir(newcell,D_W))) { // always add door makedoor(cell); } else { poss[npossible] = x; npossible++; } } } } if (npossible > 0) { int sel = rand() % npossible; //printf("adding N door at %d\n",poss[sel]); cell = getcellat(map, poss[sel], y); makedoor(cell); } // S npossible = 0; y = maxy; for (x = minx+1; x <= maxx-1; x++) { cell = getcellat(map, x, y); newcell = getcellindir(cell, D_S); if (newcell && !newcell->type->solid) { int doorcount; doorcount = countadjcellswithflag(cell, F_DOOR); if (doorcount == 0) { if ((countcellexits(newcell) == 1) && (iswallindir(newcell,D_E)) && (iswallindir(newcell,D_W))) { // always add door makedoor(cell); } else { poss[npossible] = x; npossible++; } } } } if (npossible > 0) { int sel = rand() % npossible; //printf("adding S door at %d\n",poss[sel]); cell = getcellat(map, poss[sel], y); makedoor(cell); } // W npossible = 0; x = minx; for (y = miny+1; y <= maxy-1; y++) { cell = getcellat(map, x, y); newcell = getcellindir(cell, D_W); if (newcell && !newcell->type->solid) { int doorcount; doorcount = countadjcellswithflag(cell, F_DOOR); if (doorcount == 0) { if ((countcellexits(newcell) == 1) && (iswallindir(newcell,D_N)) && (iswallindir(newcell,D_S))) { // always add door makedoor(cell); } else { poss[npossible] = y; npossible++; } } } } if (npossible > 0) { int sel = rand() % npossible; //printf("adding W door at %d\n",poss[sel]); cell = getcellat(map, x, poss[sel]); makedoor(cell); } // E npossible = 0; x = maxx; for (y = miny+1; y <= maxy-1; y++) { cell = getcellat(map, x, y); newcell = getcellindir(cell, D_E); if (newcell && !newcell->type->solid) { int doorcount; doorcount = countadjcellswithflag(cell, F_DOOR); if (doorcount == 0) { if ((countcellexits(newcell) == 1) && (iswallindir(newcell,D_N)) && (iswallindir(newcell,D_S))) { // always add door makedoor(cell); } else { poss[npossible] = y; npossible++; } } } } if (npossible > 0) { int sel = rand() % npossible; //printf("adding E door at %d\n",poss[sel]); cell = getcellat(map, x, poss[sel]); makedoor(cell); } } int dirtox(int dt, int dir) { if (dt == DT_ORTH) { switch (dir) { case D_E: return 1; case D_W: return -1; default: return 0; } } else if (dt == DT_COMPASS) { switch (dir) { case DC_NE: case DC_E: case DC_SE: return 1; case DC_NW: case DC_W: case DC_SW: return -1; default: return 0; } } return 0; } int dirtoy(int dt, int dir) { if (dt == DT_ORTH) { switch (dir) { case D_S: return 1; case D_N: return -1; default: return 0; } } else if (dt == DT_COMPASS) { switch (dir) { case DC_SW: case DC_S: case DC_SE: return 1; case DC_NE: case DC_N: case DC_NW: return -1; default: return 0; } } return 0; } void dumpmap(map_t *map) { int x,y; cell_t *cell; printf("dump of map '%s' (%d x %d):\n",map->name, map->w, map->h); for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { cell = getcellat(map, x, y); printf("%c",cell->type->glyph.ch); } printf("\n"); } } void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int wantannounce) { int x,y; animradial(c, range, '}', C_RED); if (haslos(player, c)) { if (wantannounce) { msg("You see %s explosion!", (range > 0) ? "a huge" : "an"); } } else { noise(c, NULL, "an explosion!", NULL); } for (y = c->y - range ; y <= c->y + range ; y++) { for (x = c->x - range ; x <= c->x + range ; x++) { cell_t *cc; cc = getcellat(c->map, x,y); if (cc && (getcelldist(c, cc) <= range)) { explodesinglecell(cc, dam, killwalls, o, c); } } } // lfs up to 1 cell away are knocked back for (y = c->y - range-1 ; y <= c->y + range+1 ; y++) { for (x = c->x - range-1 ; x <= c->x + range+1 ; x++) { cell_t *cc; cc = getcellat(c->map, x,y); if (cc && (getcelldist(c, cc) <= (range+1))) { if (cc->lf && !isdead(cc->lf)) { // move away from centre of explosion knockback(cc->lf, getdiraway(cc, c, NULL, B_FALSE, DT_COMPASS), 2, NULL); } } } } } // this should never be called directly - only from explodecells(). // (otherwise knockback effect won't happen) void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre) { char obname[BUFLEN]; if (c->lf) { char buf[BUFLEN]; if (o) { getobname(o, obname, 1); sprintf(buf, "an exploding %s",strchr(obname, ' ')+1); } else { sprintf(buf, "an explosion"); } // take damage losehp(c->lf, dam, DT_EXPLOSIVE, NULL, buf); } damageallobs(o, c->obpile, dam, DT_EXPLOSIVE); if (killwalls) { if (c->type->solid) { // make it empty! setcelltype(c, getemptycelltype(c->map->habitat)); // add some rubble addob(c->obpile, "10-50 stones"); } } } map_t *findmap(int mid) { map_t *m; for (m = firstmap ; m ; m = m->next) { if (m->id == mid) return m; } return NULL; } map_t *findmapofdepth(int depth) { map_t *m; for (m = firstmap ; m ; m = m->next) { if (m->depth == depth) return m; } return NULL; } // find the object with id 'id' in map 'm' object_t *findobidinmap(map_t *m, long id) { cell_t *c; int x,y; for (y = 0; y < m->h; y++) { for (x = 0; x < m->w; x++) { object_t *o; c = getcellat(m, x, y); o = findobbyid(c->obpile, id); if (o) return o; } } return NULL; } // find the cell in 'map' which contains object oid cell_t *findobinmap(map_t *m, enum OBCLASS oid) { cell_t *c; int x,y; for (y = 0; y < m->h; y++) { for (x = 0; x < m->w; x++) { c = getcellat(m, x, y); if (hasob(c->obpile, oid)) { return c; } } } return NULL; } void forgetcells(map_t *map, int amt) { int amtleft; //int totcells; int i; cell_t *poss[MAX_MAPW*MAX_MAPH]; cell_t *c; int nposs = 0; // how many cells to forget? //totcells = (map->w * map->h); //amtleft = (int) (((float) pct / 100.0) * (float)totcells); amtleft = amt; // get a list of all known cells for (i = 0; i < (map->w*map->h); i++){ c = map->cell[i]; if (c && c->known && !haslos(player, c)) { poss[nposs] = c; nposs++; } } if (amtleft > nposs) amtleft = nposs; // forget cells... for (i = 0; i < amtleft; i++) { int n; int sel; sel = rnd(0,nposs-1); poss[sel]->known = B_FALSE; // shuffle down for (n = i; n < (amtleft-1); n++) { poss[n] = poss[n+1]; } nposs--; } } cell_t *getcellindir(cell_t *cell, int dir) { cell_t *newcell; int newx,newy; int dt; switch (dir) { case D_N: case D_S: case D_E: case D_W: dt = DT_ORTH; break; case DC_N: case DC_E: case DC_S: case DC_W: case DC_NE: case DC_SE: case DC_SW: case DC_NW: dt = DT_COMPASS; break; default: return NULL; } newx = cell->x + dirtox(dt, dir); newy = cell->y + dirtoy(dt, dir); newcell = getcellat(cell->map, newx,newy); return newcell; } // select a new direction (random chance of turnung) int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved) { int foundvaliddir = B_FALSE; int dir; int tried[4], numtries; int i; int turned = B_FALSE; cell_t *newcell; int db = B_FALSE; char err[BUFLEN]; // haven't tried any dirs yet numtries = 0; for (i = 0; i < MAXDIR_ORTH; i++) { tried[i] = B_FALSE; } while (!foundvaliddir) { // keep going until we get a valid direction if (numtries >= MAXDIR_ORTH) { // no valid dirs return D_NONE; // (pick a new random spot and refresh tried dirs and current dir) } if (lastdir == D_UNKNOWN) { // just pick a random dir dir = rnd(0, MAXDIR_ORTH-1); turned = B_TRUE; } else { // chance of changing dir if (rnd(1,100) <= turnpct) { dir = rnd(0, MAXDIR_ORTH-1); turned = B_TRUE; } else { dir = lastdir; } } // now validate the direction if (db) printf("--- Trying %s...\n",getdirname(dir)); if (tried[dir] == B_TRUE) { // already found this dir to be invalid lastdir = D_UNKNOWN; if (db) printf("--- Already know %s is invalid.\n",getdirname(dir)); } else { // check 1 cell ahead newcell = getcellindir(cell, dir); if (isnewcellok(newcell, err)) { cell_t *newcell1, *newcell2; // check 2 cells ahead and sidewars newcell = getcellindir(newcell, dir); if (newcell) { switch (dir) { case D_N: case D_S: newcell1 = getcellindir(newcell,D_E); newcell2 = getcellindir(newcell,D_W); break; case D_E: case D_W: newcell1 = getcellindir(newcell,D_N); newcell2 = getcellindir(newcell,D_S); break; default: // should never happen newcell1 = NULL; newcell2 = NULL; break; } } else { newcell1 = NULL; newcell2 = NULL; } if (!isnewcellok(newcell, err)) { if (db) printf("--- %s %s!\n",getdirname(dir), err); tried[dir] = B_TRUE; lastdir = D_UNKNOWN; numtries++; } else if (!isnewcellok(newcell1, err)) { if (db) printf("--- %s %s!\n",getdirname(dir), err); tried[dir] = B_TRUE; lastdir = D_UNKNOWN; numtries++; } else if (!isnewcellok(newcell2, err)) { if (db) printf("--- %s %s!\n",getdirname(dir), err); tried[dir] = B_TRUE; lastdir = D_UNKNOWN; numtries++; } else { // ok if (db) printf("--- %s %s!\n",getdirname(dir), err); foundvaliddir = B_TRUE; } } else { if (db) printf("--- %s %s!\n",getdirname(dir), err); tried[dir] = B_TRUE; lastdir = D_UNKNOWN; numtries++; } } } //newcell = getcellindir(cell, dir); //printf("getrandomdigdir() - on cell %d,%d, returning dir %d (-> %d,%d)\n", // cell->x, cell->y, dir, newcell->x, newcell->y); if (turned) *moved = 0; return dir; } // chance of each empty cell in a map has of getting an object int getobchance(int habitat) { switch (habitat) { case H_DUNGEON: return 3; } // default of no objects return 0; } cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand) { int radius = 1; int x,y; cell_t *poss[MAXCANDIDATES]; int nposs = 0; cell_t *new; int done = B_FALSE; while (!done) { int numwithlof = 0; for (y = c->y - radius ; y <= c->y + radius ; y++) { for (x = c->x - radius ; x <= c->x + radius ; x++) { new = getcellat(c->map, x, y); if (new && (getcelldist(c,new) == radius) && haslof(c, new, LOF_WALLSTOP, NULL)) { numwithlof++; if (wantempty == WE_EMPTY) { // make sure it's empty if (isempty(new)) { poss[nposs++] = new; } } else if (wantempty == WE_WALKABLE) { if (cellwalkable(NULL, new, NULL)) { poss[nposs++] = new; } } else if (wantempty == WE_PORTAL) { if (cellwalkable(NULL, new, NULL) && !hasenterableobject(new) ) { if (!hasobwithflag(new->obpile, F_DOOR)) { poss[nposs++] = new; } } } else { // always ok poss[nposs++] = new; } } } } // found any possibilities ? if (nposs) { done = B_TRUE; } else { if (allowexpand) { if (numwithlof) { // increment radius radius++; } else { return NULL; } } else { return NULL; } } } return poss[rnd(0,nposs-1)]; } cell_t *getrandomcell(map_t *map) { int x,y; cell_t *cell; x = (rand() % map->w); y = (rand() % map->h); cell = getcellat(map, x, y); assert(cell); return cell; } cell_t *getrandomcelloftype(map_t *map, int id) { cell_t *cell; cell = getrandomcell(map); while (cell->type->id != id) { cell = getrandomcell(map); } return cell; } int getrandomdir(int dirtype) { if (dirtype == DT_ORTH) { return rnd(D_N, D_W); } else { // ie. DT_COMPASS return rnd(DC_N, DC_NW); } } cell_t *getrandomroomcell(map_t *map, int roomid) { int npossible = 0; int selidx; int x,y; cell_t *c, **poss; poss = malloc((map->w*map->h) * sizeof(cell_t)); npossible = 0; for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { c = getcellat(map, x, y); // is this cell in the correct room and not a wall? if (c && isempty(c)) { int ok = B_FALSE; if (c->roomid == roomid) { ok = B_TRUE; } else if (roomid == ANYROOM) { if (c->roomid != -1) { ok = B_TRUE; } } if (ok) { poss[npossible] = c; npossible++; } } } } if (npossible <= 0) { return NULL; } selidx = rnd(0, npossible-1); c = poss[selidx]; free(poss); return c; } // returns how slippery this cell is int getslipperyness(cell_t *c, object_t **slipob) { object_t *o; int totalslip = 0; if (slipob) *slipob = NULL; for (o = c->obpile->first ; o ; o = o->next) { int thisslip; sumflags(o->flags, F_SLIPPERY, &thisslip, NULL, NULL); if (thisslip > 0) { if (slipob && (*slipob == NULL)) { *slipob = o; } } thisslip *= o->amt; totalslip += thisslip; } totalslip *= 2; return totalslip; } cell_t *getstairdestination(object_t *o) { flag_t *f; cell_t *newcell = NULL; f = hasflag(o->flags, F_MAPLINK); if (f) { map_t *newmap; int newx,newy; newmap = findmap(f->val[0]); assert(newmap); // prefer an object id if we have it if (strlen(f->text)) { object_t *o2; long obid; obid = atol(f->text); o2 = findobidinmap(newmap, obid); if (o2) { newcell = getoblocation(o2); } else { dblog("stairs link to object %ld which no longer exists!",obid); msg("stairs link to object %ld which no longer exists!",obid); return NULL; } } else { // otherwise look for x/y coors newx = f->val[1]; newy = f->val[2]; // find dst x/y newcell = getcellat(newmap, newx, newy); } } return newcell; } object_t *hasenterableobject(cell_t *c) { return hasobwithflag(c->obpile, F_CLIMBABLE); } lifeform_t *haslf(cell_t *c) { if (c->lf && !isdead(c->lf)) { return c->lf; } return NULL; } int hasobject(cell_t *c) { if (c->obpile->first) { return B_TRUE; } return B_FALSE; } int isadjacent(cell_t *src, cell_t *dst) { if (getcelldist(src, dst) == 1) { return B_TRUE; } return B_FALSE; } int isdark(cell_t *c) { switch (c->lit) { case L_PERMDARK: case L_NOTLIT: return B_TRUE; default: break; } return B_FALSE; } int isdiggable(cell_t *c) { switch (c->type->id) { case CT_WALL: return B_TRUE; case CT_ROOMWALL: return B_TRUE; } return B_FALSE; } // if isopen provided, returns whether or not the door is opened int isdoor(object_t *o, int *isopen) { int isdoor = B_FALSE; if (hasflag(o->flags, F_DOOR)) { isdoor = B_TRUE; } else { isdoor = B_FALSE; } if (isdoor) { if (isopen) { if (hasflag(o->flags, F_OPEN)) { *isopen = B_TRUE; } else { *isopen = B_FALSE; } } } return isdoor; } int isempty(cell_t *c) { if (!c) return B_FALSE; if (c->type->solid) return B_FALSE; if (c->lf) return B_FALSE; if (!cellwalkable(NULL, c, NULL)) return B_FALSE; return B_TRUE; } //returns TT_ based on what you can scan there int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { flag_t *f; // handle scanner f = lfhasflag(player, F_DETECTLIFE); if (f) { if (c->lf) { if (getcelldistorth(player->cell, c) <= f->val[0]) { *thing = c->lf; if (f->val[1] == B_TRUE) { if (desc) { real_getlfnamea(c->lf, desc, B_FALSE); strcat(desc, " (detected)"); } if (glyph) { *glyph = *(getlfglyph(c->lf)); } } else { if (desc) { char *p; p = getsizetext(getlfsize(c->lf)); sprintf(desc, "%s %s monster", isvowel(*p) ? "an" : "a", p); } if (glyph) { // select glyph based on size glyph->ch = '0' + ((int) getlfsize(c->lf)); glyph->colour = C_GREY; } } return TT_MONSTER; } } } f = lfhasflag(player, F_DETECTMETAL); if (f) { if (getcelldistorth(player->cell, c) <= f->val[0]) { if (c->lf && ismetal(c->lf->race->material->id) ) { *thing = c->lf; if (glyph) { glyph->ch = '*'; glyph->colour = C_GREY; } if (desc) sprintf(desc, "something metallic"); return TT_MONSTER; } else { object_t *o; for (o = c->obpile->first ; o ; o = o->next) { if (ismetal(o->material->id)) { *thing = o; if (glyph) { glyph->ch = '*'; glyph->colour = C_GREY; } if (desc) sprintf(desc, "something metallic"); return TT_OBJECT; } } } } } // can hear them using master level listen skill? if (c->lf && lfhasflagval(player, F_CANHEARLF, c->lf->id, NA, NA, NULL)) { if (glyph) { *glyph = *(getlfglyph(c->lf)); } if (desc) { real_getlfnamea(c->lf, desc, B_FALSE); strcat(desc, " (heard)"); } *thing = c->lf; return TT_MONSTER; } f = lfhasflag(player, F_DETECTOBS); if (f) { if (getcelldistorth(player->cell, c) <= f->val[0]) { object_t *o; for (o = c->obpile->first ; o ; o = o->next) { if (!hasflag(o->flags, F_NOPICKUP) && !hasflag(o->flags, F_DOOR)) { *thing = o; if (glyph) { glyph->ch = '*'; glyph->colour = C_GREY; } if (desc) sprintf(desc, "an object"); return TT_OBJECT; } } } } return B_FALSE; } int islit(cell_t *c) { switch (c->lit) { case L_TEMP: case L_PERMLIGHT: return B_TRUE; default: break; } return B_FALSE; } int isloopdirok(cell_t *cell, int dir) { int dirok = B_FALSE; cell_t *newcell; // is there a corridor in this direction? newcell = getcellindir(cell, dir); while (newcell) { // got a corridor? if (!newcell->type->solid) { dirok = B_TRUE; break; } // keep going newcell = getcellindir(newcell, dir); } // we've either gone off the map or // hit a corridor return dirok; } int isnewcellok(cell_t *cell, char *err) { if ( !cell) { // can't go that way if (err) sprintf(err,"goes off the map."); return B_FALSE; } else if ( !cell->type->solid) { // already an empty space there if (err) sprintf(err,"goes to an empty space (%d,%d)",cell->x,cell->y); return B_FALSE; } // ok! if (err) sprintf(err, "OK!"); return B_TRUE; } int isonmap(map_t *map, int x, int y) { if ((x < 0) || (y < 0)) { return B_FALSE; } if ((x >= map->w) || (y >= map->h)) { return B_FALSE; } return B_TRUE; } int iswallindir(cell_t *cell, int dir) { cell_t *newcell; newcell = getcellindir(cell, dir); if (!newcell) { return B_TRUE; } if (newcell->type->solid) { return B_TRUE; } return B_FALSE; } // link the staircase 'o' to a free one in map 'othermap' // returns TRUE if it failed because othermap doesn't exist. int linkstairs(object_t *o) { map_t *othermap; object_t *o2; map_t *stairmap; cell_t *staircell; cell_t *c2; objecttype_t *otherstairtype; int n,found = B_FALSE; int dir; flag_t *f; staircell = getoblocation(o); stairmap = staircell->map; otherstairtype = getoppositestairs(o->type); f = hasflag(o->flags, F_CLIMBABLE); if (f) { if (f->val[0] == D_UP) { dir = -1; } else { dir = 1; } } else { dblog("ERROR: stair object has no f_climbable!"); msg("ERROR: stair object has no f_climbable!"); exit(1); } othermap = findmapofdepth(stairmap->depth + dir); if (othermap) { // find an empty staircase in other map for (n = 0; n < othermap->w*othermap->h; n++) { c2 = othermap->cell[n]; o2 = hasob(c2->obpile, otherstairtype->id); // does it go nowhere? if (o2 && !hasflag(o2->flags, F_MAPLINK)) { char obid[BUFLEN]; // link it to here! sprintf(obid, "%ld", o->id); addflag(o2->flags, F_MAPLINK, stairmap->id, NA, NA, obid); // link me to there sprintf(obid, "%ld", o2->id); addflag(o->flags, F_MAPLINK, othermap->id, NA, NA, obid); found = B_TRUE; break; } } if (!found) { dblog("ERROR - stairs link to existing map #%d, but it has no free stairs.",othermap->id); msg("ERROR - stairs link to existing map #%d, but it has no free stairs.",othermap->id); exit(1); } } else { return B_TRUE; } return B_FALSE; } void makedoor(cell_t *cell) { object_t *o; map_t *m; m = cell->map; setcelltype(cell, getemptycelltype(cell->map->habitat)); o = addob(cell->obpile, "wooden door"); if (o && (rnd(1,2) == 1)) { opendoor(NULL, o); } else { int chance; // door is closed - lock it? chance = rolldie(1,6); // ie. 1 in 6 // ie. at dungeon lev 10, chance is 2 in 6 // at dungeon lev 20, chance is 3 in 6 // ... // at dungeon lev 50, chance is 5 in 6 chance -= (m->depth / 10); if (chance <= 1) { addflag(o->flags, F_LOCKED, B_TRUE, NA, NA, NULL); } } } void makelit(cell_t *c, enum LIGHTLEV how, int howlong) { // don't override permenant light with temp light! //if ((c->lit == L_PERMLIGHT) && (how == L_TEMP)) { if (how == L_TEMP) { //if ((c->lit == L_PERMLIGHT) || (c->lit == L_PERMDARK)) { if (c->lit == L_PERMLIGHT) { // light sources can't override permenant light return; } if (c->lit == L_PERMDARK) { // light sources can't override darkness spell return; } } if (howlong > 0) { // TODO: use a stack here instead c->origlit = c->lit; c->origlittimer = c->littimer; c->littimer = howlong; } c->lit = how; } void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong) { int x,y; cell_t *c2; int (*distfunc)(cell_t *, cell_t *); if (radius <= 0) return; if (radius == 1) { distfunc = getcelldist; } else { distfunc = getcelldistorth; } for (y = c->y - radius ; y <= c->y + radius; y++) { for (x = c->x - radius ; x <= c->x + radius; x++) { c2 = getcellat(c->map, x, y); if (c2 && (distfunc(c, c2) <= radius)) { if (cellhaslos(c,c2)) { makelit(c2, how,howlong); } } } } } void setcelltype(cell_t *cell, int id) { assert(cell); cell->type = findcelltype(id); assert(cell->type); cell->roomid = 0; } void updateknowncells(void) { int x,y; map_t *map; object_t *wep; int seenundead = B_FALSE; map = player->cell->map; wep = getweapon(player); for (y = viewy; y < viewy + viewh; y++) { for (x = viewx; x < viewx + vieww; x++) { cell_t *cell; cell = getcellat(map, x, y); if (cell) { //if ((player->cell == cell) || haslos(player, cell)) { if (haslos(player, cell)) { if (!cell->known) { cell->known = B_TRUE; } if (cell->lf && lfhasflag(cell->lf, F_UNDEAD)) { seenundead = B_TRUE; } } } } } }