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

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