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
#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 *));
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
-/* 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. */
res = use_container(&obj, 1);
break;
case BAG_OF_TRICKS:
- bagotricks(obj);
+ (void) bagotricks(obj, FALSE);
break;
case CAN_OF_GREASE:
use_grease(obj);
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:
-/* 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. */
(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--;
-/* 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. */
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*/
-/* 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. */
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
-/* 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. */
if (!cobj) return 0;
/* normal case */
- if (Is_container(cobj)) {
+ if (Is_container(cobj) || cobj->otyp == HORN_OF_PLENTY) {
tipcontainer(cobj);
return 1;
}
{
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.");
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];
-/* 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. */
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 ||
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" */