From 6bf7c5a1eb9da05d380980750e34ccfddda3d1d8 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Thu, 9 Aug 2007 03:20:24 +0000 Subject: [PATCH] tin access (trunk only) From the newsgroup: The tin opens like magic! You stop opening the tin. Either it opens immediately or it doesn't, so the "opens like magic" message is inaccurate. Rather than simply changing the phrasing, this gives blessed tins a 50% chance to really open immediately so that their contents are available for eating on the same turn, and 50% to behave as before but with a message which is suitable for the single turn delay. Hero poly'd into a metalivore always gets the same-turn case when eating any tin. Use of a tin opener has a chance to do so (always when blessed, 50/50 for same-turn vs 1 turn delay when uncursed, 33/33/33 same-turn or 1 or 2 turn delay when cursed). Overall, blessed tins are better than they used to be, since half of the time you'll save a turn, but they're still not reliable to eat in the midst of combat since sometimes you'll need another turn and will be likely to get interrupted in that situation. Uncursed tin openers still give the same behavior as opening blessed tins, so are also better than they used to be. Blessed tin openers are now superior, and cursed ones are slightly inferior in addition to being welded to hero's weapon hand. --- doc/fixes35.0 | 2 + src/eat.c | 286 +++++++++++++++++++++++++++++--------------------- 2 files changed, 166 insertions(+), 122 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 761e33c96..7f276be63 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -263,6 +263,8 @@ random "treasure drop" upon monster's death bypassed dropping side-effects melted ice on Valkyrie quest should be pool, not moat some variations of attempting to use open or close commands on a drawbridge didn't give drawbridge-specific feedback +tin contents can now sometimes be accessed on the same turn that the tin + starts being opened; when not, the opening feedback is more accurate Platform- and/or Interface-Specific Fixes diff --git a/src/eat.c b/src/eat.c index 98b078114..7f4e32f02 100644 --- a/src/eat.c +++ b/src/eat.c @@ -30,6 +30,7 @@ STATIC_DCL void FDECL(cprefx, (int)); STATIC_DCL int FDECL(intrinsic_possible, (int,struct permonst *)); STATIC_DCL void FDECL(givit, (int,struct permonst *)); STATIC_DCL void FDECL(cpostfx, (int)); +STATIC_DCL void FDECL(consume_tin, (const char *)); STATIC_DCL void FDECL(start_tin, (struct obj *)); STATIC_DCL int FDECL(eatcorpse, (struct obj *)); STATIC_DCL void FDECL(start_eating, (struct obj *)); @@ -129,7 +130,7 @@ init_uhunger() u.uhs = NOT_HUNGRY; } -/* tin types */ +/* tin types [SPINACH_TIN = -1, overrides corpsenm, nut==600] */ static const struct { const char *txt; /* description */ int nut; /* nutrition */ @@ -1076,8 +1077,10 @@ register int pm; break; case PM_CHAMELEON: case PM_DOPPELGANGER: - /* case PM_SANDESTIN: */ - if (!Unchanging) { + case PM_SANDESTIN: /* moot--they don't leave corpses */ + if (Unchanging) { + You_feel("momentarily different."); /* same as poly trap */ + } else { You_feel("a change coming over you."); polyself(0); } @@ -1221,14 +1224,15 @@ int mnum; char *buf; { char buf2[BUFSZ]; + int r = tin_variety(obj, TRUE); + if (obj && buf) { - if(obj->spe > 0) + if (r == SPINACH_TIN) Strcat(buf, " of spinach"); else if (mnum == NON_PM) Strcpy(buf, "empty tin"); else { if ((obj->cknown || iflags.override_ID) && obj->spe < 0) { - int r = tin_variety(obj, TRUE); if (r == ROTTEN_TIN || r == HOMEMADE_TIN) { /* put these before the word tin */ Sprintf(buf2,"%s %s of ", tintxts[r].txt, buf); @@ -1302,16 +1306,139 @@ boolean disp; /* we're just displaying so leave things alone */ return r; } +STATIC_OVL +void +consume_tin(mesg) +const char *mesg; +{ + const char *what; + int which, mnum, r; + struct obj *tin = context.tin.tin; + + r = tin_variety(tin, FALSE); + if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) { + b_trapped("tin", 0); + costly_tin(COST_DSTROY); + goto use_up_tin; + } + + pline(mesg); /* "You succeed in opening the tin." */ + + if (r != SPINACH_TIN) { + mnum = tin->corpsenm; + if (mnum == NON_PM) { + pline("It turns out to be empty."); + tin->dknown = tin->known = 1; + costly_tin(COST_OPEN); + goto use_up_tin; + } + + which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */ + if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE) && + (Stone_resistance || Hallucination)) { + what = "chicken"; + which = 1; /* suppress pluralization */ + } else if (Hallucination) { + what = rndmonnam(); + } else { + what = mons[mnum].mname; + if (the_unique_pm(&mons[mnum])) which = 2; + else if (type_is_pname(&mons[mnum])) which = 1; + } + if (which == 0) what = makeplural(what); + else if (which == 2) what = the(what); + + pline("It smells like %s.", what); + if (yn("Eat it?") == 'n') { + if (flags.verbose) You("discard the open tin."); + if (!Hallucination) tin->dknown = tin->known = 1; + costly_tin(COST_OPEN); + goto use_up_tin; + } + + /* in case stop_occupation() was called on previous meal */ + context.victual.piece = (struct obj *)0; + context.victual.o_id = 0; + context.victual.fullwarn = context.victual.eating = + context.victual.doreset = FALSE; + + You("consume %s %s.", tintxts[r].txt, mons[mnum].mname); + + /* KMH, conduct */ + u.uconduct.food++; + if (!vegan(&mons[mnum])) + u.uconduct.unvegan++; + if (!vegetarian(&mons[mnum])) + violated_vegetarian(); + + tin->dknown = tin->known = 1; + cprefx(mnum); + cpostfx(mnum); + + /* charge for one at pre-eating cost */ + costly_tin(COST_OPEN); + + if (tintxts[r].nut < 0) /* rotten */ + make_vomiting((long)rn1(15, 10), FALSE); + else + lesshungry(tintxts[r].nut); + + if (tintxts[r].greasy) { + /* Assume !Glib, because you can't open tins when Glib. */ + incr_itimeout(&Glib, rnd(15)); + pline("Eating %s food made your %s very slippery.", + tintxts[r].txt, makeplural(body_part(FINGER))); + } + + } else { /* spinach... */ + if (tin->cursed) { + pline("It contains some decaying%s%s substance.", + Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN)); + } else { + pline("It contains spinach."); + tin->dknown = tin->known = 1; + } + + if (yn("Eat it?") == 'n') { + if (flags.verbose) You("discard the open tin."); + costly_tin(COST_OPEN); + goto use_up_tin; + } + + /* + * Same order as with non-spinach above: + * conduct update, side-effects, shop handling, and nutrition. + */ + u.uconduct.food++; /* don't need vegan/vegetarian checks for spinach */ + if (!tin->cursed) + pline("This makes you feel like %s!", + Hallucination ? "Swee'pea" : "Popeye"); + gainstr(tin, 0); + + costly_tin(COST_OPEN); + + lesshungry(tin->blessed ? 600 : /* blessed */ + !tin->cursed ? (400 + rnd(200)) : /* uncursed */ + (200 + rnd(400))); /* cursed */ + } + + use_up_tin: + if (carried(tin)) + useup(tin); + else + useupf(tin, 1L); + context.tin.tin = (struct obj *)0; + context.tin.o_id = 0; +} + STATIC_PTR int opentin(VOID_ARGS) /* called during each move whilst opening a tin */ { - register int r; - const char *what; - int which, mnum; - - if(!carried(context.tin.tin) && !obj_here(context.tin.tin, u.ux, u.uy)) - /* perhaps it was stolen? */ + /* perhaps it was stolen (although that should cause interruption) */ + if (!carried(context.tin.tin) && + (!obj_here(context.tin.tin, u.ux, u.uy) || + !can_reach_floor(TRUE))) return(0); /* %% probably we should use tinoid */ if(context.tin.usedtime++ >= 50) { You("give up your attempt to open the tin."); @@ -1319,108 +1446,8 @@ opentin(VOID_ARGS) /* called during each move whilst opening a tin */ } if(context.tin.usedtime < context.tin.reqtime) return(1); /* still busy */ - if(context.tin.tin->otrapped || - (context.tin.tin->cursed && context.tin.tin->spe != -1 && !rn2(8))) { - b_trapped("tin", 0); - costly_tin(COST_DSTROY); - goto use_me; - } - You("succeed in opening the tin."); - if(context.tin.tin->spe != 1) { - mnum = context.tin.tin->corpsenm; - if (mnum == NON_PM) { - pline("It turns out to be empty."); - context.tin.tin->dknown = context.tin.tin->known = TRUE; - costly_tin(COST_OPEN); - goto use_me; - } - r = tin_variety(context.tin.tin, FALSE); - which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */ - if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE) && - (Stone_resistance || Hallucination)) { - what = "chicken"; - which = 1; /* suppress pluralization */ - } else if (Hallucination) { - what = rndmonnam(); - } else { - what = mons[mnum].mname; - if (the_unique_pm(&mons[mnum])) which = 2; - else if (type_is_pname(&mons[mnum])) which = 1; - } - if (which == 0) what = makeplural(what); - - pline("It smells like %s%s.", (which == 2) ? "the " : "", what); - if (yn("Eat it?") == 'n') { - if (!Hallucination) - context.tin.tin->dknown = context.tin.tin->known = TRUE; - if (flags.verbose) You("discard the open tin."); - costly_tin(COST_OPEN); - goto use_me; - } - /* in case stop_occupation() was called on previous meal */ - context.victual.piece = (struct obj *)0; - context.victual.o_id = 0; - context.victual.fullwarn = context.victual.eating = - context.victual.doreset = FALSE; - - You("consume %s %s.", tintxts[r].txt, mons[mnum].mname); - - /* KMH, conduct */ - u.uconduct.food++; - if (!vegan(&mons[mnum])) - u.uconduct.unvegan++; - if (!vegetarian(&mons[mnum])) - violated_vegetarian(); - - context.tin.tin->dknown = context.tin.tin->known = TRUE; - cprefx(mnum); - cpostfx(mnum); - - /* charge for one at pre-eating cost */ - costly_tin(COST_OPEN); - - /* check for vomiting added by GAN 01/16/87 */ - if(tintxts[r].nut < 0) make_vomiting((long)rn1(15,10), FALSE); - else lesshungry(tintxts[r].nut); - - if (tintxts[r].greasy) { - /* Assume !Glib, because you can't open tins when Glib. */ - incr_itimeout(&Glib, rnd(15)); - pline("Eating %s food made your %s very slippery.", - tintxts[r].txt, makeplural(body_part(FINGER))); - } - } else { - if (context.tin.tin->cursed) - pline("It contains some decaying%s%s substance.", - Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN)); - else - pline("It contains spinach."); - - if (yn("Eat it?") == 'n') { - if (!Hallucination && !context.tin.tin->cursed) - context.tin.tin->dknown = context.tin.tin->known = TRUE; - if (flags.verbose) - You("discard the open tin."); - costly_tin(COST_OPEN); - goto use_me; - } - - context.tin.tin->dknown = context.tin.tin->known = TRUE; - costly_tin(COST_OPEN); - - if (!context.tin.tin->cursed) - pline("This makes you feel like %s!", - Hallucination ? "Swee'pea" : "Popeye"); - lesshungry(600); - gainstr(context.tin.tin, 0); - u.uconduct.food++; - } -use_me: - if (carried(context.tin.tin)) useup(context.tin.tin); - else useupf(context.tin.tin, 1L); - context.tin.tin = (struct obj *) 0; - context.tin.o_id = 0; + consume_tin("You succeed in opening the tin."); return(0); } @@ -1428,21 +1455,32 @@ STATIC_OVL void start_tin(otmp) /* called when starting to open a tin */ register struct obj *otmp; { + const char *mesg = 0; register int tmp; if (metallivorous(youmonst.data)) { - You("bite right into the metal tin..."); - tmp = 1; + mesg = "You bite right into the metal tin..."; + tmp = 0; } else if (nolimbs(youmonst.data)) { You("cannot handle the tin properly to open it."); return; } else if (otmp->blessed) { - pline_The("tin opens like magic!"); - tmp = 1; + /* 50/50 chance for immediate access vs 1 turn delay (unless + wielding blessed tin opener which always yields immediate + access); 1 turn delay case is non-deterministic: getting + interrupted and retrying might yield another 1 turn delay + or might open immediately on 2nd (or 3rd, 4th, ...) try */ + tmp = (uwep && uwep->blessed && uwep->otyp == TIN_OPENER) ? 0 : + rn2(2); + if (!tmp) + mesg = "The tin opens like magic!"; + else + pline_The("tin seems easy to open."); } else if(uwep) { switch(uwep->otyp) { case TIN_OPENER: - tmp = 1; + mesg = "You easily open the tin."; /* iff tmp==0 */ + tmp = rn2(uwep->cursed ? 3 : !uwep->blessed ? 2 : 1); break; case DAGGER: case SILVER_DAGGER: @@ -1476,12 +1514,16 @@ no_opener: } tmp = rn1(1 + 500/((int)(ACURR(A_DEX) + ACURRSTR)), 10); } - context.tin.reqtime = tmp; - context.tin.usedtime = 0; + context.tin.tin = otmp; - if (context.tin.tin) - context.tin.o_id = context.tin.tin->o_id; - set_occupation(opentin, "opening the tin", 0); + context.tin.o_id = otmp->o_id; + if (!tmp) { + consume_tin(mesg); /* begin immediately */ + } else { + context.tin.reqtime = tmp; + context.tin.usedtime = 0; + set_occupation(opentin, "opening the tin", 0); + } return; }