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