From f1fe8c1600eff1cfa659ef79d6517e7fa0b0376c Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Sat, 1 Oct 2005 05:14:19 +0000 Subject: [PATCH] mind flayer brain attacks (trunk only) Fix a couple of problems From a bug report. Eating a Rider corpse is fatal, but eating a live Rider's brain was not--now it will be, both for monster mind flayers and for player poly'd into one. Also, there was no check for cannibalism when poly'd hero eats brains--now there is. Not mentioned in the report: eating Medusa's brains will now be fatal just like eating her corpse. And pet mind flayers who eat the hero's brains will gain some nutrition like they do when eating monster brains. Creating a common eat_brains() routine turned out to be something of a mistake; there is only a tiny amount of overlap among the u-vs-m, m-vs-u, and m-vs-m cases. Makefiles need a dependency update to add edog.h for eat.c. --- doc/fixes35.0 | 1 + include/extern.h | 1 + src/eat.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++- src/mhitm.c | 26 +++------ src/mhitu.c | 39 +------------ src/uhitm.c | 29 +--------- 6 files changed, 161 insertions(+), 81 deletions(-) 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: -- 2.40.0