wet towel enhancements

Flesh out wet towels a bit:
1) wielding a wet towel--or a dry one which becomes wet--won't give a
   "you begin bashing with your wet towel" message when attacking;
2) if a formerly wet towel dries out completely while wielded, *do* give
   "you begin bashing with your towel" on the next attack;
3) successfully hitting with a wet towel no longer always loses wetness;
4) water damage to dry towel always confers at least 1 point of wetness;
5) taking fire damage (via burnarmor() which is used for most types of
   fire damage) has a chance to partially or fully dry a wet towel
   (regardless of whether it's wielded at the time; applies to monsters
   as well as hero; each towel being carried is checked until one is
   affected, then any others escape drying.

Not done:
-) attacking with a wielded wet towel perhaps ought to be treated as a
   weapon attack using whip skill rather than an augmented arbitrary-
   junk-by-weight attack;
-) throwing a wet towel should probably ignore wetness--it's just a wet
   piece of cloth when not finishing with a whip snap; right now, it
   loses a point of wetness when thrown and usually--#3 above--another
   point if it hits...;
-) hitting burning creatures is no different than hitting anything else;
-) likewise for hitting wet creatures.
This commit is contained in:
PatR
2015-10-17 17:00:53 -07:00
parent af1c77808b
commit 4b8db661dd
8 changed files with 163 additions and 67 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 extern.h $NHDT-Date: 1440120640 2015/08/21 01:30:40 $ $NHDT-Branch: master $:$NHDT-Revision: 1.506 $ */
/* NetHack 3.6 extern.h $NHDT-Date: 1445126411 2015/10/18 00:00:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.508 $ */
/* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */
@@ -2574,6 +2574,8 @@ E void FDECL(mwepgone, (struct monst *));
E int FDECL(mon_wield_item, (struct monst *));
E int NDECL(abon);
E int NDECL(dbon);
E void FDECL(wet_a_towel, (struct obj *, int, BOOLEAN_P));
E void FDECL(dry_a_towel, (struct obj *, int, BOOLEAN_P));
E int NDECL(enhance_weapon_skill);
E void FDECL(unrestrict_weapon_skill, (int));
E void FDECL(use_skill, (int, int));

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 obj.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.49 $ */
/* NetHack 3.6 obj.h $NHDT-Date: 1445126423 2015/10/18 00:00:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.50 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -187,6 +187,9 @@ struct obj {
&& objects[otmp->otyp].oc_skill <= -P_DART)
#define is_weptool(o) \
((o)->oclass == TOOL_CLASS && objects[(o)->otyp].oc_skill != P_NONE)
/* towel is not a weptool: spe isn't an enchantment, cursed towel
doesn't weld to hand, and twoweapon won't work with one */
#define is_wet_towel(o) ((o)->otyp == TOWEL && (o)->spe > 0)
#define bimanual(otmp) \
((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
&& objects[otmp->otyp].oc_bimanual)

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 apply.c $NHDT-Date: 1440120650 2015/08/21 01:30:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.201 $ */
/* NetHack 3.6 apply.c $NHDT-Date: 1445126424 2015/10/18 00:00:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.206 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -88,6 +88,8 @@ STATIC_OVL int
use_towel(obj)
struct obj *obj;
{
boolean drying_feedback = (obj == uwep);
if (!freehand()) {
You("have no free %s!", body_part(HAND));
return 0;
@@ -102,7 +104,8 @@ struct obj *obj;
incr_itimeout(&Glib, rn1(10, 3));
Your("%s %s!", makeplural(body_part(HAND)),
(old ? "are filthier than ever" : "get slimy"));
if (obj->spe > 0) obj->spe--;
if (is_wet_towel(obj))
dry_a_towel(obj, -1, drying_feedback);
return 1;
case 1:
if (!ublindf) {
@@ -128,7 +131,8 @@ struct obj *obj;
dropx(saved_ublindf);
}
}
if (obj->spe > 0) obj->spe--;
if (is_wet_towel(obj))
dry_a_towel(obj, -1, drying_feedback);
return 1;
case 0:
break;
@@ -138,13 +142,12 @@ struct obj *obj;
if (Glib) {
Glib = 0;
You("wipe off your %s.", makeplural(body_part(HAND)));
if (obj->spe > 0) obj->spe--;
if (is_wet_towel(obj))
dry_a_towel(obj, -1, drying_feedback);
return 1;
} else if (u.ucreamed) {
Blinded -= u.ucreamed;
u.ucreamed = 0;
if (obj->spe > 0) obj->spe--;
if (!Blinded) {
pline("You've got the glop off.");
if (!gulp_blnd_check()) {
@@ -154,6 +157,8 @@ struct obj *obj;
} else {
Your("%s feels clean now.", body_part(FACE));
}
if (is_wet_towel(obj))
dry_a_towel(obj, -1, drying_feedback);
return 1;
}

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 objnam.c $NHDT-Date: 1444617222 2015/10/12 02:33:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.143 $ */
/* NetHack 3.6 objnam.c $NHDT-Date: 1445126428 2015/10/18 00:00:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.148 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -308,7 +308,7 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */
case TOOL_CLASS:
if (typ == LENSES)
Strcpy(buf, "pair of ");
else if (typ == TOWEL && obj->spe > 0)
else if (is_wet_towel(obj))
Strcpy(buf, (obj->spe < 3) ? "moist " : "wet ");
if (!dknown)
@@ -323,10 +323,14 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */
Strcat(buf, dn ? dn : actualn);
/* If we use an() here we'd have to remember never to use */
/* it whenever calling doname() or xname(). */
if (typ == FIGURINE && omndx != NON_PM)
if (typ == FIGURINE && omndx != NON_PM) {
Sprintf(eos(buf), " of a%s %s",
index(vowels, *mons[omndx].mname) ? "n" : "",
mons[omndx].mname);
} else if (is_wet_towel(obj)) {
if (wizard)
Sprintf(eos(buf), " (%d)", obj->spe);
}
break;
case ARMOR_CLASS:
/* depends on order of the dragon scales objects */
@@ -3285,7 +3289,8 @@ typfnd:
}
break;
case TOWEL:
if (wetness) otmp->spe = wetness;
if (wetness)
otmp->spe = wetness;
break;
case SLIME_MOLD:
otmp->spe = ftype;

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 trap.c $NHDT-Date: 1436753526 2015/07/13 02:12:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.237 $ */
/* NetHack 3.6 trap.c $NHDT-Date: 1445126429 2015/10/18 00:00:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.241 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -47,23 +47,38 @@ STATIC_VAR const char *const blindgas[6] = { "humid", "odorless",
"pungent", "chilling",
"acrid", "biting" };
/* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode) */
boolean /* returns TRUE if hit on torso */
burnarmor(victim)
/* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode);
returns TRUE if hit on torso */
boolean
burnarmor(victim)
struct monst *victim;
{
struct obj *item;
char buf[BUFSZ];
int mat_idx;
int mat_idx, oldspe;
boolean hitting_u;
if (!victim)
return 0;
hitting_u = (victim == &youmonst);
/* burning damage may dry wet towel */
item = hitting_u ? carrying(TOWEL) : m_carrying(victim, TOWEL);
while (item) {
if (is_wet_towel(item)) {
oldspe = item->spe;
dry_a_towel(item, rn2(oldspe + 1), TRUE);
if (item->spe != oldspe)
break; /* stop once one towel has been affected */
}
item = item->nobj;
}
#define burn_dmg(obj, descr) erode_obj(obj, descr, ERODE_BURN, EF_GREASE)
while (1) {
switch (rn2(5)) {
case 0:
item =
(victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH);
item = hitting_u ? uarmh : which_armor(victim, W_ARMH);
if (item) {
mat_idx = objects[item->otyp].oc_material;
Sprintf(buf, "%s %s", materialnm[mat_idx],
@@ -73,45 +88,41 @@ struct monst *victim;
continue;
break;
case 1:
item =
(victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC);
item = hitting_u ? uarmc : which_armor(victim, W_ARMC);
if (item) {
(void) burn_dmg(item, cloak_simple_name(item));
return TRUE;
}
item = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM);
item = hitting_u ? uarm : which_armor(victim, W_ARM);
if (item) {
(void) burn_dmg(item, xname(item));
return TRUE;
}
item =
(victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU);
item = hitting_u ? uarmu : which_armor(victim, W_ARMU);
if (item)
(void) burn_dmg(item, "shirt");
return TRUE;
case 2:
item =
(victim == &youmonst) ? uarms : which_armor(victim, W_ARMS);
item = hitting_u ? uarms : which_armor(victim, W_ARMS);
if (!burn_dmg(item, "wooden shield"))
continue;
break;
case 3:
item =
(victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG);
item = hitting_u ? uarmg : which_armor(victim, W_ARMG);
if (!burn_dmg(item, "gloves"))
continue;
break;
case 4:
item =
(victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF);
item = hitting_u ? uarmf : which_armor(victim, W_ARMF);
if (!burn_dmg(item, "boots"))
continue;
break;
}
break; /* Out of while loop */
}
return FALSE;
#undef burn_dmg
return FALSE;
}
/* Generic erode-item function.
@@ -3308,7 +3319,7 @@ boolean force;
if (obj->otyp == CAN_OF_GREASE && obj->spe > 0) {
return ER_NOTHING;
} else if (obj->otyp == TOWEL && obj->spe < 7) {
obj->spe = max(obj->spe, rn2(8));
wet_a_towel(obj, rnd(7), TRUE);
return ER_NOTHING;
} else if (obj->greased) {
if (!rn2(2))

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 uhitm.c $NHDT-Date: 1432512769 2015/05/25 00:12:49 $ $NHDT-Branch: master $:$NHDT-Revision: 1.144 $ */
/* NetHack 3.6 uhitm.c $NHDT-Date: 1445126430 2015/10/18 00:00:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.148 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -785,7 +785,7 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
tmp = (obj->corpsenm >= LOW_PM ? mons[obj->corpsenm].msize
: 0) + 1;
break;
case EGG: {
#define useup_eggs(o) \
{ \
if (thrown) \
@@ -794,6 +794,7 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
useupall(o); \
o = (struct obj *) 0; \
} /* now gone */
case EGG: {
long cnt = obj->quan;
tmp = 1; /* nominal physical damage */
@@ -925,9 +926,13 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
/* non-weapons can damage because of their weight */
/* (but not too much) */
tmp = obj->owt / 100;
if (obj->otyp == TOWEL && obj->spe > 0) { /* wet towel */
if (is_wet_towel(obj)) {
/* wielded wet towel should probably use whip skill
(but not by setting objects[TOWEL].oc_skill==P_WHIP
because that would turn towel into a weptool) */
tmp += obj->spe;
obj->spe--;
if (rn2(obj->spe + 1)) /* usually lose some wetness */
dry_a_towel(obj, -1, TRUE);
}
if (tmp < 1)
tmp = 1;
@@ -1075,11 +1080,10 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
monflee(mon, 10 * rnd(tmp), FALSE, FALSE);
}
if ((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING])
&&
/* pudding is alive and healthy enough to split */
mon->mhp > 1 && !mon->mcan &&
&& mon->mhp > 1 && !mon->mcan
/* iron weapon using melee or polearm hit */
obj && obj == uwep && objects[obj->otyp].oc_material == IRON
&& obj && obj == uwep && objects[obj->otyp].oc_material == IRON
&& hand_to_hand) {
if (clone_mon(mon, 0, 0)) {
pline("%s divides as you hit it!", Monnam(mon));

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 weapon.c $NHDT-Date: 1436753527 2015/07/13 02:12:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.51 $ */
/* NetHack 3.6 weapon.c $NHDT-Date: 1445126431 2015/10/18 00:00:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.54 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -79,8 +79,9 @@ STATIC_DCL void FDECL(skill_advance, (int));
static NEARDATA const char kebabable[] = { S_XORN, S_DRAGON, S_JABBERWOCK,
S_NAGA, S_GIANT, '\0' };
/* weapon's skill category name for use as generalized description of weapon
*/
/* weapon's skill category name for use as generalized description of weapon;
mostly used to shorten "you drop your <weapon>" messages when slippery
fingers or polymorph causes hero to involuntarily drop wielded weapon(s) */
const char *
weapon_descr(obj)
struct obj *obj;
@@ -91,10 +92,12 @@ struct obj *obj;
/* assorted special cases */
switch (skill) {
case P_NONE:
/* not a weapon: use item class name; override "food" for corpses,
tins, and eggs and "large rock" for statues and boulders */
/* not a weapon or weptool: use item class name;
override class name "food" for corpses, tins, and eggs,
"large rock" for statues and boulders, and "tool" for towels */
descr = (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG
|| obj->otyp == STATUE || obj->otyp == BOULDER)
|| obj->otyp == STATUE || obj->otyp == BOULDER
|| obj->otyp == TOWEL)
? OBJ_NAME(objects[obj->otyp])
: def_oc_syms[(int) obj->oclass].name;
break;
@@ -102,13 +105,11 @@ struct obj *obj;
if (is_ammo(obj))
descr = (obj->otyp == ROCK || is_graystone(obj))
? "stone"
:
/* avoid "rock"; what about known glass? */
(obj->oclass == GEM_CLASS)
: (obj->oclass == GEM_CLASS)
? "gem"
:
/* in case somebody adds odd sling ammo */
def_oc_syms[(int) obj->oclass].name;
: def_oc_syms[(int) obj->oclass].name;
break;
case P_BOW:
if (is_ammo(obj))
@@ -738,7 +739,9 @@ struct monst *mon;
}
}
int abon() /* attack bonus for strength & dexterity */
/* attack bonus for strength & dexterity */
int
abon()
{
int sbon;
int str = ACURR(A_STR), dex = ACURR(A_DEX);
@@ -774,7 +777,9 @@ int abon() /* attack bonus for strength & dexterity */
return (sbon + dex - 14);
}
int dbon() /* damage bonus for strength */
/* damage bonus for strength */
int
dbon()
{
int str = ACURR(A_STR);
@@ -799,6 +804,67 @@ int dbon() /* damage bonus for strength */
return (6);
}
/* increase a towel's wetness */
void
wet_a_towel(obj, amt, verbose)
struct obj *obj;
int amt; /* positive: new value; negative: increment by -amt; zero: no-op */
boolean verbose;
{
int newspe = (amt <= 0) ? obj->spe - amt : amt;
/* new state is only reported if it's an increase */
if (newspe > obj->spe) {
if (verbose) {
const char *wetness = (newspe < 3)
? (!obj->spe ? "damp" : "damper")
: (!obj->spe ? "wet" : "wetter");
if (carried(obj))
pline("%s gets %s.", Yobjnam2(obj, (const char *) 0),
wetness);
else if (mcarried(obj) && canseemon(obj->ocarry))
pline("%s %s gets %s.", s_suffix(Monnam(obj->ocarry)),
xname(obj), wetness);
}
}
obj->spe = min(newspe, 7);
/* if hero is wielding this towel, don't give "you begin bashing
with your wet towel" message on next attack with it */
if (obj == uwep)
unweapon = !is_wet_towel(obj);
}
/* decrease a towel's wetness */
void
dry_a_towel(obj, amt, verbose)
struct obj *obj;
int amt; /* positive: new value; negative: decrement by -amt; zero: no-op */
boolean verbose;
{
int newspe = (amt <= 0) ? obj->spe + amt : amt;
/* new state is only reported if it's a decrease */
if (newspe < obj->spe) {
if (verbose) {
if (carried(obj))
pline("%s dries%s.", Yobjnam2(obj, (const char *) 0),
!newspe ? " out" : "");
else if (mcarried(obj) && canseemon(obj->ocarry))
pline("%s %s drie%s.", s_suffix(Monnam(obj->ocarry)),
xname(obj), !newspe ? " out" : "");
}
}
newspe = min(newspe, 7);
obj->spe = max(newspe, 0);
/* if hero is wielding this towel and it is now dry, give "you begin
bashing with your towel" message on next attack with it */
if (obj == uwep)
unweapon = !is_wet_towel(obj);
}
/* copy the skill level name into the given buffer */
STATIC_OVL char *
skill_level_name(skill, buf)

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 wield.c $NHDT-Date: 1437877186 2015/07/26 02:19:46 $ $NHDT-Branch: master $:$NHDT-Revision: 1.44 $ */
/* NetHack 3.6 wield.c $NHDT-Date: 1445126432 2015/10/18 00:00:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.45 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -23,7 +23,7 @@
* with the main weapon. If the "pushweapon" option is set,
* the (w)ield command will also store the old weapon in the
* secondary slot.
* 2. Can be field with anything that will fit in the main weapon
* 2. Can be filled with anything that will fit in the main weapon
* slot; that is, any type of item.
* 3. Is usually NOT considered to be carried in the hands.
* That would force too many checks among the main weapon,
@@ -45,6 +45,8 @@
* 5. Never conveys intrinsics.
* 6. Cursed items never weld; their effect is handled by the normal
* throwing code.
* 7. The autoquiver option will fill it with something deemed
* suitable if (f)ire is used when it's empty.
*
* No item may be in more than one of these slots.
*/
@@ -102,7 +104,7 @@ register struct obj *obj;
unweapon = (obj->oclass == WEAPON_CLASS)
? is_launcher(obj) || is_ammo(obj) || is_missile(obj)
|| (is_pole(obj) && !u.usteed)
: !is_weptool(obj);
: !is_weptool(obj) && !is_wet_towel(obj);
} else
unweapon = TRUE; /* for "bare hands" message */
update_inventory();
@@ -156,6 +158,7 @@ struct obj *wep;
res++;
if (will_weld(wep)) {
const char *tmp = xname(wep), *thestr = "The ";
if (strncmp(tmp, thestr, 4) && !strncmp(The(tmp), thestr, 4))
tmp = thestr;
else
@@ -173,6 +176,7 @@ struct obj *wep;
* say "weapon in hand", thus this kludge.
*/
long dummy = wep->owornmask;
wep->owornmask |= W_WEP;
prinv((char *) 0, wep, 0L);
wep->owornmask = dummy;
@@ -188,17 +192,15 @@ struct obj *wep;
pline("%s to shine %s!", Tobjnam(wep, "begin"),
arti_light_description(wep));
}
#if 0
/* we'll get back to this someday, but it's not balanced yet */
if (Race_if(PM_ELF) && !wep->oartifact &&
objects[wep->otyp].oc_material == IRON) {
/* Elves are averse to wielding cold iron */
You("have an uneasy feeling about wielding cold iron.");
change_luck(-1);
}
/* we'll get back to this someday, but it's not balanced yet */
if (Race_if(PM_ELF) && !wep->oartifact
&& objects[wep->otyp].oc_material == IRON) {
/* Elves are averse to wielding cold iron */
You("have an uneasy feeling about wielding cold iron.");
change_luck(-1);
}
#endif
if (wep->unpaid) {
struct monst *this_shkp;
@@ -256,7 +258,7 @@ dowield()
return (0);
else if (wep == uwep) {
You("are already wielding that!");
if (is_weptool(wep))
if (is_weptool(wep) || is_wet_towel(wep))
unweapon = FALSE; /* [see setuwep()] */
return (0);
} else if (welded(uwep)) {
@@ -394,9 +396,7 @@ dowieldquiver()
return (0);
}
/* used for #rub and for applying pick-axe, whip, grappling hook, or polearm
*/
/* (moved from apply.c) */
/* used for #rub and for applying pick-axe, whip, grappling hook or polearm */
boolean
wield_tool(obj, verb)
struct obj *obj;