Enable hero to wash hands in fountains and pools

Dipping hands (with '-') or currently-worn gloves in a fountain or pool
will cause the hero to wash her hands, washing away any oil and clearing
the Glib intrinsic timeout.  This does mean bare hands can be used to
fish for fountain effects, without having to pick up a stray arrow and
carry it around as a dipping item, but having your hands be the only
thing that does not activate those effects felt weird.  If that would be
too unbalancing this could be scrapped.
This commit is contained in:
Michael Meyer
2023-11-09 16:41:04 -08:00
committed by PatR
parent 33034ebaba
commit 5af1fad398
3 changed files with 58 additions and 13 deletions
+1
View File
@@ -972,6 +972,7 @@ extern void dogushforth(int);
extern void dryup(coordxy, coordxy, boolean); extern void dryup(coordxy, coordxy, boolean);
extern void drinkfountain(void); extern void drinkfountain(void);
extern void dipfountain(struct obj *); extern void dipfountain(struct obj *);
extern int wash_hands(void);
extern void breaksink(coordxy, coordxy); extern void breaksink(coordxy, coordxy);
extern void drinksink(void); extern void drinksink(void);
+29 -5
View File
@@ -389,6 +389,7 @@ void
dipfountain(register struct obj *obj) dipfountain(register struct obj *obj)
{ {
int er = ER_NOTHING; int er = ER_NOTHING;
boolean is_hands = (obj == &cg.zeroobj);
if (Levitation) { if (Levitation) {
floating_above("fountain"); floating_above("fountain");
@@ -437,17 +438,19 @@ dipfountain(register struct obj *obj)
if (in_town(u.ux, u.uy)) if (in_town(u.ux, u.uy))
(void) angry_guards(FALSE); (void) angry_guards(FALSE);
return; return;
} else if (is_hands || obj == uarmg) {
er = wash_hands();
} else { } else {
er = water_damage(obj, NULL, TRUE); er = water_damage(obj, NULL, TRUE);
}
if (er == ER_DESTROYED || (er != ER_NOTHING && !rn2(2))) { if (er == ER_DESTROYED || (er != ER_NOTHING && !rn2(2))) {
return; /* no further effect */ return; /* no further effect */
}
} }
switch (rnd(30)) { switch (rnd(30)) {
case 16: /* Curse the item */ case 16: /* Curse the item */
if (obj->oclass != COIN_CLASS && !obj->cursed) { if (!is_hands && obj->oclass != COIN_CLASS && !obj->cursed) {
curse(obj); curse(obj);
} }
break; break;
@@ -455,7 +458,7 @@ dipfountain(register struct obj *obj)
case 18: case 18:
case 19: case 19:
case 20: /* Uncurse the item */ case 20: /* Uncurse the item */
if (obj->cursed) { if (!is_hands && obj->cursed) {
if (!Blind) if (!Blind)
pline_The("%s glows for a moment.", hliquid("water")); pline_The("%s glows for a moment.", hliquid("water"));
uncurse(obj); uncurse(obj);
@@ -539,6 +542,27 @@ dipfountain(register struct obj *obj)
dryup(u.ux, u.uy, TRUE); dryup(u.ux, u.uy, TRUE);
} }
int
wash_hands(void)
{
const char *hands = makeplural(body_part(HAND));
int res = ER_NOTHING;
You("wash your %s%s in the %s.", uarmg ? "gloved " : "", hands,
hliquid("water"));
if (Glib) {
make_glib(0);
Your("%s are no longer slippery.",
uarmg ? gloves_simple_name(uarmg) : hands);
/* not what ER_GREASED is for, but the checks in dipfountain just
compare the result to ER_DESTROYED and ER_NOTHING, so it works */
res = ER_GREASED;
} else if (uarmg) {
res = water_damage(uarmg, (const char *) 0, TRUE);
}
return res;
}
void void
breaksink(coordxy x, coordxy y) breaksink(coordxy x, coordxy y)
{ {
+28 -8
View File
@@ -2177,8 +2177,10 @@ mixtype(struct obj *o1, struct obj *o2)
static int static int
dip_ok(struct obj *obj) dip_ok(struct obj *obj)
{ {
/* dipping hands and gold isn't currently implemented */ if (!obj)
if (!obj || obj->oclass == COIN_CLASS) return GETOBJ_DOWNPLAY;
/* dipping gold isn't currently implemented */
if (obj->oclass == COIN_CLASS)
return GETOBJ_EXCLUDE; return GETOBJ_EXCLUDE;
if (inaccessible_equipment(obj, (const char *) 0, FALSE)) if (inaccessible_equipment(obj, (const char *) 0, FALSE))
@@ -2218,14 +2220,16 @@ dodip(void)
uchar here; 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;
if (!(obj = getobj("dip", dip_ok, GETOBJ_PROMPT))) if (!(obj = getobj("dip", dip_ok, GETOBJ_PROMPT)))
return ECMD_CANCEL; return ECMD_CANCEL;
if (inaccessible_equipment(obj, "dip", FALSE)) if (inaccessible_equipment(obj, "dip", FALSE))
return ECMD_OK; return ECMD_OK;
shortestname = (is_plural(obj) || pair_of(obj)) ? "them" : "it"; is_hands = (obj == &cg.zeroobj);
shortestname = (is_hands || is_plural(obj) || pair_of(obj)) ? "them"
: "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
fountains and pools plus the prompting which those entail */ fountains and pools plus the prompting which those entail */
@@ -2239,10 +2243,16 @@ dodip(void)
* supplied type name. * supplied type name.
* getobj: "What do you want to dip <the object> into? [xyz or ?*] " * getobj: "What do you want to dip <the object> into? [xyz or ?*] "
*/ */
Strcpy(obuf, short_oname(obj, doname, thesimpleoname, if (is_hands) {
/* 128 - (24 + 54 + 1) leaves 49 for <object> */ Snprintf(obuf, sizeof(obuf), "your %s",
QBUFSZ - sizeof "What do you want to dip \ makeplural(body_part(HAND)));
} else {
Strcpy(obuf, short_oname(obj, doname, thesimpleoname,
/* 128 - (24 + 54 + 1) leaves 49 for
<object> */
QBUFSZ - sizeof "What do you want to dip\
into? [abdeghjkmnpqstvwyzBCEFHIKLNOQRTUWXZ#-# or ?*] ")); into? [abdeghjkmnpqstvwyzBCEFHIKLNOQRTUWXZ#-# or ?*] "));
}
here = levl[u.ux][u.uy].typ; here = levl[u.ux][u.uy].typ;
/* Is there a fountain to dip into here? */ /* Is there a fountain to dip into here? */
@@ -2253,7 +2263,8 @@ dodip(void)
flags.verbose ? obuf : shortestname); flags.verbose ? obuf : shortestname);
/* "Dip <the object> into the fountain?" */ /* "Dip <the object> into the fountain?" */
if (y_n(qbuf) == 'y') { if (y_n(qbuf) == 'y') {
obj->pickup_prev = 0; if (!is_hands)
obj->pickup_prev = 0;
dipfountain(obj); dipfountain(obj);
return ECMD_TIME; return ECMD_TIME;
} }
@@ -2270,6 +2281,10 @@ dodip(void)
} else if (u.usteed && !is_swimmer(u.usteed->data) } else if (u.usteed && !is_swimmer(u.usteed->data)
&& P_SKILL(P_RIDING) < P_BASIC) { && P_SKILL(P_RIDING) < P_BASIC) {
rider_cant_reach(); /* not skilled enough to reach */ rider_cant_reach(); /* not skilled enough to reach */
} else if (is_hands || obj == uarmg) {
if (!is_hands)
obj->pickup_prev = 0;
(void) wash_hands();
} else { } else {
obj->pickup_prev = 0; obj->pickup_prev = 0;
if (obj->otyp == POT_ACID) if (obj->otyp == POT_ACID)
@@ -2338,6 +2353,11 @@ potion_dip(struct obj *obj, struct obj *potion)
pline("That is a potion bottle, not a Klein bottle!"); pline("That is a potion bottle, not a Klein bottle!");
return ECMD_OK; return ECMD_OK;
} }
if (obj == &cg.zeroobj) {
You("can't fit your %s into the mouth of the bottle!",
body_part(HAND));
return ECMD_OK;
}
obj->pickup_prev = 0; /* no longer 'recently picked up' */ obj->pickup_prev = 0; /* no longer 'recently picked up' */
potion->in_use = TRUE; /* assume it will be used up */ potion->in_use = TRUE; /* assume it will be used up */