wishing could attempt to place one)
opening/unlocking magic zapped at monster holding the hero will release hold
(zap at engulfer already expels hero); zapping at self has same effect
-when riding, allow scroll of remove curse to affect to affect steed's saddle
+when riding, allow scroll of remove curse read by hero to affect steed's saddle
the 'scores' option for final top ten display left default values in place if
only some of the three settings were set; 'scores:own' should have
produced '0 top/0 around/own' but ended up as '3 top/2 around/own'
were not shown on the screen; treat being swallowed or underwater as
situations which block telepathy, extended monster detection, warning
some rolling boulder trap feedback was inconsistent
+change "killed by <a foo>, while {paralyzed|frozen} by <a foo>" into
+ "killed by <a foo>, while {paralyzed|frozen}" if the killer caused
+ hero's helplessness
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
char command_line[COLNO];
long command_count;
const char *multi_reason;
+ char multireasonbuf[QBUFSZ]; /* note: smaller than usual [BUFSZ] */
int nroom;
int nsubroom;
int occtime;
/* ### uhitm.c ### */
+extern void dynamic_multi_reason(struct monst *, const char *, boolean);
extern void erode_armor(struct monst *, int);
extern boolean attack_checks(struct monst *, struct obj *);
extern void check_caitiff(struct monst *);
UNDEFINED_VALUES, /* command_line */
0, /* command_count */
NULL, /* multi_reason */
+ /* multi_reason usually points to a string literal (when not Null)
+ but multireasonbuf[] is available for when it needs to be dynamic */
+ DUMMY, /* multireasonbuf[] */
0, /* nroom */
0, /* nsubroom */
0, /* occtime */
}
Strcpy(g.killer.name, buf);
+
+ /* might need to fix up multi_reason if 'mtmp' caused the reason */
+ if (g.multi_reason
+ && g.multi_reason > g.multireasonbuf
+ && g.multi_reason < g.multireasonbuf + sizeof g.multireasonbuf - 1) {
+ char reasondummy, *p;
+ unsigned reasonmid = 0;
+
+ /*
+ * multireasonbuf[] contains 'm_id:reason' and multi_reason
+ * points at the text past the colon, so we have something
+ * like "42:paralyzed by a ghoul"; if mtmp->m_id matches 42
+ * then we truncate 'reason' at its first space so that final
+ * death reason becomes "Killed by a ghoul, while paralyzed."
+ * instead of "Killed by a ghoul, while paralyzed by a ghoul."
+ * (3.6.x gave "Killed by a ghoul, while paralyzed by a monster."
+ * which is potenitally misleading when the monster is also
+ * the killer.)
+ *
+ * Note that if the hero is life-saved and then killed again
+ * before the helplessness has cleared, the second death will
+ * report the truncated helplessness reason even if some other
+ * monster peforms the /coup de grace/.
+ */
+ if (sscanf(g.multireasonbuf, "%u:%c", &reasonmid, &reasondummy) == 2
+ && mtmp->m_id == reasonmid) {
+ if ((p = index(g.multireasonbuf, ' ')) != 0)
+ *p = '\0';
+ }
+ }
+
/*
* Chicken and egg issue:
* Ordinarily Unchanging ought to override something like this,
g.multi_reason = death_fixups[i].include;
else /* remove the helplessness reason */
g.multi_reason = (char *) 0;
+ g.multireasonbuf[0] = '\0'; /* dynamic buf stale either way */
if (death_fixups[i].unmulti) /* possibly hide helplessness */
g.multi = 0L;
break;
u.usleep = 0;
g.multi = nval;
if (nval == 0)
- g.multi_reason = NULL;
+ g.multi_reason = NULL, g.multireasonbuf[0] = '\0';
end_running(TRUE);
}
}
g.nomovemsg = 0;
u.usleep = 0;
- g.multi_reason = NULL;
+ g.multi_reason = NULL, g.multireasonbuf[0] = '\0';
if (g.afternmv) {
int (*f)(void) = g.afternmv;
#define PROJECTILE(obj) ((obj) && is_ammo(obj))
+/* multi_reason is usually a literal string; here we generate one that
+ has the causing monster's type included */
+void
+dynamic_multi_reason(struct monst *mon, const char *verb, boolean by_gaze)
+{
+ /* combination of noname_monnam() and m_monnam(), more or less;
+ accurate regardless of visibility or hallucination (only seen
+ if game ends) and without personal name (M2_PNAME excepted) */
+ char *who = x_monnam(mon, ARTICLE_A, (char *) 0,
+ (SUPPRESS_IT | SUPPRESS_INVISIBLE
+ | SUPPRESS_HALLUCINATION | SUPPRESS_SADDLE
+ | SUPPRESS_NAME),
+ FALSE),
+ *p = g.multireasonbuf;
+
+ /* prefix info for done_in_by() */
+ Sprintf(p, "%u:", mon->m_id);
+ p = eos(p);
+ Sprintf(p, "%s by %s%s", verb,
+ !by_gaze ? who : s_suffix(who),
+ !by_gaze ? "" : " gaze");
+ g.multi_reason = p;
+}
+
void
erode_armor(struct monst *mdef, int hurt)
{
You("are frozen by %s!", mon_nam(magr));
g.nomovemsg = You_can_move_again;
nomul(-rnd(10));
- g.multi_reason = "paralyzed by a monster";
+ /* set g.multi_reason;
+ 3.6.x used "paralyzed by a monster"; be more specific */
+ dynamic_multi_reason(magr, "paralyzed", FALSE);
exercise(A_DEX, FALSE);
}
}
} else {
You("are frozen by %s gaze!", s_suffix(mon_nam(mon)));
nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127);
- g.multi_reason = "frozen by a monster's gaze";
+ /* set g.multi_reason;
+ 3.6.x used "frozen by a monster's gaze" */
+ dynamic_multi_reason(mon, "frozen", TRUE);
g.nomovemsg = 0;
}
} else {
You("are frozen by %s!", mon_nam(mon));
g.nomovemsg = You_can_move_again;
nomul(-tmp);
- g.multi_reason = "frozen by a monster";
+ /* set g.multi_reason;
+ 3.6.x used "frozen by a monster"; be more specific */
+ dynamic_multi_reason(mon, "frozen", FALSE);
exercise(A_DEX, FALSE);
}
break;