diff --git a/include/extern.h b/include/extern.h index 902cacc35..1ba34bb25 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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_move(struct monst *, int); extern void finish_meating(struct monst *); +extern void quickmimic(struct monst *); /* ### dokick.c ### */ @@ -1542,6 +1543,7 @@ extern int minliquid(struct monst *); extern boolean movemon_singlemon(struct monst *); extern int movemon(void); extern void meatbox(struct monst *, struct obj *); +extern void m_consume_obj(struct monst *, struct obj *); extern int meatmetal(struct monst *); extern int meatobj(struct monst *); extern int meatcorpse(struct monst *); diff --git a/src/dogmove.c b/src/dogmove.c index 6a0ed7a1a..3833ee626 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -22,7 +22,6 @@ static long score_targ(struct monst *, struct monst *); static boolean can_reach_location(struct monst *, coordxy, coordxy, coordxy, coordxy); static boolean could_reach_item(struct monst *, coordxy, coordxy); -static void quickmimic(struct monst *); /* pick a carried item for pet to drop */ struct obj * @@ -220,8 +219,7 @@ dog_eat(struct monst *mtmp, boolean devour) { register struct edog *edog = EDOG(mtmp); - boolean poly, grow, heal, eyes, slimer, deadmimic; - int nutrit, res, corpsenm; + int nutrit, res; long oprice; char objnambuf[BUFSZ], *obj_name; @@ -230,16 +228,6 @@ dog_eat(struct monst *mtmp, edog->hungrytime = gm.moves; 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 (mtmp->meating > 1) mtmp->meating /= 2; @@ -306,14 +294,6 @@ dog_eat(struct monst *mtmp, Strcpy(objnambuf, xname(obj)); 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) { /* The object's rustproofing is gone now */ if (obj->unpaid) @@ -326,54 +306,24 @@ dog_eat(struct monst *mtmp, pline("%s spits %s out in disgust!", Monnam(mtmp), obj_name); } - } else if (obj == uball) { - unpunish(); - delobj(obj); /* we assume this can't be unpaid */ - } else if (obj == uchain) { - unpunish(); } 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) { /* edible item owned by shop has been thrown or kicked by hero and caught by tame or food-tameable monst */ oprice = unpaid_cost(obj, TRUE); pline("That %s will cost you %ld %s.", objnambuf, 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... */ - /* 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; + return (DEADMONSTER(mtmp)) ? 2 : 1; } static void @@ -1427,7 +1377,7 @@ finish_meating(struct monst *mtmp) } } -static void +void quickmimic(struct monst *mtmp) { int idx = 0, trycnt = 5, spotted, seeloc; diff --git a/src/mon.c b/src/mon.c index fa6f2db5f..8736edbe3 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1125,6 +1125,73 @@ meatbox(struct monst *mon, struct obj *otmp) (ofood(obj) && (touch_petrifies(&mons[(obj)->corpsenm]) \ || (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). * Return value: 0 => nothing happened, 1 => monster ate something, @@ -1136,9 +1203,8 @@ int meatmetal(struct monst *mtmp) { struct obj *otmp; - struct permonst *ptr; 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 (mtmp->mtame) @@ -1185,56 +1251,9 @@ meatmetal(struct monst *mtmp) } } mtmp->meating = otmp->owt / 2 + 1; - /* Heal up to the object's weight in hp */ - if (mtmp->mhp < mtmp->mhpmax) { - mtmp->mhp += objects[otmp->otyp].oc_weight; - 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 */ - } + m_consume_obj(mtmp, otmp); + if (DEADMONSTER(mtmp)) + return 2; /* Left behind a pile? */ if (rnd(25) < 3) (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 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; buf[0] = '\0'; @@ -1337,42 +1356,14 @@ meatobj(struct monst* mtmp) /* for gelatinous cubes */ if (otmp->oclass == SCROLL_CLASS && objdescr_is(otmp, "YUM YUM")) pline("Yum%c", otmp->blessed ? '!' : '.'); - if (otmp->otyp == CORPSE) - mon_givit(mtmp, &mons[otmp->corpsenm]); } else { Soundeffect(se_slurping_sound, 30); if (Verbose(2, meatobj2)) You_hear("a slurping sound."); } - /* Heal up to the object's weight in hp */ - 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)); + m_consume_obj(mtmp, otmp); /* in case it polymorphed or died */ + ptr = mtmp->data; if (ptr != original_ptr) return !ptr ? 2 : 1; } @@ -1400,7 +1391,6 @@ meatcorpse( { struct obj *otmp; struct permonst *ptr, *original_ptr = mtmp->data, *corpsepm; - boolean poly, grow, heal, eyes = FALSE, vis = canseemon(mtmp); coordxy x = mtmp->mx, y = mtmp->my; /* if a pet, eating is handled separately, in dog.c */ @@ -1448,28 +1438,9 @@ meatcorpse( You_hear("a masticating sound."); } - mon_givit(mtmp, &mons[otmp->corpsenm]); - - /* [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)); + m_consume_obj(mtmp, otmp); /* in case it polymorphed or died */ + ptr = mtmp->data; if (ptr != original_ptr) return !ptr ? 2 : 1;