From 83bdf71932cfce3808d1774e9259ee354c0090cd Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 6 Jan 2024 15:13:31 -0800 Subject: [PATCH] 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 --- doc/fixes3-7-0.txt | 1 + include/mondata.h | 2 ++ src/dog.c | 11 +++++------ src/eat.c | 32 +++++++++++++++++--------------- src/mon.c | 28 +++++++++------------------- 5 files changed, 34 insertions(+), 40 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 713537929..1bede7645 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -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 diff --git a/include/mondata.h b/include/mondata.h index b12d6e382..10ffcea8a 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -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 diff --git a/src/dog.c b/src/dog.c index 2bd734b44..85c04f3ec 100644 --- a/src/dog.c +++ b/src/dog.c @@ -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 diff --git a/src/eat.c b/src/eat.c index 020292440..804686dda 100644 --- a/src/eat.c +++ b/src/eat.c @@ -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++) { diff --git a/src/mon.c b/src/mon.c index d9e7067c4..ef5c63519 100644 --- a/src/mon.c +++ b/src/mon.c @@ -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 */