refine PR #1112 - washing, dipping in sinks

If hero has slippery hands, include '-' among likely candidates for
item to #dip when dipping at a pool, fountain, or sink location.

When dipping an item (including hands), have a modest chance for the
sink to be destroyed--which turns it into a fountain--each time so
that it can't be used to blank scrolls an unlimited number of items.
(Pools can already be used for that, but you need to obtain water
walking ability or else drop most of your stuff and enter the water;
sinks weren't imposing any such requirements or risks.)
This commit is contained in:
PatR
2023-11-09 18:22:06 -08:00
parent f86dbf13b5
commit 394fa24666
3 changed files with 55 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1286 $ $NHDT-Date: 1699233285 2023/11/06 01:14:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1290 $ $NHDT-Date: 1699582923 2023/11/10 02:22:03 $
General Fixes and Modified Features General Fixes and Modified Features
----------------------------------- -----------------------------------
@@ -1735,6 +1735,8 @@ knockback or recoil while levitating could hurtle the hero through a wall of
if recoil from throwing an item while levitating sent hero into a wall of if recoil from throwing an item while levitating sent hero into a wall of
water, the thrown item got placed in that water rather than at its water, the thrown item got placed in that water rather than at its
intended destination intended destination
include '-' as suggested item in "what to dip?" prompt if dipping at pool or
fountain or sink with slippery hands
Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 fountain.c $NHDT-Date: 1687058871 2023/06/18 03:27:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.95 $ */ /* NetHack 3.7 fountain.c $NHDT-Date: 1699582923 2023/11/10 02:22:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.100 $ */
/* Copyright Scott R. Turner, srt@ucla, 10/27/86 */ /* Copyright Scott R. Turner, srt@ucla, 10/27/86 */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -238,6 +238,7 @@ dryup(coordxy x, coordxy y, boolean isyou)
} }
} }
/* quaff from a fountain when standing on its location */
void void
drinkfountain(void) drinkfountain(void)
{ {
@@ -385,8 +386,9 @@ drinkfountain(void)
dryup(u.ux, u.uy, TRUE); dryup(u.ux, u.uy, TRUE);
} }
/* dip an object into a fountain when standing on its location */
void void
dipfountain(register struct obj *obj) dipfountain(struct obj *obj)
{ {
int er = ER_NOTHING; int er = ER_NOTHING;
boolean is_hands = (obj == &cg.zeroobj); boolean is_hands = (obj == &cg.zeroobj);
@@ -495,6 +497,7 @@ dipfountain(register struct obj *obj)
{ {
long money = money_cnt(gi.invent); long money = money_cnt(gi.invent);
struct obj *otmp; struct obj *otmp;
if (money > 10) { if (money > 10) {
/* Amount to lose. Might get rounded up as fountains don't /* Amount to lose. Might get rounded up as fountains don't
* pay change... */ * pay change... */
@@ -542,6 +545,7 @@ dipfountain(register struct obj *obj)
dryup(u.ux, u.uy, TRUE); dryup(u.ux, u.uy, TRUE);
} }
/* dipping '-' in fountain, pool, or sink */
int int
wash_hands(void) wash_hands(void)
{ {
@@ -552,8 +556,7 @@ wash_hands(void)
hliquid("water")); hliquid("water"));
if (Glib) { if (Glib) {
make_glib(0); make_glib(0);
Your("%s are no longer slippery.", Your("%s are no longer slippery.", fingers_or_gloves(TRUE));
uarmg ? gloves_simple_name(uarmg) : hands);
/* not what ER_GREASED is for, but the checks in dipfountain just /* not what ER_GREASED is for, but the checks in dipfountain just
compare the result to ER_DESTROYED and ER_NOTHING, so it works */ compare the result to ER_DESTROYED and ER_NOTHING, so it works */
res = ER_GREASED; res = ER_GREASED;
@@ -563,6 +566,7 @@ wash_hands(void)
return res; return res;
} }
/* convert a sink into a fountain */
void void
breaksink(coordxy x, coordxy y) breaksink(coordxy x, coordxy y)
{ {
@@ -576,6 +580,7 @@ breaksink(coordxy x, coordxy y)
newsym(x, y); newsym(x, y);
} }
/* quaff from a sink while standing on its location */
void void
drinksink(void) drinksink(void)
{ {
@@ -694,12 +699,21 @@ drinksink(void)
} }
} }
/* for #dip(potion.c) when standing on a sink */
void void
dipsink(struct obj *obj) dipsink(struct obj *obj)
{ {
boolean try_call = FALSE; boolean try_call = FALSE,
not_looted_yet = (levl[u.ux][u.uy].looted & S_LRING) == 0;
if (obj == &cg.zeroobj || obj == uarmg) { if (!rn2(not_looted_yet ? 25 : 15)) {
/* can't rely on using sink for unlimited scroll blanking; however,
since sink will be converted into a fountain, hero can dip again */
breaksink(u.ux, u.uy); /* "The pipes break! Water spurts out!" */
if (Glib)
Your("%s are still slippery.", fingers_or_gloves(TRUE));
return;
} else if (obj == &cg.zeroobj || obj == uarmg) {
(void) wash_hands(); (void) wash_hands();
return; return;
} else if (obj->oclass != POTION_CLASS) { } else if (obj->oclass != POTION_CLASS) {
@@ -772,6 +786,7 @@ dipsink(struct obj *obj)
useup(obj); useup(obj);
} }
/* find a ring in a sink */
void void
sink_backs_up(coordxy x, coordxy y) sink_backs_up(coordxy x, coordxy y)
{ {

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 potion.c $NHDT-Date: 1685135014 2023/05/26 21:03:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.238 $ */ /* NetHack 3.7 potion.c $NHDT-Date: 1699582924 2023/11/10 02:22:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.251 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -38,6 +38,7 @@ static boolean H2Opotion_dip(struct obj *, struct obj *, boolean,
const char *); const char *);
static short mixtype(struct obj *, struct obj *); static short mixtype(struct obj *, struct obj *);
static int dip_ok(struct obj *); static int dip_ok(struct obj *);
static int dip_hands_ok(struct obj *);
static void hold_potion(struct obj *, const char *, const char *, static void hold_potion(struct obj *, const char *, const char *,
const char *); const char *);
static int potion_dip(struct obj *obj, struct obj *potion); static int potion_dip(struct obj *obj, struct obj *potion);
@@ -2179,6 +2180,7 @@ dip_ok(struct obj *obj)
{ {
if (!obj) if (!obj)
return GETOBJ_DOWNPLAY; return GETOBJ_DOWNPLAY;
/* dipping gold isn't currently implemented */ /* dipping gold isn't currently implemented */
if (obj->oclass == COIN_CLASS) if (obj->oclass == COIN_CLASS)
return GETOBJ_EXCLUDE; return GETOBJ_EXCLUDE;
@@ -2189,12 +2191,24 @@ dip_ok(struct obj *obj)
return GETOBJ_SUGGEST; return GETOBJ_SUGGEST;
} }
/* getobj callback for object to be dipped when hero has slippery hands */
static int
dip_hands_ok(struct obj *obj)
{
if (!obj && (Glib && can_reach_floor(FALSE)))
return GETOBJ_SUGGEST;
return dip_ok(obj);
}
/* call hold_another_object() to deal with a transformed potion; its weight /* call hold_another_object() to deal with a transformed potion; its weight
won't have changed but it might require an extra slot that isn't available won't have changed but it might require an extra slot that isn't available
or it might merge into some other carried stack */ or it might merge into some other carried stack */
static void static void
hold_potion(struct obj *potobj, const char *drop_fmt, const char *drop_arg, hold_potion(
const char *hold_msg) struct obj *potobj,
const char *drop_fmt, const char *drop_arg,
const char *hold_msg)
{ {
int cap = near_capacity(), int cap = near_capacity(),
save_pickup_burden = flags.pickup_burden; save_pickup_burden = flags.pickup_burden;
@@ -2211,18 +2225,23 @@ hold_potion(struct obj *potobj, const char *drop_fmt, const char *drop_arg,
return; return;
} }
/* #dip command - get item to dip, then get potion to dip it into */ /* #dip command - get item to dip, then get potion to dip it into;
precede with 'm' to bypass fountain, pool, or sink at hero's spot */
int int
dodip(void) dodip(void)
{ {
static const char Dip_[] = "Dip "; static const char Dip_[] = "Dip ";
struct obj *potion, *obj; struct obj *potion, *obj;
uchar here;
char qbuf[QBUFSZ], obuf[QBUFSZ]; char qbuf[QBUFSZ], obuf[QBUFSZ];
const char *shortestname; /* last resort obj name for prompt */ const char *shortestname; /* last resort obj name for prompt */
boolean is_hands; uchar here = levl[u.ux][u.uy].typ;
boolean is_hands, at_pool = is_pool(u.ux, u.uy),
at_fountain = IS_FOUNTAIN(here), at_sink = IS_SINK(here),
at_here = (!iflags.menu_requested
&& (at_pool || at_fountain || at_sink));
if (!(obj = getobj("dip", dip_ok, GETOBJ_PROMPT))) obj = getobj("dip", at_here ? dip_hands_ok : dip_ok, GETOBJ_PROMPT);
if (!obj)
return ECMD_CANCEL; return ECMD_CANCEL;
if (inaccessible_equipment(obj, "dip", FALSE)) if (inaccessible_equipment(obj, "dip", FALSE))
return ECMD_OK; return ECMD_OK;
@@ -2231,8 +2250,8 @@ dodip(void)
shortestname = (is_hands || is_plural(obj) || pair_of(obj)) ? "them" shortestname = (is_hands || is_plural(obj) || pair_of(obj)) ? "them"
: "it"; : "it";
drink_ok_extra = 0; drink_ok_extra = 0;
/* preceding #dip with 'm' skips the possibility of dipping into /* preceding #dip with 'm' skips the possibility of dipping into pools,
fountains and pools plus the prompting which those entail */ fountains, and sinks plus the extra prompting which those entail */
if (!iflags.menu_requested) { if (!iflags.menu_requested) {
/* /*
* Bypass safe_qbuf() since it doesn't handle varying suffix without * Bypass safe_qbuf() since it doesn't handle varying suffix without
@@ -2254,11 +2273,10 @@ dodip(void)
into? [abdeghjkmnpqstvwyzBCEFHIKLNOQRTUWXZ#-# or ?*] ")); into? [abdeghjkmnpqstvwyzBCEFHIKLNOQRTUWXZ#-# or ?*] "));
} }
here = levl[u.ux][u.uy].typ;
/* Is there a fountain to dip into here? */ /* Is there a fountain to dip into here? */
if (!can_reach_floor(FALSE)) { if (!can_reach_floor(FALSE)) {
; /* can't dip something into fountain or pool if can't reach */ ; /* can't dip something into fountain or pool if can't reach */
} else if (IS_FOUNTAIN(here)) { } else if (at_fountain) {
Snprintf(qbuf, sizeof(qbuf), "%s%s into the fountain?", Dip_, Snprintf(qbuf, sizeof(qbuf), "%s%s into the fountain?", Dip_,
flags.verbose ? obuf : shortestname); flags.verbose ? obuf : shortestname);
/* "Dip <the object> into the fountain?" */ /* "Dip <the object> into the fountain?" */
@@ -2269,7 +2287,7 @@ dodip(void)
return ECMD_TIME; return ECMD_TIME;
} }
++drink_ok_extra; ++drink_ok_extra;
} else if (IS_SINK(here)) { } else if (at_sink) {
Snprintf(qbuf, sizeof(qbuf), "%s%s into the sink?", Dip_, Snprintf(qbuf, sizeof(qbuf), "%s%s into the sink?", Dip_,
flags.verbose ? obuf : shortestname); flags.verbose ? obuf : shortestname);
if (y_n(qbuf) == 'y') { if (y_n(qbuf) == 'y') {
@@ -2279,7 +2297,7 @@ dodip(void)
return ECMD_TIME; return ECMD_TIME;
} }
++drink_ok_extra; ++drink_ok_extra;
} else if (is_pool(u.ux, u.uy)) { } else if (at_pool) {
const char *pooltype = waterbody_name(u.ux, u.uy); const char *pooltype = waterbody_name(u.ux, u.uy);
Snprintf(qbuf, sizeof(qbuf), "%s%s into the %s?", Dip_, Snprintf(qbuf, sizeof(qbuf), "%s%s into the %s?", Dip_,