fix issue #1062 - monster hiding messages

Reported by Umbire:  if a statue of a hider-under was activated by
a statue trap, it would hide underneath its own statue.  Also, the
hero saw a snake hide under unseen submerged kelp.

Both of those things were exposed by new "you see <monster> hide"
message rather than caused by it.  It also led to the [re-]discovery
that an existing monster hiding under a statue that was a not-yet-
triggered trap prevented the trap from producing a monster.

This redoes yesterday's can't-hide-under-statue change:  hiders can
hide under statues again, but they can't hide under anything at trap
locations.  [Pits containing one or more objects are an exception,
although it seems silly that a hero is prevented from falling into
one by the presence of a tiny creepy-crawly hiding under a ring or
dart in there.]  So, hider-underers won't be able to interfere with
statue traps by being present at the trap location.  [Trappers and
lurkers-above probably need a similar restriction; I didn't look.
They avoid trap spots rather than get lured to such by objects.]

It also prevents newly created hider-underers from becoming hidden
as part of the their creation (except when that creation is part
of level creation) whether their creation uses up an object (statue
activation, egg hatching) or there are simply other items present.
That will prevent statue of a hider producing a monster that hides
under the activated statue (which was happening due to the sequence
create monster, transfer any statue contents to monster inventory,
destroy statue).

The can't-hide-under-statues code has been repurposed to prevent
hiding under gold pieces unless there are at least 10 (arbitrary
threshold) of those or they're in a pile with some other object(s).

Sea monsters hide in water regardless of the presence of objects.
Prevent other swimmers from hiding under objects at water locations.
Such creatures don't have gills and shouldn't be able to stay
submerged in hiding for an arbitrary length of time.  [No exception
is made for non-breathers.  The overlap between swimmers and hider-
underers is limited to small snakes, even though it is feasible for
a creature wearing an amulet of magical breathing to polymorph into
one.  Heros don't spend enough time underwater to worry about snakes
hiding under kelp or thrown junk.]

Lastly, alter the "suddenly, you notice a <monster>" message if
monster-vs-monster activity causes one you've just seen going into
hiding comes back out again without any intervening messages.  [I'm
not sure whether something similar is needed for the "Wait.  There's
something there" message in the you-vs-monster case.]

Fixes #1062
This commit is contained in:
PatR
2023-06-16 21:19:43 -07:00
parent 5688754684
commit bbba8b82d2
8 changed files with 113 additions and 36 deletions

View File

@@ -4203,52 +4203,74 @@ maybe_unhide_at(coordxy x, coordxy y)
(void) hideunder(mtmp);
}
/* monster/hero tries to hide under something at the current location */
/* monster/hero tries to hide under something at the current location;
if used by monster creation, should only happen during during level
creation, otherwise there will be message sequencing issues */
boolean
hideunder(struct monst *mtmp)
{
struct trap *t;
struct obj *otmp;
const char *seenmon = (char *) 0, *seenobj = (char *) 0;
int seeit = canseemon(mtmp);
int seeit = gi.in_mklev ? 0 : canseemon(mtmp);
boolean oldundetctd, undetected = FALSE, is_u = (mtmp == &gy.youmonst);
coordxy x = is_u ? u.ux : mtmp->mx, y = is_u ? u.uy : mtmp->my;
struct obj *otmp;
if (mtmp == u.ustuck) {
; /* undetected==FALSE; can't hide if holding you or held by you */
} else if (is_u ? (u.utrap && u.utraptype != TT_PIT)
: (mtmp->mtrapped
&& (t = t_at(x, y)) != 0 && !is_pit(t->ttyp))) {
; /* undetected==FALSE; can't hide while stuck in a non-pit trap */
} else if ((is_u ? u.utrap : mtmp->mtrapped)
|| ((t = t_at(x, y)) != 0 && !is_pit(t->ttyp))) {
; /* undetected==FALSE; can't hide while trapped or on/in/under
any non-pit trap when not trapped */
} else if (mtmp->data->mlet == S_EEL) {
undetected = (is_pool(x, y) && !Is_waterlevel(&u.uz));
/* aquatic creatures only hide under water, not under objects;
they don't do so on the Plane of Water or when hero is also
under water unless some obstacle blocks line-of-sight */
undetected = (is_pool(x, y) && !Is_waterlevel(&u.uz)
&& (!Underwater || !couldsee(x, y)));
if (seeit)
seenobj = "the water";
} else if (hides_under(mtmp->data) && OBJ_AT(x, y)
&& (otmp = gl.level.objects[x][y]) != 0 && can_hide_under_obj(otmp)) {
if (seeit)
} else if (hides_under(mtmp->data)
/* hider-underers only hide under objects */
&& (otmp = gl.level.objects[x][y]) != 0
/* most things can be hidden under, but not all */
&& can_hide_under_obj(otmp)
/* aquatic creatures don't reach here; other swimmers
shouldn't hide beneath underwater objects */
&& !is_pool_or_lava(x, y)) {
if (seeit) /*&& (!is_pool(x, y) || (Underwater && distu(x, y) <= 2))*/
seenobj = ansimpleoname(otmp);
/* most monsters won't hide under cockatrice corpse but they
/* most monsters won't hide under a cockatrice corpse but they
can hide under a pile containing more than just such corpses */
while (otmp && otmp->otyp == CORPSE
&& touch_petrifies(&mons[otmp->corpsenm]))
otmp = otmp->nexthere;
if (otmp != 0 || ((mtmp == &gy.youmonst) ? Stone_resistance
: resists_ston(mtmp)))
if (is_u ? !Stone_resistance : !resists_ston(mtmp))
while (otmp && otmp->otyp == CORPSE
&& touch_petrifies(&mons[otmp->corpsenm]))
otmp = otmp->nexthere;
if (otmp)
undetected = TRUE;
}
if (is_u) {
oldundetctd = u.uundetected != 0;
u.uundetected = undetected ? 1 : 0;
#if 0 /* feedback handled via #monster */
if (undetected && !oldundeteced && seenobj)
You("hide under %s.", seenobj);
#endif
} else {
if (seeit)
seenmon = y_monnam(mtmp);
oldundetctd = mtmp->mundetected != 0;
mtmp->mundetected = undetected ? 1 : 0;
if (undetected && seenmon && seenobj)
/* the "you see" message won't be shown for monster hiding during
level creation because 'seeit' will be 0 so 'seenmon' and 'seenobj'
will be Null */
if (undetected && seenmon && seenobj) {
You_see("%s %s under %s.", seenmon,
locomotion(mtmp->data, "hide"), seenobj);
iflags.last_msg = PLNMSG_HIDE_UNDER;
gl.last_hider = mtmp->m_id;
}
}
if (undetected != oldundetctd)
newsym(x, y);