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
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
39
src/apply.c
39
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:
|
||||
|
||||
@@ -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--;
|
||||
|
||||
@@ -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*/
|
||||
|
||||
63
src/mkobj.c
63
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
|
||||
|
||||
29
src/pickup.c
29
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];
|
||||
|
||||
|
||||
15
src/shk.c
15
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" */
|
||||
|
||||
Reference in New Issue
Block a user