/*      SCCS Id: @(#)wield.c    3.2     96/07/04        */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"

/* KMH -- Differences between the three weapon slots.
 *
 * The main weapon (uwep):
 * 1.  Is filled by the (w)ield command.
 * 2.  Can be filled with any type of item.
 * 3.  May be carried in one or both hands.
 * 4.  Is used as the melee weapon and as the launcher for
 *     ammunition.
 * 5.  Only conveys intrinsics when it is a weapon, weapon-tool,
 *     or artifact.
 * 6.  Certain cursed items will weld to the hand and cannot be
 *     unwielded or dropped.  See erodeable_wep() and will_weld()
 *     below for the list of which items apply.
 *
 * The secondary weapon (uswapwep):
 * 1.  Is filled by the e(x)change command, which swaps this slot
 *     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
 *     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,
 *     second weapon, shield, gloves, and rings; and it would
 *     further be complicated by bimanual weapons.  A special
 *     exception is made for two-weapon combat.
 * 4.  Is used as the second weapon for two-weapon combat, and as
 *     a convenience to swap with the main weapon.
 * 5.  Never conveys intrinsics.
 * 6.  Cursed items never weld (see #3 for reasons), but they also
 *     prevent two-weapon combat.
 *
 * The quiver (uquiver):
 * 1.  Is filled by the (Q)uiver command.
 * 2.  Can be filled with any type of item.
 * 3.  Is considered to be carried in a special part of the pack.
 * 4.  Is used as the item to throw with the (f)ire command.
 *     This is a convenience over the normal (t)hrow command.
 * 5.  Never conveys intrinsics.
 * 6.  Cursed items never weld; their effect is handled by the normal
 *     throwing code.
 *
 * No item may be in more than one of these slots.
 */


static int FDECL(ready_weapon, (struct obj *));


/* elven weapons vibrate warningly when enchanted beyond a limit */
#define is_elven_weapon(optr)   ((optr)->otyp == ELVEN_ARROW\
				|| (optr)->otyp == ELVEN_SPEAR\
				|| (optr)->otyp == ELVEN_DAGGER\
				|| (optr)->otyp == ELVEN_SHORT_SWORD\
				|| (optr)->otyp == ELVEN_BROADSWORD\
				|| (optr)->otyp == ELVEN_BOW)

/* used by erode_weapon() and will_weld() */
#define erodeable_wep(optr)   ((optr)->oclass == WEAPON_CLASS \
                                || is_weptool(optr) \
                                || (optr)->otyp == HEAVY_IRON_BALL \
                                || (optr)->otyp == IRON_CHAIN)
  
/* used by welded(), and also while wielding */
#define will_weld(optr)         ((optr)->cursed \
                                && (erodeable_wep(optr) \
                                || (optr)->otyp == TIN_OPENER))


/* KMH -- Functions to directly set a slot.
 * Proper usage includes:
 * 1.  Initializing the slot during character generation or a
 *     restore.
 * 2.  Setting the slot due to a player's actions.
 * 3.  If one of the objects in the slot are split off, these
 *     functions can be used to put the remainder back in the slot.
 * 4.  Putting an item that was thrown and returned back into the slot.
 * 5.  Emptying the slot, by passing a null object.  NEVER pass
 *     zeroobj!
 *
 * Note: setuwep() with a null obj, and uwepgone(), are NOT the same!
 * Sometimes unwielding a weapon can kill you, and lifesaving will then
 * put it back into your hand.  If lifesaving is permitted to do this,
 * use setwuep((struct obj *)0); otherwise use uwepgone().
 *
 * If the item is being moved from another slot, it is the caller's
 * responsibility to handle that.  It's also the caller's responsibility
 * to print the appropriate messages.
 */
void
setuwep(obj)
register struct obj *obj;
{
	if (obj == uwep) return; /* necessary to not set unweapon */
	setworn(obj, W_WEP);
	/* Note: Explicitly wielding a pick-axe will not give a "bashing"
	 * message.  Wielding one via 'a'pplying it will.
	 * 3.2.2:  Wielding arbitrary objects will give bashing message too.
	 */
	if (obj) {
		/* KMH, balance patch -- new macros */
		/* WAC -- polearms "bash" if used as melee */
		unweapon = (obj->oclass == WEAPON_CLASS) ?
				is_launcher(obj) || is_ammo(obj) ||
				is_missile(obj) || is_pole(obj) :
				!is_weptool(obj);
	} else
		unweapon = TRUE;        /* for "bare hands" message */
	update_inventory();
}

/* [Tom]'s quiver */
void
setuqwep(obj)
register struct obj *obj;
{
	setworn(obj, W_QUIVER);
	update_inventory();
}

void
setuswapwep(obj)
register struct obj *obj;
{
	setworn(obj, W_SWAPWEP);
	update_inventory();
}


/* KMH -- Rewrote commands to change slot(s).
 */

static NEARDATA const char wield_objs[] =
	{ ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, TOOL_CLASS, 0 };


static
int
ready_weapon(struct obj *wep)
{
	/* [Tom] separated function so swapping works easily */
	register int res = 0;


	if (!wep) {
		/* No weapon */
		if (uwep) {
			You("are empty %s.", body_part(HANDED));
			setuwep((struct obj *) 0);
			res++;
		} else
		You("are already empty %s.", body_part(HANDED));
	/* Prevent wielding cockatrice when not wearing gloves --KAA */
	/* KMH, balance patch -- new intrinsic */
	} else if (!uarmg && !Stone_resistance && (wep->otyp == CORPSE &&                   
                  (touch_petrifies(&mons[wep->corpsenm])))) {
            char kbuf[BUFSZ];

            You("wield the %s corpse in your bare %s.",
                mons[wep->corpsenm].mname, makeplural(body_part(HAND)));
            Sprintf(kbuf, "%s corpse", mons[wep->corpsenm].mname);            
            instapetrify(kbuf);
	} else if (uarms && bimanual(wep))
	    You("cannot wield a two-handed %s while wearing a shield.",
		is_sword(wep) ? "sword" :
		    wep->otyp == BATTLE_AXE ? "axe" : "weapon");
	else if (wep->oartifact && !touch_artifact(wep, &youmonst)) {
		res++;      /* takes a turn even though it doesn't get wielded */
	} else if (tech_inuse(T_EVISCERATE) > 1) {
		/* WAC - if you have 'L' has claws out and wields weapon,
		 * can't retract claws
		 */
		You("can't retract your claws!");
	} else {
		/* Weapon WILL be wielded after this point */
		if (wep->otyp == LIGHTSABER) {
			You("feel the power of the Force flowing through you.");
			if (u.ualign.type != A_LAWFUL) {
			pline("It overwhelms you!");
			losehp(rnd(15), "the Force", KILLED_BY);
			exercise(A_WIS, FALSE);
		}
# ifdef D_SABER
       } else if (wep->otyp == DIMSABER) {
         You("feel the Force balancing your soul.");
         if (u.ualign.type != A_NEUTRAL) {
               pline("You catch your breath!");
               losehp(rnd(15), "beholding the balance of the Force", KILLED_BY);
	       		exercise(A_WIS, FALSE);
	    		}
# endif /* D_SABER */
	    } else if (wep->otyp == DARKSABER) {
	    	You("feel the power of the Dark Side of the Force.");
	    	if (u.ualign.type != A_CHAOTIC) {
	       		pline("You shudder...");
	       		losehp(rnd(15), "the Dark Side of the Force", KILLED_BY);
	       		exercise(A_WIS, FALSE);
	    	}
	   }
	   if (will_weld(wep)) {
		const char *tmp = xname(wep), *thestr = "The ";
		if (strncmp(tmp, thestr, 4) && !strncmp(The(tmp),thestr,4))
		    tmp = thestr; else tmp = "";
		pline("%s%s %s to your %s!",tmp, aobjnam(wep, "weld"),
		      (wep->quan == 1L) ? "itself" : "themselves", /* a3 */
		      body_part(HAND));
		wep->bknown = TRUE;
	   } else {
			/* The message must be printed before setuwep (since
			 * you might die and be revived from changing weapons),
			 * and the message must be before the death message and
			 * Lifesaved rewielding.  Yet we want the message to
			 * say "weapon in hand", thus this kludge.
			 */
			long dummy = wep->owornmask;
			wep->owornmask |= W_WEP;
			prinv((char *)0, wep, 0L);
			wep->owornmask = dummy;
	    }
	    setuwep(wep);

		/* KMH, balance patch -- Talking artifacts are finally implemented */
		arti_speak(wep);

	    if (wep->unpaid) {
			struct monst *this_shkp;

			if ((this_shkp = shop_keeper(inside_shop(u.ux, u.uy))) !=
			    (struct monst *)0) {
			    pline("%s says \"You be careful with my %s!\"",
				  shkname(this_shkp),
				  xname(wep));
			}
	    }
	}

	/* Take no time if we are dextrous enough */
	return ((rnd(20) > ACURR(A_DEX)) ? res : 0);
}


int
dowield()
{
	register struct obj *newwep;


	/* May we attempt this? */
	multi = 0;
	if (cantwield(uasmon)) {
		pline("Don't be ridiculous!");
		return(0);
	}

	/* Prompt for a new weapon */
	if (!(newwep = getobj(wield_objs, "wield")))
		/* Cancelled */
		return (0);
	if (welded(uwep)) {
		weldmsg(uwep);
		return (0);
	}

	/* Handle no object, or object in other slot */
	if (newwep == &zeroobj)
		newwep = (struct obj *) 0;
	else if (newwep == uwep) {
	    You("are already wielding that!");
	    if (is_weptool(newwep)) unweapon = FALSE;	/* [see setuwep()] */
		return (0);
	} else if (newwep == uswapwep)
		return (doswapweapon());
	else if (newwep == uquiver)
		setuqwep((struct obj *) 0);
	else if (newwep->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
		You("cannot wield that!");
		return (0);
	}

	/* Set your new primary weapon */
#ifdef WEAPON_SKILLS
	if (u.twoweap && !can_twoweapon())
		untwoweapon();
#endif
	if (flags.pushweapon && uwep)
		setuswapwep(uwep);
	return (ready_weapon(newwep));
}


int doswapweapon()
{
	register struct obj *oldwep, *oldswap;
	int result = 0;


	/* May we attempt this? */
	multi = 0;
	if (cantwield(uasmon)) {
		pline("Don't be ridiculous!");
		return(0);
	}
	if (welded(uwep)) {
		weldmsg(uwep);
		return (0);
	}

	/* Unwield your current secondary weapon */
	oldwep = uwep;
	oldswap = uswapwep;
	setuswapwep((struct obj *) 0);

	/* Set your new primary weapon */
	result = ready_weapon(oldswap);

	/* Set your new secondary weapon */
	if (uwep == oldwep)
		/* Wield failed for some reason */
		setuswapwep(oldswap);
	else {
		setuswapwep(oldwep);
		if (uswapwep)
			prinv((char *)0, uswapwep, 0L);
		else
			You("have no secondary weapon readied.");
	}

#ifdef WEAPON_SKILLS
	if (u.twoweap && !can_twoweapon())
		untwoweapon();
#endif

	/* If you're a klutz, you will still take some time to swap */
	return (result);
}


int
dowieldquiver()
{
	register struct obj *newquiver;


	/* Since the quiver isn't in your hands, don't check cantwield(), */
	/* will_weld(), touch_petrifies(), etc. */
	multi = 0;

	/* Prompt for a new quiver */
	if (!(newquiver = getobj(wield_objs, "ready")))
		/* Cancelled */
		return (0);

	/* Handle no object, or object in other slot */
	/* We used to reject armor, but now we give no intrinsics anyways */
	if (newquiver == &zeroobj) {
		/* Explicitly nothing */
		if (uquiver) {
			pline("You now have no ammunition readied.");
			setuqwep(newquiver = (struct obj *) 0);
		} else {
			pline("You already have no ammunition readied!");
			return(0);
		}
	} else if (newquiver == uquiver) {
		pline("That ammunition is already readied!");
		return(0);
	} else if (newquiver == uwep) {
		/* Prevent accidentally readying the main weapon */
		pline("That ammunition is being used as a weapon!");
		return(0);
	} else if (newquiver->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
		You("cannot ready that!");
		return (0);
	} else {
		long dummy;


		/* Check if it's the secondary weapon */
		if (newquiver == uswapwep) {
			setuswapwep((struct obj *) 0);
#ifdef WEAPON_SKILLS
			untwoweapon();
#endif
		}

		/* Okay to put in quiver; print it */
		dummy = newquiver->owornmask;
		newquiver->owornmask |= W_QUIVER;
		prinv(NULL, newquiver, 0L);
		newquiver->owornmask = dummy;
	}

	/* Finally, place it in the quiver */
	setuqwep(newquiver);
	/* Take no time if we are dextrous enough */
	return (rnd(20) > ACURR(A_DEX));
}


#ifdef WEAPON_SKILLS

int can_twoweapon ()
{
	if (Upolyd)
		You("can only use two weapons in your normal form.");
/*	else if (!uwep || uwep->oclass != WEAPON_CLASS || bimanual(uwep))*/
	else if (uwep && bimanual(uwep))
		You("aren't wielding a one-handed weapon.");
/*	else if (!uswapwep || uswapwep->oclass != WEAPON_CLASS ||
			bimanual(uswapwep))*/
	else if (uswapwep && bimanual(uswapwep))
		You("aren't carrying a one-handed weapon as your secondary weapon.");
        /* WAC:  FIXME:  secondary weapon artifacts are problematic ... */
        else if (uswapwep->oartifact /* && !touch_artifact(uswapwep, &youmonst) */)
		You("cannot start two weapon combat.");
	else if (uarms)
		You("can't use two weapons while carrying a shield.");
	else if (!uarmg && !Stone_resistance && (uswapwep->otyp == CORPSE &&                   
                  (touch_petrifies(&mons[uswapwep->corpsenm])))) {
		char kbuf[BUFSZ];

		You("wield the %s corpse with your bare %s.",
		    mons[uswapwep->corpsenm].mname, body_part(HAND));
		Sprintf(kbuf, "%s corpse", mons[uswapwep->corpsenm].mname);            
		instapetrify(kbuf);
	} else if (Glib || uswapwep->cursed) {
		struct obj *obj = uswapwep;

		Your("%s from your %s!",  aobjnam(obj, "slip"),
				makeplural(body_part(HAND)));
		if (!Glib)
			obj->bknown = TRUE;
		setuswapwep((struct obj *) 0);
		dropx(obj);
	} else
		return (TRUE);
	return (FALSE);
}


int
dotwoweapon()
{
	/* You can always toggle it off */
	if (u.twoweap) {
		You("switch to your primary weapon.");
		u.twoweap = 0;
		return (0);
	}

	/* May we use two weapons? */
	if (can_twoweapon()) {
		/* Success! */
		You("begin two-weapon combat.");
		u.twoweap = 1;
		return (rnd(20) > ACURR(A_DEX));
	}
	return (0);
}

#endif	/* WEAPON_SKILLS */


/* KMH -- Functions to empty a given slot.
 * These should be used only when the item can't be put back in
 * the slot by life saving.  Proper usage includes:
 * 1.  The item has been eaten, stolen, burned away, or rotted away.
 * 2.  Making an item disappear for a bones pile.
 */
void
uwepgone()
{
	if (uwep) {
		setworn((struct obj *)0, W_WEP);
		unweapon = TRUE;
		update_inventory();
	}
}

void
uswapwepgone()
{
	if (uswapwep) {
		setworn((struct obj *)0, W_SWAPWEP);
		update_inventory();
	}
}

void
uqwepgone()
{
	if (uquiver) {
		setworn((struct obj *)0, W_QUIVER);
		update_inventory();
	}
}

#ifdef WEAPON_SKILLS
void
untwoweapon()
{
	if (u.twoweap) {
		You("can no longer use two weapons at once.");
		u.twoweap = FALSE;
/*		if (uwep) {
			long dummy = uwep->owornmask;
			uwep->owornmask |= W_WEP;
			prinv((char *)0, uwep, 0L);
			uwep->owornmask = dummy;
		} else
			You("are empty %s.", body_part(HANDED));*/
	}
	return;
}
#endif	/* WEAPON_SKILLS */


/* maybe rust weapon, or corrode it if acid damage is called for */
void
erode_weapon(acid_dmg)
boolean acid_dmg;
{
	if (!uwep || !erodeable_wep(uwep))
		return;

  	if (uwep->greased) {
  		grease_protect(uwep,(char *)0,FALSE);
  	/* KMH -- Acid has small chance of dissolving erosionproofing */
  	} else if (acid_dmg && uwep->oerodeproof && !rn2(20)) {
  		if (uwep->rknown)
			pline("%s %s golden shield.",  Yname2(uwep),
                  (uwep->quan > 1L) ? "lose their" : "loses its");
		uwep->oerodeproof = FALSE;
	} else if (uwep->oerodeproof ||
                    (acid_dmg ? !is_corrodeable(uwep) : !is_rustprone(uwep))) {
		if (flags.verbose || !(uwep->oerodeproof && uwep->rknown))
		    Your("%s not affected.", aobjnam(uwep, "are"));
		if (uwep->oerodeproof) uwep->rknown = TRUE;
	} else if (uwep->oeroded < MAX_ERODE) {
		Your("%s%s!", aobjnam(uwep, acid_dmg ? "corrode" : "rust"),
		     uwep->oeroded+1 == MAX_ERODE ? " completely" :
		     uwep->oeroded ? " further" : "");
		uwep->oeroded++;
	} else {
		if (flags.verbose)
		    Your("%s completely %s.",
			 aobjnam(uwep, Blind ? "feel" : "look"),
			 acid_dmg ? "corroded" : "rusty");
	}
}

int
chwepon(otmp, amount)
register struct obj *otmp;
register int amount;
{
	register const char *color = hcolor((amount < 0) ? Black : blue);
	register const char *xtime;

	if(!uwep || (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))) {
		char buf[BUFSZ];

		Sprintf(buf, "Your %s %s.", makeplural(body_part(HAND)),
			(amount >= 0) ? "twitch" : "itch");
		strange_feeling(otmp, buf);
		exercise(A_DEX, (boolean) (amount >= 0));
		return(0);
	}

	if(uwep->otyp == WORM_TOOTH && amount >= 0) {
		uwep->otyp = CRYSKNIFE;
		Your("weapon seems sharper now.");
		uwep->cursed = 0;
		return(1);
	}

	if(uwep->otyp == CRYSKNIFE && amount < 0) {
		uwep->otyp = WORM_TOOTH;
		Your("weapon seems duller now.");
		return(1);
	}

	if (amount < 0 && uwep->oartifact && restrict_name(uwep, ONAME(uwep))) {
	    if (!Blind)
		Your("%s %s.", aobjnam(uwep, "faintly glow"), color);
	    return(1);
	}
	/* there is a (soft) upper and lower limit to uwep->spe */
	if(((uwep->spe > 5 && amount >= 0) || (uwep->spe < -5 && amount < 0))
								&& rn2(3)) {
	    if (!Blind)
	    Your("%s %s for a while and then evaporate%s.",
		 aobjnam(uwep, "violently glow"), color,
		 uwep->quan == 1L ? "s" : "");
	    else
		Your("%s.", aobjnam(uwep, "evaporate"));

	    while(uwep)         /* let all of them disappear */
				/* note: uwep->quan = 1 is nogood if unpaid */
		useup(uwep);
	    return(1);
	}
	if (!Blind) {
	    xtime = (amount*amount == 1) ? "moment" : "while";
	    Your("%s %s for a %s.",
		 aobjnam(uwep, amount == 0 ? "violently glow" : "glow"),
		 color, xtime);
	}
	uwep->spe += amount;
	if(amount > 0) uwep->cursed = 0;

	/*
	 * Enchantment, which normally improves a weapon, has an
	 * addition adverse reaction on Magicbane whose effects are
	 * spe dependent.  Give an obscure clue here.
	 */
	if (uwep->oartifact == ART_MAGICBANE && uwep->spe >= 0) {
		Your("right %s %sches!",
			body_part(HAND),
			(((amount > 1) && (uwep->spe > 1)) ? "flin" : "it"));
	}

	/* an elven magic clue, cookie@keebler */
	if ((uwep->spe > 3)
		&& (is_elven_weapon(uwep) || uwep->oartifact || !rn2(7)))
	    Your("%s unexpectedly.",
		aobjnam(uwep, "suddenly vibrate"));

	return(1);
}

int
welded(obj)
register struct obj *obj;
{
	if (obj && obj == uwep && will_weld(obj)) {
		obj->bknown = TRUE;
		return 1;
	}
	return 0;
}

void
weldmsg(obj)
register struct obj *obj;
{
        long savewornmask;

        savewornmask = obj->owornmask;
        Your("%s %s welded to your %s!",
                xname(obj), (obj->quan == 1L) ? "is" : "are",
  		bimanual(obj) ? (const char *)makeplural(body_part(HAND))
  				: body_part(HAND));
        obj->owornmask = savewornmask;
}

/*wield.c*/
