Rework stairs structure

Use a linked list to store stair and ladder information, instead
of having fixed up/down stairs/ladders and a single "special" (branch)
stair.

Breaks saves and bones.

Adds information to migrating objects and monsters for the dungeon
and level where they are migrating from.
This commit is contained in:
Pasi Kallinen
2020-11-13 20:27:17 +02:00
parent e23f764d11
commit 6ec55a3624
34 changed files with 552 additions and 361 deletions
+1 -1
View File
@@ -706,4 +706,4 @@ get rid of 3.6.1 workaround needed to retain compatibility with 3.6.0 bones
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
+1 -18
View File
@@ -75,16 +75,6 @@ struct dgn_topology { /* special dungeon levels for speed */
#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"
@@ -726,10 +716,7 @@ struct instance_globals {
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;
@@ -754,7 +741,6 @@ struct instance_globals {
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;
@@ -765,9 +751,6 @@ struct instance_globals {
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];
+3 -1
View File
@@ -34,7 +34,9 @@ typedef struct s_level { /* special dungeon level element */
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 */
+9
View File
@@ -630,6 +630,15 @@ E void FDECL(next_level, (BOOLEAN_P));
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);
+1
View File
@@ -82,6 +82,7 @@ struct monst {
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 */
+2
View File
@@ -122,6 +122,8 @@ struct obj {
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 */
};
+1 -1
View File
@@ -17,7 +17,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files.
*/
#define EDITLEVEL 24
#define EDITLEVEL 25
/*
* Development status possibilities.
+2
View File
@@ -243,6 +243,8 @@ enum screen_symbols {
#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 {
+12 -34
View File
@@ -712,43 +712,21 @@ do_positionbar()
{
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;
}
/* 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);
/* 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;
}
if (is_cmap_stairs(glyph)) {
*p++ = (stway->up ? '<' : '>');
*p++ = stway->sx;
}
stway = stway->next;
}
/* hero location */
if (u.ux) {
+4 -4
View File
@@ -2556,10 +2556,10 @@ struct obj *otmp;
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))
+5 -6
View File
@@ -3958,6 +3958,7 @@ boolean doit;
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);
@@ -3974,16 +3975,14 @@ boolean doit;
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 */
+1 -8
View File
@@ -270,10 +270,7 @@ const struct instance_globals g_init = {
(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 */
@@ -294,7 +291,6 @@ const struct instance_globals g_init = {
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 */
@@ -305,9 +301,6 @@ const struct instance_globals g_init = {
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 */
+6 -5
View File
@@ -188,7 +188,8 @@ int x, y;
(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)
@@ -1431,12 +1432,12 @@ zap_dig()
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);
+13 -12
View File
@@ -950,10 +950,9 @@ int
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;
@@ -1105,6 +1104,8 @@ dodown()
int
doup()
{
stairway *stway = stairway_at(u.ux,u.uy);
if (u_rooted())
return 1;
@@ -1114,10 +1115,7 @@ doup()
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;
}
@@ -1458,6 +1456,7 @@ boolean at_stairs, falling, portal;
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);
@@ -1528,8 +1527,9 @@ boolean at_stairs, falling, portal;
}
} 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
@@ -1544,8 +1544,9 @@ boolean at_stairs, falling, portal;
(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
+26 -5
View File
@@ -306,6 +306,8 @@ boolean with_you;
xchar xlocale, ylocale, xyloc, xyflags, wander;
int num_segs;
boolean failed_to_place = FALSE;
stairway *stway;
d_level fromdlev;
mtmp->nmon = fmon;
fmon = mtmp;
@@ -331,6 +333,8 @@ boolean with_you;
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)
@@ -376,19 +380,34 @@ boolean with_you;
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)) {
@@ -719,6 +738,8 @@ coord *cc; /* optional destination coordinates */
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;
+38 -20
View File
@@ -19,7 +19,7 @@ static int FDECL(kick_object, (XCHAR_P, XCHAR_P, char *));
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";
@@ -1322,10 +1322,13 @@ dokick()
}
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 */
@@ -1340,12 +1343,14 @@ schar loc;
/*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:
@@ -1373,7 +1378,7 @@ xchar dlev; /* if !0 send to dlev near player */
return;
toloc = down_gate(x, y);
drop_to(&cc, toloc);
drop_to(&cc, toloc, x, y);
if (!cc.y)
return;
@@ -1502,7 +1507,7 @@ boolean shop_floor_obj;
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;
@@ -1586,6 +1591,7 @@ boolean shop_floor_obj;
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;
@@ -1614,6 +1620,9 @@ boolean near_hero;
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;
@@ -1633,16 +1642,21 @@ boolean near_hero;
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;
@@ -1652,6 +1666,8 @@ boolean near_hero;
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)) {
@@ -1727,6 +1743,8 @@ unsigned long deliverflags;
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)
@@ -1773,19 +1791,19 @@ down_gate(x, y)
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;
}
+167 -30
View File
@@ -1398,13 +1398,14 @@ void
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);
@@ -1416,17 +1417,22 @@ void
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);
@@ -1492,13 +1498,141 @@ int upflag;
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);
}
@@ -1507,8 +1641,10 @@ int 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 */
}
@@ -1517,8 +1653,10 @@ u_on_upstairs()
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 */
}
@@ -1527,37 +1665,34 @@ boolean
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
@@ -1599,6 +1734,8 @@ Can_rise_up(x, y, lev)
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)
@@ -1607,7 +1744,7 @@ d_level *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
+5 -6
View File
@@ -3362,6 +3362,7 @@ char *buf;
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) {
@@ -3402,15 +3403,13 @@ char *buf;
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" */
+8 -9
View File
@@ -151,6 +151,7 @@ coord *startp;
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 ---
@@ -166,15 +167,13 @@ coord *startp;
* 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;
}
/*
+8 -12
View File
@@ -1095,20 +1095,16 @@ coord *cc;
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;
+15 -25
View File
@@ -719,10 +719,7 @@ clear_level_structures()
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;
@@ -1112,13 +1109,6 @@ mklev()
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);
}
@@ -1262,14 +1252,10 @@ xchar x, y; /* location */
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;
boolean goes_up = on_level(&br->end1, &u.uz) ? br->end1_up : !br->end1_up;
levl[x][y].ladder = g.sstairs.up ? LA_UP : LA_DOWN;
stairway_add(x,y, goes_up, FALSE, dest);
levl[x][y].ladder = goes_up ? LA_UP : LA_DOWN;
levl[x][y].typ = STAIRS;
}
/*
@@ -1633,13 +1619,17 @@ struct mkroom *croom;
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;
@@ -1659,7 +1649,7 @@ struct mkroom *croom;
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)));
+6 -4
View File
@@ -1015,6 +1015,7 @@ const char *s;
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
@@ -1047,10 +1048,11 @@ const char *s;
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);
+2
View File
@@ -2130,6 +2130,8 @@ struct obj *obj;
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;
}
+14 -8
View File
@@ -622,10 +622,13 @@ 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);
stairway *stway = g.stairs;
while (stway) {
if (!stway->up && inside_room(sroom, stway->sx, stway->sy))
return TRUE;
stway = stway->next;
}
return FALSE;
}
@@ -633,10 +636,13 @@ 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);
stairway *stway = g.stairs;
while (stway) {
if (stway->up && inside_room(sroom, stway->sx, stway->sy))
return TRUE;
stway = stway->next;
}
return FALSE;
}
+6 -2
View File
@@ -2327,11 +2327,15 @@ register struct monst *mtmp;
#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;
+35 -21
View File
@@ -336,6 +336,7 @@ struct monst *mtmp;
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;
@@ -432,23 +433,25 @@ struct monst *mtmp;
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 {
@@ -653,6 +656,7 @@ struct monst *mtmp;
struct obj *otmp = g.m.defensive;
boolean vis, vismon, oseen;
const char *Mnam;
stairway *stway;
if ((i = precheck(mtmp, otmp)) != 0)
return i;
@@ -770,8 +774,7 @@ struct monst *mtmp;
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;
}
@@ -893,6 +896,9 @@ struct monst *mtmp;
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)
@@ -910,33 +916,45 @@ struct monst *mtmp;
} 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
@@ -959,12 +977,12 @@ struct monst *mtmp;
}
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:
@@ -1223,11 +1241,7 @@ struct monst *mtmp;
&& !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;
}
+1 -3
View File
@@ -1051,9 +1051,7 @@ register struct obj *otmp;
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' */
+51 -10
View File
@@ -905,6 +905,33 @@ NHFILE *nhfp;
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;
@@ -1050,11 +1077,7 @@ xchar lev;
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));
@@ -1132,22 +1155,33 @@ xchar lev;
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(&ltmp, &br->end2);
@@ -1157,8 +1191,15 @@ xchar lev;
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, &ltmp);
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), &ltmp);
break;
case BR_PORTAL: /* max of 1 portal per level */
for (trap = g.ftrap; trap; trap = trap->ntrap)
+31 -5
View File
@@ -28,6 +28,7 @@ static void FDECL(savedamage, (NHFILE *));
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 *));
@@ -457,11 +458,7 @@ xchar lev;
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);
@@ -496,6 +493,7 @@ xchar lev;
fobj = 0;
g.level.buriedobjlist = 0;
g.billobjs = 0;
stairway_free_all();
/* level.bonesinfo = 0; -- handled by savecemetery() */
}
save_engravings(nhfp);
@@ -668,6 +666,34 @@ struct obj *otmp;
}
}
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;
+9 -2
View File
@@ -362,6 +362,13 @@ register boolean nearshop;
{
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" */
@@ -375,8 +382,8 @@ register boolean nearshop;
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;
+22 -83
View File
@@ -60,7 +60,6 @@ static void FDECL(create_object, (object *, struct mkroom *));
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 *));
@@ -500,6 +499,7 @@ boolean extras;
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)
@@ -537,29 +537,11 @@ boolean extras;
}
/* 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 */
@@ -2564,52 +2546,6 @@ schar ftyp, btyp;
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
@@ -2622,7 +2558,6 @@ corridor *c;
coord org, dest;
if (c->src.room == -1) {
fix_stair_rooms();
makecorridors(); /*makecorridors(c->src.door);*/
return;
}
@@ -3933,12 +3868,18 @@ boolean using_ladder;
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 {
@@ -5334,17 +5275,15 @@ ensure_way_out()
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
+25 -6
View File
@@ -1260,6 +1260,17 @@ register int x, y;
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
@@ -1268,6 +1279,7 @@ struct monst *mtmp; /* mx==0 implies migrating monster arrival */
boolean suppress_impossible;
{
register int x, y, trycount;
stairway *stway;
if (mtmp == u.usteed) {
tele();
@@ -1275,12 +1287,19 @@ boolean suppress_impossible;
}
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) */
+15 -19
View File
@@ -329,30 +329,26 @@ xchar *sx;
xchar *sy;
{
xchar x = 0, y = 0;
stairway *stway = g.stairs;
boolean stdir = !builds_up(&u.uz);
if (builds_up(&u.uz)) {
if (xdnstair) {
x = xdnstair;
y = ydnstair;
} else if (xdnladder) {
x = xdnladder;
y = ydnladder;
}
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;
+7 -1
View File
@@ -2891,6 +2891,7 @@ struct obj *obj; /* wand or spell */
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> */
@@ -2913,11 +2914,16 @@ struct obj *obj; /* wand or spell */
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()) {