]> granicus.if.org Git - nethack/commitdiff
fix "Killed by foo, while paralyzed by a monster"
authorPatR <rankin@nethack.org>
Thu, 22 Apr 2021 23:13:41 +0000 (16:13 -0700)
committerPatR <rankin@nethack.org>
Thu, 22 Apr 2021 23:13:41 +0000 (16:13 -0700)
If the killer and the paralyzer are the same monster, truncate
that to "Killed by a foo, while paralyzed".  When not the same,
spell out the paralyzer's monster type instead of using generic
"monster".  "Killed by a fox, while paralyzed by a ghoul", or
"Killed by a ghoul, while paralyzed by a ghoul" *if* they were
two different ghouls.

doc/fixes37.0
include/decl.h
include/extern.h
src/decl.c
src/end.c
src/hack.c
src/uhitm.c

index 91af31f7ac759ade8bba9df373e5cea742fc475d..7434b8931b5ab9c178cad2bc9ef93a30b080fa28 100644 (file)
@@ -472,7 +472,7 @@ if a branch has only one level (Fort Ludios), prevent creation of any level
        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'
@@ -488,6 +488,9 @@ when swallowed or underwater, player could be told about events (such as a
        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
index 8276f2ddf1e05fa71c053d19a66ae9746c8ebaf8..4ef27b6b52eb4b53d21bc706254633bc1bd0fe79 100644 (file)
@@ -717,6 +717,7 @@ struct instance_globals {
     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;
index fc3a7a14e0088ef735fd272cc1127b8e30d8bd65..fb167cb1706203ab4e65e062882ef7322ab1ad81 100644 (file)
@@ -2637,6 +2637,7 @@ extern void u_init(void);
 
 /* ### 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 *);
index 5a764ed5b17797b05652267bd6c7acc31be24ca2..81d5e9e526bbc854a8ed62935270d78f222ed3d0 100644 (file)
@@ -259,6 +259,9 @@ const struct instance_globals g_init = {
     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 */
index 98e1a9c51c3d67bbdfb0173dc07d55b3e75270fd..614e161c52d8122f3d0855713dada826da1eb659 100644 (file)
--- a/src/end.c
+++ b/src/end.c
@@ -494,6 +494,37 @@ done_in_by(struct monst *mtmp, int how)
     }
 
     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,
@@ -555,6 +586,7 @@ fixup_death(int how)
                     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;
index 435ad9b3a5cad502918d3b5e83e97921e0158106..a324726b737447c53d9280dbf871557146e7f59d 100644 (file)
@@ -3020,7 +3020,7 @@ nomul(int nval)
     u.usleep = 0;
     g.multi = nval;
     if (nval == 0)
-        g.multi_reason = NULL;
+        g.multi_reason = NULL, g.multireasonbuf[0] = '\0';
     end_running(TRUE);
 }
 
@@ -3047,7 +3047,7 @@ unmul(const char *msg_override)
     }
     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;
 
index 45ddb0450d62a74ddae5edf64c6dc6e5c95c69c0..2085e5deedf9d96be488a33b4451b2161b9bfee4 100644 (file)
@@ -28,6 +28,30 @@ static boolean shade_aware(struct obj *);
 
 #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)
 {
@@ -2813,7 +2837,9 @@ mhitm_ad_plys(struct monst *magr, struct attack *mattk, struct monst *mdef,
                     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);
             }
         }
@@ -4967,7 +4993,9 @@ passive(struct monst *mon,
                     } 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 {
@@ -4982,7 +5010,9 @@ passive(struct monst *mon,
                 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;