add an additional note to mextra.h and obj.h comments that reminds people to
appropriately init new fields if they need to initialize to something
other than zero
-
+rework stairs structure into a linked list
#define sokoend_level (g.dungeon_topology.d_sokoend_level)
/* clang-format on */
-#define xdnstair (g.dnstair.sx)
-#define ydnstair (g.dnstair.sy)
-#define xupstair (g.upstair.sx)
-#define yupstair (g.upstair.sy)
-
-#define xdnladder (g.dnladder.sx)
-#define ydnladder (g.dnladder.sy)
-#define xupladder (g.upladder.sx)
-#define yupladder (g.upladder.sy)
-
#define dunlev_reached(x) (g.dungeons[(x)->dnum].dunlev_ureached)
#include "quest.h"
int y_maze_max;
int otg_temp; /* used by object_to_glyph() [otg] */
int in_doagain;
- stairway dnstair; /* stairs down */
- stairway upstair; /* stairs up */
- stairway dnladder; /* ladder down */
- stairway upladder; /* ladder up */
+ stairway *stairs;
int smeq[MAXNROFROOMS + 1];
int doorindex;
char *save_cm;
number of shots, index of current one, validity check, shoot vs throw */
struct multishot m_shot;
dungeon dungeons[MAXDUNGEON]; /* ini'ed by init_dungeon() */
- stairway sstairs;
dest_area updest;
dest_area dndest;
coord inv_pos;
boolean mrg_to_wielded; /* weapon picked is merged with wielded one */
struct plinemsg_type *plinemsg_types;
char toplines[TBUFSZ];
- struct mkroom *upstairs_room;
- struct mkroom *dnstairs_room;
- struct mkroom *sstairs_room;
coord bhitpos; /* place where throw or zap hits or stops */
boolean in_steed_dismounting;
coord doors[DOORMAX];
typedef struct stairway { /* basic stairway identifier */
xchar sx, sy; /* x / y location of the stair */
d_level tolev; /* where does it go */
- char up; /* what type of stairway (up/down) */
+ boolean up; /* up or down? */
+ boolean isladder; /* ladder or stairway? */
+ struct stairway *next;
} stairway;
/* level region types */
E void FDECL(prev_level, (BOOLEAN_P));
E void FDECL(u_on_newpos, (int, int));
E void FDECL(u_on_rndspot, (int));
+E void FDECL(stairway_add, (int,int, BOOLEAN_P, BOOLEAN_P, d_level *));
+E void NDECL(stairway_print);
+E void NDECL(stairway_free_all);
+E stairway *FDECL(stairway_at, (int, int));
+E stairway *FDECL(stairway_find, (d_level *));
+E stairway *FDECL(stairway_find_from, (d_level *, BOOLEAN_P));
+E stairway *FDECL(stairway_find_dir, (BOOLEAN_P));
+E stairway *FDECL(stairway_find_type_dir, (BOOLEAN_P, BOOLEAN_P));
+E stairway *FDECL(stairway_find_special_dir, (BOOLEAN_P));
E void FDECL(u_on_sstairs, (int));
E void NDECL(u_on_upstairs);
E void NDECL(u_on_dnstairs);
xchar mx, my;
xchar mux, muy; /* where the monster thinks you are */
#define MTSZ 4
+ /* mtrack[0..2] is used to keep extra data when migrating the monster */
coord mtrack[MTSZ]; /* monster track */
int mhp, mhpmax;
unsigned mappearance; /* for undetected mimics and the wiz */
long age; /* creation date */
long owornmask;
unsigned lua_ref_cnt; /* # of lua script references for this object */
+ xchar omigr_from_dnum; /* where obj is migrating from */
+ xchar omigr_from_dlevel; /* where obj is migrating from */
struct oextra *oextra; /* pointer to oextra struct */
};
* Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files.
*/
-#define EDITLEVEL 24
+#define EDITLEVEL 25
/*
* Development status possibilities.
#define is_cmap_furniture(i) ((i) >= S_upstair && (i) <= S_fountain)
#define is_cmap_water(i) ((i) == S_pool || (i) == S_water)
#define is_cmap_lava(i) ((i) == S_lava)
+#define is_cmap_stairs(i) ((i) == S_upstair || (i) == S_dnstair || \
+ (i) == S_upladder || (i) == S_dnladder)
struct symdef {
{
static char pbar[COLNO];
char *p;
+ stairway *stway = g.stairs;
p = pbar;
- /* up stairway */
- if (g.upstair.sx
- && (glyph_to_cmap(g.level.locations[g.upstair.sx][g.upstair.sy].glyph)
- == S_upstair
- || glyph_to_cmap(g.level.locations[g.upstair.sx][g.upstair.sy].glyph)
- == S_upladder)) {
- *p++ = '<';
- *p++ = g.upstair.sx;
- }
- if (g.sstairs.sx
- && (glyph_to_cmap(g.level.locations[g.sstairs.sx][g.sstairs.sy].glyph)
- == S_upstair
- || glyph_to_cmap(g.level.locations[g.sstairs.sx][g.sstairs.sy].glyph)
- == S_upladder)) {
- *p++ = '<';
- *p++ = g.sstairs.sx;
- }
-
- /* down stairway */
- if (g.dnstair.sx
- && (glyph_to_cmap(g.level.locations[g.dnstair.sx][g.dnstair.sy].glyph)
- == S_dnstair
- || glyph_to_cmap(g.level.locations[g.dnstair.sx][g.dnstair.sy].glyph)
- == S_dnladder)) {
- *p++ = '>';
- *p++ = g.dnstair.sx;
- }
- if (g.sstairs.sx
- && (glyph_to_cmap(g.level.locations[g.sstairs.sx][g.sstairs.sy].glyph)
- == S_dnstair
- || glyph_to_cmap(g.level.locations[g.sstairs.sx][g.sstairs.sy].glyph)
- == S_dnladder)) {
- *p++ = '>';
- *p++ = g.sstairs.sx;
- }
+ /* TODO: use the same method as getpos() so objects don't cover stairs */
+ while (stway) {
+ int x = stway->sx;
+ int y = stway->sy;
+ int glyph = glyph_to_cmap(g.level.locations[x][y].glyph);
+
+ if (is_cmap_stairs(glyph)) {
+ *p++ = (stway->up ? '<' : '>');
+ *p++ = stway->sx;
+ }
+ stway = stway->next;
+ }
/* hero location */
if (u.ux) {
what = "in water";
else if (is_lava(u.ux, u.uy))
what = "in lava";
- else if (On_stairs(u.ux, u.uy))
- what = (u.ux == xdnladder || u.ux == xupladder) ? "on the ladder"
- : "on the stairs";
- else if (IS_FURNITURE(levtyp) || IS_ROCK(levtyp)
+ else if (On_stairs(u.ux, u.uy)) {
+ stairway *stway = stairway_at(u.ux, u.uy);
+ what = stway->isladder ? "on the ladder" : "on the stairs";
+ } else if (IS_FURNITURE(levtyp) || IS_ROCK(levtyp)
|| closed_door(u.ux, u.uy) || t_at(u.ux, u.uy))
what = "here";
else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
schar typ = levl[u.ux][u.uy].typ;
int npick;
menu_item *picks = (menu_item *) 0;
+ stairway *stway = stairway_at(u.ux, u.uy);
win = create_nhwindow(NHW_MENU);
start_menu(win, MENU_BEHAVE_STANDARD);
add_herecmd_menuitem(win, dosit,
"Sit on the throne");
- if (On_stairs_up(u.ux, u.uy)) {
+ if (stway && stway->up) {
Sprintf(buf, "Go up the %s",
- (u.ux == xupladder && u.uy == yupladder)
- ? "ladder" : "stairs");
+ stway->isladder ? "ladder" : "stairs");
add_herecmd_menuitem(win, doup, buf);
}
- if (On_stairs_dn(u.ux, u.uy)) {
+ if (stway && !stway->up) {
Sprintf(buf, "Go down the %s",
- (u.ux == xupladder && u.uy == yupladder)
- ? "ladder" : "stairs");
+ stway->isladder ? "ladder" : "stairs");
add_herecmd_menuitem(win, dodown, buf);
}
if (u.usteed) { /* another movement choice */
(ROWNO - 1) & ~1, /* y_maze_max */
UNDEFINED_VALUE, /* otg_temp */
0, /* in_doagain */
- DUMMY, /* dnstair */
- DUMMY, /* upstair */
- DUMMY, /* dnladder */
- DUMMY, /* upladder */
+ NULL, /* stairs */
DUMMY, /* smeq */
0, /* doorindex */
NULL, /* save_cm */
UNDEFINED_PTR, /* sp_levchn */
{ 0, 0, STRANGE_OBJECT, FALSE }, /* m_shot */
UNDEFINED_VALUES, /* dungeons */
- { 0, 0, { 0, 0 }, 0 }, /* sstairs */
{ 0, 0, 0, 0, 0, 0, 0, 0 }, /* updest */
{ 0, 0, 0, 0, 0, 0, 0, 0 }, /* dndest */
{ 0, 0} , /* inv_pos */
FALSE, /* mrg_to_wielded */
NULL, /* plinemsg_types */
UNDEFINED_VALUES, /* toplines */
- UNDEFINED_PTR, /* upstairs_room */
- UNDEFINED_PTR, /* dnstairs_room */
- UNDEFINED_PTR, /* sstairs_room */
DUMMY, /* bhitpos */
FALSE, /* in_steed_dismounting */
DUMMY, /* doors */
(madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in";
if (On_stairs(x, y)) {
- if (x == xdnladder || x == xupladder) {
+ stairway *stway = stairway_at(x, y);
+ if (stway->isladder) {
if (verbose)
pline_The("ladder resists your effort.");
} else if (verbose)
if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater) {
if (u.dz < 0 || On_stairs(u.ux, u.uy)) {
int dmg;
- if (On_stairs(u.ux, u.uy))
+ if (On_stairs(u.ux, u.uy)) {
+ stairway *stway = stairway_at(u.ux, u.uy);
pline_The("beam bounces off the %s and hits the %s.",
- (u.ux == xdnladder || u.ux == xupladder)
- ? "ladder"
- : "stairs",
+ stway->isladder ? "ladder" : "stairs",
ceiling(u.ux, u.uy));
+ }
You("loosen a rock from the %s.", ceiling(u.ux, u.uy));
pline("It falls on your %s!", body_part(HEAD));
dmg = rnd((uarmh && is_metallic(uarmh)) ? 2 : 6);
dodown()
{
struct trap *trap = 0;
- boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair)
- || (u.ux == g.sstairs.sx && u.uy == g.sstairs.sy
- && !g.sstairs.up)),
- ladder_down = (u.ux == xdnladder && u.uy == ydnladder);
+ stairway *stway = stairway_at(u.ux, u.uy);
+ boolean stairs_down = (stway && !stway->up && !stway->isladder),
+ ladder_down = (stway && !stway->up && stway->isladder);
if (u_rooted())
return 1;
int
doup()
{
+ stairway *stway = stairway_at(u.ux,u.uy);
+
if (u_rooted())
return 1;
return 1;
}
- if ((u.ux != xupstair || u.uy != yupstair)
- && (!xupladder || u.ux != xupladder || u.uy != yupladder)
- && (!g.sstairs.sx || u.ux != g.sstairs.sx || u.uy != g.sstairs.sy
- || !g.sstairs.up)) {
+ if (!stway || (stway && !stway->up)) {
You_cant("go up here.");
return 0;
}
dunlev_reached(&u.uz) = dunlev(&u.uz);
}
+ stairway_free_all();
/* set default level change destination areas */
/* the special level code may override these */
(void) memset((genericptr_t) &g.updest, 0, sizeof g.updest);
}
} else if (at_stairs && !In_endgame(&u.uz)) {
if (up) {
- if (g.at_ladder)
- u_on_newpos(xdnladder, ydnladder);
+ stairway *stway = stairway_find_from(&u.uz0, g.at_ladder);
+ if (stway)
+ u_on_newpos(stway->sx, stway->sy);
else if (newdungeon)
u_on_sstairs(1);
else
(Flying && g.at_ladder) ? " along" : "",
g.at_ladder ? "ladder" : "stairs");
} else { /* down */
- if (g.at_ladder)
- u_on_newpos(xupladder, yupladder);
+ stairway *stway = stairway_find_from(&u.uz0, g.at_ladder);
+ if (stway)
+ u_on_newpos(stway->sx, stway->sy);
else if (newdungeon)
u_on_sstairs(0);
else
xchar xlocale, ylocale, xyloc, xyflags, wander;
int num_segs;
boolean failed_to_place = FALSE;
+ stairway *stway;
+ d_level fromdlev;
mtmp->nmon = fmon;
fmon = mtmp;
xyflags = mtmp->mtrack[0].y;
xlocale = mtmp->mtrack[1].x;
ylocale = mtmp->mtrack[1].y;
+ fromdlev.dnum = mtmp->mtrack[2].x;
+ fromdlev.dlevel = mtmp->mtrack[2].y;
memset(mtmp->mtrack, 0, sizeof mtmp->mtrack);
if (mtmp == u.usteed)
xlocale = u.ux, ylocale = u.uy;
break;
case MIGR_STAIRS_UP:
- xlocale = xupstair, ylocale = yupstair;
+ if ((stway = stairway_find_from(&fromdlev, FALSE)) != 0) {
+ xlocale = stway->sx;
+ ylocale = stway->sy;
+ }
break;
case MIGR_STAIRS_DOWN:
- xlocale = xdnstair, ylocale = ydnstair;
+ if ((stway = stairway_find_from(&fromdlev, FALSE)) != 0) {
+ xlocale = stway->sx;
+ ylocale = stway->sy;
+ }
break;
case MIGR_LADDER_UP:
- xlocale = xupladder, ylocale = yupladder;
+ if ((stway = stairway_find_from(&fromdlev, TRUE)) != 0) {
+ xlocale = stway->sx;
+ ylocale = stway->sy;
+ }
break;
case MIGR_LADDER_DOWN:
- xlocale = xdnladder, ylocale = ydnladder;
+ if ((stway = stairway_find_from(&fromdlev, TRUE)) != 0) {
+ xlocale = stway->sx;
+ ylocale = stway->sy;
+ }
break;
case MIGR_SSTAIRS:
- xlocale = g.sstairs.sx, ylocale = g.sstairs.sy;
+ if ((stway = stairway_find(&fromdlev)) != 0) {
+ xlocale = stway->sx;
+ ylocale = stway->sy;
+ }
break;
case MIGR_PORTAL:
if (In_endgame(&u.uz)) {
xyflags |= 2;
mtmp->wormno = num_segs;
mtmp->mlstmv = g.monstermoves;
+ mtmp->mtrack[2].x = u.uz.dnum; /* migrating from this dungeon */
+ mtmp->mtrack[2].y = u.uz.dlevel; /* migrating from this dungeon level */
mtmp->mtrack[1].x = cc ? cc->x : mtmp->mx;
mtmp->mtrack[1].y = cc ? cc->y : mtmp->my;
mtmp->mtrack[0].x = xyloc;
static int FDECL(really_kick_object, (XCHAR_P, XCHAR_P));
static char *FDECL(kickstr, (char *, const char *));
static void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long));
-static void FDECL(drop_to, (coord *, SCHAR_P));
+static void FDECL(drop_to, (coord *, SCHAR_P, XCHAR_P, XCHAR_P));
static const char kick_passes_thru[] = "kick passes harmlessly through";
}
static void
-drop_to(cc, loc)
+drop_to(cc, loc, x,y)
coord *cc;
schar loc;
+xchar x,y;
{
+ stairway *stway = stairway_at(x, y);
+
/* cover all the MIGR_xxx choices generated by down_gate() */
switch (loc) {
case MIGR_RANDOM: /* trap door or hole */
/*FALLTHRU*/
case MIGR_STAIRS_UP:
case MIGR_LADDER_UP:
- cc->x = u.uz.dnum;
- cc->y = u.uz.dlevel + 1;
- break;
case MIGR_SSTAIRS:
- cc->x = g.sstairs.tolev.dnum;
- cc->y = g.sstairs.tolev.dlevel;
+ if (stway) {
+ cc->x = stway->tolev.dnum;
+ cc->y = stway->tolev.dlevel;
+ } else {
+ cc->x = u.uz.dnum;
+ cc->y = u.uz.dlevel + 1;
+ }
break;
default:
case MIGR_NOWHERE:
return;
toloc = down_gate(x, y);
- drop_to(&cc, toloc);
+ drop_to(&cc, toloc, x, y);
if (!cc.y)
return;
return FALSE;
if ((toloc = down_gate(x, y)) == MIGR_NOWHERE)
return FALSE;
- drop_to(&cc, toloc);
+ drop_to(&cc, toloc, x, y);
if (!cc.y)
return FALSE;
otmp->ox = cc.x;
otmp->oy = cc.y;
otmp->owornmask = (long) toloc;
+
/* boulder from rolling boulder trap, no longer part of the trap */
if (otmp->otyp == BOULDER)
otmp->otrapped = 0;
register int nx, ny;
int where;
boolean nobreak, noscatter;
+ stairway *stway;
+ d_level fromdlev;
+ boolean isladder;
for (otmp = g.migrating_objs; otmp; otmp = otmp2) {
otmp2 = otmp->nobj;
obj_extract_self(otmp);
otmp->owornmask = 0L;
+ fromdlev.dnum = otmp->omigr_from_dnum;
+ fromdlev.dlevel = otmp->omigr_from_dlevel;
+
+ isladder = FALSE;
switch (where) {
- case MIGR_STAIRS_UP:
- nx = xupstair, ny = yupstair;
- break;
case MIGR_LADDER_UP:
- nx = xupladder, ny = yupladder;
- break;
+ isladder = TRUE;
+ case MIGR_STAIRS_UP:
case MIGR_SSTAIRS:
- nx = g.sstairs.sx, ny = g.sstairs.sy;
+ if ((stway = stairway_find_from(&fromdlev, isladder)) != 0) {
+ nx = stway->sx;
+ nx = stway->sy;
+ }
+ break;
break;
case MIGR_WITH_HERO:
nx = u.ux, ny = u.uy;
nx = ny = 0;
break;
}
+ otmp->omigr_from_dnum = 0;
+ otmp->omigr_from_dlevel = 0;
if (nx > 0) {
place_object(otmp, nx, ny);
if (!nobreak && !IS_SOFT(levl[nx][ny].typ)) {
free_oname(otmp);
}
otmp->migr_species = NON_PM;
+ otmp->omigr_from_dnum = 0;
+ otmp->omigr_from_dlevel = 0;
(void) add_to_minv(mtmp, otmp);
cnt++;
if (maxobj && cnt >= maxobj)
xchar x, y;
{
struct trap *ttmp;
+ stairway *stway = stairway_at(x, y);
g.gate_str = 0;
/* this matches the player restriction in goto_level() */
if (on_level(&u.uz, &qstart_level) && !ok_to_quest())
return MIGR_NOWHERE;
- if ((xdnstair == x && ydnstair == y)
- || (g.sstairs.sx == x && g.sstairs.sy == y && !g.sstairs.up)) {
+ if (stway && !stway->up && !stway->isladder) {
g.gate_str = "down the stairs";
- return (xdnstair == x && ydnstair == y) ? MIGR_STAIRS_UP
- : MIGR_SSTAIRS;
+ return (stway->tolev.dnum == u.uz.dnum) ? MIGR_STAIRS_UP
+ : MIGR_SSTAIRS;
}
- if (xdnladder == x && ydnladder == y) {
+ if (stway && !stway->up && stway->isladder) {
g.gate_str = "down the ladder";
return MIGR_LADDER_UP;
}
next_level(at_stairs)
boolean at_stairs;
{
- if (at_stairs && u.ux == g.sstairs.sx && u.uy == g.sstairs.sy) {
- /* Taking a down dungeon branch. */
- goto_level(&g.sstairs.tolev, at_stairs, FALSE, FALSE);
- } else {
- /* Going down a stairs or jump in a trap door. */
- d_level newlevel;
+ stairway *stway = stairway_at(u.ux, u.uy);
+ d_level newlevel;
+ if (at_stairs && stway) {
+ newlevel.dnum = stway->tolev.dnum;
+ newlevel.dlevel = stway->tolev.dlevel;
+ goto_level(&newlevel, at_stairs, FALSE, FALSE);
+ } else {
newlevel.dnum = u.uz.dnum;
newlevel.dlevel = u.uz.dlevel + 1;
goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
prev_level(at_stairs)
boolean at_stairs;
{
- if (at_stairs && u.ux == g.sstairs.sx && u.uy == g.sstairs.sy) {
+ stairway *stway = stairway_at(u.ux, u.uy);
+ d_level newlevel;
+
+ if (at_stairs && stway && stway->tolev.dnum != u.uz.dnum) {
/* Taking an up dungeon branch. */
/* KMH -- Upwards branches are okay if not level 1 */
/* (Just make sure it doesn't go above depth 1) */
if (!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet)
done(ESCAPED);
- else
- goto_level(&g.sstairs.tolev, at_stairs, FALSE, FALSE);
+ else {
+ newlevel.dnum = stway->tolev.dnum;
+ newlevel.dlevel = stway->tolev.dlevel;
+ goto_level(&newlevel, at_stairs, FALSE, FALSE);
+ }
} else {
/* Going up a stairs or rising through the ceiling. */
- d_level newlevel;
newlevel.dnum = u.uz.dnum;
newlevel.dlevel = u.uz.dlevel - 1;
goto_level(&newlevel, at_stairs, FALSE, FALSE);
switch_terrain();
}
+void
+stairway_add(x,y, up, ladder, dest)
+int x,y;
+boolean up, ladder;
+d_level *dest;
+{
+ stairway *tmp = (stairway *)alloc(sizeof(stairway));
+
+ tmp->sx = x;
+ tmp->sy = y;
+ tmp->up = up;
+ tmp->isladder = ladder;
+ assign_level(&(tmp->tolev), dest);
+ tmp->next = g.stairs;
+ g.stairs = tmp;
+}
+
+void
+stairway_free_all()
+{
+ stairway *tmp = g.stairs;
+
+ while (tmp) {
+ stairway *tmp2 = tmp->next;
+ free(tmp);
+ tmp = tmp2;
+ }
+ g.stairs = NULL;
+}
+
+stairway *
+stairway_at(x,y)
+int x,y;
+{
+ stairway *tmp = g.stairs;
+
+ while (tmp && !(tmp->sx == x && tmp->sy == y))
+ tmp = tmp->next;
+
+ return tmp;
+}
+
+stairway *
+stairway_find(fromdlev)
+d_level *fromdlev;
+{
+ stairway *tmp = g.stairs;
+
+ while (tmp) {
+ if (tmp->tolev.dnum == fromdlev->dnum
+ && tmp->tolev.dlevel == fromdlev->dlevel)
+ return tmp;
+ tmp = tmp->next;
+ }
+
+ return tmp;
+}
+
+stairway *
+stairway_find_from(fromdlev, ladder)
+d_level *fromdlev;
+boolean ladder;
+{
+ stairway *tmp = g.stairs;
+
+ while (tmp) {
+ if (tmp->tolev.dnum == fromdlev->dnum
+ && tmp->tolev.dlevel == fromdlev->dlevel
+ && tmp->isladder == ladder)
+ return tmp;
+ tmp = tmp->next;
+ }
+
+ return tmp;
+}
+
+stairway *
+stairway_find_dir(up)
+boolean up;
+{
+ stairway *tmp = g.stairs;
+
+ while (tmp && !(tmp->up == up))
+ tmp = tmp->next;
+
+ return tmp;
+}
+
+stairway *
+stairway_find_ladder()
+{
+ stairway *tmp = g.stairs;
+
+ while (tmp && !tmp->isladder)
+ tmp = tmp->next;
+
+ return tmp;
+}
+
+stairway *
+stairway_find_type_dir(ladder,up)
+boolean ladder, up;
+{
+ stairway *tmp = g.stairs;
+
+ while (tmp && !(tmp->isladder == ladder && tmp->up == up))
+ tmp = tmp->next;
+
+ return tmp;
+}
+
+stairway *
+stairway_find_special_dir(up)
+boolean up;
+{
+ stairway *tmp = g.stairs;
+
+ while (tmp) {
+ if (tmp->tolev.dnum != u.uz.dnum && tmp->up != up)
+ return tmp;
+ tmp = tmp->next;
+ }
+
+ return tmp;
+}
+
/* place you on the special staircase */
void
u_on_sstairs(upflag)
int upflag;
{
- if (g.sstairs.sx)
- u_on_newpos(g.sstairs.sx, g.sstairs.sy);
+ stairway *stway = stairway_find_special_dir(upflag);
+
+ if (stway)
+ u_on_newpos(stway->sx, stway->sy);
else
u_on_rndspot(upflag);
}
void
u_on_upstairs()
{
- if (xupstair)
- u_on_newpos(xupstair, yupstair);
+ stairway *stway = stairway_find_dir(TRUE);
+
+ if (stway)
+ u_on_newpos(stway->sx, stway->sy);
else
u_on_sstairs(0); /* destination upstairs implies moving down */
}
void
u_on_dnstairs()
{
- if (xdnstair)
- u_on_newpos(xdnstair, ydnstair);
+ stairway *stway = stairway_find_dir(FALSE);
+
+ if (stway)
+ u_on_newpos(stway->sx, stway->sy);
else
u_on_sstairs(1); /* destination dnstairs implies moving up */
}
On_stairs(x, y)
xchar x, y;
{
- return (boolean) ((x == xupstair && y == yupstair)
- || (x == xdnstair && y == ydnstair)
- || (x == xdnladder && y == ydnladder)
- || (x == xupladder && y == yupladder)
- || (x == g.sstairs.sx && y == g.sstairs.sy));
+ return (stairway_at(x,y) != NULL);
}
boolean
On_ladder(x, y)
xchar x, y;
{
- return (boolean) ((x == xdnladder && y == ydnladder)
- || (x == xupladder && y == yupladder));
+ stairway *stway = stairway_at(x,y);
+
+ return (boolean) (stway && stway->isladder);
}
boolean
On_stairs_up(x, y)
xchar x, y;
{
- return ((x == xupstair && y == yupstair)
- || (x == g.sstairs.sx && y == g.sstairs.sy && g.sstairs.up)
- || (x == xupladder && y == yupladder));
+ stairway *stway = stairway_at(x,y);
+
+ return (boolean) (stway && stway->up);
}
boolean
On_stairs_dn(x, y)
xchar x, y;
{
- return ((x == xdnstair && y == ydnstair)
- || (x == g.sstairs.sx && y == g.sstairs.sy && !g.sstairs.up)
- || (x == xdnladder && y == ydnladder));
+ stairway *stway = stairway_at(x,y);
+
+ return (boolean) (stway && !stway->up);
}
boolean
int x, y;
d_level *lev;
{
+ stairway *stway = stairway_find_special_dir(FALSE);
+
/* can't rise up from inside the top of the Wizard's tower */
/* KMH -- or in sokoban */
if (In_endgame(lev) || In_sokoban(lev)
return (boolean) (lev->dlevel > 1
|| (g.dungeons[lev->dnum].entry_lev == 1
&& ledger_no(lev) != 1
- && g.sstairs.sx && g.sstairs.up));
+ && stway && stway->up));
}
boolean
int ltyp = lev->typ, cmap = -1;
const char *dfeature = 0;
static char altbuf[BUFSZ];
+ stairway *stway = stairway_at(x,y);
if (IS_DOOR(ltyp)) {
switch (lev->doormask) {
a_gname(),
align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
dfeature = altbuf;
- } else if ((x == xupstair && y == yupstair)
- || (x == g.sstairs.sx && y == g.sstairs.sy && g.sstairs.up))
+ } else if (stway && !stway->isladder && stway->up)
cmap = S_upstair; /* "staircase up" */
- else if ((x == xdnstair && y == ydnstair)
- || (x == g.sstairs.sx && y == g.sstairs.sy && !g.sstairs.up))
+ else if (stway && !stway->isladder && !stway->up)
cmap = S_dnstair; /* "staircase down" */
- else if (x == xupladder && y == yupladder)
+ else if (stway && stway->isladder && stway->up)
cmap = S_upladder; /* "ladder up" */
- else if (x == xdnladder && y == ydnladder)
+ else if (stway && stway->isladder && !stway->up)
cmap = S_dnladder; /* "ladder down" */
else if (ltyp == DRAWBRIDGE_DOWN)
cmap = S_vodbridge; /* "lowered drawbridge" */
int lax; /* if TRUE, pick a position in sight. */
int dd; /* distance to current point */
int max_distance; /* max distance found so far */
+ stairway *stway = g.stairs;
/*
* If blind and not telepathic, then it doesn't matter what we pick ---
* Arrive at an up or down stairwell if it is in line of sight from the
* hero.
*/
- if (couldsee(g.upstair.sx, g.upstair.sy)) {
- startp->x = g.upstair.sx;
- startp->y = g.upstair.sy;
- return TRUE;
- }
- if (couldsee(g.dnstair.sx, g.dnstair.sy)) {
- startp->x = g.dnstair.sx;
- startp->y = g.dnstair.sy;
- return TRUE;
+ while (stway) {
+ if (stway->tolev.dnum == u.uz.dnum && couldsee(stway->sx, stway->sy)) {
+ startp->x = stway->sx;
+ startp->y = stway->sy;
+ return TRUE;
+ }
+ stway = stway->next;
}
/*
goto gotgood;
}
if (bl == 0 && (!mon || mon->data->mmove)) {
+ stairway *stway = g.stairs;
/* all map positions are visible (or not good),
try to pick something logical */
- if (g.dnstair.sx && !rn2(2)) {
- nx = g.dnstair.sx;
- ny = g.dnstair.sy;
- } else if (g.upstair.sx && !rn2(2)) {
- nx = g.upstair.sx;
- ny = g.upstair.sy;
- } else if (g.dnladder.sx && !rn2(2)) {
- nx = g.dnladder.sx;
- ny = g.dnladder.sy;
- } else if (g.upladder.sx && !rn2(2)) {
- nx = g.upladder.sx;
- ny = g.upladder.sy;
+ while (stway) {
+ if (stway->tolev.dnum == u.uz.dnum && !rn2(2)) {
+ nx = stway->sx;
+ ny = stway->sy;
+ break;
+ }
+ stway = stway->next;
}
if (goodpos(nx, ny, mon, gpflags))
goto gotgood;
g.doorindex = 0;
init_rect();
init_vault();
- xdnstair = ydnstair = xupstair = yupstair = 0;
- g.sstairs.sx = g.sstairs.sy = 0;
- xdnladder = ydnladder = xupladder = yupladder = 0;
- g.dnstairs_room = g.upstairs_room = g.sstairs_room = (struct mkroom *) 0;
+ stairway_free_all();
g.made_branch = FALSE;
clear_regions();
g.xstart = 1;
for (ridx = 0; ridx < SIZE(g.rooms); ridx++)
g.rooms[ridx].orig_rtype = g.rooms[ridx].rtype;
- /* something like this usually belongs in clear_level_structures()
- but these aren't saved and restored so might not retain their
- values for the life of the current level; reset them to default
- now so that they never do and no one will be tempted to introduce
- a new use of them for anything on this level */
- g.dnstairs_room = g.upstairs_room = g.sstairs_room = (struct mkroom *) 0;
-
reseed_random(rn2);
reseed_random(rn2_on_display_rng);
}
if (br->type == BR_PORTAL) {
mkportal(x, y, dest->dnum, dest->dlevel);
} else if (make_stairs) {
- g.sstairs.sx = x;
- g.sstairs.sy = y;
- g.sstairs.up =
- (char) on_level(&br->end1, &u.uz) ? br->end1_up : !br->end1_up;
- assign_level(&g.sstairs.tolev, dest);
- g.sstairs_room = br_room;
-
- levl[x][y].ladder = g.sstairs.up ? LA_UP : LA_DOWN;
+ boolean goes_up = on_level(&br->end1, &u.uz) ? br->end1_up : !br->end1_up;
+
+ stairway_add(x,y, goes_up, FALSE, dest);
+ levl[x][y].ladder = goes_up ? LA_UP : LA_DOWN;
levl[x][y].typ = STAIRS;
}
/*
return;
if (up) {
- xupstair = x;
- yupstair = y;
- g.upstairs_room = croom;
+ d_level dest;
+
+ dest.dnum = u.uz.dnum;
+ dest.dlevel = u.uz.dlevel - 1;
+ stairway_add(x,y, TRUE, FALSE, &dest);
} else {
- xdnstair = x;
- ydnstair = y;
- g.dnstairs_room = croom;
+ d_level dest;
+
+ dest.dnum = u.uz.dnum;
+ dest.dlevel = u.uz.dlevel + 1;
+ stairway_add(x,y, FALSE, FALSE, &dest);
}
levl[x][y].typ = STAIRS;
int phase;
{
return (croom && (croom->needjoining || (phase < 0))
- && ((croom != g.dnstairs_room && croom != g.upstairs_room)
+ && ((!has_dnstairs(croom) && !has_upstairs(croom))
|| phase < 1)
&& (croom->rtype == OROOM
|| ((phase < 2) && croom->rtype == THEMEROOM)));
mazexy(&mm);
mkstairs(mm.x, mm.y, 0, (struct mkroom *) 0); /* down */
} else { /* choose "vibrating square" location */
+ stairway *stway;
int trycnt = 0;
#define x_maze_min 2
#define y_maze_min 2
to be on a spot that's already in use (wall|trap) */
if (++trycnt > 1000)
break;
- } while (x == xupstair || y == yupstair /*(direct line)*/
- || abs(x - xupstair) == abs(y - yupstair)
- || distmin(x, y, xupstair, yupstair) <= INVPOS_DISTANCE
- || !SPACE_POS(levl[x][y].typ) || occupied(x, y));
+ } while (((stway = stairway_find_dir(TRUE)) != 0)
+ && (x == stway->sx || y == stway->sy /*(direct line)*/
+ || abs(x - stway->sx) == abs(y - stway->sy)
+ || distmin(x, y, stway->sx, stway->sy) <= INVPOS_DISTANCE
+ || !SPACE_POS(levl[x][y].typ) || occupied(x, y)));
g.inv_pos.x = x;
g.inv_pos.y = y;
maketrap(g.inv_pos.x, g.inv_pos.y, VIBRATING_SQUARE);
obj->where = OBJ_MIGRATING;
obj->nobj = g.migrating_objs;
+ obj->omigr_from_dnum = u.uz.dnum;
+ obj->omigr_from_dlevel = u.uz.dlevel;
g.migrating_objs = obj;
}
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);
+ stairway *stway = g.stairs;
+
+ while (stway) {
+ if (!stway->up && inside_room(sroom, stway->sx, stway->sy))
+ return TRUE;
+ stway = stway->next;
+ }
return FALSE;
}
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);
+ stairway *stway = g.stairs;
+
+ while (stway) {
+ if (stway->up && inside_room(sroom, stway->sx, stway->sy))
+ return TRUE;
+ stway = stway->next;
+ }
return FALSE;
}
#endif
if (mtmp->data->mlet == S_KOP) {
+ stairway *stway = stairway_find_type_dir(FALSE, FALSE);
+
/* Dead Kops may come back. */
switch (rnd(5)) {
case 1: /* returns near the stairs */
- (void) makemon(mtmp->data, xdnstair, ydnstair, NO_MM_FLAGS);
- break;
+ if (stway) {
+ (void) makemon(mtmp->data, stway->sx, stway->sy, NO_MM_FLAGS);
+ break;
+ }
case 2: /* randomly */
(void) makemon(mtmp->data, 0, 0, NO_MM_FLAGS);
break;
int fraction, x = mtmp->mx, y = mtmp->my;
boolean stuck = (mtmp == u.ustuck),
immobile = (mtmp->data->mmove == 0);
+ stairway *stway;
if (is_animal(mtmp->data) || mindless(mtmp->data))
return FALSE;
if (stuck || immobile) {
; /* fleeing by stairs or traps is not possible */
} else if (levl[x][y].typ == STAIRS) {
- if (x == xdnstair && y == ydnstair) {
+ stway = stairway_at(x,y);
+ if (stway && !stway->up && stway->tolev.dnum == u.uz.dnum) {
if (!is_floater(mtmp->data))
g.m.has_defense = MUSE_DOWNSTAIRS;
- } else if (x == xupstair && y == yupstair) {
+ } else if (stway && stway->up && stway->tolev.dnum == u.uz.dnum) {
g.m.has_defense = MUSE_UPSTAIRS;
- } else if (g.sstairs.sx && x == g.sstairs.sx && y == g.sstairs.sy) {
- if (g.sstairs.up || !is_floater(mtmp->data))
+ } else if (stway && stway->tolev.dnum != u.uz.dnum) {
+ if (stway->up || !is_floater(mtmp->data))
g.m.has_defense = MUSE_SSTAIRS;
}
} else if (levl[x][y].typ == LADDER) {
- if (x == xupladder && y == yupladder) {
+ stway = stairway_at(x,y);
+ if (stway && stway->up && stway->tolev.dnum == u.uz.dnum) {
g.m.has_defense = MUSE_UP_LADDER;
- } else if (x == xdnladder && y == ydnladder) {
+ } else if (stway && !stway->up && stway->tolev.dnum == u.uz.dnum) {
if (!is_floater(mtmp->data))
g.m.has_defense = MUSE_DN_LADDER;
- } else if (g.sstairs.sx && x == g.sstairs.sx && y == g.sstairs.sy) {
- if (g.sstairs.up || !is_floater(mtmp->data))
+ } else if (stway && stway->tolev.dnum != u.uz.dnum) {
+ if (stway->up || !is_floater(mtmp->data))
g.m.has_defense = MUSE_SSTAIRS;
}
} else {
struct obj *otmp = g.m.defensive;
boolean vis, vismon, oseen;
const char *Mnam;
+ stairway *stway;
if ((i = precheck(mtmp, otmp)) != 0)
return i;
if (IS_FURNITURE(levl[mtmp->mx][mtmp->my].typ)
|| IS_DRAWBRIDGE(levl[mtmp->mx][mtmp->my].typ)
|| (is_drawbridge_wall(mtmp->mx, mtmp->my) >= 0)
- || (g.sstairs.sx && g.sstairs.sx == mtmp->mx
- && g.sstairs.sy == mtmp->my)) {
+ || stairway_at(mtmp->mx, mtmp->my)) {
pline_The("digging ray is ineffective.");
return 2;
}
return 2;
case MUSE_UPSTAIRS:
m_flee(mtmp);
+ stway = stairway_at(mtmp->mx, mtmp->my);
+ if (!stway)
+ return 0;
if (ledger_no(&u.uz) == 1)
goto escape; /* impossible; level 1 upstairs are SSTAIRS */
if (Inhell && mon_has_amulet(mtmp) && !rn2(4)
} else {
if (vismon)
pline("%s escapes upstairs!", Monnam(mtmp));
- migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_STAIRS_DOWN,
+ migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_STAIRS_DOWN,
(coord *) 0);
}
return 2;
case MUSE_DOWNSTAIRS:
m_flee(mtmp);
+ stway = stairway_at(mtmp->mx, mtmp->my);
+ if (!stway)
+ return 0;
if (vismon)
pline("%s escapes downstairs!", Monnam(mtmp));
- migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_STAIRS_UP,
+ migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_STAIRS_UP,
(coord *) 0);
return 2;
case MUSE_UP_LADDER:
m_flee(mtmp);
+ stway = stairway_at(mtmp->mx, mtmp->my);
+ if (!stway)
+ return 0;
if (vismon)
pline("%s escapes up the ladder!", Monnam(mtmp));
- migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_LADDER_DOWN,
+ migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_LADDER_DOWN,
(coord *) 0);
return 2;
case MUSE_DN_LADDER:
m_flee(mtmp);
+ stway = stairway_at(mtmp->mx, mtmp->my);
+ if (!stway)
+ return 0;
if (vismon)
pline("%s escapes down the ladder!", Monnam(mtmp));
- migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_LADDER_UP,
+ migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_LADDER_UP,
(coord *) 0);
return 2;
case MUSE_SSTAIRS:
m_flee(mtmp);
+ stway = stairway_at(mtmp->mx, mtmp->my);
+ if (!stway)
+ return 0;
if (ledger_no(&u.uz) == 1) {
escape:
/* Monsters without the Amulet escape the dungeon and
}
if (vismon)
pline("%s escapes %sstairs!", Monnam(mtmp),
- g.sstairs.up ? "up" : "down");
+ stway->up ? "up" : "down");
/* going from the Valley to Castle (Stronghold) has no sstairs
to target, but having g.sstairs.<sx,sy> == <0,0> will work the
same as specifying MIGR_RANDOM when mon_arrive() eventually
places the monster, so we can use MIGR_SSTAIRS unconditionally */
- migrate_to_level(mtmp, ledger_no(&g.sstairs.tolev), MIGR_SSTAIRS,
+ migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_SSTAIRS,
(coord *) 0);
return 2;
case MUSE_TELEPORT_TRAP:
&& !Teleport_control
/* do try to move hero to a more vulnerable spot */
&& (onscary(u.ux, u.uy, mtmp)
- || (u.ux == xupstair && u.uy == yupstair)
- || (u.ux == xdnstair && u.uy == ydnstair)
- || (u.ux == g.sstairs.sx && u.uy == g.sstairs.sy)
- || (u.ux == xupladder && u.uy == yupladder)
- || (u.ux == xdnladder && u.uy == ydnladder))) {
+ || (stairway_at(u.ux, u.uy))) {
g.m.offensive = obj;
g.m.has_offense = MUSE_WAN_TELEPORTATION;
}
HLevitation &= ~I_SPECIAL; /* can't descend upon demand */
if (BLevitation) {
; /* rising via levitation is blocked */
- } else if ((u.ux == xupstair && u.uy == yupstair)
- || (g.sstairs.up && u.ux == g.sstairs.sx && u.uy == g.sstairs.sy)
- || (xupladder && u.ux == xupladder && u.uy == yupladder)) {
+ } else if (stairway_find_dir(TRUE)) {
(void) doup();
/* in case we're already Levitating, which would have
resulted in incrementing 'nothing' */
return 1;
}
+void
+rest_stairs(nhfp)
+NHFILE *nhfp;
+{
+ int buflen = 0;
+ stairway stway;
+ int len = 0;
+
+ stairway_free_all();
+ while (1) {
+ if (nhfp->structlevel) {
+ len += sizeof(buflen);
+ mread(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+ }
+
+ if (buflen == -1)
+ break;
+
+ if (nhfp->structlevel) {
+ len += sizeof(stairway);
+ mread(nhfp->fd, (genericptr_t) &stway, sizeof(stairway));
+ }
+
+ stairway_add(stway.sx, stway.sy, stway.up, stway.isladder, &(stway.tolev));
+ }
+}
+
void
restcemetery(nhfp, cemeteryaddr)
NHFILE *nhfp;
elapsed = g.monstermoves - g.omoves;
if (nhfp->structlevel) {
- mread(nhfp->fd, (genericptr_t)&g.upstair, sizeof(stairway));
- mread(nhfp->fd, (genericptr_t)&g.dnstair, sizeof(stairway));
- mread(nhfp->fd, (genericptr_t)&g.upladder, sizeof(stairway));
- mread(nhfp->fd, (genericptr_t)&g.dnladder, sizeof(stairway));
- mread(nhfp->fd, (genericptr_t)&g.sstairs, sizeof(stairway));
+ rest_stairs(nhfp);
mread(nhfp->fd, (genericptr_t)&g.updest, sizeof(dest_area));
mread(nhfp->fd, (genericptr_t)&g.dndest, sizeof(dest_area));
mread(nhfp->fd, (genericptr_t)&g.level.flags, sizeof(g.level.flags));
rest_regions(nhfp);
if (ghostly) {
+ stairway *stway = g.stairs;
+ while (stway) {
+ if (!stway->isladder && !stway->up && stway->tolev.dnum == u.uz.dnum)
+ break;
+ stway = stway->next;
+ }
+
/* Now get rid of all the temp fruits... */
freefruitchn(g.oldfruit), g.oldfruit = 0;
if (lev > ledger_no(&medusa_level)
- && lev < ledger_no(&stronghold_level) && xdnstair == 0) {
+ && lev < ledger_no(&stronghold_level) && !stway) {
coord cc;
+ d_level dest;
+
+ dest.dnum = u.uz.dnum;
+ dest.dlevel = u.uz.dlevel + 1;
mazexy(&cc);
- xdnstair = cc.x;
- ydnstair = cc.y;
+ stairway_add(cc.x, cc.y, FALSE, FALSE, &dest);
levl[cc.x][cc.y].typ = STAIRS;
}
br = Is_branchlev(&u.uz);
if (br && u.uz.dlevel == 1) {
d_level ltmp;
+ stairway *stway;
if (on_level(&u.uz, &br->end1))
assign_level(<mp, &br->end2);
switch (br->type) {
case BR_STAIR:
case BR_NO_END1:
- case BR_NO_END2: /* OK to assign to g.sstairs if it's not used */
- assign_level(&g.sstairs.tolev, <mp);
+ case BR_NO_END2:
+ stway = g.stairs;
+ while (stway) {
+ if (stway->tolev.dnum != u.uz.dnum)
+ break;
+ stway = stway->next;
+ }
+ if (stway)
+ assign_level(&(stway->tolev), <mp);
break;
case BR_PORTAL: /* max of 1 portal per level */
for (trap = g.ftrap; trap; trap = trap->ntrap)
static void FDECL(saveobj, (NHFILE *,struct obj *));
static void FDECL(savemon, (NHFILE *,struct monst *));
static void FDECL(savelevl, (NHFILE *,BOOLEAN_P));
+static void FDECL(save_stairs, (NHFILE *));
static void FDECL(saveobjchn, (NHFILE *,struct obj *));
static void FDECL(savemonchn, (NHFILE *,struct monst *));
static void FDECL(savetrapchn, (NHFILE *,struct trap *));
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) g.lastseentyp, sizeof g.lastseentyp);
bwrite(nhfp->fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
- bwrite(nhfp->fd, (genericptr_t) &g.upstair, sizeof (stairway));
- bwrite(nhfp->fd, (genericptr_t) &g.dnstair, sizeof (stairway));
- bwrite(nhfp->fd, (genericptr_t) &g.upladder, sizeof (stairway));
- bwrite(nhfp->fd, (genericptr_t) &g.dnladder, sizeof (stairway));
- bwrite(nhfp->fd, (genericptr_t) &g.sstairs, sizeof (stairway));
+ save_stairs(nhfp);
bwrite(nhfp->fd, (genericptr_t) &g.updest, sizeof (dest_area));
bwrite(nhfp->fd, (genericptr_t) &g.dndest, sizeof (dest_area));
bwrite(nhfp->fd, (genericptr_t) &g.level.flags, sizeof g.level.flags);
fobj = 0;
g.level.buriedobjlist = 0;
g.billobjs = 0;
+ stairway_free_all();
/* level.bonesinfo = 0; -- handled by savecemetery() */
}
save_engravings(nhfp);
}
}
+static void
+save_stairs(nhfp)
+NHFILE *nhfp;
+{
+ stairway *stway = g.stairs;
+ int buflen = (int) sizeof (stairway);
+ int len = 0;
+
+ while (stway) {
+ if (perform_bwrite(nhfp)) {
+ if (nhfp->structlevel) {
+ len += sizeof(buflen);
+ bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+ len += sizeof(stairway);
+ bwrite(nhfp->fd, (genericptr_t) stway, sizeof(stairway));
+ }
+ }
+ stway = stway->next;
+ }
+ if (perform_bwrite(nhfp)) {
+ if (nhfp->structlevel) {
+ buflen = -1;
+ len += sizeof(buflen);
+ bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+ }
+ }
+}
+
static void
saveobjchn(nhfp, otmp)
NHFILE *nhfp;
{
coord mm;
+ stairway *stway = g.stairs;
+
+ while (stway) {
+ if (!stway->isladder && !stway->up && stway->tolev.dnum == u.uz.dnum)
+ break;
+ stway = stway->next;
+ }
if (nearshop) {
/* Create swarm around you, if you merely "stepped out" */
if (flags.verbose)
pline_The("Keystone Kops are after you!");
/* Create swarm near down staircase (hinders return to level) */
- mm.x = xdnstair;
- mm.y = ydnstair;
+ mm.x = stway->sx;
+ mm.y = stway->sy;
makekops(&mm);
/* Create swarm near shopkeeper (hinders return to shop) */
mm.x = shkp->mx;
static void FDECL(create_altar, (altar *, struct mkroom *));
static boolean FDECL(search_door, (struct mkroom *,
xchar *, xchar *, XCHAR_P, int));
-static void NDECL(fix_stair_rooms);
static void FDECL(create_corridor, (corridor *));
static struct mkroom *FDECL(build_room, (room *, struct mkroom *));
static void FDECL(light_region, (region *));
struct mkroom *sroom;
timer_element *timer;
boolean ball_active = FALSE, ball_fliparea = FALSE;
+ stairway *stway;
/* nothing to do unless (flp & 1) or (flp & 2) or both */
if ((flp & 3) == 0)
}
/* stairs and ladders */
- if (flp & 1) {
- if (xupstair)
- yupstair = FlipY(yupstair);
- if (xdnstair)
- ydnstair = FlipY(ydnstair);
- if (xupladder)
- yupladder = FlipY(yupladder);
- if (xdnladder)
- ydnladder = FlipY(ydnladder);
- if (g.sstairs.sx)
- g.sstairs.sy = FlipY(g.sstairs.sy);
- }
- if (flp & 2) {
- if (xupstair)
- xupstair = FlipX(xupstair);
- if (xdnstair)
- xdnstair = FlipX(xdnstair);
- if (xupladder)
- xupladder = FlipX(xupladder);
- if (xdnladder)
- xdnladder = FlipX(xdnladder);
- if (g.sstairs.sx)
- g.sstairs.sx = FlipX(g.sstairs.sx);
+ for (stway = g.stairs; stway; stway = stway->next) {
+ if (flp & 1)
+ stway->sy = FlipY(stway->sy);
+ if (flp & 2)
+ stway->sx = FlipX(stway->sx);
}
/* traps */
return TRUE;
}
-/*
- * Disgusting hack: since special levels have their rooms filled before
- * sorting the rooms, we have to re-arrange the speed values g.upstairs_room
- * and g.dnstairs_room after the rooms have been sorted. On normal levels,
- * stairs don't get created until _after_ sorting takes place.
- */
-static void
-fix_stair_rooms()
-{
- int i;
- struct mkroom *croom;
-
- if (xdnstair
- && !((g.dnstairs_room->lx <= xdnstair
- && xdnstair <= g.dnstairs_room->hx)
- && (g.dnstairs_room->ly <= ydnstair
- && ydnstair <= g.dnstairs_room->hy))) {
- for (i = 0; i < g.nroom; i++) {
- croom = &g.rooms[i];
- if ((croom->lx <= xdnstair && xdnstair <= croom->hx)
- && (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
- g.dnstairs_room = croom;
- break;
- }
- }
- if (i == g.nroom)
- panic("Couldn't find dnstair room in fix_stair_rooms!");
- }
- if (xupstair
- && !((g.upstairs_room->lx <= xupstair
- && xupstair <= g.upstairs_room->hx)
- && (g.upstairs_room->ly <= yupstair
- && yupstair <= g.upstairs_room->hy))) {
- for (i = 0; i < g.nroom; i++) {
- croom = &g.rooms[i];
- if ((croom->lx <= xupstair && xupstair <= croom->hx)
- && (croom->ly <= yupstair && yupstair <= croom->hy)) {
- g.upstairs_room = croom;
- break;
- }
- }
- if (i == g.nroom)
- panic("Couldn't find upstair room in fix_stair_rooms!");
- }
-}
-
/*
* Corridors always start from a door. But it can end anywhere...
* Basically we search for door coordinates or for endpoints coordinates
coord org, dest;
if (c->src.room == -1) {
- fix_stair_rooms();
makecorridors(); /*makecorridors(c->src.door);*/
return;
}
if (using_ladder) {
levl[x][y].typ = LADDER;
if (up) {
- xupladder = x;
- yupladder = y;
+ d_level dest;
+
+ dest.dnum = u.uz.dnum;
+ dest.dlevel = u.uz.dlevel - 1;
+ stairway_add(x, y, TRUE, TRUE, &dest);
levl[x][y].ladder = LA_UP;
} else {
- xdnladder = x;
- ydnladder = y;
+ d_level dest;
+
+ dest.dnum = u.uz.dnum;
+ dest.dlevel = u.uz.dlevel + 1;
+ stairway_add(x, y, FALSE, TRUE, &dest);
levl[x][y].ladder = LA_DOWN;
}
} else {
struct trap *ttmp = g.ftrap;
int x,y;
boolean ret = TRUE;
+ stairway *stway = g.stairs;
set_selection_floodfillchk(floodfillchk_match_accessible);
- if (xupstair && !selection_getpoint(xupstair, yupstair, ov))
- selection_floodfill(ov, xupstair, yupstair, TRUE);
- if (xdnstair && !selection_getpoint(xdnstair, ydnstair, ov))
- selection_floodfill(ov, xdnstair, ydnstair, TRUE);
- if (xupladder && !selection_getpoint(xupladder, yupladder, ov))
- selection_floodfill(ov, xupladder, yupladder, TRUE);
- if (xdnladder && !selection_getpoint(xdnladder, ydnladder, ov))
- selection_floodfill(ov, xdnladder, ydnladder, TRUE);
+ while (stway) {
+ if (stway->tolev.dnum == u.uz.dnum)
+ selection_floodfill(ov, stway->sx, stway->sy, TRUE);
+ stway = stway->next;
+ }
while (ttmp) {
if ((ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE
make_angry_shk(mtmp, oldx, oldy);
}
+static stairway *
+stairway_find_forwiz(ladder, up)
+boolean ladder, up;
+{
+ stairway *stway = g.stairs;
+
+ while (stway && !(stway->isladder == ladder && stway->up == up && stway->tolev.dnum == u.uz.dnum))
+ stway = stway->next;
+ return stway;
+}
+
/* place a monster at a random location, typically due to teleport */
/* return TRUE if successful, FALSE if not */
boolean
boolean suppress_impossible;
{
register int x, y, trycount;
+ stairway *stway;
if (mtmp == u.usteed) {
tele();
}
if (mtmp->iswiz && mtmp->mx) { /* Wizard, not just arriving */
- if (!In_W_tower(u.ux, u.uy, &u.uz))
- x = xupstair, y = yupstair;
- else if (!xdnladder) /* bottom level of tower */
- x = xupladder, y = yupladder;
- else
- x = xdnladder, y = ydnladder;
+ if (!In_W_tower(u.ux, u.uy, &u.uz)) {
+ stway = stairway_find_forwiz(FALSE, TRUE);
+ x = stway->sx;
+ y = stway->sy;
+ } else if (!stairway_find_forwiz(TRUE, FALSE)) { /* bottom level of tower */
+ stway = stairway_find_forwiz(TRUE, TRUE);
+ x = stway->sx;
+ y = stway->sy;
+ } else {
+ stway = stairway_find_forwiz(TRUE, FALSE);
+ x = stway->sx;
+ y = stway->sy;
+ }
/* if the wiz teleports away to heal, try the up staircase,
to block the player's escaping before he's healed
(deliberately use `goodpos' rather than `rloc_pos_ok' here) */
xchar *sy;
{
xchar x = 0, y = 0;
-
- if (builds_up(&u.uz)) {
- if (xdnstair) {
- x = xdnstair;
- y = ydnstair;
- } else if (xdnladder) {
- x = xdnladder;
- y = ydnladder;
- }
+ stairway *stway = g.stairs;
+ boolean stdir = !builds_up(&u.uz);
+
+ if ((stway = stairway_find_type_dir(FALSE, stdir)) != 0) {
+ x = stway->sx;
+ y = stway->sy;
+ } else if ((stway = stairway_find_type_dir(TRUE, stdir)) != 0) {
+ x = stway->sx;
+ y = stway->sy;
} else {
- if (xupstair) {
- x = xupstair;
- y = yupstair;
- } else if (xupladder) {
- x = xupladder;
- y = yupladder;
+ while (stway) {
+ if (stway->tolev.dnum != u.uz.dnum) {
+ x = stway->sx;
+ y = stway->sy;
+ break;
+ }
+ stway = stway->next;
}
}
- if (!x && g.sstairs.sx) {
- x = g.sstairs.sx;
- y = g.sstairs.sy;
- }
-
if (x && y) {
*sx = x;
*sy = y;
struct engr *e;
struct trap *ttmp;
char buf[BUFSZ];
+ stairway *stway = g.stairs;
/* some wands have special effects other than normal bhitpile */
/* drawbridge might change <u.ux,u.uy> */
return TRUE; /* we've done our own bhitpile */
case WAN_OPENING:
case SPE_KNOCK:
+ while (stway) {
+ if (!stway->isladder && !stway->up && stway->tolev.dnum == u.uz.dnum)
+ break;
+ stway = stway->next;
+ }
/* up or down, but at closed portcullis only */
if (is_db_wall(x, y) && find_drawbridge(&xx, &yy)) {
open_drawbridge(xx, yy);
disclose = TRUE;
- } else if (u.dz > 0 && (x == xdnstair && y == ydnstair)
+ } else if (u.dz > 0 && stway && stway->sx == x && stway->sy == y
/* can't use the stairs down to quest level 2 until
leader "unlocks" them; give feedback if you try */
&& on_level(&u.uz, &qstart_level) && !ok_to_quest()) {