munstone fixes (trunk only)

From a bug report, a monster who eats a lizard
corpse in order to cure confusion was treated the same as one who did so
to cure petrification, losing intrinsic speed in the process.  In the same
report by <l>, monsters wouldn't eat lizard corpses to cure being stunned,
and those who ate them for another reason weren't cured of stunning, even
though the hero gets that benefit.  While fixing those, I added some code
to let monsters who are carrying tins of lizard or acidic monster use them
if they're also carrying a tin opener, dagger, or knife.  I don't think
any monsters except for nymphs are willing to pick up tins, so it won't
have much effect.  It now works for nymphs though.

     Examining the code while testing showed that mon_consume_unstone()
has been accessing the potion (acid) or corpse (lizard or acidic monster)
after the item had been used up, so that has been fixed too.  I never saw
any detectable problems due to this, but folks using a debugging malloc
implementation which overwrites freed memory may have not been suffering
collateral acid damage or receiving intended confusion cure, or perhaps
did get either or both of those effects when they shouldn't have.  Since
it only applied to monsters it wouldn't have been easy to observe.
This commit is contained in:
nethack.rankin
2006-04-13 07:10:48 +00:00
parent cc31b25634
commit a157ceae1b
2 changed files with 86 additions and 29 deletions

View File

@@ -136,6 +136,10 @@ preform autopickup and/or report on objects at the spot when a failed #untrap
attempt causes the hero to move onto a trap's location
thrown silver weapon hitting silver-hating poly'd hero got double silver damage
wielded silver weapon hitting silver-hating poly'd hero lacked silver message
monsters who ate lizard corpses to cure confusion would lose intrinsic speed
monsters couldn't eat lizard corpses to cure being stunned
code handling a monster's use of potion or food to cure stoning or confusion
was accessing freed memory after the object had been used up
Platform- and/or Interface-Specific Fixes
@@ -198,6 +202,7 @@ new effect for reading a scroll of light while confused
allow digging an adjacent pit with wand of digging while trapped in a pit
#terrain command for debug mode
digging can activate or disarm some types of traps
some monsters can eat tins in addition to corpses to cure some ailments
Platform- and/or Interface-Specific New Features

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)muse.c 3.5 2006/01/04 */
/* SCCS Id: @(#)muse.c 3.5 2006/04/11 */
/* Copyright (C) 1990 by Ken Arromdee */
/* NetHack may be freely redistributed. See license for details. */
@@ -28,6 +28,7 @@ STATIC_DCL void FDECL(mbhit,
(struct monst *,int,int FDECL((*),(MONST_P,OBJ_P)),
int FDECL((*),(OBJ_P,OBJ_P)),struct obj *));
STATIC_DCL void FDECL(you_aggravate, (struct monst *));
STATIC_DCL boolean FDECL(mcould_eat_tin, (struct monst *));
STATIC_DCL void FDECL(mon_consume_unstone, (struct monst *,struct obj *,
BOOLEAN_P,BOOLEAN_P));
@@ -282,14 +283,25 @@ struct monst *mtmp;
}
}
if (mtmp->mconf) {
for(obj = mtmp->minvent; obj; obj = obj->nobj) {
if (mtmp->mconf || mtmp->mstun) {
struct obj *liztin = 0;
for (obj = mtmp->minvent; obj; obj = obj->nobj) {
if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD) {
m.defensive = obj;
m.has_defense = MUSE_LIZARD_CORPSE;
return TRUE;
} else if (obj->otyp == TIN && obj->corpsenm == PM_LIZARD) {
liztin = obj;
}
}
/* confused or stunned monster might not be able to open tin */
if (liztin && mcould_eat_tin(mtmp) && rn2(3)) {
m.defensive = liztin;
/* tin and corpse ultimately end up being handled the same */
m.has_defense = MUSE_LIZARD_CORPSE;
return TRUE;
}
}
/* It so happens there are two unrelated cases when we might want to
@@ -2107,14 +2119,19 @@ struct monst *mon;
boolean by_you;
{
struct obj *obj;
boolean tinok;
if (resists_ston(mon)) return FALSE;
if (mon->meating || !mon->mcanmove || mon->msleeping) return FALSE;
for(obj = mon->minvent; obj; obj = obj->nobj) {
/* Monsters can also use potions of acid */
if ((obj->otyp == POT_ACID) || (obj->otyp == CORPSE &&
(obj->corpsenm == PM_LIZARD || (acidic(&mons[obj->corpsenm]) && obj->corpsenm != PM_GREEN_SLIME)))) {
tinok = mcould_eat_tin(mon);
for (obj = mon->minvent; obj; obj = obj->nobj) {
/* monsters can also use potions of acid */
if (obj->otyp == POT_ACID ||
((obj->otyp == CORPSE || (obj->otyp == TIN && tinok)) &&
obj->corpsenm == PM_LIZARD ||
(acidic(&mons[obj->corpsenm]) &&
obj->corpsenm != PM_GREEN_SLIME))) {
mon_consume_unstone(mon, obj, by_you, TRUE);
return TRUE;
}
@@ -2129,46 +2146,54 @@ struct obj *obj;
boolean by_you;
boolean stoning;
{
int nutrit = (obj->otyp == CORPSE) ? dog_nutrition(mon, obj) : 0;
/* also sets meating */
boolean vis = canseemon(mon),
tinned = obj->otyp == TIN,
food = obj->otyp == CORPSE || tinned,
acid = obj->otyp == POT_ACID || (food && acidic(&mons[obj->corpsenm])),
lizard = food && obj->corpsenm == PM_LIZARD;
int nutrit = food ? dog_nutrition(mon, obj) : 0; /* also sets meating */
/* give a "<mon> is slowing down" message and also remove
intrinsic speed (comparable to similar effect on the hero) */
mon_adjust_speed(mon, -3, (struct obj *)0);
if (stoning) mon_adjust_speed(mon, -3, (struct obj *)0);
if (canseemon(mon)) {
if (vis) {
long save_quan = obj->quan;
obj->quan = 1L;
pline("%s %ss %s.", Monnam(mon),
(obj->otyp == POT_ACID) ? "quaff" : "eat",
distant_name(obj,doname));
pline("%s %s %s.", Monnam(mon),
(obj->oclass == POTION_CLASS) ? "quaffs" :
(obj->otyp == TIN) ? "opens and eats the contents of" :
"eats",
distant_name(obj, doname));
obj->quan = save_quan;
} else if (!Deaf)
You_hear("%s.", (obj->otyp == POT_ACID) ? "drinking" : "chewing");
m_useup(mon, obj);
if (((obj->otyp == POT_ACID) || acidic(&mons[obj->corpsenm])) &&
!resists_acid(mon)) {
if (acid && !tinned && !resists_acid(mon)) {
mon->mhp -= rnd(15);
pline("%s has a very bad case of stomach acid.",
Monnam(mon));
if (vis)
pline("%s has a very bad case of stomach acid.", Monnam(mon));
if (mon->mhp <= 0) {
pline("%s dies!", Monnam(mon));
if (by_you) xkilled(mon, 0);
else mondead(mon);
return;
}
}
if (mon->mhp <= 0) {
pline("%s dies!", Monnam(mon));
if (by_you) xkilled(mon, 0);
else mondead(mon);
return;
}
if (stoning && canseemon(mon)) {
if (stoning && vis) {
if (Hallucination)
pline("What a pity - %s just ruined a future piece of art!",
mon_nam(mon));
pline("What a pity - %s just ruined a future piece of art!",
mon_nam(mon));
else
pline("%s seems limber!", Monnam(mon));
}
if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD && mon->mconf) {
if (lizard && (mon->mconf || mon->mstun)) {
mon->mconf = 0;
if (canseemon(mon))
mon->mstun = 0;
if (vis && !is_bat(mon->data) && mon->data != &mons[PM_STALKER])
pline("%s seems steadier now.", Monnam(mon));
}
if (mon->mtame && !mon->isminion && nutrit > 0) {
@@ -2181,4 +2206,31 @@ boolean stoning;
mon->mlstmv = monstermoves; /* it takes a turn */
}
STATIC_OVL boolean
mcould_eat_tin(mon)
struct monst *mon;
{
struct obj *obj, *mwep;
/* monkeys who manage to steal tins can't open and eat them
even if they happen to also have the appropriate tool */
if (is_animal(mon->data)) return FALSE;
mwep = MON_WEP(mon);
/* this is different from the player; tin opener or dagger doesn't
have to be wielded, and knife can be used instead of dagger
(even so, non-nymphs don't pick up tins, so only nymphs might
end up being able to benefit from them) */
for (obj = mon->minvent; obj; obj = obj->nobj) {
/* if stuck with a cursed weapon, don't check rest of inventory */
if (mwep && mwep->cursed && obj != mwep) continue;
if (obj->otyp == TIN_OPENER ||
(obj->oclass == WEAPON_CLASS &&
(objects[obj->otyp].oc_skill == P_DAGGER ||
objects[obj->otyp].oc_skill == P_KNIFE))) return TRUE;
}
return FALSE;
}
/*muse.c*/