From bb5820b493fd5899df32431fc02bb0d5c300cfcc Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Sat, 25 Oct 2008 01:04:04 +0000 Subject: [PATCH] monsters eating green slime corpses (trunk only) From a bug report, pets able to eat acidic and poisonous corpses (black naga was the case cited) would eat green slime corpses without turning into green slime, unlike the hero. This prevents such monsters from eating green slime unless they're starving, implements transformation into green slime for the case where it does get eaten, and prevents non-pet gelatinous cubes from devouring such corpses. meatobj() is reorganized to hopefully become clearer, and it removes the assumption that the object eater is a g.cube in case we ever adopt slash'em's "tasmanian devil" monster. Monsters with digestion attacks who swallow green slime monsters are turned into green slime, but ones who swallow hero poly'd into green slime are not. This doesn't address that. --- doc/fixes35.0 | 1 + src/dog.c | 6 +++- src/dogmove.c | 23 ++++++++++---- src/mon.c | 85 +++++++++++++++++++++++++++++++++------------------ 4 files changed, 78 insertions(+), 37 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 0ede291cc..60815050a 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -291,6 +291,7 @@ if breaking a wand of polymorph causes hero to drop items, don't transform them give "shuddering vibrations" feedback if breaking a poly wand uses up items if polymorph causes a monster to drop items, they won't be used up via shuddering vibrations or as golem creation fodder +monsters who ate green slime corpses weren't turned into green slime Platform- and/or Interface-Specific Fixes diff --git a/src/dog.c b/src/dog.c index 5fd97fb93..9c8099fd4 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)dog.c 3.5 2007/03/02 */ +/* SCCS Id: @(#)dog.c 3.5 2008/10/20 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -727,6 +727,10 @@ register struct obj *obj; (acidic(fptr) && !resists_acid(mon)) || (poisonous(fptr) && !resists_poison(mon))) return POISON; + /* turning into slime is preferrable to starvation */ + else if (fptr == &mons[PM_GREEN_SLIME] && + !slimeproof(mon->data)) + return (starving ? ACCFOOD : POISON); else if (vegan(fptr)) return (herbi ? CADAVER : MANFOOD); /* most humanoids will avoid cannibalism unless starving; diff --git a/src/dogmove.c b/src/dogmove.c index 5d1149033..300023cb0 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)dogmove.c 3.5 2007/08/20 */ +/* SCCS Id: @(#)dogmove.c 3.5 2008/10/20 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -200,7 +200,7 @@ int x, y; /* dog's starting location, might be different from current */ boolean devour; { register struct edog *edog = EDOG(mtmp); - boolean poly = FALSE, grow = FALSE, heal = FALSE, deadmimic; + boolean poly, grow, heal, slimer, deadmimic; int nutrit; long oprice; char objnambuf[BUFSZ]; @@ -214,10 +214,11 @@ boolean devour; (obj->corpsenm == PM_SMALL_MIMIC || obj->corpsenm == PM_LARGE_MIMIC || obj->corpsenm == PM_GIANT_MIMIC)); - + slimer = (obj->otyp == CORPSE && obj->corpsenm == PM_GREEN_SLIME); poly = polyfodder(obj); grow = mlevelgain(obj); heal = mhealup(obj); + if (devour) { if (mtmp->meating > 1) mtmp->meating /= 2; if (nutrit > 1) nutrit = (nutrit * 3) / 4; @@ -300,9 +301,19 @@ boolean devour; delobj(obj); } - if (poly) { - (void) newcham(mtmp, (struct permonst *)0, FALSE, - cansee(mtmp->mx, mtmp->my)); +#if 0 /* pet is eating, so slime recovery is not feasible... */ + /* turning into slime might be cureable */ + if (slimer && munslime(mtmp, FALSE)) { + /* but the cure (fire directed at self) might be fatal */ + if (mtmp->mhp < 1) return 2; + slimer = FALSE; /* sliming is avoided, skip polymorph */ + } +#endif + + if (poly || slimer) { + struct permonst *ptr = slimer ? &mons[PM_GREEN_SLIME] : 0; + + (void) newcham(mtmp, ptr, FALSE, cansee(mtmp->mx, mtmp->my)); } /* limit "instant" growth to prevent potential abuse */ diff --git a/src/mon.c b/src/mon.c index e89447d0a..96a8fc135 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mon.c 3.5 2008/02/07 */ +/* SCCS Id: @(#)mon.c 3.5 2008/10/20 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -697,12 +697,13 @@ meatmetal(mtmp) return 0; } +/* monster eats a pile of objects */ int meatobj(mtmp) /* for gelatinous cubes */ register struct monst *mtmp; { register struct obj *otmp, *otmp2; - struct permonst *ptr; + struct permonst *ptr, *original_ptr = mtmp->data; int poly, grow, heal, count = 0, ecount = 0; char buf[BUFSZ]; @@ -710,18 +711,56 @@ meatobj(mtmp) /* for gelatinous cubes */ /* If a pet, eating is handled separately, in dog.c */ if (mtmp->mtame) return 0; - /* Eats organic objects, including cloth and wood, if there */ - /* Engulfs others, except huge rocks and metal attached to player */ + /* eat organic objects, including cloth and wood, if present; + engulf others, except huge rocks and metal attached to player + [despite comment at top, doesn't assume that eater is a g.cube] */ for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; - if (is_organic(otmp) && !obj_resists(otmp, 5, 95) && - touch_artifact(otmp,mtmp)) { - if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && - !resists_ston(mtmp)) - continue; - if (otmp->otyp == AMULET_OF_STRANGULATION || - otmp->otyp == RIN_SLOW_DIGESTION) - continue; + + /* touch senstive items */ + if (otmp->otyp == CORPSE && + is_rider(&mons[otmp->corpsenm])) { + /* Rider corpse isn't just inedible; can't engulf it either */ + (void)revive_corpse(otmp); + + /* untouchable (or inaccessible) items */ + } else if ((otmp->otyp == CORPSE && + touch_petrifies(&mons[otmp->corpsenm]) && + !resists_ston(mtmp)) || + /* don't engulf boulders and statues or ball&chain */ + otmp->oclass == ROCK_CLASS || + otmp == uball || otmp == uchain) { + /* do nothing--neither eaten nor engulfed */ + continue; + + /* inedible items -- engulf these */ + } else if (!is_organic(otmp) || + obj_resists(otmp, 5, 95) || + !touch_artifact(otmp, mtmp) || + /* redundant due to non-organic composition but + included for emphasis */ + (otmp->otyp == AMULET_OF_STRANGULATION || + otmp->otyp == RIN_SLOW_DIGESTION) || + /* cockatrice corpses handled above; this + touch_petrifies() check catches eggs */ + ((otmp->otyp == CORPSE || otmp->otyp == EGG) && + ((touch_petrifies(&mons[otmp->corpsenm]) && + !resists_ston(mtmp)) || + (otmp->corpsenm == PM_GREEN_SLIME && + !slimeproof(mtmp->data))))) { + /* engulf */ + ++ecount; + if (ecount == 1) + Sprintf(buf, "%s engulfs %s.", Monnam(mtmp), + distant_name(otmp,doname)); + else if (ecount == 2) + Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp)); + obj_extract_self(otmp); + (void) mpickobj(mtmp, otmp); /* slurp */ + + /* lastly, edible items; yum! */ + } else { + /* devour */ ++count; if (cansee(mtmp->mx,mtmp->my) && flags.verbose) pline("%s eats %s!", Monnam(mtmp), @@ -760,33 +799,19 @@ meatobj(mtmp) /* for gelatinous cubes */ mtmp->mhp = mtmp->mhpmax; } /* in case it polymorphed or died */ - if (ptr != &mons[PM_GELATINOUS_CUBE]) + if (ptr != original_ptr) return !ptr ? 2 : 1; - } else if (otmp->otyp == CORPSE && - is_rider(&mons[otmp->corpsenm])) { - /* Rider corpse will always pass the obj_resists() test above - and not be eaten; we don't want it to be engulfed either */ - (void)revive_corpse(otmp); - /* continue; -- regardless of whether it revived */ - } else if (otmp->oclass != ROCK_CLASS && - otmp != uball && otmp != uchain) { - ++ecount; - if (ecount == 1) { - Sprintf(buf, "%s engulfs %s.", Monnam(mtmp), - distant_name(otmp,doname)); - } else if (ecount == 2) - Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp)); - obj_extract_self(otmp); - (void) mpickobj(mtmp, otmp); /* slurp */ } + /* Engulf & devour is instant, so don't set meating */ if (mtmp->minvis) newsym(mtmp->mx, mtmp->my); } + if (ecount > 0) { if (cansee(mtmp->mx, mtmp->my) && flags.verbose && buf[0]) pline("%s", buf); else if (!Deaf && flags.verbose) - You_hear("%s slurping sound%s.", + You_hear("%s slurping sound%s.", ecount == 1 ? "a" : "several", ecount == 1 ? "" : "s"); }