diff --git a/include/extern.h b/include/extern.h index 5a4dffa45..5886eb0c0 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1624,6 +1624,8 @@ extern void costly_alteration(struct obj *, int) NONNULLARG1; extern void clear_dknown(struct obj *); extern void unknow_object(struct obj *); extern struct obj *mksobj(int, boolean, boolean) NONNULL; +extern boolean stone_object_type(unsigned); +extern boolean stone_furniture_type(unsigned); extern int bcsign(struct obj *) NONNULLARG1; extern int weight(struct obj *) NONNULLARG1; extern struct obj *mkgold(long, coordxy, coordxy); @@ -3385,7 +3387,7 @@ extern boolean mhitm_knockback(struct monst *, struct monst *,struct attack *, extern int passive(struct monst *, struct obj *, boolean, boolean, uchar, boolean) NONNULLARG1; extern void passive_obj(struct monst *, struct obj *, struct attack *) NONNULLARG1; -extern void that_is_a_mimic(struct monst *, boolean) NONNULLARG1; +extern void that_is_a_mimic(struct monst *, unsigned) NONNULLARG1; extern void stumble_onto_mimic(struct monst *) NONNULLARG1; extern int flash_hits_mon(struct monst *, struct obj *) NONNULLARG12; extern void light_hits_gremlin(struct monst *, int) NONNULLARG1; diff --git a/include/hack.h b/include/hack.h index c97aff6af..bf50ff3d9 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1155,6 +1155,10 @@ typedef uint32_t mmflags_nht; /* makemon MM_ flags */ #define MHID_ALTMON 4 /* if mimicking a monster, include that */ #define MHID_REGION 8 /* include region when mon is in one */ +/* flags for that_is_a_mimic() */ +#define MIM_REVEAL 1 /* seemimic() */ +#define MIM_OMIT_WAIT 2 /* strip beginning from "Wait! That is a " */ + /* flags for make_corpse() and mkcorpstat(); 0..7 are recorded in obj->spe */ #define CORPSTAT_NONE 0x00 #define CORPSTAT_GENDER 0x03 /* 0x01 | 0x02 */ diff --git a/src/mkobj.c b/src/mkobj.c index c6d65e9c0..bece8cd44 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1251,6 +1251,42 @@ mksobj(int otyp, boolean init, boolean artif) return otmp; } +/* potential mimic shapes that should be undone by stone-to-flesh; + not used for objects that will be transformed when hit by stone-to-flesh */ +boolean +stone_object_type(unsigned mappearance) +{ + int otyp = (int) mappearance; + + /* we exclude wands, rings, and gems even though some qualify as stone; + there aren't any weapons or armor classified as made out of stone */ + return (otyp == BOULDER || otyp == STATUE || otyp == FIGURINE); +} + +/* possible mimic shapes that are affected by stone-to-flesh; + mappearance for furniture is a display symbol rather than a terrain type */ +boolean +stone_furniture_type(unsigned mappearance) +{ + int sym = (int) mappearance; + + switch (sym) { + case S_upstair: + case S_dnstair: + case S_brupstair: + case S_brdnstair: + case S_altar: + case S_throne: + case S_sink: /* stone sink is iffy; metal might be more appropriate */ + return TRUE; + default: + if (sym >= S_vwall && sym <= S_trwall) + return TRUE; + break; + } + return FALSE; +} + /* * Several areas of the code made direct reassignments * to obj->corpsenm. Because some special handling is diff --git a/src/uhitm.c b/src/uhitm.c index fecd46228..ced52abc5 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6103,11 +6103,13 @@ DISABLE_WARNING_FORMAT_NONLITERAL void that_is_a_mimic( struct monst *mtmp, /* a hidden mimic (nonnull) */ - boolean reveal_it) /* True: remove its disguise */ + unsigned mimic_flags) /* 0, MIM_REVEAL, MIM_OMIT_WAIT, REVEAL+OMIT */ { static char generic[] = "a monster"; char fmtbuf[BUFSZ]; const char *what = NULL; + boolean reveal_it = (mimic_flags & MIM_REVEAL) != 0, + omit_wait = (mimic_flags & MIM_OMIT_WAIT) != 0; Strcpy(fmtbuf, "Wait! That's %s!"); if (Blind) { @@ -6116,7 +6118,7 @@ that_is_a_mimic( else if (M_AP_TYPE(mtmp) == M_AP_MONSTER) what = a_monnam(mtmp); /* differs from what was sensed */ } else { - coordxy x = u.ux + u.dx, y = u.uy + u.dy; + coordxy x = mtmp->mx, y = mtmp->my; int glyph = glyph_at(x, y); if (glyph_is_cmap(glyph)) { @@ -6167,8 +6169,11 @@ that_is_a_mimic( what = a_monnam(mtmp); } - if (what) - pline(fmtbuf, what); + if (what) { + int i = (omit_wait && !strncmp(fmtbuf, "Wait! ", 7)) ? 7 : 0; + + pline(&fmtbuf[i], what); + } if (reveal_it) seemimic(mtmp); } @@ -6179,7 +6184,7 @@ RESTORE_WARNING_FORMAT_NONLITERAL void stumble_onto_mimic(struct monst *mtmp) { - that_is_a_mimic(mtmp, TRUE); + that_is_a_mimic(mtmp, MIM_REVEAL); if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK) /* must be adjacent; attack via polearm could be from farther away */ diff --git a/src/zap.c b/src/zap.c index 7118ca4da..e1d199035 100644 --- a/src/zap.c +++ b/src/zap.c @@ -365,7 +365,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) case WAN_LOCKING: case SPE_WIZARD_LOCK: if (disguised_mimic && box_or_door(mtmp)) - that_is_a_mimic(mtmp, TRUE); /*seemimic()*/ + that_is_a_mimic(mtmp, MIM_REVEAL); /*seemimic()*/ wake = closeholdingtrap(mtmp, &learn_it); break; case WAN_PROBING: @@ -377,7 +377,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) case WAN_OPENING: case SPE_KNOCK: if (disguised_mimic && box_or_door(mtmp)) - that_is_a_mimic(mtmp, TRUE); /*seemimic()*/ + that_is_a_mimic(mtmp, MIM_REVEAL); /*seemimic()*/ wake = FALSE; /* don't want immediate counterattack */ if (mtmp == u.ustuck) { /* zapping either holder/holdee or self [zapyourself()] will @@ -483,21 +483,35 @@ 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); + if (mtmp->data->mlet == S_GOLEM) { + const char *mesg; + char *name = Monnam(mtmp); /* before possible polymorph */ - /* turn into flesh golem */ - if (newcham(mtmp, &mons[PM_FLESH_GOLEM], NO_NC_FLAGS)) { - if (canseemon(mtmp)) - pline("%s turns to flesh!", name); - } else { - if (canseemon(mtmp)) - pline("%s looks rather fleshy for a moment.", name); + /* turn stone golem into flesh golem */ + if (monsndx(mtmp->data) == PM_STONE_GOLEM + && newcham(mtmp, &mons[PM_FLESH_GOLEM], NO_NC_FLAGS)) + mesg = "turns to flesh!"; + else if (monsndx(mtmp->data) == PM_FLESH_GOLEM) + mesg = "seems fleshier..."; + else + mesg = "looks rather fleshy for a moment."; + + if (canseemon(mtmp)) + pline("%s %s", name, mesg); + } else if (mtmp->data->mlet == S_MIMIC + && ((M_AP_TYPE(mtmp) == M_AP_FURNITURE + && stone_furniture_type(mtmp->mappearance)) + || (M_AP_TYPE(mtmp) == M_AP_OBJECT + && stone_object_type(mtmp->mappearance)))) { + /* note: if that_is_a_mimic() doesn't get called to reveal the + mimic, wakeup() below will call seemimic() */ + if (cansee(mtmp->mx, mtmp->my)) { + set_msg_xy(mtmp->mx, mtmp->my); + that_is_a_mimic(mtmp, MIM_REVEAL | MIM_OMIT_WAIT); } - } else + } else { wake = FALSE; + } break; case SPE_DRAIN_LIFE: if (disguised_mimic) @@ -530,22 +544,19 @@ bhitm(struct monst *mtmp, struct obj *otmp) impossible("What an interesting effect (%d)", otyp); break; } - if (wake) { - if (!DEADMONSTER(mtmp)) { - wakeup(mtmp, helpful_gesture ? FALSE : TRUE); - m_respond(mtmp); - if (mtmp->isshk && !*u.ushops) - hot_pursuit(mtmp); - } else if (M_AP_TYPE(mtmp)) - seemimic(mtmp); /* might unblock if mimicking a boulder/door */ + if (wake && !DEADMONSTER(mtmp)) { + /* seemimic() is done by wakeup() and might unblock vision */ + wakeup(mtmp, helpful_gesture ? FALSE : TRUE); + m_respond(mtmp); + if (mtmp->isshk && !*u.ushops) + hot_pursuit(mtmp); } /* note: gb.bhitpos won't be set if swallowed, but that's okay since * reveal_invis will be false. We can't use mtmp->mx, my since it * might be an invisible worm hit on the tail. */ - if (reveal_invis) { - if (!DEADMONSTER(mtmp) && cansee(gb.bhitpos.x, gb.bhitpos.y) - && !canspotmon(mtmp)) + if (reveal_invis && !DEADMONSTER(mtmp)) { + if (cansee(gb.bhitpos.x, gb.bhitpos.y) && !canspotmon(mtmp)) map_invisible(gb.bhitpos.x, gb.bhitpos.y); } /* if effect was observable then discover the wand type provided