From: Pasi Kallinen Date: Sun, 5 Apr 2020 09:43:54 +0000 (+0300) Subject: Purple worm changes X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cf1c72514883f70856a8b98c654f52f2a9896794;p=nethack Purple worm changes 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 , added with some formatting adjustments and consolidation. --- diff --git a/doc/fixes37.0 b/doc/fixes37.0 index e2c36003c..01c61e4ee 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -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 diff --git a/include/extern.h b/include/extern.h index 05e1dab3d..35ed65beb 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 *)); diff --git a/include/monst.h b/include/monst.h index c58094652..1eb33d39b 100644 --- a/include/monst.h +++ b/include/monst.h @@ -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) diff --git a/src/mon.c b/src/mon.c index 22fae52f4..655711c55 100644 --- 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(); diff --git a/src/monmove.c b/src/monmove.c index 04e5ee9f4..989d600c2 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -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; diff --git a/src/polyself.c b/src/polyself.c index 210a5fc53..b06f2287e 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1908,6 +1908,7 @@ polysense() switch (u.umonnum) { case PM_PURPLE_WORM: + case PM_BABY_PURPLE_WORM: warnidx = PM_SHRIEKER; break; case PM_VAMPIRE: