more wizard mode wishing for terrain

Try a lot harder to keep terrain/level flags in a sane state.  They're
overloaded so it's not simple.

Creating a fountain or sink incremented the corresponding counter (for
controlling ambient sounds) but removing one by wishing for something
else in its place didn't decrement.

Allow wish for "disturbed grave" to create a grave with the 'disturbed'
flag set, similar to existing "magic fountain" and 'blessedftn' flag.
(I didn't add "looted throne", "looted tree", and several other things
that use the 'looted' overload of 'rm.flags'.)

Automate block_point (tree, cloud, secret corridor, or secret door in
open doorway) and add unblock_point (use Pass_wall to move into wall
or tree or stone, or just walk onto a cloud, then make iron bars or
almost any other wishable terrain to replace the blocking feature).
This commit is contained in:
PatR
2020-01-26 12:23:50 -08:00
parent 4505a8dc4c
commit c911446188
2 changed files with 85 additions and 30 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 rm.h $NHDT-Date: 1578258722 2020/01/05 21:12:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.77 $ */
/* NetHack 3.6 rm.h $NHDT-Date: 1580070206 2020/01/26 20:23:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.78 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Pasi Kallinen, 2017. */
/* NetHack may be freely redistributed. See license for details. */
@@ -528,16 +528,19 @@ struct rm {
#define SV7 0x80
#define SVALL 0xFF
#define doormask flags
#define altarmask flags
#define wall_info flags
#define ladder flags
#define drawbridgemask flags
#define looted flags
#define icedpool flags
/* if these get changed or expanded, make sure wizard-mode wishing becomes
aware of the new usage */
#define doormask flags /* door, sdoor (note conflict with wall_info) */
#define altarmask flags /* alignment and maybe temple */
#define wall_info flags /* wall, sdoor (note conflict with doormask) */
#define ladder flags /* up or down */
#define drawbridgemask flags /* what's underneath when the span is open */
#define looted flags /* used for throne, tree, fountain, sink, door */
#define icedpool flags /* used for ice (in case it melts) */
/* horizonal applies to walls, doors (including sdoor); also to iron bars
even though they don't have separate symbols for horizontal and vertical */
#define blessedftn horizontal /* a fountain that grants attribs */
#define disturbed horizontal /* a grave that has been disturbed */
#define disturbed horizontal /* a grave that has been disturbed */
struct damage {
struct damage *next;

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 objnam.c $NHDT-Date: 1579261291 2020/01/17 11:41:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.288 $ */
/* NetHack 3.7 objnam.c $NHDT-Date: 1580070220 2020/01/26 20:23:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.291 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */
@@ -2952,8 +2952,8 @@ char *bp, *p;
int locked, trapped;
{
struct rm *lev;
boolean madeterrain = FALSE, badterrain = FALSE;
int trap, x = u.ux, y = u.uy;
boolean madeterrain = FALSE, badterrain = FALSE, didblock;
int trap, oldtyp, x = u.ux, y = u.uy;
for (trap = NO_TRAP + 1; trap < TRAPNUM; trap++) {
struct trap *t;
@@ -2978,21 +2978,25 @@ int locked, trapped;
/* furniture and terrain (use at your own risk; can clobber stairs
or place furniture on existing traps which shouldn't be allowed) */
lev = &levl[x][y];
oldtyp = lev->typ;
didblock = does_block(x, y, lev);
p = eos(bp);
if (!BSTRCMPI(bp, p - 8, "fountain")) {
lev->typ = FOUNTAIN;
g.level.flags.nfountains++;
if (!strncmpi(bp, "magic ", 6))
lev->blessedftn = 1;
lev->looted = 0; /* overlays 'flags' */
lev->blessedftn = !strncmpi(bp, "magic ", 6);
pline("A %sfountain.", lev->blessedftn ? "magic " : "");
madeterrain = TRUE;
} else if (!BSTRCMPI(bp, p - 6, "throne")) {
lev->typ = THRONE;
lev->looted = 0; /* overlays 'flags' */
pline("A throne.");
madeterrain = TRUE;
} else if (!BSTRCMPI(bp, p - 4, "sink")) {
lev->typ = SINK;
g.level.flags.nsinks++;
lev->looted = 0; /* overlays 'flags' */
pline("A sink.");
madeterrain = TRUE;
@@ -3000,6 +3004,7 @@ int locked, trapped;
} else if (!BSTRCMPI(bp, p - 4, "pool")
|| !BSTRCMPI(bp, p - 4, "moat")) {
lev->typ = !BSTRCMPI(bp, p - 4, "pool") ? POOL : MOAT;
lev->flags = 0;
del_engr_at(x, y);
pline("A %s.", (lev->typ == POOL) ? "pool" : "moat");
/* Must manually make kelp! */
@@ -3009,6 +3014,7 @@ int locked, trapped;
/* also matches "molten lava" */
} else if (!BSTRCMPI(bp, p - 4, "lava")) {
lev->typ = LAVAPOOL;
lev->flags = 0;
del_engr_at(x, y);
pline("A pool of molten lava.");
if (!(Levitation || Flying))
@@ -3028,34 +3034,51 @@ int locked, trapped;
al = A_NONE;
else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
al = !rn2(6) ? A_NONE : (rn2((int) A_LAWFUL + 2) - 1);
lev->altarmask = Align2amask(al);
lev->altarmask = Align2amask(al); /* overlays 'flags' */
pline("%s altar.", An(align_str(al)));
madeterrain = TRUE;
} else if (!BSTRCMPI(bp, p - 5, "grave")
|| !BSTRCMPI(bp, p - 9, "headstone")) {
make_grave(x, y, (char *) 0);
pline("%s.", IS_GRAVE(lev->typ) ? "A grave"
: "Can't place a grave here");
madeterrain = TRUE;
if (IS_GRAVE(lev->typ)) {
lev->looted = 0; /* overlays 'flags' */
lev->disturbed = !strncmpi(bp, "disturbed ", 10);
pline("A %sgrave.", lev->disturbed ? "disturbed " : "");
madeterrain = TRUE;
} else {
pline("Can't place a grave here");
badterrain = TRUE;
}
} else if (!BSTRCMPI(bp, p - 4, "tree")) {
lev->typ = TREE;
lev->looted = 0; /* overlays 'flags' */
pline("A tree.");
block_point(x, y);
madeterrain = TRUE;
} else if (!BSTRCMPI(bp, p - 4, "bars")) {
lev->typ = IRONBARS;
lev->flags = 0;
/* [FIXME: if this isn't a wall or door location where 'horizontal'
is already set up, that should be calculated for this spot.
Unforutnately, it can be tricky; placing one in open space
and then another adjacent might need to recalculate first one.] */
pline("Iron bars.");
madeterrain = TRUE;
} else if (!BSTRCMPI(bp, p - 5, "cloud")) {
lev->typ = CLOUD;
block_point(x, y);
lev->flags = 0;
pline("A cloud.");
madeterrain = TRUE;
} else if (!BSTRCMPI(bp, p - 11, "secret door")) {
if (lev->typ == DOOR
|| (IS_WALL(lev->typ) && lev->typ != DBWALL)) {
/* require door or wall so that the 'horizontal' flag will
already have the correct value (it will matter once the
secret door is discovered and becomes a regular door);
player might choose to put SDOOR on top of existing SDOOR
to control its trapped state; iron bars are surrogate walls */
if (lev->typ == DOOR || lev->typ == SDOOR
|| (IS_WALL(lev->typ) && lev->typ != DBWALL)
|| lev->typ == IRONBARS) {
lev->typ = SDOOR;
lev->wall_info = 0;
lev->wall_info = 0; /* overlays 'flags' */
/* lev->horizontal stays as-is */
/* no special handling for rogue level is necessary;
exposing a secret door there yields a doorless doorway */
@@ -3073,7 +3096,6 @@ int locked, trapped;
#endif
if (trapped)
lev->doormask |= D_TRAPPED;
block_point(x, y);
pline("Secret door.");
madeterrain = TRUE;
} else {
@@ -3083,7 +3105,7 @@ int locked, trapped;
} else if (!BSTRCMPI(bp, p - 15, "secret corridor")) {
if (lev->typ == CORR) {
lev->typ = SCORR;
block_point(x, y);
/* neither CORR nor SCORR uses 'flags' or 'horizontal' */
pline("Secret corridor.");
madeterrain = TRUE;
} else {
@@ -3099,11 +3121,41 @@ int locked, trapped;
if (u.uinwater && !is_pool(u.ux, u.uy)) {
u.uinwater = 0; /* leave the water */
docrt();
g.vision_full_recalc = 1;
} else if (u.utrap && u.utraptype == TT_LAVA
&& !is_lava(u.ux, u.uy)) {
reset_utrap(FALSE);
/* [block/unblock_point was handled by docrt -> vision_recalc] */
} else {
if (u.utrap && u.utraptype == TT_LAVA && !is_lava(u.ux, u.uy))
reset_utrap(FALSE);
if (does_block(x, y, lev)) {
if (!didblock)
block_point(x, y);
} else {
if (didblock)
unblock_point(x, y);
}
}
/* fixups for replaced terrain that aren't handled above;
for fountain placed on fountain or sink placed on sink, the
increment above gets canceled out by the decrement here;
otherwise if fountain or sink was replaced, there's one less */
if (IS_FOUNTAIN(oldtyp))
g.level.flags.nfountains--;
else if (IS_SINK(oldtyp))
g.level.flags.nsinks--;
/* horizontal is overlaid by fountain->blessedftn, grave->disturbed */
if (IS_FOUNTAIN(oldtyp) || IS_GRAVE(oldtyp)
|| IS_WALL(oldtyp) || oldtyp == IRONBARS
|| IS_DOOR(oldtyp) || oldtyp == SDOOR) {
/* when new terrain is a fountain, 'blessedftn' was explicitly
set above; likewise for grave and 'disturbed'; when it's a
secret door, the old type was a wall or a door and we retain
the 'horizontal' value from those */
if (!IS_FOUNTAIN(lev->typ) && !IS_GRAVE(lev->typ)
&& lev->typ != SDOOR)
lev->horizontal = 0; /* also clears blessedftn, disturbed */
}
/* note: lev->lit and lev->nondiggable retain their values even
though those might not make sense with the new terrain */
}
if (madeterrain || badterrain) {
/* cast 'const' away; caller won't modify this */