1/*	SCCS Id: @(#)weapon.c	3.4	2002/11/07	*/
2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3/* NetHack may be freely redistributed.  See license for details. */
4
5/*
6 *	This module contains code for calculation of "to hit" and damage
7 *	bonuses for any given weapon used, as well as weapons selection
8 *	code for monsters.
9 */
10#include "hack.h"
11
12/* Categories whose names don't come from OBJ_NAME(objects[type])
13 */
14#define PN_BARE_HANDED			(-1)	/* includes martial arts */
15#define PN_TWO_WEAPONS			(-2)
16#define PN_RIDING			(-3)
17#define PN_POLEARMS			(-4)
18#define PN_SABER			(-5)
19#define PN_HAMMER			(-6)
20#define PN_WHIP				(-7)
21#define PN_ATTACK_SPELL			(-8)
22#define PN_HEALING_SPELL		(-9)
23#define PN_DIVINATION_SPELL		(-10)
24#define PN_ENCHANTMENT_SPELL		(-11)
25#define PN_CLERIC_SPELL			(-12)
26#define PN_ESCAPE_SPELL			(-13)
27#define PN_MATTER_SPELL			(-14)
28
29STATIC_DCL void FDECL(give_may_advance_msg, (int));
30
31#ifndef OVLB
32
33STATIC_DCL NEARDATA const short skill_names_indices[];
34STATIC_DCL NEARDATA const char *odd_skill_names[];
35STATIC_DCL NEARDATA const char *barehands_or_martial[];
36
37#else	/* OVLB */
38
39STATIC_VAR NEARDATA const short skill_names_indices[P_NUM_SKILLS] = {
40	0,                DAGGER,         KNIFE,        AXE,
41	PICK_AXE,         SHORT_SWORD,    BROADSWORD,   LONG_SWORD,
42	TWO_HANDED_SWORD, SCIMITAR,       PN_SABER,     CLUB,
43	MACE,             MORNING_STAR,   FLAIL,
44	PN_HAMMER,        QUARTERSTAFF,   PN_POLEARMS,  SPEAR,
45	JAVELIN,          TRIDENT,        LANCE,        BOW,
46	SLING,            CROSSBOW,       DART,
47	SHURIKEN,         BOOMERANG,      PN_WHIP,      UNICORN_HORN,
48	PN_ATTACK_SPELL,     PN_HEALING_SPELL,
49	PN_DIVINATION_SPELL, PN_ENCHANTMENT_SPELL,
50	PN_CLERIC_SPELL,     PN_ESCAPE_SPELL,
51	PN_MATTER_SPELL,
52	PN_BARE_HANDED,   PN_TWO_WEAPONS,
53#ifdef STEED
54	PN_RIDING
55#endif
56};
57
58/* note: entry [0] isn't used */
59STATIC_VAR NEARDATA const char * const odd_skill_names[] = {
60    "no skill",
61    "bare hands",		/* use barehands_or_martial[] instead */
62    "two weapon combat",
63    "riding",
64    "polearms",
65    "saber",
66    "hammer",
67    "whip",
68    "attack spells",
69    "healing spells",
70    "divination spells",
71    "enchantment spells",
72    "clerical spells",
73    "escape spells",
74    "matter spells",
75};
76/* indexed vis `is_martial() */
77STATIC_VAR NEARDATA const char * const barehands_or_martial[] = {
78    "bare handed combat", "martial arts"
79};
80
81STATIC_OVL void
82give_may_advance_msg(skill)
83int skill;
84{
85	You_feel("more confident in your %sskills.",
86		skill == P_NONE ?
87			"" :
88		skill <= P_LAST_WEAPON ?
89			"weapon " :
90		skill <= P_LAST_SPELL ?
91			"spell casting " :
92		"fighting ");
93}
94
95#endif	/* OVLB */
96
97STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P));
98STATIC_DCL boolean FDECL(could_advance, (int));
99STATIC_DCL boolean FDECL(peaked_skill, (int));
100STATIC_DCL int FDECL(slots_required, (int));
101
102#ifdef OVL1
103
104STATIC_DCL char *FDECL(skill_level_name, (int,char *));
105STATIC_DCL void FDECL(skill_advance, (int));
106
107#endif	/* OVL1 */
108
109#define P_NAME(type) ((skill_names_indices[type] > 0) ? \
110		      OBJ_NAME(objects[skill_names_indices[type]]) : \
111		      (type == P_BARE_HANDED_COMBAT) ? \
112			barehands_or_martial[martial_bonus()] : \
113			odd_skill_names[-skill_names_indices[type]])
114
115#ifdef OVLB
116static NEARDATA const char kebabable[] = {
117	S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0'
118};
119
120/*
121 *	hitval returns an integer representing the "to hit" bonuses
122 *	of "otmp" against the monster.
123 */
124int
125hitval(otmp, mon)
126struct obj *otmp;
127struct monst *mon;
128{
129	int	tmp = 0;
130	struct permonst *ptr = mon->data;
131	boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
132
133	if (Is_weapon)
134		tmp += otmp->spe;
135
136/*	Put weapon specific "to hit" bonuses in below:		*/
137	tmp += objects[otmp->otyp].oc_hitbon;
138
139/*	Put weapon vs. monster type "to hit" bonuses in below:	*/
140
141	/* Blessed weapons used against undead or demons */
142	if (Is_weapon && otmp->blessed &&
143	   (is_demon(ptr) || is_undead(ptr))) tmp += 2;
144
145	if (is_spear(otmp) &&
146	   index(kebabable, ptr->mlet)) tmp += 2;
147
148	/* trident is highly effective against swimmers */
149	if (otmp->otyp == TRIDENT && is_swimmer(ptr)) {
150	   if (is_pool(mon->mx, mon->my)) tmp += 4;
151	   else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE) tmp += 2;
152	}
153
154	/* Picks used against xorns and earth elementals */
155	if (is_pick(otmp) &&
156	   (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2;
157
158#ifdef INVISIBLE_OBJECTS
159	/* Invisible weapons against monsters who can't see invisible */
160	if (otmp->oinvis && !perceives(ptr)) tmp += 3;
161#endif
162
163	/* Check specially named weapon "to hit" bonuses */
164	if (otmp->oartifact) tmp += spec_abon(otmp, mon);
165
166	return tmp;
167}
168
169/* Historical note: The original versions of Hack used a range of damage
170 * which was similar to, but not identical to the damage used in Advanced
171 * Dungeons and Dragons.  I figured that since it was so close, I may as well
172 * make it exactly the same as AD&D, adding some more weapons in the process.
173 * This has the advantage that it is at least possible that the player would
174 * already know the damage of at least some of the weapons.  This was circa
175 * 1987 and I used the table from Unearthed Arcana until I got tired of typing
176 * them in (leading to something of an imbalance towards weapons early in
177 * alphabetical order).  The data structure still doesn't include fields that
178 * fully allow the appropriate damage to be described (there's no way to say
179 * 3d6 or 1d6+1) so we add on the extra damage in dmgval() if the weapon
180 * doesn't do an exact die of damage.
181 *
182 * Of course new weapons were added later in the development of Nethack.  No
183 * AD&D consistency was kept, but most of these don't exist in AD&D anyway.
184 *
185 * Second edition AD&D came out a few years later; luckily it used the same
186 * table.  As of this writing (1999), third edition is in progress but not
187 * released.  Let's see if the weapon table stays the same.  --KAA
188 * October 2000: It didn't.  Oh, well.
189 */
190
191/*
192 *	dmgval returns an integer representing the damage bonuses
193 *	of "otmp" against the monster.
194 */
195int
196dmgval(otmp, mon)
197struct obj *otmp;
198struct monst *mon;
199{
200	int tmp = 0, otyp = otmp->otyp;
201	struct permonst *ptr = mon->data;
202	boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
203
204	if (otyp == CREAM_PIE) return 0;
205
206	if (bigmonst(ptr)) {
207	    if (objects[otyp].oc_wldam)
208		tmp = rnd(objects[otyp].oc_wldam);
209	    switch (otyp) {
210		case IRON_CHAIN:
211		case CROSSBOW_BOLT:
212		case MORNING_STAR:
213		case PARTISAN:
214		case RUNESWORD:
215		case ELVEN_BROADSWORD:
216		case BROADSWORD:	tmp++; break;
217
218		case FLAIL:
219		case RANSEUR:
220		case VOULGE:		tmp += rnd(4); break;
221
222		case ACID_VENOM:
223		case HALBERD:
224		case SPETUM:		tmp += rnd(6); break;
225
226		case BATTLE_AXE:
227		case BARDICHE:
228		case TRIDENT:		tmp += d(2,4); break;
229
230		case TSURUGI:
231		case DWARVISH_MATTOCK:
232		case TWO_HANDED_SWORD:	tmp += d(2,6); break;
233	    }
234	} else {
235	    if (objects[otyp].oc_wsdam)
236		tmp = rnd(objects[otyp].oc_wsdam);
237	    switch (otyp) {
238		case IRON_CHAIN:
239		case CROSSBOW_BOLT:
240		case MACE:
241		case WAR_HAMMER:
242		case FLAIL:
243		case SPETUM:
244		case TRIDENT:		tmp++; break;
245
246		case BATTLE_AXE:
247		case BARDICHE:
248		case BILL_GUISARME:
249		case GUISARME:
250		case LUCERN_HAMMER:
251		case MORNING_STAR:
252		case RANSEUR:
253		case BROADSWORD:
254		case ELVEN_BROADSWORD:
255		case RUNESWORD:
256		case VOULGE:		tmp += rnd(4); break;
257
258		case ACID_VENOM:	tmp += rnd(6); break;
259	    }
260	}
261	if (Is_weapon) {
262		tmp += otmp->spe;
263		/* negative enchantment mustn't produce negative damage */
264		if (tmp < 0) tmp = 0;
265	}
266
267	if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr))
268		/* thick skinned/scaled creatures don't feel it */
269		tmp = 0;
270	if (ptr == &mons[PM_SHADE] && objects[otyp].oc_material != SILVER)
271		tmp = 0;
272
273	/* "very heavy iron ball"; weight increase is in increments of 160 */
274	if (otyp == HEAVY_IRON_BALL && tmp > 0) {
275	    int wt = (int)objects[HEAVY_IRON_BALL].oc_weight;
276
277	    if ((int)otmp->owt > wt) {
278		wt = ((int)otmp->owt - wt) / 160;
279		tmp += rnd(4 * wt);
280		if (tmp > 25) tmp = 25;	/* objects[].oc_wldam */
281	    }
282	}
283
284/*	Put weapon vs. monster type damage bonuses in below:	*/
285	if (Is_weapon || otmp->oclass == GEM_CLASS ||
286		otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) {
287	    int bonus = 0;
288
289	    if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
290		bonus += rnd(4);
291	    if (is_axe(otmp) && is_wooden(ptr))
292		bonus += rnd(4);
293	    if (objects[otyp].oc_material == SILVER && hates_silver(ptr))
294		bonus += rnd(20);
295
296	    /* if the weapon is going to get a double damage bonus, adjust
297	       this bonus so that effectively it's added after the doubling */
298	    if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25)
299		bonus = (bonus + 1) / 2;
300
301	    tmp += bonus;
302	}
303
304	if (tmp > 0) {
305		/* It's debateable whether a rusted blunt instrument
306		   should do less damage than a pristine one, since
307		   it will hit with essentially the same impact, but
308		   there ought to some penalty for using damaged gear
309		   so always subtract erosion even for blunt weapons. */
310		tmp -= greatest_erosion(otmp);
311		if (tmp < 1) tmp = 1;
312	}
313
314	return(tmp);
315}
316
317#endif /* OVLB */
318#ifdef OVL0
319
320STATIC_DCL struct obj *FDECL(oselect, (struct monst *,int));
321#define Oselect(x)	if ((otmp = oselect(mtmp, x)) != 0) return(otmp);
322
323STATIC_OVL struct obj *
324oselect(mtmp, x)
325struct monst *mtmp;
326int x;
327{
328	struct obj *otmp;
329
330	for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
331	    if (otmp->otyp == x &&
332		    /* never select non-cockatrice corpses */
333		    !((x == CORPSE || x == EGG) &&
334			!touch_petrifies(&mons[otmp->corpsenm])) &&
335		    (!otmp->oartifact || touch_artifact(otmp,mtmp)))
336		return otmp;
337	}
338	return (struct obj *)0;
339}
340
341static NEARDATA const int rwep[] =
342{	DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR,
343	JAVELIN, SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW,
344	ORCISH_ARROW, CROSSBOW_BOLT, SILVER_DAGGER, ELVEN_DAGGER, DAGGER,
345	ORCISH_DAGGER, KNIFE, FLINT, ROCK, LOADSTONE, LUCKSTONE, DART,
346	/* BOOMERANG, */ CREAM_PIE
347	/* note: CREAM_PIE should NOT be #ifdef KOPS */
348};
349
350static NEARDATA const int pwep[] =
351{	HALBERD, BARDICHE, SPETUM, BILL_GUISARME, VOULGE, RANSEUR, GUISARME,
352	GLAIVE, LUCERN_HAMMER, BEC_DE_CORBIN, FAUCHARD, PARTISAN, LANCE
353};
354
355static struct obj *propellor;
356
357struct obj *
358select_rwep(mtmp)	/* select a ranged weapon for the monster */
359register struct monst *mtmp;
360{
361	register struct obj *otmp;
362	int i;
363
364#ifdef KOPS
365	char mlet = mtmp->data->mlet;
366#endif
367
368	propellor = &zeroobj;
369	Oselect(EGG); /* cockatrice egg */
370#ifdef KOPS
371	if(mlet == S_KOP)	/* pies are first choice for Kops */
372	    Oselect(CREAM_PIE);
373#endif
374	if(throws_rocks(mtmp->data))	/* ...boulders for giants */
375	    Oselect(BOULDER);
376
377	/* Select polearms first; they do more damage and aren't expendable */
378	/* The limit of 13 here is based on the monster polearm range limit
379	 * (defined as 5 in mthrowu.c).  5 corresponds to a distance of 2 in
380	 * one direction and 1 in another; one space beyond that would be 3 in
381	 * one direction and 2 in another; 3^2+2^2=13.
382	 */
383	if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 13 && couldsee(mtmp->mx, mtmp->my)) {
384	    for (i = 0; i < SIZE(pwep); i++) {
385		/* Only strong monsters can wield big (esp. long) weapons.
386		 * Big weapon is basically the same as bimanual.
387		 * All monsters can wield the remaining weapons.
388		 */
389		if (((strongmonst(mtmp->data) && (mtmp->misc_worn_check & W_ARMS) == 0)
390			|| !objects[pwep[i]].oc_bimanual) &&
391		    (objects[pwep[i]].oc_material != SILVER
392			|| !hates_silver(mtmp->data))) {
393		    if ((otmp = oselect(mtmp, pwep[i])) != 0) {
394			propellor = otmp; /* force the monster to wield it */
395			return otmp;
396		    }
397		}
398	    }
399	}
400
401	/*
402	 * other than these two specific cases, always select the
403	 * most potent ranged weapon to hand.
404	 */
405	for (i = 0; i < SIZE(rwep); i++) {
406	    int prop;
407
408	    /* shooting gems from slings; this goes just before the darts */
409	    /* (shooting rocks is already handled via the rwep[] ordering) */
410	    if (rwep[i] == DART && !likes_gems(mtmp->data) &&
411		    m_carrying(mtmp, SLING)) {		/* propellor */
412		for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
413		    if (otmp->oclass == GEM_CLASS &&
414			    (otmp->otyp != LOADSTONE || !otmp->cursed)) {
415			propellor = m_carrying(mtmp, SLING);
416			return otmp;
417		    }
418	    }
419
420		/* KMH -- This belongs here so darts will work */
421	    propellor = &zeroobj;
422
423	    prop = (objects[rwep[i]]).oc_skill;
424	    if (prop < 0) {
425		switch (-prop) {
426		case P_BOW:
427		  propellor = (oselect(mtmp, YUMI));
428		  if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW));
429		  if (!propellor) propellor = (oselect(mtmp, BOW));
430		  if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW));
431		  break;
432		case P_SLING:
433		  propellor = (oselect(mtmp, SLING));
434		  break;
435		case P_CROSSBOW:
436		  propellor = (oselect(mtmp, CROSSBOW));
437		}
438		if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor
439				&& mtmp->weapon_check == NO_WEAPON_WANTED)
440			propellor = 0;
441	    }
442	    /* propellor = obj, propellor to use
443	     * propellor = &zeroobj, doesn't need a propellor
444	     * propellor = 0, needed one and didn't have one
445	     */
446	    if (propellor != 0) {
447		/* Note: cannot use m_carrying for loadstones, since it will
448		 * always select the first object of a type, and maybe the
449		 * monster is carrying two but only the first is unthrowable.
450		 */
451		if (rwep[i] != LOADSTONE) {
452			/* Don't throw a cursed weapon-in-hand or an artifact */
453			if ((otmp = oselect(mtmp, rwep[i])) && !otmp->oartifact
454			    && (!otmp->cursed || otmp != MON_WEP(mtmp)))
455				return(otmp);
456		} else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
457		    if (otmp->otyp == LOADSTONE && !otmp->cursed)
458			return otmp;
459		}
460	    }
461	  }
462
463	/* failure */
464	return (struct obj *)0;
465}
466
467/* Weapons in order of preference */
468static const NEARDATA short hwep[] = {
469	  CORPSE,  /* cockatrice corpse */
470	  TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE,
471	  KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD,
472	  ELVEN_BROADSWORD, BROADSWORD, SCIMITAR, SILVER_SABER,
473	  MORNING_STAR, ELVEN_SHORT_SWORD, DWARVISH_SHORT_SWORD, SHORT_SWORD,
474	  ORCISH_SHORT_SWORD, MACE, AXE, DWARVISH_SPEAR, SILVER_SPEAR,
475	  ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL, BULLWHIP, QUARTERSTAFF,
476	  JAVELIN, AKLYS, CLUB, PICK_AXE,
477#ifdef KOPS
478	  RUBBER_HOSE,
479#endif /* KOPS */
480	  WAR_HAMMER, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER,
481	  ATHAME, SCALPEL, KNIFE, WORM_TOOTH
482	};
483
484struct obj *
485select_hwep(mtmp)	/* select a hand to hand weapon for the monster */
486register struct monst *mtmp;
487{
488	register struct obj *otmp;
489	register int i;
490	boolean strong = strongmonst(mtmp->data);
491	boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0;
492
493	/* prefer artifacts to everything else */
494	for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) {
495		if (otmp->oclass == WEAPON_CLASS
496			&& otmp->oartifact && touch_artifact(otmp,mtmp)
497			&& ((strong && !wearing_shield)
498			    || !objects[otmp->otyp].oc_bimanual))
499		    return otmp;
500	}
501
502	if(is_giant(mtmp->data))	/* giants just love to use clubs */
503	    Oselect(CLUB);
504
505	/* only strong monsters can wield big (esp. long) weapons */
506	/* big weapon is basically the same as bimanual */
507	/* all monsters can wield the remaining weapons */
508	for (i = 0; i < SIZE(hwep); i++) {
509	    if (hwep[i] == CORPSE && !(mtmp->misc_worn_check & W_ARMG))
510		continue;
511	    if (((strong && !wearing_shield)
512			|| !objects[hwep[i]].oc_bimanual) &&
513		    (objects[hwep[i]].oc_material != SILVER
514			|| !hates_silver(mtmp->data)))
515		Oselect(hwep[i]);
516	}
517
518	/* failure */
519	return (struct obj *)0;
520}
521
522/* Called after polymorphing a monster, robbing it, etc....  Monsters
523 * otherwise never unwield stuff on their own.  Might print message.
524 */
525void
526possibly_unwield(mon, polyspot)
527struct monst *mon;
528boolean polyspot;
529{
530	struct obj *obj, *mw_tmp;
531
532	if (!(mw_tmp = MON_WEP(mon)))
533		return;
534	for (obj = mon->minvent; obj; obj = obj->nobj)
535		if (obj == mw_tmp) break;
536	if (!obj) { /* The weapon was stolen or destroyed */
537		MON_NOWEP(mon);
538		mon->weapon_check = NEED_WEAPON;
539		return;
540	}
541	if (!attacktype(mon->data, AT_WEAP)) {
542		setmnotwielded(mon, mw_tmp);
543		MON_NOWEP(mon);
544		mon->weapon_check = NO_WEAPON_WANTED;
545		obj_extract_self(obj);
546		if (cansee(mon->mx, mon->my)) {
547		    pline("%s drops %s.", Monnam(mon),
548			  distant_name(obj, doname));
549		    newsym(mon->mx, mon->my);
550		}
551		/* might be dropping object into water or lava */
552		if (!flooreffects(obj, mon->mx, mon->my, "drop")) {
553		    if (polyspot) bypass_obj(obj);
554		    place_object(obj, mon->mx, mon->my);
555		    stackobj(obj);
556		}
557		return;
558	}
559	/* The remaining case where there is a change is where a monster
560	 * is polymorphed into a stronger/weaker monster with a different
561	 * choice of weapons.  This has no parallel for players.  It can
562	 * be handled by waiting until mon_wield_item is actually called.
563	 * Though the monster still wields the wrong weapon until then,
564	 * this is OK since the player can't see it.  (FIXME: Not okay since
565	 * probing can reveal it.)
566	 * Note that if there is no change, setting the check to NEED_WEAPON
567	 * is harmless.
568	 * Possible problem: big monster with big cursed weapon gets
569	 * polymorphed into little monster.  But it's not quite clear how to
570	 * handle this anyway....
571	 */
572	if (!(mw_tmp->cursed && mon->weapon_check == NO_WEAPON_WANTED))
573	    mon->weapon_check = NEED_WEAPON;
574	return;
575}
576
577/* Let a monster try to wield a weapon, based on mon->weapon_check.
578 * Returns 1 if the monster took time to do it, 0 if it did not.
579 */
580int
581mon_wield_item(mon)
582register struct monst *mon;
583{
584	struct obj *obj;
585
586	/* This case actually should never happen */
587	if (mon->weapon_check == NO_WEAPON_WANTED) return 0;
588	switch(mon->weapon_check) {
589		case NEED_HTH_WEAPON:
590			obj = select_hwep(mon);
591			break;
592		case NEED_RANGED_WEAPON:
593			(void)select_rwep(mon);
594			obj = propellor;
595			break;
596		case NEED_PICK_AXE:
597			obj = m_carrying(mon, PICK_AXE);
598			/* KMH -- allow other picks */
599			if (!obj && !which_armor(mon, W_ARMS))
600			    obj = m_carrying(mon, DWARVISH_MATTOCK);
601			break;
602		case NEED_AXE:
603			/* currently, only 2 types of axe */
604			obj = m_carrying(mon, BATTLE_AXE);
605			if (!obj || which_armor(mon, W_ARMS))
606			    obj = m_carrying(mon, AXE);
607			break;
608		case NEED_PICK_OR_AXE:
609			/* prefer pick for fewer switches on most levels */
610			obj = m_carrying(mon, DWARVISH_MATTOCK);
611			if (!obj) obj = m_carrying(mon, BATTLE_AXE);
612			if (!obj || which_armor(mon, W_ARMS)) {
613			    obj = m_carrying(mon, PICK_AXE);
614			    if (!obj) obj = m_carrying(mon, AXE);
615			}
616			break;
617		default: impossible("weapon_check %d for %s?",
618				mon->weapon_check, mon_nam(mon));
619			return 0;
620	}
621	if (obj && obj != &zeroobj) {
622		struct obj *mw_tmp = MON_WEP(mon);
623		if (mw_tmp && mw_tmp->otyp == obj->otyp) {
624		/* already wielding it */
625			mon->weapon_check = NEED_WEAPON;
626			return 0;
627		}
628		/* Actually, this isn't necessary--as soon as the monster
629		 * wields the weapon, the weapon welds itself, so the monster
630		 * can know it's cursed and needn't even bother trying.
631		 * Still....
632		 */
633		if (mw_tmp && mw_tmp->cursed && mw_tmp->otyp != CORPSE) {
634		    if (canseemon(mon)) {
635			char welded_buf[BUFSZ];
636			const char *mon_hand = mbodypart(mon, HAND);
637
638			if (bimanual(mw_tmp)) mon_hand = makeplural(mon_hand);
639			Sprintf(welded_buf, "%s welded to %s %s",
640				otense(mw_tmp, "are"),
641				mhis(mon), mon_hand);
642
643			if (obj->otyp == PICK_AXE) {
644			    pline("Since %s weapon%s %s,",
645				  s_suffix(mon_nam(mon)),
646				  plur(mw_tmp->quan), welded_buf);
647			    pline("%s cannot wield that %s.",
648				mon_nam(mon), xname(obj));
649			} else {
650			    pline("%s tries to wield %s.", Monnam(mon),
651				doname(obj));
652			    pline("%s %s %s!",
653				  s_suffix(Monnam(mon)),
654				  xname(mw_tmp), welded_buf);
655			}
656			mw_tmp->bknown = 1;
657		    }
658		    mon->weapon_check = NO_WEAPON_WANTED;
659		    return 1;
660		}
661		mon->mw = obj;		/* wield obj */
662		setmnotwielded(mon, mw_tmp);
663		mon->weapon_check = NEED_WEAPON;
664		if (canseemon(mon)) {
665		    pline("%s wields %s!", Monnam(mon), doname(obj));
666		    if (obj->cursed && obj->otyp != CORPSE) {
667			pline("%s %s to %s %s!",
668			    Tobjnam(obj, "weld"),
669			    is_plural(obj) ? "themselves" : "itself",
670			    s_suffix(mon_nam(mon)), mbodypart(mon,HAND));
671			obj->bknown = 1;
672		    }
673		}
674		if (artifact_light(obj) && !obj->lamplit) {
675		    begin_burn(obj, FALSE);
676		    if (canseemon(mon))
677			pline("%s brilliantly in %s %s!",
678			    Tobjnam(obj, "glow"),
679			    s_suffix(mon_nam(mon)), mbodypart(mon,HAND));
680		}
681		obj->owornmask = W_WEP;
682		return 1;
683	}
684	mon->weapon_check = NEED_WEAPON;
685	return 0;
686}
687
688int
689abon()		/* attack bonus for strength & dexterity */
690{
691	int sbon;
692	int str = ACURR(A_STR), dex = ACURR(A_DEX);
693
694	if (Upolyd) return(adj_lev(&mons[u.umonnum]) - 3);
695	if (str < 6) sbon = -2;
696	else if (str < 8) sbon = -1;
697	else if (str < 17) sbon = 0;
698	else if (str <= STR18(50)) sbon = 1;	/* up to 18/50 */
699	else if (str < STR18(100)) sbon = 2;
700	else sbon = 3;
701
702/* Game tuning kludge: make it a bit easier for a low level character to hit */
703	sbon += (u.ulevel < 3) ? 1 : 0;
704
705	if (dex < 4) return(sbon-3);
706	else if (dex < 6) return(sbon-2);
707	else if (dex < 8) return(sbon-1);
708	else if (dex < 14) return(sbon);
709	else return(sbon + dex-14);
710}
711
712#endif /* OVL0 */
713#ifdef OVL1
714
715int
716dbon()		/* damage bonus for strength */
717{
718	int str = ACURR(A_STR);
719
720	if (Upolyd) return(0);
721
722	if (str < 6) return(-1);
723	else if (str < 16) return(0);
724	else if (str < 18) return(1);
725	else if (str == 18) return(2);		/* up to 18 */
726	else if (str <= STR18(75)) return(3);		/* up to 18/75 */
727	else if (str <= STR18(90)) return(4);		/* up to 18/90 */
728	else if (str < STR18(100)) return(5);		/* up to 18/99 */
729	else return(6);
730}
731
732
733/* copy the skill level name into the given buffer */
734STATIC_OVL char *
735skill_level_name(skill, buf)
736int skill;
737char *buf;
738{
739    const char *ptr;
740
741    switch (P_SKILL(skill)) {
742	case P_UNSKILLED:    ptr = "Unskilled"; break;
743	case P_BASIC:	     ptr = "Basic";     break;
744	case P_SKILLED:	     ptr = "Skilled";   break;
745	case P_EXPERT:	     ptr = "Expert";    break;
746	/* these are for unarmed combat/martial arts only */
747	case P_MASTER:	     ptr = "Master";    break;
748	case P_GRAND_MASTER: ptr = "Grand Master"; break;
749	default:	     ptr = "Unknown";	break;
750    }
751    Strcpy(buf, ptr);
752    return buf;
753}
754
755/* return the # of slots required to advance the skill */
756STATIC_OVL int
757slots_required(skill)
758int skill;
759{
760    int tmp = P_SKILL(skill);
761
762    /* The more difficult the training, the more slots it takes.
763     *	unskilled -> basic	1
764     *	basic -> skilled	2
765     *	skilled -> expert	3
766     */
767    if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT)
768	return tmp;
769
770    /* Fewer slots used up for unarmed or martial.
771     *	unskilled -> basic	1
772     *	basic -> skilled	1
773     *	skilled -> expert	2
774     *	expert -> master	2
775     *	master -> grand master	3
776     */
777    return (tmp + 1) / 2;
778}
779
780/* return true if this skill can be advanced */
781/*ARGSUSED*/
782STATIC_OVL boolean
783can_advance(skill, speedy)
784int skill;
785boolean speedy;
786{
787    return !P_RESTRICTED(skill)
788	    && P_SKILL(skill) < P_MAX_SKILL(skill) && (
789#ifdef WIZARD
790	    (wizard && speedy) ||
791#endif
792	    (P_ADVANCE(skill) >=
793		(unsigned) practice_needed_to_advance(P_SKILL(skill))
794	    && u.skills_advanced < P_SKILL_LIMIT
795	    && u.weapon_slots >= slots_required(skill)));
796}
797
798/* return true if this skill could be advanced if more slots were available */
799STATIC_OVL boolean
800could_advance(skill)
801int skill;
802{
803    return !P_RESTRICTED(skill)
804	    && P_SKILL(skill) < P_MAX_SKILL(skill) && (
805	    (P_ADVANCE(skill) >=
806		(unsigned) practice_needed_to_advance(P_SKILL(skill))
807	    && u.skills_advanced < P_SKILL_LIMIT));
808}
809
810/* return true if this skill has reached its maximum and there's been enough
811   practice to become eligible for the next step if that had been possible */
812STATIC_OVL boolean
813peaked_skill(skill)
814int skill;
815{
816    return !P_RESTRICTED(skill)
817	    && P_SKILL(skill) >= P_MAX_SKILL(skill) && (
818	    (P_ADVANCE(skill) >=
819		(unsigned) practice_needed_to_advance(P_SKILL(skill))));
820}
821
822STATIC_OVL void
823skill_advance(skill)
824int skill;
825{
826    u.weapon_slots -= slots_required(skill);
827    P_SKILL(skill)++;
828    u.skill_record[u.skills_advanced++] = skill;
829    /* subtly change the advance message to indicate no more advancement */
830    You("are now %s skilled in %s.",
831	P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more",
832	P_NAME(skill));
833}
834
835const static struct skill_range {
836	short first, last;
837	const char *name;
838} skill_ranges[] = {
839    { P_FIRST_H_TO_H, P_LAST_H_TO_H, "Fighting Skills" },
840    { P_FIRST_WEAPON, P_LAST_WEAPON, "Weapon Skills" },
841    { P_FIRST_SPELL,  P_LAST_SPELL,  "Spellcasting Skills" },
842};
843
844/*
845 * The `#enhance' extended command.  What we _really_ would like is
846 * to keep being able to pick things to advance until we couldn't any
847 * more.  This is currently not possible -- the menu code has no way
848 * to call us back for instant action.  Even if it did, we would also need
849 * to be able to update the menu since selecting one item could make
850 * others unselectable.
851 */
852int
853enhance_weapon_skill()
854{
855    int pass, i, n, len, longest,
856	to_advance, eventually_advance, maxxed_cnt;
857    char buf[BUFSZ], sklnambuf[BUFSZ];
858    const char *prefix;
859    menu_item *selected;
860    anything any;
861    winid win;
862    boolean speedy = FALSE;
863
864#ifdef WIZARD
865	if (wizard && yn("Advance skills without practice?") == 'y')
866	    speedy = TRUE;
867#endif
868
869	do {
870	    /* find longest available skill name, count those that can advance */
871	    to_advance = eventually_advance = maxxed_cnt = 0;
872	    for (longest = 0, i = 0; i < P_NUM_SKILLS; i++) {
873		if (P_RESTRICTED(i)) continue;
874		if ((len = strlen(P_NAME(i))) > longest)
875		    longest = len;
876		if (can_advance(i, speedy)) to_advance++;
877		else if (could_advance(i)) eventually_advance++;
878		else if (peaked_skill(i)) maxxed_cnt++;
879	    }
880
881	    win = create_nhwindow(NHW_MENU);
882	    start_menu(win);
883
884	    /* start with a legend if any entries will be annotated
885	       with "*" or "#" below */
886	    if (eventually_advance > 0 || maxxed_cnt > 0) {
887		any.a_void = 0;
888		if (eventually_advance > 0) {
889		    Sprintf(buf,
890			    "(Skill%s flagged by \"*\" may be enhanced %s.)",
891			    plur(eventually_advance),
892			    (u.ulevel < MAXULEV) ?
893				"when you're more experienced" :
894				"if skill slots become available");
895		    add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
896			     buf, MENU_UNSELECTED);
897		}
898		if (maxxed_cnt > 0) {
899		    Sprintf(buf,
900		  "(Skill%s flagged by \"#\" cannot be enhanced any further.)",
901			    plur(maxxed_cnt));
902		    add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
903			     buf, MENU_UNSELECTED);
904		}
905		add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
906			     "", MENU_UNSELECTED);
907	    }
908
909	    /* List the skills, making ones that could be advanced
910	       selectable.  List the miscellaneous skills first.
911	       Possible future enhancement:  list spell skills before
912	       weapon skills for spellcaster roles. */
913	  for (pass = 0; pass < SIZE(skill_ranges); pass++)
914	    for (i = skill_ranges[pass].first;
915		 i <= skill_ranges[pass].last; i++) {
916		/* Print headings for skill types */
917		any.a_void = 0;
918		if (i == skill_ranges[pass].first)
919		    add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
920			     skill_ranges[pass].name, MENU_UNSELECTED);
921
922		if (P_RESTRICTED(i)) continue;
923		/*
924		 * Sigh, this assumes a monospaced font unless
925		 * iflags.menu_tab_sep is set in which case it puts
926		 * tabs between columns.
927		 * The 12 is the longest skill level name.
928		 * The "    " is room for a selection letter and dash, "a - ".
929		 */
930		if (can_advance(i, speedy))
931		    prefix = "";	/* will be preceded by menu choice */
932		else if (could_advance(i))
933		    prefix = "  * ";
934		else if (peaked_skill(i))
935		    prefix = "  # ";
936		else
937		    prefix = (to_advance + eventually_advance +
938				maxxed_cnt > 0) ? "    " : "";
939		(void) skill_level_name(i, sklnambuf);
940#ifdef WIZARD
941		if (wizard) {
942		    if (!iflags.menu_tab_sep)
943			Sprintf(buf, " %s%-*s %-12s %5d(%4d)",
944			    prefix, longest, P_NAME(i), sklnambuf,
945			    P_ADVANCE(i),
946			    practice_needed_to_advance(P_SKILL(i)));
947		    else
948			Sprintf(buf, " %s%s\t%s\t%5d(%4d)",
949			    prefix, P_NAME(i), sklnambuf,
950			    P_ADVANCE(i),
951			    practice_needed_to_advance(P_SKILL(i)));
952		 } else
953#endif
954		{
955		    if (!iflags.menu_tab_sep)
956			Sprintf(buf, " %s %-*s [%s]",
957			    prefix, longest, P_NAME(i), sklnambuf);
958		    else
959			Sprintf(buf, " %s%s\t[%s]",
960			    prefix, P_NAME(i), sklnambuf);
961		}
962		any.a_int = can_advance(i, speedy) ? i+1 : 0;
963		add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
964			 buf, MENU_UNSELECTED);
965	    }
966
967	    Strcpy(buf, (to_advance > 0) ? "Pick a skill to advance:" :
968					   "Current skills:");
969#ifdef WIZARD
970	    if (wizard && !speedy)
971		Sprintf(eos(buf), "  (%d slot%s available)",
972			u.weapon_slots, plur(u.weapon_slots));
973#endif
974	    end_menu(win, buf);
975	    n = select_menu(win, to_advance ? PICK_ONE : PICK_NONE, &selected);
976	    destroy_nhwindow(win);
977	    if (n > 0) {
978		n = selected[0].item.a_int - 1;	/* get item selected */
979		free((genericptr_t)selected);
980		skill_advance(n);
981		/* check for more skills able to advance, if so then .. */
982		for (n = i = 0; i < P_NUM_SKILLS; i++) {
983		    if (can_advance(i, speedy)) {
984			if (!speedy) You_feel("you could be more dangerous!");
985			n++;
986			break;
987		    }
988		}
989	    }
990	} while (speedy && n > 0);
991	return 0;
992}
993
994/*
995 * Change from restricted to unrestricted, allowing P_BASIC as max.  This
996 * function may be called with with P_NONE.  Used in pray.c.
997 */
998void
999unrestrict_weapon_skill(skill)
1000int skill;
1001{
1002    if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) {
1003	P_SKILL(skill) = P_UNSKILLED;
1004	P_MAX_SKILL(skill) = P_BASIC;
1005	P_ADVANCE(skill) = 0;
1006    }
1007}
1008
1009#endif /* OVL1 */
1010#ifdef OVLB
1011
1012void
1013use_skill(skill,degree)
1014int skill;
1015int degree;
1016{
1017    boolean advance_before;
1018
1019    if (skill != P_NONE && !P_RESTRICTED(skill)) {
1020	advance_before = can_advance(skill, FALSE);
1021	P_ADVANCE(skill)+=degree;
1022	if (!advance_before && can_advance(skill, FALSE))
1023	    give_may_advance_msg(skill);
1024    }
1025}
1026
1027void
1028add_weapon_skill(n)
1029int n;	/* number of slots to gain; normally one */
1030{
1031    int i, before, after;
1032
1033    for (i = 0, before = 0; i < P_NUM_SKILLS; i++)
1034	if (can_advance(i, FALSE)) before++;
1035    u.weapon_slots += n;
1036    for (i = 0, after = 0; i < P_NUM_SKILLS; i++)
1037	if (can_advance(i, FALSE)) after++;
1038    if (before < after)
1039	give_may_advance_msg(P_NONE);
1040}
1041
1042void
1043lose_weapon_skill(n)
1044int n;	/* number of slots to lose; normally one */
1045{
1046    int skill;
1047
1048    while (--n >= 0) {
1049	/* deduct first from unused slots, then from last placed slot, if any */
1050	if (u.weapon_slots) {
1051	    u.weapon_slots--;
1052	} else if (u.skills_advanced) {
1053	    skill = u.skill_record[--u.skills_advanced];
1054	    if (P_SKILL(skill) <= P_UNSKILLED)
1055		panic("lose_weapon_skill (%d)", skill);
1056	    P_SKILL(skill)--;	/* drop skill one level */
1057	    /* Lost skill might have taken more than one slot; refund rest. */
1058	    u.weapon_slots = slots_required(skill) - 1;
1059	    /* It might now be possible to advance some other pending
1060	       skill by using the refunded slots, but giving a message
1061	       to that effect would seem pretty confusing.... */
1062	}
1063    }
1064}
1065
1066int
1067weapon_type(obj)
1068struct obj *obj;
1069{
1070	/* KMH -- now uses the object table */
1071	int type;
1072
1073	if (!obj)
1074		/* Not using a weapon */
1075		return (P_BARE_HANDED_COMBAT);
1076	if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS &&
1077	    obj->oclass != GEM_CLASS)
1078		/* Not a weapon, weapon-tool, or ammo */
1079		return (P_NONE);
1080	type = objects[obj->otyp].oc_skill;
1081	return ((type < 0) ? -type : type);
1082}
1083
1084int
1085uwep_skill_type()
1086{
1087	if (u.twoweap)
1088		return P_TWO_WEAPON_COMBAT;
1089	return weapon_type(uwep);
1090}
1091
1092/*
1093 * Return hit bonus/penalty based on skill of weapon.
1094 * Treat restricted weapons as unskilled.
1095 */
1096int
1097weapon_hit_bonus(weapon)
1098struct obj *weapon;
1099{
1100    int type, wep_type, skill, bonus = 0;
1101    static const char bad_skill[] = "weapon_hit_bonus: bad skill %d";
1102
1103    wep_type = weapon_type(weapon);
1104    /* use two weapon skill only if attacking with one of the wielded weapons */
1105    type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ?
1106	    P_TWO_WEAPON_COMBAT : wep_type;
1107    if (type == P_NONE) {
1108	bonus = 0;
1109    } else if (type <= P_LAST_WEAPON) {
1110	switch (P_SKILL(type)) {
1111	    default: impossible(bad_skill, P_SKILL(type)); /* fall through */
1112	    case P_ISRESTRICTED:
1113	    case P_UNSKILLED:   bonus = -4; break;
1114	    case P_BASIC:       bonus =  0; break;
1115	    case P_SKILLED:     bonus =  2; break;
1116	    case P_EXPERT:      bonus =  3; break;
1117	}
1118    } else if (type == P_TWO_WEAPON_COMBAT) {
1119	skill = P_SKILL(P_TWO_WEAPON_COMBAT);
1120	if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type);
1121	switch (skill) {
1122	    default: impossible(bad_skill, skill); /* fall through */
1123	    case P_ISRESTRICTED:
1124	    case P_UNSKILLED:   bonus = -9; break;
1125	    case P_BASIC:	bonus = -7; break;
1126	    case P_SKILLED:	bonus = -5; break;
1127	    case P_EXPERT:	bonus = -3; break;
1128	}
1129    } else if (type == P_BARE_HANDED_COMBAT) {
1130	/*
1131	 *	       b.h.  m.a.
1132	 *	unskl:	+1   n/a
1133	 *	basic:	+1    +3
1134	 *	skild:	+2    +4
1135	 *	exprt:	+2    +5
1136	 *	mastr:	+3    +6
1137	 *	grand:	+3    +7
1138	 */
1139	bonus = P_SKILL(type);
1140	bonus = max(bonus,P_UNSKILLED) - 1;	/* unskilled => 0 */
1141	bonus = ((bonus + 2) * (martial_bonus() ? 2 : 1)) / 2;
1142    }
1143
1144#ifdef STEED
1145	/* KMH -- It's harder to hit while you are riding */
1146	if (u.usteed) {
1147		switch (P_SKILL(P_RIDING)) {
1148		    case P_ISRESTRICTED:
1149		    case P_UNSKILLED:   bonus -= 2; break;
1150		    case P_BASIC:       bonus -= 1; break;
1151		    case P_SKILLED:     break;
1152		    case P_EXPERT:      break;
1153		}
1154		if (u.twoweap) bonus -= 2;
1155	}
1156#endif
1157
1158    return bonus;
1159}
1160
1161/*
1162 * Return damage bonus/penalty based on skill of weapon.
1163 * Treat restricted weapons as unskilled.
1164 */
1165int
1166weapon_dam_bonus(weapon)
1167struct obj *weapon;
1168{
1169    int type, wep_type, skill, bonus = 0;
1170
1171    wep_type = weapon_type(weapon);
1172    /* use two weapon skill only if attacking with one of the wielded weapons */
1173    type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ?
1174	    P_TWO_WEAPON_COMBAT : wep_type;
1175    if (type == P_NONE) {
1176	bonus = 0;
1177    } else if (type <= P_LAST_WEAPON) {
1178	switch (P_SKILL(type)) {
1179	    default: impossible("weapon_dam_bonus: bad skill %d",P_SKILL(type));
1180		     /* fall through */
1181	    case P_ISRESTRICTED:
1182	    case P_UNSKILLED:	bonus = -2; break;
1183	    case P_BASIC:	bonus =  0; break;
1184	    case P_SKILLED:	bonus =  1; break;
1185	    case P_EXPERT:	bonus =  2; break;
1186	}
1187    } else if (type == P_TWO_WEAPON_COMBAT) {
1188	skill = P_SKILL(P_TWO_WEAPON_COMBAT);
1189	if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type);
1190	switch (skill) {
1191	    default:
1192	    case P_ISRESTRICTED:
1193	    case P_UNSKILLED:	bonus = -3; break;
1194	    case P_BASIC:	bonus = -1; break;
1195	    case P_SKILLED:	bonus = 0; break;
1196	    case P_EXPERT:	bonus = 1; break;
1197	}
1198    } else if (type == P_BARE_HANDED_COMBAT) {
1199	/*
1200	 *	       b.h.  m.a.
1201	 *	unskl:	 0   n/a
1202	 *	basic:	+1    +3
1203	 *	skild:	+1    +4
1204	 *	exprt:	+2    +6
1205	 *	mastr:	+2    +7
1206	 *	grand:	+3    +9
1207	 */
1208	bonus = P_SKILL(type);
1209	bonus = max(bonus,P_UNSKILLED) - 1;	/* unskilled => 0 */
1210	bonus = ((bonus + 1) * (martial_bonus() ? 3 : 1)) / 2;
1211    }
1212
1213#ifdef STEED
1214	/* KMH -- Riding gives some thrusting damage */
1215	if (u.usteed && type != P_TWO_WEAPON_COMBAT) {
1216		switch (P_SKILL(P_RIDING)) {
1217		    case P_ISRESTRICTED:
1218		    case P_UNSKILLED:   break;
1219		    case P_BASIC:       break;
1220		    case P_SKILLED:     bonus += 1; break;
1221		    case P_EXPERT:      bonus += 2; break;
1222		}
1223	}
1224#endif
1225
1226    return bonus;
1227}
1228
1229/*
1230 * Initialize weapon skill array for the game.  Start by setting all
1231 * skills to restricted, then set the skill for every weapon the
1232 * hero is holding, finally reading the given array that sets
1233 * maximums.
1234 */
1235void
1236skill_init(class_skill)
1237const struct def_skill *class_skill;
1238{
1239	struct obj *obj;
1240	int skmax, skill;
1241
1242	/* initialize skill array; by default, everything is restricted */
1243	for (skill = 0; skill < P_NUM_SKILLS; skill++) {
1244	    P_SKILL(skill) = P_ISRESTRICTED;
1245	    P_MAX_SKILL(skill) = P_ISRESTRICTED;
1246	    P_ADVANCE(skill) = 0;
1247	}
1248
1249	/* Set skill for all weapons in inventory to be basic */
1250	for (obj = invent; obj; obj = obj->nobj) {
1251	    skill = weapon_type(obj);
1252	    if (skill != P_NONE)
1253		P_SKILL(skill) = P_BASIC;
1254	}
1255
1256	/* set skills for magic */
1257	if (Role_if(PM_HEALER) || Role_if(PM_MONK)) {
1258		P_SKILL(P_HEALING_SPELL) = P_BASIC;
1259	} else if (Role_if(PM_PRIEST)) {
1260		P_SKILL(P_CLERIC_SPELL) = P_BASIC;
1261	} else if (Role_if(PM_WIZARD)) {
1262		P_SKILL(P_ATTACK_SPELL) = P_BASIC;
1263		P_SKILL(P_ENCHANTMENT_SPELL) = P_BASIC;
1264	}
1265
1266	/* walk through array to set skill maximums */
1267	for (; class_skill->skill != P_NONE; class_skill++) {
1268	    skmax = class_skill->skmax;
1269	    skill = class_skill->skill;
1270
1271	    P_MAX_SKILL(skill) = skmax;
1272	    if (P_SKILL(skill) == P_ISRESTRICTED)	/* skill pre-set */
1273		P_SKILL(skill) = P_UNSKILLED;
1274	}
1275
1276	/* High potential fighters already know how to use their hands. */
1277	if (P_MAX_SKILL(P_BARE_HANDED_COMBAT) > P_EXPERT)
1278	    P_SKILL(P_BARE_HANDED_COMBAT) = P_BASIC;
1279
1280	/* Roles that start with a horse know how to ride it */
1281#ifdef STEED
1282	if (urole.petnum == PM_PONY)
1283	    P_SKILL(P_RIDING) = P_BASIC;
1284#endif
1285
1286	/*
1287	 * Make sure we haven't missed setting the max on a skill
1288	 * & set advance
1289	 */
1290	for (skill = 0; skill < P_NUM_SKILLS; skill++) {
1291	    if (!P_RESTRICTED(skill)) {
1292		if (P_MAX_SKILL(skill) < P_SKILL(skill)) {
1293		    impossible("skill_init: curr > max: %s", P_NAME(skill));
1294		    P_MAX_SKILL(skill) = P_SKILL(skill);
1295		}
1296		P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill)-1);
1297	    }
1298	}
1299}
1300
1301void
1302setmnotwielded(mon,obj)
1303register struct monst *mon;
1304register struct obj *obj;
1305{
1306    if (!obj) return;
1307    if (artifact_light(obj) && obj->lamplit) {
1308	end_burn(obj, FALSE);
1309	if (canseemon(mon))
1310	    pline("%s in %s %s %s glowing.", The(xname(obj)),
1311		  s_suffix(mon_nam(mon)), mbodypart(mon,HAND),
1312		  otense(obj, "stop"));
1313    }
1314    obj->owornmask &= ~W_WEP;
1315}
1316
1317#endif /* OVLB */
1318
1319/*weapon.c*/
1320