From: nethack.rankin Date: Sun, 18 Jun 2006 05:20:36 +0000 (+0000) Subject: bag of tricks, horn of plenty, #tip (trunk only) X-Git-Tag: MOVE2GIT~979 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=58137a608acf418700dd527bc69b2ad5a198495d;p=nethack bag of tricks, horn of plenty, #tip (trunk only) reported that he applied an unID'd bag and it became discovered as a bag of tricks even though a spellbook appeared on the floor next to him rather than having a monster show up (the monster was a mimic). Suppress the bag discovery unless you can see or sense a monster appear. (This doesn't really achieve much for most players, who'll recognize the bag because they know that only one type of container doesn't prompt to take things out and/or put things in, but I think it does make sense.) While mucking with bag of tricks I decided that to be consistent with the behavior of other containers, the #tip command should release all the monsters in the bag instead of just one. And after doing that, I realized that horn of plenty ought to behave much the same, so #tip will operate on it now. However, it won't be listed as a likely candidate in the "which item?" prompt unless/until it has been discovered. (Attempting to empty any other type of horn yields "nothing happens", same as for a horn of plenty with no charges left.) Emptying a horn of plenty in a shop can be extremely verbose, but I don't think that qualifies as a bug and don't currently have any plans to alter it. --- diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 771e13ade..448f0a3c8 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -149,6 +149,7 @@ ensure that the punishment ball and chain make it into the save file after being temporarily orphaned from the normal chains in the swallowing code charge for thrown wand that shatters into a thousand pieces in a shop wielded light source susceptible to water gets extinguished when weapon rusts +don't discover unknown bag of tricks when monster it releases is undetected Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index e3404936c..23a0a484d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1004,7 +1004,7 @@ E void FDECL(mimic_hit_msg, (struct monst *, SHORT_P)); #ifdef GOLDOBJ E void FDECL(mkmonmoney, (struct monst *, long)); #endif -E void FDECL(bagotricks, (struct obj *)); +E int FDECL(bagotricks, (struct obj *,BOOLEAN_P)); E boolean FDECL(propagate, (int, BOOLEAN_P,BOOLEAN_P)); E boolean FDECL(usmellmon, (struct permonst *)); @@ -1168,6 +1168,7 @@ E void FDECL(add_to_buried, (struct obj *)); E void FDECL(dealloc_obj, (struct obj *)); E void FDECL(obj_ice_effects, (int, int, BOOLEAN_P)); E long FDECL(peek_at_iced_corpse_age, (struct obj *)); +E int FDECL(hornoplenty, (struct obj *,BOOLEAN_P)); #ifdef WIZARD E void NDECL(obj_sanity_check); #endif diff --git a/src/apply.c b/src/apply.c index cb3b7314a..e61b42e91 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)apply.c 3.5 2006/05/13 */ +/* SCCS Id: @(#)apply.c 3.5 2006/06/17 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2985,7 +2985,7 @@ doapply() res = use_container(&obj, 1); break; case BAG_OF_TRICKS: - bagotricks(obj); + (void) bagotricks(obj, FALSE); break; case CAN_OF_GREASE: use_grease(obj); @@ -3107,40 +3107,7 @@ doapply() res = do_play_instrument(obj); break; case HORN_OF_PLENTY: /* not a musical instrument */ - if (obj->spe > 0) { - struct obj *otmp; - const char *what; - - consume_obj_charge(obj, TRUE); - if (!rn2(13)) { - otmp = mkobj(POTION_CLASS, FALSE); - if (objects[otmp->otyp].oc_magic) do { - otmp->otyp = rnd_class(POT_BOOZE, POT_WATER); - } while (otmp->otyp == POT_SICKNESS); - what = "A potion"; - } else { - otmp = mkobj(FOOD_CLASS, FALSE); - if (otmp->otyp == FOOD_RATION && !rn2(7)) - otmp->otyp = LUMP_OF_ROYAL_JELLY; - what = "Some food"; - } - pline("%s spills out.", what); - otmp->blessed = obj->blessed; - otmp->cursed = obj->cursed; - otmp->owt = weight(otmp); - otmp = hold_another_object(otmp, u.uswallow ? - "Oops! %s out of your reach!" : - (Is_airlevel(&u.uz) || - Is_waterlevel(&u.uz) || - levl[u.ux][u.uy].typ < IRONBARS || - levl[u.ux][u.uy].typ >= ICE) ? - "Oops! %s away from you!" : - "Oops! %s to the floor!", - The(aobjnam(otmp, "slip")), - (const char *)0); - makeknown(HORN_OF_PLENTY); - } else - pline(nothing_happens); + (void) hornoplenty(obj, FALSE); break; case LAND_MINE: case BEARTRAP: diff --git a/src/invent.c b/src/invent.c index f6cf34fc2..36b6de999 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)invent.c 3.5 2006/05/17 */ +/* SCCS Id: @(#)invent.c 3.5 2006/06/17 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -896,7 +896,10 @@ register const char *let,*word; (otmp->dknown && objects[OIL_LAMP].oc_name_known)))) || (!strcmp(word, "untrap with") && (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)) - || (!strcmp(word, "tip") && !Is_container(otmp)) + || (!strcmp(word, "tip") && !Is_container(otmp) && + /* include horn of plenty if sufficiently discovered */ + (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown || + !objects[HORN_OF_PLENTY].oc_name_known)) || (!strcmp(word, "charge") && !is_chargeable(otmp)) ) foo--; diff --git a/src/makemon.c b/src/makemon.c index 49d8197f1..86f991a34 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)makemon.c 3.5 2006/04/14 */ +/* SCCS Id: @(#)makemon.c 3.5 2006/06/17 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1805,28 +1805,47 @@ assign_sym: mtmp->mappearance = appear; } -/* release a monster from a bag of tricks */ -void -bagotricks(bag) +/* release a monster from a bag of tricks; return number of monsters created */ +int +bagotricks(bag, tipping) struct obj *bag; +boolean tipping; /* caller emptying entire contents; affects shop handling */ { + int moncount = 0; + if (!bag || bag->otyp != BAG_OF_TRICKS) { impossible("bad bag o' tricks"); } else if (bag->spe < 1) { pline(nothing_happens); + /* now known to be empty if sufficiently discovered */ + if (bag->dknown && objects[bag->otyp].oc_name_known) bag->cknown = 1; } else { - boolean gotone = FALSE; - int cnt = 1; - - consume_obj_charge(bag, TRUE); - - if (!rn2(23)) cnt += rn1(7, 1); - while (cnt-- > 0) { - if (makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS)) - gotone = TRUE; + struct monst *mtmp; + boolean sawone = FALSE; + int creatcnt = 1; + + consume_obj_charge(bag, !tipping); + + if (!rn2(23)) creatcnt += rnd(7); + do { + mtmp = makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS); + if (mtmp) { + ++moncount; + if (canspotmon(mtmp)) sawone = TRUE; + } + } while (--creatcnt > 0); + if (sawone) { + /* don't set contents-known flag if we just used last charge + (such suppression doesn't actually gain us much since + player can now deduce that the bag has become empty) */ + if (bag->spe > 0) bag->cknown = 1; + if (bag->dknown) makeknown(BAG_OF_TRICKS); + } else { + /* #tip while blind can trigger this successive times */ + Norep("Nothing seems to happen."); } - if (gotone) makeknown(BAG_OF_TRICKS); } + return moncount; } /*makemon.c*/ diff --git a/src/mkobj.c b/src/mkobj.c index 1f0e22273..0df94c503 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mkobj.c 3.5 2006/05/09 */ +/* SCCS Id: @(#)mkobj.c 3.5 2006/06/17 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1768,6 +1768,67 @@ dealloc_obj(obj) free((genericptr_t) obj); } +/* create an object from a horn of plenty; mirrors bagotricks(makemon.c) */ +int +hornoplenty(horn, tipping) +struct obj *horn; +boolean tipping; /* caller emptying entire contents; affects shop handling */ +{ + int objcount = 0; + + if (!horn || horn->otyp != HORN_OF_PLENTY) { + impossible("bad horn o' plenty"); + } else if (horn->spe < 1) { + pline(nothing_happens); + } else { + struct obj *obj; + const char *what; + + consume_obj_charge(horn, !tipping); + if (!rn2(13)) { + obj = mkobj(POTION_CLASS, FALSE); + if (objects[obj->otyp].oc_magic) do { + obj->otyp = rnd_class(POT_BOOZE, POT_WATER); + } while (obj->otyp == POT_SICKNESS); + what = (obj->quan > 1L) ? "Some potions" : "A potion"; + } else { + obj = mkobj(FOOD_CLASS, FALSE); + if (obj->otyp == FOOD_RATION && !rn2(7)) + obj->otyp = LUMP_OF_ROYAL_JELLY; + what = "Some food"; + } + ++objcount; + pline("%s %s out.", what, vtense(what, "spill")); + obj->blessed = horn->blessed; + obj->cursed = horn->cursed; + obj->owt = weight(obj); + if (!tipping) { + obj = hold_another_object(obj, u.uswallow ? + "Oops! %s out of your reach!" : + (Is_airlevel(&u.uz) || + Is_waterlevel(&u.uz) || + levl[u.ux][u.uy].typ < IRONBARS || + levl[u.ux][u.uy].typ >= ICE) ? + "Oops! %s away from you!" : + "Oops! %s to the floor!", + The(aobjnam(obj, "slip")), + (const char *)0); + } else { + /* assumes this is taking place at hero's location */ + if (!can_reach_floor(TRUE)) + hitfloor(obj); + else if (IS_ALTAR(levl[u.ux][u.uy].typ)) + doaltarobj(obj); + else + pline("%s %s to the %s.", Doname2(obj), + otense(obj, "drop"), surface(u.ux, u.uy)); + dropy(obj); + } + if (horn->dknown) makeknown(HORN_OF_PLENTY); + } + return objcount; +} + #ifdef WIZARD /* Check all object lists for consistency. */ void diff --git a/src/pickup.c b/src/pickup.c index 23072b400..db4fa6a29 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)pickup.c 3.5 2006/02/03 */ +/* SCCS Id: @(#)pickup.c 3.5 2006/06/17 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2502,7 +2502,7 @@ dotip() if (!cobj) return 0; /* normal case */ - if (Is_container(cobj)) { + if (Is_container(cobj) || cobj->otyp == HORN_OF_PLENTY) { tipcontainer(cobj); return 1; } @@ -2555,6 +2555,9 @@ struct obj *box; /* or bag */ { boolean empty_it = FALSE; + /* caveat: this assumes that cknown, lknown, olocked, and otrapped + fields haven't been overloaded to mean something special for the + non-standard "container" horn of plenty */ box->lknown = 1; if (box->olocked) { pline("It's locked."); @@ -2566,10 +2569,24 @@ struct obj *box; /* or bag */ nomul(-1); nomovemsg = ""; } - } else if (box->otyp == BAG_OF_TRICKS && box->spe > 0) { - /* apply (not loot) this bag; uses up one charge */ - bagotricks(box); - box->cknown = 1; + } else if (box->otyp == BAG_OF_TRICKS || box->otyp == HORN_OF_PLENTY) { + boolean bag = box->otyp == BAG_OF_TRICKS; + int old_spe = box->spe; + + /* apply this bag/horn until empty or monster/object creation fails + (if the latter occurs, force the former...) */ + do { + if (!(bag ? bagotricks(box, TRUE) : hornoplenty(box, TRUE))) + break; + } while (box->spe > 0); + + if (box->spe < old_spe) { + /* check_unpaid wants to see a non-zero charge count */ + box->spe = old_spe; + check_unpaid_usage(box, TRUE); + box->spe = 0; /* empty */ + box->cknown = 1; + } } else if (box->spe) { char yourbuf[BUFSZ]; diff --git a/src/shk.c b/src/shk.c index 2837e7879..e32c8848d 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)shk.c 3.5 2006/05/20 */ +/* SCCS Id: @(#)shk.c 3.5 2006/06/17 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3897,7 +3897,8 @@ boolean altusage; /* some items have an "alternate" use with different cost */ tmp /= 2L; } else if(otmp->otyp == BAG_OF_TRICKS || /* 1 - 20 */ otmp->otyp == HORN_OF_PLENTY) { - tmp /= 5L; + /* altusage: emptying of all the contents at once */ + if (!altusage) tmp /= 5L; } else if(otmp->otyp == CRYSTAL_BALL || /* 1 - 5 */ otmp->otyp == OIL_LAMP || /* 1 - 10 */ otmp->otyp == BRASS_LANTERN || @@ -3949,16 +3950,22 @@ boolean altusage; arg2 = ESHK(shkp)->debit > 0L ? " an additional" : ""; } else if (otmp->otyp == POT_OIL) { fmt = "%s%sThat will cost you %ld %s (Yendorian Fuel Tax)."; + } else if (altusage && + (otmp->otyp == BAG_OF_TRICKS || otmp->otyp == HORN_OF_PLENTY)) { + fmt = "%s%sEmptying that will cost you %ld %s."; + if (!rn2(3)) arg1 = "Whoa! "; + if (!rn2(3)) arg1 = "Watch it! "; } else { fmt = "%s%sUsage fee, %ld %s."; if (!rn2(3)) arg1 = "Hey! "; if (!rn2(3)) arg2 = "Ahem. "; } - if (shkp->mcanmove || !shkp->msleeping) + if (!muteshk(shkp)) { verbalize(fmt, arg1, arg2, tmp, currency(tmp)); + exercise(A_WIS, TRUE); /* you just got info */ + } ESHK(shkp)->debit += tmp; - exercise(A_WIS, TRUE); /* you just got info */ } /* for using charges of unpaid objects "used in the normal manner" */