diff --git a/include/extern.h b/include/extern.h index 7cae62d8c..3bbcd4d54 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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)); diff --git a/include/obj.h b/include/obj.h index f837c7d40..487907cc5 100644 --- a/include/obj.h +++ b/include/obj.h @@ -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) diff --git a/src/apply.c b/src/apply.c index a14ab81c8..cf2579960 100644 --- a/src/apply.c +++ b/src/apply.c @@ -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; } diff --git a/src/objnam.c b/src/objnam.c index 1dc44cdc0..ff8ba5e4c 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -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; diff --git a/src/trap.c b/src/trap.c index d3e63363b..c5bdfcad6 100644 --- a/src/trap.c +++ b/src/trap.c @@ -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)) diff --git a/src/uhitm.c b/src/uhitm.c index a51ca3124..8c24df38b 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -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)); diff --git a/src/weapon.c b/src/weapon.c index eb0e0b67c..a202498cc 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -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 " 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) diff --git a/src/wield.c b/src/wield.c index 494ea7831..236367ab6 100644 --- a/src/wield.c +++ b/src/wield.c @@ -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;