2010-12-02 12:17:54 +11:00
|
|
|
#include <assert.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "defs.h"
|
|
|
|
#include "nexus.h"
|
2010-12-07 18:34:26 +11:00
|
|
|
#include "lf.h"
|
2010-12-02 12:17:54 +11:00
|
|
|
#include "map.h"
|
|
|
|
#include "objects.h"
|
|
|
|
|
|
|
|
extern map_t *firstmap,*lastmap;
|
2010-12-07 18:34:26 +11:00
|
|
|
extern int viewx,viewy,vieww,viewh;
|
|
|
|
extern lifeform_t *player;
|
2010-12-02 12:17:54 +11:00
|
|
|
|
|
|
|
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];
|
2010-12-07 18:34:26 +11:00
|
|
|
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);
|
|
|
|
}
|
2010-12-02 12:17:54 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-12-07 18:34:26 +11:00
|
|
|
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--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-02 12:17:54 +11:00
|
|
|
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;
|
2010-12-07 18:34:26 +11:00
|
|
|
for (y = 0; y < map->h; y++) {
|
|
|
|
for (x = 0; x < map->w; x++) {
|
2010-12-02 12:17:54 +11:00
|
|
|
c = getcellat(map, x, y);
|
2010-12-07 18:34:26 +11:00
|
|
|
// is this cell in the correct room and not a wall?
|
|
|
|
if (c && !c->type->solid && (c->roomid == roomid)) {
|
2010-12-02 12:17:54 +11:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-07 18:34:26 +11:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|