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
+1
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) 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 an engulfer capable of passing through iron bars could do so even when hero
was engulfed 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 Fixes to 3.7.0-x General Problems Exposed Via git Repository
+2
View File
@@ -199,6 +199,8 @@
#define touch_petrifies(ptr) \ #define touch_petrifies(ptr) \
((ptr) == &mons[PM_COCKATRICE] || (ptr) == &mons[PM_CHICKATRICE]) ((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 /* missiles made of rocks don't harm these: xorns and earth elementals
(but not ghosts and shades because that would impact all missile use (but not ghosts and shades because that would impact all missile use
+5 -6
View File
@@ -929,17 +929,16 @@ dogfood(struct monst *mon, struct obj *obj)
switch (obj->oclass) { switch (obj->oclass) {
case FOOD_CLASS: case FOOD_CLASS:
fx = (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG) fx = (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG)
/* corpsenm might be NON_PM (special tin, unhatachable egg) */
? obj->corpsenm ? obj->corpsenm
: NUMMONS; /* valid mons[mndx] to pacify static analyzer */ : NON_PM;
/* mons[NUMMONS] is valid; predicate tests against it will fail */
fptr = fx >= LOW_PM ? &mons[fx] : NULL; fptr = &mons[(fx >= LOW_PM) ? fx : NUMMONS];
if (obj->otyp == CORPSE && is_rider(fptr)) if (obj->otyp == CORPSE && is_rider(fptr))
return TABU; return TABU;
if ((obj->otyp == CORPSE || obj->otyp == EGG) if ((obj->otyp == CORPSE || obj->otyp == EGG)
/* Medusa's corpse doesn't pass the touch_petrifies() test && flesh_petrifies(fptr) /* c*ckatrice or Medusa */
but does cause petrification if eaten */
&& ((fptr && touch_petrifies(fptr)) || obj->corpsenm == PM_MEDUSA)
&& !resists_ston(mon)) && !resists_ston(mon))
return POISON; return POISON;
if (obj->otyp == LUMP_OF_ROYAL_JELLY if (obj->otyp == LUMP_OF_ROYAL_JELLY
+17 -15
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 */ /* 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)) #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 /* 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; 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 acid blob corpses eventually rot away to nothing but before that happens
@@ -58,7 +55,7 @@ static int tin_ok(struct obj *);
become rotten */ become rotten */
#define nonrotting_corpse(mnum) \ #define nonrotting_corpse(mnum) \
((mnum) == PM_LIZARD || (mnum) == PM_LICHEN \ ((mnum) == PM_LIZARD || (mnum) == PM_LICHEN \
|| ((mnum) >= LOW_PM && is_rider(&mons[mnum])) \ || is_rider(&mons[mnum]) \
|| (mnum) == PM_ACID_BLOB) || (mnum) == PM_ACID_BLOB)
/* non-rotting non-corpses; unlike lizard corpses, these items will behave /* 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 void
set_tin_variety(struct obj *obj, int forcetype) set_tin_variety(struct obj *obj, int forcetype)
{ {
register int r; int r, mnum = obj->corpsenm;
if (forcetype == SPINACH_TIN if (forcetype == SPINACH_TIN
|| (forcetype == HEALTHY_TIN || (forcetype == HEALTHY_TIN
&& (obj->corpsenm == NON_PM /* empty or already spinach */ && (mnum == NON_PM /* empty or already spinach */
|| !vegetarian(&mons[obj->corpsenm])))) { /* replace meat */ || !vegetarian(&mons[mnum])))) { /* replace meat */
obj->corpsenm = NON_PM; /* not based on any monster */ obj->corpsenm = NON_PM; /* not based on any monster */
obj->spe = 1; /* spinach */ obj->spe = 1; /* spinach */
return; return;
@@ -1434,17 +1431,18 @@ set_tin_variety(struct obj *obj, int forcetype)
r = forcetype; r = forcetype;
} else { /* RANDOM_TIN */ } else { /* RANDOM_TIN */
r = rn2(TTSZ - 1); /* take your pick */ 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 */ r = HOMEMADE_TIN; /* lizards don't rot */
} }
obj->spe = -(r + 1); /* offset by 1 to allow index 0 */ obj->spe = -(r + 1); /* offset by 1 to allow index 0 */
} }
static int static int
tin_variety(struct obj *obj, tin_variety(
boolean displ) /* we're just displaying so leave things alone */ 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) { if (obj->spe == 1) {
r = SPINACH_TIN; r = SPINACH_TIN;
@@ -1453,13 +1451,14 @@ tin_variety(struct obj *obj,
} else if (obj->spe < 0) { } else if (obj->spe < 0) {
r = -(obj->spe); r = -(obj->spe);
--r; /* get rid of the offset */ --r; /* get rid of the offset */
} else } else {
r = rn2(TTSZ - 1); r = rn2(TTSZ - 1);
}
if (!displ && r == HOMEMADE_TIN && !obj->blessed && !rn2(7)) if (!displ && r == HOMEMADE_TIN && !obj->blessed && !rn2(7))
r = ROTTEN_TIN; /* some homemade tins go bad */ 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 */ r = HOMEMADE_TIN; /* lizards don't rot */
return r; return r;
} }
@@ -1762,12 +1761,15 @@ eatcorpse(struct obj *otmp)
int retcode = 0, tp = 0, mnum = otmp->corpsenm; int retcode = 0, tp = 0, mnum = otmp->corpsenm;
long rotted = 0L; long rotted = 0L;
int ll_conduct = 0; int ll_conduct = 0;
boolean stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance boolean stoneable,
&& !poly_when_stoned(gy.youmonst.data)),
slimeable = (mnum == PM_GREEN_SLIME && !Slimed && !Unchanging slimeable = (mnum == PM_GREEN_SLIME && !Slimed && !Unchanging
&& !slimeproof(gy.youmonst.data)), && !slimeproof(gy.youmonst.data)),
glob = otmp->globby ? TRUE : FALSE; glob = otmp->globby ? TRUE : FALSE;
assert(mnum >= LOW_PM);
stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
&& !poly_when_stoned(gy.youmonst.data));
/* KMH, conduct */ /* KMH, conduct */
if (!vegan(&mons[mnum])) if (!vegan(&mons[mnum]))
if (!u.uconduct.unvegan++) { if (!u.uconduct.unvegan++) {
+9 -19
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 struct obj *make_corpse(struct monst *, unsigned);
static int minliquid_core(struct monst *); static int minliquid_core(struct monst *);
static void m_calcdistress(struct monst *); static void m_calcdistress(struct monst *);
static boolean mstoning(const struct obj *obj);
static boolean monlineu(struct monst *, int, int); static boolean monlineu(struct monst *, int, int);
static long mm_2way_aggression(struct monst *, struct monst *); static long mm_2way_aggression(struct monst *, struct monst *);
static long mm_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 #define mstoning(obj) \
mstoning(const struct obj *obj) (ofood(obj) && obj->corpsenm >= LOW_PM \
{ && flesh_petrifies(&mons[obj->corpsenm]))
const int nm = obj->corpsenm;
if (nm < LOW_PM) /* Monster mtmp consumes an object.
return FALSE; Monster may die, polymorph, grow up, heal, etc; meating is not changed.
Object is extracted from any linked list and freed. */
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. */
void void
m_consume_obj(struct monst *mtmp, struct obj *otmp) 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; return (count > 0 || ecount > 0) ? 1 : 0;
} }
#undef mstoning
/* Monster eats a corpse off the ground. /* 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 int
meatcorpse( meatcorpse(
struct monst *mtmp) /* for purple worms and other voracious monsters */ struct monst *mtmp) /* for purple worms and other voracious monsters */