hearing an unseen monster read a scroll

Heroes recognized unseen same-race monsters by voice, but it yielded
an unexpected result if the monster was unique.  Change it so that
hero will recognize any type of monster by its voice if that monster
has been seen and limit unseen same-race ones to non-unique monsters.
Treats shopkeepers as unique since they have distinct names.

This adds a new flag to struct monst in order to track whether each
specific monster has ever been seen or sensed.
This commit is contained in:
PatR
2023-04-22 02:00:04 -07:00
parent 861fcdf9c4
commit 85a002c157
5 changed files with 61 additions and 31 deletions
+1 -1
View File
@@ -156,7 +156,7 @@ struct monst {
Bitfield(iswiz, 1); /* is the Wizard of Yendor */ Bitfield(iswiz, 1); /* is the Wizard of Yendor */
Bitfield(wormno, 5); /* at most 31 worms on any level */ Bitfield(wormno, 5); /* at most 31 worms on any level */
Bitfield(mtemplit, 1); /* temporarily seen; only valid during bhit() */ Bitfield(mtemplit, 1); /* temporarily seen; only valid during bhit() */
/* 1 free bit */ Bitfield(meverseen, 1); /* mon has been seen at some point */
#define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */ #define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */
+35 -22
View File
@@ -502,22 +502,24 @@ show_mon_or_warn(coordxy x, coordxy y, int monglyph)
* *
*/ */
static void static void
display_monster(coordxy x, coordxy y, /* display position */ display_monster(
struct monst *mon, /* monster to display */ coordxy x, coordxy y, /* display position */
int sightflags, /* 1 if the monster is physically seen; struct monst *mon, /* monster to display */
2 if detected using Detect_monsters */ int sightflags, /* 1 if the monster is physically seen;
boolean worm_tail) /* mon is actually a worm tail */ * 2 if detected using Detect_monsters */
boolean worm_tail) /* mon is actually a worm tail */
{ {
boolean mon_mimic = (M_AP_TYPE(mon) != M_AP_NOTHING); boolean mon_mimic = (M_AP_TYPE(mon) != M_AP_NOTHING);
int sensed = (mon_mimic && (Protection_from_shape_changers int sensed = (mon_mimic && (Protection_from_shape_changers
|| sensemon(mon))); || sensemon(mon))),
mgendercode = mon->female ? FEMALE : MALE;
/* /*
* We must do the mimic check first. If the mimic is mimicing something, * We must do the mimic check first. If the mimic is mimicing something,
* and the location is in sight, we have to change the hero's memory * and the location is in sight, we have to change the hero's memory
* so that when the position is out of sight, the hero remembers what * so that when the position is out of sight, the hero remembers what
* the mimic was mimicing. * the mimic was mimicing.
*/ */
if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) { if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) {
switch (M_AP_TYPE(mon)) { switch (M_AP_TYPE(mon)) {
default: default:
@@ -563,13 +565,13 @@ display_monster(coordxy x, coordxy y, /* display position */
break; break;
} }
case M_AP_MONSTER: case M_AP_MONSTER: {
show_glyph(x, y, int mndx = what_mon((int) mon->mappearance, rn2_on_display_rng);
monnum_to_glyph(what_mon((int) mon->mappearance,
rn2_on_display_rng), show_glyph(x, y, monnum_to_glyph(mndx, mgendercode));
mon->female ? FEMALE : MALE));
break; break;
} } /* case M_AP_MONSTER */
} /* switch M_AP_TYPE() */
} }
/* If mimic is unsuccessfully mimicing something, display the monster. */ /* If mimic is unsuccessfully mimicing something, display the monster. */
@@ -586,26 +588,26 @@ display_monster(coordxy x, coordxy y, /* display position */
*/ */
if (mon->mtame && !Hallucination) { if (mon->mtame && !Hallucination) {
if (worm_tail) if (worm_tail)
num = petnum_to_glyph(PM_LONG_WORM_TAIL, num = petnum_to_glyph(PM_LONG_WORM_TAIL, mgendercode);
mon->female ? FEMALE : MALE);
else else
num = pet_to_glyph(mon, rn2_on_display_rng); num = pet_to_glyph(mon, rn2_on_display_rng);
} else if (sightflags == DETECTED) { } else if (sightflags == DETECTED) {
if (worm_tail) if (worm_tail)
num = detected_monnum_to_glyph( num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL,
what_mon(PM_LONG_WORM_TAIL, rn2_on_display_rng), rn2_on_display_rng),
mon->female ? FEMALE : MALE); mgendercode);
else else
num = detected_mon_to_glyph(mon, rn2_on_display_rng); num = detected_mon_to_glyph(mon, rn2_on_display_rng);
} else { } else {
if (worm_tail) if (worm_tail)
num = monnum_to_glyph( num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL,
what_mon(PM_LONG_WORM_TAIL, rn2_on_display_rng), rn2_on_display_rng),
mon->female ? FEMALE : MALE); mgendercode);
else else
num = mon_to_glyph(mon, rn2_on_display_rng); num = mon_to_glyph(mon, rn2_on_display_rng);
} }
show_mon_or_warn(x, y, num); show_mon_or_warn(x, y, num);
mon->meverseen = 1;
} }
} }
@@ -1405,13 +1407,24 @@ see_monsters(void)
if (gd.defer_see_monsters) if (gd.defer_see_monsters)
return; return;
/* steed and unseen engulfer/holder/holdee are recognized via touch
even if they don't aren't going to be rendered; other monsters
may get flagged as having been seen by display_monster() if it's
called by newsym() */
if (u.usteed)
u.usteed->meverseen = 1;
if (u.ustuck)
u.ustuck->meverseen = 1;
/* loop through level.monsters (aka fmon) */
for (mon = fmon; mon; mon = mon->nmon) { for (mon = fmon; mon; mon = mon->nmon) {
if (DEADMONSTER(mon)) if (DEADMONSTER(mon))
continue; continue;
newsym(mon->mx, mon->my); newsym(mon->mx, mon->my);
if (mon->wormno) if (mon->wormno)
see_wsegs(mon); see_wsegs(mon);
if (Warn_of_mon && (gc.context.warntype.obj & mon->data->mflags2) != 0L) if (Warn_of_mon
&& (gc.context.warntype.obj & mon->data->mflags2) != 0L)
new_warn_obj_cnt++; new_warn_obj_cnt++;
} }
+2
View File
@@ -4822,6 +4822,8 @@ newcham(
place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my); place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my);
} }
mtmp->meverseen = 0; /* never seen mon in present shape; newsym() ->
* display_monster() may change it right back */
newsym(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my);
if (msg) { if (msg) {
+13 -8
View File
@@ -240,15 +240,20 @@ mreadmsg(struct monst *mtmp, struct obj *otmp)
if (vismon) { if (vismon) {
/* directly see the monster reading the scroll */ /* directly see the monster reading the scroll */
pline("%s reads %s!", Monnam(mtmp), onambuf); pline("%s reads %s!", Monnam(mtmp), onambuf);
} else { } else { /* !Deaf, otherwise we wouldn't reach here */
char blindbuf[BUFSZ]; char blindbuf[BUFSZ];
boolean similar = same_race(gy.youmonst.data, mtmp->data),
boolean m_is_like_u = (!Hallucination uniqmon = ((mtmp->data->geno & G_UNIQ) != 0
&& same_race(gy.youmonst.data, mtmp->data)); /* shopkeepers aren't unique monsters but since
/* describe the unseen monster accurately if it is similar to the they have distinct names, treat them as such */
hero's current form (unless hallucinating), else use "someone" */ || mtmp->isshk),
recognize = (!Hallucination
&& (mtmp->meverseen || (similar && !uniqmon)));
/* describe unseen monster accurately when not hallucinating if it
has ever been seen or is the same race as the hero (not yet seen
unique monsters excepted) */
int mflags = (SUPPRESS_INVISIBLE | SUPPRESS_SADDLE int mflags = (SUPPRESS_INVISIBLE | SUPPRESS_SADDLE
| (m_is_like_u ? SUPPRESS_IT : AUGMENT_IT)); | (recognize ? SUPPRESS_IT : AUGMENT_IT));
/* monster can't be seen; hero might be blind or monster might /* monster can't be seen; hero might be blind or monster might
be at a spot that isn't in view or might be invisible; remember be at a spot that isn't in view or might be invisible; remember
@@ -263,7 +268,7 @@ mreadmsg(struct monst *mtmp, struct obj *otmp)
x_monnam(mtmp, ARTICLE_A, (char *) 0, mflags, FALSE), x_monnam(mtmp, ARTICLE_A, (char *) 0, mflags, FALSE),
blindbuf); blindbuf);
} }
if (mtmp->mconf) if (mtmp->mconf) /* (note: won't get if not seen and hero can't hear) */
pline("Being confused, %s mispronounces the magic words...", pline("Being confused, %s mispronounces the magic words...",
vismon ? mon_nam(mtmp) : mhe(mtmp)); vismon ? mon_nam(mtmp) : mhe(mtmp));
} }
+10
View File
@@ -1002,6 +1002,8 @@ recharge(struct obj* obj, int curse_bless)
static void static void
forget(int howmuch) forget(int howmuch)
{ {
struct monst *mtmp;
if (Punished) if (Punished)
u.bc_felt = 0; /* forget felt ball&chain */ u.bc_felt = 0; /* forget felt ball&chain */
@@ -1010,6 +1012,14 @@ forget(int howmuch)
/* Forget some skills. */ /* Forget some skills. */
drain_weapon_skill(rnd(howmuch ? 5 : 3)); drain_weapon_skill(rnd(howmuch ? 5 : 3));
/* forget having seen monsts (affects recognizing unseen ones by sound) */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if (mtmp != u.usteed && mtmp != u.ustuck)
mtmp->meverseen = 0;
/* [perhaps ought to forget having seen every monster on every level] */
for (mtmp = gm.migrating_mons; mtmp; mtmp = mtmp->nmon)
mtmp->meverseen = 0;
} }
/* monster is hit by scroll of taming's effect */ /* monster is hit by scroll of taming's effect */