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. */
4
5#include "hack.h"
6
7/* KMH -- Differences between the three weapon slots.
8 *
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
14 *     ammunition.
15 * 5.  Only conveys intrinsics when it is a weapon, weapon-tool,
16 *     or artifact.
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.
20 *
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
25 *     secondary slot.
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.
38 *
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
47 *     throwing code.
48 *
49 * No item may be in more than one of these slots.
50 */
51
52
53STATIC_DCL int FDECL(ready_weapon, (struct obj *));
54
55/* used by will_weld() */
56/* probably should be renamed */
57#define erodeable_wep(optr)	((optr)->oclass == WEAPON_CLASS \
58				|| is_weptool(optr) \
59				|| (optr)->otyp == HEAVY_IRON_BALL \
60				|| (optr)->otyp == IRON_CHAIN)
61
62/* used by welded(), and also while wielding */
63#define will_weld(optr)		((optr)->cursed \
64				&& (erodeable_wep(optr) \
65				   || (optr)->otyp == TIN_OPENER))
66
67
68/*** Functions that place a given item in a slot ***/
69/* Proper usage includes:
70 * 1.  Initializing the slot during character generation or a
71 *     restore.
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
77 *     zeroobj!
78 *
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.
82 */
83void
84setuwep(obj)
85register struct obj *obj;
86{
87	struct obj *olduwep = uwep;
88
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.
92	 */
93	setworn(obj, W_WEP);
94	if (uwep == obj && artifact_light(olduwep) && olduwep->lamplit) {
95	    end_burn(olduwep, FALSE);
96	    if (!Blind) pline("%s glowing.", Tobjnam(olduwep, "stop"));
97	}
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.
101	 */
102	if (obj) {
103		unweapon = (obj->oclass == WEAPON_CLASS) ?
104				is_launcher(obj) || is_ammo(obj) ||
105				is_missile(obj) || (is_pole(obj)
106#ifdef STEED
107				&& !u.usteed
108#endif
109				) : !is_weptool(obj);
110	} else
111		unweapon = TRUE;	/* for "bare hands" message */
112	update_inventory();
113}
114
115STATIC_OVL int
116ready_weapon(wep)
117struct obj *wep;
118{
119	/* Separated function so swapping works easily */
120	int res = 0;
121
122	if (!wep) {
123	    /* No weapon */
124	    if (uwep) {
125		You("are empty %s.", body_part(HANDED));
126		setuwep((struct obj *) 0);
127		res++;
128	    } else
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 */
133	    char kbuf[BUFSZ];
134
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));
138	    instapetrify(kbuf);
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 */
145	} else {
146	    /* Weapon WILL be wielded after this point */
147	    res++;
148	    if (will_weld(wep)) {
149		const char *tmp = xname(wep), *thestr = "The ";
150		if (strncmp(tmp, thestr, 4) && !strncmp(The(tmp),thestr,4))
151		    tmp = thestr;
152		else tmp = "";
153		pline("%s%s %s to your %s!", tmp, aobjnam(wep, "weld"),
154			(wep->quan == 1L) ? "itself" : "themselves", /* a3 */
155			bimanual(wep) ?
156				(const char *)makeplural(body_part(HAND))
157				: body_part(HAND));
158		wep->bknown = TRUE;
159	    } else {
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.
165		 */
166		long dummy = wep->owornmask;
167		wep->owornmask |= W_WEP;
168		prinv((char *)0, wep, 0L);
169		wep->owornmask = dummy;
170	    }
171	    setuwep(wep);
172
173	    /* KMH -- Talking artifacts are finally implemented */
174	    arti_speak(wep);
175
176	    if (artifact_light(wep) && !wep->lamplit) {
177		begin_burn(wep, FALSE);
178		if (!Blind)
179		    pline("%s to glow brilliantly!", Tobjnam(wep, "begin"));
180	    }
181
182#if 0
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.");
188		change_luck(-1);
189	    }
190#endif
191
192	    if (wep->unpaid) {
193		struct monst *this_shkp;
194
195		if ((this_shkp = shop_keeper(inside_shop(u.ux, u.uy))) !=
196		    (struct monst *)0) {
197		    pline("%s says \"You be careful with my %s!\"",
198			  shkname(this_shkp),
199			  xname(wep));
200		}
201	    }
202	}
203	return(res);
204}
205
206void
207setuqwep(obj)
208register struct obj *obj;
209{
210	setworn(obj, W_QUIVER);
211	update_inventory();
212}
213
214void
215setuswapwep(obj)
216register struct obj *obj;
217{
218	setworn(obj, W_SWAPWEP);
219	update_inventory();
220}
221
222
223/*** Commands to change particular slot(s) ***/
224
225static NEARDATA const char wield_objs[] =
226	{ ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, TOOL_CLASS, 0 };
227static NEARDATA const char ready_objs[] =
228	{ ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0 };
229static NEARDATA const char bullets[] =	/* (note: different from dothrow.c) */
230	{ ALL_CLASSES, ALLOW_NONE, GEM_CLASS, WEAPON_CLASS, 0 };
231
232int
233dowield()
234{
235	register struct obj *wep, *oldwep;
236	int result;
237
238	/* May we attempt this? */
239	multi = 0;
240	if (cantwield(youmonst.data)) {
241		pline("Don't be ridiculous!");
242		return(0);
243	}
244
245	/* Prompt for a new weapon */
246	if (!(wep = getobj(wield_objs, "wield")))
247		/* Cancelled */
248		return (0);
249	else if (wep == uwep) {
250	    You("are already wielding that!");
251	    if (is_weptool(wep)) unweapon = FALSE;	/* [see setuwep()] */
252		return (0);
253	} else if (welded(uwep)) {
254		weldmsg(uwep);
255		/* previously interrupted armor removal mustn't be resumed */
256		reset_remarm();
257		return (0);
258	}
259
260	/* Handle no object, or object in other slot */
261	if (wep == &zeroobj)
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
268#ifdef STEED
269			| W_SADDLE
270#endif
271			)) {
272		You("cannot wield that!");
273		return (0);
274	}
275
276	/* Set your new primary weapon */
277	oldwep = uwep;
278	result = ready_weapon(wep);
279	if (flags.pushweapon && oldwep && uwep != oldwep)
280		setuswapwep(oldwep);
281	untwoweapon();
282
283	return (result);
284}
285
286int
287doswapweapon()
288{
289	register struct obj *oldwep, *oldswap;
290	int result = 0;
291
292
293	/* May we attempt this? */
294	multi = 0;
295	if (cantwield(youmonst.data)) {
296		pline("Don't be ridiculous!");
297		return(0);
298	}
299	if (welded(uwep)) {
300		weldmsg(uwep);
301		return (0);
302	}
303
304	/* Unwield your current secondary weapon */
305	oldwep = uwep;
306	oldswap = uswapwep;
307	setuswapwep((struct obj *) 0);
308
309	/* Set your new primary weapon */
310	result = ready_weapon(oldswap);
311
312	/* Set your new secondary weapon */
313	if (uwep == oldwep)
314		/* Wield failed for some reason */
315		setuswapwep(oldswap);
316	else {
317		setuswapwep(oldwep);
318		if (uswapwep)
319			prinv((char *)0, uswapwep, 0L);
320		else
321			You("have no secondary weapon readied.");
322	}
323
324	if (u.twoweap && !can_twoweapon())
325		untwoweapon();
326
327	return (result);
328}
329
330int
331dowieldquiver()
332{
333	register struct obj *newquiver;
334	const char *quivee_types = (uslinging() ||
335		  (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING)) ?
336				  bullets : ready_objs;
337
338	/* Since the quiver isn't in your hands, don't check cantwield(), */
339	/* will_weld(), touch_petrifies(), etc. */
340	multi = 0;
341
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.");
345
346	/* Prompt for a new quiver */
347	if (!(newquiver = getobj(quivee_types, "ready")))
348		/* Cancelled */
349		return (0);
350
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 */
355		if (uquiver) {
356			You("now have no ammunition readied.");
357			setuqwep(newquiver = (struct obj *) 0);
358		} else {
359			You("already have no ammunition readied!");
360			return(0);
361		}
362	} else if (newquiver == uquiver) {
363		pline("That ammunition is already readied!");
364		return(0);
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");
369		return(0);
370	} else if (newquiver->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL
371#ifdef STEED
372			| W_SADDLE
373#endif
374			)) {
375		You("cannot ready that!");
376		return (0);
377	} else {
378		long dummy;
379
380
381		/* Check if it's the secondary weapon */
382		if (newquiver == uswapwep) {
383			setuswapwep((struct obj *) 0);
384			untwoweapon();
385		}
386
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;
392	}
393
394	/* Finally, place it in the quiver */
395	setuqwep(newquiver);
396	/* Take no time since this is a convenience slot */
397	return (0);
398}
399
400/* used for #rub and for applying pick-axe, whip, grappling hook, or polearm */
401/* (moved from apply.c) */
402boolean
403wield_tool(obj, verb)
404struct obj *obj;
405const char *verb;	/* "rub",&c */
406{
407    const char *what;
408    boolean more_than_1;
409
410    if (obj == uwep) return TRUE;   /* nothing to do if already wielding it */
411
412    if (!verb) verb = "wield";
413    what = xname(obj);
414    more_than_1 = (obj->quan > 1L ||
415		   strstri(what, "pair of ") != 0 ||
416		   strstri(what, "s of ") != 0);
417
418    if (obj->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL)) {
419	char yourbuf[BUFSZ];
420
421	You_cant("%s %s %s while wearing %s.",
422		 verb, shk_your(yourbuf, obj), what,
423		 more_than_1 ? "them" : "it");
424	return FALSE;
425    }
426    if (welded(uwep)) {
427	if (flags.verbose) {
428	    const char *hand = body_part(HAND);
429
430	    if (bimanual(uwep)) hand = makeplural(hand);
431	    if (strstri(what, "pair of ") != 0) more_than_1 = FALSE;
432	    pline(
433	     "Since your weapon is welded to your %s, you cannot %s %s %s.",
434		  hand, verb, more_than_1 ? "those" : "that", xname(obj));
435	} else {
436	    You_cant("do that.");
437	}
438	return FALSE;
439    }
440    if (cantwield(youmonst.data)) {
441	You_cant("hold %s strongly enough.", more_than_1 ? "them" : "it");
442	return FALSE;
443    }
444    /* check shield */
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");
448	return FALSE;
449    }
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;
455    } else {
456	You("now wield %s.", doname(obj));
457	setuwep(obj);
458    }
459    if (uwep != obj) return FALSE;	/* rewielded old object after dying */
460    /* applying weapon or tool that gets wielded ends two-weapon combat */
461    if (u.twoweap)
462	untwoweapon();
463    if (obj->oclass != WEAPON_CLASS)
464	unweapon = TRUE;
465    return TRUE;
466}
467
468int
469can_twoweapon()
470{
471	struct obj *otmp;
472
473#define NOT_WEAPON(obj) (!is_weptool(obj) && obj->oclass != WEAPON_CLASS)
474	if (!could_twoweap(youmonst.data)) {
475		if (Upolyd)
476		    You_cant("use two weapons in your current form.");
477		else
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));
491	} else if (uarms)
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]))) {
498		char kbuf[BUFSZ];
499
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));
503		instapetrify(kbuf);
504	} else if (Glib || uswapwep->cursed) {
505		if (!Glib)
506			uswapwep->bknown = TRUE;
507		drop_uswapwep();
508	} else
509		return (TRUE);
510	return (FALSE);
511}
512
513void
514drop_uswapwep()
515{
516	char str[BUFSZ];
517	struct obj *obj = uswapwep;
518
519	/* Avoid trashing makeplural's static buffer */
520	Strcpy(str, makeplural(body_part(HAND)));
521	Your("%s from your %s!",  aobjnam(obj, "slip"), str);
522	dropx(obj);
523}
524
525int
526dotwoweapon()
527{
528	/* You can always toggle it off */
529	if (u.twoweap) {
530		You("switch to your primary weapon.");
531		u.twoweap = 0;
532		update_inventory();
533		return (0);
534	}
535
536	/* May we use two weapons? */
537	if (can_twoweapon()) {
538		/* Success! */
539		You("begin two-weapon combat.");
540		u.twoweap = 1;
541		update_inventory();
542		return (rnd(20) > ACURR(A_DEX));
543	}
544	return (0);
545}
546
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.
552 */
553void
554uwepgone()
555{
556	if (uwep) {
557		if (artifact_light(uwep) && uwep->lamplit) {
558		    end_burn(uwep, FALSE);
559		    if (!Blind) pline("%s glowing.", Tobjnam(uwep, "stop"));
560		}
561		setworn((struct obj *)0, W_WEP);
562		unweapon = TRUE;
563		update_inventory();
564	}
565}
566
567void
568uswapwepgone()
569{
570	if (uswapwep) {
571		setworn((struct obj *)0, W_SWAPWEP);
572		update_inventory();
573	}
574}
575
576void
577uqwepgone()
578{
579	if (uquiver) {
580		setworn((struct obj *)0, W_QUIVER);
581		update_inventory();
582	}
583}
584
585void
586untwoweapon()
587{
588	if (u.twoweap) {
589		You("can no longer use two weapons at once.");
590		u.twoweap = FALSE;
591		update_inventory();
592	}
593	return;
594}
595
596/* Maybe rust object, or corrode it if acid damage is called for */
597void
598erode_obj(target, acid_dmg, fade_scrolls)
599struct obj *target;		/* object (e.g. weapon or armor) to erode */
600boolean acid_dmg;
601boolean fade_scrolls;
602{
603	int erosion;
604	struct monst *victim;
605	boolean vismon;
606	boolean visobj;
607
608	if (!target)
609	    return;
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 */
614
615	erosion = acid_dmg ? target->oeroded2 : target->oeroded;
616
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
621#ifdef MAIL
622	    && target->otyp != SCR_MAIL
623#endif
624					)
625	    {
626		if (!Blind) {
627		    if (victim == &youmonst)
628			Your("%s.", aobjnam(target, "fade"));
629		    else if (vismon)
630			pline("%s's %s.", Monnam(victim),
631			      aobjnam(target, "fade"));
632		    else if (visobj)
633			pline_The("%s.", aobjnam(target, "fade"));
634		}
635		target->otyp = SCR_BLANK_PAPER;
636		target->spe = 0;
637	    }
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"));
643		else if (vismon)
644		    pline("%s's %s not affected.", Monnam(victim),
645			aobjnam(target, "are"));
646		/* no message if not carried */
647	    }
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" : "");
654	    else if (vismon)
655		pline("%s's %s%s!", Monnam(victim),
656		    aobjnam(target, acid_dmg ? "corrode" : "rust"),
657		    erosion+1 == MAX_ERODE ? " completely" :
658		    erosion ? " further" : "");
659	    else if (visobj)
660		pline_The("%s%s!",
661		    aobjnam(target, acid_dmg ? "corrode" : "rust"),
662		    erosion+1 == MAX_ERODE ? " completely" :
663		    erosion ? " further" : "");
664	    if (acid_dmg)
665		target->oeroded2++;
666	    else
667		target->oeroded++;
668	} else {
669	    if (flags.verbose) {
670		if (victim == &youmonst)
671		    Your("%s completely %s.",
672			aobjnam(target, Blind ? "feel" : "look"),
673			acid_dmg ? "corroded" : "rusty");
674		else if (vismon)
675		    pline("%s's %s completely %s.", Monnam(victim),
676			aobjnam(target, "look"),
677			acid_dmg ? "corroded" : "rusty");
678		else if (visobj)
679		    pline_The("%s completely %s.",
680			aobjnam(target, "look"),
681			acid_dmg ? "corroded" : "rusty");
682	    }
683	}
684}
685
686int
687chwepon(otmp, amount)
688register struct obj *otmp;
689register int amount;
690{
691	const char *color = hcolor((amount < 0) ? NH_BLACK : NH_BLUE);
692	const char *xtime;
693	int otyp = STRANGE_OBJECT;
694
695	if(!uwep || (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))) {
696		char buf[BUFSZ];
697
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));
702		return(0);
703	}
704
705	if (otmp && otmp->oclass == SCROLL_CLASS) otyp = otmp->otyp;
706
707	if(uwep->otyp == WORM_TOOTH && amount >= 0) {
708		uwep->otyp = CRYSKNIFE;
709		uwep->oerodeproof = 0;
710		Your("weapon seems sharper now.");
711		uwep->cursed = 0;
712		if (otyp != STRANGE_OBJECT) makeknown(otyp);
713		return(1);
714	}
715
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);
721		return(1);
722	}
723
724	if (amount < 0 && uwep->oartifact && restrict_name(uwep, ONAME(uwep))) {
725	    if (!Blind)
726		Your("%s %s.", aobjnam(uwep, "faintly glow"), color);
727	    return(1);
728	}
729	/* there is a (soft) upper and lower limit to uwep->spe */
730	if(((uwep->spe > 5 && amount >= 0) || (uwep->spe < -5 && amount < 0))
731								&& rn2(3)) {
732	    if (!Blind)
733	    Your("%s %s for a while and then %s.",
734		 aobjnam(uwep, "violently glow"), color,
735		 otense(uwep, "evaporate"));
736	    else
737		Your("%s.", aobjnam(uwep, "evaporate"));
738
739	    useupall(uwep);	/* let all of them disappear */
740	    return(1);
741	}
742	if (!Blind) {
743	    xtime = (amount*amount == 1) ? "moment" : "while";
744	    Your("%s %s for a %s.",
745		 aobjnam(uwep, amount == 0 ? "violently glow" : "glow"),
746		 color, xtime);
747	    if (otyp != STRANGE_OBJECT && uwep->known &&
748		    (amount > 0 || (amount < 0 && otmp->bknown)))
749		makeknown(otyp);
750	}
751	uwep->spe += amount;
752	if(amount > 0) uwep->cursed = 0;
753
754	/*
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.
758	 */
759	if (uwep->oartifact == ART_MAGICBANE && uwep->spe >= 0) {
760		Your("right %s %sches!",
761			body_part(HAND),
762			(((amount > 1) && (uwep->spe > 1)) ? "flin" : "it"));
763	}
764
765	/* an elven magic clue, cookie@keebler */
766	/* elven weapons vibrate warningly when enchanted beyond a limit */
767	if ((uwep->spe > 5)
768		&& (is_elven_weapon(uwep) || uwep->oartifact || !rn2(7)))
769	    Your("%s unexpectedly.",
770		aobjnam(uwep, "suddenly vibrate"));
771
772	return(1);
773}
774
775int
776welded(obj)
777register struct obj *obj;
778{
779	if (obj && obj == uwep && will_weld(obj)) {
780		obj->bknown = TRUE;
781		return 1;
782	}
783	return 0;
784}
785
786void
787weldmsg(obj)
788register struct obj *obj;
789{
790	long savewornmask;
791
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))
796				: body_part(HAND));
797	obj->owornmask = savewornmask;
798}
799
800/*wield.c*/
801