bag of tricks, horn of plenty, #tip (trunk only)

<Someone> 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.
This commit is contained in:
nethack.rankin
2006-06-18 05:20:36 +00:00
parent e79a41ccb6
commit 58137a608a
8 changed files with 138 additions and 62 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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--;

View File

@@ -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;
struct monst *mtmp;
boolean sawone = FALSE;
int creatcnt = 1;
consume_obj_charge(bag, TRUE);
consume_obj_charge(bag, !tipping);
if (!rn2(23)) cnt += rn1(7, 1);
while (cnt-- > 0) {
if (makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS))
gotone = TRUE;
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*/

View File

@@ -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

View File

@@ -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];

View File

@@ -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" */