diff --git a/doc/fixes35.0 b/doc/fixes35.0 index a8ca82367..ea35c7216 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -88,6 +88,7 @@ prevent lose-level+regain-level cycle from arbritrarily boosting HP and Pw prevent polymorphing into "new man" at low level from magnifying HP and Pw losing a level while polymorphed affects hero's current monster HP as well as underlying normal HP +mind flayer brain eating is subject to certain fatal targets and to cannibalism Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 934ef429f..b2ccde1ee 100644 --- a/include/extern.h +++ b/include/extern.h @@ -565,6 +565,7 @@ E void NDECL(vomit); E int FDECL(eaten_stat, (int,struct obj *)); E void FDECL(food_disappears, (struct obj *)); E void FDECL(food_substitution, (struct obj *,struct obj *)); +E int FDECL(eat_brains, (struct monst *,struct monst *,BOOLEAN_P,int *)); E void NDECL(fix_petrification); E void FDECL(consume_oeaten, (struct obj *,int)); E boolean FDECL(maybe_finished_meal, (BOOLEAN_P)); diff --git a/src/eat.c b/src/eat.c index 62dc27cec..a439021b6 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1,8 +1,9 @@ -/* SCCS Id: @(#)eat.c 3.5 2005/09/09 */ +/* SCCS Id: @(#)eat.c 3.5 2005/09/27 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" +#include "edog.h" /* #define DEBUG */ /* uncomment to enable new eat code debugging */ #ifdef DEBUG @@ -418,14 +419,157 @@ boolean message; context.victual.fullwarn = context.victual.eating = context.victual.doreset = FALSE; } +/* handle side-effects of mind flayer's tentacle attack */ +int +eat_brains(magr, mdef, visflag, dmg_p) +struct monst *magr, *mdef; +boolean visflag; +int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ +{ + struct permonst *pd = mdef->data; + boolean give_nutrit = FALSE; + int result = MM_HIT, xtra_dmg = rnd(10); + + if (magr == &youmonst) { + You("eat %s brain!", s_suffix(mon_nam(mdef))); + } else if (mdef == &youmonst) { + Your("brain is eaten!"); + } else { /* monster against monster */ + if (visflag) pline("%s brain is eaten!", s_suffix(Monnam(mdef))); + } + + if (flesh_petrifies(pd)) { + /* mind flayer has attempted to eat the brains of a petrification + inducing critter (most likely Medusa; attacking a cockatrice via + tentacle-touch should have been caught before reaching this far) */ + if (magr == &youmonst) { + if (!Stone_resistance && !Stoned) + make_stoned(5L, (char *)0, KILLED_BY_AN, pd->mname); + } else { + /* no need to check for poly_when_stoned or Stone_resistance; + mind flayers don't have those capabilities */ + if (visflag) pline("%s turns to stone!", Monnam(magr)); + monstone(magr); + if (magr->mhp > 0) { + /* life-saved; don't continue eating the brains */ + return MM_MISS; + } else { + if (magr->mtame && !visflag) + /* parallels mhitm.c's brief_feeling */ + You("have a sad thought for a moment, then is passes."); + return MM_AGR_DIED; + } + } + } + + if (magr == &youmonst) { + /* + * player mind flayer is eating something's brain + */ + u.uconduct.food++; + if (!vegan(pd)) + u.uconduct.unvegan++; + if (!vegetarian(pd)) + violated_vegetarian(); + if (mindless(pd)) { /* (cannibalism not possible here) */ + pline("%s doesn't notice.", Monnam(mdef)); + /* all done; no extra harm inflicted upon target */ + return MM_MISS; + } else if (is_rider(pd)) { + pline("Ingesting that is fatal."); + Sprintf(killer.name, "unwisely ate the brain of %s", pd->mname); + killer.format = NO_KILLER_PREFIX; + done(DIED); + /* life-saving needed to reach here */ + exercise(A_WIS, FALSE); + *dmg_p += xtra_dmg; /* Rider takes extra damage */ + } else { + morehungry(-rnd(30)); /* cannot choke */ + if (ABASE(A_INT) < AMAX(A_INT)) { + /* recover lost Int; won't increase current max */ + ABASE(A_INT) += rnd(4); + if (ABASE(A_INT) > AMAX(A_INT)) ABASE(A_INT) = AMAX(A_INT); + context.botl = 1; + } + exercise(A_WIS, TRUE); + *dmg_p += xtra_dmg; + } + /* targetting another mind flayer or your own underlying species + is cannibalism */ + (void) maybe_cannibal(monsndx(pd), TRUE); + + } else if (mdef == &youmonst) { + /* + * monster mind flayer is eating hero's brain + */ + /* no such thing as mindless players */ + if (ABASE(A_INT) <= ATTRMIN(A_INT)) { + static NEARDATA const char brainlessness[] = "brainlessness"; + + if (Lifesaved) { + Strcpy(killer.name, brainlessness); + killer.format = KILLED_BY; + done(DIED); + /* amulet of life saving has now been used up */ + pline("Unfortunately your brain is still gone."); + } else { + Your("last thought fades away."); + } + Strcpy(killer.name, brainlessness); + killer.format = KILLED_BY; + done(DIED); + /* can only get here when in wizard or explore mode and user has + explicitly chosen not to die; arbitrarily boost intelligence */ + ABASE(A_INT) = ATTRMIN(A_INT) + 2; + You_feel("like a scarecrow."); + } + give_nutrit = TRUE; /* in case a conflicted pet is doing this */ + exercise(A_WIS, FALSE); + /* caller handles Int and memory loss */ + + } else { /* mhitm */ + /* + * monster mind flayer is eating another monster's brain + */ + if (mindless(pd)) { + if (visflag) pline("%s doesn't notice.", Monnam(mdef)); + return MM_MISS; + } else if (is_rider(pd)) { + mondied(magr); + if (magr->mhp <= 0) result = MM_AGR_DIED; + /* Rider takes extra damage regardless of whether attacker dies */ + *dmg_p += xtra_dmg; + } else { + *dmg_p += xtra_dmg; + give_nutrit = TRUE; + if (*dmg_p >= mdef->mhp && visflag) + pline("%s last thought fades away...", s_suffix(Monnam(mdef))); + } + } + + if (give_nutrit && magr->mtame && !magr->isminion) { + EDOG(magr)->hungrytime += rnd(60); + magr->mconf = 0; + } + + return result; +} + /* eating a corpse or egg of one's own species is usually naughty */ STATIC_OVL boolean maybe_cannibal(pm, allowmsg) int pm; boolean allowmsg; { + static NEARDATA long ate_brains = 0L; struct permonst *fptr = &mons[pm]; /* food type */ + /* when poly'd into a mind flayer, multiple tentacle hits in one + turn cause multiple digestion checks to occur; avoid giving + multiple luck penalties for the same attack */ + if (moves == ate_brains) return FALSE; + ate_brains = moves; /* ate_anything, not just brains... */ + if (!CANNIBAL_ALLOWED() && /* non-cannibalistic heroes shouldn't eat own species ever and also shouldn't eat current species when polymorphed diff --git a/src/mhitm.c b/src/mhitm.c index db8fae376..997587e32 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mhitm.c 3.5 2005/04/15 */ +/* SCCS Id: @(#)mhitm.c 3.5 2005/09/27 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -694,7 +694,8 @@ mdamagem(magr, mdef, mattk) struct obj *obj; char buf[BUFSZ]; struct permonst *pa = magr->data, *pd = mdef->data; - int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd); + int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd), + res = MM_MISS; boolean cancelled; if (touch_petrifies(pd) && !resists_ston(magr)) { @@ -1196,19 +1197,7 @@ mdamagem(magr, mdef, mattk) } break; } - if (vis) pline("%s brain is eaten!", s_suffix(Monnam(mdef))); - if (mindless(pd)) { - if (vis) pline("%s doesn't notice.", Monnam(mdef)); - break; - } - tmp += rnd(10); /* fakery, since monsters lack INT scores */ - if (magr->mtame && !magr->isminion) { - EDOG(magr)->hungrytime += rnd(60); - magr->mconf = 0; - } - if (tmp >= mdef->mhp && vis) - pline("%s last thought fades away...", - s_suffix(Monnam(mdef))); + res = eat_brains(magr, mdef, vis, &tmp); break; case AD_SLIM: if (cancelled) break; /* physical damage only */ @@ -1233,7 +1222,7 @@ mdamagem(magr, mdef, mattk) default: tmp = 0; break; } - if(!tmp) return(MM_MISS); + if (!tmp) return res; if((mdef->mhp -= tmp) < 1) { if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */ @@ -1243,7 +1232,8 @@ mdamagem(magr, mdef, mattk) mdef->mhp = 0; } monkilled(mdef, "", (int)mattk->adtyp); - if (mdef->mhp > 0) return 0; /* mdef lifesaved */ + if (mdef->mhp > 0) return res; /* mdef lifesaved */ + else if (res == MM_AGR_DIED) return (MM_DEF_DIED | MM_AGR_DIED); if (mattk->adtyp == AD_DGST) { /* various checks similar to dog_eat and meatobj. @@ -1263,7 +1253,7 @@ mdamagem(magr, mdef, mattk) return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } - return(MM_HIT); + return (res == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT; } /* `mon' is hit by a sleep attack; return 1 if it's affected, 0 otherwise */ diff --git a/src/mhitu.c b/src/mhitu.c index df1cc4fa1..41aa0c1c1 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mhitu.c 3.5 2005/07/13 */ +/* SCCS Id: @(#)mhitu.c 3.5 2005/09/27 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1060,45 +1060,12 @@ dopois: if (Half_physical_damage) dmg = (dmg+1) / 2; mdamageu(mtmp, dmg); - if (!uarmh || uarmh->otyp != DUNCE_CAP) { - Your("brain is eaten!"); - /* No such thing as mindless players... */ - if (ABASE(A_INT) <= ATTRMIN(A_INT)) { - int lifesaved = 0; - struct obj *wore_amulet = uamul; - - while(1) { - /* avoid looping on "die(y/n)?" */ - if (lifesaved && (discover || wizard)) { - if (wore_amulet && !uamul) { - /* used up AMULET_OF_LIFE_SAVING; still - subject to dying from brainlessness */ - wore_amulet = 0; - } else { - /* explicitly chose not to die; - arbitrarily boost intelligence */ - ABASE(A_INT) = ATTRMIN(A_INT) + 2; - You_feel("like a scarecrow."); - break; - } - } - - if (lifesaved) - pline("Unfortunately your brain is still gone."); - else - Your("last thought fades away."); - Strcpy(killer.name, "brainlessness"); - killer.format = KILLED_BY; - done(DIED); - lifesaved++; - } - } - } + if (!uarmh || uarmh->otyp != DUNCE_CAP) + (void) eat_brains(mtmp, &youmonst, TRUE, (int *)0); /* adjattrib gives dunce cap message when appropriate */ (void) adjattrib(A_INT, -rnd(2), FALSE); forget_levels(25); /* lose memory of 25% of levels */ forget_objects(25); /* lose memory of 25% of objects */ - exercise(A_WIS, FALSE); break; case AD_PLYS: hitmsg(mtmp, mattk); diff --git a/src/uhitm.c b/src/uhitm.c index 839495997..5503fd555 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)uhitm.c 3.5 2005/06/21 */ +/* SCCS Id: @(#)uhitm.c 3.5 2005/09/27 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1307,8 +1307,7 @@ register struct monst *mdef; register struct attack *mattk; { register struct permonst *pd = mdef->data; - register int tmp = d((int)mattk->damn, (int)mattk->damd); - int armpro; + int armpro, tmp = d((int)mattk->damn, (int)mattk->damd); boolean negated; armpro = magic_negation(mdef); @@ -1568,29 +1567,7 @@ register struct attack *mattk; break; } - You("eat %s brain!", s_suffix(mon_nam(mdef))); - u.uconduct.food++; - if (touch_petrifies(mdef->data) && !Stone_resistance && !Stoned) { - make_stoned(5L, (char *)0, - KILLED_BY_AN, mdef->data->mname); - } - if (!vegan(mdef->data)) - u.uconduct.unvegan++; - if (!vegetarian(mdef->data)) - violated_vegetarian(); - if (mindless(mdef->data)) { - pline("%s doesn't notice.", Monnam(mdef)); - break; - } - tmp += rnd(10); - morehungry(-rnd(30)); /* cannot choke */ - if (ABASE(A_INT) < AMAX(A_INT)) { - ABASE(A_INT) += rnd(4); - if (ABASE(A_INT) > AMAX(A_INT)) - ABASE(A_INT) = AMAX(A_INT); - context.botl = 1; - } - exercise(A_WIS, TRUE); + (void) eat_brains(&youmonst, mdef, TRUE, &tmp); break; } case AD_STCK: