OSDN Git Service

no E-word
[nethackexpress/trunk.git] / src / weapon.c
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
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
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
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 *
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 *
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 *
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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*/