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 
29 STATIC_DCL void FDECL(give_may_advance_msg, (int));
30 
31 #ifndef OVLB
32 
33 STATIC_DCL NEARDATA const short skill_names_indices[];
34 STATIC_DCL NEARDATA const char *odd_skill_names[];
35 STATIC_DCL NEARDATA const char *barehands_or_martial[];
36 
37 #else	/* OVLB */
38 
39 STATIC_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 */
59 STATIC_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() */
77 STATIC_VAR NEARDATA const char * const barehands_or_martial[] = {
78     "bare handed combat", "martial arts"
79 };
80 
81 STATIC_OVL void
give_may_advance_msg(skill)82 give_may_advance_msg(skill)
83 int 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 
97 STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P));
98 STATIC_DCL boolean FDECL(could_advance, (int));
99 STATIC_DCL boolean FDECL(peaked_skill, (int));
100 STATIC_DCL int FDECL(slots_required, (int));
101 
102 #ifdef OVL1
103 
104 STATIC_DCL char *FDECL(skill_level_name, (int,char *));
105 STATIC_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
116 static 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  */
124 int
hitval(otmp,mon)125 hitval(otmp, mon)
126 struct obj *otmp;
127 struct 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  */
195 int
dmgval(otmp,mon)196 dmgval(otmp, mon)
197 struct obj *otmp;
198 struct 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 
320 STATIC_DCL struct obj *FDECL(oselect, (struct monst *,int));
321 #define Oselect(x)	if ((otmp = oselect(mtmp, x)) != 0) return(otmp);
322 
323 STATIC_OVL struct obj *
oselect(mtmp,x)324 oselect(mtmp, x)
325 struct monst *mtmp;
326 int 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 
341 static 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 
350 static 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 
355 static struct obj *propellor;
356 
357 struct obj *
select_rwep(mtmp)358 select_rwep(mtmp)	/* select a ranged weapon for the monster */
359 register 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 */
468 static 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 
484 struct obj *
select_hwep(mtmp)485 select_hwep(mtmp)	/* select a hand to hand weapon for the monster */
486 register 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  */
525 void
possibly_unwield(mon,polyspot)526 possibly_unwield(mon, polyspot)
527 struct monst *mon;
528 boolean 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  */
580 int
mon_wield_item(mon)581 mon_wield_item(mon)
582 register 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 
688 int
abon()689 abon()		/* 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 
715 int
dbon()716 dbon()		/* 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 */
734 STATIC_OVL char *
skill_level_name(skill,buf)735 skill_level_name(skill, buf)
736 int skill;
737 char *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 */
756 STATIC_OVL int
slots_required(skill)757 slots_required(skill)
758 int 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*/
782 STATIC_OVL boolean
can_advance(skill,speedy)783 can_advance(skill, speedy)
784 int skill;
785 boolean 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 */
799 STATIC_OVL boolean
could_advance(skill)800 could_advance(skill)
801 int 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 */
812 STATIC_OVL boolean
peaked_skill(skill)813 peaked_skill(skill)
814 int 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 
822 STATIC_OVL void
skill_advance(skill)823 skill_advance(skill)
824 int 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 
835 const 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  */
852 int
enhance_weapon_skill()853 enhance_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  */
998 void
unrestrict_weapon_skill(skill)999 unrestrict_weapon_skill(skill)
1000 int 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 
1012 void
use_skill(skill,degree)1013 use_skill(skill,degree)
1014 int skill;
1015 int 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 
1027 void
add_weapon_skill(n)1028 add_weapon_skill(n)
1029 int 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 
1042 void
lose_weapon_skill(n)1043 lose_weapon_skill(n)
1044 int 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 
1066 int
weapon_type(obj)1067 weapon_type(obj)
1068 struct 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 
1084 int
uwep_skill_type()1085 uwep_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  */
1096 int
weapon_hit_bonus(weapon)1097 weapon_hit_bonus(weapon)
1098 struct 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  */
1165 int
weapon_dam_bonus(weapon)1166 weapon_dam_bonus(weapon)
1167 struct 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  */
1235 void
skill_init(class_skill)1236 skill_init(class_skill)
1237 const 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 
1301 void
setmnotwielded(mon,obj)1302 setmnotwielded(mon,obj)
1303 register struct monst *mon;
1304 register 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