From: PatR Date: Thu, 30 Sep 2021 12:26:04 +0000 (-0700) Subject: fix github issue #594 - special attacks X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=017a8687e0b541a8e5848ef3037e25dc819208ca;p=nethack fix github issue #594 - special attacks by the Riders that only damage the hero, not other monsters. Noticed and diagnosed by vultur-cadens. Attacks dishing out the damage type AD_DETH (Death), AD_FAMN (Famine), AD_PEST (Pestilence), and also AD_DISE (Demogorgon, Juiblex, Scorpius) did 0 damage if inflicted against monsters. That made Death harmless to other monsters. The others have additional attacks (in the two Rider's cases, only if both instances of their special attack hit on the same move so that the second one is converted into a stun attack) and could manage to kill other monsters. The uhitm case can't happen. I suspect that the mhitm case was originally intentionally omitted as something which won't happen, but that's just a guess. Fixes #594 --- diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 69599746d..faf7ba8c9 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -622,6 +622,8 @@ Izchak occasionally stocks wands/scrolls/spellbooks of light data tracking for #overview was mis-using u.urooms[] and after being in a situation where hero was in multiple rooms at once, visiting other levels might flag unvisisted rooms as having been visited +special damage attacks by the Riders and by fatal-illness inflictors such as + Demogorgon did no damage against other monsters, only against the hero Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/uhitm.c b/src/uhitm.c index f510686f9..064779286 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -2046,7 +2046,8 @@ mhitm_ad_fire(struct monst *magr, struct attack *mattk, struct monst *mdef, mhm->done = TRUE; return; } - mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + mhm->hitflags = (MM_DEF_DIED + | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); mhm->done = TRUE; return; } @@ -2242,6 +2243,7 @@ mhitm_ad_acid(struct monst *magr, struct attack *mattk, struct monst *mdef, } } +/* steal gold */ void mhitm_ad_sgld(struct monst *magr, struct attack *mattk, struct monst *mdef, struct mhitm_data *mhm) @@ -3155,9 +3157,13 @@ void mhitm_ad_famn(struct monst *magr, struct attack *mattk UNUSED, struct monst *mdef, struct mhitm_data *mhm) { + struct permonst *pd = mdef->data; + if (magr == &g.youmonst) { - /* uhitm */ - mhm->damage = 0; + /* uhitm; hero can't polymorph into anything with this attack + so this won't happen; if it could, it would be the same as + the mhitm case except for messaging */ + goto mhitm_famn; } else if (mdef == &g.youmonst) { /* mhitu */ pline("%s reaches out, and your body shrivels.", Monnam(magr)); @@ -3166,28 +3172,39 @@ mhitm_ad_famn(struct monst *magr, struct attack *mattk UNUSED, morehungry(rn1(40, 40)); /* plus the normal damage */ } else { - /* mhitm */ - mhm->damage = 0; + mhitm_famn: + /* mhitm; it's possible for Famine to hit another monster; + if target is something that doesn't eat, it won't be harmed; + otherwise, just inflict the normal damage */ + if (!(carnivorous(pd) || herbivorous(pd) || metallivorous(pd))) + mhm->damage = 0; } } void -mhitm_ad_pest(struct monst *magr, struct attack *mattk UNUSED, +mhitm_ad_pest(struct monst *magr, struct attack *mattk, struct monst *mdef, struct mhitm_data *mhm) { + struct attack alt_attk; struct permonst *pa = magr->data; if (magr == &g.youmonst) { - /* uhitm */ - mhm->damage = 0; + /* uhitm; hero can't polymorph into anything with this attack + so this won't happen; if it could, it would be the same as + the mhitm case except for messaging */ + goto mhitm_pest; } else if (mdef == &g.youmonst) { /* mhitu */ pline("%s reaches out, and you feel fever and chills.", Monnam(magr)); (void) diseasemu(pa); /* plus the normal damage */ } else { - /* mhitm */ - mhm->damage = 0; + mhitm_pest: + /* mhitm; it's possible for Pestilence to hit another monster; + treat it the same as an attack for AD_DISE damage */ + alt_attk = *mattk; + alt_attk.adtyp = AD_DISE; + mhitm_ad_dise(magr, &alt_attk, mdef, mhm); } } @@ -3198,13 +3215,16 @@ mhitm_ad_deth(struct monst *magr, struct attack *mattk UNUSED, struct permonst *pd = mdef->data; if (magr == &g.youmonst) { - /* uhitm */ - mhm->damage = 0; + /* uhitm; hero can't polymorph into anything with this attack + so this won't happen; if it could, it would be the same as + the mhitm case except for messaging */ + goto mhitm_deth; } else if (mdef == &g.youmonst) { /* mhitu */ pline("%s reaches out with its deadly touch.", Monnam(magr)); if (is_undead(pd)) { - /* Still does normal damage */ + /* still does some damage */ + mhm->damage = (mhm->damage + 1) / 2; pline("Was that the touch of death?"); return; } @@ -3220,7 +3240,7 @@ mhitm_ad_deth(struct monst *magr, struct attack *mattk UNUSED, /*FALLTHRU*/ default: /* case 16: ... case 5: */ You_feel("your life force draining away..."); - mhm->permdmg = 1; /* actual damage done below */ + mhm->permdmg = 1; /* actual damage done by caller */ return; case 4: case 3: @@ -3234,8 +3254,18 @@ mhitm_ad_deth(struct monst *magr, struct attack *mattk UNUSED, return; } } else { - /* mhitm */ - mhm->damage = 0; + mhitm_deth: + /* mhitm; it's possible for Death to hit another monster; + if target is undead, it will take some damage but less than an + undead hero would; otherwise, just inflict the normal damage */ + if (is_undead(pd) && mhm->damage > 1) + mhm->damage = rnd(mhm->damage / 2); + /* + * FIXME? + * most monsters should be vulnerable to Death's touch + * instead of only receiving ordinary damage, but is it + * worth bothering with? + */ } } @@ -3855,26 +3885,37 @@ mhitm_ad_samu(struct monst *magr, struct attack *mattk, struct monst *mdef, } } +/* disease */ void mhitm_ad_dise(struct monst *magr, struct attack *mattk, struct monst *mdef, struct mhitm_data *mhm) { - struct permonst *pa = magr->data; + struct obj *mwep; + struct permonst *pa = magr->data, *pd = mdef->data; if (magr == &g.youmonst) { - /* uhitm */ - mhm->damage = 0; + /* uhitm; hero can't polymorph into anything with this attack so + this won't happen; if it could, it would be the same as the + mhitm case except for messaging */ + goto mhitm_dise; } else if (mdef == &g.youmonst) { /* mhitu */ hitmsg(magr, mattk); if (!diseasemu(pa)) mhm->damage = 0; } else { - /* mhitm */ - mhm->damage = 0; + mhitm_dise: + /* mhitm; protected monsters use the same criteria as for + poly'd hero gaining sick resistance combined with any hero + [hypothetically] wielding a weapon that guards against disease */ + if (pd->mlet == S_FUNGUS || pd == &mons[PM_GHOUL] + || ((mwep = MON_WEP(mdef)) != 0 && defends(AD_DISE, mwep))) + mhm->damage = 0; + /* else does ordinary damage */ } } +/* seduce and also steal item */ void mhitm_ad_sedu(struct monst *magr, struct attack *mattk, struct monst *mdef, struct mhitm_data *mhm) @@ -3981,7 +4022,8 @@ mhitm_ad_sedu(struct monst *magr, struct attack *mattk, struct monst *mdef, mdef->mstrategy &= ~STRAT_WAITFORU; mselftouch(mdef, (const char *) 0, FALSE); if (DEADMONSTER(mdef)) { - mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + mhm->hitflags = (MM_DEF_DIED + | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); mhm->done = TRUE; return; }