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 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 corpses of neuter monsters had random chance to be flagged as female so would
only stack with others that made the same random choice 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 curses: 'msg_window' option wasn't functional for curses unless the binary
also included tty support 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]) #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
they can be sacrificed regardless of age which implies that they never
become rotten */
#define nonrotting_corpse(mnum) \ #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 /* non-rotting non-corpses; unlike lizard corpses, these items will behave
as if rotten if they are cursed (fortune cookies handled elsewhere) */ 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 */ /* 3.7: globs don't become tainted, they shrink away */
if (mnum != PM_ACID_BLOB && !glob && !stoneable && !slimeable if (!glob && !stoneable && !slimeable && rotted > 5L) {
&& rotted > 5L) {
boolean cannibal = maybe_cannibal(mnum, FALSE); boolean cannibal = maybe_cannibal(mnum, FALSE);
/* tp++; -- early return makes this unnecessary */ /* tp++; -- early return makes this unnecessary */
@@ -1815,6 +1818,7 @@ eatcorpse(struct obj *otmp)
KILLED_BY_AN); KILLED_BY_AN);
} else } else
You("seem unaffected by the poison."); You("seem unaffected by the poison.");
/* now any corpse left too long will make you mildly ill */ /* now any corpse left too long will make you mildly ill */
} else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) { } else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) {
tp++; tp++;
@@ -1860,11 +1864,11 @@ eatcorpse(struct obj *otmp)
&& herbivorous(g.youmonst.data)) && herbivorous(g.youmonst.data))
: (carnivorous(g.youmonst.data) : (carnivorous(g.youmonst.data)
&& !herbivorous(g.youmonst.data))), && !herbivorous(g.youmonst.data))),
palatable = ((vegetarian(&mons[mnum]) palatable = ((vegetarian(&mons[mnum])
? herbivorous(g.youmonst.data) ? herbivorous(g.youmonst.data)
: carnivorous(g.youmonst.data)) : carnivorous(g.youmonst.data))
&& rn2(10) && rn2(10)
&& ((rotted < 1) ? TRUE : !rn2((int)rotted+1))); && (rotted < 1 || !rn2((int) rotted + 1)));
const char *pmxnam = food_xname(otmp, FALSE); const char *pmxnam = food_xname(otmp, FALSE);
if (!strncmpi(pmxnam, "the ", 4)) if (!strncmpi(pmxnam, "the ", 4))
@@ -2474,7 +2478,7 @@ edibility_prompts(struct obj *otmp)
* or dangerous and avoid it. * or dangerous and avoid it.
*/ */
char buf[BUFSZ], foodsmell[BUFSZ], 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 */ /* 3.7: decaying globs don't become tainted anymore; in 3.6, they did */
boolean cadaver = (otmp->otyp == CORPSE), stoneorslime = FALSE; boolean cadaver = (otmp->otyp == CORPSE), stoneorslime = FALSE;
int material = objects[otmp->otyp].oc_material, mnum = otmp->corpsenm; 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(foodsmell, Tobjnam(otmp, "smell"));
Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they"); 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() */ /* These checks must match those in eatcorpse() */
stoneorslime = (mnum >= LOW_PM stoneorslime = (mnum >= LOW_PM
&& flesh_petrifies(&mons[mnum]) && flesh_petrifies(&mons[mnum])
@@ -2512,109 +2515,64 @@ edibility_prompts(struct obj *otmp)
* These problems with food should be checked in * These problems with food should be checked in
* order from most detrimental to least detrimental. * 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 */ /* Tainted meat */
Snprintf(buf, sizeof(buf), "%s like %s could be tainted! %s", Snprintf(buf, sizeof buf, "%s like %s could be tainted!",
foodsmell, it_or_they, eat_it_anyway); foodsmell, it_or_they);
if (yn_function(buf, ynchars, 'n') == 'n') } else if (stoneorslime) {
return 1; Snprintf(buf, sizeof buf,
else "%s like %s could be something very dangerous!",
return 2; foodsmell, it_or_they);
} } else if (cadaver && rotted > 5L && Sick_resistance) {
if (stoneorslime) { /* Tainted meat with Sick_resistance (testing for that is
Snprintf(buf, sizeof(buf), redundant; we don't get this far for !Sick_resistance)
"%s like %s could be something very dangerous! %s", needs to be done now even though there is no danger because
foodsmell, it_or_they, eat_it_anyway); it can't match after the rotten (cadaver && rotted > 3) test */
if (yn_function(buf, ynchars, 'n') == 'n') Snprintf(buf, sizeof buf, "%s like %s could be tainted.",
return 1; foodsmell, it_or_they);
else } else if (otmp->orotten || (cadaver && rotted > 3L)) {
return 2;
}
if (otmp->orotten || (cadaver && rotted > 3L)) {
/* Rotten */ /* Rotten */
Snprintf(buf, sizeof(buf), "%s like %s could be rotten! %s", Snprintf(buf, sizeof buf, "%s like %s could be rotten!",
foodsmell, it_or_they, eat_it_anyway); foodsmell, it_or_they);
if (yn_function(buf, ynchars, 'n') == 'n') } else if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
return 1;
else
return 2;
}
if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
/* poisonous */ /* poisonous */
Snprintf(buf, sizeof(buf), "%s like %s might be poisonous! %s", Snprintf(buf, sizeof buf, "%s like %s might be poisonous!",
foodsmell, it_or_they, eat_it_anyway); foodsmell, it_or_they);
if (yn_function(buf, ynchars, 'n') == 'n') } else if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
return 1;
else
return 2;
}
if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
/* causes sleep, for long enough to be dangerous */ /* causes sleep, for long enough to be dangerous */
Snprintf(buf, sizeof(buf), "%s like %s might have been poisoned. %s", Snprintf(buf, sizeof buf, "%s like %s might have been poisoned.",
foodsmell, it_or_they, eat_it_anyway); foodsmell, it_or_they);
return (yn_function(buf, ynchars, 'n') == 'n') ? 1 : 2; } else if (cadaver && !vegetarian(&mons[mnum])
} && !u.uconduct.unvegetarian && Role_if(PM_MONK)) {
if (cadaver && !vegetarian(&mons[mnum]) && !u.uconduct.unvegetarian Snprintf(buf, sizeof buf, "%s unhealthy.", foodsmell);
&& Role_if(PM_MONK)) { } else if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
Snprintf(buf, sizeof(buf), "%s unhealthy. %s", foodsmell, Snprintf(buf, sizeof buf, "%s rather acidic.", foodsmell);
eat_it_anyway); } else if (Upolyd && u.umonnum == PM_RUST_MONSTER && is_metallic(otmp)
if (yn_function(buf, ynchars, 'n') == 'n') && otmp->oerodeproof) {
return 1; Snprintf(buf, sizeof buf, "%s disgusting to you right now.",
else foodsmell);
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;
}
/* /*
* Breaks conduct, but otherwise safe. * Breaks conduct, but otherwise safe.
*/ */
if (!u.uconduct.unvegan } else if (!u.uconduct.unvegan
&& ((material == LEATHER || material == BONE && ((material == LEATHER || material == BONE
|| material == DRAGON_HIDE || material == WAX) || material == DRAGON_HIDE || material == WAX)
|| (cadaver && !vegan(&mons[mnum])))) { || (cadaver && !vegan(&mons[mnum])))) {
Snprintf(buf, sizeof(buf), "%s foul and unfamiliar to you. %s", Snprintf(buf, sizeof buf, "%s foul and unfamiliar to you.",
foodsmell, eat_it_anyway); foodsmell);
if (yn_function(buf, ynchars, 'n') == 'n') } else if (!u.uconduct.unvegetarian
return 1; && ((material == LEATHER || material == BONE
else || material == DRAGON_HIDE)
return 2; || (cadaver && !vegetarian(&mons[mnum])))) {
} Snprintf(buf, sizeof buf, "%s unfamiliar to you.", foodsmell);
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;
} }
if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) { if (*buf) {
/* Tainted meat with Sick_resistance */ Snprintf(eos(buf), sizeof buf - strlen(buf), " Eat %s anyway?",
Snprintf(buf, sizeof(buf), "%s like %s could be tainted! %s", (otmp->quan == 1L) ? "it" : "one");
foodsmell, it_or_they, eat_it_anyway); return (yn_function(buf, ynchars, 'n') == 'n') ? 1 : 2;
if (yn_function(buf, ynchars, 'n') == 'n')
return 1;
else
return 2;
} }
return 0; return 0;
} }