fix issue #1046 - unseen monster reading scroll

Reported by copperwater "on behalf of Maud":  when hero hears an
unseen monster read a not-yet-discovered scroll of create monster
and doesn't see any new monster appear, the player is given a chance
to call the scroll something.  When hearing an unseen monster read
a not-yet-discovered scroll of teleportation, the label is revealed
but no such 'call it' opportunity is offered, so the player could
deduce which of the two scroll types it was for either case.

Provide an opportunity to supply a 'called' name for scrolls of
teleportation when heard being read, same as with create monster.
Surprisingly complicated to achieve.

Eliminated a couple of goto's in the process.

Fixes #1046
This commit is contained in:
PatR
2023-06-04 16:22:38 -07:00
parent 22d79e245d
commit 7e4be52a6c
2 changed files with 58 additions and 36 deletions

View File

@@ -1199,6 +1199,10 @@ applying a cream pie (always) or lump of royal jelly (sometimes) would use up
the object and then access its memory after that had been freed the object and then access its memory after that had been freed
keep track of hero's pending movement points across save and restore keep track of hero's pending movement points across save and restore
give feedback if hero sees a monster become hidden under an object or water give feedback if hero sees a monster become hidden under an object or water
hero might hear unseen monster read scroll of create monster or scroll of
teleportation; when it was create monster, player was given a chance
to call it something but not when it was teleportation, allowing the
player to deduce which type of scroll it actually was
Fixes to 3.7.0-x General Problems Exposed Via git Repository Fixes to 3.7.0-x General Problems Exposed Via git Repository

View File

@@ -21,6 +21,7 @@ static void mreadmsg(struct monst *, struct obj *);
static void mquaffmsg(struct monst *, struct obj *); static void mquaffmsg(struct monst *, struct obj *);
static boolean m_use_healing(struct monst *); static boolean m_use_healing(struct monst *);
static boolean m_sees_sleepy_soldier(struct monst *); static boolean m_sees_sleepy_soldier(struct monst *);
static void m_tele(struct monst *, boolean, boolean, int);
static boolean linedup_chk_corpse(coordxy, coordxy); static boolean linedup_chk_corpse(coordxy, coordxy);
static void m_use_undead_turning(struct monst *, struct obj *); static void m_use_undead_turning(struct monst *, struct obj *);
static boolean hero_behind_chokepoint(struct monst *); static boolean hero_behind_chokepoint(struct monst *);
@@ -364,6 +365,29 @@ m_sees_sleepy_soldier(struct monst *mtmp)
return FALSE; return FALSE;
} }
static void
m_tele(
struct monst *mtmp, /* monst that might be teleported */
boolean vismon, /* can see it */
boolean oseen, /* have seen the object that triggered this */
int how) /* type of that object */
{
if (tele_restrict(mtmp)) { /* mysterious force... */
if (vismon && how) /* mentions 'teleport' */
makeknown(how);
/* monster learns that teleportation isn't useful here */
if (noteleport_level(mtmp))
mon_learns_traps(mtmp, TELEP_TRAP);
} else if ((mon_has_amulet(mtmp) || On_W_tower_level(&u.uz)) && !rn2(3)) {
if (vismon)
pline("%s seems disoriented for a moment.", Monnam(mtmp));
} else {
if (oseen && how)
makeknown(how);
(void) rloc(mtmp, RLOC_MSG);
}
}
/* Select a defensive item/action for a monster. Returns TRUE iff one is /* Select a defensive item/action for a monster. Returns TRUE iff one is
found. */ found. */
boolean boolean
@@ -683,7 +707,7 @@ find_defensive(struct monst *mtmp, boolean tryescape)
int int
use_defensive(struct monst *mtmp) use_defensive(struct monst *mtmp)
{ {
int i, fleetim, how = 0; int i, fleetim;
struct obj *otmp = gm.m.defensive; struct obj *otmp = gm.m.defensive;
boolean vis, vismon, oseen; boolean vis, vismon, oseen;
const char *Mnam; const char *Mnam;
@@ -734,24 +758,7 @@ use_defensive(struct monst *mtmp)
return 2; return 2;
m_flee(mtmp); m_flee(mtmp);
mzapwand(mtmp, otmp, TRUE); mzapwand(mtmp, otmp, TRUE);
how = WAN_TELEPORTATION; m_tele(mtmp, vismon, oseen, WAN_TELEPORTATION);
mon_tele:
if (tele_restrict(mtmp)) { /* mysterious force... */
if (vismon && how) /* mentions 'teleport' */
makeknown(how);
/* monster learns that teleportation isn't useful here */
if (noteleport_level(mtmp))
mon_learns_traps(mtmp, TELEP_TRAP);
return 2;
}
if ((mon_has_amulet(mtmp) || On_W_tower_level(&u.uz)) && !rn2(3)) {
if (vismon)
pline("%s seems disoriented for a moment.", Monnam(mtmp));
return 2;
}
if (oseen && how)
makeknown(how);
(void) rloc(mtmp, RLOC_MSG);
return 2; return 2;
case MUSE_WAN_TELEPORTATION: case MUSE_WAN_TELEPORTATION:
gz.zap_oseen = oseen; gz.zap_oseen = oseen;
@@ -769,32 +776,42 @@ use_defensive(struct monst *mtmp)
if (mtmp->isshk || mtmp->isgd || mtmp->ispriest) if (mtmp->isshk || mtmp->isgd || mtmp->ispriest)
return 2; return 2;
m_flee(mtmp); m_flee(mtmp);
mreadmsg(mtmp, otmp); /* we want to be able to access otmp after the teleport but it
m_useup(mtmp, otmp); /* otmp might be free'ed */ might get destroyed if still in mtmp's inventory (maybe mtmp
how = SCR_TELEPORTATION; lands in lava or on a fire trap) so take it out in advance */
if (otmp->quan > 1L)
otmp = splitobj(otmp, 1L);
extract_from_minvent(mtmp, otmp, FALSE, FALSE);
/* 'last_msg' will be changed to PLNMSG_UNKNOWN if any messages
are issued by mreadmsg(), 'if (vismon) pline()', or m_tele() */
iflags.last_msg = PLNMSG_enum;
mreadmsg(mtmp, otmp); /* sets otmp->dknown if !Blind or !Deaf */
if (obj_is_cursed || mtmp->mconf) { if (obj_is_cursed || mtmp->mconf) {
int nlev; int nlev;
d_level flev; d_level flev;
nlev = random_teleport_level();
if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
if (vismon) if (vismon)
pline("%s seems very disoriented for a moment.", pline("%s seems very disoriented for a moment.",
Monnam(mtmp)); Monnam(mtmp));
return 2; } else if (nlev == depth(&u.uz)) {
}
nlev = random_teleport_level();
if (nlev == depth(&u.uz)) {
if (vismon) if (vismon)
pline("%s shudders for a moment.", Monnam(mtmp)); pline("%s shudders for a moment.", Monnam(mtmp));
return 2; } else {
get_level(&flev, nlev);
migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM,
(coord *) 0);
} }
get_level(&flev, nlev); } else {
migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM, m_tele(mtmp, vismon, oseen, SCR_TELEPORTATION);
(coord *) 0); }
if (oseen) /* m_tele() handles makeknown(); trycall() will be a no-op when
makeknown(SCR_TELEPORTATION); otmp->otyp is already discovered */
} else if (otmp->dknown && iflags.last_msg != PLNMSG_enum)
goto mon_tele; trycall(otmp);
/* already removed from mtmp->minvent so not 'm_useup(mtmp, otmp)' */
obfree(otmp, (struct obj *) 0);
return 2; return 2;
} }
case MUSE_WAN_DIGGING: { case MUSE_WAN_DIGGING: {
@@ -1047,8 +1064,9 @@ use_defensive(struct monst *mtmp)
if (mtmp->wormno) if (mtmp->wormno)
worm_move(mtmp); worm_move(mtmp);
newsym(gt.trapx, gt.trapy); newsym(gt.trapx, gt.trapy);
/* 0: 'no object' rather than STRANGE_OBJECT; FALSE: obj not seen */
goto mon_tele; m_tele(mtmp, vismon, FALSE, 0);
return 2;
case MUSE_POT_HEALING: case MUSE_POT_HEALING:
mquaffmsg(mtmp, otmp); mquaffmsg(mtmp, otmp);
i = d(6 + 2 * bcsign(otmp), 4); i = d(6 + 2 * bcsign(otmp), 4);