fix #K4042 - visible but unreachable teleport trap

If a monster fled from the hero by intentionally jumping into a vault
teleporter located in a niche which was still hidden and the hero
saw it happen, the trap would be mapped but the niche would remain as
a secret corridor spot.  The hero couldn't move onto the trap until
searching or wall kicking or other map disclosing activity converted
the spot into regular corridor.

Trap doors in hidden niches did already change the secret corridor
into normal corridor to unhide the trap's spot, but only if the hero
saw it happen.  Now the terrain change occurs even if hero doesn't
see it; only mapping the trap depends on that.

While testing the fix, I noticed that a monster jumping onto a vault
teleporter was teleporting randomly rather than being sent to the
vault, unlike when triggering such a trap by accident.  The code has
changed for 3.7 but this bug was already present in earlier versions.
This commit is contained in:
PatR
2023-12-02 15:05:45 -08:00
parent 0c03b9bea6
commit 6c38bfeba2
2 changed files with 56 additions and 30 deletions

View File

@@ -1305,6 +1305,10 @@ alchemy may affect only a portion of the dipped potions if a large
monster kills can no longer deathdrop comestibles (other than the
monster's corpse) unless the monster collects food or
generates with food
if a monster fled from hero by intentionally jumping into a vault teleporter,
it would teleport randomly instead of into the vault, and if the
teleport trap's niche wasn't mapped yet, the trap would become mapped
but the spot would remain a secret corridor and not become accessible
Fixes to 3.7.0-x General Problems Exposed Via git Repository

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 muse.c $NHDT-Date: 1654972707 2022/06/11 18:38:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.164 $ */
/* NetHack 3.7 muse.c $NHDT-Date: 1701557157 2023/12/02 22:45:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.202 $ */
/* Copyright (C) 1990 by Ken Arromdee */
/* NetHack may be freely redistributed. See license for details. */
@@ -22,6 +22,7 @@ static void mquaffmsg(struct monst *, struct obj *);
static boolean m_use_healing(struct monst *);
static boolean m_sees_sleepy_soldier(struct monst *);
static void m_tele(struct monst *, boolean, boolean, int);
static void reveal_trap(struct trap *, boolean);
static boolean linedup_chk_corpse(coordxy, coordxy);
static void m_use_undead_turning(struct monst *, struct obj *);
static boolean hero_behind_chokepoint(struct monst *);
@@ -382,9 +383,18 @@ m_tele(
if (vismon)
pline("%s seems disoriented for a moment.", Monnam(mtmp));
} else {
if (oseen && how)
makeknown(how);
(void) rloc(mtmp, RLOC_MSG);
/* teleport monster 'mtmp' */
if (how) {
/* teleporation has been triggered by an object */
if (oseen)
makeknown(how);
(void) rloc(mtmp, RLOC_MSG);
} else {
/* monster is voluntarily entering a teleporation trap; use the
trap instead of rloc() in case it sends 'victim' to a vault */
mtmp->mx = gt.trapx, mtmp->my = gt.trapy;
(void) mintrap(mtmp, FORCETRAP);
}
}
}
@@ -699,6 +709,24 @@ find_defensive(struct monst *mtmp, boolean tryescape)
#undef nomore
}
/* when a monster deliberately enters a trap, make sure the spot becomes
accessible (trap doors and teleporters inside niches are located at
secret corridor locations; convert such into normal corridor even if
hero doesn't see it happen) */
static void
reveal_trap(struct trap *t, boolean seeit)
{
struct rm *lev = &levl[t->tx][t->ty];
if (lev->typ == SCORR) {
lev->typ = CORR, lev->flags = 0; /* set_levltyp(,,CORR) */
if (seeit)
unblock_point(t->tx, t->ty);
}
if (seeit)
seetrap(t);
}
/* Perform a defensive action for a monster. Must be called immediately
* after find_defensive(). Return values are 0: did something, 1: died,
* 2: did something and can't attack again (i.e. teleported).
@@ -709,7 +737,7 @@ use_defensive(struct monst *mtmp)
int i, fleetim;
struct obj *otmp = gm.m.defensive;
boolean vis, vismon, oseen;
const char *Mnam;
struct trap *t;
stairway *stway;
if ((i = precheck(mtmp, otmp)) != 0)
@@ -813,9 +841,7 @@ use_defensive(struct monst *mtmp)
obfree(otmp, (struct obj *) 0);
return 2;
}
case MUSE_WAN_DIGGING: {
struct trap *ttmp;
case MUSE_WAN_DIGGING:
m_flee(mtmp);
mzapwand(mtmp, otmp, FALSE);
if (oseen)
@@ -831,7 +857,7 @@ use_defensive(struct monst *mtmp)
/* can't dig further if there's already a pit (or other trap)
here, or if pit creation fails for some reason */
if (t_at(mtmp->mx, mtmp->my)
|| !(ttmp = maketrap(mtmp->mx, mtmp->my, PIT))) {
|| !(t = maketrap(mtmp->mx, mtmp->my, PIT))) {
if (vismon) {
pline_The("%s here is too hard to dig in.",
surface(mtmp->mx, mtmp->my));
@@ -840,16 +866,16 @@ use_defensive(struct monst *mtmp)
}
/* pit creation succeeded */
if (vis) {
seetrap(ttmp);
seetrap(t);
pline("%s has made a pit in the %s.", Monnam(mtmp),
surface(mtmp->mx, mtmp->my));
}
return (mintrap(mtmp, FORCEBUNGLE) == Trap_Killed_Mon) ? 1 : 2;
}
ttmp = maketrap(mtmp->mx, mtmp->my, HOLE);
if (!ttmp)
t = maketrap(mtmp->mx, mtmp->my, HOLE);
if (!t)
return 2;
seetrap(ttmp);
seetrap(t);
if (vis) {
pline("%s has made a hole in the %s.", Monnam(mtmp),
surface(mtmp->mx, mtmp->my));
@@ -864,7 +890,6 @@ use_defensive(struct monst *mtmp)
migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM,
(coord *) 0);
return 2;
}
case MUSE_WAN_UNDEAD_TURNING:
gz.zap_oseen = oseen;
mzapwand(mtmp, otmp, FALSE);
@@ -932,19 +957,14 @@ use_defensive(struct monst *mtmp)
if (Is_botlevel(&u.uz))
return 0;
m_flee(mtmp);
t = t_at(gt.trapx, gt.trapy);
if (vis) {
struct trap *t = t_at(gt.trapx, gt.trapy);
Mnam = Monnam(mtmp);
pline("%s %s into a %s!", Mnam,
pline("%s %s into a %s!", Monnam(mtmp),
vtense(fakename[0], locomotion(mtmp->data, "jump")),
(t->ttyp == TRAPDOOR) ? "trap door" : "hole");
if (levl[gt.trapx][gt.trapy].typ == SCORR) {
levl[gt.trapx][gt.trapy].typ = CORR;
unblock_point(gt.trapx, gt.trapy);
}
seetrap(t_at(gt.trapx, gt.trapy));
trapname(t->ttyp, FALSE));
}
/* if trap was in a concealed niche, it's no longer concealed */
reveal_trap(t, vis);
/* don't use rloc_to() because worm tails must "move" */
remove_monster(mtmp->mx, mtmp->my);
@@ -1050,12 +1070,14 @@ use_defensive(struct monst *mtmp)
return 2;
case MUSE_TELEPORT_TRAP:
m_flee(mtmp);
t = t_at(gt.trapx, gt.trapy);
if (vis) {
Mnam = Monnam(mtmp);
pline("%s %s onto a teleport trap!", Mnam,
vtense(fakename[0], locomotion(mtmp->data, "jump")));
seetrap(t_at(gt.trapx, gt.trapy));
pline("%s %s onto a %s!", Monnam(mtmp),
vtense(fakename[0], locomotion(mtmp->data, "jump")),
trapname(t->ttyp, FALSE));
}
/* if trap was in a concealed niche, it's no longer concealed */
reveal_trap(t, vis);
/* don't use rloc_to() because worm tails must "move" */
remove_monster(mtmp->mx, mtmp->my);
newsym(mtmp->mx, mtmp->my); /* update old location */
@@ -2323,9 +2345,9 @@ use_misc(struct monst *mtmp)
if (vis || vistrapspot)
seetrap(t);
if (vismon || vistrapspot) {
pline("%s deliberately %s onto a %s trap!", Some_Monnam(mtmp),
pline("%s deliberately %s onto a %s!", Some_Monnam(mtmp),
vtense(fakename[0], locomotion(mtmp->data, "jump")),
t->tseen ? "polymorph" : "hidden");
t->tseen ? trapname(t->ttyp, FALSE) : "hidden trap");
/* note: if mtmp is unseen because it is invisible, its new
shape will also be invisible and could produce "Its armor
falls off" messages during the transformation; those make