Unify monster-consumes-object

This code was in three different places; pet eating,
monster eating metal, and monster eating other objects.

Other than very minor changes (eg. rustproofing completely
protects pets from bad effects, rustproof items are no longer
giving apport, and monsters eating corpses are healed), it
should behave the same as before... But I haven't exhaustively
gone through every iteration.
This commit is contained in:
Pasi Kallinen
2023-01-21 10:13:26 +02:00
parent f607a775a8
commit b859288f5c
3 changed files with 88 additions and 165 deletions
+2
View File
@@ -621,6 +621,7 @@ extern int dog_nutrition(struct monst *, struct obj *);
extern int dog_eat(struct monst *, struct obj *, coordxy, coordxy, boolean); extern int dog_eat(struct monst *, struct obj *, coordxy, coordxy, boolean);
extern int dog_move(struct monst *, int); extern int dog_move(struct monst *, int);
extern void finish_meating(struct monst *); extern void finish_meating(struct monst *);
extern void quickmimic(struct monst *);
/* ### dokick.c ### */ /* ### dokick.c ### */
@@ -1542,6 +1543,7 @@ extern int minliquid(struct monst *);
extern boolean movemon_singlemon(struct monst *); extern boolean movemon_singlemon(struct monst *);
extern int movemon(void); extern int movemon(void);
extern void meatbox(struct monst *, struct obj *); extern void meatbox(struct monst *, struct obj *);
extern void m_consume_obj(struct monst *, struct obj *);
extern int meatmetal(struct monst *); extern int meatmetal(struct monst *);
extern int meatobj(struct monst *); extern int meatobj(struct monst *);
extern int meatcorpse(struct monst *); extern int meatcorpse(struct monst *);
+10 -60
View File
@@ -22,7 +22,6 @@ static long score_targ(struct monst *, struct monst *);
static boolean can_reach_location(struct monst *, coordxy, coordxy, coordxy, static boolean can_reach_location(struct monst *, coordxy, coordxy, coordxy,
coordxy); coordxy);
static boolean could_reach_item(struct monst *, coordxy, coordxy); static boolean could_reach_item(struct monst *, coordxy, coordxy);
static void quickmimic(struct monst *);
/* pick a carried item for pet to drop */ /* pick a carried item for pet to drop */
struct obj * struct obj *
@@ -220,8 +219,7 @@ dog_eat(struct monst *mtmp,
boolean devour) boolean devour)
{ {
register struct edog *edog = EDOG(mtmp); register struct edog *edog = EDOG(mtmp);
boolean poly, grow, heal, eyes, slimer, deadmimic; int nutrit, res;
int nutrit, res, corpsenm;
long oprice; long oprice;
char objnambuf[BUFSZ], *obj_name; char objnambuf[BUFSZ], *obj_name;
@@ -230,16 +228,6 @@ dog_eat(struct monst *mtmp,
edog->hungrytime = gm.moves; edog->hungrytime = gm.moves;
nutrit = dog_nutrition(mtmp, obj); nutrit = dog_nutrition(mtmp, obj);
deadmimic = (obj->otyp == CORPSE && (obj->corpsenm == PM_SMALL_MIMIC
|| obj->corpsenm == PM_LARGE_MIMIC
|| obj->corpsenm == PM_GIANT_MIMIC));
slimer = (obj->otyp == GLOB_OF_GREEN_SLIME);
poly = polyfodder(obj);
grow = mlevelgain(obj);
heal = mhealup(obj);
eyes = (obj->otyp == CARROT);
corpsenm = (obj->otyp == CORPSE ? obj->corpsenm : NON_PM);
if (devour) { if (devour) {
if (mtmp->meating > 1) if (mtmp->meating > 1)
mtmp->meating /= 2; mtmp->meating /= 2;
@@ -306,14 +294,6 @@ dog_eat(struct monst *mtmp,
Strcpy(objnambuf, xname(obj)); Strcpy(objnambuf, xname(obj));
iflags.suppress_price--; iflags.suppress_price--;
} }
/* some monsters that eat items could eat a container with contents */
if (Has_contents(obj))
meatbox(mtmp, obj);
/* It's a reward if it's DOGFOOD and the player dropped/threw it.
We know the player had it if invlet is set. -dlc */
if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet)
edog->apport += (int) (200L / ((long) edog->dropdist + gm.moves
- edog->droptime));
if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) { if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) {
/* The object's rustproofing is gone now */ /* The object's rustproofing is gone now */
if (obj->unpaid) if (obj->unpaid)
@@ -326,54 +306,24 @@ dog_eat(struct monst *mtmp,
pline("%s spits %s out in disgust!", pline("%s spits %s out in disgust!",
Monnam(mtmp), obj_name); Monnam(mtmp), obj_name);
} }
} else if (obj == uball) {
unpunish();
delobj(obj); /* we assume this can't be unpaid */
} else if (obj == uchain) {
unpunish();
} else { } else {
/* It's a reward if it's DOGFOOD and the player dropped/threw it.
We know the player had it if invlet is set. -dlc */
if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet)
edog->apport += (int) (200L / ((long) edog->dropdist + gm.moves
- edog->droptime));
m_consume_obj(mtmp, obj);
if (obj->unpaid) { if (obj->unpaid) {
/* edible item owned by shop has been thrown or kicked /* edible item owned by shop has been thrown or kicked
by hero and caught by tame or food-tameable monst */ by hero and caught by tame or food-tameable monst */
oprice = unpaid_cost(obj, TRUE); oprice = unpaid_cost(obj, TRUE);
pline("That %s will cost you %ld %s.", objnambuf, oprice, pline("That %s will cost you %ld %s.", objnambuf, oprice,
currency(oprice)); currency(oprice));
/* delobj->obfree will handle actual shop billing update */ /* m_consume_obj->delobj->obfree will handle actual shop billing update */
} }
delobj(obj);
} }
#if 0 /* pet is eating, so slime recovery is not feasible... */ return (DEADMONSTER(mtmp)) ? 2 : 1;
/* turning into slime might be cureable */
if (slimer && munslime(mtmp, FALSE)) {
/* but the cure (fire directed at self) might be fatal */
if (DEADMONSTER(mtmp))
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,
cansee(mtmp->mx, mtmp->my) ? NC_SHOW_MSG : 0);
}
/* limit "instant" growth to prevent potential abuse */
if (grow && (int) mtmp->m_lev < (int) mtmp->data->mlevel + 15) {
if (!grow_up(mtmp, (struct monst *) 0))
return 2;
}
if (heal)
mtmp->mhp = mtmp->mhpmax;
if ((eyes || heal) && !mtmp->mcansee)
mcureblindness(mtmp, canseemon(mtmp));
if (deadmimic)
quickmimic(mtmp);
if (corpsenm != NON_PM)
mon_givit(mtmp, &mons[corpsenm]);
return 1;
} }
static void static void
@@ -1427,7 +1377,7 @@ finish_meating(struct monst *mtmp)
} }
} }
static void void
quickmimic(struct monst *mtmp) quickmimic(struct monst *mtmp)
{ {
int idx = 0, trycnt = 5, spotted, seeloc; int idx = 0, trycnt = 5, spotted, seeloc;
+76 -105
View File
@@ -1125,6 +1125,73 @@ meatbox(struct monst *mon, struct obj *otmp)
(ofood(obj) && (touch_petrifies(&mons[(obj)->corpsenm]) \ (ofood(obj) && (touch_petrifies(&mons[(obj)->corpsenm]) \
|| (obj)->corpsenm == PM_MEDUSA)) || (obj)->corpsenm == PM_MEDUSA))
/* monster consumes an object.
monster may die, polymorph, grow up, heal, etc; meating is not changed.
object is extracted from any linked list and freed. */
void
m_consume_obj(struct monst *mtmp, struct obj *otmp)
{
boolean ispet = mtmp->mtame;
/* non-pet: Heal up to the object's weight in hp */
if (!ispet && mtmp->mhp < mtmp->mhpmax) {
mtmp->mhp += objects[otmp->otyp].oc_weight;
if (mtmp->mhp > mtmp->mhpmax)
mtmp->mhp = mtmp->mhpmax;
}
if (Has_contents(otmp))
meatbox(mtmp, otmp);
if (otmp == uball) {
unpunish();
delobj(otmp);
} else if (otmp == uchain) {
unpunish(); /* frees uchain */
} else {
boolean deadmimic, slimer;
int poly, grow, heal, eyes, mstone, vis = canseemon(mtmp);
int corpsenm = (otmp->otyp == CORPSE ? otmp->corpsenm : NON_PM);
deadmimic = (otmp->otyp == CORPSE && (otmp->corpsenm == PM_SMALL_MIMIC
|| otmp->corpsenm == PM_LARGE_MIMIC
|| otmp->corpsenm == PM_GIANT_MIMIC));
slimer = (otmp->otyp == GLOB_OF_GREEN_SLIME);
poly = polyfodder(otmp);
grow = mlevelgain(otmp);
heal = mhealup(otmp);
eyes = (otmp->otyp == CARROT);
mstone = mstoning(otmp);
delobj(otmp); /* munch */
if (poly || slimer) {
struct permonst *ptr = slimer ? &mons[PM_GREEN_SLIME] : 0;
(void) newcham(mtmp, ptr, vis ? NC_SHOW_MSG : NO_NC_FLAGS);
}
if (grow) {
if ((ispet && (int) mtmp->m_lev < (int) mtmp->data->mlevel + 15)
|| !ispet)
(void) grow_up(mtmp, (struct monst *) 0);
}
if (mstone) {
if (poly_when_stoned(mtmp->data)) {
mon_to_stone(mtmp);
} else if (!resists_ston(mtmp)) {
if (vis)
pline("%s turns to stone!", Monnam(mtmp));
monstone(mtmp);
}
}
if (heal)
mtmp->mhp = mtmp->mhpmax;
if ((eyes || heal) && !mtmp->mcansee)
mcureblindness(mtmp, canseemon(mtmp));
if (ispet && deadmimic)
quickmimic(mtmp);
if (corpsenm != NON_PM)
mon_givit(mtmp, &mons[corpsenm]);
}
}
/* /*
* Maybe eat a metallic object (not just gold). * Maybe eat a metallic object (not just gold).
* Return value: 0 => nothing happened, 1 => monster ate something, * Return value: 0 => nothing happened, 1 => monster ate something,
@@ -1136,9 +1203,8 @@ int
meatmetal(struct monst *mtmp) meatmetal(struct monst *mtmp)
{ {
struct obj *otmp; struct obj *otmp;
struct permonst *ptr;
char *otmpname; char *otmpname;
int poly, grow, heal, mstone, vis = canseemon(mtmp); int vis = canseemon(mtmp);
/* If a pet, eating is handled separately, in dog.c */ /* If a pet, eating is handled separately, in dog.c */
if (mtmp->mtame) if (mtmp->mtame)
@@ -1185,56 +1251,9 @@ meatmetal(struct monst *mtmp)
} }
} }
mtmp->meating = otmp->owt / 2 + 1; mtmp->meating = otmp->owt / 2 + 1;
/* Heal up to the object's weight in hp */ m_consume_obj(mtmp, otmp);
if (mtmp->mhp < mtmp->mhpmax) { if (DEADMONSTER(mtmp))
mtmp->mhp += objects[otmp->otyp].oc_weight; return 2;
if (mtmp->mhp > mtmp->mhpmax)
mtmp->mhp = mtmp->mhpmax;
}
/* Currently there shouldn't be any metal object with
contents, but just in case... */
if (Has_contents(otmp))
meatbox(mtmp, otmp);
if (otmp == uball) {
unpunish();
delobj(otmp);
} else if (otmp == uchain) {
unpunish(); /* frees uchain */
} else {
/* these can occur via eating metal if it's a tin
[can't be slimed; that could only happen via glob] */
poly = polyfodder(otmp);
grow = mlevelgain(otmp);
heal = mhealup(otmp);
mstone = mstoning(otmp);
delobj(otmp);
ptr = mtmp->data;
if (poly) {
if (newcham(mtmp, (struct permonst *) 0,
vis ? NC_SHOW_MSG : NO_NC_FLAGS))
ptr = mtmp->data;
} else if (grow) {
ptr = grow_up(mtmp, (struct monst *) 0);
} else if (mstone) {
if (poly_when_stoned(ptr)) {
mon_to_stone(mtmp);
ptr = mtmp->data;
} else if (!resists_ston(mtmp)) {
if (vis)
pline("%s turns to stone!", Monnam(mtmp));
monstone(mtmp);
/* might be life-saved if had a previous shape
which was capable to putting on an amulet */
if (DEADMONSTER(mtmp))
ptr = (struct permonst *) 0;
}
} else if (heal) {
mtmp->mhp = mtmp->mhpmax;
mcureblindness(mtmp, canseemon(mtmp));
}
if (!ptr)
return 2; /* it died */
}
/* Left behind a pile? */ /* Left behind a pile? */
if (rnd(25) < 3) if (rnd(25) < 3)
(void) mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); (void) mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE);
@@ -1252,7 +1271,7 @@ meatobj(struct monst* mtmp) /* for gelatinous cubes */
{ {
struct obj *otmp, *otmp2; struct obj *otmp, *otmp2;
struct permonst *ptr, *original_ptr = mtmp->data; struct permonst *ptr, *original_ptr = mtmp->data;
int poly, grow, heal, eyes, count = 0, ecount = 0, vis = canseemon(mtmp); int count = 0, ecount = 0;
char buf[BUFSZ], *otmpname; char buf[BUFSZ], *otmpname;
buf[0] = '\0'; buf[0] = '\0';
@@ -1337,42 +1356,14 @@ meatobj(struct monst* mtmp) /* for gelatinous cubes */
if (otmp->oclass == SCROLL_CLASS if (otmp->oclass == SCROLL_CLASS
&& objdescr_is(otmp, "YUM YUM")) && objdescr_is(otmp, "YUM YUM"))
pline("Yum%c", otmp->blessed ? '!' : '.'); pline("Yum%c", otmp->blessed ? '!' : '.');
if (otmp->otyp == CORPSE)
mon_givit(mtmp, &mons[otmp->corpsenm]);
} else { } else {
Soundeffect(se_slurping_sound, 30); Soundeffect(se_slurping_sound, 30);
if (Verbose(2, meatobj2)) if (Verbose(2, meatobj2))
You_hear("a slurping sound."); You_hear("a slurping sound.");
} }
/* Heal up to the object's weight in hp */ m_consume_obj(mtmp, otmp);
if (mtmp->mhp < mtmp->mhpmax) {
mtmp->mhp += objects[otmp->otyp].oc_weight;
if (mtmp->mhp > mtmp->mhpmax)
mtmp->mhp = mtmp->mhpmax;
}
if (Has_contents(otmp))
meatbox(mtmp, otmp);
/* possibility of being turned to stone or into slime can't
reach here (don't touch for cockatrice corpse, engulf rather
than eat for tin, cockatrice egg, or glob of green slime) */
poly = polyfodder(otmp);
grow = mlevelgain(otmp);
heal = mhealup(otmp);
eyes = (otmp->otyp == CARROT);
delobj(otmp); /* munch */
ptr = mtmp->data;
if (poly) {
if (newcham(mtmp, (struct permonst *) 0,
vis ? NC_SHOW_MSG : NO_NC_FLAGS))
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 */ /* in case it polymorphed or died */
ptr = mtmp->data;
if (ptr != original_ptr) if (ptr != original_ptr)
return !ptr ? 2 : 1; return !ptr ? 2 : 1;
} }
@@ -1400,7 +1391,6 @@ meatcorpse(
{ {
struct obj *otmp; struct obj *otmp;
struct permonst *ptr, *original_ptr = mtmp->data, *corpsepm; struct permonst *ptr, *original_ptr = mtmp->data, *corpsepm;
boolean poly, grow, heal, eyes = FALSE, vis = canseemon(mtmp);
coordxy x = mtmp->mx, y = mtmp->my; coordxy x = mtmp->mx, y = mtmp->my;
/* if a pet, eating is handled separately, in dog.c */ /* if a pet, eating is handled separately, in dog.c */
@@ -1448,28 +1438,9 @@ meatcorpse(
You_hear("a masticating sound."); You_hear("a masticating sound.");
} }
mon_givit(mtmp, &mons[otmp->corpsenm]); m_consume_obj(mtmp, otmp);
/* [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); /*[always false since not a corpse]*/
ptr = original_ptr;
delobj(otmp);
if (poly) {
if (newcham(mtmp, (struct permonst *) 0,
vis ? NC_SHOW_MSG : NO_NC_FLAGS))
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 */ /* in case it polymorphed or died */
ptr = mtmp->data;
if (ptr != original_ptr) if (ptr != original_ptr)
return !ptr ? 2 : 1; return !ptr ? 2 : 1;