Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1593 lines (1423 sloc) 39.5 KB
/* SCCS Id: @(#)mklev.c 3.4 2001/11/29 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
/* #define DEBUG */ /* uncomment to enable code debugging */
#ifdef DEBUG
# ifdef WIZARD
#define debugpline if (wizard) pline
# else
#define debugpline pline
# endif
#endif
/* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
/* croom->lx etc are schar (width <= int), so % arith ensures that */
/* conversion of result to int is reasonable */
STATIC_DCL void FDECL(mkfount,(int,struct mkroom *));
#ifdef SINKS
STATIC_DCL void FDECL(mksink,(struct mkroom *));
#endif
STATIC_DCL void FDECL(mkaltar,(struct mkroom *));
STATIC_DCL void FDECL(mkgrave,(struct mkroom *));
STATIC_DCL void NDECL(makevtele);
STATIC_DCL void NDECL(clear_level_structures);
STATIC_DCL void NDECL(makelevel);
STATIC_DCL void NDECL(mineralize);
STATIC_DCL boolean FDECL(bydoor,(XCHAR_P,XCHAR_P));
STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *));
STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P));
STATIC_DCL boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*));
STATIC_DCL void FDECL(makeniche,(int));
STATIC_DCL void NDECL(make_niches);
STATIC_PTR int FDECL( CFDECLSPEC do_comp,(const genericptr,const genericptr));
STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int));
STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P));
STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int,
BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P));
STATIC_DCL void NDECL(makerooms);
STATIC_DCL void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
STATIC_DCL void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int));
STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P));
#define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
#define init_vault() vault_x = -1
#define do_vault() (vault_x != -1)
static xchar vault_x, vault_y;
boolean goldseen;
static boolean made_branch; /* used only during level creation */
/* Args must be (const genericptr) so that qsort will always be happy. */
STATIC_PTR int CFDECLSPEC
do_comp(vx,vy)
const genericptr vx;
const genericptr vy;
{
#ifdef LINT
/* lint complains about possible pointer alignment problems, but we know
that vx and vy are always properly aligned. Hence, the following
bogus definition:
*/
return (vx == vy) ? 0 : -1;
#else
register const struct mkroom *x, *y;
x = (const struct mkroom *)vx;
y = (const struct mkroom *)vy;
if(x->lx < y->lx) return(-1);
return(x->lx > y->lx);
#endif /* LINT */
}
STATIC_OVL void
finddpos(cc, xl,yl,xh,yh)
coord *cc;
xchar xl,yl,xh,yh;
{
register xchar x, y;
x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
if(okdoor(x, y))
goto gotit;
for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
if(okdoor(x, y))
goto gotit;
for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
if(IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
goto gotit;
/* cannot find something reasonable -- strange */
x = xl;
y = yh;
gotit:
cc->x = x;
cc->y = y;
return;
}
void
sort_rooms()
{
#if defined(SYSV) || defined(DGUX)
qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp);
#else
qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp);
#endif
}
STATIC_OVL void
do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room)
register struct mkroom *croom;
int lowx, lowy;
register int hix, hiy;
boolean lit;
schar rtype;
boolean special;
boolean is_room;
{
register int x, y;
struct rm *lev;
/* locations might bump level edges in wall-less rooms */
/* add/subtract 1 to allow for edge locations */
if(!lowx) lowx++;
if(!lowy) lowy++;
if(hix >= COLNO-1) hix = COLNO-2;
if(hiy >= ROWNO-1) hiy = ROWNO-2;
if(lit) {
for(x = lowx-1; x <= hix+1; x++) {
lev = &levl[x][max(lowy-1,0)];
for(y = lowy-1; y <= hiy+1; y++)
lev++->lit = 1;
}
croom->rlit = 1;
} else
croom->rlit = 0;
croom->lx = lowx;
croom->hx = hix;
croom->ly = lowy;
croom->hy = hiy;
croom->rtype = rtype;
croom->doorct = 0;
/* if we're not making a vault, doorindex will still be 0
* if we are, we'll have problems adding niches to the previous room
* unless fdoor is at least doorindex
*/
croom->fdoor = doorindex;
croom->irregular = FALSE;
croom->nsubrooms = 0;
croom->sbrooms[0] = (struct mkroom *) 0;
if (!special) {
for(x = lowx-1; x <= hix+1; x++)
for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
levl[x][y].typ = HWALL;
levl[x][y].horizontal = 1; /* For open/secret doors. */
}
for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
for(y = lowy; y <= hiy; y++) {
levl[x][y].typ = VWALL;
levl[x][y].horizontal = 0; /* For open/secret doors. */
}
for(x = lowx; x <= hix; x++) {
lev = &levl[x][lowy];
for(y = lowy; y <= hiy; y++)
lev++->typ = ROOM;
}
if (is_room) {
levl[lowx-1][lowy-1].typ = TLCORNER;
levl[hix+1][lowy-1].typ = TRCORNER;
levl[lowx-1][hiy+1].typ = BLCORNER;
levl[hix+1][hiy+1].typ = BRCORNER;
} else { /* a subroom */
wallification(lowx-1, lowy-1, hix+1, hiy+1);
}
}
}
void
add_room(lowx, lowy, hix, hiy, lit, rtype, special)
register int lowx, lowy, hix, hiy;
boolean lit;
schar rtype;
boolean special;
{
register struct mkroom *croom;
croom = &rooms[nroom];
do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
rtype, special, (boolean) TRUE);
croom++;
croom->hx = -1;
nroom++;
}
void
add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special)
struct mkroom *proom;
register int lowx, lowy, hix, hiy;
boolean lit;
schar rtype;
boolean special;
{
register struct mkroom *croom;
croom = &subrooms[nsubroom];
do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
rtype, special, (boolean) FALSE);
proom->sbrooms[proom->nsubrooms++] = croom;
croom++;
croom->hx = -1;
nsubroom++;
}
STATIC_OVL void
makerooms()
{
boolean tried_vault = FALSE;
/* make rooms until satisfied */
/* rnd_rect() will returns 0 if no more rects are available... */
while(nroom < MAXNROFROOMS && rnd_rect()) {
if(nroom >= (MAXNROFROOMS/6) && rn2(2) && !tried_vault) {
tried_vault = TRUE;
if (create_vault()) {
vault_x = rooms[nroom].lx;
vault_y = rooms[nroom].ly;
rooms[nroom].hx = -1;
}
} else
if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
return;
}
return;
}
STATIC_OVL void
join(a,b,nxcor)
register int a, b;
boolean nxcor;
{
coord cc,tt, org, dest;
register xchar tx, ty, xx, yy;
register struct mkroom *croom, *troom;
register int dx, dy;
croom = &rooms[a];
troom = &rooms[b];
/* find positions cc and tt for doors in croom and troom
and direction for a corridor between them */
if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
if(troom->lx > croom->hx) {
dx = 1;
dy = 0;
xx = croom->hx+1;
tx = troom->lx-1;
finddpos(&cc, xx, croom->ly, xx, croom->hy);
finddpos(&tt, tx, troom->ly, tx, troom->hy);
} else if(troom->hy < croom->ly) {
dy = -1;
dx = 0;
yy = croom->ly-1;
finddpos(&cc, croom->lx, yy, croom->hx, yy);
ty = troom->hy+1;
finddpos(&tt, troom->lx, ty, troom->hx, ty);
} else if(troom->hx < croom->lx) {
dx = -1;
dy = 0;
xx = croom->lx-1;
tx = troom->hx+1;
finddpos(&cc, xx, croom->ly, xx, croom->hy);
finddpos(&tt, tx, troom->ly, tx, troom->hy);
} else {
dy = 1;
dx = 0;
yy = croom->hy+1;
ty = troom->ly-1;
finddpos(&cc, croom->lx, yy, croom->hx, yy);
finddpos(&tt, troom->lx, ty, troom->hx, ty);
}
xx = cc.x;
yy = cc.y;
tx = tt.x - dx;
ty = tt.y - dy;
if(nxcor && levl[xx+dx][yy+dy].typ)
return;
if (okdoor(xx,yy) || !nxcor)
dodoor(xx,yy,croom);
org.x = xx+dx; org.y = yy+dy;
dest.x = tx; dest.y = ty;
if (!dig_corridor(&org, &dest, nxcor,
level.flags.arboreal ? ROOM : CORR, STONE))
return;
/* we succeeded in digging the corridor */
if (okdoor(tt.x, tt.y) || !nxcor)
dodoor(tt.x, tt.y, troom);
if(smeq[a] < smeq[b])
smeq[b] = smeq[a];
else
smeq[a] = smeq[b];
}
void
makecorridors()
{
int a, b, i;
boolean any = TRUE;
for(a = 0; a < nroom-1; a++) {
join(a, a+1, FALSE);
if(!rn2(50)) break; /* allow some randomness */
}
for(a = 0; a < nroom-2; a++)
if(smeq[a] != smeq[a+2])
join(a, a+2, FALSE);
for(a = 0; any && a < nroom; a++) {
any = FALSE;
for(b = 0; b < nroom; b++)
if(smeq[a] != smeq[b]) {
join(a, b, FALSE);
any = TRUE;
}
}
if(nroom > 2)
for(i = rn2(nroom) + 4; i; i--) {
a = rn2(nroom);
b = rn2(nroom-2);
if(b >= a) b += 2;
join(a, b, TRUE);
}
}
void
add_door(x,y,aroom)
register int x, y;
register struct mkroom *aroom;
{
register struct mkroom *broom;
register int tmp;
aroom->doorct++;
broom = aroom+1;
if(broom->hx < 0)
tmp = doorindex;
else
for(tmp = doorindex; tmp > broom->fdoor; tmp--)
doors[tmp] = doors[tmp-1];
doorindex++;
doors[tmp].x = x;
doors[tmp].y = y;
for( ; broom->hx >= 0; broom++) broom->fdoor++;
}
STATIC_OVL void
dosdoor(x,y,aroom,type)
register xchar x, y;
register struct mkroom *aroom;
register int type;
{
boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE);
if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */
type = DOOR;
levl[x][y].typ = type;
if(type == DOOR) {
if(!rn2(3)) { /* is it a locked door, closed, or a doorway? */
if(!rn2(5))
levl[x][y].doormask = D_ISOPEN;
else if(!rn2(6))
levl[x][y].doormask = D_LOCKED;
else
levl[x][y].doormask = D_CLOSED;
if (levl[x][y].doormask != D_ISOPEN && !shdoor &&
level_difficulty() >= 5 && !rn2(25))
levl[x][y].doormask |= D_TRAPPED;
} else
#ifdef STUPID
if (shdoor)
levl[x][y].doormask = D_ISOPEN;
else
levl[x][y].doormask = D_NODOOR;
#else
levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
#endif
if(levl[x][y].doormask & D_TRAPPED) {
struct monst *mtmp;
if (level_difficulty() >= 9 && !rn2(5) &&
!((mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) &&
(mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) &&
(mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) {
/* make a mimic instead */
levl[x][y].doormask = D_NODOOR;
mtmp = makemon(mkclass(S_MIMIC,0), x, y, NO_MM_FLAGS);
if (mtmp)
set_mimic_sym(mtmp);
}
}
/* newsym(x,y); */
} else { /* SDOOR */
if(shdoor || !rn2(5)) levl[x][y].doormask = D_LOCKED;
else levl[x][y].doormask = D_CLOSED;
if(!shdoor && level_difficulty() >= 4 && !rn2(20))
levl[x][y].doormask |= D_TRAPPED;
}
add_door(x,y,aroom);
}
STATIC_OVL boolean
place_niche(aroom,dy,xx,yy)
register struct mkroom *aroom;
int *dy, *xx, *yy;
{
coord dd;
if(rn2(2)) {
*dy = 1;
finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1);
} else {
*dy = -1;
finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1);
}
*xx = dd.x;
*yy = dd.y;
return((boolean)((isok(*xx,*yy+*dy) && levl[*xx][*yy+*dy].typ == STONE)
&& (isok(*xx,*yy-*dy) && !IS_POOL(levl[*xx][*yy-*dy].typ)
&& !IS_FURNITURE(levl[*xx][*yy-*dy].typ))));
}
/* there should be one of these per trap, in the same order as trap.h */
static NEARDATA const char *trap_engravings[TRAPNUM] = {
(char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
(char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
(char *)0, (char *)0, (char *)0, (char *)0,
/* 14..16: trap door, teleport, level-teleport */
"Vlad was here", "ad aerarium", "ad aerarium",
(char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
(char *)0,
};
STATIC_OVL void
makeniche(trap_type)
int trap_type;
{
register struct mkroom *aroom;
register struct rm *rm;
register int vct = 8;
int dy, xx, yy;
register struct trap *ttmp;
if(doorindex < DOORMAX)
while(vct--) {
aroom = &rooms[rn2(nroom)];
if(aroom->rtype != OROOM) continue; /* not an ordinary room */
if(aroom->doorct == 1 && rn2(5)) continue;
if(!place_niche(aroom,&dy,&xx,&yy)) continue;
rm = &levl[xx][yy+dy];
if(trap_type || !rn2(4)) {
rm->typ = SCORR;
if(trap_type) {
if((trap_type == HOLE || trap_type == TRAPDOOR)
&& !Can_fall_thru(&u.uz))
trap_type = ROCKTRAP;
ttmp = maketrap(xx, yy+dy, trap_type);
if (ttmp) {
if (trap_type != ROCKTRAP) ttmp->once = 1;
if (trap_engravings[trap_type]) {
make_engr_at(xx, yy-dy,
trap_engravings[trap_type], 0L, DUST);
wipe_engr_at(xx, yy-dy, 5); /* age it a little */
}
}
}
dosdoor(xx, yy, aroom, SDOOR);
} else {
rm->typ = CORR;
if(rn2(7))
dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
else {
if (!level.flags.noteleport)
(void) mksobj_at(SCR_TELEPORTATION,
xx, yy+dy, TRUE, FALSE);
if (!rn2(3)) (void) mkobj_at(0, xx, yy+dy, TRUE);
}
}
return;
}
}
STATIC_OVL void
make_niches()
{
register int ct = rnd((nroom>>1) + 1), dep = depth(&u.uz);
boolean ltptr = (!level.flags.noteleport && dep > 15),
vamp = (dep > 5 && dep < 25);
while(ct--) {
if (ltptr && !rn2(6)) {
ltptr = FALSE;
makeniche(LEVEL_TELEP);
} else if (vamp && !rn2(6)) {
vamp = FALSE;
makeniche(TRAPDOOR);
} else makeniche(NO_TRAP);
}
}
STATIC_OVL void
makevtele()
{
makeniche(TELEP_TRAP);
}
/* clear out various globals that keep information on the current level.
* some of this is only necessary for some types of levels (maze, normal,
* special) but it's easier to put it all in one place than make sure
* each type initializes what it needs to separately.
*/
STATIC_OVL void
clear_level_structures()
{
static struct rm zerorm = { cmap_to_glyph(S_stone),
0, 0, 0, 0, 0, 0, 0, 0 };
register int x,y;
register struct rm *lev;
for(x=0; x<COLNO; x++) {
lev = &levl[x][0];
for(y=0; y<ROWNO; y++) {
*lev++ = zerorm;
#ifdef MICROPORT_BUG
level.objects[x][y] = (struct obj *)0;
level.monsters[x][y] = (struct monst *)0;
#endif
}
}
#ifndef MICROPORT_BUG
(void) memset((genericptr_t)level.objects, 0, sizeof(level.objects));
(void) memset((genericptr_t)level.monsters, 0, sizeof(level.monsters));
#endif
level.objlist = (struct obj *)0;
level.buriedobjlist = (struct obj *)0;
level.monlist = (struct monst *)0;
level.damagelist = (struct damage *)0;
level.flags.nfountains = 0;
level.flags.nsinks = 0;
level.flags.has_shop = 0;
level.flags.has_vault = 0;
level.flags.has_zoo = 0;
level.flags.has_court = 0;
level.flags.has_morgue = level.flags.graveyard = 0;
level.flags.has_beehive = 0;
level.flags.has_barracks = 0;
level.flags.has_temple = 0;
level.flags.has_swamp = 0;
level.flags.noteleport = 0;
level.flags.hardfloor = 0;
level.flags.nommap = 0;
level.flags.hero_memory = 1;
level.flags.shortsighted = 0;
level.flags.arboreal = 0;
level.flags.is_maze_lev = 0;
level.flags.is_cavernous_lev = 0;
nroom = 0;
rooms[0].hx = -1;
nsubroom = 0;
subrooms[0].hx = -1;
doorindex = 0;
init_rect();
init_vault();
xdnstair = ydnstair = xupstair = yupstair = 0;
sstairs.sx = sstairs.sy = 0;
xdnladder = ydnladder = xupladder = yupladder = 0;
made_branch = FALSE;
clear_regions();
}
STATIC_OVL void
makelevel()
{
register struct mkroom *croom, *troom;
register int tryct;
register int x, y;
struct monst *tmonst; /* always put a web with a spider */
branch *branchp;
int room_threshold;
if(wiz1_level.dlevel == 0) init_dungeons();
oinit(); /* assign level dependent obj probabilities */
clear_level_structures();
{
register s_level *slev = Is_special(&u.uz);
/* check for special levels */
#ifdef REINCARNATION
if (slev && !Is_rogue_level(&u.uz))
#else
if (slev)
#endif
{
makemaz(slev->proto);
return;
} else if (dungeons[u.uz.dnum].proto[0]) {
makemaz("");
return;
} else if (In_mines(&u.uz)) {
makemaz("minefill");
return;
} else if (In_quest(&u.uz)) {
char fillname[9];
s_level *loc_lev;
Sprintf(fillname, "%s-loca", urole.filecode);
loc_lev = find_level(fillname);
Sprintf(fillname, "%s-fil", urole.filecode);
Strcat(fillname,
(u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
makemaz(fillname);
return;
} else if(In_hell(&u.uz) ||
(rn2(5) && u.uz.dnum == medusa_level.dnum
&& depth(&u.uz) > depth(&medusa_level))) {
makemaz("");
return;
}
}
/* otherwise, fall through - it's a "regular" level. */
#ifdef REINCARNATION
if (Is_rogue_level(&u.uz)) {
makeroguerooms();
makerogueghost();
} else
#endif
makerooms();
sort_rooms();
/* construct stairs (up and down in different rooms if possible) */
croom = &rooms[rn2(nroom)];
if (!Is_botlevel(&u.uz))
mkstairs(somex(croom), somey(croom), 0, croom); /* down */
if (nroom > 1) {
troom = croom;
croom = &rooms[rn2(nroom-1)];
if (croom == troom) croom++;
}
if (u.uz.dlevel != 1) {
xchar sx, sy;
do {
sx = somex(croom);
sy = somey(croom);
} while(occupied(sx, sy));
mkstairs(sx, sy, 1, croom); /* up */
}
branchp = Is_branchlev(&u.uz); /* possible dungeon branch */
room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed
to allow a random special room */
#ifdef REINCARNATION
if (Is_rogue_level(&u.uz)) goto skip0;
#endif
makecorridors();
make_niches();
/* make a secret treasure vault, not connected to the rest */
if(do_vault()) {
xchar w,h;
#ifdef DEBUG
debugpline("trying to make a vault...");
#endif
w = 1;
h = 1;
if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) {
fill_vault:
add_room(vault_x, vault_y, vault_x+w,
vault_y+h, TRUE, VAULT, FALSE);
level.flags.has_vault = 1;
++room_threshold;
fill_room(&rooms[nroom - 1], FALSE);
mk_knox_portal(vault_x+w, vault_y+h);
if(!level.flags.noteleport && !rn2(3)) makevtele();
} else if(rnd_rect() && create_vault()) {
vault_x = rooms[nroom].lx;
vault_y = rooms[nroom].ly;
if (check_room(&vault_x, &w, &vault_y, &h, TRUE))
goto fill_vault;
else
rooms[nroom].hx = -1;
}
}
{
register int u_depth = depth(&u.uz);
#ifdef WIZARD
if(wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else
#endif
if (u_depth > 1 &&
u_depth < depth(&medusa_level) &&
nroom >= room_threshold &&
rn2(u_depth) < 3) mkroom(SHOPBASE);
else if (u_depth > 4 && !rn2(6)) mkroom(COURT);
else if (u_depth > 5 && !rn2(8) &&
!(mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) mkroom(LEPREHALL);
else if (u_depth > 6 && !rn2(7)) mkroom(ZOO);
else if (u_depth > 8 && !rn2(5)) mkroom(TEMPLE);
else if (u_depth > 9 && !rn2(5) &&
!(mvitals[PM_KILLER_BEE].mvflags & G_GONE)) mkroom(BEEHIVE);
else if (u_depth > 11 && !rn2(6)) mkroom(MORGUE);
else if (u_depth > 12 && !rn2(8)) mkroom(ANTHOLE);
else if (u_depth > 14 && !rn2(4) &&
!(mvitals[PM_SOLDIER].mvflags & G_GONE)) mkroom(BARRACKS);
else if (u_depth > 15 && !rn2(6)) mkroom(SWAMP);
else if (u_depth > 16 && !rn2(8) &&
!(mvitals[PM_COCKATRICE].mvflags & G_GONE)) mkroom(COCKNEST);
}
#ifdef REINCARNATION
skip0:
#endif
/* Place multi-dungeon branch. */
place_branch(branchp, 0, 0);
/* for each room: put things inside */
for(croom = rooms; croom->hx > 0; croom++) {
if(croom->rtype != OROOM) continue;
/* put a sleeping monster inside */
/* Note: monster may be on the stairs. This cannot be
avoided: maybe the player fell through a trap door
while a monster was on the stairs. Conclusion:
we have to check for monsters on the stairs anyway. */
if(u.uhave.amulet || !rn2(3)) {
x = somex(croom); y = somey(croom);
tmonst = makemon((struct permonst *) 0, x,y,NO_MM_FLAGS);
if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] &&
!occupied(x, y))
(void) maketrap(x, y, WEB);
}
/* put traps and mimics inside */
goldseen = FALSE;
x = 8 - (level_difficulty()/6);
if (x <= 1) x = 2;
while (!rn2(x))
mktrap(0,0,croom,(coord*)0);
if (!goldseen && !rn2(3))
(void) mkgold(0L, somex(croom), somey(croom));
#ifdef REINCARNATION
if(Is_rogue_level(&u.uz)) goto skip_nonrogue;
#endif
if(!rn2(10)) mkfount(0,croom);
#ifdef SINKS
if(!rn2(60)) mksink(croom);
#endif
if(!rn2(60)) mkaltar(croom);
x = 80 - (depth(&u.uz) * 2);
if (x < 2) x = 2;
if(!rn2(x)) mkgrave(croom);
/* put statues inside */
if(!rn2(20))
(void) mkcorpstat(STATUE, (struct monst *)0,
(struct permonst *)0,
somex(croom), somey(croom), TRUE);
/* put box/chest inside;
* 40% chance for at least 1 box, regardless of number
* of rooms; about 5 - 7.5% for 2 boxes, least likely
* when few rooms; chance for 3 or more is neglible.
*/
if(!rn2(nroom * 5 / 2))
(void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
somex(croom), somey(croom), TRUE, FALSE);
/* maybe make some graffiti */
if(!rn2(27 + 3 * abs(depth(&u.uz)))) {
char buf[BUFSZ];
const char *mesg = random_engraving(buf);
if (mesg) {
do {
x = somex(croom); y = somey(croom);
} while(levl[x][y].typ != ROOM && !rn2(40));
if (!(IS_POOL(levl[x][y].typ) ||
IS_FURNITURE(levl[x][y].typ)))
make_engr_at(x, y, mesg, 0L, MARK);
}
}
#ifdef REINCARNATION
skip_nonrogue:
#endif
if(!rn2(3)) {
(void) mkobj_at(0, somex(croom), somey(croom), TRUE);
tryct = 0;
while(!rn2(5)) {
if(++tryct > 100) {
impossible("tryct overflow4");
break;
}
(void) mkobj_at(0, somex(croom), somey(croom), TRUE);
}
}
}
}
/*
* Place deposits of minerals (gold and misc gems) in the stone
* surrounding the rooms on the map.
* Also place kelp in water.
*/
STATIC_OVL void
mineralize()
{
s_level *sp;
struct obj *otmp;
int goldprob, gemprob, x, y, cnt;
/* Place kelp, except on the plane of water */
if (In_endgame(&u.uz)) return;
for (x = 2; x < (COLNO - 2); x++)
for (y = 1; y < (ROWNO - 1); y++)
if ((levl[x][y].typ == POOL && !rn2(10)) ||
(levl[x][y].typ == MOAT && !rn2(30)))
(void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE);
/* determine if it is even allowed;
almost all special levels are excluded */
if (In_hell(&u.uz) || In_V_tower(&u.uz) ||
#ifdef REINCARNATION
Is_rogue_level(&u.uz) ||
#endif
level.flags.arboreal ||
((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz)
&& (!In_mines(&u.uz) || sp->flags.town)
)) return;
/* basic level-related probabilities */
goldprob = 20 + depth(&u.uz) / 3;
gemprob = goldprob / 4;
/* mines have ***MORE*** goodies - otherwise why mine? */
if (In_mines(&u.uz)) {
goldprob *= 2;
gemprob *= 3;
} else if (In_quest(&u.uz)) {
goldprob /= 4;
gemprob /= 6;
}
/*
* Seed rock areas with gold and/or gems.
* We use fairly low level object handling to avoid unnecessary
* overhead from placing things in the floor chain prior to burial.
*/
for (x = 2; x < (COLNO - 2); x++)
for (y = 1; y < (ROWNO - 1); y++)
if (levl[x][y+1].typ != STONE) { /* <x,y> spot not eligible */
y += 2; /* next two spots aren't eligible either */
} else if (levl[x][y].typ != STONE) { /* this spot not eligible */
y += 1; /* next spot isn't eligible either */
} else if (!(levl[x][y].wall_info & W_NONDIGGABLE) &&
levl[x][y-1].typ == STONE &&
levl[x+1][y-1].typ == STONE && levl[x-1][y-1].typ == STONE &&
levl[x+1][y].typ == STONE && levl[x-1][y].typ == STONE &&
levl[x+1][y+1].typ == STONE && levl[x-1][y+1].typ == STONE) {
if (rn2(1000) < goldprob) {
if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) {
otmp->ox = x, otmp->oy = y;
otmp->quan = 1L + rnd(goldprob * 3);
otmp->owt = weight(otmp);
if (!rn2(3)) add_to_buried(otmp);
else place_object(otmp, x, y);
}
}
if (rn2(1000) < gemprob) {
for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--)
if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) {
if (otmp->otyp == ROCK) {
dealloc_obj(otmp); /* discard it */
} else {
otmp->ox = x, otmp->oy = y;
if (!rn2(3)) add_to_buried(otmp);
else place_object(otmp, x, y);
}
}
}
}
}
void
mklev()
{
struct mkroom *croom;
if(getbones()) return;
in_mklev = TRUE;
makelevel();
bound_digging();
mineralize();
in_mklev = FALSE;
/* has_morgue gets cleared once morgue is entered; graveyard stays
set (graveyard might already be set even when has_morgue is clear
[see fixup_special()], so don't update it unconditionally) */
if (level.flags.has_morgue)
level.flags.graveyard = 1;
if (!level.flags.is_maze_lev) {
for (croom = &rooms[0]; croom != &rooms[nroom]; croom++)
#ifdef SPECIALIZATION
topologize(croom, FALSE);
#else
topologize(croom);
#endif
}
set_wall_state();
}
void
#ifdef SPECIALIZATION
topologize(croom, do_ordinary)
register struct mkroom *croom;
boolean do_ordinary;
#else
topologize(croom)
register struct mkroom *croom;
#endif
{
register int x, y, roomno = (croom - rooms) + ROOMOFFSET;
register int lowx = croom->lx, lowy = croom->ly;
register int hix = croom->hx, hiy = croom->hy;
#ifdef SPECIALIZATION
register schar rtype = croom->rtype;
#endif
register int subindex, nsubrooms = croom->nsubrooms;
/* skip the room if already done; i.e. a shop handled out of order */
/* also skip if this is non-rectangular (it _must_ be done already) */
if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular)
return;
#ifdef SPECIALIZATION
# ifdef REINCARNATION
if (Is_rogue_level(&u.uz))
do_ordinary = TRUE; /* vision routine helper */
# endif
if ((rtype != OROOM) || do_ordinary)
#endif
{
/* do innards first */
for(x = lowx; x <= hix; x++)
for(y = lowy; y <= hiy; y++)
#ifdef SPECIALIZATION
if (rtype == OROOM)
levl[x][y].roomno = NO_ROOM;
else
#endif
levl[x][y].roomno = roomno;
/* top and bottom edges */
for(x = lowx-1; x <= hix+1; x++)
for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
levl[x][y].edge = 1;
if (levl[x][y].roomno)
levl[x][y].roomno = SHARED;
else
levl[x][y].roomno = roomno;
}
/* sides */
for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
for(y = lowy; y <= hiy; y++) {
levl[x][y].edge = 1;
if (levl[x][y].roomno)
levl[x][y].roomno = SHARED;
else
levl[x][y].roomno = roomno;
}
}
/* subrooms */
for (subindex = 0; subindex < nsubrooms; subindex++)
#ifdef SPECIALIZATION
topologize(croom->sbrooms[subindex], (rtype != OROOM));
#else
topologize(croom->sbrooms[subindex]);
#endif
}
/* Find an unused room for a branch location. */
STATIC_OVL struct mkroom *
find_branch_room(mp)
coord *mp;
{
struct mkroom *croom = 0;
if (nroom == 0) {
mazexy(mp); /* already verifies location */
} else {
/* not perfect - there may be only one stairway */
if(nroom > 2) {
int tryct = 0;
do
croom = &rooms[rn2(nroom)];
while((croom == dnstairs_room || croom == upstairs_room ||
croom->rtype != OROOM) && (++tryct < 100));
} else
croom = &rooms[rn2(nroom)];
do {
if (!somexy(croom, mp))
impossible("Can't place branch!");
} while(occupied(mp->x, mp->y) ||
(levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM));
}
return croom;
}
/* Find the room for (x,y). Return null if not in a room. */
STATIC_OVL struct mkroom *
pos_to_room(x, y)
xchar x, y;
{
int i;
struct mkroom *curr;
for (curr = rooms, i = 0; i < nroom; curr++, i++)
if (inside_room(curr, x, y)) return curr;;
return (struct mkroom *) 0;
}
/* If given a branch, randomly place a special stair or portal. */
void
place_branch(br, x, y)
branch *br; /* branch to place */
xchar x, y; /* location */
{
coord m;
d_level *dest;
boolean make_stairs;
struct mkroom *br_room;
/*
* Return immediately if there is no branch to make or we have
* already made one. This routine can be called twice when
* a special level is loaded that specifies an SSTAIR location
* as a favored spot for a branch.
*/
if (!br || made_branch) return;
if (!x) { /* find random coordinates for branch */
br_room = find_branch_room(&m);
x = m.x;
y = m.y;
} else {
br_room = pos_to_room(x, y);
}
if (on_level(&br->end1, &u.uz)) {
/* we're on end1 */
make_stairs = br->type != BR_NO_END1;
dest = &br->end2;
} else {
/* we're on end2 */
make_stairs = br->type != BR_NO_END2;
dest = &br->end1;
}
if (br->type == BR_PORTAL) {
mkportal(x, y, dest->dnum, dest->dlevel);
} else if (make_stairs) {
sstairs.sx = x;
sstairs.sy = y;
sstairs.up = (char) on_level(&br->end1, &u.uz) ?
br->end1_up : !br->end1_up;
assign_level(&sstairs.tolev, dest);
sstairs_room = br_room;
levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN;
levl[x][y].typ = STAIRS;
}
/*
* Set made_branch to TRUE even if we didn't make a stairwell (i.e.
* make_stairs is false) since there is currently only one branch
* per level, if we failed once, we're going to fail again on the
* next call.
*/
made_branch = TRUE;
}
STATIC_OVL boolean
bydoor(x, y)
register xchar x, y;
{
register int typ;
if (isok(x+1, y)) {
typ = levl[x+1][y].typ;
if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
}
if (isok(x-1, y)) {
typ = levl[x-1][y].typ;
if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
}
if (isok(x, y+1)) {
typ = levl[x][y+1].typ;
if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
}
if (isok(x, y-1)) {
typ = levl[x][y-1].typ;
if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
}
return FALSE;
}
/* see whether it is allowable to create a door at [x,y] */
int
okdoor(x,y)
register xchar x, y;
{
register boolean near_door = bydoor(x, y);
return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) &&
doorindex < DOORMAX && !near_door);
}
void
dodoor(x,y,aroom)
register int x, y;
register struct mkroom *aroom;
{
if(doorindex >= DOORMAX) {
impossible("DOORMAX exceeded?");
return;
}
dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
}
boolean
occupied(x, y)
register xchar x, y;
{
return((boolean)(t_at(x, y)
|| IS_FURNITURE(levl[x][y].typ)
|| is_lava(x,y)
|| is_pool(x,y)
|| invocation_pos(x,y)
));
}
/* make a trap somewhere (in croom if mazeflag = 0 && !tm) */
/* if tm != null, make trap at that location */
void
mktrap(num, mazeflag, croom, tm)
register int num, mazeflag;
register struct mkroom *croom;
coord *tm;
{
register int kind;
coord m;
/* no traps in pools */
if (tm && is_pool(tm->x,tm->y)) return;
if (num > 0 && num < TRAPNUM) {
kind = num;
#ifdef REINCARNATION
} else if (Is_rogue_level(&u.uz)) {
switch (rn2(7)) {
default: kind = BEAR_TRAP; break; /* 0 */
case 1: kind = ARROW_TRAP; break;
case 2: kind = DART_TRAP; break;
case 3: kind = TRAPDOOR; break;
case 4: kind = PIT; break;
case 5: kind = SLP_GAS_TRAP; break;
case 6: kind = RUST_TRAP; break;
}
#endif
} else if (Inhell && !rn2(5)) {
/* bias the frequency of fire traps in Gehennom */
kind = FIRE_TRAP;
} else {
unsigned lvl = level_difficulty();
do {
kind = rnd(TRAPNUM-1);
/* reject "too hard" traps */
switch (kind) {
case MAGIC_PORTAL:
kind = NO_TRAP; break;
case ROLLING_BOULDER_TRAP:
case SLP_GAS_TRAP:
if (lvl < 2) kind = NO_TRAP; break;
case LEVEL_TELEP:
if (lvl < 5 || level.flags.noteleport)
kind = NO_TRAP; break;
case SPIKED_PIT:
if (lvl < 5) kind = NO_TRAP; break;
case LANDMINE:
if (lvl < 6) kind = NO_TRAP; break;
case WEB:
if (lvl < 7) kind = NO_TRAP; break;
case STATUE_TRAP:
case POLY_TRAP:
if (lvl < 8) kind = NO_TRAP; break;
case FIRE_TRAP:
if (!Inhell) kind = NO_TRAP; break;
case TELEP_TRAP:
if (level.flags.noteleport) kind = NO_TRAP; break;
case HOLE:
/* make these much less often than other traps */
if (rn2(7)) kind = NO_TRAP; break;
}
} while (kind == NO_TRAP);
}
if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz))
kind = ROCKTRAP;
if (tm)
m = *tm;
else {
register int tryct = 0;
boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT ||
kind == TRAPDOOR || kind == HOLE);
do {
if (++tryct > 200)
return;
if (mazeflag)
mazexy(&m);
else if (!somexy(croom,&m))
return;
} while (occupied(m.x, m.y) ||
(avoid_boulder && sobj_at(BOULDER, m.x, m.y)));
}
(void) maketrap(m.x, m.y, kind);
if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER],
m.x, m.y, NO_MM_FLAGS);
}
void
mkstairs(x, y, up, croom)
xchar x, y;
char up;
struct mkroom *croom;
{
if (!x) {
impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y);
return;
}
/*
* We can't make a regular stair off an end of the dungeon. This
* attempt can happen when a special level is placed at an end and
* has an up or down stair specified in its description file.
*/
if ((dunlev(&u.uz) == 1 && up) ||
(dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up))
return;
if(up) {
xupstair = x;
yupstair = y;
upstairs_room = croom;
} else {
xdnstair = x;
ydnstair = y;
dnstairs_room = croom;
}
levl[x][y].typ = STAIRS;
levl[x][y].ladder = up ? LA_UP : LA_DOWN;
}
STATIC_OVL
void
mkfount(mazeflag,croom)
register int mazeflag;
register struct mkroom *croom;
{
coord m;
register int tryct = 0;
do {
if(++tryct > 200) return;
if(mazeflag)
mazexy(&m);
else
if (!somexy(croom, &m))
return;
} while(occupied(m.x, m.y) || bydoor(m.x, m.y));
/* Put a fountain at m.x, m.y */
levl[m.x][m.y].typ = FOUNTAIN;
/* Is it a "blessed" fountain? (affects drinking from fountain) */
if(!rn2(7)) levl[m.x][m.y].blessedftn = 1;
level.flags.nfountains++;
}
#ifdef SINKS
STATIC_OVL void
mksink(croom)
register struct mkroom *croom;
{
coord m;
register int tryct = 0;
do {
if(++tryct > 200) return;
if (!somexy(croom, &m))
return;
} while(occupied(m.x, m.y) || bydoor(m.x, m.y));
/* Put a sink at m.x, m.y */
levl[m.x][m.y].typ = SINK;
level.flags.nsinks++;
}
#endif /* SINKS */
STATIC_OVL void
mkaltar(croom)
register struct mkroom *croom;
{
coord m;
register int tryct = 0;
aligntyp al;
if (croom->rtype != OROOM) return;
do {
if(++tryct > 200) return;
if (!somexy(croom, &m))
return;
} while (occupied(m.x, m.y) || bydoor(m.x, m.y));
/* Put an altar at m.x, m.y */
levl[m.x][m.y].typ = ALTAR;
/* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
al = rn2((int)A_LAWFUL+2) - 1;
levl[m.x][m.y].altarmask = Align2amask( al );
}
static void
mkgrave(croom)
struct mkroom *croom;
{
coord m;
register int tryct = 0;
register struct obj *otmp;
boolean dobell = !rn2(10);
if(croom->rtype != OROOM) return;
do {
if(++tryct > 200) return;
if (!somexy(croom, &m))
return;
} while (occupied(m.x, m.y) || bydoor(m.x, m.y));
/* Put a grave at m.x, m.y */
make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0);
/* Possibly fill it with objects */
if (!rn2(3)) (void) mkgold(0L, m.x, m.y);
for (tryct = rn2(5); tryct; tryct--) {
otmp = mkobj(RANDOM_CLASS, TRUE);
if (!otmp) return;
curse(otmp);
otmp->ox = m.x;
otmp->oy = m.y;
add_to_buried(otmp);
}
/* Leave a bell, in case we accidentally buried someone alive */
if (dobell) (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE);
return;
}
/* maze levels have slightly different constraints from normal levels */
#define x_maze_min 2
#define y_maze_min 2
/*
* Major level transmutation: add a set of stairs (to the Sanctum) after
* an earthquake that leaves behind a a new topology, centered at inv_pos.
* Assumes there are no rooms within the invocation area and that inv_pos
* is not too close to the edge of the map. Also assume the hero can see,
* which is guaranteed for normal play due to the fact that sight is needed
* to read the Book of the Dead.
*/
void
mkinvokearea()
{
int dist;
xchar xmin = inv_pos.x, xmax = inv_pos.x;
xchar ymin = inv_pos.y, ymax = inv_pos.y;
register xchar i;
pline_The("floor shakes violently under you!");
pline_The("walls around you begin to bend and crumble!");
display_nhwindow(WIN_MESSAGE, TRUE);
mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */
for(dist = 1; dist < 7; dist++) {
xmin--; xmax++;
/* top and bottom */
if(dist != 3) { /* the area is wider that it is high */
ymin--; ymax++;
for(i = xmin+1; i < xmax; i++) {
mkinvpos(i, ymin, dist);
mkinvpos(i, ymax, dist);
}
}
/* left and right */
for(i = ymin; i <= ymax; i++) {
mkinvpos(xmin, i, dist);
mkinvpos(xmax, i, dist);
}
flush_screen(1); /* make sure the new glyphs shows up */
delay_output();
}
You("are standing at the top of a stairwell leading down!");
mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */
newsym(u.ux, u.uy);
vision_full_recalc = 1; /* everything changed */
}
/* Change level topology. Boulders in the vicinity are eliminated.
* Temporarily overrides vision in the name of a nice effect.
*/
STATIC_OVL void
mkinvpos(x,y,dist)
xchar x,y;
int dist;
{
struct trap *ttmp;
struct obj *otmp;
boolean make_rocks;
register struct rm *lev = &levl[x][y];
/* clip at existing map borders if necessary */
if (!within_bounded_area(x, y, x_maze_min + 1, y_maze_min + 1,
x_maze_max - 1, y_maze_max - 1)) {
/* only outermost 2 columns and/or rows may be truncated due to edge */
if (dist < (7 - 2))
panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist);
return;
}
/* clear traps */
if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
/* clear boulders; leave some rocks for non-{moat|trap} locations */
make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE;
while ((otmp = sobj_at(BOULDER, x, y)) != 0) {
if (make_rocks) {
fracture_rock(otmp);
make_rocks = FALSE; /* don't bother with more rocks */
} else {
obj_extract_self(otmp);
obfree(otmp, (struct obj *)0);
}
}
unblock_point(x,y); /* make sure vision knows this location is open */
/* fake out saved state */
lev->seenv = 0;
lev->doormask = 0;
if(dist < 6) lev->lit = TRUE;
lev->waslit = TRUE;
lev->horizontal = FALSE;
viz_array[y][x] = (dist < 6 ) ?
(IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
COULD_SEE;
switch(dist) {
case 1: /* fire traps */
if (is_pool(x,y)) break;
lev->typ = ROOM;
ttmp = maketrap(x, y, FIRE_TRAP);
if (ttmp) ttmp->tseen = TRUE;
break;
case 0: /* lit room locations */
case 2:
case 3:
case 6: /* unlit room locations */
lev->typ = ROOM;
break;
case 4: /* pools (aka a wide moat) */
case 5:
lev->typ = MOAT;
/* No kelp! */
break;
default:
impossible("mkinvpos called with dist %d", dist);
break;
}
/* display new value of position; could have a monster/object on it */
newsym(x,y);
}
/*
* The portal to Ludios is special. The entrance can only occur within a
* vault in the main dungeon at a depth greater than 10. The Ludios branch
* structure reflects this by having a bogus "source" dungeon: the value
* of n_dgns (thus, Is_branchlev() will never find it).
*
* Ludios will remain isolated until the branch is corrected by this function.
*/
STATIC_OVL void
mk_knox_portal(x, y)
xchar x, y;
{
extern int n_dgns; /* from dungeon.c */
d_level *source;
branch *br;
schar u_depth;
br = dungeon_branch("Fort Ludios");
if (on_level(&knox_level, &br->end1)) {
source = &br->end2;
} else {
/* disallow Knox branch on a level with one branch already */
if(Is_branchlev(&u.uz))
return;
source = &br->end1;
}
/* Already set or 2/3 chance of deferring until a later level. */
if (source->dnum < n_dgns || (rn2(3)
#ifdef WIZARD
&& !wizard
#endif
)) return;
if (! (u.uz.dnum == oracle_level.dnum /* in main dungeon */
&& !at_dgn_entrance("The Quest") /* but not Quest's entry */
&& (u_depth = depth(&u.uz)) > 10 /* beneath 10 */
&& u_depth < depth(&medusa_level))) /* and above Medusa */
return;
/* Adjust source to be current level and re-insert branch. */
*source = u.uz;
insert_branch(br, TRUE);
#ifdef DEBUG
pline("Made knox portal.");
#endif
place_branch(br, x, y);
}
/*mklev.c*/