From 35cabe53bff8eda537a469e7d49cf8bbdaa38f5b Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 3 Aug 2015 18:38:38 -0700 Subject: [PATCH] wear/remove commands, P & R vs W & T Allow 'P' and 'R' commands to accept armor and wear/take-off the chosen item, and 'W' and 'T' commands to accept accessories and put-on/remove the item. The which-object prompt only lists the type(s) of items that traditionally go with each command, as does an inventory menu if the user picks '?', but items of the alternate type(s) can be chosen, by unshown letter or by the inventory menu given for '*'. There shouldn't be much difference if you continue picking items that go with the original commands, although you will somestimes get "which object? [*]" when the only choices are for alternate command. And you won't see the all-four-accessories-are-already-worn message for 'P' unless you also have something worn in all seven armor slots. The Guidebook.mn changes have been tested (that's how/why I noticed the preface glitch) but the corresponding Guidebook.tex ones haven't. --- doc/Guidebook.mn | 53 +++- doc/Guidebook.tex | 51 +++- src/do_wear.c | 639 +++++++++++++++++++++++++--------------------- src/invent.c | 24 +- 4 files changed, 436 insertions(+), 331 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 4921c162d..c8af0011b 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: master $:$NHDT-Revision: 1.179 $ $NHDT-Date: 1435003374 2015/06/22 20:02:54 $ +.\" $NHDT-Branch: master $:$NHDT-Revision: 1.180 $ $NHDT-Date: 1438652308 2015/08/04 01:38:28 $ .ds h0 "NetHack Guidebook .ds h1 .ds h2 % @@ -643,9 +643,13 @@ game rather than with the `O' command; see the section on options below. .lp p Pay your shopping bill. .lp P -Put on a ring or other accessory (amulet, blindfold). +Put on an accessory (ring, amulet, or blindfold). .lp "" -Use the 'W' command to wear armor. +This command may also be used to wear armor. The prompt for +which inventory item to use will only list accessories, but choosing +an unlisted item of armor will attempt to wear it. +(See the `W' command below. It lists armor as the inventory +choices but will accept an accessory and attempt to put that on.) .lp ^P Repeat previous message. .lp "" @@ -659,20 +663,26 @@ Quaff (drink) something (potion, water, etc). Select an object for your quiver, quiver sack, or just generally at the ready (only one of these is available at a time). You can then throw this (or one of these) using -the `f' command. (In versions prior to 3.3 this was the command to quit -the game, which has now been moved to `#quit'.) +the `f' command. +.lp "" +(In versions prior to 3.3 this was the command to quit +the game, which has been moved to ``#quit''.) .lp r Read a scroll or spellbook. .lp R -Remove an accessory (ring, amulet, etc). +Remove a worn accessory (ring, amulet, or blindfold). .lp "" If you're wearing more than one, you'll be prompted for which one to -remove. If you're only wearing one, then by default it will be removed +remove. When you're only wearing one, then by default it will be removed without asking, but you can set the .op paranoid_confirmation option to require a prompt. .lp "" -Use the 'T' command to take off armor. +This command may also be used to take off armor. The prompt for which +inventory item to remove only lists worn accessories, but an item of +worn armor can be chosen. +(See the `T' command below. It lists armor as the inventory +choices but will accept an accessory and attempt to remove it.) .lp ^R Redraw the screen. .lp s @@ -687,12 +697,19 @@ Throw an object or shoot a projectile. Take off armor. .lp "" If you're wearing more than one piece, you'll be prompted for which -one to take off. If you're only wearing one, then by default it will +one to take off. (Note that this treats a cloak covering a suit +and/or a shirt, or a suit covering a shirt, as if the underlying items +weren't there.) +When you're only wearing one, then by default it will be taken off without asking, but you can set the .op paranoid_confirmation option to require a prompt. .lp "" -Use the 'R' command to remove accessories. +This command may also be used to remove accessories. The prompt +for which inventory item to take off only lists worn armor, but a worn +accessory can be chosen. +(See the `R' command above. It lists accessories as the inventory +choices but will accept an item of armor and attempt to take it off.) .lp ^T Teleport, if you have the ability. .lp v @@ -706,12 +723,16 @@ Wield weapon. w- - wield nothing, use your bare hands. .ei .ed -Some characters can wield two weapons and once; use the ``#twoweapon'' -extended command to do so. +Some characters can wield two weapons at once; use the `X' command +(or the ``#twoweapon'' extended command) to do so. .lp W Wear armor. .lp "" -Use the 'P' command to put on accessories. +This command may also be used to put on an accessory (ring, amulet, or +blindfold). The prompt for which inventory item to use will only list +armor, but choosing an unlisted accessory will attempt to put it on. +(See the `P' command above. It lists accessories as the inventory +choices but will accept an item of armor and attempt to wear it.) .lp x Exchange your wielded weapon with the item in your alternate weapon slot. .lp "" @@ -720,7 +741,11 @@ two-weapon combat. Note that if one of these slots is empty, the exchange still takes place. .lp X Toggle two-weapon combat, if your character can do it. Also available -via the ``#twoweapon'' extended command +via the ``#twoweapon'' extended command. +.lp "" +(In versions prior to 3.6 this was the command to switch from normal +play to "explore mode", also known as "discovery mode", which has now +been moved to ``#explore''.) .lp ^X Display basic information about your character. .lp "" diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 747da4cb2..574b31fa9 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -785,9 +785,13 @@ game rather than with the `{\tt O}' command; see the section on options below. Pay your shopping bill. %.lp \item[\tb{P}] -Put on a ring or other accessory (amulet, blindfold).\\ +Put on an accessory (ring, amulet, blindfold).\\ %.lp "" -Use the `{\tt W}' command to wear armor. +This command may also be used to wear armor. The prompt for +which inventory item to use will only list accessories, but choosing +an unlisted item of armor will attempt to wear it. +(See the `{\tt W}' command below. It lists armor as the inventory +choices but will accept an accessory and attempt to put that on.) %.lp \item[\tb{\^{}P}] Repeat previous message.\\ @@ -802,22 +806,28 @@ Quaff (drink) something (potion, water, etc). Select an object for your quiver, quiver sack, or just generally at the ready (only one of these is available at a time). You can then throw this (or one of these) using -the `f' command. (In versions prior to 3.3 this was the command to quit -the game, which has now been moved to `{\tt \#quit}'.) +the `f' command.\\ +%.lp "" +(In versions prior to 3.3 this was the command to quit +the game, which has been moved to ``{\tt \#quit}''.) %.lp \item[\tb{r}] Read a scroll or spellbook. %.lp \item[\tb{R}] -Remove an accessory (ring, amulet, etc).\\ +Remove a worn accessory (ring, amulet, or blindfold).\\ %.lp "" If you're wearing more than one, you'll be prompted for which one to -remove. If you're only wearing one, then by default it will be removed +remove. When you're only wearing one, then by default it will be removed without asking, but you can set the {\it paranoid\verb+_+confirmation\/} option to require a prompt.\\ %.lp "" -Use the `{\tt T}' command to take off armor. +This command may also be used to take off armor. The prompt for which +inventory item to remove only lists worn accessories, but an item of +worn armor can be chosen. +(See the `{\tt T}' command below. It lists armor as the inventory +choices but will accept an accessory and attempt to remove it.) %.lp \item[\tb{\^{}R}] Redraw the screen. @@ -837,12 +847,19 @@ Throw an object or shoot a projectile. Take off armor.\\ %.lp "" If you're wearing more than one piece, you'll be prompted for which -one to take off. If you're only wearing one, then by default it will +one to take off. (Note that this treats a cloak covering a suit +and/or a shirt, or a suit covering a shirt, as if the underlying items +weren't there.) +When you're only wearing one, then by default it will be taken off without asking, but you can set the {\it paranoid\verb+_+confirmation\/} option to require a prompt.\\ %.lp "" -Use the `{\tt R}' command to remove accessories. +This command may also be used to remove accessories. The prompt +for which inventory item to take off only lists worn armor, but a worn +accessory can be chosen. +(See the `{\tt R}' command above. It lists accessories as the inventory +choices but will accept an item of armor and attempt to take it off.) %.lp \item[\tb{\^{}T}] Teleport, if you have the ability. @@ -860,13 +877,17 @@ Wield weapon.\\ {\tt w-} --- wield nothing, use your bare hands.\\ %.ei %.ed -Some characters can wield two weapons and once; use the ``{\tt \#twoweapon}'' -extended command to do so. +Some characters can wield two weapons at once; use the `{\tt X}' command +(or the ``{\tt \#twoweapon}'' extended command) to do so. %.lp \item[\tb{W}] Wear armor.\\ %.lp "" -Use the `{\tt P}' command to put on accessories. +This command may also be used to put on an accessory (ring, amulet, or +blindfold). The prompt for which inventory item to use will only list +armor, but choosing an unlisted accessory will attempt to put it on. +(See the `{\tt P}' command above. It lists accessories as the inventory +choices but will accept an item of armor and attempt to wear it.) %.lp \item[\tb{x}] Exchange your wielded weapon with the item in your alternate weapon slot.\\ @@ -877,7 +898,11 @@ the exchange still takes place. %.lp \item[\tb{X}] Toggle two-weapon combat, if your character can do it. Also available -via the ``{\tt \#twoweapon}'' extended command +via the ``{\tt \#twoweapon}'' extended command.\\ ++.lp "" ++(In versions prior to 3.6 this was the command to switch from normal ++play to ``explore mode'', also known as ``discovery mode'', which has now ++been moved to ``{\tt \#explore}''.) %.lp \item[\tb{\^{}X}] Display basic information about your character.\\ diff --git a/src/do_wear.c b/src/do_wear.c index cb86520ba..a159ca6f9 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_wear.c $NHDT-Date: 1437877177 2015/07/26 02:19:37 $ $NHDT-Branch: master $:$NHDT-Revision: 1.83 $ */ +/* NetHack 3.6 do_wear.c $NHDT-Date: 1438652304 2015/08/04 01:38:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.84 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -37,6 +37,9 @@ STATIC_PTR int FDECL(select_off, (struct obj *)); STATIC_DCL struct obj *NDECL(do_takeoff); STATIC_PTR int NDECL(take_off); STATIC_DCL int FDECL(menu_remarm, (int)); +STATIC_DCL void FDECL(count_worn_stuff, (struct obj **, BOOLEAN_P)); +STATIC_PTR int FDECL(armor_or_accessory_off, (struct obj *)); +STATIC_PTR int FDECL(accessory_or_armor_on, (struct obj *)); STATIC_DCL void FDECL(already_wearing, (const char *)); STATIC_DCL void FDECL(already_wearing2, (const char *, const char *)); @@ -83,9 +86,9 @@ boolean on; if (on ? initial_don : context.takeoff.cancelled_don) return; - if (!oldprop && /* extrinsic stealth from something else */ - !HStealth && /* intrinsic stealth */ - !BStealth) { /* stealth blocked by something */ + if (!oldprop /* extrinsic stealth from something else */ + && !HStealth /* intrinsic stealth */ + && !BStealth) { /* stealth blocked by something */ if (obj->otyp == RIN_STEALTH) learnring(obj, TRUE); else @@ -117,19 +120,21 @@ boolean on; if (on ? initial_don : context.takeoff.cancelled_don) return; - if (!oldprop && /* extrinsic displacement from something else */ - !(u.uprops[DISPLACED].intrinsic) && /* (theoretical) */ - !(u.uprops[DISPLACED].blocked) && /* (also theoretical) */ + if (!oldprop /* extrinsic displacement from something else */ + && !(u.uprops[DISPLACED].intrinsic) /* (theoretical) */ + && !(u.uprops[DISPLACED].blocked) /* (also theoretical) */ /* we don't use canseeself() here because it augments vision with touch, which isn't appropriate for deciding whether we'll notice that monsters have trouble spotting the hero */ - ((!Blind && /* see anything */ - !u.uswallow && /* see surroundings */ - !Invisible) || /* see self */ - /* actively sensing nearby monsters via telepathy or extended - monster detection overrides vision considerations because - hero also senses self in this situation */ - (Unblind_telepat || (Blind_telepat && Blind) || Detect_monsters))) { + && ((!Blind /* see anything */ + && !u.uswallow /* see surroundings */ + && !Invisible) /* see self */ + /* actively sensing nearby monsters via telepathy or extended + monster detection overrides vision considerations because + hero also senses self in this situation */ + || (Unblind_telepat + || (Blind_telepat && Blind) + || Detect_monsters))) { makeknown(obj->otyp); You_feel("that monsters%s have difficulty pinpointing your location.", @@ -1180,9 +1185,11 @@ struct obj *obj; /* if null, do all worn items; otherwise just obj itself */ initial_don = FALSE; } -/* check whether the target object is currently being put on (or taken off) */ -boolean donning(otmp) /* also checks for doffing */ -register struct obj *otmp; +/* check whether the target object is currently being put on (or taken off-- + also checks for doffing) */ +boolean +donning(otmp) +struct obj *otmp; { /* long what = (occupation == take_off) ? context.takeoff.what : 0L; */ long what = context.takeoff.what; /* if nonzero, occupation is implied */ @@ -1302,37 +1309,103 @@ struct obj *stolenobj; /* no message if stolenobj is already being doffing */ return result; } -static NEARDATA const char clothes[] = { ARMOR_CLASS, 0 }; -static NEARDATA const char accessories[] = { RING_CLASS, AMULET_CLASS, - TOOL_CLASS, FOOD_CLASS, 0 }; +/* both 'clothes' and 'accessories' now include both armor and accessories; + TOOL_CLASS is for eyewear, FOOD_CLASS is for MEAT_RING */ +static NEARDATA const char clothes[] = { + ARMOR_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, FOOD_CLASS, 0 +}; +static NEARDATA const char accessories[] = { + RING_CLASS, AMULET_CLASS, TOOL_CLASS, FOOD_CLASS, ARMOR_CLASS, 0 +}; +STATIC_VAR NEARDATA int Narmorpieces, Naccessories; + +/* assign values to Narmorpieces and Naccessories */ +STATIC_OVL void +count_worn_stuff(which, accessorizing) +struct obj **which; /* caller wants this when count is 1 */ +boolean accessorizing; +{ + struct obj *otmp; + + Narmorpieces = Naccessories = 0; + +#define MOREWORN(x,wtyp) do { if (x) { wtyp++; otmp = x; } } while (0) + otmp = 0; + MOREWORN(uarmh, Narmorpieces); + MOREWORN(uarms, Narmorpieces); + MOREWORN(uarmg, Narmorpieces); + MOREWORN(uarmf, Narmorpieces); + /* for cloak/suit/shirt, we only count the outermost item so that it + can be taken off without confirmation if final count ends up as 1 */ + if (uarmc) + MOREWORN(uarmc, Narmorpieces); + else if (uarm) + MOREWORN(uarm, Narmorpieces); + else if (uarmu) + MOREWORN(uarmu, Narmorpieces); + if (!accessorizing) + *which = otmp; /* default item iff Narmorpieces is 1 */ + + otmp = 0; + MOREWORN(uleft, Naccessories); + MOREWORN(uright, Naccessories); + MOREWORN(uamul, Naccessories); + MOREWORN(ublindf, Naccessories); + if (accessorizing) + *which = otmp; /* default item iff Naccessories is 1 */ +#undef MOREWORN +} + +/* take off one piece or armor or one accessory; + shared by dotakeoff('T') and doremring('R') */ +STATIC_OVL int +armor_or_accessory_off(obj) +struct obj *obj; +{ + if (!(obj->owornmask & (W_ARMOR | W_ACCESSORY))) { + You("are not wearing that."); + return 0; + } + + reset_remarm(); /* clear context.takeoff.mask and context.takeoff.what */ + (void) select_off(obj); + if (!context.takeoff.mask) + return 0; + /* none of armoroff()/Ring_/Amulet/Blindf_off() use context.takeoff.mask */ + reset_remarm(); + + if (obj->owornmask & W_ARMOR) { + (void) armoroff(obj); + } else if (obj == uright || obj == uleft) { + /* Sometimes we want to give the off_msg before removing and + * sometimes after; for instance, "you were wearing a moonstone + * ring (on right hand)" is desired but "you were wearing a + * square amulet (being worn)" is not because of the redundant + * "being worn". + */ + off_msg(obj); + Ring_off(obj); + } else if (obj == uamul) { + Amulet_off(); + off_msg(obj); + } else if (obj == ublindf) { + Blindf_off(obj); /* does its own off_msg */ + } else { + impossible("removing strange accessory?"); + if (obj->owornmask) + remove_worn_item(obj, FALSE); + } + return 1; +} /* the 'T' command */ int dotakeoff() { - register struct obj *otmp = (struct obj *) 0; - int armorpieces = 0; + struct obj *otmp = (struct obj *) 0; -#define MOREARM(x) \ - if (x) { \ - armorpieces++; \ - otmp = x; \ - } - MOREARM(uarmh); - MOREARM(uarms); - MOREARM(uarmg); - MOREARM(uarmf); - if (uarmc) { - armorpieces++; - otmp = uarmc; - } else if (uarm) { - armorpieces++; - otmp = uarm; - } else if (uarmu) { - armorpieces++; - otmp = uarmu; - } - if (!armorpieces) { + count_worn_stuff(&otmp, FALSE); + if (!Narmorpieces && !Naccessories) { /* assert( GRAY_DRAGON_SCALES > YELLOW_DRAGON_SCALE_MAIL ); */ if (uskin) pline_The("%s merged with your skin!", @@ -1340,23 +1413,15 @@ dotakeoff() ? "dragon scales are" : "dragon scale mail is"); else - pline("Not wearing any armor.%s", - (iflags.cmdassist && (uleft || uright || uamul || ublindf)) - ? " Use 'R' command to remove accessories." - : ""); + pline("Not wearing any armor or accessories."); return 0; } - if (armorpieces > 1 || ParanoidRemove) + if (Narmorpieces != 1 || ParanoidRemove) otmp = getobj(clothes, "take off"); if (!otmp) return 0; - if (!(otmp->owornmask & W_ARMOR)) { - You("are not wearing that."); - return 0; - } - /* note: the `uskin' case shouldn't be able to happen here; dragons - can't wear any armor so will end up with `armorpieces == 0' above */ - if (otmp == uskin || ((otmp == uarm) && uarmc) + if (otmp == uskin + || ((otmp == uarm) && uarmc) || ((otmp == uarmu) && (uarmc || uarm))) { char why[BUFSZ], what[BUFSZ]; @@ -1375,74 +1440,26 @@ dotakeoff() return 0; } - reset_remarm(); /* clear context.takeoff.mask and context.takeoff.what */ - (void) select_off(otmp); - if (!context.takeoff.mask) - return 0; - reset_remarm(); /* armoroff() doesn't use context.takeoff.mask */ - - (void) armoroff(otmp); - return (1); + return armor_or_accessory_off(otmp); } /* the 'R' command */ int doremring() { - register struct obj *otmp = 0; - int Accessories = 0; + struct obj *otmp = 0; -#define MOREACC(x) \ - if (x) { \ - Accessories++; \ - otmp = x; \ + count_worn_stuff(&otmp, TRUE); + if (!Naccessories && !Narmorpieces) { + pline("Not wearing any accessories or armor."); + return 0; } - MOREACC(uleft); - MOREACC(uright); - MOREACC(uamul); - MOREACC(ublindf); - - if (!Accessories) { - pline("Not wearing any accessories.%s", - (iflags.cmdassist && (uarm || uarmc || uarmu || uarms || uarmh - || uarmg || uarmf)) - ? " Use 'T' command to take off armor." - : ""); - return (0); - } - if (Accessories > 1 || ParanoidRemove) + if (Naccessories != 1 || ParanoidRemove) otmp = getobj(accessories, "remove"); if (!otmp) return 0; - if (!(otmp->owornmask & W_ACCESSORY)) { - You("are not wearing that."); - return 0; - } - reset_remarm(); /* clear context.takeoff.mask and context.takeoff.what */ - (void) select_off(otmp); - if (!context.takeoff.mask) - return 0; - reset_remarm(); /* not used by Ring_/Amulet_/Blindf_off() */ - - if (otmp == uright || otmp == uleft) { - /* Sometimes we want to give the off_msg before removing and - * sometimes after; for instance, "you were wearing a moonstone - * ring (on right hand)" is desired but "you were wearing a - * square amulet (being worn)" is not because of the redundant - * "being worn". - */ - off_msg(otmp); - Ring_off(otmp); - } else if (otmp == uamul) { - Amulet_off(); - off_msg(otmp); - } else if (otmp == ublindf) { - Blindf_off(otmp); /* does its own off_msg */ - } else { - impossible("removing strange accessory?"); - } - return (1); + return armor_or_accessory_off(otmp); } /* Check if something worn is cursed _and_ unremovable. */ @@ -1457,9 +1474,9 @@ register struct obj *otmp; You("can't. %s cursed.", use_plural ? "They are" : "It is"); otmp->bknown = TRUE; - return (1); + return 1; } - return (0); + return 0; } int @@ -1516,7 +1533,7 @@ register struct obj *otmp; off_msg(otmp); } context.takeoff.mask = context.takeoff.what = 0L; - return (1); + return 1; } STATIC_OVL void @@ -1549,12 +1566,16 @@ boolean noisy; int err = 0; const char *which; - which = is_cloak(otmp) ? c_cloak : is_shirt(otmp) - ? c_shirt - : is_suit(otmp) ? c_suit : 0; - if (which && cantweararm(youmonst.data) && + which = is_cloak(otmp) + ? c_cloak + : is_shirt(otmp) + ? c_shirt + : is_suit(otmp) + ? c_suit + : 0; + if (which && cantweararm(youmonst.data) /* same exception for cloaks as used in m_dowear() */ - (which != c_cloak || youmonst.data->msize != MZ_SMALL) + && (which != c_cloak || youmonst.data->msize != MZ_SMALL) && (racial_exception(&youmonst, otmp) < 1)) { if (noisy) pline_The("%s will not fit on your body.", which); @@ -1703,202 +1724,226 @@ boolean noisy; return !err; } +STATIC_OVL int +accessory_or_armor_on(obj) +struct obj *obj; +{ + long mask = 0L; + boolean armor, ring, eyewear; + + if (obj->owornmask & (W_ACCESSORY | W_ARMOR)) { + already_wearing(c_that_); + return 0; + } + armor = (obj->oclass == ARMOR_CLASS); + ring = (obj->oclass == RING_CLASS || obj->otyp == MEAT_RING); + eyewear = (obj->otyp == BLINDFOLD || obj->otyp == TOWEL + || obj->otyp == LENSES); + /* checks which are performed prior to actually touching the item */ + if (armor) { + if (!canwearobj(obj, &mask, TRUE)) + return 0; + + if (obj->otyp == HELM_OF_OPPOSITE_ALIGNMENT + && qstart_level.dnum == u.uz.dnum) { /* in quest */ + if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL]) + You("narrowly avoid losing all chance at your goal."); + else /* converted */ + You("are suddenly overcome with shame and change your mind."); + u.ublessed = 0; /* lose your god's protection */ + makeknown(obj->otyp); + context.botl = 1; /*for AC after zeroing u.ublessed */ + return 1; + } + } else { + /* accessory */ + if (ring) { + char answer, qbuf[QBUFSZ]; + int res = 0; + + if (nolimbs(youmonst.data)) { + You("cannot make the ring stick to your body."); + return 0; + } + if (uleft && uright) { + There("are no more %s%s to fill.", + humanoid(youmonst.data) ? "ring-" : "", + makeplural(body_part(FINGER))); + return 0; + } + if (uleft) { + mask = RIGHT_RING; + } else if (uright) { + mask = LEFT_RING; + } else { + do { + Sprintf(qbuf, "Which %s%s, Right or Left?", + humanoid(youmonst.data) ? "ring-" : "", + body_part(FINGER)); + answer = yn_function(qbuf, "rl", '\0'); + switch (answer) { + case '\0': + return 0; + case 'l': + case 'L': + mask = LEFT_RING; + break; + case 'r': + case 'R': + mask = RIGHT_RING; + break; + } + } while (!mask); + } + if (uarmg && uarmg->cursed) { + res = !uarmg->bknown; + uarmg->bknown = 1; + You("cannot remove your gloves to put on the ring."); + return res; /* uses move iff we learned gloves are cursed */ + } + if (uwep) { + res = !uwep->bknown; /* check this before calling welded() */ + if ((mask == RIGHT_RING || bimanual(uwep)) && welded(uwep)) { + const char *hand = body_part(HAND); + + /* welded will set bknown */ + if (bimanual(uwep)) + hand = makeplural(hand); + You("cannot free your weapon %s to put on the ring.", + hand); + return res; /* uses move iff we learned weapon is cursed */ + } + } + } else if (obj->oclass == AMULET_CLASS) { + if (uamul) { + already_wearing("an amulet"); + return 0; + } + } else if (eyewear) { + if (ublindf) { + if (ublindf->otyp == TOWEL) + Your("%s is already covered by a towel.", + body_part(FACE)); + else if (ublindf->otyp == BLINDFOLD) { + if (obj->otyp == LENSES) + already_wearing2("lenses", "a blindfold"); + else + already_wearing("a blindfold"); + } else if (ublindf->otyp == LENSES) { + if (obj->otyp == BLINDFOLD) + already_wearing2("a blindfold", "some lenses"); + else + already_wearing("some lenses"); + } else { + already_wearing(something); /* ??? */ + } + return 0; + } + } else { + /* neither armor nor accessory */ + You_cant("wear that!"); + return 0; + } + } + + if (!retouch_object(&obj, FALSE)) + return 1; /* costs a turn even though it didn't get worn */ + + if (armor) { + int delay; + + obj->known = 1; /* since AC is shown on the status line */ + /* if the armor is wielded, release it for wearing */ + if (obj->owornmask & W_WEAPON) + remove_worn_item(obj, FALSE); + setworn(obj, mask); + delay = -objects[obj->otyp].oc_delay; + if (delay) { + nomul(delay); + multi_reason = "dressing up"; + if (is_boots(obj)) + afternmv = Boots_on; + if (is_helmet(obj)) + afternmv = Helmet_on; + if (is_gloves(obj)) + afternmv = Gloves_on; + if (obj == uarm) + afternmv = Armor_on; + nomovemsg = "You finish your dressing maneuver."; + } else { + if (is_cloak(obj)) + (void) Cloak_on(); + if (is_shield(obj)) + (void) Shield_on(); + if (is_shirt(obj)) + (void) Shirt_on(); + on_msg(obj); + } + context.takeoff.mask = context.takeoff.what = 0L; + } else { /* not armor */ + boolean give_feedback = FALSE; + + /* [releasing wielded accessory handled in Xxx_on()] */ + if (ring) { + setworn(obj, mask); + Ring_on(obj); + give_feedback = TRUE; + } else if (obj->oclass == AMULET_CLASS) { + setworn(obj, W_AMUL); + Amulet_on(); + /* no feedback here if amulet of change got used up */ + give_feedback = (uamul != 0); + } else if (eyewear) { + /* setworn() handled by Blindf_on() */ + Blindf_on(obj); + /* message handled by Blindf_on(); leave give_feedback False */ + } + /* feedback for ring or for amulet other than 'change' */ + if (give_feedback && is_worn(obj)) + prinv((char *) 0, obj, 0L); + } + return 1; +} + /* the 'W' command */ int dowear() { struct obj *otmp; - int delay; - long mask = 0; - /* cantweararm checks for suits of armor */ - /* verysmall or nohands checks for shields, gloves, etc... */ + /* cantweararm() checks for suits of armor, not what we want here; + verysmall() or nohands() checks for shields, gloves, etc... */ if ((verysmall(youmonst.data) || nohands(youmonst.data))) { pline("Don't even bother."); - return (0); + return 0; + } + if (uarm && uarmu && uarmc && uarmh && uarms && uarmg && uarmf + && uleft && uright && uamul && ublindf) { + /* 'W' message doesn't mention accessories */ + You("are already wearing a full complement of armor."); + return 0; } - otmp = getobj(clothes, "wear"); - if (!otmp) - return (0); - - if (!canwearobj(otmp, &mask, TRUE)) - return (0); - - if (!retouch_object(&otmp, FALSE)) - return 1; /* costs a turn even though it didn't get worn */ - - if (otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT - && qstart_level.dnum == u.uz.dnum) { /* in quest */ - if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL]) - You("narrowly avoid losing all chance at your goal."); - else /* converted */ - You("are suddenly overcome with shame and change your mind."); - u.ublessed = 0; /* lose your god's protection */ - makeknown(otmp->otyp); - context.botl = 1; - return 1; - } - - otmp->known = 1; /* since AC is shown on the status line */ - /* if the armor is wielded, release it for wearing */ - if (otmp->owornmask & W_WEAPON) - remove_worn_item(otmp, FALSE); - setworn(otmp, mask); - delay = -objects[otmp->otyp].oc_delay; - if (delay) { - nomul(delay); - multi_reason = "dressing up"; - if (is_boots(otmp)) - afternmv = Boots_on; - if (is_helmet(otmp)) - afternmv = Helmet_on; - if (is_gloves(otmp)) - afternmv = Gloves_on; - if (otmp == uarm) - afternmv = Armor_on; - nomovemsg = "You finish your dressing maneuver."; - } else { - if (is_cloak(otmp)) - (void) Cloak_on(); - if (is_shield(otmp)) - (void) Shield_on(); - if (is_shirt(otmp)) - (void) Shirt_on(); - on_msg(otmp); - } - context.takeoff.mask = context.takeoff.what = 0L; - return (1); + return otmp ? accessory_or_armor_on(otmp) : 0; } +/* the 'P' command */ int doputon() { struct obj *otmp; - long mask = 0L; - if (uleft && uright && uamul && ublindf) { + if (uleft && uright && uamul && ublindf + && uarm && uarmu && uarmc && uarmh && uarms && uarmg && uarmf) { + /* 'P' message doesn't mention armor */ Your("%s%s are full, and you're already wearing an amulet and %s.", humanoid(youmonst.data) ? "ring-" : "", makeplural(body_part(FINGER)), (ublindf->otyp == LENSES) ? "some lenses" : "a blindfold"); - return (0); + return 0; } otmp = getobj(accessories, "put on"); - if (!otmp) - return (0); - if (otmp->owornmask & W_ACCESSORY) { - already_wearing(c_that_); - return (0); - } - if (welded(otmp)) { - weldmsg(otmp); - return (0); - } -#if 0 /* defer til Xxx_on(); various failures below now leave item wielded */ - /* accessory might be wielded; release it for wearing */ - if (otmp->owornmask & W_WEAPON) - remove_worn_item(otmp, FALSE); -#endif - - if (otmp->oclass == RING_CLASS || otmp->otyp == MEAT_RING) { - if (nolimbs(youmonst.data)) { - You("cannot make the ring stick to your body."); - return (0); - } - if (uleft && uright) { - There("are no more %s%s to fill.", - humanoid(youmonst.data) ? "ring-" : "", - makeplural(body_part(FINGER))); - return (0); - } - if (uleft) - mask = RIGHT_RING; - else if (uright) - mask = LEFT_RING; - else - do { - char qbuf[QBUFSZ]; - char answer; - - Sprintf(qbuf, "Which %s%s, Right or Left?", - humanoid(youmonst.data) ? "ring-" : "", - body_part(FINGER)); - if (!(answer = yn_function(qbuf, "rl", '\0'))) - return (0); - switch (answer) { - case 'l': - case 'L': - mask = LEFT_RING; - break; - case 'r': - case 'R': - mask = RIGHT_RING; - break; - } - } while (!mask); - if (uarmg && uarmg->cursed) { - uarmg->bknown = TRUE; - You("cannot remove your gloves to put on the ring."); - return (0); - } - if (welded(uwep) && bimanual(uwep)) { - /* welded will set bknown */ - You("cannot free your weapon hands to put on the ring."); - return (0); - } - if (welded(uwep) && mask == RIGHT_RING) { - /* welded will set bknown */ - You("cannot free your weapon hand to put on the ring."); - return (0); - } - if (!retouch_object(&otmp, FALSE)) - return 1; /* costs a turn even though it didn't get worn */ - setworn(otmp, mask); - Ring_on(otmp); - } else if (otmp->oclass == AMULET_CLASS) { - if (uamul) { - already_wearing("an amulet"); - return (0); - } - if (!retouch_object(&otmp, FALSE)) - return 1; - setworn(otmp, W_AMUL); - Amulet_on(); - /* finished now if an amulet of change got used up */ - if (!uamul) - return 1; - } else { /* it's a blindfold, towel, or lenses */ - if (ublindf) { - if (ublindf->otyp == TOWEL) - Your("%s is already covered by a towel.", body_part(FACE)); - else if (ublindf->otyp == BLINDFOLD) { - if (otmp->otyp == LENSES) - already_wearing2("lenses", "a blindfold"); - else - already_wearing("a blindfold"); - } else if (ublindf->otyp == LENSES) { - if (otmp->otyp == BLINDFOLD) - already_wearing2("a blindfold", "some lenses"); - else - already_wearing("some lenses"); - } else - already_wearing(something); /* ??? */ - return (0); - } - if (otmp->otyp != BLINDFOLD && otmp->otyp != TOWEL - && otmp->otyp != LENSES) { - You_cant("wear that!"); - return (0); - } - if (!retouch_object(&otmp, FALSE)) - return 1; - Blindf_on(otmp); - return (1); - } - if (is_worn(otmp)) - prinv((char *) 0, otmp, 0L); - return (1); + return otmp ? accessory_or_armor_on(otmp) : 0; } void @@ -2046,7 +2091,7 @@ struct monst *victim; otmp = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS); if (otmp && (!otmph || !rn2(4))) otmph = otmp; - return (otmph); + return otmph; } /* used for praying to check and fix levitation trouble */ @@ -2206,7 +2251,7 @@ register struct obj *otmp; else impossible("select_off: %s???", doname(otmp)); - return (0); + return 0; } STATIC_OVL struct obj * @@ -2275,7 +2320,7 @@ do_takeoff() impossible("do_takeoff: taking off %lx", doff->what); } - return (otmp); + return otmp; } /* occupation callback for 'A' */ @@ -2290,7 +2335,7 @@ take_off(VOID_ARGS) if (doff->what) { if (doff->delay > 0) { doff->delay--; - return (1); /* still busy */ + return 1; /* still busy */ } else { if ((otmp = do_takeoff())) off_msg(otmp); @@ -2366,7 +2411,7 @@ take_off(VOID_ARGS) doff->delay--; set_occupation(take_off, doff->disrobing, 0); - return (1); /* get busy */ + return 1; /* get busy */ } /* clear saved context to avoid inappropriate resumption of interrupted 'A' */ @@ -2521,7 +2566,7 @@ register struct obj *atmp; #undef DESTROY_ARM stop_occupation(); - return (1); + return 1; } void diff --git a/src/invent.c b/src/invent.c index 7a58c3c22..0c430ee00 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1437877178 2015/07/26 02:19:38 $ $NHDT-Branch: master $:$NHDT-Revision: 1.169 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1438652306 2015/08/04 01:38:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.170 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -977,11 +977,11 @@ register const char *let, *word; let++, allowall = TRUE; if (*let == ALLOW_NONE) let++, allownone = TRUE; - /* "ugly check" for reading fortune cookies, part 1 */ - /* The normal 'ugly check' keeps the object on the inventory list. + /* "ugly check" for reading fortune cookies, part 1. + * The normal 'ugly check' keeps the object on the inventory list. * We don't want to do that for shirts/cookies, so the check for * them is handled a bit differently (and also requires that we set - * allowall in the caller) + * allowall in the caller). */ if (allowall && !strcmp(word, "read")) allowall = FALSE; @@ -1097,10 +1097,17 @@ register const char *let, *word; ) { foo--; } - /* ugly check for unworn armor that can't be worn */ + /* Third ugly check: acceptable but not listed as likely + * candidates in the prompt or in the inventory subset if + * player responds with '?'. + */ else if ( + /* ugly check for unworn armor that can't be worn */ (putting_on(word) && *let == ARMOR_CLASS && !canwearobj(otmp, &dummymask, FALSE)) + /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */ + || ((putting_on(word) || taking_off(word)) + && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS))) /* or unsuitable items rubbed on known touchstone */ || (!strncmp(word, "rub on the stone", 16) && *let == GEM_CLASS && otmp->dknown @@ -1310,6 +1317,9 @@ silly_thing(word, otmp) const char *word; struct obj *otmp; { +#if 1 /* 'P','R' vs 'W','T' handling is obsolete */ + nhUse(otmp); +#else const char *s1, *s2, *s3, *what; int ocls = otmp->oclass, otyp = otmp->otyp; @@ -1336,9 +1346,9 @@ struct obj *otmp; if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp)) what = "those"; pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); - } else { + } else +#endif pline(silly_thing_to, word); - } } STATIC_PTR int