#include #include #include #include #include #include "defs.h" #include "nexus.h" #include "lf.h" #include "map.h" #include "objects.h" extern map_t *firstmap,*lastmap; extern int viewx,viewy,vieww,viewh; extern lifeform_t *player; 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; } 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; a->nextlfid = 0; for (i = 0; i < MAXDIR_ORTH; i++) { a->nextmap[i] = -1; } return a; } void addrandomthing(cell_t *c) { char buf[BUFLEN]; int level; race_t *r; // if there's already someone there, // then add an object. if (c->lf || (rnd(1,2) == 1)) { // object if (getrandomob(c->map, buf)) { dblog("adding %s to cell %d,%d",buf,c->x,c->y); addob(c->obpile, buf); } } else { r = getrandomlf(c->map, &level); if (r) { dblog("adding %s to cell %d,%d",buf,c->x,c->y); addlf(c, r->id, level); } } } 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 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? if (countcellexits(cell)) { score++; 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 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 habitat) { lifeform_t *lf; char buf[BUFLEN]; int wantrooms = B_TRUE; int x,y,newx,newy; 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; //object_t *o; // parameters int turnpct = DEF_TURNPCT; int sparseness = DEF_SPARSENESS; int looppct = DEF_LOOPPCT; int minrooms = MINROOMS; int maxrooms = MAXROOMS; int moved = 0; int db = 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; // rememebr seed map->seed = rand() % 65535; // fill entire maze with walls for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { addcell(map, x, y); } } // pick initial random spot cell = getrandomcell(map); setcelltype(cell, CT_CORRIDOR); 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 (cell->type->solid) { 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,CT_CORRIDOR); 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, CT_CORRIDOR); 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; } */ } } } /* 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; int obchance; c = getcellat(map, x, y); if (c && !c->type->solid) { if (rnd(1,100) <= getobchance(map->habitat)) { addrandomthing(c); } } } } if (wantrooms && (numrooms > 0)) { // add pillars & objects & monsters to rooms for (i = 0; i < numrooms; i++) { int numobsmin,numobsmax,numobs,n; int x,y; 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); 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 && !c->type->solid && !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]); //} // then objects/monsters if (numobsmax <= numobsmin) { numobs = numobsmin; } else { numobs = rnd(numobsmin,numobsmax); } 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 && !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 { */ addrandomthing(c); 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; } } } } } 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)); } 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)) { 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; x <= maxx; x++) { cell = getcellat(map, x, y); newcell = getcellindir(cell, D_N); if (newcell && !newcell->type->solid) { int doorcount; doorcount = countadjcellsoftype(cell, CT_DOOROPEN) + countadjcellsoftype(cell, CT_DOORCLOSED); 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; x <= maxx; x++) { cell = getcellat(map, x, y); newcell = getcellindir(cell, D_S); if (newcell && !newcell->type->solid) { int doorcount; doorcount = countadjcellsoftype(cell, CT_DOOROPEN) + countadjcellsoftype(cell, CT_DOORCLOSED); 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; y <= maxy; y++) { cell = getcellat(map, x, y); newcell = getcellindir(cell, D_W); if (newcell && !newcell->type->solid) { int doorcount; doorcount = countadjcellsoftype(cell, CT_DOOROPEN) + countadjcellsoftype(cell, CT_DOORCLOSED); 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; y <= maxy; y++) { cell = getcellat(map, x, y); newcell = getcellindir(cell, D_E); if (newcell && !newcell->type->solid) { int doorcount; doorcount = countadjcellsoftype(cell, CT_DOOROPEN) + countadjcellsoftype(cell, CT_DOORCLOSED); 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; } } } 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); } printf("\n"); } } map_t *findmap(int mid) { map_t *m; for (m = firstmap ; m ; m = m->next) { if (m->id == mid) return m; } 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; } 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 int newx,newy; 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; } } 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 *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 && !c->type->solid && (c->roomid == roomid)) { poss[npossible] = c; npossible++; } } } if (npossible <= 0) { return NULL; } selidx = rnd(0, npossible-1); c = poss[selidx]; free(poss); return c; } 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; } void makedoor(cell_t *cell) { setcelltype(cell, CT_DOORCLOSED); } void setcelltype(cell_t *cell, int id) { int i; assert(cell); cell->type = findcelltype(id); assert(cell->type); cell->roomid = 0; } void updateknowncells(void) { int x,y; map_t *map; map = player->cell->map; for (y = viewy; y < viewy + viewh; y++) { for (x = viewx; x < viewx + vieww; x++) { cell_t *cell; cell = getcellat(map, x, y); if (cell && !cell->known && haslos(player, cell)) { cell->known = B_TRUE; } } } }