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