fix github issue #729 - edibility_prompts()

Issue #729 by argrath points out that one of the checks in
edibility_prompts() couldn't work.

For the next-meal effect after reading a blessed scroll of food
detection, the check whether a corpse was tainted but not dangerous
because the hero had sickness resistance could never be evaluated.
An earlier condition would cause the routine to return before
reaching that check.

Move it sooner, even though doing so violates the "order by most
to least dangerous" guideline.  It was either that or eliminate it
altogether.

edibility_prompts() had a lot of repetitive code that has now been
condensed.

Simplify acid blob corpse handling--for all of eating, not just for
edibility_prompts()--by treating that as "never rots" so that the
'rotted' variable always stays 0.  Now checks for that variable
being greater than some threshold don't need to include "and not an
acid blob corpse" as an exception.  A side-effect of this change is
that not only do they never become tainted, they'll no longer yield
the "you feel sick" outcome when they're old but not old enough to
exceed the tainted threshold.

Bug fix:  edibility testing stopped warning about green slimes.
That worked in 3.6.x, but 3.7 changed the 'cadaver' variable to
exclude them so the check for eating a glob of green slime could no
longer be reached.

Fixes #729
This commit is contained in:
PatR
2022-04-21 16:40:43 -07:00
parent 98eebb97d2
commit e584f718a8
2 changed files with 67 additions and 106 deletions
+3
View File
@@ -1160,6 +1160,9 @@ items obtained via wishing while blind were erroneously being marked as 'seen
up close' so behaving differently from items picked up off the floor
corpses of neuter monsters had random chance to be flagged as female so would
only stack with others that made the same random choice
one-shot food testing ability conferred by blessed scroll of food detection
didn't warn about globs of green slime because the relevant code was
only executed for corpses, eggs, and tins, not for globs
curses: 'msg_window' option wasn't functional for curses unless the binary
also included tty support
+64 -106
View File
@@ -52,9 +52,13 @@ static int tin_ok(struct obj *);
#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 */
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
they can be sacrificed regardless of age which implies that they never
become rotten */
#define nonrotting_corpse(mnum) \
((mnum) == PM_LIZARD || (mnum) == PM_LICHEN || is_rider(&mons[mnum]))
((mnum) == PM_LIZARD || (mnum) == PM_LICHEN || is_rider(&mons[mnum]) \
|| (mnum) == PM_ACID_BLOB)
/* non-rotting non-corpses; unlike lizard corpses, these items will behave
as if rotten if they are cursed (fortune cookies handled elsewhere) */
@@ -1772,8 +1776,7 @@ eatcorpse(struct obj *otmp)
}
/* 3.7: globs don't become tainted, they shrink away */
if (mnum != PM_ACID_BLOB && !glob && !stoneable && !slimeable
&& rotted > 5L) {
if (!glob && !stoneable && !slimeable && rotted > 5L) {
boolean cannibal = maybe_cannibal(mnum, FALSE);
/* tp++; -- early return makes this unnecessary */
@@ -1815,6 +1818,7 @@ eatcorpse(struct obj *otmp)
KILLED_BY_AN);
} else
You("seem unaffected by the poison.");
/* now any corpse left too long will make you mildly ill */
} else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) {
tp++;
@@ -1860,11 +1864,11 @@ eatcorpse(struct obj *otmp)
&& herbivorous(g.youmonst.data))
: (carnivorous(g.youmonst.data)
&& !herbivorous(g.youmonst.data))),
palatable = ((vegetarian(&mons[mnum])
? herbivorous(g.youmonst.data)
: carnivorous(g.youmonst.data))
&& rn2(10)
&& ((rotted < 1) ? TRUE : !rn2((int)rotted+1)));
palatable = ((vegetarian(&mons[mnum])
? herbivorous(g.youmonst.data)
: carnivorous(g.youmonst.data))
&& rn2(10)
&& (rotted < 1 || !rn2((int) rotted + 1)));
const char *pmxnam = food_xname(otmp, FALSE);
if (!strncmpi(pmxnam, "the ", 4))
@@ -2474,7 +2478,7 @@ edibility_prompts(struct obj *otmp)
* or dangerous and avoid it.
*/
char buf[BUFSZ], foodsmell[BUFSZ],
it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ];
it_or_they[QBUFSZ];
/* 3.7: decaying globs don't become tainted anymore; in 3.6, they did */
boolean cadaver = (otmp->otyp == CORPSE), stoneorslime = FALSE;
int material = objects[otmp->otyp].oc_material, mnum = otmp->corpsenm;
@@ -2482,10 +2486,9 @@ edibility_prompts(struct obj *otmp)
Strcpy(foodsmell, Tobjnam(otmp, "smell"));
Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they");
Sprintf(eat_it_anyway, "Eat %s anyway?",
(otmp->quan == 1L) ? "it" : "one");
if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) {
if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN
|| otmp->otyp == GLOB_OF_GREEN_SLIME) {
/* These checks must match those in eatcorpse() */
stoneorslime = (mnum >= LOW_PM
&& flesh_petrifies(&mons[mnum])
@@ -2512,109 +2515,64 @@ edibility_prompts(struct obj *otmp)
* These problems with food should be checked in
* order from most detrimental to least detrimental.
*/
if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) {
buf[0] = '\0';
if (cadaver && rotted > 5L && !Sick_resistance) {
/* Tainted meat */
Snprintf(buf, sizeof(buf), "%s like %s could be tainted! %s",
foodsmell, it_or_they, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
}
if (stoneorslime) {
Snprintf(buf, sizeof(buf),
"%s like %s could be something very dangerous! %s",
foodsmell, it_or_they, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
}
if (otmp->orotten || (cadaver && rotted > 3L)) {
Snprintf(buf, sizeof buf, "%s like %s could be tainted!",
foodsmell, it_or_they);
} else if (stoneorslime) {
Snprintf(buf, sizeof buf,
"%s like %s could be something very dangerous!",
foodsmell, it_or_they);
} else if (cadaver && rotted > 5L && Sick_resistance) {
/* Tainted meat with Sick_resistance (testing for that is
redundant; we don't get this far for !Sick_resistance)
needs to be done now even though there is no danger because
it can't match after the rotten (cadaver && rotted > 3) test */
Snprintf(buf, sizeof buf, "%s like %s could be tainted.",
foodsmell, it_or_they);
} else if (otmp->orotten || (cadaver && rotted > 3L)) {
/* Rotten */
Snprintf(buf, sizeof(buf), "%s like %s could be rotten! %s",
foodsmell, it_or_they, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
}
if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
Snprintf(buf, sizeof buf, "%s like %s could be rotten!",
foodsmell, it_or_they);
} else if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
/* poisonous */
Snprintf(buf, sizeof(buf), "%s like %s might be poisonous! %s",
foodsmell, it_or_they, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
}
if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
Snprintf(buf, sizeof buf, "%s like %s might be poisonous!",
foodsmell, it_or_they);
} else if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
/* causes sleep, for long enough to be dangerous */
Snprintf(buf, sizeof(buf), "%s like %s might have been poisoned. %s",
foodsmell, it_or_they, eat_it_anyway);
return (yn_function(buf, ynchars, 'n') == 'n') ? 1 : 2;
}
if (cadaver && !vegetarian(&mons[mnum]) && !u.uconduct.unvegetarian
&& Role_if(PM_MONK)) {
Snprintf(buf, sizeof(buf), "%s unhealthy. %s", foodsmell,
eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
}
if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
Snprintf(buf, sizeof(buf), "%s rather acidic. %s",
foodsmell, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
}
if (Upolyd && u.umonnum == PM_RUST_MONSTER && is_metallic(otmp)
&& otmp->oerodeproof) {
Snprintf(buf, sizeof(buf), "%s disgusting to you right now. %s",
foodsmell, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
}
Snprintf(buf, sizeof buf, "%s like %s might have been poisoned.",
foodsmell, it_or_they);
} else if (cadaver && !vegetarian(&mons[mnum])
&& !u.uconduct.unvegetarian && Role_if(PM_MONK)) {
Snprintf(buf, sizeof buf, "%s unhealthy.", foodsmell);
} else if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
Snprintf(buf, sizeof buf, "%s rather acidic.", foodsmell);
} else if (Upolyd && u.umonnum == PM_RUST_MONSTER && is_metallic(otmp)
&& otmp->oerodeproof) {
Snprintf(buf, sizeof buf, "%s disgusting to you right now.",
foodsmell);
/*
* Breaks conduct, but otherwise safe.
*/
if (!u.uconduct.unvegan
&& ((material == LEATHER || material == BONE
|| material == DRAGON_HIDE || material == WAX)
|| (cadaver && !vegan(&mons[mnum])))) {
Snprintf(buf, sizeof(buf), "%s foul and unfamiliar to you. %s",
foodsmell, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
}
if (!u.uconduct.unvegetarian
&& ((material == LEATHER || material == BONE
|| material == DRAGON_HIDE)
|| (cadaver && !vegetarian(&mons[mnum])))) {
Snprintf(buf, sizeof(buf), "%s unfamiliar to you. %s",
foodsmell, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
} else if (!u.uconduct.unvegan
&& ((material == LEATHER || material == BONE
|| material == DRAGON_HIDE || material == WAX)
|| (cadaver && !vegan(&mons[mnum])))) {
Snprintf(buf, sizeof buf, "%s foul and unfamiliar to you.",
foodsmell);
} else if (!u.uconduct.unvegetarian
&& ((material == LEATHER || material == BONE
|| material == DRAGON_HIDE)
|| (cadaver && !vegetarian(&mons[mnum])))) {
Snprintf(buf, sizeof buf, "%s unfamiliar to you.", foodsmell);
}
if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) {
/* Tainted meat with Sick_resistance */
Snprintf(buf, sizeof(buf), "%s like %s could be tainted! %s",
foodsmell, it_or_they, eat_it_anyway);
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
if (*buf) {
Snprintf(eos(buf), sizeof buf - strlen(buf), " Eat %s anyway?",
(otmp->quan == 1L) ? "it" : "one");
return (yn_function(buf, ynchars, 'n') == 'n') ? 1 : 2;
}
return 0;
}