github issue #1299 - sleeping mimics

Issue reported by elunna:  sleeping mimics can grab the hero, and
zapping a concealed mimic with a wand of sleep describes the target
as a mimic but doesn't bring it out of concealment.

The grab-when-asleep case is reasonable.  It's a reflexive counter-
attack by a magical creature.  And the mimic wakes up in the process.
But the mimic wasn't being brought out of concealment.  Do that.

Unconceal mimics hit by wand of sleep unless already sleeping.

Fixes #1299
This commit is contained in:
PatR
2024-11-29 23:30:04 -08:00
parent 689f6c4c82
commit 149cb96020
5 changed files with 77 additions and 26 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 mhitm.c $NHDT-Date: 1698939796 2023/11/02 15:43:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.244 $ */
/* NetHack 3.7 mhitm.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.253 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1209,6 +1209,12 @@ paralyze_monst(struct monst *mon, int amt)
int
sleep_monst(struct monst *mon, int amt, int how)
{
/* reveal mimic unless already asleep or paralyzed (won't be 'busy') */
if (how >= 0 && !mon->msleeping && !mon->mfrozen
&& mon->data->mlet == S_MIMIC && (M_AP_TYPE(mon) == M_AP_FURNITURE
|| M_AP_TYPE(mon) == M_AP_OBJECT))
seemimic(mon);
if (resists_sleep(mon) || defended(mon, AD_SLEE)
|| (how >= 0 && resist(mon, (char) how, 0, NOTELL))) {
shieldeff(mon->mx, mon->my);

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 objnam.c $NHDT-Date: 1711809641 2024/03/30 14:40:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.427 $ */
/* NetHack 3.7 objnam.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.439 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */
@@ -2475,7 +2475,7 @@ static const char wrpsym[] = { WAND_CLASS, RING_CLASS, POTION_CLASS,
/* return form of the verb (input plural) if xname(otmp) were the subject */
char *
otense(struct obj* otmp,const char * verb)
otense(struct obj *otmp, const char *verb)
{
char *buf;

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 pager.c $NHDT-Date: 1724094301 2024/08/19 19:05:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.279 $ */
/* NetHack 3.7 pager.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.282 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2018. */
/* NetHack may be freely redistributed. See license for details. */
@@ -280,7 +280,10 @@ mhidden_description(
/* extracted from lookat(); also used by namefloorobj() */
boolean
object_from_map(int glyph, coordxy x, coordxy y, struct obj **obj_p)
object_from_map(
int glyph,
coordxy x, coordxy y,
struct obj **obj_p)
{
boolean fakeobj = FALSE, mimic_obj = FALSE;
struct monst *mtmp;
@@ -305,8 +308,10 @@ object_from_map(int glyph, coordxy x, coordxy y, struct obj **obj_p)
if (!otmp || otmp->otyp != glyphotyp) {
/* this used to exclude STRANGE_OBJECT; now caller deals with it */
otmp = mksobj(glyphotyp, FALSE, FALSE);
if (!otmp)
return FALSE;
/* even though we pass False for mksobj()'s 'init' arg, corpse-rot,
egg-hatch, and figurine-transform timers get initialized */
if (otmp->timed)
obj_stop_timers(otmp);
fakeobj = TRUE;
if (otmp->oclass == COIN_CLASS)
otmp->quan = 2L; /* to force pluralization */

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 uhitm.c $NHDT-Date: 1713334817 2024/04/17 06:20:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.444 $ */
/* NetHack 3.7 uhitm.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.451 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
@@ -6030,8 +6030,11 @@ DISABLE_WARNING_FORMAT_NONLITERAL
void
stumble_onto_mimic(struct monst *mtmp)
{
const char *fmt = "Wait! That's %s!", *generic = "a monster", *what = 0;
static char generic[] = "a monster";
char fmt[QBUFSZ];
const char *what = NULL;
Strcpy(fmt, "Wait! That's %s!");
if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK)
/* must be adjacent; attack via polearm could be from farther away */
&& m_next2u(mtmp))
@@ -6045,16 +6048,39 @@ stumble_onto_mimic(struct monst *mtmp)
} else {
int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph;
if (glyph_is_cmap(glyph) && (glyph_to_cmap(glyph) == S_hcdoor
|| glyph_to_cmap(glyph) == S_vcdoor))
fmt = "The door actually was %s!";
else if (glyph_is_object(glyph) && glyph_to_obj(glyph) == GOLD_PIECE)
fmt = "That gold was %s!";
if (glyph_is_cmap(glyph)) {
Sprintf(fmt, "%s %s actually is %%s!",
is_cmap_stairs(glyph) ? "Those" : "That",
defsyms[mtmp->mappearance].explanation);
/* BUG: this will misclassify a paralyzed mimic as sleeping */
what = x_monnam(mtmp, ARTICLE_A, "sleeping", 0, FALSE);
} else if (glyph_is_object(glyph)) {
boolean fakeobj;
const char *otmp_name;
struct obj *otmp = NULL;
fakeobj = object_from_map(glyph, mtmp->mx, mtmp->my, &otmp);
otmp_name = (otmp && otmp->otyp != STRANGE_OBJECT)
? simpleonames(otmp) : "strange object";
Sprintf(fmt, "%s %s %s %%s!",
otmp && is_plural(otmp) ? "Those" : "That",
otmp_name, otmp ? otense(otmp, "are") : "is");
if (fakeobj && otmp) {
otmp->where = OBJ_FREE; /* object_from_map set to OBJ_FLOOR */
dealloc_obj(otmp);
}
}
/* cloned Wiz starts out mimicking some other monster and
might make himself invisible before being revealed */
if (mtmp->minvis && !See_invisible)
what = generic;
else if (mtmp->data->mlet == S_MIMIC
&& (M_AP_TYPE(mtmp) == M_AP_OBJECT
|| M_AP_TYPE(mtmp) == M_AP_FURNITURE)
&& (mtmp->msleeping || mtmp->mfrozen))
/* BUG: this will misclassify a paralyzed mimic as sleeping */
what = x_monnam(mtmp, ARTICLE_A, "sleeping", 0, FALSE);
else
what = a_monnam(mtmp);
}

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 zap.c $NHDT-Date: 1723946858 2024/08/18 02:07:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.542 $ */
/* NetHack 3.7 zap.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.551 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */
@@ -148,7 +148,11 @@ learnwand(struct obj *obj)
}
}
/* Routines for IMMEDIATE wands and spells. */
/*
* Routines for IMMEDIATE wands and spells.
* Also RAY or NODIR for wands that are being broken rather than zapped.
*/
/* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
int
bhitm(struct monst *mtmp, struct obj *otmp)
@@ -350,6 +354,10 @@ bhitm(struct monst *mtmp, struct obj *otmp)
}
case WAN_LOCKING:
case SPE_WIZARD_LOCK:
/* can't use Is_box() here */
if (disguised_mimic && (is_obj_mappear(mtmp, CHEST)
|| is_obj_mappear(mtmp, LARGE_BOX)))
seemimic(mtmp);
wake = closeholdingtrap(mtmp, &learn_it);
break;
case WAN_PROBING:
@@ -360,6 +368,9 @@ bhitm(struct monst *mtmp, struct obj *otmp)
break;
case WAN_OPENING:
case SPE_KNOCK:
if (disguised_mimic && (is_obj_mappear(mtmp, CHEST)
|| is_obj_mappear(mtmp, LARGE_BOX)))
seemimic(mtmp);
wake = FALSE; /* don't want immediate counterattack */
if (mtmp == u.ustuck) {
/* zapping either holder/holdee or self [zapyourself()] will
@@ -450,7 +461,8 @@ bhitm(struct monst *mtmp, struct obj *otmp)
break;
case WAN_SLEEP: /* (broken wand) */
/* [wakeup() doesn't rouse victims of temporary sleep,
so it's okay to leave `wake' set to TRUE here] */
so it's okay to leave `wake' set to TRUE here;
revealing concealed mimic is handled by sleep_monst()] */
reveal_invis = TRUE;
if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS))
slept_monst(mtmp);
@@ -458,6 +470,8 @@ bhitm(struct monst *mtmp, struct obj *otmp)
learn_it = TRUE;
break;
case SPE_STONE_TO_FLESH:
/* FIXME: mimics disguished as stone furniture or stone object
should be taken out of concealment. */
if (monsndx(mtmp->data) == PM_STONE_GOLEM) {
char *name = Monnam(mtmp);
@@ -3491,7 +3505,8 @@ exclam(int force)
}
void
hit(const char *str, /* zap text or missile name */
hit(
const char *str, /* zap text or missile name */
struct monst *mtmp, /* target; for missile, might be hero */
const char *force) /* usually either "." or "!" via exclam() */
{
@@ -3500,11 +3515,8 @@ hit(const char *str, /* zap text or missile name */
&& (cansee(gb.bhitpos.x, gb.bhitpos.y)
|| canspotmon(mtmp) || engulfing_u(mtmp))));
if (!verbosely)
pline("%s %s it.", The(str), vtense(str, "hit"));
else
pline("%s %s %s%s", The(str), vtense(str, "hit"),
mon_nam(mtmp), force);
pline("%s %s %s%s", The(str), vtense(str, "hit"),
verbosely ? mon_nam(mtmp) : "it", force);
}
void
@@ -4209,7 +4221,8 @@ zhitm(
tmp += destroy_items(mon, AD_COLD, orig_dmg);
break;
case ZT_SLEEP:
/* possibly resistance and shield effect handled by sleep_monst() */
/* resistance and shield effect and revealing concealed mimic are
handled by sleep_monst() */
tmp = 0;
(void) sleep_monst(mon, d(nd, 25),
type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
@@ -4576,8 +4589,9 @@ burn_floor_objects(
/* will zap/spell/breath attack score a hit against armor class `ac'? */
staticfn int
zap_hit(int ac,
int type) /* either hero cast spell type or 0 */
zap_hit(
int ac,
int type) /* either hero cast spell type or 0 */
{
int chance = rn2(20);
int spell_bonus = type ? spell_hit_bonus(type) : 0;