/*	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.
 */

/*
**	Japanese version Copyright
**	(c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-1999
**	changing point is marked `JP' (94/6/7)
**	JNetHack may be freely redistributed.  See license for details. 
*/

#include "hack.h"

#ifdef WEAPON_SKILLS
#ifndef OVLB

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

#else	/* OVLB */

STATIC_OVL NEARDATA const short skill_names_indices[P_NUM_SKILLS] = {
	DAGGER,		KNIFE,		AXE,		PICK_AXE,
	SHORT_SWORD,	BROADSWORD,	LONG_SWORD,	TWO_HANDED_SWORD,
	SCIMITAR,	PN_SABER,	CLUB,		MACE,
	MORNING_STAR,	FLAIL,		WAR_HAMMER,	QUARTERSTAFF,
	PN_POLEARMS,	SPEAR,		JAVELIN,	TRIDENT,
	LANCE,		BOW,		SLING,		CROSSBOW,
	DART,		SHURIKEN,	BOOMERANG,	BULLWHIP,
	UNICORN_HORN,	PN_TWO_WEAPONS,	PN_BARE_HANDED,
};

/* note: entry [0] isn't used */
STATIC_OVL NEARDATA const char *odd_skill_names[] = {
    0, "polearms", "saber", "two weapon combat",
    "bare handed combat", "martial arts",
};

static NEARDATA const char may_advance_msg[] =
/*JP				"feel more confident in your fighting skills.";*/
				"戦いの技量を高める自信が湧いてきた．";

#endif	/* OVLB */

STATIC_DCL boolean FDECL(can_advance, (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]]) : \
		      (type == P_BARE_HANDED_COMBAT ? \
		      	Role_is('Y') ? "sexy commando" : \
			(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 */
#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;

	if (objects[otmp->otyp].oc_wepcat == WEP_SPEAR &&
	   index(kebabable, ptr->mlet)) 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 */
	if ((otmp->otyp == PICK_AXE || otmp->otyp == DWARVISH_MATTOCK) &&
	   (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2;

	/* 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;

	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;
	    }
	} 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 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;

	    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 && otmp->corpsenm != PM_COCKATRICE) &&
		    (!otmp->oartifact || touch_artifact(otmp,mtmp)))
		return otmp;
	}
	return (struct obj *)0;
}

static NEARDATA const int rwep[] =
	{ DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN,
	  SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW,
	  CROSSBOW_BOLT, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE, ROCK,
	  LOADSTONE, LUCKSTONE, DART, /* BOOMERANG, */ CREAM_PIE
	  /* note: CREAM_PIE should NOT be #ifdef KOPS */
	  };

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);

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

	    propellor = &zeroobj;
	    /* 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);
		}
	    }
	    prop = (objects[rwep[i]]).w_propellor;
	    if (prop > 0) {
		switch (prop) {
		case WP_BOW:
		  propellor = (oselect(mtmp, YUMI));
		  if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW));
		  if (!propellor) propellor = (oselect(mtmp, BOW));
		  if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW));
		  break;
		case WP_SLING:
		  propellor = (oselect(mtmp, SLING));
		  break;
		case WP_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.
		 */
		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);
		} 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 */
static NEARDATA short hwep[] = {
	  CORPSE,  /* cockatrice corpse */
	  TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE,
	  KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD,
	  ELVEN_BROADSWORD, BROADSWORD, LUCERN_HAMMER, SCIMITAR, SILVER_SABER,
	  HALBERD, PARTISAN, LANCE, FAUCHARD, BILL_GUISARME, BEC_DE_CORBIN,
	  GUISARME, RANSEUR, SPETUM, VOULGE, BARDICHE, MORNING_STAR, GLAIVE,
	  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,
	  PICK_AXE,
#ifdef KOPS
	  RUBBER_HOSE,
#endif /* KOPS */
	  WAR_HAMMER, 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)) {
/*JP			pline("%s drops %s.", Monnam(mon),*/
			pline("%sは%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);
			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 */
			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];

/*JP			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" : "");*/
			Sprintf(welded_buf, "手に");

			if (obj->otyp == PICK_AXE) {
/*JP			    pline("Since %s weapon%s %s,",
				  s_suffix(mon_nam(mon)),
				  plur(mw_tmp->quan), welded_buf);*/
			    pline("%sは武器を%sしようとしたが，",
				  mon_nam(mon), welded_buf);
/*JP			    pline("%s cannot wield that %s.",*/
			    pline("%sは%sを装備できなかった．",
				mon_nam(mon), xname(obj));
			} else {
/*JP			    pline("%s tries to wield %s.", Monnam(mon),*/
			    pline("%sは%sを装備しようとした．", Monnam(mon),
				doname(obj));
/*JP			    pline("%s %s %s!",
				  s_suffix(Monnam(mon)),
				  xname(mw_tmp), welded_buf);*/
			    pline("%sは%sを%sした！",
				  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)) {
/*JP			pline("%s wields %s!", Monnam(mon), doname(obj));*/
			pline("%sは%sを装備した！", Monnam(mon), doname(obj));
			if (obj->cursed && obj->otyp != CORPSE) {
/*JP				pline("%s %s to %s hand!",
					The(xname(obj)),
					(obj->quan == 1L) ? "welds itself"
					    : "weld themselves",
					s_suffix(mon_nam(mon)));*/
				pline("%sは勝手に%sの手に装備された！",
					The(xname(obj)),
					mon_nam(mon));
				obj->bknown = 1;
			}
		}
		obj->owornmask = W_WEP;
		return 1;
	}
	mon->weapon_check = NEED_WEAPON;
	return 0;
}

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);
	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 = 2;
	else sbon = 3;

/* Game tuning kludge: make it a bit easier for a low level character to hit */
	sbon += (u.ulevel < 3) ? 1 : 0;

	if (dex < 4) return(sbon-3);
	else if (dex < 6) return(sbon-2);
	else if (dex < 8) return(sbon-1);
	else if (dex < 14) return(sbon);
	else return(sbon + dex-14);
}

#endif /* OVL0 */
#ifdef OVL1

int
dbon()		/* damage bonus for strength */
{
	register int	str = ACURR(A_STR);

	if (u.umonnum >= LOW_PM) return(0);

	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 < 94) return(3);		/* up to 18/75 */
	else if (str < 109) return(4);		/* up to 18/90 */
	else if (str < 118) return(5);		/* up to 18/99 */
	else return(6);
}


#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)) {
#if 0 /*JP*/
	case P_UNSKILLED:    ptr = "Unskilled"; break;
	case P_BASIC:	     ptr = "Basic";     break;
	case P_SKILLED:	     ptr = "Skilled";   break;
	case P_EXPERT:	     ptr = "Expert";    break;
	/* these are for unarmed combat/martial arts only */
	case P_MASTER:	     ptr = "Master";    break;
	case P_GRAND_MASTER: ptr = "Grand Master"; break;
	default:	     ptr = "Unknown";	break;
#endif
	case P_UNSKILLED:    ptr = "初心者"; break;
	case P_BASIC:	     ptr = "入門者";     break;
	case P_SKILLED:	     ptr = "熟練者";   break;
	case P_EXPERT:	     ptr = "エキスパート";    break;
	/* these are for unarmed combat/martial arts only */
	case P_MASTER:	     ptr = "マスター";    break;
	case P_GRAND_MASTER: ptr = "グランドマスター"; break;
	default:	     ptr = "不明";	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);

    /* The more difficult the training, the more slots it takes.
     *	unskilled -> basic	1
     *	basic -> skilled	2
     *	skilled -> expert	3
     */
    if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT)
	return tmp;

    /* Fewer slots used up for unarmed or martial.
     *	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;
{
    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);
}

static void
skill_advance(skill)
int skill;
{
    u.weapon_slots -= slots_required(skill);
    P_SKILL(skill)++;
    u.skill_record[u.skills_advanced++] = skill;
    /* subtly change the adavnce message to indicate no more advancement */
/*JP
    You("are now %s skilled in %s.",
    	P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more",
    	P_NAME(skill));
*/
    Your("%sの技量を%s高めた．", 
    	jtrns_obj(')', P_NAME(skill)),
	P_SKILL(skill) >= P_MAX_SKILL(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.
 */
int
enhance_weapon_skill()
{
    int i, n, len, longest, to_advance;
    char buf[BUFSZ], buf2[BUFSZ];
    menu_item *selected;
    anything any;
    winid win;

    /* find longest available skill name, count those that can advance */
    for (longest = 0, to_advance = 0, i = 0; i < P_NUM_SKILLS; i++) {
	if (!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);

    /* list the skills, making ones that could be advanced selectable */
    for (any.a_void = 0, i = 0; i < P_NUM_SKILLS; i++) {
	if (P_RESTRICTED(i)) continue;
	if (i == P_TWO_WEAPON_COMBAT) continue;	/* skip for now */
	/*
	 * 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)",
		    to_advance == 0 || can_advance(i) ? "" : "    " ,
		    longest, jtrns_obj(')', P_NAME(i)),
		    skill_level_name(i, buf),
		    P_ADVANCE(i), practice_needed_to_advance(P_SKILL(i)));
	else
#endif
	    Sprintf(buf2, "%s %-*s [%s]",
		    to_advance == 0 || can_advance(i) ? "" : "    ",
		    longest, jtrns_obj(')', 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);
    }

/*JP
    Strcpy(buf, to_advance ? "Pick a skill to advance:" : "Current skills:");
*/
    Strcpy(buf, to_advance ? "技量を高める武器を選択してください：" : "現在の技量：");
#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);
	/* check for more skills able to advance, if so then .. */
	for (i = 0; i < P_NUM_SKILLS; i++) {
	    if (can_advance(i)) {
/*JP		You("feel you could be more dangerous!");*/
		You("さらに技量を高めることができそうな気がした！");
		break;
	    }
	}
    }
    return 0;
}

/*
 * Change from restricted to unrestricted, allowing P_BASIC as max.  This
 * function may be called with with P_NO_TYPE.  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)
int skill;
{
    boolean advance_before;

    if (skill != P_NO_TYPE && !P_RESTRICTED(skill)) {
	advance_before = can_advance(skill);
	P_ADVANCE(skill)++;
	if (!advance_before && can_advance(skill))
	    You(may_advance_msg);
    }
}

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)
	You(may_advance_msg);
}

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;
{
    int type;

    if (obj) {
	switch (obj->otyp) {
	    case DAGGER:		case ELVEN_DAGGER:
	    case ORCISH_DAGGER:		case ATHAME:
		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 ORCISH_SHORT_SWORD:	case DWARVISH_SHORT_SWORD:
		type = P_SHORT_SWORD; break;
	    case BROADSWORD:		case ELVEN_BROADSWORD:
	    case RUNESWORD:
		type = P_BROAD_SWORD; break;
	    case LONG_SWORD:		case KATANA:
		type = P_LONG_SWORD; break;
	    case TWO_HANDED_SWORD:	case TSURUGI:
		type = P_TWO_HANDED_SWORD; break;
	    case SCIMITAR:
		type = P_SCIMITAR; break;
	    case SILVER_SABER:
		type = P_SABER; break;
	    case CLUB:			case AKLYS:
		type = P_CLUB; break;
	    case MACE:
		type = P_MACE; break;
	    case MORNING_STAR:
		type = P_MORNING_STAR; break;
	    case FLAIL:
		type = P_FLAIL; break;
	    case WAR_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:
		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 ORCISH_BOW:		case YUMI:
		type = P_BOW; break;
	    case SLING:
		type = P_SLING; break;
	    case CROSSBOW:
		type = P_CROSSBOW; break;
	    case DART:
		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_NO_TYPE; break;
	}
	return type;
    }

    /* no object => */
    return P_BARE_HANDED_COMBAT;
}

/*
 * 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_NO_TYPE) {
	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 =  2; break;
	    case P_EXPERT:      bonus =  3; break;
	}
    } 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;
	}
    } else if (type == P_BARE_HANDED_COMBAT) {
	/* restricted == 0 */
	bonus = ((P_SKILL(type) + 1) * (martial_bonus() ? 2 : 1)) / 2;
    }
    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_NO_TYPE) {
	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;
	}
    } else if (type == P_BARE_HANDED_COMBAT && P_SKILL(type)) {
	bonus = (P_SKILL(type) * (martial_bonus() ? 2 : 1)) / 2;
    }
    return bonus;
}

/*
 * 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;
	}

	/* set skill for all weapons in inventory to be basic */
	for (obj = invent; obj; obj = obj->nobj) {
	    skill = weapon_type(obj);
	    if (skill != P_NO_TYPE)
		P_SKILL(skill) = P_BASIC;
	}

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

	    P_MAX_SKILL(skill) = skmax;
	    if (P_SKILL(skill) == P_ISRESTRICTED)	/* skill pre-set */
		P_SKILL(skill) = P_UNSKILLED;
	}

	/* 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;

	/*
	 * 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);
	    }
	}
}

#endif /* WEAPON_SKILLS */

#endif /* OVLB */

/*weapon.c*/
