mon name of monster appearing as another monster

When a monster mimicks another monster (traditionally Double Trouble
Wizard, since 3.6.x also pet that eats a mimic corpse), using farlook
or getpos+autodescribe revealed the monster's real identity.  Hard to
believe that nobody ever noticed, but it was obvious when a pet dog
quick-mimicked a cat or vice versa.

Add an extra x_monnam() flag to ignore monst->m_ap_type==M_AP_MONSTER
plus monst->mappearance.  Only the m_monnam() variation of x_monnam()
includes it (via EXACT_NAME); monnam() and the rest will now describe
an M_AP_MONSTER by its appearance rather than as its true self.
This commit is contained in:
PatR
2024-04-17 14:40:20 -07:00
parent 7198981afd
commit 064523e162
2 changed files with 32 additions and 13 deletions
+7 -6
View File
@@ -942,13 +942,14 @@ typedef struct {
#define ARTICLE_YOUR 3 #define ARTICLE_YOUR 3
/* x_monnam() monster name suppress masks */ /* x_monnam() monster name suppress masks */
#define SUPPRESS_IT 0x01 #define SUPPRESS_IT 0x01
#define SUPPRESS_INVISIBLE 0x02 #define SUPPRESS_INVISIBLE 0x02
#define SUPPRESS_HALLUCINATION 0x04 #define SUPPRESS_HALLUCINATION 0x04
#define SUPPRESS_SADDLE 0x08 #define SUPPRESS_SADDLE 0x08
#define EXACT_NAME 0x0F #define SUPPRESS_MAPPEARANCE 0x10
#define SUPPRESS_NAME 0x10 #define EXACT_NAME 0x1F
#define AUGMENT_IT 0x20 /* use "someone" or "something" instead of "it" */ #define SUPPRESS_NAME 0x20
#define AUGMENT_IT 0x40 /* use "someone" or "something" instead of "it" */
/* pline (et al) for a single string argument (suppress compiler warning) */ /* pline (et al) for a single string argument (suppress compiler warning) */
#define pline1(cstr) pline("%s", cstr) #define pline1(cstr) pline("%s", cstr)
+25 -7
View File
@@ -807,8 +807,14 @@ rndghostname(void)
* suppress * suppress
* *
* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE. * SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
* SUPPRESS_MAPPEARANCE: if monster is mimicking another monster (cloned
* Wizard or quickmimic pet), describe the real monster rather
* than its current form;
* EXACT_NAME: combination of all the above * EXACT_NAME: combination of all the above
* SUPPRESS_NAME: omit monster's assigned name (unless uniq w/ pname). * SUPPRESS_NAME: omit monster's assigned name (unless uniq w/ pname).
* AUGMENT_IT: not suppression but shares suppression bitmask; if result
* would have been "it", return "someone" if humanoid or
* "something" otherwise.
* *
* Bug: if the monster is a priest or shopkeeper, not every one of these * Bug: if the monster is a priest or shopkeeper, not every one of these
* options works, since those are special cases. * options works, since those are special cases.
@@ -823,9 +829,11 @@ x_monnam(
{ {
char *buf = nextmbuf(); char *buf = nextmbuf();
struct permonst *mdat = mtmp->data; struct permonst *mdat = mtmp->data;
const char *pm_name = mon_pmname(mtmp); const char *pm_name;
boolean do_hallu, do_invis, do_it, do_saddle, do_name, augment_it; boolean do_hallu, do_invis, do_it, do_saddle, do_mappear,
boolean name_at_start, has_adjectives, insertbuf2; do_exact, do_name, augment_it;
boolean name_at_start, has_adjectives, insertbuf2,
mappear_as_mon = (M_AP_TYPE(mtmp) == M_AP_MONSTER);
char *bp, buf2[BUFSZ]; char *bp, buf2[BUFSZ];
if (mtmp == &gy.youmonst) if (mtmp == &gy.youmonst)
@@ -852,6 +860,8 @@ x_monnam(
&& !gp.program_state.gameover && mtmp != u.usteed && !gp.program_state.gameover && mtmp != u.usteed
&& !engulfing_u(mtmp) && !(suppress & SUPPRESS_IT); && !engulfing_u(mtmp) && !(suppress & SUPPRESS_IT);
do_saddle = !(suppress & SUPPRESS_SADDLE); do_saddle = !(suppress & SUPPRESS_SADDLE);
do_mappear = mappear_as_mon && !(suppress & SUPPRESS_MAPPEARANCE);
do_exact = (suppress & EXACT_NAME) == EXACT_NAME;
do_name = !(suppress & SUPPRESS_NAME) || type_is_pname(mdat); do_name = !(suppress & SUPPRESS_NAME) || type_is_pname(mdat);
augment_it = (suppress & AUGMENT_IT) != 0; augment_it = (suppress & AUGMENT_IT) != 0;
@@ -867,7 +877,7 @@ x_monnam(
} }
/* priests and minions: don't even use this function */ /* priests and minions: don't even use this function */
if (mtmp->ispriest || mtmp->isminion) { if ((mtmp->ispriest || mtmp->isminion) && !do_mappear) {
char *name; char *name;
long save_prop = EHalluc_resistance; long save_prop = EHalluc_resistance;
unsigned save_invis = mtmp->minvis; unsigned save_invis = mtmp->minvis;
@@ -878,8 +888,7 @@ x_monnam(
if (!do_invis) if (!do_invis)
mtmp->minvis = 0; mtmp->minvis = 0;
/* EXACT_NAME will force "of <deity>" on the Astral Plane */ /* EXACT_NAME will force "of <deity>" on the Astral Plane */
name = priestname(mtmp, article, name = priestname(mtmp, article, do_exact, buf2);
((suppress & EXACT_NAME) == EXACT_NAME), buf2);
EHalluc_resistance = save_prop; EHalluc_resistance = save_prop;
mtmp->minvis = save_invis; mtmp->minvis = save_invis;
if (article == ARTICLE_NONE && !strncmp(name, "the ", 4)) if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
@@ -887,12 +896,21 @@ x_monnam(
return strcpy(buf, name); return strcpy(buf, name);
} }
/* 'pm_name' is the base part of the name */
if (do_mappear) {
assert(ismnum(mtmp->mappearance));
pm_name = pmname(&mons[mtmp->mappearance],
mtmp->female ? FEMALE : MALE);
} else {
pm_name = mon_pmname(mtmp);
}
/* Shopkeepers: use shopkeeper name. For normal shopkeepers, just /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
* "Asidonhopo"; for unusual ones, "Asidonhopo the invisible * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
* shopkeeper" or "Asidonhopo the blue dragon". If hallucinating, * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
* none of this applies. * none of this applies.
*/ */
if (mtmp->isshk && !do_hallu) { if (mtmp->isshk && !do_hallu && !do_mappear) {
if (adjective && article == ARTICLE_THE) { if (adjective && article == ARTICLE_THE) {
/* pathological case: "the angry Asidonhopo the blue dragon" /* pathological case: "the angry Asidonhopo the blue dragon"
sounds silly */ sounds silly */