From 4be43239a846926ea6b71961508d56ac83e8ded9 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Fri, 18 May 2007 02:10:39 +0000 Subject: [PATCH] fix #332 - strangulation affects headless monsters (trunk only) From a bug report: amulet of strangulation continues to kill hero if he polymorphs into a creature which doesn't need to breathe or doesn't have a head or even a circulatory system. Currently, the messages are different when the hero doesn't need to breathe, but that doesn't seem good enough. This makes strangulation stop when you polymorph into something which shouldn't be vulnerable and restart if you poly into something vulnerable while still wearing the bad amulet. can_be_strangled() is doing more checks that necessary, in case the strangulation property ever gets conferred by something other than an amulet. Its criteria for protection from strangling might need tweaking. --- doc/fixes35.0 | 1 + include/extern.h | 1 + src/do_wear.c | 15 ++++++++++----- src/mondata.c | 33 ++++++++++++++++++++++++++++++++- src/polyself.c | 28 ++++++++++++++++++++++++++++ src/timeout.c | 6 ++++++ 6 files changed, 78 insertions(+), 6 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index d7ad63329..2e49b4fba 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -229,6 +229,7 @@ eliminate case-sensitivity when converting words from singular to plural and breath attack directed at self by poly'd hero always hits override non-silver vs shades for artifacts which deal extra damage to undead assorted mirror fixes--mainly visibility issues +some monsters can't be strangled; self-polymorph can stop/restart strangulation Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 1b75c11a1..d15118c6d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1329,6 +1329,7 @@ E boolean FDECL(hates_silver, (struct permonst *)); E boolean FDECL(mon_hates_silver, (struct monst *)); E boolean FDECL(passes_bars, (struct permonst *)); E boolean FDECL(can_blow, (struct monst *)); +E boolean FDECL(can_be_strangled, (struct monst *)); E boolean FDECL(can_track, (struct permonst *)); E boolean FDECL(breakarm, (struct permonst *)); E boolean FDECL(sliparm, (struct permonst *)); diff --git a/src/do_wear.c b/src/do_wear.c index 9044f7930..8ce78939b 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)do_wear.c 3.5 2007/03/19 */ +/* SCCS Id: @(#)do_wear.c 3.5 2007/05/16 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -626,9 +626,11 @@ Amulet_on() break; } case AMULET_OF_STRANGULATION: - makeknown(AMULET_OF_STRANGULATION); - pline("It constricts your throat!"); - Strangled = 6; + if (can_be_strangled(&youmonst)) { + makeknown(AMULET_OF_STRANGULATION); + pline("It constricts your throat!"); + Strangled = 6L; + } break; case AMULET_OF_RESTFUL_SLEEP: HSleeping = rnd(100); @@ -671,8 +673,11 @@ Amulet_off() break; case AMULET_OF_STRANGULATION: if (Strangled) { + if (Breathless) + Your("%s is no longer constricted!", body_part(NECK)); + else You("can breathe more easily!"); - Strangled = 0; + Strangled = 0L; } break; case AMULET_OF_RESTFUL_SLEEP: diff --git a/src/mondata.c b/src/mondata.c index f3e319fea..cd8010b5d 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mondata.c 3.5 2007/03/02 */ +/* SCCS Id: @(#)mondata.c 3.5 2007/05/16 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -299,6 +299,37 @@ register struct monst *mtmp; return TRUE; } +boolean +can_be_strangled(mon) /* TRUE if mon is vulnerable to strangulation */ +struct monst *mon; +{ + struct obj *mamul; + boolean nonbreathing, nobrainer; + + /* For amulet of strangulation support: here we're considering + strangulation to be loss of blood flow to the brain due to + constriction of the arteries in the neck, so all headless + creatures are immune (no neck) as are mindless creatures + who don't need to breathe (brain, if any, doesn't care). + Mindless creatures who do need to breath are vulnerable, as + are non-breathing creatures which have higher brain function. */ + if (!has_head(mon->data)) return FALSE; + if (mon == &youmonst) { + /* hero can't be mindless but poly'ing into mindless form can + confer strangulation protection */ + nobrainer = mindless(youmonst.data); + nonbreathing = Breathless; + } else { + nobrainer = mindless(mon->data); + /* monsters don't wear amulets of magical breathing, + so second part doesn't achieve anything useful... */ + nonbreathing = (breathless(mon->data) || + ((mamul = which_armor(mon, W_AMUL)) != 0 && + (mamul->otyp == AMULET_OF_MAGICAL_BREATHING))); + } + return (boolean)(!nobrainer || !nonbreathing); +} + boolean can_track(ptr) /* returns TRUE if monster can track well */ register struct permonst *ptr; diff --git a/src/polyself.c b/src/polyself.c index fe7989023..20d1ff147 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -21,6 +21,7 @@ #include "hack.h" +STATIC_DCL void FDECL(check_strangling, (BOOLEAN_P)); STATIC_DCL void FDECL(polyman, (const char *,const char *)); STATIC_DCL void NDECL(break_armor); STATIC_DCL void FDECL(drop_weapon,(int)); @@ -46,6 +47,30 @@ set_uasmon() #endif } +/* for changing into form that's immune to strangulation */ +STATIC_OVL void +check_strangling(on) +boolean on; +{ + if (on) { /* on -- maybe resume strangling */ + /* when Strangled is already set, polymorphing from one + vulnerable form into another causes the counter to be reset */ + if (uamul && uamul->otyp == AMULET_OF_STRANGULATION && + can_be_strangled(&youmonst)) { + Your("%s %s your %s!", simpleonames(uamul), + Strangled ? "still constricts" : "begins constricting", + body_part(NECK)); /* "throat" */ + Strangled = 6L; + makeknown(AMULET_OF_STRANGULATION); + } + } else { /* off -- maybe block strangling */ + if (Strangled && !can_be_strangled(&youmonst)) { + Strangled = 0L; + You("are no longer being strangled."); + } + } +} + /* make a (new) human out of the player */ STATIC_OVL void polyman(fmt, arg) @@ -109,6 +134,7 @@ const char *fmt, *arg; Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ } + check_strangling(TRUE); if(!Levitation && !u.ustuck && (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy))) @@ -491,6 +517,7 @@ int mntmp; make_slimed(0L, (char*) 0); } } + check_strangling(FALSE); /* maybe stop strangling */ if (nohands(youmonst.data)) Glib = 0; /* @@ -631,6 +658,7 @@ int mntmp; You("orient yourself on the web."); u.utrap = 0; } + check_strangling(TRUE); /* maybe start strangling */ (void) polysense(youmonst.data); context.botl = 1; diff --git a/src/timeout.c b/src/timeout.c index a3898ce4b..b0f7793bc 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -354,6 +354,12 @@ nh_timeout() Strcpy(killer.name, (u.uburied) ? "suffocation" : "strangulation"); done(DIED); + /* must be declining to die in explore|wizard mode; + treat like being cured of strangulation by prayer */ + if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) { + Your("amulet vanishes!"); + useup(uamul); + } break; case FUMBLING: /* call this only when a move took place. */