/*	SCCS Id: @(#)weapon.c	3.1	93/01/15	*/
/* 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 OVLB

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

/*
 *	hitval returns an integer representing the "to hit" bonuses
 *	of "otmp" against the monster type "ptr".
 */
int
hitval(otmp, ptr)
struct	obj *otmp;
struct	permonst *ptr;
{
	int	tmp = 0;

	if (otmp->oclass == WEAPON_CLASS ||
	    otmp->otyp == PICK_AXE || otmp->otyp == UNICORN_HORN)
		tmp += otmp->spe;

/*	Put weapon specific "to hit" bonuses in below:		*/
	tmp += objects[otmp->otyp].oc_hitbon;

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

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

	if(otmp->otyp >= SPEAR && otmp->otyp <= JAVELIN &&
	   index(kebabable, ptr->mlet)) tmp += 2;

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

/*
 *	dmgval returns an integer representing the damage bonuses
 *	of "otmp" against the monster type "ptr".
 */
int
dmgval(otmp, ptr)
struct	obj *otmp;
struct	permonst *ptr;
{
	int	tmp = 0;

	if(otmp->otyp == CREAM_PIE)	return(0);

	if(ptr->msize >= MZ_HUMAN) {
	    if(objects[otmp->otyp].oc_wldam)
		tmp = rnd(objects[otmp->otyp].oc_wldam);
	    switch (otmp->otyp) {
		case CROSSBOW_BOLT:
		case MORNING_STAR:
		case PARTISAN:
		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[otmp->otyp].oc_wsdam)
		tmp = rnd(objects[otmp->otyp].oc_wsdam);
	    switch (otmp->otyp) {
		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 VOULGE:		tmp += rnd(4); break;

		case ACID_VENOM:	tmp += rnd(6); break;
	    }
	}
	if (otmp->oclass == WEAPON_CLASS || otmp->otyp == PICK_AXE
						|| otmp->otyp == UNICORN_HORN)
		tmp += otmp->spe;

	tmp -= otmp->oeroded;

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

/*	Put weapon vs. monster type damage bonuses in below:	*/
	if(otmp->oclass == WEAPON_CLASS) {
	    if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
		tmp += rnd(4);
	    if ((otmp->otyp == AXE || otmp->otyp == BATTLE_AXE)
		&& is_wooden(ptr))
		tmp += rnd(4);
	    if (objects[otmp->otyp].oc_material == SILVER && hates_silver(ptr))
		tmp += rnd(20);
	}

	return(tmp);
}

void
set_uasmon()		/* update the "uasmon" structure */
{
#ifdef POLYSELF
	if(u.umonnum >= 0) uasmon = &mons[u.umonnum];
	else {
#endif

		uasmon = &playermon;
		playermon.mlevel = u.ulevel;
		playermon.ac = u.uac;
		playermon.mr = (u.ulevel > 8) ? 5 * (u.ulevel-7) : u.ulevel;
#ifdef POLYSELF
	}
#endif
	return;
}

#endif /* OVLB */
#ifdef OVL0

#define	Oselect(x)	if((otmp = oselect(mtmp, x))) return(otmp);

static struct obj * FDECL(oselect, (struct monst *,int));

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

static const int NEARDATA rwep[] =
	{ DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN,
	  SHURIKEN, 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, 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));
		}
#ifdef MUSE
		if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor
				&& mtmp->weapon_check == NO_WEAPON_WANTED)
			propellor = 0;
#endif
	    }
	    /* 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) {
#ifdef MUSE
			/* Don't throw a cursed weapon-in-hand */
			if ((otmp = oselect(mtmp, rwep[i]))
			    && (!otmp->cursed || otmp != MON_WEP(mtmp)))
				return(otmp);
#else
			Oselect(rwep[i]);
#endif
		} else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
		    if (otmp->otyp == LOADSTONE && !otmp->cursed)
			return otmp;
		}
	    }
	  }

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

/* 0 = used by any monster; 1 = only used by strong monsters */
static const struct hwep { short otyp, big; } NEARDATA hwep[] = {
	  {TSURUGI,1}, {RUNESWORD,0},
	  {DWARVISH_MATTOCK,1}, {TWO_HANDED_SWORD,1}, {BATTLE_AXE,1},
	  {KATANA,0}, {UNICORN_HORN,1}, {CRYSKNIFE,0},
	  {TRIDENT,0}, {LONG_SWORD,0}, {ELVEN_BROADSWORD,0}, {BROADSWORD,0},
	  {LUCERN_HAMMER,1}, {SCIMITAR,1}, {SILVER_SABER,0}, {HALBERD,1},
	  {PARTISAN,1}, {LANCE,1}, {FAUCHARD,1}, {BILL_GUISARME,1},
	  {BEC_DE_CORBIN,1}, {GUISARME,1}, {RANSEUR,1}, {SPETUM,1},
	  {VOULGE,1}, {BARDICHE,0}, {MORNING_STAR,0}, {GLAIVE,0},
	  {ELVEN_SHORT_SWORD,0}, {DWARVISH_SHORT_SWORD,0}, {SHORT_SWORD,0},
	  {ORCISH_SHORT_SWORD,0}, {MACE,0}, {AXE,0}, {DWARVISH_SPEAR,0},
	  {ELVEN_SPEAR,0}, {SPEAR,0}, {ORCISH_SPEAR,0}, {FLAIL,0},
	  {QUARTERSTAFF,1}, {JAVELIN,0}, {AKLYS,0}, {CLUB,0}, {PICK_AXE,0},
#ifdef KOPS
	  {RUBBER_HOSE,0},
#endif /* KOPS */
	  {WAR_HAMMER,0}, {ELVEN_DAGGER,0}, {DAGGER,0}, {ORCISH_DAGGER,0},
	  {ATHAME,0}, {SCALPEL,0}, {KNIFE,0}, {WORM_TOOTH,0}, {BULLWHIP,0}
	};

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;
	register const struct hwep *hw;
	boolean strong = strongmonst(mtmp->data);

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

	/* only strong monsters can wield big (esp. long) weapons */
	/* all monsters can wield the remaining weapons */
	for (i = 0, hw = hwep; i < SIZE(hwep); i++, hw++)
	    if ((strong || !hw->big) &&
#ifdef MUSE
	      (!objects[hw->otyp].oc_bimanual || !which_armor(mtmp, W_ARMS)) &&
#endif
	(objects[hw->otyp].oc_material != SILVER || !hates_silver(mtmp->data)))
		Oselect(hw->otyp);

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

#ifdef MUSE
/* 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 *otmp, *backobj, *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)) {
		MON_NOWEP(mon);
		mon->weapon_check = NO_WEAPON_WANTED;
		if (cansee(mon->mx, mon->my)) {
			pline("%s drops %s.", Monnam(mon),
				distant_name(obj, doname));
		}
		backobj = 0;
		for(otmp = mon->minvent; otmp; otmp = otmp->nobj) {
			/* flooreffects unnecessary, can't wield boulders */
			if (otmp == obj) {
				if (!backobj) mon->minvent = otmp->nobj;
				else backobj->nobj = otmp->nobj;
				place_object(otmp, mon->mx, mon->my);
				otmp->nobj = fobj;
				fobj = otmp;
				stackobj(fobj);
				if(cansee(mon->mx,mon->my))
					newsym(mon->mx, mon->my);
				break;
			}
			backobj = otmp;
		}
		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.
	 * 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;
	return;
}

/* 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 == obj) { /* 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) {
		    if (obj->otyp == PICK_AXE) {
			if (canseemon(mon)) {
			    pline("Since %s weapon %s welded to %s hand,",
				s_suffix(mon_nam(mon)),
				(mw_tmp->quan == 1L) ? "is" : "are",
				humanoid(mon->data)
					? (mon->female ? "her" : "his")
					: "its");
			    pline("%s cannot wield that %s.",
				mon_nam(mon), xname(obj));
			    mw_tmp->bknown = 1;
			}
		    } else {
			if (canseemon(mon)) {
			    pline("%s tries to wield %s.", Monnam(mon),
				doname(obj));
			    pline("%s %s %s welded to %s hand!",
				s_suffix(Monnam(mon)), xname(mw_tmp),
				(mw_tmp->quan == 1L) ? "is" : "are",
				humanoid(mon->data)
					? (mon->female ? "her" : "his")
					: "its");
			    mw_tmp->bknown = 1;
			}
		    }
		    mon->weapon_check = NO_WEAPON_WANTED;
		    return 1;
		}
		mon->mw = obj;		/* wield obj */
		mon->weapon_check = NEED_WEAPON;
		if (canseemon(mon)) {
			pline("%s wields %s!", Monnam(mon), doname(obj));
			if (obj->cursed) {
				pline("%s %s to %s hand!",
					The(xname(obj)),
					(obj->quan == 1L) ? "welds itself"
					    : "weld themselves",
					s_suffix(mon_nam(mon)));
				obj->bknown = 1;
			}
		}
		return 1;
	}
	mon->weapon_check = NEED_WEAPON;
	return 0;
}

/* rearrange a monster's inventory so that wielded weapon is first */
void
sort_mwep(mon)
struct monst *mon;
{
	struct obj *otmp, *prev, *mw_tmp = MON_WEP(mon);

	if (!mw_tmp) return;
	for (otmp = mon->minvent, prev = 0; otmp; otmp = otmp->nobj) {
		if (otmp == mw_tmp)  break;
		prev = otmp;
	}
	if (!otmp) {
		MON_NOWEP(mon);
	} else if (prev) {
		prev->nobj = otmp->nobj;
		otmp->nobj = mon->minvent;
		mon->minvent = otmp;
	}
}
#endif

int
abon() {	/* attack bonus for strength & dexterity */
	int	sbon;
	register int	str = ACURR(A_STR), dex = ACURR(A_DEX);

#ifdef POLYSELF
	if (u.umonnum >= 0) return(adj_lev(&mons[u.umonnum])-3);
#endif
	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;
/*
 *	Temporary kludge - make it a bit easier for a low level character
 *			   to hit until we tune the game a little better.
 */
	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);

#ifdef POLYSELF
	if (u.umonnum >= 0) return(0);
#endif

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

#endif /* OVL1 */

/*weapon.c*/
