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:
@@ -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
|
temporarily orphaned from the normal chains in the swallowing code
|
||||||
charge for thrown wand that shatters into a thousand pieces in a shop
|
charge for thrown wand that shatters into a thousand pieces in a shop
|
||||||
wielded light source susceptible to water gets extinguished when weapon rusts
|
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
|
Platform- and/or Interface-Specific Fixes
|
||||||
|
|||||||
+2
-1
@@ -1004,7 +1004,7 @@ E void FDECL(mimic_hit_msg, (struct monst *, SHORT_P));
|
|||||||
#ifdef GOLDOBJ
|
#ifdef GOLDOBJ
|
||||||
E void FDECL(mkmonmoney, (struct monst *, long));
|
E void FDECL(mkmonmoney, (struct monst *, long));
|
||||||
#endif
|
#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(propagate, (int, BOOLEAN_P,BOOLEAN_P));
|
||||||
E boolean FDECL(usmellmon, (struct permonst *));
|
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(dealloc_obj, (struct obj *));
|
||||||
E void FDECL(obj_ice_effects, (int, int, BOOLEAN_P));
|
E void FDECL(obj_ice_effects, (int, int, BOOLEAN_P));
|
||||||
E long FDECL(peek_at_iced_corpse_age, (struct obj *));
|
E long FDECL(peek_at_iced_corpse_age, (struct obj *));
|
||||||
|
E int FDECL(hornoplenty, (struct obj *,BOOLEAN_P));
|
||||||
#ifdef WIZARD
|
#ifdef WIZARD
|
||||||
E void NDECL(obj_sanity_check);
|
E void NDECL(obj_sanity_check);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+3
-36
@@ -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. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
@@ -2985,7 +2985,7 @@ doapply()
|
|||||||
res = use_container(&obj, 1);
|
res = use_container(&obj, 1);
|
||||||
break;
|
break;
|
||||||
case BAG_OF_TRICKS:
|
case BAG_OF_TRICKS:
|
||||||
bagotricks(obj);
|
(void) bagotricks(obj, FALSE);
|
||||||
break;
|
break;
|
||||||
case CAN_OF_GREASE:
|
case CAN_OF_GREASE:
|
||||||
use_grease(obj);
|
use_grease(obj);
|
||||||
@@ -3107,40 +3107,7 @@ doapply()
|
|||||||
res = do_play_instrument(obj);
|
res = do_play_instrument(obj);
|
||||||
break;
|
break;
|
||||||
case HORN_OF_PLENTY: /* not a musical instrument */
|
case HORN_OF_PLENTY: /* not a musical instrument */
|
||||||
if (obj->spe > 0) {
|
(void) hornoplenty(obj, FALSE);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
case LAND_MINE:
|
case LAND_MINE:
|
||||||
case BEARTRAP:
|
case BEARTRAP:
|
||||||
|
|||||||
+5
-2
@@ -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. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* 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))))
|
(otmp->dknown && objects[OIL_LAMP].oc_name_known))))
|
||||||
|| (!strcmp(word, "untrap with") &&
|
|| (!strcmp(word, "untrap with") &&
|
||||||
(otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
|
(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))
|
|| (!strcmp(word, "charge") && !is_chargeable(otmp))
|
||||||
)
|
)
|
||||||
foo--;
|
foo--;
|
||||||
|
|||||||
+31
-12
@@ -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. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
@@ -1805,28 +1805,47 @@ assign_sym:
|
|||||||
mtmp->mappearance = appear;
|
mtmp->mappearance = appear;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* release a monster from a bag of tricks */
|
/* release a monster from a bag of tricks; return number of monsters created */
|
||||||
void
|
int
|
||||||
bagotricks(bag)
|
bagotricks(bag, tipping)
|
||||||
struct obj *bag;
|
struct obj *bag;
|
||||||
|
boolean tipping; /* caller emptying entire contents; affects shop handling */
|
||||||
{
|
{
|
||||||
|
int moncount = 0;
|
||||||
|
|
||||||
if (!bag || bag->otyp != BAG_OF_TRICKS) {
|
if (!bag || bag->otyp != BAG_OF_TRICKS) {
|
||||||
impossible("bad bag o' tricks");
|
impossible("bad bag o' tricks");
|
||||||
} else if (bag->spe < 1) {
|
} else if (bag->spe < 1) {
|
||||||
pline(nothing_happens);
|
pline(nothing_happens);
|
||||||
|
/* now known to be empty if sufficiently discovered */
|
||||||
|
if (bag->dknown && objects[bag->otyp].oc_name_known) bag->cknown = 1;
|
||||||
} else {
|
} else {
|
||||||
boolean gotone = FALSE;
|
struct monst *mtmp;
|
||||||
int cnt = 1;
|
boolean sawone = FALSE;
|
||||||
|
int creatcnt = 1;
|
||||||
|
|
||||||
consume_obj_charge(bag, TRUE);
|
consume_obj_charge(bag, !tipping);
|
||||||
|
|
||||||
if (!rn2(23)) cnt += rn1(7, 1);
|
if (!rn2(23)) creatcnt += rnd(7);
|
||||||
while (cnt-- > 0) {
|
do {
|
||||||
if (makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS))
|
mtmp = makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS);
|
||||||
gotone = TRUE;
|
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*/
|
/*makemon.c*/
|
||||||
|
|||||||
+62
-1
@@ -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. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
@@ -1768,6 +1768,67 @@ dealloc_obj(obj)
|
|||||||
free((genericptr_t) 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
|
#ifdef WIZARD
|
||||||
/* Check all object lists for consistency. */
|
/* Check all object lists for consistency. */
|
||||||
void
|
void
|
||||||
|
|||||||
+23
-6
@@ -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. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
@@ -2502,7 +2502,7 @@ dotip()
|
|||||||
if (!cobj) return 0;
|
if (!cobj) return 0;
|
||||||
|
|
||||||
/* normal case */
|
/* normal case */
|
||||||
if (Is_container(cobj)) {
|
if (Is_container(cobj) || cobj->otyp == HORN_OF_PLENTY) {
|
||||||
tipcontainer(cobj);
|
tipcontainer(cobj);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -2555,6 +2555,9 @@ struct obj *box; /* or bag */
|
|||||||
{
|
{
|
||||||
boolean empty_it = FALSE;
|
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;
|
box->lknown = 1;
|
||||||
if (box->olocked) {
|
if (box->olocked) {
|
||||||
pline("It's locked.");
|
pline("It's locked.");
|
||||||
@@ -2566,10 +2569,24 @@ struct obj *box; /* or bag */
|
|||||||
nomul(-1);
|
nomul(-1);
|
||||||
nomovemsg = "";
|
nomovemsg = "";
|
||||||
}
|
}
|
||||||
} else if (box->otyp == BAG_OF_TRICKS && box->spe > 0) {
|
} else if (box->otyp == BAG_OF_TRICKS || box->otyp == HORN_OF_PLENTY) {
|
||||||
/* apply (not loot) this bag; uses up one charge */
|
boolean bag = box->otyp == BAG_OF_TRICKS;
|
||||||
bagotricks(box);
|
int old_spe = box->spe;
|
||||||
box->cknown = 1;
|
|
||||||
|
/* 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) {
|
} else if (box->spe) {
|
||||||
char yourbuf[BUFSZ];
|
char yourbuf[BUFSZ];
|
||||||
|
|
||||||
|
|||||||
@@ -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. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* 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;
|
tmp /= 2L;
|
||||||
} else if(otmp->otyp == BAG_OF_TRICKS || /* 1 - 20 */
|
} else if(otmp->otyp == BAG_OF_TRICKS || /* 1 - 20 */
|
||||||
otmp->otyp == HORN_OF_PLENTY) {
|
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 */
|
} else if(otmp->otyp == CRYSTAL_BALL || /* 1 - 5 */
|
||||||
otmp->otyp == OIL_LAMP || /* 1 - 10 */
|
otmp->otyp == OIL_LAMP || /* 1 - 10 */
|
||||||
otmp->otyp == BRASS_LANTERN ||
|
otmp->otyp == BRASS_LANTERN ||
|
||||||
@@ -3949,16 +3950,22 @@ boolean altusage;
|
|||||||
arg2 = ESHK(shkp)->debit > 0L ? " an additional" : "";
|
arg2 = ESHK(shkp)->debit > 0L ? " an additional" : "";
|
||||||
} else if (otmp->otyp == POT_OIL) {
|
} else if (otmp->otyp == POT_OIL) {
|
||||||
fmt = "%s%sThat will cost you %ld %s (Yendorian Fuel Tax).";
|
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 {
|
} else {
|
||||||
fmt = "%s%sUsage fee, %ld %s.";
|
fmt = "%s%sUsage fee, %ld %s.";
|
||||||
if (!rn2(3)) arg1 = "Hey! ";
|
if (!rn2(3)) arg1 = "Hey! ";
|
||||||
if (!rn2(3)) arg2 = "Ahem. ";
|
if (!rn2(3)) arg2 = "Ahem. ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shkp->mcanmove || !shkp->msleeping)
|
if (!muteshk(shkp)) {
|
||||||
verbalize(fmt, arg1, arg2, tmp, currency(tmp));
|
verbalize(fmt, arg1, arg2, tmp, currency(tmp));
|
||||||
|
exercise(A_WIS, TRUE); /* you just got info */
|
||||||
|
}
|
||||||
ESHK(shkp)->debit += tmp;
|
ESHK(shkp)->debit += tmp;
|
||||||
exercise(A_WIS, TRUE); /* you just got info */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for using charges of unpaid objects "used in the normal manner" */
|
/* for using charges of unpaid objects "used in the normal manner" */
|
||||||
|
|||||||
Reference in New Issue
Block a user