pull request #1175 - obj->corpsenm fixes

Pull request by mkuoppal:  some objects which use the corpsenm field
to access the mons[] array can have a corpsenm value of NON_PM (-1)
and weren't avoiding array access in those cases.

In addition to a fixes entry for it, this makes some revisions to the
commited code, handling a few of the cases differently.

Closes #1175
This commit is contained in:
PatR
2024-01-06 15:13:31 -08:00
parent 4669676fc0
commit 83bdf71932
5 changed files with 34 additions and 40 deletions

View File

@@ -1348,6 +1348,7 @@ if polymorphing a potion turned it into oil, dipping potions produced oil
into non-oil kept its relative age (no noticeable effect though)
an engulfer capable of passing through iron bars could do so even when hero
was engulfed
some uses of mons[obj->corpsenm] weren't excluding obj->corpsenm==NON_PM (-1)
Fixes to 3.7.0-x General Problems Exposed Via git Repository

View File

@@ -199,6 +199,8 @@
#define touch_petrifies(ptr) \
((ptr) == &mons[PM_COCKATRICE] || (ptr) == &mons[PM_CHICKATRICE])
/* Medusa doesn't pass touch_petrifies() but does petrify if eaten */
#define flesh_petrifies(pm) (touch_petrifies(pm) || (pm) == &mons[PM_MEDUSA])
/* missiles made of rocks don't harm these: xorns and earth elementals
(but not ghosts and shades because that would impact all missile use

View File

@@ -929,17 +929,16 @@ dogfood(struct monst *mon, struct obj *obj)
switch (obj->oclass) {
case FOOD_CLASS:
fx = (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG)
/* corpsenm might be NON_PM (special tin, unhatachable egg) */
? obj->corpsenm
: NUMMONS; /* valid mons[mndx] to pacify static analyzer */
fptr = fx >= LOW_PM ? &mons[fx] : NULL;
: NON_PM;
/* mons[NUMMONS] is valid; predicate tests against it will fail */
fptr = &mons[(fx >= LOW_PM) ? fx : NUMMONS];
if (obj->otyp == CORPSE && is_rider(fptr))
return TABU;
if ((obj->otyp == CORPSE || obj->otyp == EGG)
/* Medusa's corpse doesn't pass the touch_petrifies() test
but does cause petrification if eaten */
&& ((fptr && touch_petrifies(fptr)) || obj->corpsenm == PM_MEDUSA)
&& flesh_petrifies(fptr) /* c*ckatrice or Medusa */
&& !resists_ston(mon))
return POISON;
if (obj->otyp == LUMP_OF_ROYAL_JELLY

View File

@@ -48,9 +48,6 @@ static int tin_ok(struct obj *);
/* also used to see if you're allowed to eat cats and dogs */
#define CANNIBAL_ALLOWED() (Role_if(PM_CAVE_DWELLER) || Race_if(PM_ORC))
/* monster types that cause hero to be turned into stone if eaten */
#define flesh_petrifies(pm) (touch_petrifies(pm) || (pm) == &mons[PM_MEDUSA])
/* Rider corpses are treated as non-rotting so that attempting to eat one
will be sure to reach the stage of eating where that meal is fatal;
acid blob corpses eventually rot away to nothing but before that happens
@@ -58,7 +55,7 @@ static int tin_ok(struct obj *);
become rotten */
#define nonrotting_corpse(mnum) \
((mnum) == PM_LIZARD || (mnum) == PM_LICHEN \
|| ((mnum) >= LOW_PM && is_rider(&mons[mnum])) \
|| is_rider(&mons[mnum]) \
|| (mnum) == PM_ACID_BLOB)
/* non-rotting non-corpses; unlike lizard corpses, these items will behave
@@ -1415,12 +1412,12 @@ tin_details(struct obj *obj, int mnum, char *buf)
void
set_tin_variety(struct obj *obj, int forcetype)
{
register int r;
int r, mnum = obj->corpsenm;
if (forcetype == SPINACH_TIN
|| (forcetype == HEALTHY_TIN
&& (obj->corpsenm == NON_PM /* empty or already spinach */
|| !vegetarian(&mons[obj->corpsenm])))) { /* replace meat */
&& (mnum == NON_PM /* empty or already spinach */
|| !vegetarian(&mons[mnum])))) { /* replace meat */
obj->corpsenm = NON_PM; /* not based on any monster */
obj->spe = 1; /* spinach */
return;
@@ -1434,17 +1431,18 @@ set_tin_variety(struct obj *obj, int forcetype)
r = forcetype;
} else { /* RANDOM_TIN */
r = rn2(TTSZ - 1); /* take your pick */
if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm))
if (r == ROTTEN_TIN && (mnum >= LOW_PM && nonrotting_corpse(mnum)))
r = HOMEMADE_TIN; /* lizards don't rot */
}
obj->spe = -(r + 1); /* offset by 1 to allow index 0 */
}
static int
tin_variety(struct obj *obj,
boolean displ) /* we're just displaying so leave things alone */
tin_variety(
struct obj *obj,
boolean displ) /* we're just displaying so leave things alone */
{
register int r;
int r, mnum = obj->corpsenm;
if (obj->spe == 1) {
r = SPINACH_TIN;
@@ -1453,13 +1451,14 @@ tin_variety(struct obj *obj,
} else if (obj->spe < 0) {
r = -(obj->spe);
--r; /* get rid of the offset */
} else
} else {
r = rn2(TTSZ - 1);
}
if (!displ && r == HOMEMADE_TIN && !obj->blessed && !rn2(7))
r = ROTTEN_TIN; /* some homemade tins go bad */
if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm))
if (r == ROTTEN_TIN && (mnum >= LOW_PM && nonrotting_corpse(mnum)))
r = HOMEMADE_TIN; /* lizards don't rot */
return r;
}
@@ -1762,12 +1761,15 @@ eatcorpse(struct obj *otmp)
int retcode = 0, tp = 0, mnum = otmp->corpsenm;
long rotted = 0L;
int ll_conduct = 0;
boolean stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
&& !poly_when_stoned(gy.youmonst.data)),
boolean stoneable,
slimeable = (mnum == PM_GREEN_SLIME && !Slimed && !Unchanging
&& !slimeproof(gy.youmonst.data)),
glob = otmp->globby ? TRUE : FALSE;
assert(mnum >= LOW_PM);
stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
&& !poly_when_stoned(gy.youmonst.data));
/* KMH, conduct */
if (!vegan(&mons[mnum]))
if (!u.uconduct.unvegan++) {

View File

@@ -11,7 +11,6 @@ static void sanity_check_single_mon(struct monst *, boolean, const char *);
static struct obj *make_corpse(struct monst *, unsigned);
static int minliquid_core(struct monst *);
static void m_calcdistress(struct monst *);
static boolean mstoning(const struct obj *obj);
static boolean monlineu(struct monst *, int, int);
static long mm_2way_aggression(struct monst *, struct monst *);
static long mm_aggression(struct monst *, struct monst *);
@@ -1157,24 +1156,13 @@ meatbox(struct monst *mon, struct obj *otmp)
}
}
static boolean
mstoning(const struct obj *obj)
{
const int nm = obj->corpsenm;
#define mstoning(obj) \
(ofood(obj) && obj->corpsenm >= LOW_PM \
&& flesh_petrifies(&mons[obj->corpsenm]))
if (nm < LOW_PM)
return FALSE;
if (nm == PM_MEDUSA)
return TRUE;
return ofood(obj) && touch_petrifies(&mons[nm]);
}
/* 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. */
/* Monster mtmp 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)
{
@@ -1429,8 +1417,10 @@ meatobj(struct monst* mtmp) /* for gelatinous cubes */
return (count > 0 || ecount > 0) ? 1 : 0;
}
#undef mstoning
/* Monster eats a corpse off the ground.
* Return value is 0 = nothing eaten, 1 = ate a corpse, 2 = died */
Return value is 0 = nothing eaten, 1 = ate a corpse, 2 = died. */
int
meatcorpse(
struct monst *mtmp) /* for purple worms and other voracious monsters */