tin consumption edge cases
If eating a tin killed the hero (choked, turned to stone, poly'd into a new man with new Xp too low to survive) and bones were saved, the tin remained intact in them. When hero who is poly'd into metallivore form eats a tin, give a little extra nutrition for the tin itself. Also, eat it immediately by skipping the "It smells like <creature>" message and "Eat it? [yn]" prompt. (The message while eating it also reports <creature>, so skipping the 'smells' one doesn't end up hiding anything.)
This commit is contained in:
@@ -1476,6 +1476,11 @@ a pet with the hides-under attribute could "move reluctantly over" a cursed
|
|||||||
prevent monster generation in the sokoban trap hallway
|
prevent monster generation in the sokoban trap hallway
|
||||||
change MSGHANDLER from compile-time to sysconf option
|
change MSGHANDLER from compile-time to sysconf option
|
||||||
allow changing extended command autocompletions via #optionsfull
|
allow changing extended command autocompletions via #optionsfull
|
||||||
|
if eating a tin's contents caused the hero to choke to death or turn to stone,
|
||||||
|
resulting bones would contain the tin still intact
|
||||||
|
when hero who is poly'd into metallivore form eats a tin, bypass "smells like
|
||||||
|
<monster>" feedback and the "Eat it?" prompt; just eat the contents
|
||||||
|
along with the tin without asking
|
||||||
|
|
||||||
|
|
||||||
Fixes to 3.7.0-x General Problems Exposed Via git Repository
|
Fixes to 3.7.0-x General Problems Exposed Via git Repository
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ staticfn boolean temp_givit(int, struct permonst *);
|
|||||||
staticfn void givit(int, struct permonst *);
|
staticfn void givit(int, struct permonst *);
|
||||||
staticfn void eye_of_newt_buzz(void);
|
staticfn void eye_of_newt_buzz(void);
|
||||||
staticfn void cpostfx(int);
|
staticfn void cpostfx(int);
|
||||||
|
staticfn void use_up_tin(struct obj *) NONNULLARG1;
|
||||||
staticfn void consume_tin(const char *);
|
staticfn void consume_tin(const char *);
|
||||||
staticfn void start_tin(struct obj *);
|
staticfn void start_tin(struct obj *);
|
||||||
staticfn int eatcorpse(struct obj *);
|
staticfn int eatcorpse(struct obj *);
|
||||||
@@ -788,6 +789,10 @@ cprefx(int pm)
|
|||||||
if (!Stone_resistance
|
if (!Stone_resistance
|
||||||
&& !(poly_when_stoned(gy.youmonst.data)
|
&& !(poly_when_stoned(gy.youmonst.data)
|
||||||
&& polymon(PM_STONE_GOLEM))) {
|
&& polymon(PM_STONE_GOLEM))) {
|
||||||
|
/* if food was a tin, use it up early to keep it out of bones */
|
||||||
|
if (svc.context.tin.tin)
|
||||||
|
use_up_tin(svc.context.tin.tin);
|
||||||
|
|
||||||
Sprintf(svk.killer.name, "tasting %s meat",
|
Sprintf(svk.killer.name, "tasting %s meat",
|
||||||
mons[pm].pmnames[NEUTRAL]);
|
mons[pm].pmnames[NEUTRAL]);
|
||||||
svk.killer.format = KILLED_BY;
|
svk.killer.format = KILLED_BY;
|
||||||
@@ -1232,6 +1237,14 @@ cpostfx(int pm)
|
|||||||
if (Unchanging) {
|
if (Unchanging) {
|
||||||
You_feel("momentarily different."); /* same as poly trap */
|
You_feel("momentarily different."); /* same as poly trap */
|
||||||
} else {
|
} else {
|
||||||
|
/* polyself() is potentially fatal; if food is a tin, use it up
|
||||||
|
early to keep it out of bones */
|
||||||
|
if (svc.context.tin.tin) {
|
||||||
|
use_up_tin(svc.context.tin.tin);
|
||||||
|
/* most tin effects end up being skipped */
|
||||||
|
lesshungry(200 + (metallivorous(gy.youmonst.data) ? 5 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
You("%s.", (pm == PM_GENETIC_ENGINEER)
|
You("%s.", (pm == PM_GENETIC_ENGINEER)
|
||||||
? "undergo a freakish metamorphosis"
|
? "undergo a freakish metamorphosis"
|
||||||
: "feel a change coming over you");
|
: "feel a change coming over you");
|
||||||
@@ -1486,18 +1499,34 @@ tin_variety(
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* finish consume_tin(); also potentially used by cprefx() and cpostfx() */
|
||||||
|
staticfn void
|
||||||
|
use_up_tin(struct obj *tin)
|
||||||
|
{
|
||||||
|
if (carried(tin))
|
||||||
|
useup(tin);
|
||||||
|
else
|
||||||
|
useupf(tin, 1L);
|
||||||
|
/* reset tin context */
|
||||||
|
svc.context.tin.tin = (struct obj *) NULL;
|
||||||
|
svc.context.tin.o_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
staticfn void
|
staticfn void
|
||||||
consume_tin(const char *mesg)
|
consume_tin(const char *mesg)
|
||||||
{
|
{
|
||||||
const char *what;
|
const char *what;
|
||||||
int which, mnum, r;
|
int which, mnum, r, nutamt;
|
||||||
|
/* if you've eaten tin itself, chance to not eat contents gets bypassed */
|
||||||
|
boolean always_eat = metallivorous(gy.youmonst.data);
|
||||||
struct obj *tin = svc.context.tin.tin;
|
struct obj *tin = svc.context.tin.tin;
|
||||||
|
|
||||||
r = tin_variety(tin, FALSE);
|
r = tin_variety(tin, FALSE);
|
||||||
if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) {
|
if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) {
|
||||||
b_trapped("tin", NO_PART);
|
b_trapped("tin", NO_PART);
|
||||||
tin = costly_tin(COST_DSTROY);
|
tin = costly_tin(COST_DSTROY);
|
||||||
goto use_up_tin;
|
use_up_tin(tin);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pline1(mesg); /* "You succeed in opening the tin." */
|
pline1(mesg); /* "You succeed in opening the tin." */
|
||||||
@@ -1508,7 +1537,10 @@ consume_tin(const char *mesg)
|
|||||||
pline("It turns out to be empty.");
|
pline("It turns out to be empty.");
|
||||||
tin->dknown = tin->known = 1;
|
tin->dknown = tin->known = 1;
|
||||||
tin = costly_tin(COST_OPEN);
|
tin = costly_tin(COST_OPEN);
|
||||||
goto use_up_tin;
|
use_up_tin(tin);
|
||||||
|
if (always_eat)
|
||||||
|
lesshungry(5); /* metallivorous hero ate the tin itself */
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
|
which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
|
||||||
@@ -1530,14 +1562,17 @@ consume_tin(const char *mesg)
|
|||||||
else if (which == 2)
|
else if (which == 2)
|
||||||
what = the(what);
|
what = the(what);
|
||||||
|
|
||||||
pline("It smells like %s.", what);
|
if (!always_eat) {
|
||||||
if (y_n("Eat it?") == 'n') {
|
pline("It smells like %s.", what);
|
||||||
if (flags.verbose)
|
if (y_n("Eat it?") == 'n') {
|
||||||
You("discard the open tin.");
|
if (flags.verbose)
|
||||||
if (!Hallucination)
|
You("discard the open tin.");
|
||||||
tin->dknown = tin->known = 1;
|
if (!Hallucination)
|
||||||
tin = costly_tin(COST_OPEN);
|
tin->dknown = tin->known = 1;
|
||||||
goto use_up_tin;
|
tin = costly_tin(COST_OPEN);
|
||||||
|
use_up_tin(tin);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* in case stop_occupation() was called on previous meal */
|
/* in case stop_occupation() was called on previous meal */
|
||||||
@@ -1548,31 +1583,44 @@ consume_tin(const char *mesg)
|
|||||||
eating_conducts(&mons[mnum]);
|
eating_conducts(&mons[mnum]);
|
||||||
|
|
||||||
tin->dknown = tin->known = 1;
|
tin->dknown = tin->known = 1;
|
||||||
cprefx(mnum);
|
|
||||||
cpostfx(mnum);
|
|
||||||
|
|
||||||
/* charge for one at pre-eating cost */
|
/* charge for one at pre-eating cost */
|
||||||
tin = costly_tin(COST_OPEN);
|
tin = svc.context.tin.tin = costly_tin(COST_OPEN);
|
||||||
|
|
||||||
|
/* cprefx() or cpostfx() might use up tin to keep it out of bones */
|
||||||
|
cprefx(mnum);
|
||||||
|
if (svc.context.tin.tin)
|
||||||
|
cpostfx(mnum);
|
||||||
|
if (!svc.context.tin.tin)
|
||||||
|
return;
|
||||||
|
|
||||||
if (tintxts[r].nut < 0) { /* rotten */
|
if (tintxts[r].nut < 0) { /* rotten */
|
||||||
make_vomiting((long) rn1(15, 10), FALSE);
|
make_vomiting((long) rn1(15, 10), FALSE);
|
||||||
} else {
|
} else {
|
||||||
int nutamt = tintxts[r].nut;
|
nutamt = tintxts[r].nut;
|
||||||
|
|
||||||
/* nutrition from a homemade tin (made from a single corpse)
|
/* nutrition from a homemade tin (made from a single corpse)
|
||||||
shouldn't be more than nutrition from the corresponding
|
shouldn't be more than nutrition from the corresponding
|
||||||
corpse; other tinning modes might use more than one corpse
|
corpse; other tinning modes might use more than one corpse
|
||||||
or add extra ingredients so aren't similarly restricted */
|
or add extra ingredients so aren't similarly restricted */
|
||||||
if (r == HOMEMADE_TIN && nutamt > mons[mnum].cnutrit)
|
if (r == HOMEMADE_TIN && nutamt > mons[mnum].cnutrit)
|
||||||
nutamt = mons[mnum].cnutrit;
|
nutamt = mons[mnum].cnutrit;
|
||||||
|
if (always_eat)
|
||||||
|
nutamt += 5; /* metallivorous hero ate the tin itself */
|
||||||
|
/* use up tin now; lesshungry() could be fatal and produce bones */
|
||||||
|
use_up_tin(tin), tin = NULL;
|
||||||
lesshungry(nutamt);
|
lesshungry(nutamt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tintxts[r].greasy) {
|
if (tintxts[r].greasy) {
|
||||||
/* Assume !Glib, because you can't open tins when Glib. */
|
/* normal hero is !Glib, because you can't open tins when Glib,
|
||||||
make_glib(rn1(11, 5)); /* 5..15 */
|
but one poly'd into metallivorous form might already be Glib;
|
||||||
pline("Eating %s food made your %s very slippery.",
|
it's debatable whether a rock mole should have its paws made
|
||||||
tintxts[r].txt, fingers_or_gloves(TRUE));
|
slippery when eating a greasy tin, but we'll go with that... */
|
||||||
|
int alreadyglib = (int) (Glib & TIMEOUT);
|
||||||
|
|
||||||
|
make_glib(alreadyglib + rn1(11, 5)); /* 5..15 */
|
||||||
|
pline("Eating %s food made your %s %s slippery.",
|
||||||
|
tintxts[r].txt, fingers_or_gloves(TRUE),
|
||||||
|
alreadyglib ? "even more" : "very");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { /* spinach... */
|
} else { /* spinach... */
|
||||||
@@ -1584,11 +1632,12 @@ consume_tin(const char *mesg)
|
|||||||
tin->dknown = tin->known = 1;
|
tin->dknown = tin->known = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y_n("Eat it?") == 'n') {
|
if (!always_eat && y_n("Eat it?") == 'n') {
|
||||||
if (flags.verbose)
|
if (flags.verbose)
|
||||||
You("discard the open tin.");
|
You("discard the open tin.");
|
||||||
tin = costly_tin(COST_OPEN);
|
tin = costly_tin(COST_OPEN);
|
||||||
goto use_up_tin;
|
use_up_tin(tin);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1612,19 +1661,19 @@ consume_tin(const char *mesg)
|
|||||||
: (flags.female ? "Olive Oyl" : "Bluto"));
|
: (flags.female ? "Olive Oyl" : "Bluto"));
|
||||||
gainstr(tin, 0, FALSE);
|
gainstr(tin, 0, FALSE);
|
||||||
|
|
||||||
tin = costly_tin(COST_OPEN);
|
tin = svc.context.tin.tin = costly_tin(COST_OPEN);
|
||||||
lesshungry(tin->blessed ? 600 /* blessed */
|
nutamt = (tin->blessed ? 600 /* blessed */
|
||||||
: !tin->cursed ? (400 + rnd(200)) /* uncursed */
|
: !tin->cursed ? (400 + rnd(200)) /* uncursed */
|
||||||
: (200 + rnd(400))); /* cursed */
|
: (200 + rnd(400))); /* cursed */
|
||||||
|
if (always_eat)
|
||||||
|
nutamt += 5; /* metallivorous hero also eats the tin itself */
|
||||||
|
/* use up tin first; lesshungry() could be fatal and produce bones */
|
||||||
|
use_up_tin(tin), tin = NULL;
|
||||||
|
lesshungry(nutamt);
|
||||||
}
|
}
|
||||||
|
if (tin)
|
||||||
use_up_tin:
|
use_up_tin(tin);
|
||||||
if (carried(tin))
|
return;
|
||||||
useup(tin);
|
|
||||||
else
|
|
||||||
useupf(tin, 1L);
|
|
||||||
svc.context.tin.tin = (struct obj *) 0;
|
|
||||||
svc.context.tin.o_id = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called during each move whilst opening a tin */
|
/* called during each move whilst opening a tin */
|
||||||
|
|||||||
Reference in New Issue
Block a user