From: PatR Date: Sun, 5 Mar 2023 23:11:25 +0000 (-0800) Subject: git issue #994 - killed by a touch of death X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b3d5158e644af1f044b5d293c5d053fd7e21aa45;p=nethack git issue #994 - killed by a touch of death Issue reported by vultur-cadens: cause of death reason for touch of death and death due to loss of strength only showed the cause, not the monster spellcaster who was responsible. This changes |Killed by a touch of death. to |Killed by the touch of death inflicted by the Wizard of Yendor. and |Killed by terminal fraility. to |Killed by strength loss inflicted by a chameleon imitating an arch-lich. (The 'imitating' part doesn't fit on the tombstone but will be present in logfile/xlogfile.) Noticed while implemented this: touch of death was modifying u.uhpmax and basing death vs damage on that even when hero was polymorphed. It now rehumanizes the hero in that situation. Closes #994 --- diff --git a/include/extern.h b/include/extern.h index 802b564c4..ecd49a89f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1320,7 +1320,7 @@ extern boolean usmellmon(struct permonst *); /* ### mcastu.c ### */ extern int castmu(struct monst *, struct attack *, boolean, boolean); -extern void touch_of_death(void); +extern void touch_of_death(struct monst *); extern int buzzmu(struct monst *, struct attack *); /* ### mdlib.c ### */ diff --git a/src/do_name.c b/src/do_name.c index abd8e2d18..9e52945ea 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -2228,10 +2228,10 @@ Amonnam(struct monst *mtmp) /* used for monster ID by the '/', ';', and 'C' commands to block remote identification of the endgame altars via their attending priests */ char * -distant_monnam(struct monst *mon, - int article, /* only ARTICLE_NONE and ARTICLE_THE - are handled here */ - char *outbuf) +distant_monnam( + struct monst *mon, + int article, /* only ARTICLE_NONE and ARTICLE_THE are handled here */ + char *outbuf) { /* high priest(ess)'s identity is concealed on the Astral Plane, unless you're adjacent (overridden for hallucination which does diff --git a/src/end.c b/src/end.c index a83f082f5..b730264a8 100644 --- a/src/end.c +++ b/src/end.c @@ -409,9 +409,8 @@ done_in_by(struct monst *mtmp, int how) { char buf[BUFSZ]; struct permonst *mptr = mtmp->data, - *champtr = ((mtmp->cham >= LOW_PM) - ? &mons[mtmp->cham] - : mptr); + *champtr = (mtmp->cham >= LOW_PM) ? &mons[mtmp->cham] + : mptr; boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)), mimicker = (M_AP_TYPE(mtmp) == M_AP_MONSTER), imitator = (mptr != champtr || mimicker); @@ -442,7 +441,7 @@ done_in_by(struct monst *mtmp, int how) if (imitator) { char shape[BUFSZ]; const char *realnm = pmname(champtr, Mgender(mtmp)), - *fakenm = pmname(mptr, Mgender(mtmp)); + *fakenm = pmname(mptr, Mgender(mtmp)); boolean alt = is_vampshifter(mtmp); if (mimicker) { @@ -498,7 +497,8 @@ done_in_by(struct monst *mtmp, int how) /* might need to fix up multi_reason if 'mtmp' caused the reason */ if (gm.multi_reason && gm.multi_reason > gm.multireasonbuf - && gm.multi_reason < gm.multireasonbuf + sizeof gm.multireasonbuf - 1) { + && gm.multi_reason + < gm.multireasonbuf + sizeof gm.multireasonbuf - 1) { char reasondummy, *p; unsigned reasonmid = 0; diff --git a/src/mcastu.c b/src/mcastu.c index c1390e091..a97fcd04a 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -39,6 +39,7 @@ static void cursetxt(struct monst *, boolean); static int choose_magic_spell(int); static int choose_clerical_spell(int); static int m_cure_self(struct monst *, int); +static char *death_inflicted_by(char *, const char *, struct monst *); static void cast_wizard_spell(struct monst *, int, int); static void cast_cleric_spell(struct monst *, int, int); static boolean is_undirected_spell(unsigned int, int); @@ -345,23 +346,60 @@ m_cure_self(struct monst *mtmp, int dmg) return dmg; } +/* unlike the finger of death spell which behaves like a wand of death, + this monster spell only attacks the hero */ void -touch_of_death(void) +touch_of_death(struct monst *mtmp) { - static const char touchodeath[] = "touch of death"; + char kbuf[BUFSZ]; int dmg = 50 + d(8, 6); int drain = dmg / 2; + /* if we get here, we know that hero isn't magic resistant and isn't + poly'd into an undead or demon */ You_feel("drained..."); - - if (drain >= u.uhpmax) { - gk.killer.format = KILLED_BY_AN; - Strcpy(gk.killer.name, touchodeath); + (void) death_inflicted_by(kbuf, "the touch of death", mtmp); + + if (Upolyd) { + u.mh = 0; + rehumanize(); /* fatal iff Unchanging */ + } else if (drain >= u.uhpmax) { + gk.killer.format = KILLED_BY; + Strcpy(gk.killer.name, kbuf); done(DIED); } else { u.uhpmax -= drain; - losehp(dmg, touchodeath, KILLED_BY_AN); + losehp(dmg, kbuf, KILLED_BY); + } + gk.killer.name[0] = '\0'; /* not killed if we get here... */ +} + +/* give a reason for death by some monster spells */ +static char * +death_inflicted_by( + char *outbuf, /* assumed big enough; pm_names are short */ + const char *deathreason, /* cause of death */ + struct monst *mtmp) /* monster who caused it */ +{ + Strcpy(outbuf, deathreason); + if (mtmp) { + struct permonst *mptr = mtmp->data, + *champtr = (mtmp->cham >= LOW_PM) ? &mons[mtmp->cham] : mptr; + const char *realnm = pmname(champtr, Mgender(mtmp)), + *fakenm = pmname(mptr, Mgender(mtmp)); + + /* greatly simplfied extract from done_in_by(), primarily for + reason for death due to 'touch of death' spell; if mtmp is + shape changed, it won't be a vampshifter or mimic since they + can't cast spells */ + if (!type_is_pname(champtr) && !the_unique_pm(mptr)) + realnm = an(realnm); + Sprintf(eos(outbuf), " inflicted by %s%s", + the_unique_pm(mptr) ? "the " : "", realnm); + if (champtr != mptr) + Sprintf(eos(outbuf), " imitating %s", an(fakenm)); } + return outbuf; } /* @@ -394,7 +432,7 @@ cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum) if (Hallucination) { You("have an out of body experience."); } else { - touch_of_death(); + touch_of_death(mtmp); } } else { if (Antimagic) { @@ -467,13 +505,18 @@ cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum) monstseesu(M_SEEN_MAGR); You_feel("momentarily weakened."); } else { + char kbuf[BUFSZ]; + You("suddenly feel weaker!"); dmg = mtmp->m_lev - 6; if (dmg < 1) /* paranoia since only chosen when m_lev is high */ dmg = 1; if (Half_spell_damage) dmg = (dmg + 1) / 2; - losestr(rnd(dmg), (const char *) 0, 0); + losestr(rnd(dmg), + death_inflicted_by(kbuf, "strength loss", mtmp), + KILLED_BY); + gk.killer.name[0] = '\0'; /* not killed if we get here... */ } dmg = 0; break; diff --git a/src/polyself.c b/src/polyself.c index 379101353..87a1dfcbb 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1254,6 +1254,10 @@ rehumanize(void) gk.killer.format = NO_KILLER_PREFIX; Strcpy(gk.killer.name, "killed while stuck in creature form"); done(DIED); + /* can get to here if declining to die in explore or wizard + mode; since we're wearing an amulet of unchanging we can't + be wearing an amulet of life-saving */ + return; /* don't rehumanize after all */ } else if (uamul && uamul->otyp == AMULET_OF_UNCHANGING) { Your("%s %s!", simpleonames(uamul), otense(uamul, "fail")); uamul->dknown = 1; @@ -1274,7 +1278,8 @@ rehumanize(void) /* can only happen if some bit of code reduces u.uhp instead of u.mh while poly'd */ Your("old form was not healthy enough to survive."); - Sprintf(gk.killer.name, "reverting to unhealthy %s form", gu.urace.adj); + Sprintf(gk.killer.name, "reverting to unhealthy %s form", + gu.urace.adj); gk.killer.format = KILLED_BY; done(DIED); } diff --git a/src/uhitm.c b/src/uhitm.c index 7c65267a1..35a54dc56 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -3477,8 +3477,10 @@ mhitm_ad_pest(struct monst *magr, struct attack *mattk, } void -mhitm_ad_deth(struct monst *magr, struct attack *mattk UNUSED, - struct monst *mdef, struct mhitm_data *mhm) +mhitm_ad_deth( + struct monst *magr, + struct attack *mattk UNUSED, + struct monst *mdef, struct mhitm_data *mhm) { struct permonst *pd = mdef->data; @@ -3501,7 +3503,7 @@ mhitm_ad_deth(struct monst *magr, struct attack *mattk UNUSED, case 18: case 17: if (!Antimagic) { - touch_of_death(); + touch_of_death(magr); mhm->damage = 0; return; }