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.
This commit is contained in:
nethack.rankin
2008-10-25 01:04:04 +00:00
parent 3425a19dff
commit bb5820b493
4 changed files with 78 additions and 37 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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");
}