Files
nethack/src/mkroom.c
copperwater 3d03a472f6 Stock all special rooms at the end of level creation
This unifies the two separate special-room-stocking code paths, one in
the standard dungeon generator and one in the special level generator
(neither of which reacted to themed rooms, which is the reason for this
commit) into the end of makelevel(), placing the special room stocking
as the very last step of level creation.

Under the new system, when a regular or special level decides to create
a special room, it sets that room's rtype, but the room is not stocked
until later. It already worked this way for special levels, so the main
difference here is in the normal level generation, where the mkroom
family of functions identifies and marks a room as a special room, but
stops short of filling it. (I suppose perhaps the mkroom, mkzoo, mkshop
family of functions would be better off changing their names to
"pickroom" and so on.)

This also restructures makelevel() itself a bit, but the only real
change is that the paths that call makemaz don't return immediately
afterward; they continue to the special room stocking code. Also, this
code was lifted from fill_special_rooms, which is now not used
anywhere, so it has been deleted.

I don't really like how fill_ordinary_room is in mklev.c and
fill_special_room is in sp_lev.c; they seem like they'd be better off in
mkroom.c, but in the interest of not making unnecessary code changes,
I'll just recommend it.
2020-09-27 18:54:15 +03:00

1020 lines
28 KiB
C

/* NetHack 3.7 mkroom.c $NHDT-Date: 1596498184 2020/08/03 23:43:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.45 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */
/*
* Entry points:
* mkroom() -- make and stock a room of a given type
* nexttodoor() -- return TRUE if adjacent to a door
* has_dnstairs() -- return TRUE if given room has a down staircase
* has_upstairs() -- return TRUE if given room has an up staircase
* courtmon() -- generate a court monster
* save_rooms() -- save rooms into file fd
* rest_rooms() -- restore rooms from file fd
* cmap_to_type() -- convert S_xxx symbol to XXX topology code
*/
#include "hack.h"
static boolean FDECL(isbig, (struct mkroom *));
static struct mkroom *FDECL(pick_room, (BOOLEAN_P));
static void NDECL(mkshop), FDECL(mkzoo, (int)), NDECL(mkswamp);
static void FDECL(mk_zoo_thronemon, (int, int));
static void NDECL(mktemple);
static coord *FDECL(shrine_pos, (int));
static struct permonst *NDECL(morguemon);
static struct permonst *NDECL(squadmon);
static void FDECL(save_room, (NHFILE *, struct mkroom *));
static void FDECL(rest_room, (NHFILE *, struct mkroom *));
#define sq(x) ((x) * (x))
extern const struct shclass shtypes[]; /* defined in shknam.c */
static boolean
isbig(sroom)
register struct mkroom *sroom;
{
register int area = (sroom->hx - sroom->lx + 1)
* (sroom->hy - sroom->ly + 1);
return (boolean) (area > 20);
}
/* make and stock a room of a given type */
void
mkroom(roomtype)
int roomtype;
{
if (roomtype >= SHOPBASE)
mkshop(); /* someday, we should be able to specify shop type */
else
switch (roomtype) {
case COURT:
mkzoo(COURT);
break;
case ZOO:
mkzoo(ZOO);
break;
case BEEHIVE:
mkzoo(BEEHIVE);
break;
case MORGUE:
mkzoo(MORGUE);
break;
case BARRACKS:
mkzoo(BARRACKS);
break;
case SWAMP:
mkswamp();
break;
case TEMPLE:
mktemple();
break;
case LEPREHALL:
mkzoo(LEPREHALL);
break;
case COCKNEST:
mkzoo(COCKNEST);
break;
case ANTHOLE:
mkzoo(ANTHOLE);
break;
default:
impossible("Tried to make a room of type %d.", roomtype);
}
}
static void
mkshop()
{
register struct mkroom *sroom;
int i = -1;
char *ep = (char *) 0; /* (init == lint suppression) */
/* first determine shoptype */
if (wizard) {
#ifndef MAC
ep = nh_getenv("SHOPTYPE");
if (ep) {
if (*ep == 'z' || *ep == 'Z') {
mkzoo(ZOO);
return;
}
if (*ep == 'm' || *ep == 'M') {
mkzoo(MORGUE);
return;
}
if (*ep == 'b' || *ep == 'B') {
mkzoo(BEEHIVE);
return;
}
if (*ep == 't' || *ep == 'T' || *ep == '\\') {
mkzoo(COURT);
return;
}
if (*ep == 's' || *ep == 'S') {
mkzoo(BARRACKS);
return;
}
if (*ep == 'a' || *ep == 'A') {
mkzoo(ANTHOLE);
return;
}
if (*ep == 'c' || *ep == 'C') {
mkzoo(COCKNEST);
return;
}
if (*ep == 'l' || *ep == 'L') {
mkzoo(LEPREHALL);
return;
}
if (*ep == '_') {
mktemple();
return;
}
if (*ep == '}') {
mkswamp();
return;
}
for (i = 0; shtypes[i].name; i++)
if (*ep == def_oc_syms[(int) shtypes[i].symb].sym)
goto gottype;
if (*ep == 'g' || *ep == 'G')
i = 0;
else if (*ep == 'v' || *ep == 'V')
i = FODDERSHOP - SHOPBASE; /* veggy food */
else
i = -1;
}
#endif
}
#ifndef MAC
gottype:
#endif
for (sroom = &g.rooms[0];; sroom++) {
if (sroom->hx < 0)
return;
if (sroom - g.rooms >= g.nroom) {
pline("g.rooms not closed by -1?");
return;
}
if (sroom->rtype != OROOM)
continue;
if (has_dnstairs(sroom) || has_upstairs(sroom))
continue;
if ((wizard && ep && sroom->doorct != 0) || sroom->doorct == 1)
break;
}
if (!sroom->rlit) {
int x, y;
for (x = sroom->lx - 1; x <= sroom->hx + 1; x++)
for (y = sroom->ly - 1; y <= sroom->hy + 1; y++)
levl[x][y].lit = 1;
sroom->rlit = 1;
}
if (i < 0) { /* shoptype not yet determined */
register int j;
/* pick a shop type at random */
for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++)
continue;
/* big rooms cannot be wand or book shops,
* - so make them general stores
*/
if (isbig(sroom) && (shtypes[i].symb == WAND_CLASS
|| shtypes[i].symb == SPBOOK_CLASS))
i = 0;
}
sroom->rtype = SHOPBASE + i;
/* set room bits before stocking the shop */
#ifdef SPECIALIZATION
topologize(sroom, FALSE); /* doesn't matter - this is a special room */
#else
topologize(sroom);
#endif
/* The shop used to be stocked here, but this no longer happens - all we do
* is set its rtype, and it gets stocked at the end of makelevel() along
* with other special rooms. */
sroom->needfill = FILL_NORMAL;
}
/* pick an unused room, preferably with only one door */
static struct mkroom *
pick_room(strict)
register boolean strict;
{
register struct mkroom *sroom;
register int i = g.nroom;
for (sroom = &g.rooms[rn2(g.nroom)]; i--; sroom++) {
if (sroom == &g.rooms[g.nroom])
sroom = &g.rooms[0];
if (sroom->hx < 0)
return (struct mkroom *) 0;
if (sroom->rtype != OROOM)
continue;
if (!strict) {
if (has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3)))
continue;
} else if (has_upstairs(sroom) || has_dnstairs(sroom))
continue;
if (sroom->doorct == 1 || !rn2(5) || wizard)
return sroom;
}
return (struct mkroom *) 0;
}
static void
mkzoo(type)
int type;
{
register struct mkroom *sroom;
if ((sroom = pick_room(FALSE)) != 0) {
sroom->rtype = type;
/* room does not get stocked at this time - it will get stocked at the
* end of makelevel() */
sroom->needfill = FILL_NORMAL;
}
}
static void
mk_zoo_thronemon(x,y)
int x,y;
{
int i = rnd(level_difficulty());
int pm = (i > 9) ? PM_OGRE_KING
: (i > 5) ? PM_ELVENKING
: (i > 2) ? PM_DWARF_KING
: PM_GNOME_KING;
struct monst *mon = makemon(&mons[pm], x, y, NO_MM_FLAGS);
if (mon) {
mon->msleeping = 1;
mon->mpeaceful = 0;
set_malign(mon);
/* Give him a sceptre to pound in judgment */
(void) mongets(mon, MACE);
}
}
void
fill_zoo(sroom)
struct mkroom *sroom;
{
struct monst *mon;
register int sx, sy, i;
int sh, tx = 0, ty = 0, goldlim = 0, type = sroom->rtype;
int rmno = (int) ((sroom - g.rooms) + ROOMOFFSET);
coord mm;
/* Note: This doesn't check needfill; it assumes the caller has already done
* that. */
sh = sroom->fdoor;
switch (type) {
case COURT:
if (g.level.flags.is_maze_lev) {
for (tx = sroom->lx; tx <= sroom->hx; tx++)
for (ty = sroom->ly; ty <= sroom->hy; ty++)
if (IS_THRONE(levl[tx][ty].typ))
goto throne_placed;
}
i = 100;
do { /* don't place throne on top of stairs */
(void) somexy(sroom, &mm);
tx = mm.x;
ty = mm.y;
} while (occupied((xchar) tx, (xchar) ty) && --i > 0);
throne_placed:
mk_zoo_thronemon(tx, ty);
break;
case BEEHIVE:
tx = sroom->lx + (sroom->hx - sroom->lx + 1) / 2;
ty = sroom->ly + (sroom->hy - sroom->ly + 1) / 2;
if (sroom->irregular) {
/* center might not be valid, so put queen elsewhere */
if ((int) levl[tx][ty].roomno != rmno || levl[tx][ty].edge) {
(void) somexy(sroom, &mm);
tx = mm.x;
ty = mm.y;
}
}
break;
case ZOO:
case LEPREHALL:
goldlim = 500 * level_difficulty();
break;
}
for (sx = sroom->lx; sx <= sroom->hx; sx++)
for (sy = sroom->ly; sy <= sroom->hy; sy++) {
if (sroom->irregular) {
if ((int) levl[sx][sy].roomno != rmno || levl[sx][sy].edge
|| (sroom->doorct
&& distmin(sx, sy, g.doors[sh].x, g.doors[sh].y) <= 1))
continue;
} else if (!SPACE_POS(levl[sx][sy].typ)
|| (sroom->doorct
&& ((sx == sroom->lx && g.doors[sh].x == sx - 1)
|| (sx == sroom->hx && g.doors[sh].x == sx + 1)
|| (sy == sroom->ly && g.doors[sh].y == sy - 1)
|| (sy == sroom->hy
&& g.doors[sh].y == sy + 1))))
continue;
/* don't place monster on explicitly placed throne */
if (type == COURT && IS_THRONE(levl[sx][sy].typ))
continue;
mon = makemon((type == COURT)
? courtmon()
: (type == BARRACKS)
? squadmon()
: (type == MORGUE)
? morguemon()
: (type == BEEHIVE)
? (sx == tx && sy == ty
? &mons[PM_QUEEN_BEE]
: &mons[PM_KILLER_BEE])
: (type == LEPREHALL)
? &mons[PM_LEPRECHAUN]
: (type == COCKNEST)
? &mons[PM_COCKATRICE]
: (type == ANTHOLE)
? antholemon()
: (struct permonst *) 0,
sx, sy, MM_ASLEEP);
if (mon) {
mon->msleeping = 1;
if (type == COURT && mon->mpeaceful) {
mon->mpeaceful = 0;
set_malign(mon);
}
}
switch (type) {
case ZOO:
case LEPREHALL:
if (sroom->doorct) {
int distval = dist2(sx, sy, g.doors[sh].x, g.doors[sh].y);
i = sq(distval);
} else
i = goldlim;
if (i >= goldlim)
i = 5 * level_difficulty();
goldlim -= i;
(void) mkgold((long) rn1(i, 10), sx, sy);
break;
case MORGUE:
if (!rn2(5))
(void) mk_tt_object(CORPSE, sx, sy);
if (!rn2(10)) /* lots of treasure buried with dead */
(void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy,
TRUE, FALSE);
if (!rn2(5))
make_grave(sx, sy, (char *) 0);
break;
case BEEHIVE:
if (!rn2(3))
(void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE,
FALSE);
break;
case BARRACKS:
if (!rn2(20)) /* the payroll and some loot */
(void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy,
TRUE, FALSE);
break;
case COCKNEST:
if (!rn2(3)) {
struct obj *sobj = mk_tt_object(STATUE, sx, sy);
if (sobj) {
for (i = rn2(5); i; i--)
(void) add_to_container(
sobj, mkobj(RANDOM_CLASS, FALSE));
sobj->owt = weight(sobj);
}
}
break;
case ANTHOLE:
if (!rn2(3))
(void) mkobj_at(FOOD_CLASS, sx, sy, FALSE);
break;
}
}
switch (type) {
case COURT: {
struct obj *chest, *gold;
levl[tx][ty].typ = THRONE;
(void) somexy(sroom, &mm);
gold = mksobj(GOLD_PIECE, TRUE, FALSE);
gold->quan = (long) rn1(50 * level_difficulty(), 10);
gold->owt = weight(gold);
/* the royal coffers */
chest = mksobj_at(CHEST, mm.x, mm.y, TRUE, FALSE);
add_to_container(chest, gold);
chest->owt = weight(chest);
chest->spe = 2; /* so it can be found later */
g.level.flags.has_court = 1;
break;
}
case BARRACKS:
g.level.flags.has_barracks = 1;
break;
case ZOO:
g.level.flags.has_zoo = 1;
break;
case MORGUE:
g.level.flags.has_morgue = 1;
break;
case SWAMP:
g.level.flags.has_swamp = 1;
break;
case BEEHIVE:
g.level.flags.has_beehive = 1;
break;
}
}
/* make a swarm of undead around mm */
void
mkundead(mm, revive_corpses, mm_flags)
coord *mm;
boolean revive_corpses;
int mm_flags;
{
int cnt = (level_difficulty() + 1) / 10 + rnd(5);
struct permonst *mdat;
struct obj *otmp;
coord cc;
while (cnt--) {
mdat = morguemon();
if (mdat && enexto(&cc, mm->x, mm->y, mdat)
&& (!revive_corpses
|| !(otmp = sobj_at(CORPSE, cc.x, cc.y))
|| !revive(otmp, FALSE)))
(void) makemon(mdat, cc.x, cc.y, mm_flags);
}
g.level.flags.graveyard = TRUE; /* reduced chance for undead corpse */
}
static struct permonst *
morguemon()
{
register int i = rn2(100), hd = rn2(level_difficulty());
if (hd > 10 && i < 10) {
if (Inhell || In_endgame(&u.uz)) {
return mkclass(S_DEMON, 0);
} else {
int ndemon_res = ndemon(A_NONE);
if (ndemon_res != NON_PM)
return &mons[ndemon_res];
/* else do what? As is, it will drop to ghost/wraith/zombie */
}
}
if (hd > 8 && i > 85)
return mkclass(S_VAMPIRE, 0);
return ((i < 20) ? &mons[PM_GHOST]
: (i < 40) ? &mons[PM_WRAITH]
: mkclass(S_ZOMBIE, 0));
}
struct permonst *
antholemon()
{
int mtyp, indx, trycnt = 0;
/* casts are for dealing with time_t */
indx = (int) ((long) ubirthday % 3L);
indx += level_difficulty();
/* Same monsters within a level, different ones between levels */
do {
switch ((indx + trycnt) % 3) {
case 0:
mtyp = PM_SOLDIER_ANT;
break;
case 1:
mtyp = PM_FIRE_ANT;
break;
default:
mtyp = PM_GIANT_ANT;
break;
}
/* try again if chosen type has been genocided or used up */
} while (++trycnt < 3 && (g.mvitals[mtyp].mvflags & G_GONE));
return ((g.mvitals[mtyp].mvflags & G_GONE) ? (struct permonst *) 0
: &mons[mtyp]);
}
static void
mkswamp() /* Michiel Huisjes & Fred de Wilde */
{
register struct mkroom *sroom;
register int sx, sy, i, eelct = 0;
for (i = 0; i < 5; i++) { /* turn up to 5 rooms swampy */
sroom = &g.rooms[rn2(g.nroom)];
if (sroom->hx < 0 || sroom->rtype != OROOM || has_upstairs(sroom)
|| has_dnstairs(sroom))
continue;
/* satisfied; make a swamp */
sroom->rtype = SWAMP;
for (sx = sroom->lx; sx <= sroom->hx; sx++)
for (sy = sroom->ly; sy <= sroom->hy; sy++)
if (!OBJ_AT(sx, sy) && !MON_AT(sx, sy) && !t_at(sx, sy)
&& !nexttodoor(sx, sy)) {
if ((sx + sy) % 2) {
levl[sx][sy].typ = POOL;
if (!eelct || !rn2(4)) {
/* mkclass() won't do, as we might get kraken */
(void) makemon(rn2(5)
? &mons[PM_GIANT_EEL]
: rn2(2)
? &mons[PM_PIRANHA]
: &mons[PM_ELECTRIC_EEL],
sx, sy, NO_MM_FLAGS);
eelct++;
}
} else if (!rn2(4)) /* swamps tend to be moldy */
(void) makemon(mkclass(S_FUNGUS, 0), sx, sy,
NO_MM_FLAGS);
}
g.level.flags.has_swamp = 1;
}
}
static coord *
shrine_pos(roomno)
int roomno;
{
static coord buf;
int delta;
struct mkroom *troom = &g.rooms[roomno - ROOMOFFSET];
/* if width and height are odd, placement will be the exact center;
if either or both are even, center point is a hypothetical spot
between map locations and placement will be adjacent to that */
delta = troom->hx - troom->lx;
buf.x = troom->lx + delta / 2;
if ((delta % 2) && rn2(2))
buf.x++;
delta = troom->hy - troom->ly;
buf.y = troom->ly + delta / 2;
if ((delta % 2) && rn2(2))
buf.y++;
return &buf;
}
static void
mktemple()
{
register struct mkroom *sroom;
coord *shrine_spot;
register struct rm *lev;
if (!(sroom = pick_room(TRUE)))
return;
/* set up Priest and shrine */
sroom->rtype = TEMPLE;
/*
* In temples, shrines are blessed altars
* located in the center of the room
*/
shrine_spot = shrine_pos((int) ((sroom - g.rooms) + ROOMOFFSET));
lev = &levl[shrine_spot->x][shrine_spot->y];
lev->typ = ALTAR;
lev->altarmask = induced_align(80);
priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE);
lev->altarmask |= AM_SHRINE;
g.level.flags.has_temple = 1;
}
boolean
nexttodoor(sx, sy)
register int sx, sy;
{
register int dx, dy;
register struct rm *lev;
for (dx = -1; dx <= 1; dx++)
for (dy = -1; dy <= 1; dy++) {
if (!isok(sx + dx, sy + dy))
continue;
lev = &levl[sx + dx][sy + dy];
if (IS_DOOR(lev->typ) || lev->typ == SDOOR)
return TRUE;
}
return FALSE;
}
boolean
has_dnstairs(sroom)
register struct mkroom *sroom;
{
if (sroom == g.dnstairs_room)
return TRUE;
if (g.sstairs.sx && !g.sstairs.up)
return (boolean) (sroom == g.sstairs_room);
return FALSE;
}
boolean
has_upstairs(sroom)
register struct mkroom *sroom;
{
if (sroom == g.upstairs_room)
return TRUE;
if (g.sstairs.sx && g.sstairs.up)
return (boolean) (sroom == g.sstairs_room);
return FALSE;
}
int
somex(croom)
register struct mkroom *croom;
{
return rn1(croom->hx - croom->lx + 1, croom->lx);
}
int
somey(croom)
register struct mkroom *croom;
{
return rn1(croom->hy - croom->ly + 1, croom->ly);
}
boolean
inside_room(croom, x, y)
struct mkroom *croom;
xchar x, y;
{
if (croom->irregular) {
int i = (int) ((croom - g.rooms) + ROOMOFFSET);
return (!levl[x][y].edge && (int) levl[x][y].roomno == i);
}
return (boolean) (x >= croom->lx - 1 && x <= croom->hx + 1
&& y >= croom->ly - 1 && y <= croom->hy + 1);
}
boolean
somexy(croom, c)
struct mkroom *croom;
coord *c;
{
int try_cnt = 0;
int i;
if (croom->irregular) {
i = (int) ((croom - g.rooms) + ROOMOFFSET);
while (try_cnt++ < 100) {
c->x = somex(croom);
c->y = somey(croom);
if (!levl[c->x][c->y].edge && (int) levl[c->x][c->y].roomno == i)
return TRUE;
}
/* try harder; exhaustively search until one is found */
for (c->x = croom->lx; c->x <= croom->hx; c->x++)
for (c->y = croom->ly; c->y <= croom->hy; c->y++)
if (!levl[c->x][c->y].edge
&& (int) levl[c->x][c->y].roomno == i)
return TRUE;
return FALSE;
}
if (!croom->nsubrooms) {
c->x = somex(croom);
c->y = somey(croom);
return TRUE;
}
/* Check that coords doesn't fall into a subroom or into a wall */
while (try_cnt++ < 100) {
c->x = somex(croom);
c->y = somey(croom);
if (IS_WALL(levl[c->x][c->y].typ))
continue;
for (i = 0; i < croom->nsubrooms; i++)
if (inside_room(croom->sbrooms[i], c->x, c->y))
goto you_lose;
break;
you_lose:
;
}
if (try_cnt >= 100)
return FALSE;
return TRUE;
}
boolean
somexyspace(croom, c)
struct mkroom *croom;
coord *c;
{
int trycnt = 0;
boolean okay;
do {
okay = somexy(croom, c) && isok(c->x, c->y) && !occupied(c->x, c->y)
&& (levl[c->x][c->y].typ == ROOM
|| levl[c->x][c->y].typ == CORR
|| levl[c->x][c->y].typ == ICE);
} while (trycnt++ < 100 && !okay);
return okay;
}
/*
* Search for a special room given its type (zoo, court, etc...)
* Special values :
* - ANY_SHOP
* - ANY_TYPE
*/
struct mkroom *
search_special(type)
schar type;
{
register struct mkroom *croom;
for (croom = &g.rooms[0]; croom->hx >= 0; croom++)
if ((type == ANY_TYPE && croom->rtype != OROOM)
|| (type == ANY_SHOP && croom->rtype >= SHOPBASE)
|| croom->rtype == type)
return croom;
for (croom = &g.subrooms[0]; croom->hx >= 0; croom++)
if ((type == ANY_TYPE && croom->rtype != OROOM)
|| (type == ANY_SHOP && croom->rtype >= SHOPBASE)
|| croom->rtype == type)
return croom;
return (struct mkroom *) 0;
}
struct permonst *
courtmon()
{
int i = rn2(60) + rn2(3 * level_difficulty());
if (i > 100)
return mkclass(S_DRAGON, 0);
else if (i > 95)
return mkclass(S_GIANT, 0);
else if (i > 85)
return mkclass(S_TROLL, 0);
else if (i > 75)
return mkclass(S_CENTAUR, 0);
else if (i > 60)
return mkclass(S_ORC, 0);
else if (i > 45)
return &mons[PM_BUGBEAR];
else if (i > 30)
return &mons[PM_HOBGOBLIN];
else if (i > 15)
return mkclass(S_GNOME, 0);
else
return mkclass(S_KOBOLD, 0);
}
static const struct {
unsigned pm;
unsigned prob;
} squadprob[] = { { PM_SOLDIER, 80 },
{ PM_SERGEANT, 15 },
{ PM_LIEUTENANT, 4 },
{ PM_CAPTAIN, 1 } };
/* return soldier types. */
static struct permonst *
squadmon()
{
int sel_prob, i, cpro, mndx;
sel_prob = rnd(80 + level_difficulty());
cpro = 0;
for (i = 0; i < SIZE(squadprob); i++) {
cpro += squadprob[i].prob;
if (cpro > sel_prob) {
mndx = squadprob[i].pm;
goto gotone;
}
}
mndx = squadprob[rn2(SIZE(squadprob))].pm;
gotone:
if (!(g.mvitals[mndx].mvflags & G_GONE))
return &mons[mndx];
else
return (struct permonst *) 0;
}
/*
* save_room : A recursive function that saves a room and its subrooms
* (if any).
*/
static void
save_room(nhfp, r)
NHFILE *nhfp;
struct mkroom *r;
{
short i;
/*
* Well, I really should write only useful information instead
* of writing the whole structure. That is I should not write
* the g.subrooms pointers, but who cares ?
*/
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom));
for (i = 0; i < r->nsubrooms; i++) {
save_room(nhfp, r->sbrooms[i]);
}
}
/*
* save_rooms : Save all the rooms on disk!
*/
void
save_rooms(nhfp)
NHFILE *nhfp;
{
short i;
/* First, write the number of rooms */
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &g.nroom, sizeof(g.nroom));
for (i = 0; i < g.nroom; i++)
save_room(nhfp, &g.rooms[i]);
}
static void
rest_room(nhfp, r)
NHFILE *nhfp;
struct mkroom *r;
{
short i;
if (nhfp->structlevel)
mread(nhfp->fd, (genericptr_t) r, sizeof(struct mkroom));
for (i = 0; i < r->nsubrooms; i++) {
r->sbrooms[i] = &g.subrooms[g.nsubroom];
rest_room(nhfp, &g.subrooms[g.nsubroom]);
g.subrooms[g.nsubroom++].resident = (struct monst *) 0;
}
}
/*
* rest_rooms : That's for restoring rooms. Read the rooms structure from
* the disk.
*/
void
rest_rooms(nhfp)
NHFILE *nhfp;
{
short i;
if (nhfp->structlevel)
mread(nhfp->fd, (genericptr_t) &g.nroom, sizeof(g.nroom));
g.nsubroom = 0;
for (i = 0; i < g.nroom; i++) {
rest_room(nhfp, &g.rooms[i]);
g.rooms[i].resident = (struct monst *) 0;
}
g.rooms[g.nroom].hx = -1; /* restore ending flags */
g.subrooms[g.nsubroom].hx = -1;
}
/* convert a display symbol for terrain into topology type;
used for remembered terrain when mimics pose as furniture */
int
cmap_to_type(sym)
int sym;
{
int typ = STONE; /* catchall */
switch (sym) {
case S_stone:
typ = STONE;
break;
case S_vwall:
typ = VWALL;
break;
case S_hwall:
typ = HWALL;
break;
case S_tlcorn:
typ = TLCORNER;
break;
case S_trcorn:
typ = TRCORNER;
break;
case S_blcorn:
typ = BLCORNER;
break;
case S_brcorn:
typ = BRCORNER;
break;
case S_crwall:
typ = CROSSWALL;
break;
case S_tuwall:
typ = TUWALL;
break;
case S_tdwall:
typ = TDWALL;
break;
case S_tlwall:
typ = TLWALL;
break;
case S_trwall:
typ = TRWALL;
break;
case S_ndoor: /* no door (empty doorway) */
case S_vodoor: /* open door in vertical wall */
case S_hodoor: /* open door in horizontal wall */
case S_vcdoor: /* closed door in vertical wall */
case S_hcdoor:
typ = DOOR;
break;
case S_bars:
typ = IRONBARS;
break;
case S_tree:
typ = TREE;
break;
case S_room:
typ = ROOM;
break;
case S_corr:
case S_litcorr:
typ = CORR;
break;
case S_upstair:
case S_dnstair:
typ = STAIRS;
break;
case S_upladder:
case S_dnladder:
typ = LADDER;
break;
case S_altar:
typ = ALTAR;
break;
case S_grave:
typ = GRAVE;
break;
case S_throne:
typ = THRONE;
break;
case S_sink:
typ = SINK;
break;
case S_fountain:
typ = FOUNTAIN;
break;
case S_pool:
typ = POOL;
break;
case S_ice:
typ = ICE;
break;
case S_lava:
typ = LAVAPOOL;
break;
case S_vodbridge: /* open drawbridge spanning north/south */
case S_hodbridge:
typ = DRAWBRIDGE_DOWN;
break; /* east/west */
case S_vcdbridge: /* closed drawbridge in vertical wall */
case S_hcdbridge:
typ = DBWALL;
break;
case S_air:
typ = AIR;
break;
case S_cloud:
typ = CLOUD;
break;
case S_water:
typ = WATER;
break;
default:
break; /* not a cmap symbol? */
}
return typ;
}
/*mkroom.c*/