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

/*
 *      This module contains code for calculation of "to hit" and damage
 *      bonuses for any given weapon used, as well as weapons selection
 *      code for monsters.
 */
#include "hack.h"


#ifdef WEAPON_SKILLS

static void FDECL(give_may_advance_msg, (int));
STATIC_PTR int NDECL(practice);
static int FDECL(get_obj_skill, (struct obj *));
static void FDECL(mon_ignite_lightsaber, (struct obj *, struct monst *));

/*WAC practicing needs a delay counter*/
static NEARDATA schar delay;            /* moves left for practice */
static NEARDATA boolean speed_advance = FALSE;

#ifndef OVLB

STATIC_DCL NEARDATA const short skill_names_indices[];
STATIC_DCL NEARDATA const char *odd_skill_names[];

#else   /* OVLB */

/* categories whose names don't come from OBJ_NAME(objects[type]) */
#define PN_POLEARMS			(-1)
#define PN_SABER			(-2)
#define PN_HAMMER			(-3)
#define PN_WHIP				(-4)
#define PN_PADDLE			(-5)
#define PN_FIREARMS			(-6)
#define PN_ATTACK_SPELL		(-7)
#define PN_HEALING_SPELL	(-8)
#define PN_DIVINATION_SPELL	(-9)
#define PN_ENCHANTMENT_SPELL	(-10)
#define PN_PROTECTION_SPELL	(-11)
#define PN_BODY_SPELL		(-12)
#define PN_MATTER_SPELL		(-13)
#define PN_BARE_HANDED		(-14)
#define PN_MARTIAL_ARTS		(-15)
#define PN_RIDING		(-16)
#define PN_TWO_WEAPONS		(-17)
#define PN_LIGHTSABER		(-18)

/* KMH, balance patch -- updated */
STATIC_OVL NEARDATA const short skill_names_indices[P_NUM_SKILLS] = {
	0,                DAGGER,         KNIFE,          AXE,
	PICK_AXE,         SHORT_SWORD,    BROADSWORD,     LONG_SWORD,
	TWO_HANDED_SWORD, SCIMITAR,       PN_SABER,       CLUB,
	PN_PADDLE,        MACE,           MORNING_STAR,   FLAIL,
	PN_HAMMER,        QUARTERSTAFF,   PN_POLEARMS,    SPEAR,
	JAVELIN,          TRIDENT,        LANCE,          BOW,
	SLING,            PN_FIREARMS,    CROSSBOW,       DART,
	SHURIKEN,         BOOMERANG,      PN_WHIP,        UNICORN_HORN,
	PN_LIGHTSABER,
	PN_ATTACK_SPELL,                PN_HEALING_SPELL,
	PN_DIVINATION_SPELL,            PN_ENCHANTMENT_SPELL,
	PN_PROTECTION_SPELL,            PN_BODY_SPELL,
	PN_MATTER_SPELL,
	PN_BARE_HANDED, 		PN_MARTIAL_ARTS, 
	PN_RIDING, 			PN_TWO_WEAPONS
};


STATIC_OVL NEARDATA const char *odd_skill_names[] = {
	"no skill",
	"polearms",
	"saber",
	"hammer",
	"whip",
	"paddle",
	"firearms",
	"attack spells",
	"healing spells",
	"divination spells",
	"enchantment spells",
	"protection spells",
	"body spells",
	"matter spells",
	"bare-handed combat",
	"martial arts",
	"riding",
	"two-weapon combat",
	"lightsaber"
};


static
void give_may_advance_msg(skill)
int skill;
{
    You("feel more %s in your %sskills.",
	    !P_RESTRICTED(skill) ? "confident" : "comfortable",
            skill == P_NONE  ?
                    "" :
            skill <= P_LAST_WEAPON ?
                    "weapon " :
            skill <= P_LAST_SPELL ?
                    "spell casting " :
            skill <= P_LAST_H_TO_H ?
	            "fighting ":
	            "");
}


#endif  /* OVLB */

STATIC_DCL boolean FDECL(can_advance, (int));
/* WAC for Practicing */
STATIC_DCL boolean FDECL(can_practice, (int));

#ifdef OVL1

static char *FDECL(skill_level_name, (int,char *));
static int FDECL(slots_required, (int));
static void FDECL(skill_advance, (int));

#endif  /* OVL1 */

#define P_NAME(type) (skill_names_indices[type] > 0 ? \
                      OBJ_NAME(objects[skill_names_indices[type]]) : \
                      odd_skill_names[-skill_names_indices[type]])
/*                      OBJ_NAME(objects[skill_names_indices[type]]) : \
                      (type == P_BARE_HANDED_COMBAT ? \
			(martial_bonus() ? odd_skill_names[-PN_MARTIAL_ARTS] \
					 : odd_skill_names[-PN_BARE_HANDED]) : \
		      odd_skill_names[-skill_names_indices[type]]))
*/
#endif /* WEAPON_SKILLS */

#ifdef OVLB

static NEARDATA const char kebabable[] = {
	S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0'
};

/*
 *      hitval returns an integer representing the "to hit" bonuses
 *      of "otmp" against the monster.
 */
int
hitval(otmp, mon)
struct obj *otmp;
struct monst *mon;
{
	int     tmp = 0;
	struct permonst *ptr = mon->data;
	boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));

	if (Is_weapon)
		tmp += otmp->spe;

/*      Put weapon specific "to hit" bonuses in below:          */
	tmp += objects[otmp->otyp].oc_hitbon;
#ifdef WEAPON_SKILLS
	tmp += weapon_hit_bonus(otmp);  /* weapon skill */
	if (u.twoweap)
		tmp += (skill_bonus(P_TWO_WEAPON_COMBAT) * 2) - 5;
#endif /* WEAPON_SKILLS */

/*      Put weapon vs. monster type "to hit" bonuses in below:  */

	/* Blessed weapons used against undead or demons */
	if (Is_weapon && otmp->blessed &&
	   (is_demon(ptr) || is_undead(ptr))) tmp += 2;

	/* KMH, balance patch -- new macro */
	if (is_spear(otmp) && index(kebabable, ptr->mlet)) tmp += 2;

	/* KMH -- Paddles are effective against insects */
	if (Is_weapon && (objects[otmp->otyp].oc_skill == P_PADDLE) &&
			(ptr->mlet == S_ANT || ptr->mlet == S_SPIDER || ptr->mlet == S_XAN))
		tmp += 2;
	
	/* trident is highly effective against swimmers */
	if (otmp->otyp == TRIDENT && is_swimmer(ptr)) {
	   if (is_pool(mon->mx, mon->my)) tmp += 4;
	   else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE) tmp += 2;
	}

	/* pick-axe used against xorns and earth elementals */
	/* WAC made generic against "rock people" */
	/* KMH, balance patch -- allow all picks */
	if (is_pick(otmp) &&
/*           (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2;*/
           (made_of_rock(ptr))) tmp += 2;


#ifdef INVISIBLE_OBJECTS
	/* invisible weapons against monsters who can't see invisible */
	if (otmp->oinvis && !perceives(ptr)) tmp += 3;
#endif

	/* Check specially named weapon "to hit" bonuses */
	if (otmp->oartifact) tmp += spec_abon(otmp, mon);

	return tmp;
}

/*
 *      dmgval returns an integer representing the damage bonuses
 *      of "otmp" against the monster.
 */
int
dmgval(otmp, mon)
struct obj *otmp;
struct monst *mon;
{
	int tmp = 0, otyp = otmp->otyp;
	struct permonst *ptr = mon->data;
	boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));

	if (otyp == CREAM_PIE) return 0;

# ifdef P_SPOON
	if (otmp->oartifact == ART_HOUCHOU)
	        return 9999;
# endif /* P_SPOON */

	if (bigmonst(ptr)) {
	    if (objects[otyp].oc_wldam)
			tmp = rnd(objects[otyp].oc_wldam);
	    switch (otyp) {
		case IRON_CHAIN:
		case CROSSBOW_BOLT:
		case MORNING_STAR:
		case PARTISAN:
		case RUNESWORD:
		case ELVEN_BROADSWORD:
		case BROADSWORD:        tmp++; break;

		case FLAIL:
		case RANSEUR:
		case VOULGE:            tmp += rnd(4); break;

		case ACID_VENOM:
		case HALBERD:
		case SPETUM:            tmp += rnd(6); break;

		case BATTLE_AXE:
		case BARDICHE:
		case TRIDENT:           tmp += d(2,4); break;

		case TSURUGI:
		case DWARVISH_MATTOCK:
		case TWO_HANDED_SWORD:  tmp += d(2,6); break;

		case GREEN_LIGHTSABER:  tmp +=13; break;
		case BLUE_LIGHTSABER:   tmp +=12; break;
		case RED_DOUBLE_LIGHTSABER: 
			if (otmp->altmode) tmp += rnd(11);
			/* fallthrough */
		case RED_LIGHTSABER:    tmp +=10; break;
	    }
	} else {
	    if (objects[otyp].oc_wsdam)
		tmp = rnd(objects[otyp].oc_wsdam);
	    switch (otyp) {
		case IRON_CHAIN:
		case CROSSBOW_BOLT:
		case MACE:
		case WAR_HAMMER:
		case FLAIL:
		case SPETUM:
		case TRIDENT:           tmp++; break;

		case BATTLE_AXE:
		case BARDICHE:
		case BILL_GUISARME:
		case GUISARME:
		case LUCERN_HAMMER:
		case MORNING_STAR:
		case RANSEUR:
		case BROADSWORD:
		case ELVEN_BROADSWORD:
		case RUNESWORD:
		case VOULGE:            tmp += rnd(4); break;

		case GREEN_LIGHTSABER:  tmp +=9; break;
		case BLUE_LIGHTSABER:   tmp +=8; break;
		case RED_DOUBLE_LIGHTSABER:
			if (otmp->altmode) tmp += rnd(9);
			/* fallthrough */
		case RED_LIGHTSABER: 	tmp +=6; break;

		case ACID_VENOM:        tmp += rnd(6); break;
	    }
	}
	if (Is_weapon) {
		tmp += otmp->spe;
		/* negative enchantment mustn't produce negative damage */
		if (tmp < 0) tmp = 0;
	}

	if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr))
		/* thick skinned/scaled creatures don't feel it */
		tmp = 0;
	if (ptr == &mons[PM_SHADE] && objects[otyp].oc_material != SILVER)
		tmp = 0;

	/* "very heavy iron ball"; weight increase is in increments of 160 */
	if (otyp == HEAVY_IRON_BALL && tmp > 0) {
	    int wt = (int)objects[HEAVY_IRON_BALL].oc_weight;

	    if ((int)otmp->owt > wt) {
	        wt = ((int)otmp->owt - wt) / 160;
	        tmp += rnd(4 * wt);
	        if (tmp > 25) tmp = 25; /* objects[].oc_wldam */
	    }
	}
  
/*      Put weapon vs. monster type damage bonuses in below:    */
	if (Is_weapon || otmp->oclass == GEM_CLASS ||
	        otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) {
	    int bonus = 0;

#ifdef YEOMAN
		/* KMH -- Lances are especially made for riding */
		if (otmp == uwep && u.usteed &&
				objects[otmp->otyp].oc_skill == P_LANCE)
			bonus += d(2,10);
#endif

	    if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
			bonus += rnd(4);
	    if ((otyp == AXE || otyp == BATTLE_AXE) && is_wooden(ptr))
			bonus += rnd(4);
	    if (objects[otyp].oc_material == SILVER && hates_silver(ptr))
			bonus += rnd(20);

	    /* if the weapon is going to get a double damage bonus, adjust
	       this bonus so that effectively it's added after the doubling */
	    if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25)
		bonus = (bonus + 1) / 2;

	    tmp += bonus;
	}

	if (tmp > 0) {
                /* It's debateable whether a rusted blunt instrument
                   should do less damage than a pristine one, since
                   it will hit with essentially the same impact, but
                   there ought to some penalty for using damaged gear
                   so always subtract erosion even for blunt weapons. */
		tmp -= otmp->oeroded;
		if (tmp < 1) tmp = 1;
	}

	return(tmp);
}

#endif /* OVLB */
#ifdef OVL0

static struct obj *FDECL(oselect, (struct monst *,int));
#define Oselect(x)      if ((otmp = oselect(mtmp, x)) != 0) return(otmp);

static struct obj *
oselect(mtmp, x)
struct monst *mtmp;
int x;
{
	struct obj *otmp;

	for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
	    if (otmp->otyp == x &&
		    /* never select non-cockatrice corpses */
                    !(x == CORPSE && !touch_petrifies(&mons[otmp->corpsenm])) &&
                    (!is_lightsaber(otmp) || otmp->age) &&
		    (!otmp->oartifact || touch_artifact(otmp,mtmp)))
		return otmp;
	}
	return (struct obj *)0;
}


/* WAC added the Ya, increased priority of silver dagger, added Spoon */
/* KMH -- added bullets */
static NEARDATA const int rwep[] =
{	
#ifdef SPOON
	SPOON,
#endif
#ifdef FIREARMS
	SILVER_BULLET, BULLET,
#endif
	DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, SILVER_SPEAR,
	JAVELIN, SHURIKEN, SILVER_ARROW, ELVEN_ARROW,
	DARK_ELVEN_ARROW, YA, ARROW, ORCISH_ARROW,
	CROSSBOW_BOLT, ELVEN_DAGGER, DARK_ELVEN_DAGGER, SILVER_DAGGER,
	DAGGER, ORCISH_DAGGER, KNIFE, ROCK, LOADSTONE, LUCKSTONE, DART,
	/* BOOMERANG, */ CREAM_PIE
	/* note: CREAM_PIE should NOT be #ifdef KOPS */
};

/* WAC -- Pole-weapons */
static NEARDATA const int pwep[] =
{	HALBERD, PARTISAN, LANCE, FAUCHARD, BILL_GUISARME, BEC_DE_CORBIN,
	GUISARME, RANSEUR, SPETUM, VOULGE, BARDICHE, GLAIVE
};

static struct obj *propellor;

struct obj *
select_rwep(mtmp)       /* select a ranged weapon for the monster */
register struct monst *mtmp;
{
	register struct obj *otmp;
	int i;

#ifdef KOPS
	char mlet = mtmp->data->mlet;
#endif

	propellor = &zeroobj;
#ifdef KOPS
	if(mlet == S_KOP)       /* pies are first choice for Kops */
	    Oselect(CREAM_PIE);
#endif
	if(throws_rocks(mtmp->data))    /* ...boulders for giants */
	    Oselect(BOULDER);

	/* WAC -- Select polearms */
	/* KMH -- Put this first; they do more damage and aren't expendable */
	for (i = 0; i < SIZE(pwep); i++) {
		/* only strong monsters can wield big (esp. long) weapons */
		/* big weapon is basically the same as bimanual */
		/* all monsters can wield the remaining weapons */
		if (((strongmonst(mtmp->data) && (mtmp->misc_worn_check & W_ARMS) == 0)
			|| !objects[pwep[i]].oc_bimanual) &&
		    (objects[pwep[i]].oc_material != SILVER
			|| !hates_silver(mtmp->data)))
			Oselect(pwep[i]);
	}

	/*
	 * other than these two specific cases, always select the
	 * most potent ranged weapon to hand.
	 */
	for (i = 0; i < SIZE(rwep); i++) {
	    int prop;

	    /* shooting gems from slings; this goes just before the darts */
	    if (rwep[i] == DART && !likes_gems(mtmp->data)
			&& (propellor = m_carrying(mtmp, SLING))) {
			for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
			    if(otmp->oclass == GEM_CLASS && otmp->otyp != LOADSTONE && 
			      !otmp->cursed) return(otmp);
			}
	    }

	    /* KMH -- This belongs here so darts will work */
	    propellor = &zeroobj;
	    
	    /* KMH, balance patch -- now using skills */
	    prop = -(objects[rwep[i]]).oc_skill;
	    if (prop > 0) {
		switch (prop) {
		case P_BOW:
		  propellor = (oselect(mtmp, YUMI));
		  if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW));
		  /* WAC added dark elven bow */
		  if (!propellor) propellor = (oselect(mtmp, DARK_ELVEN_BOW));
		  if (!propellor) propellor = (oselect(mtmp, BOW));
		  if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW));
		  break;
		case P_SLING:
		  propellor = (oselect(mtmp, SLING));
		  break;
#ifdef FIREARMS
		case P_FIREARM:
		  if (!propellor) propellor = (oselect(mtmp, SUBMACHINE_GUN));
		  if (!propellor) propellor = (oselect(mtmp, RIFLE));
		  if (!propellor) propellor = (oselect(mtmp, PISTOL));
		  /* lowest range, so last */
		  if (!propellor) propellor = (oselect(mtmp, SHOTGUN));
		  break;
#endif
		case P_CROSSBOW:
		  propellor = (oselect(mtmp, CROSSBOW));
		}
		if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor
				&& mtmp->weapon_check == NO_WEAPON_WANTED)
			propellor = 0;
	    }
	    /* propellor = obj, propellor to use
	     * propellor = &zeroobj, doesn't need a propellor
	     * propellor = 0, needed one and didn't have one
	     */
	    if (propellor != 0) {
		/* Note: cannot use m_carrying for loadstones, since it will
		 * always select the first object of a type, and maybe the
		 * monster is carrying two but only the first is unthrowable.
		 */
		/* STEPHEN WHITE'S NEW CODE */
		if (rwep[i] != LOADSTONE) {
			/* Don't throw a cursed weapon-in-hand */
			if ((otmp = oselect(mtmp, rwep[i]))
			    && (!otmp->cursed || otmp != MON_WEP(mtmp)))
				return(otmp);
		/* STEPHEN WHITE'S NEW CODE */
		/* KMH, balance patch -- removed stone of rotting */
		} else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
		    if (otmp->otyp == LOADSTONE && !otmp->cursed)
			return otmp;
		}
	    }
	}

	/* failure */
	return (struct obj *)0;
}

/* Weapons in order of preference */
/* WAC -- added dark elven short sword here */
/* WAC -- removed polearms */
static NEARDATA short hwep[] = {
	CORPSE,  /* cockatrice corpse */
	TSURUGI, RUNESWORD, HEAVY_HAMMER, 
	DWARVISH_MATTOCK, 
	RED_DOUBLE_LIGHTSABER, 
	RED_LIGHTSABER, BLUE_LIGHTSABER, GREEN_LIGHTSABER,
	TWO_HANDED_SWORD, BATTLE_AXE,
	KATANA, UNICORN_HORN, CRYSKNIFE,
	TRIDENT, LONG_SWORD, ELVEN_BROADSWORD, BROADSWORD, 
	LUCERN_HAMMER, SCIMITAR, SILVER_SABER, SILVER_DAGGER,
	SILVER_SHORT_SWORD, SILVER_LONG_SWORD, SILVER_MACE,
	SILVER_SPEAR, MORNING_STAR, ELVEN_SHORT_SWORD,
	DARK_ELVEN_SHORT_SWORD, DWARVISH_SHORT_SWORD,
	SHORT_SWORD, ORCISH_SHORT_SWORD, MACE, AXE, 
	DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, 
	FLAIL, BULLWHIP, QUARTERSTAFF, JAVELIN, AKLYS, CLUB,
	FLY_SWATTER, PICK_AXE,
#ifdef KOPS
	RUBBER_HOSE,
#endif /* KOPS */
	/* WAC added wooden stake */
	WAR_HAMMER, WOODEN_STAKE, ELVEN_DAGGER, DAGGER,
	ORCISH_DAGGER, ATHAME, SCALPEL,
	KNIFE, WORM_TOOTH
};

struct obj *
select_hwep(mtmp)       /* select a hand to hand weapon for the monster */
register struct monst *mtmp;
{
	register struct obj *otmp;
	register int i;
	boolean strong = strongmonst(mtmp->data);
	boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0;

	/* prefer artifacts to everything else */
	for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) {
		if (otmp->oclass == WEAPON_CLASS
			&& otmp->oartifact && touch_artifact(otmp,mtmp)
			&& ((strong && !wearing_shield)
			    || !objects[otmp->otyp].oc_bimanual))
		    return otmp;
	}

	if(is_giant(mtmp->data))        /* giants just love to use clubs */
	    Oselect(CLUB);

	/* only strong monsters can wield big (esp. long) weapons */
	/* big weapon is basically the same as bimanual */
	/* all monsters can wield the remaining weapons */
	for (i = 0; i < SIZE(hwep); i++)
	    if (((strong && !wearing_shield)
			|| !objects[hwep[i]].oc_bimanual) &&
		    (objects[hwep[i]].oc_material != SILVER
			|| !hates_silver(mtmp->data)))
		Oselect(hwep[i]);

	/* failure */
	return (struct obj *)0;
}

/* Called after polymorphing a monster, robbing it, etc....  Monsters
 * otherwise never unwield stuff on their own.  Shouldn't print messages.
 */
void
possibly_unwield(mon)
register struct monst *mon;
{
	register struct obj *obj;
	struct obj *mw_tmp;

	if (!(mw_tmp = MON_WEP(mon)))
		return;
	for(obj=mon->minvent; obj; obj=obj->nobj)
		if (obj == mw_tmp) 
			break;
	if (!obj) { /* The weapon was stolen or destroyed */
		MON_NOWEP(mon);
		mon->weapon_check = NEED_WEAPON;
		return;
	}	
	if (!attacktype(mon->data, AT_WEAP)) {
		mw_tmp->owornmask &= ~W_WEP;
		MON_NOWEP(mon);
		mon->weapon_check = NO_WEAPON_WANTED;
		obj_extract_self(obj);
		/* flooreffects unnecessary, can't wield boulders */
		place_object(obj, mon->mx, mon->my);
		stackobj(obj);
		if (cansee(mon->mx, mon->my)) {
			pline("%s drops %s.", Monnam(mon),
				distant_name(obj, doname));
			newsym(mon->mx, mon->my);
		}
		return;
	}
	/* The remaining case where there is a change is where a monster
	 * is polymorphed into a stronger/weaker monster with a different
	 * choice of weapons.  This has no parallel for players.  It can
	 * be handled by waiting until mon_wield_item is actually called.
	 * Though the monster still wields the wrong weapon until then,
	 * this is OK since the player can't see it.
	 * Note that if there is no change, setting the check to NEED_WEAPON
	 * is harmless.
	 * Possible problem: big monster with big cursed weapon gets
	 * polymorphed into little monster.  But it's not quite clear how to
	 * handle this anyway....
	 */
	mon->weapon_check = NEED_WEAPON;
}

/* Let a monster try to wield a weapon, based on mon->weapon_check.
 * Returns 1 if the monster took time to do it, 0 if it did not.
 */
int
mon_wield_item(mon)
register struct monst *mon;
{
	struct obj *obj;

	/* This case actually should never happen */
	if (mon->weapon_check == NO_WEAPON_WANTED) return 0;

	switch(mon->weapon_check) {
		case NEED_HTH_WEAPON:
			obj = select_hwep(mon);
			break;
		case NEED_RANGED_WEAPON:
			(void)select_rwep(mon);
			obj = propellor;
			break;
		case NEED_PICK_AXE:
			obj = m_carrying(mon, PICK_AXE);
			/* KMH, balance patch -- allow other picks */
			if (!obj) obj = m_carrying(mon, DWARVISH_MATTOCK);
			break;
		default: impossible("weapon_check %d for %s?",
				mon->weapon_check, mon_nam(mon));
			return 0;
	}
	if (obj && obj != &zeroobj) {
		struct obj *mw_tmp = MON_WEP(mon);
		
		if (mw_tmp && mw_tmp->otyp == obj->otyp) {
			/* already wielding it */
			if (is_lightsaber(obj))
				mon_ignite_lightsaber(obj, mon);
			mon->weapon_check = NEED_WEAPON;
			return 0;
		}
		/* Actually, this isn't necessary--as soon as the monster
		 * wields the weapon, the weapon welds itself, so the monster
		 * can know it's cursed and needn't even bother trying.
		 * Still....
		 */
		if (mw_tmp && mw_tmp->cursed && mw_tmp->otyp != CORPSE) {
		    if (canseemon(mon)) {
			char welded_buf[BUFSZ];

			Sprintf(welded_buf, "%s welded to %s hand%s",
				(mw_tmp->quan == 1L) ? "is" : "are",
				his[pronoun_gender(mon)],
				objects[mw_tmp->otyp].oc_bimanual ? "s" : "");

			if (obj->otyp == PICK_AXE) {
			    pline("Since %s weapon%s %s,",
				  s_suffix(mon_nam(mon)),
				  plur(mw_tmp->quan), welded_buf);
			    pline("%s cannot wield that %s.",
				mon_nam(mon), xname(obj));
			} else {
			    pline("%s tries to wield %s.", Monnam(mon),
				doname(obj));
			    pline("%s %s %s!",
				  s_suffix(Monnam(mon)),
				  xname(mw_tmp), welded_buf);
			}
			mw_tmp->bknown = 1;
		    }
		    mon->weapon_check = NO_WEAPON_WANTED;
		    return 1;
		}
		mon->mw = obj;          /* wield obj */
		if (mw_tmp) mw_tmp->owornmask &= ~W_WEP;
		mon->weapon_check = NEED_WEAPON;
		if (canseemon(mon)) {
			pline("%s wields %s!", Monnam(mon), doname(obj));
			if (obj->cursed && obj->otyp != CORPSE) {
				pline("%s %s to %s hand!",
					The(xname(obj)),
					(obj->quan == 1L) ? "welds itself"
					    : "weld themselves",
					s_suffix(mon_nam(mon)));
				obj->bknown = 1;
			}
		}
		obj->owornmask = W_WEP;
		if (is_lightsaber(obj))
			mon_ignite_lightsaber(obj, mon);
		return 1;
	}
	mon->weapon_check = NEED_WEAPON;
	return 0;
}

static void
mon_ignite_lightsaber(obj, mon)
struct obj * obj;
struct monst * mon;
{
	/* No obj or not lightsaber */
	if (!obj || !is_lightsaber(obj)) return;

	/* WAC - Check lightsaber is on */
	if (!obj->lamplit) {
	    if (obj->cursed && !rn2(2)) {
		if (canseemon(mon)) pline("%s %s flickers and goes out.", 
			s_suffix(Monnam(mon)), xname(obj));

	    } else {
		if (canseemon(mon)) {
			makeknown(obj->otyp);
			pline("%s ignites %s.", Monnam(mon),
				an(xname(obj)));
		}	    	
		begin_burn(obj, FALSE);
	    }
	} else {
		/* Double Lightsaber in single mode? Ignite second blade */
		if (obj->otyp == RED_DOUBLE_LIGHTSABER && !obj->altmode) {
		    /* Do we want to activate dual bladed mode? */
		    if (!obj->altmode && (!obj->cursed || rn2(4))) {
			if (canseemon(mon)) pline("%s ignites the second blade of %s.", 
				Monnam(mon), an(xname(obj)));
		    	obj->altmode = TRUE;
		    	return;
		    } else obj->altmode = FALSE;
		    lightsaber_deactivate(obj, TRUE);
		}
		return;
	}
}

/* STEPHEN WHITE'S NEW CODE */
int
abon()          /* attack bonus for strength & dexterity */
{
	int     sbon;
	register int    str = ACURR(A_STR), dex = ACURR(A_DEX);

	if (u.umonnum >= LOW_PM) return(adj_lev(&mons[u.umonnum]) - 3);
	/* [Tom] lowered these a little */        
	if (str < 6) sbon = -2;
	else if (str < 8) sbon = -1;
	else if (str < 17) sbon = 0;
	else if (str < 69) sbon = 1;    /* up to 18/50 */
	else if (str < 118) sbon = 1;   /* up to 18/99 */        
	else if (str == 118) sbon = 2;  /* 18/00 */
	else if (str == 119) sbon = 2;  /* 19 */
	else if (str == 120) sbon = 3;  /* 20 */
	else if (str == 121) sbon = 3;  /* 21 */
	else if (str == 122) sbon = 4;  /* 22 */
	else if (str == 123) sbon = 4;  /* 23 */
	else if (str == 124) sbon = 5;  /* 24 */
	else sbon = 5;
  
	if (dex < 5) sbon -= 2;
	else if (dex < 7) sbon -= 1;
	else if (dex < 15) sbon += 0;
	else if (dex == 15) sbon += 1;  /* 15 */
	else if (dex == 16) sbon += 1;  /* 16 */
	else if (dex == 17) sbon += 1;  /* 17 */
	else if (dex == 18) sbon += 2;  /* 18 */
	else if (dex == 19) sbon += 2;  /* 19 */
	else if (dex == 20) sbon += 2;  /* 20 */
	else if (dex == 21) sbon += 3;  /* 21 */
	else if (dex == 22) sbon += 3;  /* 22 */
	else if (dex == 23) sbon += 3;  /* 23 */
	else if (dex == 24) sbon += 4;  /* 24 */
	else sbon += 5;
	
/* Game tuning kludge: make it a bit easier for a low level character to hit */
	sbon += (u.ulevel < 3) ? 1 : 0;
	return(sbon);
}

#endif /* OVL0 */
#ifdef OVL1

/* STEPHEN WHITE'S NEW CODE */
int
dbon()          /* damage bonus for strength */
{
	register int    str = ACURR(A_STR);

	if (u.umonnum >= LOW_PM) return(0);
	/* [Tom] I lowered this a little */
	if (str < 6) return(-1);
	else if (str < 16) return(0);
	else if (str < 18) return(1);
	else if (str == 18) return(2);          /* up to 18 */
	else if (str < 118) return(3);          /* up to 18/99 */
	else if (str == 118) return(4);         /* 18/00 */
	else if (str == 119) return(5);         /* 19 */
	else if (str == 120) return(6);         /* 20 */
	else if (str == 121) return(7);         /* 21 */
	else if (str == 122) return(8);         /* 22 */
	else if (str == 123) return(9);         /* 23 */
	else if (str == 124) return(10);        /* 24 */
	else return(11);
}


#ifdef WEAPON_SKILLS

/* copy the skill level name into the given buffer */
static char *
skill_level_name(skill, buf)
int skill;
char *buf;
{
    const char *ptr;

    switch (P_SKILL(skill)) {
	case P_UNSKILLED:    ptr = "Unskilled"; break;
	case P_BASIC:        ptr = "Basic";     break;
	case P_SKILLED:      ptr = "Skilled";   break;
	case P_EXPERT:       ptr = "Expert";    break;
	case P_MASTER:       ptr = "Master";    break;
	case P_GRAND_MASTER: 
            if (skill <= P_LAST_WEAPON)
                    ptr = "Wizard" ;
            else if (skill <= P_LAST_SPELL)
                    ptr = "Legendary";
	    else if (skill <= P_LAST_H_TO_H) 
	    	    ptr = "Grand Master"; 
	    else ptr = "Unprecedented";
	    break;
	default:             ptr = "Unknown";   break;
    }
    Strcpy(buf, ptr);
    return buf;
}

/* return the # of slots required to advance the skill */
static int
slots_required(skill)
int skill;
{
      int tmp = P_SKILL(skill);
      
      /* WAC if you're over your class max,  it's twice as costly */      
      if (tmp >= P_MAX_SKILL(skill)) tmp *=2;
      if (tmp < 0) tmp = 0; /* for Restricted skills */
  
      /* The more difficult the training, the more slots it takes.
       *        unskilled -> basic      1
       *        basic -> skilled        2
       *        skilled -> expert       3
       */
    if (skill <= P_LAST_SPELL)
        return tmp;

      /* Fewer slots used up for unarmed or martial, miscellaneous skills
       *        unskilled -> basic      1
       *        basic -> skilled        1
       *        skilled -> expert       2
       *        expert -> master        2
       *        master -> grand master  3
       */
      return (tmp + 1) / 2;
}

/* return true if this skill can be advanced */
STATIC_OVL boolean
can_advance(skill)
int skill;
{
#ifdef WIZARD
/* WAC - wizard mode characters can advance without practicing */
    if (wizard && speed_advance)    
/*
    return !P_RESTRICTED(skill)
            && P_SKILL(skill) < P_MAX_SKILL(skill)
            && u.skills_advanced < P_SKILL_LIMIT;
*/
    return (P_SKILL(skill) < P_LIMIT
    	    && u.skills_advanced < P_SKILL_LIMIT);
    else
#endif
/*
    return !P_RESTRICTED(skill)
	    && P_SKILL(skill) < P_MAX_SKILL(skill)
	    && P_ADVANCE(skill) >=
		(unsigned) practice_needed_to_advance(P_SKILL(skill))
	    && u.skills_advanced < P_SKILL_LIMIT
	    && u.weapon_slots >= slots_required(skill);
*/
    return (P_SKILL(skill) < P_LIMIT
	    && (P_ADVANCE(skill) >= 
	    	(unsigned) practice_needed_to_advance(P_SKILL(skill),skill))
	    && u.skills_advanced < P_SKILL_LIMIT
	    && u.weapon_slots >= slots_required(skill));
}

/* WAC return true if skill can be practiced */
STATIC_OVL boolean
can_practice(skill)
int skill;
{
    return !P_RESTRICTED(skill)
            && P_SKILL(skill) < P_MAX_SKILL(skill)
            && u.skills_advanced < P_SKILL_LIMIT;
}



static void
skill_advance(skill)
int skill;
{
#ifdef WIZARD
    if (wizard && speed_advance && P_RESTRICTED(skill)) {
    	unrestrict_weapon_skill(skill);
	return;
    }
#endif
    
    u.weapon_slots -= slots_required(skill);
    P_SKILL(skill)++;
    u.skill_record[u.skills_advanced++] = skill;
    /* subtly change the advance message to indicate no more advancement */
    You("are now %s skilled in %s.", 
	P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more",
	P_NAME(skill));
}

/*
 * The `#enhance' extended command.  What we _really_ would like is
 * to keep being able to pick things to advance until we couldn't any
 * more.  This is currently not possible -- the menu code has no way
 * to call us back for instant action.  Even if it did, we would also need
 * to be able to update the menu since selecting one item could make
 * others unselectable.
 */
/*WAC - an mediocre attempt using a big while loop ;B */
int
enhance_weapon_skill()
{
    int i, n, len, longest, to_advance;
    char buf[BUFSIZ], buf2[BUFSIZ];
    menu_item *selected;
    anything any;
    winid win;
/*WAC ask if wizard wants to "cheat-advance"*/
#ifdef WIZARD
    speed_advance = FALSE;
    if (wizard)
        if (yn("Advance skills without practice?") == 'y') speed_advance = TRUE;
#endif

/*WAC - Do..while wrapper.  Simple hack,  but seems to work*/
  do {

    /* find longest available skill name, count those that can advance */
    for (longest = 0, to_advance = 0, i = 0; i < P_NUM_SKILLS; i++) {

/*WAC I've added some more of these...don't forget to remove the 3 references
        in this section otherwise funny things will happen to the
        display*/

		if ((
#ifdef WIZARD
		(wizard && speed_advance) ||
#endif
		!P_RESTRICTED(i)) && (len = strlen(P_NAME(i))) > longest)
		    longest = len;
		if (can_advance(i)) to_advance++;
    }

    win = create_nhwindow(NHW_MENU);
    start_menu(win);

    /* WAC Assume that everyone has some weapon skills*/
    any.a_void = 0;
    any.a_int = 0;
    add_menu(win, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Weapon Skills", MENU_UNSELECTED);

    /* list the skills, making ones that could be advanced selectable */
    for (any.a_void = 0, i = 0; i < P_NUM_SKILLS; i++) {
        /*WAC Added Headings for the Skill Types*/
        any.a_int = 0;
        if (i == P_LAST_WEAPON + 1)
                add_menu(win, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Spellcasting Skills", MENU_UNSELECTED);
        if (i == P_LAST_SPELL + 1)
                add_menu(win, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Fighting Skills", MENU_UNSELECTED);
        if (i == P_LAST_H_TO_H + 1)
                add_menu(win, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Miscellaneous Skills", MENU_UNSELECTED);
	if (
#ifdef WIZARD
		(!(wizard && speed_advance)) &&
#endif
		P_RESTRICTED(i)) continue;
	
	/*
	 * Sigh, this assumes a monospaced font.
	 * The 12 is the longest skill level name.
	 * The "    " is room for a selection letter and dash, "a - ".
	 */
#ifdef WIZARD
	if (wizard)
            Sprintf(buf2, "%s%-*s %-12s %4d(%4d)",
/*WAC Fixed brackets here and below*/
                    (to_advance == 0 || (can_advance(i)) ? "" : "    ") ,
		    longest, P_NAME(i),
		    skill_level_name(i, buf),
		    P_ADVANCE(i), practice_needed_to_advance(P_SKILL(i),i));
	else
#endif
            Sprintf(buf2, "%s%-*s [%s]",
                    (to_advance == 0 || can_advance(i)) ? "" : "    ",
		    longest, P_NAME(i),
		    skill_level_name(i, buf));
	any.a_int = can_advance(i) ? i+1 : 0;
	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf2, MENU_UNSELECTED);
    }

      Strcpy(buf, to_advance ? "Pick a skill to advance:" : "Current skills:");
#ifdef WIZARD
      if (wizard) Sprintf(eos(buf), "  (%d slot%s available)",
                        u.weapon_slots, plur(u.weapon_slots));
#endif
      end_menu(win, buf);
    n = select_menu(win, to_advance ? PICK_ONE : PICK_NONE, &selected);
    destroy_nhwindow(win);
    if (n > 0) {
	n = selected[0].item.a_int - 1; /* get item selected */
	free((genericptr_t)selected);
	skill_advance(n);
        /*WAC zero out n*/
        n = 0;
	/* check for more skills able to advance, if so then .. */
        /* .. set n to 1 and repeat! */
	for (i = 0; i < P_NUM_SKILLS; i++) {
	    if (can_advance(i)) {
                  n = 1;
/*                You("feel you could be more dangerous!");
		break;
*/
	    }
	}
    }
  } while (n > 0);
#ifdef WIZARD
    /*WAC must reset this,  otherwise midgame calls to
    can_advance might be messed up*/
    speed_advance = FALSE;
#endif

  return 0;
}

/*
 * Change from restricted to unrestricted, allowing P_BASIC as max.  This
 * function may be called with with P_NONE.  Used in pray.c.
 */
void
unrestrict_weapon_skill(skill)
int skill;
{
    if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) {
	P_SKILL(skill) = P_UNSKILLED;
	P_MAX_SKILL(skill) = P_BASIC;
	P_ADVANCE(skill) = 0;
    }
}

#endif /* WEAPON_SKILLS */

#endif /* OVL1 */
#ifdef OVLB

#ifdef WEAPON_SKILLS

void
use_skill(skill,degree)
int skill;
int degree;
{
    boolean advance_before;

/*    if (skill != P_NONE && !P_RESTRICTED(skill)) {*/
    if (skill != P_NONE) {
	advance_before = can_advance(skill);
	P_ADVANCE(skill) += degree;
	if (!advance_before && can_advance(skill)) {
	    give_may_advance_msg(skill);
	    if (P_RESTRICTED(skill)) {
	    	unrestrict_weapon_skill(skill);
	    }
	}
    }
}

void
add_weapon_skill(n)
int n;        /* number of slots to gain; normally one */
{
    int i, before, after;

    for (i = 0, before = 0; i < P_NUM_SKILLS; i++)
	if (can_advance(i)) before++;
    u.weapon_slots += n;
    for (i = 0, after = 0; i < P_NUM_SKILLS; i++)
	if (can_advance(i)) after++;
    if (before < after)
	give_may_advance_msg(P_NONE);
}

void
lose_weapon_skill(n)
int n;        /* number of slots to lose; normally one */
{
    int skill;

      while (--n >= 0) {
        /* deduct first from unused slots, then from last placed slot, if any */
        if (u.weapon_slots) {
            u.weapon_slots--;
        } else if (u.skills_advanced) {
            skill = u.skill_record[--u.skills_advanced];
            if (P_SKILL(skill) <= P_UNSKILLED)
                panic("lose_weapon_skill (%d)", skill);
            P_SKILL(skill)--;   /* drop skill one level */
            /* Lost skill might have taken more than one slot; refund rest. */
            u.weapon_slots = slots_required(skill) - 1;
            /* It might now be possible to advance some other pending
               skill by using the refunded slots, but giving a message
               to that affect would seem pretty confusing.... */
        }
    }
}


int
weapon_type(obj)
struct obj *obj;
{
	/* KMH, balance patch -- now uses the object table */
	int type;


	if (!obj)
		/* Not using a weapon */
		return (martial_bonus() ? P_MARTIAL_ARTS :
				P_BARE_HANDED_COMBAT);
/*	-- WAC  This is now handled separately
	if (u.twoweap)
		return (P_TWO_WEAPON_COMBAT);*/
	if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS &&
	    obj->oclass != GEM_CLASS)
		/* Not a weapon, weapon-tool, or ammo */
		return (P_NONE);
	type = objects[obj->otyp].oc_skill;
	return ((type < 0) ? -type : type);

#if 0
    if (obj) {
	switch (obj->otyp) {
	    case DAGGER:
            case ELVEN_DAGGER:
	    case DARK_ELVEN_DAGGER:	
	    case ORCISH_DAGGER:
	    case SILVER_DAGGER:		
            case ATHAME:
	    case GREAT_DAGGER:
	    case WOODEN_STAKE:
		type = P_DAGGER; break;
	    case KNIFE:       
            case STILETTO:
	    case WORM_TOOTH:
            case CRYSKNIFE:
	    case SCALPEL:
		type = P_KNIFE; break;
	    case AXE:
            case BATTLE_AXE:
		type = P_AXE; break;
	    case DWARVISH_MATTOCK:
	    case PICK_AXE:
		type = P_PICK_AXE; break;
	    case SHORT_SWORD:
            case ELVEN_SHORT_SWORD:
            case DARK_ELVEN_SHORT_SWORD:
	    case ORCISH_SHORT_SWORD:
            case DWARVISH_SHORT_SWORD:
	    case SILVER_SHORT_SWORD: 
		type = P_SHORT_SWORD; break;
	    case BROADSWORD:
            case ELVEN_BROADSWORD:
	    case RUNESWORD:
		type = P_BROAD_SWORD; break;
	    case LONG_SWORD:
	    case SILVER_LONG_SWORD:
            case KATANA:
		type = P_LONG_SWORD; break;
	    case TWO_HANDED_SWORD:
            case TSURUGI:
	    case GREEN_LIGHTSABER:
#ifdef D_SABER
            case BLUE_LIGHTSABER:
#endif /* D_SABER */
	    case RED_LIGHTSABER:
		type = P_TWO_HANDED_SWORD; break;
	    case SCIMITAR:
		type = P_SCIMITAR; break;
	    case RAPIER:
	    case SILVER_SABER:
		type = P_SABER; break;
	    case CLUB:
            case AKLYS:
	    case BASEBALL_BAT:
		type = P_CLUB; break;
	    case MACE:
	    case SILVER_MACE:	
		type = P_MACE; break;
	    case MORNING_STAR:
		type = P_MORNING_STAR; break;
	    case FLAIL:
		type = P_FLAIL; break;
	    case WAR_HAMMER:
	    case HEAVY_HAMMER:
		type = P_HAMMER; break;
	    case QUARTERSTAFF:
		type = P_QUARTERSTAFF; break;
	    case PARTISAN:
            case RANSEUR:
	    case SPETUM:
            case GLAIVE:
	    case HALBERD:
            case BARDICHE:
	    case VOULGE:
            case FAUCHARD:
	    case GUISARME:
            case BILL_GUISARME:
	    case LUCERN_HAMMER:
            case BEC_DE_CORBIN:
		type = P_POLEARMS; break;
	    case SPEAR:
            case ELVEN_SPEAR:
	    case ORCISH_SPEAR:
            case DWARVISH_SPEAR:
	    case SILVER_SPEAR:	
		type = P_SPEAR; break;
	    case JAVELIN:
		type = P_JAVELIN; break;
	    case TRIDENT:
		type = P_TRIDENT; break;
	    case LANCE:
		type = P_LANCE; break;
	    case BOW:
            case ELVEN_BOW:
	    case DARK_ELVEN_BOW:	
	    case ORCISH_BOW:
            case YUMI:
		type = P_BOW; break;
	    case SLING:
		type = P_SLING; break;
	    case CROSSBOW:
		type = P_CROSSBOW; break;
	    case DART:
# ifdef P_SPOON
                case SPOON:
# endif /* P_SPOON */
		type = P_DART; break;
	    case SHURIKEN:
		type = P_SHURIKEN; break;
	    case BOOMERANG:
		type = P_BOOMERANG; break;
	    case BULLWHIP:
#ifdef KOPS
	    case RUBBER_HOSE:
#endif
		type = P_WHIP; break;
	    case UNICORN_HORN:
		type = P_UNICORN_HORN; break;
	    default:
		type = P_NONE; break;
	}
	return type;
    }

    /* no object => */
    /* WAC Martial Arts over Bare handed */
    return (martial_bonus() ? P_MARTIAL_ARTS : P_BARE_HANDED_COMBAT);
#endif
}

/*
 * Return hit bonus/penalty based on skill of weapon.
 * Treat restricted weapons as unskilled.
 */
int
weapon_hit_bonus(weapon)
struct obj *weapon;
{
    int type, bonus = 0;
    static const char bad_skill[] = "weapon_hit_bonus: bad skill %d";

    type = weapon_type(weapon);
    if (type == P_NONE) {
		bonus = 0;
    } else if (type <= P_LAST_WEAPON) {
		switch (P_SKILL(type)) {
		    default: impossible(bad_skill, P_SKILL(type)); /* fall through */
		    case P_ISRESTRICTED:
		    case P_UNSKILLED:   bonus = -4; break;
		    case P_BASIC:       bonus =  0; break;
		    case P_SKILLED:     bonus =  1; break;
		    case P_EXPERT:      bonus =  2; break;
		    case P_MASTER:	bonus =  3; break;
		    case P_GRAND_MASTER:	bonus =  4; break;
		}
/* WAC -- No longer needed here...  */
#if 0
    } else if (type == P_TWO_WEAPON_COMBAT) {
		switch (P_SKILL(type)) {
		    default: impossible(bad_skill, P_SKILL(type)); /* fall through */
		    case P_ISRESTRICTED:
		    case P_UNSKILLED:   bonus = -9; break;
		    case P_BASIC:       bonus = -7; break;
		    case P_SKILLED:     bonus = -5; break;
		    case P_EXPERT:      bonus = -3; break;
		    case P_MASTER:	bonus = -1; break;
		    case P_GRAND_MASTER:	bonus =  1; break;
		}
#endif
        /* WAC  because we split Martial Arts and Bare handed*/
    } else if (type <= P_LAST_H_TO_H) {
	/* restricted == 0 */
		bonus = ((P_SKILL(type) + 1) * (martial_bonus() ? 2 : 1)) / 2;
    }

#ifdef YEOMAN
	/* KMH -- It's harder to hit while you are riding */
	if (u.usteed) {
		switch (P_SKILL(P_RIDING)) {
		    case P_ISRESTRICTED:
		    case P_UNSKILLED:   bonus -= 2; break;
		    case P_BASIC:       bonus -= 1; break;
		    case P_SKILLED:     break;
		    case P_EXPERT:      break;
		    case P_MASTER:	bonus += 1; break;
		    case P_GRAND_MASTER:	bonus += 2; break;
		}
		if (type == P_LANCE) bonus++;
	}
#endif

    return bonus;
}

/*
 * Return damage bonus/penalty based on skill of weapon.
 * Treat restricted weapons as unskilled.
 */
int
weapon_dam_bonus(weapon)
struct obj *weapon;
{
    int type, bonus = 0;

    type = weapon_type(weapon);
    if (type == P_NONE) {
		bonus = 0;
    } else if (P_RESTRICTED(type) || type <= P_LAST_WEAPON) {
		switch (P_SKILL(type)) {
		    default: impossible("weapon_dam_bonus: bad skill %d",P_SKILL(type));
			     /* fall through */
		    case P_ISRESTRICTED:
		    case P_UNSKILLED:   bonus = -2; break;
		    case P_BASIC:       bonus =  0; break;
		    case P_SKILLED:     bonus =  1; break;
		    case P_EXPERT:      bonus =  2; break;
		    case P_MASTER:	bonus =  3; break;
		    case P_GRAND_MASTER:	bonus =  4; break;
		}
        /* from == P_bare... to < = P_last_h.... */
    } else if (type <= P_LAST_H_TO_H && P_SKILL(type)) {
		bonus = (P_SKILL(type) * (martial_bonus() ? 2 : 1)) / 2;
    } /* Misc skills aren't usually called by weapons */

#ifdef YEOMAN
	/* KMH -- Riding some thrusting damage */
	if (u.usteed) {
		switch (P_SKILL(P_RIDING)) {
		    case P_ISRESTRICTED:
		    case P_UNSKILLED:   break;
		    case P_BASIC:       break;
		    case P_SKILLED:     bonus += 1; break;
		    case P_EXPERT:      bonus += 2; break;
		    case P_MASTER:	bonus += 3; break;
		    case P_GRAND_MASTER:	bonus += 4; break;
		}
		if (type == P_LANCE) bonus +=3;
	}
#endif

    return bonus;
}

int
skill_bonus(type)
int type;
{
    int bonus = 0;
    if (type == P_NONE) {
		bonus = 0;
    } else if (type <= P_LAST_WEAPON) {
		switch (P_SKILL(type)) {
		    default: impossible("skill_bonus: bad skill %d",P_SKILL(type));
			     /* fall through */
		    case P_ISRESTRICTED:
		    case P_UNSKILLED:   bonus = -2; break;
		    case P_BASIC:       bonus =  0; break;
		    case P_SKILLED:     bonus =  1; break;
		    case P_EXPERT:      bonus =  2; break;
		    case P_MASTER:	bonus =  3; break;
		    case P_GRAND_MASTER:	bonus =  4; break;
		}
        /* from == P_bare... to < = P_last_h.... */
    } else if (type <= P_LAST_H_TO_H && P_SKILL(type)) {
		bonus = (P_SKILL(type) * (martial_bonus() ? 2 : 1)) / 2;
    } else {
    		/* Misc. */
		switch (P_SKILL(type)) {
		    default: impossible("skill_bonus: bad skill %d",P_SKILL(type));
			     /* fall through */
		    case P_ISRESTRICTED:
		    case P_UNSKILLED:   bonus = -2; break;
		    case P_BASIC:       bonus =  0; break;
		    case P_SKILLED:     bonus =  1; break;
		    case P_EXPERT:      bonus =  2; break;
		    case P_MASTER:	bonus =  3; break;
		    case P_GRAND_MASTER:	bonus =  4; break;
		}
    }

    return bonus;
}

/* Try to return an associated skill for the specified object */
static 
int get_obj_skill(obj)
struct obj *obj;
{
	int skill;
	
	/* Try for a weapon skill */
	skill = weapon_type(obj);

	/* Try for a spell type */
	if (skill == P_NONE && obj->oclass == SPBOOK_CLASS) 
		skill = spell_skilltype(obj->otyp);
	
	/* Should be integrated into oc_subtyp as soon as more skills are 
	 * invented 
	 */
#ifdef YEOMAN
	if (obj->otyp == SADDLE) skill = P_RIDING;
#endif
    	/* Negative skills == not a skill */
	if (skill < P_NONE) skill = P_NONE;

	return (skill);
}

/*
 * Initialize weapon skill array for the game.  Start by setting all
 * skills to restricted, then set the skill for every weapon the
 * hero is holding, finally reading the given array that sets
 * maximums.
 */
void
skill_init(class_skill)
struct def_skill *class_skill;
{
	struct obj *obj;
	int skmax, skill;

	/* initialize skill array; by default, everything is restricted */
	for (skill = 0; skill < P_NUM_SKILLS; skill++) {
	    P_SKILL(skill) = P_ISRESTRICTED;
	    P_MAX_SKILL(skill) = P_ISRESTRICTED;
	    P_ADVANCE(skill) = 0;
	}

	/* Walk through array to set skill maximums */
	for (; class_skill->skill != P_NONE; class_skill++) {
	    skill = class_skill->skill;
	    skmax = class_skill->skmax;

	    P_MAX_SKILL(skill) = skmax;
	    if (P_SKILL(skill) == P_ISRESTRICTED)       /* skill pre-set */
			P_SKILL(skill) = P_UNSKILLED;
	    /* Really high potential in the skill
	     * Right now only used for H to H skills
	     */
	    if (P_MAX_SKILL(skill) > P_EXPERT) P_SKILL(skill) = P_BASIC;
	}

	/* Set skill for all weapons in inventory to be basic */
	for (obj = invent; obj; obj = obj->nobj) {
	    skill = get_obj_skill(obj);
#if 0
	    skill = weapon_type(obj);
#ifdef YEOMAN
	    if (obj->otyp == SADDLE) skill = P_RIDING;
#endif
#endif
	    if (skill != P_NONE) {
			P_SKILL(skill) = P_BASIC;
			/* KMH -- If you came into the dungeon with it, you should at least be skilled */
			if (P_MAX_SKILL(skill) < P_SKILLED) {
				pline("Warning: %s should be at least skilled.  Fixing...", P_NAME(skill));
				P_MAX_SKILL(skill) = P_SKILLED;
			}
		}
	}

#if 0  /* This should all be handled above now... */
	/* set skills for magic */
    /* WAC - added setup for role is F, I, M or N*/
    if (Role_if(PM_HEALER) || Role_if(PM_MONK))  {
		P_SKILL(P_HEALING_SPELL) = P_BASIC;
	} else if (Role_if(PM_PRIEST)) {
		P_SKILL(P_PROTECTION_SPELL) = P_BASIC;
    } else if (Role_if(PM_NECROMANCER)) {
		P_SKILL(P_ATTACK_SPELL) = P_BASIC;
    } else if (Role_if(PM_FLAME_MAGE) || Role_if(PM_ICE_MAGE))  {
		P_SKILL(P_MATTER_SPELL) = P_BASIC;
	} else if (Role_if(PM_WIZARD)) {
		P_SKILL(P_ATTACK_SPELL) = P_BASIC;
		P_SKILL(P_ENCHANTMENT_SPELL) = P_BASIC;
	}

	/* High potential fighters already know how to use their hands. */
	if (P_MAX_SKILL(P_BARE_HANDED_COMBAT) > P_EXPERT)
	    P_SKILL(P_BARE_HANDED_COMBAT) = P_BASIC;
	if (P_MAX_SKILL(P_MARTIAL_ARTS) > P_EXPERT)
		P_SKILL(P_MARTIAL_ARTS) = P_BASIC;
#endif

	/*
	 * Make sure we haven't missed setting the max on a skill
	 * & set advance
	 */
	for (skill = 0; skill < P_NUM_SKILLS; skill++) {
	    if (!P_RESTRICTED(skill)) {
		if (P_MAX_SKILL(skill) < P_SKILL(skill)) {
		    impossible("skill_init: curr > max: %s", P_NAME(skill));
		    P_MAX_SKILL(skill) = P_SKILL(skill);
		}
		P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill)-1,skill);
	    }
	}
}

/*WAC  weapon practice code*/
STATIC_PTR int
practice()
{
	if (delay) {    /* not if (delay++), so at end delay == 0 */
		delay++;
		use_skill(weapon_type(uwep), 1);
		/*WAC a bit of practice so even if you're interrupted
		  you won't be wasting your time ;B*/
		return(1); /* still busy */
	}
	You("finish your practice session.");
	use_skill(weapon_type(uwep),
	    practice_needed_to_advance(P_SKILL(weapon_type(uwep)),weapon_type(uwep))/3);
	return(0);
}

void
practice_weapon()
{
	if (can_practice(weapon_type(uwep))
#ifdef WIZARD
	    || (wizard && (yn("Skill at normal max. Practice?") == 'y'))
#endif
	    ) {
		if (uwep)    
		    You("start practicing intensely with %s",doname(uwep));
		else
		    You("start practicing intensely with your %s %s.",
		            uarmg ? "gloved" : "bare",      /* Del Lamb */
		makeplural(body_part(HAND)));

		delay=-10;
		set_occupation(practice, "practicing", 0);
	} else if (P_SKILL(weapon_type(uwep)) >= P_MAX_SKILL(weapon_type(uwep)))
		You("cannot increase your skill in %s.", P_NAME(weapon_type(uwep)));
	else You("cannot learn much about %s right now.",
                P_NAME(weapon_type(uwep)));
                
}

#endif /* WEAPON_SKILLS */

#endif /* OVLB */

/*weapon.c*/
