Skip to content

Commit

Permalink
Purple worm changes
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
paxed committed Apr 5, 2020
1 parent 8119c52 commit cf1c725
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 4 deletions.
4 changes: 4 additions & 0 deletions doc/fixes37.0
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/extern.h
Expand Up @@ -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 *));
Expand Down
1 change: 1 addition & 0 deletions include/monst.h
Expand Up @@ -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)
Expand Down
77 changes: 73 additions & 4 deletions src/mon.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down
7 changes: 7 additions & 0 deletions src/monmove.c
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions src/polyself.c
Expand Up @@ -1908,6 +1908,7 @@ polysense()

switch (u.umonnum) {
case PM_PURPLE_WORM:
case PM_BABY_PURPLE_WORM:
warnidx = PM_SHRIEKER;
break;
case PM_VAMPIRE:
Expand Down

0 comments on commit cf1c725

Please sign in to comment.