1 /* SCCS Id: @(#)wield.c 3.4 2003/01/29 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 /* KMH -- Differences between the three weapon slots.
9 * The main weapon (uwep):
10 * 1. Is filled by the (w)ield command.
11 * 2. Can be filled with any type of item.
12 * 3. May be carried in one or both hands.
13 * 4. Is used as the melee weapon and as the launcher for
15 * 5. Only conveys intrinsics when it is a weapon, weapon-tool,
17 * 6. Certain cursed items will weld to the hand and cannot be
18 * unwielded or dropped. See erodeable_wep() and will_weld()
19 * below for the list of which items apply.
21 * The secondary weapon (uswapwep):
22 * 1. Is filled by the e(x)change command, which swaps this slot
23 * with the main weapon. If the "pushweapon" option is set,
24 * the (w)ield command will also store the old weapon in the
26 * 2. Can be field with anything that will fit in the main weapon
27 * slot; that is, any type of item.
28 * 3. Is usually NOT considered to be carried in the hands.
29 * That would force too many checks among the main weapon,
30 * second weapon, shield, gloves, and rings; and it would
31 * further be complicated by bimanual weapons. A special
32 * exception is made for two-weapon combat.
33 * 4. Is used as the second weapon for two-weapon combat, and as
34 * a convenience to swap with the main weapon.
35 * 5. Never conveys intrinsics.
36 * 6. Cursed items never weld (see #3 for reasons), but they also
37 * prevent two-weapon combat.
39 * The quiver (uquiver):
40 * 1. Is filled by the (Q)uiver command.
41 * 2. Can be filled with any type of item.
42 * 3. Is considered to be carried in a special part of the pack.
43 * 4. Is used as the item to throw with the (f)ire command.
44 * This is a convenience over the normal (t)hrow command.
45 * 5. Never conveys intrinsics.
46 * 6. Cursed items never weld; their effect is handled by the normal
49 * No item may be in more than one of these slots.
53 STATIC_DCL int FDECL(ready_weapon, (struct obj *));
55 /* used by will_weld() */
56 /* probably should be renamed */
57 #define erodeable_wep(optr) ((optr)->oclass == WEAPON_CLASS \
59 || (optr)->otyp == HEAVY_IRON_BALL \
60 || (optr)->otyp == IRON_CHAIN)
62 /* used by welded(), and also while wielding */
63 #define will_weld(optr) ((optr)->cursed \
64 && (erodeable_wep(optr) \
65 || (optr)->otyp == TIN_OPENER))
68 /*** Functions that place a given item in a slot ***/
69 /* Proper usage includes:
70 * 1. Initializing the slot during character generation or a
72 * 2. Setting the slot due to a player's actions.
73 * 3. If one of the objects in the slot are split off, these
74 * functions can be used to put the remainder back in the slot.
75 * 4. Putting an item that was thrown and returned back into the slot.
76 * 5. Emptying the slot, by passing a null object. NEVER pass
79 * If the item is being moved from another slot, it is the caller's
80 * responsibility to handle that. It's also the caller's responsibility
81 * to print the appropriate messages.
85 register struct obj *obj;
87 struct obj *olduwep = uwep;
89 if (obj == uwep) return; /* necessary to not set unweapon */
90 /* This message isn't printed in the caller because it happens
91 * *whenever* Sunsword is unwielded, from whatever cause.
94 if (uwep == obj && artifact_light(olduwep) && olduwep->lamplit) {
95 end_burn(olduwep, FALSE);
96 if (!Blind) pline("%s glowing.", Tobjnam(olduwep, "stop"));
98 /* Note: Explicitly wielding a pick-axe will not give a "bashing"
99 * message. Wielding one via 'a'pplying it will.
100 * 3.2.2: Wielding arbitrary objects will give bashing message too.
103 unweapon = (obj->oclass == WEAPON_CLASS) ?
104 is_launcher(obj) || is_ammo(obj) ||
105 is_missile(obj) || (is_pole(obj)
109 ) : !is_weptool(obj);
111 unweapon = TRUE; /* for "bare hands" message */
119 /* Separated function so swapping works easily */
125 You("are empty %s.", body_part(HANDED));
126 setuwep((struct obj *) 0);
129 You("are already empty %s.", body_part(HANDED));
130 } else if (!uarmg && !Stone_resistance && wep->otyp == CORPSE
131 && touch_petrifies(&mons[wep->corpsenm])) {
132 /* Prevent wielding cockatrice when not wearing gloves --KAA */
135 You("wield the %s corpse in your bare %s.",
136 mons[wep->corpsenm].mname, makeplural(body_part(HAND)));
137 Sprintf(kbuf, "%s corpse", an(mons[wep->corpsenm].mname));
139 } else if (uarms && bimanual(wep))
140 You("cannot wield a two-handed %s while wearing a shield.",
141 is_sword(wep) ? "sword" :
142 wep->otyp == BATTLE_AXE ? "axe" : "weapon");
143 else if (wep->oartifact && !touch_artifact(wep, &youmonst)) {
144 res++; /* takes a turn even though it doesn't get wielded */
146 /* Weapon WILL be wielded after this point */
148 if (will_weld(wep)) {
149 const char *tmp = xname(wep), *thestr = "The ";
150 if (strncmp(tmp, thestr, 4) && !strncmp(The(tmp),thestr,4))
153 pline("%s%s %s to your %s!", tmp, aobjnam(wep, "weld"),
154 (wep->quan == 1L) ? "itself" : "themselves", /* a3 */
156 (const char *)makeplural(body_part(HAND))
160 /* The message must be printed before setuwep (since
161 * you might die and be revived from changing weapons),
162 * and the message must be before the death message and
163 * Lifesaved rewielding. Yet we want the message to
164 * say "weapon in hand", thus this kludge.
166 long dummy = wep->owornmask;
167 wep->owornmask |= W_WEP;
168 prinv((char *)0, wep, 0L);
169 wep->owornmask = dummy;
173 /* KMH -- Talking artifacts are finally implemented */
176 if (artifact_light(wep) && !wep->lamplit) {
177 begin_burn(wep, FALSE);
179 pline("%s to glow brilliantly!", Tobjnam(wep, "begin"));
183 /* we'll get back to this someday, but it's not balanced yet */
184 if (Race_if(PM_ELF) && !wep->oartifact &&
185 objects[wep->otyp].oc_material == IRON) {
186 /* Elves are averse to wielding cold iron */
187 You("have an uneasy feeling about wielding cold iron.");
193 struct monst *this_shkp;
195 if ((this_shkp = shop_keeper(inside_shop(u.ux, u.uy))) !=
197 pline("%s says \"You be careful with my %s!\"",
208 register struct obj *obj;
210 setworn(obj, W_QUIVER);
216 register struct obj *obj;
218 setworn(obj, W_SWAPWEP);
223 /*** Commands to change particular slot(s) ***/
225 static NEARDATA const char wield_objs[] =
226 { ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, TOOL_CLASS, 0 };
227 static NEARDATA const char ready_objs[] =
228 { ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0 };
229 static NEARDATA const char bullets[] = /* (note: different from dothrow.c) */
230 { ALL_CLASSES, ALLOW_NONE, GEM_CLASS, WEAPON_CLASS, 0 };
235 register struct obj *wep, *oldwep;
238 /* May we attempt this? */
240 if (cantwield(youmonst.data)) {
241 pline("Don't be ridiculous!");
245 /* Prompt for a new weapon */
246 if (!(wep = getobj(wield_objs, "wield")))
249 else if (wep == uwep) {
250 You("are already wielding that!");
251 if (is_weptool(wep)) unweapon = FALSE; /* [see setuwep()] */
253 } else if (welded(uwep)) {
255 /* previously interrupted armor removal mustn't be resumed */
260 /* Handle no object, or object in other slot */
262 wep = (struct obj *) 0;
263 else if (wep == uswapwep)
264 return (doswapweapon());
265 else if (wep == uquiver)
266 setuqwep((struct obj *) 0);
267 else if (wep->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL
272 You("cannot wield that!");
276 /* Set your new primary weapon */
278 result = ready_weapon(wep);
279 if (flags.pushweapon && oldwep && uwep != oldwep)
289 register struct obj *oldwep, *oldswap;
293 /* May we attempt this? */
295 if (cantwield(youmonst.data)) {
296 pline("Don't be ridiculous!");
304 /* Unwield your current secondary weapon */
307 setuswapwep((struct obj *) 0);
309 /* Set your new primary weapon */
310 result = ready_weapon(oldswap);
312 /* Set your new secondary weapon */
314 /* Wield failed for some reason */
315 setuswapwep(oldswap);
319 prinv((char *)0, uswapwep, 0L);
321 You("have no secondary weapon readied.");
324 if (u.twoweap && !can_twoweapon())
333 register struct obj *newquiver;
334 const char *quivee_types = (uslinging() ||
335 (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING)) ?
336 bullets : ready_objs;
338 /* Since the quiver isn't in your hands, don't check cantwield(), */
339 /* will_weld(), touch_petrifies(), etc. */
342 /* Because 'Q' used to be quit... */
343 if (flags.suppress_alert < FEATURE_NOTICE_VER(3,3,0))
344 pline("Note: Please use #quit if you wish to exit the game.");
346 /* Prompt for a new quiver */
347 if (!(newquiver = getobj(quivee_types, "ready")))
351 /* Handle no object, or object in other slot */
352 /* Any type is okay, since we give no intrinsics anyways */
353 if (newquiver == &zeroobj) {
354 /* Explicitly nothing */
356 You("now have no ammunition readied.");
357 setuqwep(newquiver = (struct obj *) 0);
359 You("already have no ammunition readied!");
362 } else if (newquiver == uquiver) {
363 pline("That ammunition is already readied!");
365 } else if (newquiver == uwep) {
366 /* Prevent accidentally readying the main weapon */
367 pline("%s already being used as a weapon!",
368 !is_plural(uwep) ? "That is" : "They are");
370 } else if (newquiver->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL
375 You("cannot ready that!");
381 /* Check if it's the secondary weapon */
382 if (newquiver == uswapwep) {
383 setuswapwep((struct obj *) 0);
387 /* Okay to put in quiver; print it */
388 dummy = newquiver->owornmask;
389 newquiver->owornmask |= W_QUIVER;
390 prinv((char *)0, newquiver, 0L);
391 newquiver->owornmask = dummy;
394 /* Finally, place it in the quiver */
396 /* Take no time since this is a convenience slot */
400 /* used for #rub and for applying pick-axe, whip, grappling hook, or polearm */
401 /* (moved from apply.c) */
403 wield_tool(obj, verb)
405 const char *verb; /* "rub",&c */
410 if (obj == uwep) return TRUE; /* nothing to do if already wielding it */
412 if (!verb) verb = "wield";
414 more_than_1 = (obj->quan > 1L ||
415 strstri(what, "pair of ") != 0 ||
416 strstri(what, "s of ") != 0);
418 if (obj->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL)) {
421 You_cant("%s %s %s while wearing %s.",
422 verb, shk_your(yourbuf, obj), what,
423 more_than_1 ? "them" : "it");
428 const char *hand = body_part(HAND);
430 if (bimanual(uwep)) hand = makeplural(hand);
431 if (strstri(what, "pair of ") != 0) more_than_1 = FALSE;
433 "Since your weapon is welded to your %s, you cannot %s %s %s.",
434 hand, verb, more_than_1 ? "those" : "that", xname(obj));
436 You_cant("do that.");
440 if (cantwield(youmonst.data)) {
441 You_cant("hold %s strongly enough.", more_than_1 ? "them" : "it");
445 if (uarms && bimanual(obj)) {
446 You("cannot %s a two-handed %s while wearing a shield.",
447 verb, (obj->oclass == WEAPON_CLASS) ? "weapon" : "tool");
450 if (uquiver == obj) setuqwep((struct obj *)0);
451 if (uswapwep == obj) {
452 (void) doswapweapon();
453 /* doswapweapon might fail */
454 if (uswapwep == obj) return FALSE;
456 You("now wield %s.", doname(obj));
459 if (uwep != obj) return FALSE; /* rewielded old object after dying */
460 /* applying weapon or tool that gets wielded ends two-weapon combat */
463 if (obj->oclass != WEAPON_CLASS)
473 #define NOT_WEAPON(obj) (!is_weptool(obj) && obj->oclass != WEAPON_CLASS)
474 if (!could_twoweap(youmonst.data)) {
476 You_cant("use two weapons in your current form.");
478 pline("%s aren't able to use two weapons at once.",
479 makeplural((flags.female && urole.name.f) ?
480 urole.name.f : urole.name.m));
481 } else if (!uwep || !uswapwep)
482 Your("%s%s%s empty.", uwep ? "left " : uswapwep ? "right " : "",
483 body_part(HAND), (!uwep && !uswapwep) ? "s are" : " is");
484 else if (NOT_WEAPON(uwep) || NOT_WEAPON(uswapwep)) {
485 otmp = NOT_WEAPON(uwep) ? uwep : uswapwep;
486 pline("%s %s.", Yname2(otmp),
487 is_plural(otmp) ? "aren't weapons" : "isn't a weapon");
488 } else if (bimanual(uwep) || bimanual(uswapwep)) {
489 otmp = bimanual(uwep) ? uwep : uswapwep;
490 pline("%s isn't one-handed.", Yname2(otmp));
492 You_cant("use two weapons while wearing a shield.");
493 else if (uswapwep->oartifact)
494 pline("%s %s being held second to another weapon!",
495 Yname2(uswapwep), otense(uswapwep, "resist"));
496 else if (!uarmg && !Stone_resistance && (uswapwep->otyp == CORPSE &&
497 touch_petrifies(&mons[uswapwep->corpsenm]))) {
500 You("wield the %s corpse with your bare %s.",
501 mons[uswapwep->corpsenm].mname, body_part(HAND));
502 Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname));
504 } else if (Glib || uswapwep->cursed) {
506 uswapwep->bknown = TRUE;
517 struct obj *obj = uswapwep;
519 /* Avoid trashing makeplural's static buffer */
520 Strcpy(str, makeplural(body_part(HAND)));
521 Your("%s from your %s!", aobjnam(obj, "slip"), str);
528 /* You can always toggle it off */
530 You("switch to your primary weapon.");
536 /* May we use two weapons? */
537 if (can_twoweapon()) {
539 You("begin two-weapon combat.");
542 return (rnd(20) > ACURR(A_DEX));
547 /*** Functions to empty a given slot ***/
548 /* These should be used only when the item can't be put back in
549 * the slot by life saving. Proper usage includes:
550 * 1. The item has been eaten, stolen, burned away, or rotted away.
551 * 2. Making an item disappear for a bones pile.
557 if (artifact_light(uwep) && uwep->lamplit) {
558 end_burn(uwep, FALSE);
559 if (!Blind) pline("%s glowing.", Tobjnam(uwep, "stop"));
561 setworn((struct obj *)0, W_WEP);
571 setworn((struct obj *)0, W_SWAPWEP);
580 setworn((struct obj *)0, W_QUIVER);
589 You("can no longer use two weapons at once.");
596 /* Maybe rust object, or corrode it if acid damage is called for */
598 erode_obj(target, acid_dmg, fade_scrolls)
599 struct obj *target; /* object (e.g. weapon or armor) to erode */
601 boolean fade_scrolls;
604 struct monst *victim;
610 victim = carried(target) ? &youmonst :
611 mcarried(target) ? target->ocarry : (struct monst *)0;
612 vismon = victim && (victim != &youmonst) && canseemon(victim);
613 visobj = !victim && cansee(bhitpos.x, bhitpos.y); /* assume thrown */
615 erosion = acid_dmg ? target->oeroded2 : target->oeroded;
617 if (target->greased) {
618 grease_protect(target,(char *)0,victim);
619 } else if (target->oclass == SCROLL_CLASS) {
620 if(fade_scrolls && target->otyp != SCR_BLANK_PAPER
622 && target->otyp != SCR_MAIL
627 if (victim == &youmonst)
628 Your("%s.", aobjnam(target, "fade"));
630 pline("%s's %s.", Monnam(victim),
631 aobjnam(target, "fade"));
633 pline_The("%s.", aobjnam(target, "fade"));
635 target->otyp = SCR_BLANK_PAPER;
638 } else if (target->oerodeproof ||
639 (acid_dmg ? !is_corrodeable(target) : !is_rustprone(target))) {
640 if (flags.verbose || !(target->oerodeproof && target->rknown)) {
641 if (victim == &youmonst)
642 Your("%s not affected.", aobjnam(target, "are"));
644 pline("%s's %s not affected.", Monnam(victim),
645 aobjnam(target, "are"));
646 /* no message if not carried */
648 if (target->oerodeproof) target->rknown = TRUE;
649 } else if (erosion < MAX_ERODE) {
650 if (victim == &youmonst)
651 Your("%s%s!", aobjnam(target, acid_dmg ? "corrode" : "rust"),
652 erosion+1 == MAX_ERODE ? " completely" :
653 erosion ? " further" : "");
655 pline("%s's %s%s!", Monnam(victim),
656 aobjnam(target, acid_dmg ? "corrode" : "rust"),
657 erosion+1 == MAX_ERODE ? " completely" :
658 erosion ? " further" : "");
661 aobjnam(target, acid_dmg ? "corrode" : "rust"),
662 erosion+1 == MAX_ERODE ? " completely" :
663 erosion ? " further" : "");
670 if (victim == &youmonst)
671 Your("%s completely %s.",
672 aobjnam(target, Blind ? "feel" : "look"),
673 acid_dmg ? "corroded" : "rusty");
675 pline("%s's %s completely %s.", Monnam(victim),
676 aobjnam(target, "look"),
677 acid_dmg ? "corroded" : "rusty");
679 pline_The("%s completely %s.",
680 aobjnam(target, "look"),
681 acid_dmg ? "corroded" : "rusty");
687 chwepon(otmp, amount)
688 register struct obj *otmp;
691 const char *color = hcolor((amount < 0) ? NH_BLACK : NH_BLUE);
693 int otyp = STRANGE_OBJECT;
695 if(!uwep || (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))) {
698 Sprintf(buf, "Your %s %s.", makeplural(body_part(HAND)),
699 (amount >= 0) ? "twitch" : "itch");
700 strange_feeling(otmp, buf);
701 exercise(A_DEX, (boolean) (amount >= 0));
705 if (otmp && otmp->oclass == SCROLL_CLASS) otyp = otmp->otyp;
707 if(uwep->otyp == WORM_TOOTH && amount >= 0) {
708 uwep->otyp = CRYSKNIFE;
709 uwep->oerodeproof = 0;
710 Your("weapon seems sharper now.");
712 if (otyp != STRANGE_OBJECT) makeknown(otyp);
716 if(uwep->otyp == CRYSKNIFE && amount < 0) {
717 uwep->otyp = WORM_TOOTH;
718 uwep->oerodeproof = 0;
719 Your("weapon seems duller now.");
720 if (otyp != STRANGE_OBJECT && otmp->bknown) makeknown(otyp);
724 if (amount < 0 && uwep->oartifact && restrict_name(uwep, ONAME(uwep))) {
726 Your("%s %s.", aobjnam(uwep, "faintly glow"), color);
729 /* there is a (soft) upper and lower limit to uwep->spe */
730 if(((uwep->spe > 5 && amount >= 0) || (uwep->spe < -5 && amount < 0))
733 Your("%s %s for a while and then %s.",
734 aobjnam(uwep, "violently glow"), color,
735 otense(uwep, "evaporate"));
737 Your("%s.", aobjnam(uwep, "evaporate"));
739 useupall(uwep); /* let all of them disappear */
743 xtime = (amount*amount == 1) ? "moment" : "while";
744 Your("%s %s for a %s.",
745 aobjnam(uwep, amount == 0 ? "violently glow" : "glow"),
747 if (otyp != STRANGE_OBJECT && uwep->known &&
748 (amount > 0 || (amount < 0 && otmp->bknown)))
752 if(amount > 0) uwep->cursed = 0;
755 * Enchantment, which normally improves a weapon, has an
756 * addition adverse reaction on Magicbane whose effects are
757 * spe dependent. Give an obscure clue here.
759 if (uwep->oartifact == ART_MAGICBANE && uwep->spe >= 0) {
760 Your("right %s %sches!",
762 (((amount > 1) && (uwep->spe > 1)) ? "flin" : "it"));
765 /* an elven magic clue, cookie@keebler */
766 /* elven weapons vibrate warningly when enchanted beyond a limit */
768 && (is_elven_weapon(uwep) || uwep->oartifact || !rn2(7)))
769 Your("%s unexpectedly.",
770 aobjnam(uwep, "suddenly vibrate"));
777 register struct obj *obj;
779 if (obj && obj == uwep && will_weld(obj)) {
788 register struct obj *obj;
792 savewornmask = obj->owornmask;
793 Your("%s %s welded to your %s!",
794 xname(obj), otense(obj, "are"),
795 bimanual(obj) ? (const char *)makeplural(body_part(HAND))
797 obj->owornmask = savewornmask;