purple worms

Compiler complained about 'ptr' possibly being used unitinialized
in meatcorpse() and in this case it was right.  meatcorpse() was
cloned from meatobj() but the necessary initialization was missing.

Purple worm would devore an entire stack of corpses in one bite.
Split one off and have it eat that instead.

I'm not sure whether attempting to revive a Rider corpse can force
a monster off the level to make room.  If so, meatobj() and
meatcorpse() weren't prepared to handle that, nor was their caller.
It appears that the monster (either g.cube or purple worm) will
only eat as it moves so can't revive a Rider on a completely full
level since it won't be able to move in that situation.  I fixed
the caller to be prepared to handle a result of 3 (no further
action allowed) instead of just dealing with 2 (died), but I didn't
fix either of the meatfoo() routines to return 3 since bumping the
eating monster off the level seems to not be possible.

Don't let purple worms eat lichen corpses, regardless of whether
they'll swallow live ones.
This commit is contained in:
PatR
2020-04-05 05:57:37 -07:00
parent 30ad8eed84
commit 995a6bf4fe
2 changed files with 49 additions and 24 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 mon.c $NHDT-Date: 1585856901 2020/04/02 19:48:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.329 $ */
/* NetHack 3.6 mon.c $NHDT-Date: 1586091449 2020/04/05 12:57:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.333 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1028,8 +1028,16 @@ struct monst *mtmp;
/* touch sensitive items */
if (otmp->otyp == CORPSE && is_rider(&mons[otmp->corpsenm])) {
int ox = otmp->ox, oy = otmp->oy;
boolean revived_it = revive_corpse(otmp);
newsym(ox, oy);
/* Rider corpse isn't just inedible; can't engulf it either */
(void) revive_corpse(otmp);
if (!revived_it)
continue;
/* [should check whether revival forced 'mtmp' off the level
and return 3 in that situation (if possible...)] */
break;
/* untouchable (or inaccessible) items */
} else if ((otmp->otyp == CORPSE
@@ -1158,30 +1166,48 @@ struct monst* mtmp;
if (mtmp->mtame)
return 0;
for (otmp = g.level.objects[x][y]; otmp; otmp = otmp->nexthere) {
if (otmp->otyp != CORPSE)
continue;
for (otmp = sobj_at(CORPSE, x, y); otmp;
/* won't get back here if otmp is split or gets used up */
otmp = nxtobj(otmp, CORPSE, TRUE)) {
corpsepm = &mons[otmp->corpsenm];
if (is_rider(corpsepm)) {
revive_corpse(otmp);
/* skip some corpses */
if (vegan(corpsepm) /* ignore veggy corpse even if omnivorous */
/* don't eat harmful corpses */
|| (touch_petrifies(corpsepm) && !resists_ston(mtmp)))
continue;
if (is_rider(corpsepm)) {
boolean revived_it = revive_corpse(otmp);
newsym(x, y); /* corpse is gone; mtmp might be too so do this now
since we're bypassing the bottom of the loop */
if (!revived_it)
continue; /* revival failed? if so, corpse is gone */
/* Successful Rider revival; unlike skipped corpses, don't
just move on to next corpse as if nothing has happened.
[Can Rider revival bump 'mtmp' off level when it's full?
We ought to return 3 if that happens.] */
break;
}
/* don't eat harmful corpses */
if (touch_petrifies(corpsepm) && !resists_ston(mtmp))
continue;
if (otmp->quan > 1)
otmp = splitobj(otmp, 1L);
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.");
} else {
if (flags.verbose)
You_hear("a masticating sound.");
}
/* [should include quickmimic but can't handle that unless this
gets changed to set mtmp->meating] */
poly = polyfodder(otmp);
grow = mlevelgain(otmp);
heal = mhealup(otmp);
eyes = (otmp->otyp == CARROT);
eyes = (otmp->otyp == CARROT); /*[always false since not a corpse]*/
ptr = original_ptr;
delobj(otmp);
if (poly) {
if (newcham(mtmp, NULL, FALSE, FALSE))
@@ -2996,9 +3022,9 @@ struct monst *mtmp;
}
if (!rn2(10)) {
if (!rn2(13)) {
/* don't generate purple worms if they would be too difficult */
/* don't generate purple worms if too difficult */
int pm = montoostrong(PM_PURPLE_WORM, monmax_difficulty_lev())
? PM_BABY_PURPLE_WORM : PM_PURPLE_WORM;
? PM_BABY_PURPLE_WORM : PM_PURPLE_WORM;
(void) makemon(&mons[pm], 0, 0, NO_MM_FLAGS);
} else

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 monmove.c $NHDT-Date: 1585361053 2020/03/28 02:04:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.133 $ */
/* NetHack 3.6 monmove.c $NHDT-Date: 1586091452 2020/04/05 12:57:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.137 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2006. */
/* NetHack may be freely redistributed. See license for details. */
@@ -838,7 +838,7 @@ m_move(mtmp, after)
register struct monst *mtmp;
register int after;
{
register int appr;
int appr, etmp;
xchar gx, gy, nix, niy, chcnt;
int chi; /* could be schar except for stupid Sun-2 compiler */
boolean likegold = 0, likegems = 0, likeobjs = 0, likemagic = 0,
@@ -1008,8 +1008,8 @@ register int after;
if ((!mtmp->mpeaceful || !rn2(10)) && (!Is_rogue_level(&u.uz))) {
boolean in_line = (lined_up(mtmp)
&& (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy)
<= (throws_rocks(g.youmonst.data) ? 20 : ACURRSTR / 2 + 1)));
&& (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy)
<= (throws_rocks(g.youmonst.data) ? 20 : ACURRSTR / 2 + 1)));
if (appr != 1 || !in_line) {
/* Monsters in combat won't pick stuff up, avoiding the
@@ -1530,15 +1530,14 @@ register int after;
/* Maybe a cube ate just about anything */
if (ptr == &mons[PM_GELATINOUS_CUBE]) {
if (meatobj(mtmp) == 2)
return 2; /* it died */
if ((etmp = meatobj(mtmp)) >= 2)
return etmp; /* it died or got forced off the level */
}
/* 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 ((etmp = meatcorpse(mtmp)) >= 2)
return etmp; /* it died or got forced off the level */
}
if (!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) {