]> granicus.if.org Git - nethack/commitdiff
Purple worm changes
authorPasi Kallinen <paxed@alt.org>
Sun, 5 Apr 2020 09:43:54 +0000 (12:43 +0300)
committerPasi Kallinen <paxed@alt.org>
Sun, 5 Apr 2020 09:44:25 +0000 (12:44 +0300)
Shriekers only spawn purple worms when they're appropriate difficulty.
Non-tame Purple worms eat corpses off the ground.
Baby purple worms attack shriekers.
Hero polyed into baby purple worm is warned against shriekers.

Original changes by copperwater <aosdict@gmail.com>, added with some
formatting adjustments and consolidation.

doc/fixes37.0
include/extern.h
include/monst.h
src/mon.c
src/monmove.c
src/polyself.c

index e2c36003c1f1b7a29548c32b6151ef9a710dfc1c..01c61e4ee0cec7fb6ac51b3bb65e6574c450ca58 100644 (file)
@@ -103,6 +103,10 @@ for farlook, describe water in the castle moat and in Juiblex's swamp as moat
 make hezrous emit poison clouds when they move
 stepping from one type of terrain to another was triggering an unnecessary
        status update
+make shriekers summon baby purple worms if purple worms would be too tough
+make non-tame (baby) purple worms eat corpses off the ground
+make baby purple worms attack shriekers
+make hero polymorphed into baby purple worm warned against shriekers
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index 05e1dab3dde156c0f18c3491f928bbd6ad88a75f..35ed65bebdeff2c6609589d8e0ce959903cd96e0 100644 (file)
@@ -1458,6 +1458,7 @@ E int FDECL(minliquid, (struct monst *));
 E int NDECL(movemon);
 E int FDECL(meatmetal, (struct monst *));
 E int FDECL(meatobj, (struct monst *));
+E int FDECL(meatcorpse, (struct monst *));
 E void FDECL(mpickgold, (struct monst *));
 E boolean FDECL(mpickstuff, (struct monst *, const char *));
 E int FDECL(curr_mon_load, (struct monst *));
index c58094652731d1cde95aeb6228938635b9ad8971..1eb33d39ba0e8c75374bfe69801fc01a6f5f20e0 100644 (file)
@@ -205,6 +205,7 @@ struct monst {
    given the current level difficulty and the hero's level. */
 #define monmax_difficulty(levdif) (((levdif) + u.ulevel) / 2)
 #define monmin_difficulty(levdif) ((levdif) / 6)
+#define monmax_difficulty_lev() (monmax_difficulty(level_difficulty()))
 
 /* Macros for whether a type of monster is too strong for a specific level. */
 #define montoostrong(monindx, lev) (mons[monindx].difficulty > lev)
index 22fae52f4d0a9ff722f0861ce689c41b2894b73b..655711c55b7070ef1d31a15ad4430427783c0a84 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1143,6 +1143,69 @@ struct monst *mtmp;
     return (count > 0 || ecount > 0) ? 1 : 0;
 }
 
+/* Monster eats a corpse off the ground.
+ * Return value is 0 = nothing eaten, 1 = ate a corpse, 2 = died */
+int
+meatcorpse(mtmp) /* for purple worms and other voracious monsters */
+struct monst* mtmp;
+{
+    struct obj *otmp;
+    struct permonst *ptr, *original_ptr = mtmp->data, *corpsepm;
+    boolean poly, grow, heal, eyes = FALSE;
+    int x = mtmp->mx, y = mtmp->my;
+
+    /* if a pet, eating is handled separately, in dog.c */
+    if (mtmp->mtame)
+        return 0;
+
+    for (otmp = g.level.objects[x][y]; otmp; otmp = otmp->nexthere) {
+        if (otmp->otyp != CORPSE)
+            continue;
+
+        corpsepm = &mons[otmp->corpsenm];
+        if (is_rider(corpsepm)) {
+            revive_corpse(otmp);
+            continue;
+        }
+
+        /* don't eat harmful corpses */
+        if (touch_petrifies(corpsepm) && !resists_ston(mtmp))
+            continue;
+
+        if (cansee(x, y) && canseemon(mtmp)) {
+            if (flags.verbose)
+                pline("%s eats %s!", Monnam(mtmp), distant_name(otmp, doname));
+        } else if (flags.verbose)
+            You_hear("a masticating sound.");
+
+        poly = polyfodder(otmp);
+        grow = mlevelgain(otmp);
+        heal = mhealup(otmp);
+        eyes = (otmp->otyp == CARROT);
+        delobj(otmp);
+        if (poly) {
+            if (newcham(mtmp, NULL, FALSE, FALSE))
+                ptr = mtmp->data;
+        } else if (grow) {
+            ptr = grow_up(mtmp, (struct monst *) 0);
+        } else if (heal) {
+            mtmp->mhp = mtmp->mhpmax;
+        }
+        if ((eyes || heal) && !mtmp->mcansee)
+            mcureblindness(mtmp, canseemon(mtmp));
+        /* in case it polymorphed or died */
+        if (ptr != original_ptr)
+            return !ptr ? 2 : 1;
+
+        /* Engulf & devour is instant, so don't set meating */
+        if (mtmp->minvis)
+            newsym(x, y);
+
+        return 1;
+    }
+    return 0;
+}
+
 void
 mpickgold(mtmp)
 register struct monst *mtmp;
@@ -1602,9 +1665,11 @@ mm_aggression(magr, mdef)
 struct monst *magr, /* monster that is currently deciding where to move */
              *mdef; /* another monster which is next to it */
 {
+    int mndx = monsndx(magr->data);
+
     /* supposedly purple worms are attracted to shrieking because they
        like to eat shriekers, so attack the latter when feasible */
-    if (magr->data == &mons[PM_PURPLE_WORM]
+    if ((mndx == PM_PURPLE_WORM || mndx == PM_BABY_PURPLE_WORM)
         && mdef->data == &mons[PM_SHRIEKER])
         return ALLOW_M | ALLOW_TM;
     /* Various other combinations such as dog vs cat, cat vs rat, and
@@ -2930,9 +2995,13 @@ struct monst *mtmp;
             stop_occupation();
         }
         if (!rn2(10)) {
-            if (!rn2(13))
-                (void) makemon(&mons[PM_PURPLE_WORM], 0, 0, NO_MM_FLAGS);
-            else
+            if (!rn2(13)) {
+                /* don't generate purple worms if they would be too difficult */
+                int pm = montoostrong(PM_PURPLE_WORM, monmax_difficulty_lev())
+                    ? PM_BABY_PURPLE_WORM : PM_PURPLE_WORM;
+
+                (void) makemon(&mons[pm], 0, 0, NO_MM_FLAGS);
+            } else
                 (void) makemon((struct permonst *) 0, 0, 0, NO_MM_FLAGS);
         }
         aggravate();
index 04e5ee9f46599a8b9b87d2a08ee0dc1df91d552a..989d600c203250dab75392787bb66a608cf4cf86 100644 (file)
@@ -1534,6 +1534,13 @@ register int after;
                     return 2; /* it died */
             }
 
+            /* Maybe a purple worm ate a corpse */
+            if (ptr == &mons[PM_PURPLE_WORM]
+                || ptr == &mons[PM_BABY_PURPLE_WORM]) {
+                if (meatcorpse(mtmp) == 2)
+                    return 2; /* it died */
+            }
+
             if (!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) {
                 boolean picked = FALSE;
 
index 210a5fc5390adc5ce66cee2690f2cf00eefc8cf2..b06f2287e5c72e34b3833399990b75ba8e3437b7 100644 (file)
@@ -1908,6 +1908,7 @@ polysense()
 
     switch (u.umonnum) {
     case PM_PURPLE_WORM:
+    case PM_BABY_PURPLE_WORM:
         warnidx = PM_SHRIEKER;
         break;
     case PM_VAMPIRE: