From 995a6bf4fe87e75a6f2e28099b7f5858b88eeac6 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 5 Apr 2020 05:57:37 -0700 Subject: [PATCH] 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. --- src/mon.c | 56 +++++++++++++++++++++++++++++++++++++-------------- src/monmove.c | 17 ++++++++-------- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/mon.c b/src/mon.c index 655711c55..b0c3f48ec 100644 --- a/src/mon.c +++ b/src/mon.c @@ -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 diff --git a/src/monmove.c b/src/monmove.c index 989d600c2..65433ed71 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -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)) {