]> granicus.if.org Git - nethack/commitdiff
mind flayer brain attacks (trunk only)
authornethack.rankin <nethack.rankin>
Sat, 1 Oct 2005 05:14:19 +0000 (05:14 +0000)
committernethack.rankin <nethack.rankin>
Sat, 1 Oct 2005 05:14:19 +0000 (05:14 +0000)
     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
include/extern.h
src/eat.c
src/mhitm.c
src/mhitu.c
src/uhitm.c

index a8ca82367aeb70d8607fc2e5b4c7223eaba4f595..ea35c721680661548a7d0fb57d782cd9df365d2c 100644 (file)
@@ -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
index 934ef429f18b0f1166049431be377b3a190c50a3..b2ccde1ee0bc6fba01bb376fe74698cf5e4cfacf 100644 (file)
@@ -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));
index 62dc27cecc06350adf6232ec2fcdc172aec6aa59..a439021b63383cb05a3d865ddfd86405999de50d 100644 (file)
--- 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
index db8fae376b1c94afbcc1353c8f26463061c55163..997587e3203ee6f2762cd7896e40fdd1017f52ef 100644 (file)
@@ -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 */
index df1cc4fa1de89e53e90a23a40211f0ca7fe8f679..41aa0c1c137b7b966b7633d245ad93ff18e06b16 100644 (file)
@@ -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);
index 839495997597745806958df0a588a8766d02c9cf..5503fd555b34a9aeb824b7ccb6cbc520a7e7df36 100644 (file)
@@ -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: