Give feedback just before timed levitation runs out
[aNetHack.git] / src / weapon.c
blob4a6ebbea37e749eb4ac328a1c8fbde03f109d08d
1 /* NetHack 3.6 weapon.c $NHDT-Date: 1454660575 2016/02/05 08:22:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.57 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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"
12 /* Categories whose names don't come from OBJ_NAME(objects[type])
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)
29 STATIC_DCL void FDECL(give_may_advance_msg, (int));
31 STATIC_VAR NEARDATA const short skill_names_indices[P_NUM_SKILLS] = {
32 0, DAGGER, KNIFE, AXE, PICK_AXE, SHORT_SWORD, BROADSWORD, LONG_SWORD,
33 TWO_HANDED_SWORD, SCIMITAR, PN_SABER, CLUB, MACE, MORNING_STAR, FLAIL,
34 PN_HAMMER, QUARTERSTAFF, PN_POLEARMS, SPEAR, TRIDENT, LANCE, BOW, SLING,
35 CROSSBOW, DART, SHURIKEN, BOOMERANG, PN_WHIP, UNICORN_HORN,
36 PN_ATTACK_SPELL, PN_HEALING_SPELL, PN_DIVINATION_SPELL,
37 PN_ENCHANTMENT_SPELL, PN_CLERIC_SPELL, PN_ESCAPE_SPELL, PN_MATTER_SPELL,
38 PN_BARE_HANDED, PN_TWO_WEAPONS, PN_RIDING
41 /* note: entry [0] isn't used */
42 STATIC_VAR NEARDATA const char *const odd_skill_names[] = {
43 "no skill", "bare hands", /* use barehands_or_martial[] instead */
44 "two weapon combat", "riding", "polearms", "saber", "hammer", "whip",
45 "attack spells", "healing spells", "divination spells",
46 "enchantment spells", "clerical spells", "escape spells", "matter spells",
48 /* indexed vis `is_martial() */
49 STATIC_VAR NEARDATA const char *const barehands_or_martial[] = {
50 "bare handed combat", "martial arts"
53 STATIC_OVL void
54 give_may_advance_msg(skill)
55 int skill;
57 You_feel("more confident in your %sskills.",
58 skill == P_NONE ? "" : skill <= P_LAST_WEAPON
59 ? "weapon "
60 : skill <= P_LAST_SPELL
61 ? "spell casting "
62 : "fighting ");
65 STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P));
66 STATIC_DCL boolean FDECL(could_advance, (int));
67 STATIC_DCL boolean FDECL(peaked_skill, (int));
68 STATIC_DCL int FDECL(slots_required, (int));
69 STATIC_DCL char *FDECL(skill_level_name, (int, char *));
70 STATIC_DCL void FDECL(skill_advance, (int));
72 #define P_NAME(type) \
73 ((skill_names_indices[type] > 0) \
74 ? OBJ_NAME(objects[skill_names_indices[type]]) \
75 : (type == P_BARE_HANDED_COMBAT) \
76 ? barehands_or_martial[martial_bonus()] \
77 : odd_skill_names[-skill_names_indices[type]])
79 static NEARDATA const char kebabable[] = { S_XORN, S_DRAGON, S_JABBERWOCK,
80 S_NAGA, S_GIANT, '\0' };
82 /* weapon's skill category name for use as generalized description of weapon;
83 mostly used to shorten "you drop your <weapon>" messages when slippery
84 fingers or polymorph causes hero to involuntarily drop wielded weapon(s) */
85 const char *
86 weapon_descr(obj)
87 struct obj *obj;
89 int skill = weapon_type(obj);
90 const char *descr = P_NAME(skill);
92 /* assorted special cases */
93 switch (skill) {
94 case P_NONE:
95 /* not a weapon or weptool: use item class name;
96 override class name "food" for corpses, tins, and eggs,
97 "large rock" for statues and boulders, and "tool" for towels */
98 descr = (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG
99 || obj->otyp == STATUE || obj->otyp == BOULDER
100 || obj->otyp == TOWEL)
101 ? OBJ_NAME(objects[obj->otyp])
102 : def_oc_syms[(int) obj->oclass].name;
103 break;
104 case P_SLING:
105 if (is_ammo(obj))
106 descr = (obj->otyp == ROCK || is_graystone(obj))
107 ? "stone"
108 /* avoid "rock"; what about known glass? */
109 : (obj->oclass == GEM_CLASS)
110 ? "gem"
111 /* in case somebody adds odd sling ammo */
112 : def_oc_syms[(int) obj->oclass].name;
113 break;
114 case P_BOW:
115 if (is_ammo(obj))
116 descr = "arrow";
117 break;
118 case P_CROSSBOW:
119 if (is_ammo(obj))
120 descr = "bolt";
121 break;
122 case P_FLAIL:
123 if (obj->otyp == GRAPPLING_HOOK)
124 descr = "hook";
125 break;
126 case P_PICK_AXE:
127 /* even if "dwarvish mattock" hasn't been discovered yet */
128 if (obj->otyp == DWARVISH_MATTOCK)
129 descr = "mattock";
130 break;
131 default:
132 break;
134 return makesingular(descr);
138 * hitval returns an integer representing the "to hit" bonuses
139 * of "otmp" against the monster.
142 hitval(otmp, mon)
143 struct obj *otmp;
144 struct monst *mon;
146 int tmp = 0;
147 struct permonst *ptr = mon->data;
148 boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
150 if (Is_weapon)
151 tmp += otmp->spe;
153 /* Put weapon specific "to hit" bonuses in below: */
154 tmp += objects[otmp->otyp].oc_hitbon;
156 /* Put weapon vs. monster type "to hit" bonuses in below: */
158 /* Blessed weapons used against undead or demons */
159 if (Is_weapon && otmp->blessed
160 && (is_demon(ptr) || is_undead(ptr) || is_vampshifter(mon)))
161 tmp += 2;
163 if (is_spear(otmp) && index(kebabable, ptr->mlet))
164 tmp += 2;
166 /* trident is highly effective against swimmers */
167 if (otmp->otyp == TRIDENT && is_swimmer(ptr)) {
168 if (is_pool(mon->mx, mon->my))
169 tmp += 4;
170 else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE)
171 tmp += 2;
174 /* Picks used against xorns and earth elementals */
175 if (is_pick(otmp) && (passes_walls(ptr) && thick_skinned(ptr)))
176 tmp += 2;
178 /* Check specially named weapon "to hit" bonuses */
179 if (otmp->oartifact)
180 tmp += spec_abon(otmp, mon);
182 return tmp;
185 /* Historical note: The original versions of Hack used a range of damage
186 * which was similar to, but not identical to the damage used in Advanced
187 * Dungeons and Dragons. I figured that since it was so close, I may as well
188 * make it exactly the same as AD&D, adding some more weapons in the process.
189 * This has the advantage that it is at least possible that the player would
190 * already know the damage of at least some of the weapons. This was circa
191 * 1987 and I used the table from Unearthed Arcana until I got tired of typing
192 * them in (leading to something of an imbalance towards weapons early in
193 * alphabetical order). The data structure still doesn't include fields that
194 * fully allow the appropriate damage to be described (there's no way to say
195 * 3d6 or 1d6+1) so we add on the extra damage in dmgval() if the weapon
196 * doesn't do an exact die of damage.
198 * Of course new weapons were added later in the development of Nethack. No
199 * AD&D consistency was kept, but most of these don't exist in AD&D anyway.
201 * Second edition AD&D came out a few years later; luckily it used the same
202 * table. As of this writing (1999), third edition is in progress but not
203 * released. Let's see if the weapon table stays the same. --KAA
204 * October 2000: It didn't. Oh, well.
208 * dmgval returns an integer representing the damage bonuses
209 * of "otmp" against the monster.
212 dmgval(otmp, mon)
213 struct obj *otmp;
214 struct monst *mon;
216 int tmp = 0, otyp = otmp->otyp;
217 struct permonst *ptr = mon->data;
218 boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
220 if (otyp == CREAM_PIE)
221 return 0;
223 if (bigmonst(ptr)) {
224 if (objects[otyp].oc_wldam)
225 tmp = rnd(objects[otyp].oc_wldam);
226 switch (otyp) {
227 case IRON_CHAIN:
228 case CROSSBOW_BOLT:
229 case MORNING_STAR:
230 case PARTISAN:
231 case RUNESWORD:
232 case ELVEN_BROADSWORD:
233 case BROADSWORD:
234 tmp++;
235 break;
237 case FLAIL:
238 case RANSEUR:
239 case VOULGE:
240 tmp += rnd(4);
241 break;
243 case ACID_VENOM:
244 case HALBERD:
245 case SPETUM:
246 tmp += rnd(6);
247 break;
249 case BATTLE_AXE:
250 case BARDICHE:
251 case TRIDENT:
252 tmp += d(2, 4);
253 break;
255 case TSURUGI:
256 case DWARVISH_MATTOCK:
257 case TWO_HANDED_SWORD:
258 tmp += d(2, 6);
259 break;
261 } else {
262 if (objects[otyp].oc_wsdam)
263 tmp = rnd(objects[otyp].oc_wsdam);
264 switch (otyp) {
265 case IRON_CHAIN:
266 case CROSSBOW_BOLT:
267 case MACE:
268 case WAR_HAMMER:
269 case FLAIL:
270 case SPETUM:
271 case TRIDENT:
272 tmp++;
273 break;
275 case BATTLE_AXE:
276 case BARDICHE:
277 case BILL_GUISARME:
278 case GUISARME:
279 case LUCERN_HAMMER:
280 case MORNING_STAR:
281 case RANSEUR:
282 case BROADSWORD:
283 case ELVEN_BROADSWORD:
284 case RUNESWORD:
285 case VOULGE:
286 tmp += rnd(4);
287 break;
289 case ACID_VENOM:
290 tmp += rnd(6);
291 break;
294 if (Is_weapon) {
295 tmp += otmp->spe;
296 /* negative enchantment mustn't produce negative damage */
297 if (tmp < 0)
298 tmp = 0;
301 if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr))
302 /* thick skinned/scaled creatures don't feel it */
303 tmp = 0;
304 if (ptr == &mons[PM_SHADE] && !shade_glare(otmp))
305 tmp = 0;
307 /* "very heavy iron ball"; weight increase is in increments */
308 if (otyp == HEAVY_IRON_BALL && tmp > 0) {
309 int wt = (int) objects[HEAVY_IRON_BALL].oc_weight;
311 if ((int) otmp->owt > wt) {
312 wt = ((int) otmp->owt - wt) / IRON_BALL_W_INCR;
313 tmp += rnd(4 * wt);
314 if (tmp > 25)
315 tmp = 25; /* objects[].oc_wldam */
319 /* Put weapon vs. monster type damage bonuses in below: */
320 if (Is_weapon || otmp->oclass == GEM_CLASS || otmp->oclass == BALL_CLASS
321 || otmp->oclass == CHAIN_CLASS) {
322 int bonus = 0;
324 if (otmp->blessed
325 && (is_undead(ptr) || is_demon(ptr) || is_vampshifter(mon)))
326 bonus += rnd(4);
327 if (is_axe(otmp) && is_wooden(ptr))
328 bonus += rnd(4);
329 if (objects[otyp].oc_material == SILVER && mon_hates_silver(mon))
330 bonus += rnd(20);
332 /* if the weapon is going to get a double damage bonus, adjust
333 this bonus so that effectively it's added after the doubling */
334 if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25)
335 bonus = (bonus + 1) / 2;
337 tmp += bonus;
340 if (tmp > 0) {
341 /* It's debatable whether a rusted blunt instrument
342 should do less damage than a pristine one, since
343 it will hit with essentially the same impact, but
344 there ought to some penalty for using damaged gear
345 so always subtract erosion even for blunt weapons. */
346 tmp -= greatest_erosion(otmp);
347 if (tmp < 1)
348 tmp = 1;
351 return tmp;
354 STATIC_DCL struct obj *FDECL(oselect, (struct monst *, int));
355 #define Oselect(x) \
356 if ((otmp = oselect(mtmp, x)) != 0) \
357 return otmp;
359 STATIC_OVL struct obj *
360 oselect(mtmp, x)
361 struct monst *mtmp;
362 int x;
364 struct obj *otmp;
366 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
367 if (otmp->otyp == x
368 /* never select non-cockatrice corpses */
369 && !((x == CORPSE || x == EGG)
370 && !touch_petrifies(&mons[otmp->corpsenm]))
371 && (!otmp->oartifact || touch_artifact(otmp, mtmp)))
372 return otmp;
374 return (struct obj *) 0;
377 static NEARDATA const int rwep[] = {
378 DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN,
379 SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW,
380 CROSSBOW_BOLT, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE,
381 FLINT, ROCK, LOADSTONE, LUCKSTONE, DART,
382 /* BOOMERANG, */ CREAM_PIE
385 static NEARDATA const int pwep[] = { HALBERD, BARDICHE, SPETUM,
386 BILL_GUISARME, VOULGE, RANSEUR,
387 GUISARME, GLAIVE, LUCERN_HAMMER,
388 BEC_DE_CORBIN, FAUCHARD, PARTISAN,
389 LANCE };
391 static struct obj *propellor;
393 /* select a ranged weapon for the monster */
394 struct obj *
395 select_rwep(mtmp)
396 register struct monst *mtmp;
398 register struct obj *otmp;
399 struct obj *mwep;
400 boolean mweponly;
401 int i;
403 char mlet = mtmp->data->mlet;
405 propellor = &zeroobj;
406 Oselect(EGG); /* cockatrice egg */
407 if (mlet == S_KOP) /* pies are first choice for Kops */
408 Oselect(CREAM_PIE);
409 if (throws_rocks(mtmp->data)) /* ...boulders for giants */
410 Oselect(BOULDER);
412 /* Select polearms first; they do more damage and aren't expendable.
413 But don't pick one if monster's weapon is welded, because then
414 we'd never have a chance to throw non-wielding missiles. */
415 /* The limit of 13 here is based on the monster polearm range limit
416 * (defined as 5 in mthrowu.c). 5 corresponds to a distance of 2 in
417 * one direction and 1 in another; one space beyond that would be 3 in
418 * one direction and 2 in another; 3^2+2^2=13.
420 mwep = MON_WEP(mtmp);
421 /* NO_WEAPON_WANTED means we already tried to wield and failed */
422 mweponly = (mwelded(mwep) && mtmp->weapon_check == NO_WEAPON_WANTED);
423 if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 13
424 && couldsee(mtmp->mx, mtmp->my)) {
425 for (i = 0; i < SIZE(pwep); i++) {
426 /* Only strong monsters can wield big (esp. long) weapons.
427 * Big weapon is basically the same as bimanual.
428 * All monsters can wield the remaining weapons.
430 if (((strongmonst(mtmp->data)
431 && (mtmp->misc_worn_check & W_ARMS) == 0)
432 || !objects[pwep[i]].oc_bimanual)
433 && (objects[pwep[i]].oc_material != SILVER
434 || !mon_hates_silver(mtmp))) {
435 if ((otmp = oselect(mtmp, pwep[i])) != 0
436 && (otmp == mwep || !mweponly)) {
437 propellor = otmp; /* force the monster to wield it */
438 return otmp;
445 * other than these two specific cases, always select the
446 * most potent ranged weapon to hand.
448 for (i = 0; i < SIZE(rwep); i++) {
449 int prop;
451 /* shooting gems from slings; this goes just before the darts */
452 /* (shooting rocks is already handled via the rwep[] ordering) */
453 if (rwep[i] == DART && !likes_gems(mtmp->data)
454 && m_carrying(mtmp, SLING)) { /* propellor */
455 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
456 if (otmp->oclass == GEM_CLASS
457 && (otmp->otyp != LOADSTONE || !otmp->cursed)) {
458 propellor = m_carrying(mtmp, SLING);
459 return otmp;
463 /* KMH -- This belongs here so darts will work */
464 propellor = &zeroobj;
466 prop = (objects[rwep[i]]).oc_skill;
467 if (prop < 0) {
468 switch (-prop) {
469 case P_BOW:
470 propellor = (oselect(mtmp, YUMI));
471 if (!propellor)
472 propellor = (oselect(mtmp, ELVEN_BOW));
473 if (!propellor)
474 propellor = (oselect(mtmp, BOW));
475 if (!propellor)
476 propellor = (oselect(mtmp, ORCISH_BOW));
477 break;
478 case P_SLING:
479 propellor = (oselect(mtmp, SLING));
480 break;
481 case P_CROSSBOW:
482 propellor = (oselect(mtmp, CROSSBOW));
484 if ((otmp = MON_WEP(mtmp)) && mwelded(otmp) && otmp != propellor
485 && mtmp->weapon_check == NO_WEAPON_WANTED)
486 propellor = 0;
488 /* propellor = obj, propellor to use
489 * propellor = &zeroobj, doesn't need a propellor
490 * propellor = 0, needed one and didn't have one
492 if (propellor != 0) {
493 /* Note: cannot use m_carrying for loadstones, since it will
494 * always select the first object of a type, and maybe the
495 * monster is carrying two but only the first is unthrowable.
497 if (rwep[i] != LOADSTONE) {
498 /* Don't throw a cursed weapon-in-hand or an artifact */
499 if ((otmp = oselect(mtmp, rwep[i])) && !otmp->oartifact
500 && !(otmp == MON_WEP(mtmp) && mwelded(otmp)))
501 return otmp;
502 } else
503 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
504 if (otmp->otyp == LOADSTONE && !otmp->cursed)
505 return otmp;
510 /* failure */
511 return (struct obj *) 0;
514 /* Weapons in order of preference */
515 static const NEARDATA short hwep[] = {
516 CORPSE, /* cockatrice corpse */
517 TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE,
518 KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD, ELVEN_BROADSWORD,
519 BROADSWORD, SCIMITAR, SILVER_SABER, MORNING_STAR, ELVEN_SHORT_SWORD,
520 DWARVISH_SHORT_SWORD, SHORT_SWORD, ORCISH_SHORT_SWORD, MACE, AXE,
521 DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL,
522 BULLWHIP, QUARTERSTAFF, JAVELIN, AKLYS, CLUB, PICK_AXE, RUBBER_HOSE,
523 WAR_HAMMER, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, ATHAME,
524 SCALPEL, KNIFE, WORM_TOOTH
527 /* select a hand to hand weapon for the monster */
528 struct obj *
529 select_hwep(mtmp)
530 register struct monst *mtmp;
532 register struct obj *otmp;
533 register int i;
534 boolean strong = strongmonst(mtmp->data);
535 boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0;
537 /* prefer artifacts to everything else */
538 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
539 if (otmp->oclass == WEAPON_CLASS && otmp->oartifact
540 && touch_artifact(otmp, mtmp)
541 && ((strong && !wearing_shield)
542 || !objects[otmp->otyp].oc_bimanual))
543 return otmp;
546 if (is_giant(mtmp->data)) /* giants just love to use clubs */
547 Oselect(CLUB);
549 /* only strong monsters can wield big (esp. long) weapons */
550 /* big weapon is basically the same as bimanual */
551 /* all monsters can wield the remaining weapons */
552 for (i = 0; i < SIZE(hwep); i++) {
553 if (hwep[i] == CORPSE && !(mtmp->misc_worn_check & W_ARMG)
554 && !resists_ston(mtmp))
555 continue;
556 if (((strong && !wearing_shield) || !objects[hwep[i]].oc_bimanual)
557 && (objects[hwep[i]].oc_material != SILVER
558 || !mon_hates_silver(mtmp)))
559 Oselect(hwep[i]);
562 /* failure */
563 return (struct obj *) 0;
566 /* Called after polymorphing a monster, robbing it, etc.... Monsters
567 * otherwise never unwield stuff on their own. Might print message.
569 void
570 possibly_unwield(mon, polyspot)
571 struct monst *mon;
572 boolean polyspot;
574 struct obj *obj, *mw_tmp;
576 if (!(mw_tmp = MON_WEP(mon)))
577 return;
578 for (obj = mon->minvent; obj; obj = obj->nobj)
579 if (obj == mw_tmp)
580 break;
581 if (!obj) { /* The weapon was stolen or destroyed */
582 MON_NOWEP(mon);
583 mon->weapon_check = NEED_WEAPON;
584 return;
586 if (!attacktype(mon->data, AT_WEAP)) {
587 setmnotwielded(mon, mw_tmp);
588 mon->weapon_check = NO_WEAPON_WANTED;
589 obj_extract_self(obj);
590 if (cansee(mon->mx, mon->my)) {
591 pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
592 newsym(mon->mx, mon->my);
594 /* might be dropping object into water or lava */
595 if (!flooreffects(obj, mon->mx, mon->my, "drop")) {
596 if (polyspot)
597 bypass_obj(obj);
598 place_object(obj, mon->mx, mon->my);
599 stackobj(obj);
601 return;
603 /* The remaining case where there is a change is where a monster
604 * is polymorphed into a stronger/weaker monster with a different
605 * choice of weapons. This has no parallel for players. It can
606 * be handled by waiting until mon_wield_item is actually called.
607 * Though the monster still wields the wrong weapon until then,
608 * this is OK since the player can't see it. (FIXME: Not okay since
609 * probing can reveal it.)
610 * Note that if there is no change, setting the check to NEED_WEAPON
611 * is harmless.
612 * Possible problem: big monster with big cursed weapon gets
613 * polymorphed into little monster. But it's not quite clear how to
614 * handle this anyway....
616 if (!(mwelded(mw_tmp) && mon->weapon_check == NO_WEAPON_WANTED))
617 mon->weapon_check = NEED_WEAPON;
618 return;
621 /* Let a monster try to wield a weapon, based on mon->weapon_check.
622 * Returns 1 if the monster took time to do it, 0 if it did not.
625 mon_wield_item(mon)
626 register struct monst *mon;
628 struct obj *obj;
630 /* This case actually should never happen */
631 if (mon->weapon_check == NO_WEAPON_WANTED)
632 return 0;
633 switch (mon->weapon_check) {
634 case NEED_HTH_WEAPON:
635 obj = select_hwep(mon);
636 break;
637 case NEED_RANGED_WEAPON:
638 (void) select_rwep(mon);
639 obj = propellor;
640 break;
641 case NEED_PICK_AXE:
642 obj = m_carrying(mon, PICK_AXE);
643 /* KMH -- allow other picks */
644 if (!obj && !which_armor(mon, W_ARMS))
645 obj = m_carrying(mon, DWARVISH_MATTOCK);
646 break;
647 case NEED_AXE:
648 /* currently, only 2 types of axe */
649 obj = m_carrying(mon, BATTLE_AXE);
650 if (!obj || which_armor(mon, W_ARMS))
651 obj = m_carrying(mon, AXE);
652 break;
653 case NEED_PICK_OR_AXE:
654 /* prefer pick for fewer switches on most levels */
655 obj = m_carrying(mon, DWARVISH_MATTOCK);
656 if (!obj)
657 obj = m_carrying(mon, BATTLE_AXE);
658 if (!obj || which_armor(mon, W_ARMS)) {
659 obj = m_carrying(mon, PICK_AXE);
660 if (!obj)
661 obj = m_carrying(mon, AXE);
663 break;
664 default:
665 impossible("weapon_check %d for %s?", mon->weapon_check,
666 mon_nam(mon));
667 return 0;
669 if (obj && obj != &zeroobj) {
670 struct obj *mw_tmp = MON_WEP(mon);
671 if (mw_tmp && mw_tmp->otyp == obj->otyp) {
672 /* already wielding it */
673 mon->weapon_check = NEED_WEAPON;
674 return 0;
676 /* Actually, this isn't necessary--as soon as the monster
677 * wields the weapon, the weapon welds itself, so the monster
678 * can know it's cursed and needn't even bother trying.
679 * Still....
681 if (mw_tmp && mwelded(mw_tmp)) {
682 if (canseemon(mon)) {
683 char welded_buf[BUFSZ];
684 const char *mon_hand = mbodypart(mon, HAND);
686 if (bimanual(mw_tmp))
687 mon_hand = makeplural(mon_hand);
688 Sprintf(welded_buf, "%s welded to %s %s",
689 otense(mw_tmp, "are"), mhis(mon), mon_hand);
691 if (obj->otyp == PICK_AXE) {
692 pline("Since %s weapon%s %s,", s_suffix(mon_nam(mon)),
693 plur(mw_tmp->quan), welded_buf);
694 pline("%s cannot wield that %s.", mon_nam(mon),
695 xname(obj));
696 } else {
697 pline("%s tries to wield %s.", Monnam(mon), doname(obj));
698 pline("%s %s!", Yname2(mw_tmp), welded_buf);
700 mw_tmp->bknown = 1;
702 mon->weapon_check = NO_WEAPON_WANTED;
703 return 1;
705 mon->mw = obj; /* wield obj */
706 setmnotwielded(mon, mw_tmp);
707 mon->weapon_check = NEED_WEAPON;
708 if (canseemon(mon)) {
709 pline("%s wields %s!", Monnam(mon), doname(obj));
710 if (mwelded(mw_tmp)) {
711 pline("%s %s to %s %s!", Tobjnam(obj, "weld"),
712 is_plural(obj) ? "themselves" : "itself",
713 s_suffix(mon_nam(mon)), mbodypart(mon, HAND));
714 obj->bknown = 1;
717 if (artifact_light(obj) && !obj->lamplit) {
718 begin_burn(obj, FALSE);
719 if (canseemon(mon))
720 pline("%s %s in %s %s!", Tobjnam(obj, "shine"),
721 arti_light_description(obj), s_suffix(mon_nam(mon)),
722 mbodypart(mon, HAND));
724 obj->owornmask = W_WEP;
725 return 1;
727 mon->weapon_check = NEED_WEAPON;
728 return 0;
731 /* force monster to stop wielding current weapon, if any */
732 void
733 mwepgone(mon)
734 struct monst *mon;
736 struct obj *mwep = MON_WEP(mon);
738 if (mwep) {
739 setmnotwielded(mon, mwep);
740 mon->weapon_check = NEED_WEAPON;
744 /* attack bonus for strength & dexterity */
746 abon()
748 int sbon;
749 int str = ACURR(A_STR), dex = ACURR(A_DEX);
751 if (Upolyd)
752 return (adj_lev(&mons[u.umonnum]) - 3);
753 if (str < 6)
754 sbon = -2;
755 else if (str < 8)
756 sbon = -1;
757 else if (str < 17)
758 sbon = 0;
759 else if (str <= STR18(50))
760 sbon = 1; /* up to 18/50 */
761 else if (str < STR18(100))
762 sbon = 2;
763 else
764 sbon = 3;
766 /* Game tuning kludge: make it a bit easier for a low level character to
767 * hit */
768 sbon += (u.ulevel < 3) ? 1 : 0;
770 if (dex < 4)
771 return (sbon - 3);
772 else if (dex < 6)
773 return (sbon - 2);
774 else if (dex < 8)
775 return (sbon - 1);
776 else if (dex < 14)
777 return sbon;
778 else
779 return (sbon + dex - 14);
782 /* damage bonus for strength */
784 dbon()
786 int str = ACURR(A_STR);
788 if (Upolyd)
789 return 0;
791 if (str < 6)
792 return -1;
793 else if (str < 16)
794 return 0;
795 else if (str < 18)
796 return 1;
797 else if (str == 18)
798 return 2; /* up to 18 */
799 else if (str <= STR18(75))
800 return 3; /* up to 18/75 */
801 else if (str <= STR18(90))
802 return 4; /* up to 18/90 */
803 else if (str < STR18(100))
804 return 5; /* up to 18/99 */
805 else
806 return 6;
809 /* increase a towel's wetness */
810 void
811 wet_a_towel(obj, amt, verbose)
812 struct obj *obj;
813 int amt; /* positive: new value; negative: increment by -amt; zero: no-op */
814 boolean verbose;
816 int newspe = (amt <= 0) ? obj->spe - amt : amt;
818 /* new state is only reported if it's an increase */
819 if (newspe > obj->spe) {
820 if (verbose) {
821 const char *wetness = (newspe < 3)
822 ? (!obj->spe ? "damp" : "damper")
823 : (!obj->spe ? "wet" : "wetter");
825 if (carried(obj))
826 pline("%s gets %s.", Yobjnam2(obj, (const char *) 0),
827 wetness);
828 else if (mcarried(obj) && canseemon(obj->ocarry))
829 pline("%s %s gets %s.", s_suffix(Monnam(obj->ocarry)),
830 xname(obj), wetness);
833 obj->spe = min(newspe, 7);
835 /* if hero is wielding this towel, don't give "you begin bashing
836 with your wet towel" message on next attack with it */
837 if (obj == uwep)
838 unweapon = !is_wet_towel(obj);
841 /* decrease a towel's wetness */
842 void
843 dry_a_towel(obj, amt, verbose)
844 struct obj *obj;
845 int amt; /* positive: new value; negative: decrement by -amt; zero: no-op */
846 boolean verbose;
848 int newspe = (amt <= 0) ? obj->spe + amt : amt;
850 /* new state is only reported if it's a decrease */
851 if (newspe < obj->spe) {
852 if (verbose) {
853 if (carried(obj))
854 pline("%s dries%s.", Yobjnam2(obj, (const char *) 0),
855 !newspe ? " out" : "");
856 else if (mcarried(obj) && canseemon(obj->ocarry))
857 pline("%s %s drie%s.", s_suffix(Monnam(obj->ocarry)),
858 xname(obj), !newspe ? " out" : "");
861 newspe = min(newspe, 7);
862 obj->spe = max(newspe, 0);
864 /* if hero is wielding this towel and it is now dry, give "you begin
865 bashing with your towel" message on next attack with it */
866 if (obj == uwep)
867 unweapon = !is_wet_towel(obj);
870 /* copy the skill level name into the given buffer */
871 STATIC_OVL char *
872 skill_level_name(skill, buf)
873 int skill;
874 char *buf;
876 const char *ptr;
878 switch (P_SKILL(skill)) {
879 case P_UNSKILLED:
880 ptr = "Unskilled";
881 break;
882 case P_BASIC:
883 ptr = "Basic";
884 break;
885 case P_SKILLED:
886 ptr = "Skilled";
887 break;
888 case P_EXPERT:
889 ptr = "Expert";
890 break;
891 /* these are for unarmed combat/martial arts only */
892 case P_MASTER:
893 ptr = "Master";
894 break;
895 case P_GRAND_MASTER:
896 ptr = "Grand Master";
897 break;
898 default:
899 ptr = "Unknown";
900 break;
902 Strcpy(buf, ptr);
903 return buf;
906 /* return the # of slots required to advance the skill */
907 STATIC_OVL int
908 slots_required(skill)
909 int skill;
911 int tmp = P_SKILL(skill);
913 /* The more difficult the training, the more slots it takes.
914 * unskilled -> basic 1
915 * basic -> skilled 2
916 * skilled -> expert 3
918 if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT)
919 return tmp;
921 /* Fewer slots used up for unarmed or martial.
922 * unskilled -> basic 1
923 * basic -> skilled 1
924 * skilled -> expert 2
925 * expert -> master 2
926 * master -> grand master 3
928 return (tmp + 1) / 2;
931 /* return true if this skill can be advanced */
932 /*ARGSUSED*/
933 STATIC_OVL boolean
934 can_advance(skill, speedy)
935 int skill;
936 boolean speedy;
938 if (P_RESTRICTED(skill)
939 || P_SKILL(skill) >= P_MAX_SKILL(skill)
940 || u.skills_advanced >= P_SKILL_LIMIT)
941 return FALSE;
943 if (wizard && speedy)
944 return TRUE;
946 return (boolean) ((int) P_ADVANCE(skill)
947 >= practice_needed_to_advance(P_SKILL(skill))
948 && u.weapon_slots >= slots_required(skill));
951 /* return true if this skill could be advanced if more slots were available */
952 STATIC_OVL boolean
953 could_advance(skill)
954 int skill;
956 if (P_RESTRICTED(skill)
957 || P_SKILL(skill) >= P_MAX_SKILL(skill)
958 || u.skills_advanced >= P_SKILL_LIMIT)
959 return FALSE;
961 return (boolean) ((int) P_ADVANCE(skill)
962 >= practice_needed_to_advance(P_SKILL(skill)));
965 /* return true if this skill has reached its maximum and there's been enough
966 practice to become eligible for the next step if that had been possible */
967 STATIC_OVL boolean
968 peaked_skill(skill)
969 int skill;
971 if (P_RESTRICTED(skill))
972 return FALSE;
974 return (boolean) (P_SKILL(skill) >= P_MAX_SKILL(skill)
975 && ((int) P_ADVANCE(skill)
976 >= practice_needed_to_advance(P_SKILL(skill))));
979 STATIC_OVL void
980 skill_advance(skill)
981 int skill;
983 u.weapon_slots -= slots_required(skill);
984 P_SKILL(skill)++;
985 u.skill_record[u.skills_advanced++] = skill;
986 /* subtly change the advance message to indicate no more advancement */
987 You("are now %s skilled in %s.",
988 P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more",
989 P_NAME(skill));
992 static const struct skill_range {
993 short first, last;
994 const char *name;
995 } skill_ranges[] = {
996 { P_FIRST_H_TO_H, P_LAST_H_TO_H, "Fighting Skills" },
997 { P_FIRST_WEAPON, P_LAST_WEAPON, "Weapon Skills" },
998 { P_FIRST_SPELL, P_LAST_SPELL, "Spellcasting Skills" },
1002 * The `#enhance' extended command. What we _really_ would like is
1003 * to keep being able to pick things to advance until we couldn't any
1004 * more. This is currently not possible -- the menu code has no way
1005 * to call us back for instant action. Even if it did, we would also need
1006 * to be able to update the menu since selecting one item could make
1007 * others unselectable.
1010 enhance_weapon_skill()
1012 int pass, i, n, len, longest, to_advance, eventually_advance, maxxed_cnt;
1013 char buf[BUFSZ], sklnambuf[BUFSZ];
1014 const char *prefix;
1015 menu_item *selected;
1016 anything any;
1017 winid win;
1018 boolean speedy = FALSE;
1020 if (wizard && yn("Advance skills without practice?") == 'y')
1021 speedy = TRUE;
1023 do {
1024 /* find longest available skill name, count those that can advance */
1025 to_advance = eventually_advance = maxxed_cnt = 0;
1026 for (longest = 0, i = 0; i < P_NUM_SKILLS; i++) {
1027 if (P_RESTRICTED(i))
1028 continue;
1029 if ((len = strlen(P_NAME(i))) > longest)
1030 longest = len;
1031 if (can_advance(i, speedy))
1032 to_advance++;
1033 else if (could_advance(i))
1034 eventually_advance++;
1035 else if (peaked_skill(i))
1036 maxxed_cnt++;
1039 win = create_nhwindow(NHW_MENU);
1040 start_menu(win);
1042 /* start with a legend if any entries will be annotated
1043 with "*" or "#" below */
1044 if (eventually_advance > 0 || maxxed_cnt > 0) {
1045 any = zeroany;
1046 if (eventually_advance > 0) {
1047 Sprintf(buf, "(Skill%s flagged by \"*\" may be enhanced %s.)",
1048 plur(eventually_advance),
1049 (u.ulevel < MAXULEV)
1050 ? "when you're more experienced"
1051 : "if skill slots become available");
1052 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
1053 MENU_UNSELECTED);
1055 if (maxxed_cnt > 0) {
1056 Sprintf(buf,
1057 "(Skill%s flagged by \"#\" cannot be enhanced any further.)",
1058 plur(maxxed_cnt));
1059 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
1060 MENU_UNSELECTED);
1062 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
1063 MENU_UNSELECTED);
1066 /* List the skills, making ones that could be advanced
1067 selectable. List the miscellaneous skills first.
1068 Possible future enhancement: list spell skills before
1069 weapon skills for spellcaster roles. */
1070 for (pass = 0; pass < SIZE(skill_ranges); pass++)
1071 for (i = skill_ranges[pass].first; i <= skill_ranges[pass].last;
1072 i++) {
1073 /* Print headings for skill types */
1074 any = zeroany;
1075 if (i == skill_ranges[pass].first)
1076 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
1077 skill_ranges[pass].name, MENU_UNSELECTED);
1079 if (P_RESTRICTED(i))
1080 continue;
1082 * Sigh, this assumes a monospaced font unless
1083 * iflags.menu_tab_sep is set in which case it puts
1084 * tabs between columns.
1085 * The 12 is the longest skill level name.
1086 * The " " is room for a selection letter and dash, "a - ".
1088 if (can_advance(i, speedy))
1089 prefix = ""; /* will be preceded by menu choice */
1090 else if (could_advance(i))
1091 prefix = " * ";
1092 else if (peaked_skill(i))
1093 prefix = " # ";
1094 else
1095 prefix =
1096 (to_advance + eventually_advance + maxxed_cnt > 0)
1097 ? " "
1098 : "";
1099 (void) skill_level_name(i, sklnambuf);
1100 if (wizard) {
1101 if (!iflags.menu_tab_sep)
1102 Sprintf(buf, " %s%-*s %-12s %5d(%4d)", prefix,
1103 longest, P_NAME(i), sklnambuf, P_ADVANCE(i),
1104 practice_needed_to_advance(P_SKILL(i)));
1105 else
1106 Sprintf(buf, " %s%s\t%s\t%5d(%4d)", prefix, P_NAME(i),
1107 sklnambuf, P_ADVANCE(i),
1108 practice_needed_to_advance(P_SKILL(i)));
1109 } else {
1110 if (!iflags.menu_tab_sep)
1111 Sprintf(buf, " %s %-*s [%s]", prefix, longest,
1112 P_NAME(i), sklnambuf);
1113 else
1114 Sprintf(buf, " %s%s\t[%s]", prefix, P_NAME(i),
1115 sklnambuf);
1117 any.a_int = can_advance(i, speedy) ? i + 1 : 0;
1118 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
1119 MENU_UNSELECTED);
1122 Strcpy(buf, (to_advance > 0) ? "Pick a skill to advance:"
1123 : "Current skills:");
1124 if (wizard && !speedy)
1125 Sprintf(eos(buf), " (%d slot%s available)", u.weapon_slots,
1126 plur(u.weapon_slots));
1127 end_menu(win, buf);
1128 n = select_menu(win, to_advance ? PICK_ONE : PICK_NONE, &selected);
1129 destroy_nhwindow(win);
1130 if (n > 0) {
1131 n = selected[0].item.a_int - 1; /* get item selected */
1132 free((genericptr_t) selected);
1133 skill_advance(n);
1134 /* check for more skills able to advance, if so then .. */
1135 for (n = i = 0; i < P_NUM_SKILLS; i++) {
1136 if (can_advance(i, speedy)) {
1137 if (!speedy)
1138 You_feel("you could be more dangerous!");
1139 n++;
1140 break;
1144 } while (speedy && n > 0);
1145 return 0;
1149 * Change from restricted to unrestricted, allowing P_BASIC as max. This
1150 * function may be called with with P_NONE. Used in pray.c as well as below.
1152 void
1153 unrestrict_weapon_skill(skill)
1154 int skill;
1156 if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) {
1157 P_SKILL(skill) = P_UNSKILLED;
1158 P_MAX_SKILL(skill) = P_BASIC;
1159 P_ADVANCE(skill) = 0;
1163 void
1164 use_skill(skill, degree)
1165 int skill;
1166 int degree;
1168 boolean advance_before;
1170 if (skill != P_NONE && !P_RESTRICTED(skill)) {
1171 advance_before = can_advance(skill, FALSE);
1172 P_ADVANCE(skill) += degree;
1173 if (!advance_before && can_advance(skill, FALSE))
1174 give_may_advance_msg(skill);
1178 void
1179 add_weapon_skill(n)
1180 int n; /* number of slots to gain; normally one */
1182 int i, before, after;
1184 for (i = 0, before = 0; i < P_NUM_SKILLS; i++)
1185 if (can_advance(i, FALSE))
1186 before++;
1187 u.weapon_slots += n;
1188 for (i = 0, after = 0; i < P_NUM_SKILLS; i++)
1189 if (can_advance(i, FALSE))
1190 after++;
1191 if (before < after)
1192 give_may_advance_msg(P_NONE);
1195 void
1196 lose_weapon_skill(n)
1197 int n; /* number of slots to lose; normally one */
1199 int skill;
1201 while (--n >= 0) {
1202 /* deduct first from unused slots then from last placed one, if any */
1203 if (u.weapon_slots) {
1204 u.weapon_slots--;
1205 } else if (u.skills_advanced) {
1206 skill = u.skill_record[--u.skills_advanced];
1207 if (P_SKILL(skill) <= P_UNSKILLED)
1208 panic("lose_weapon_skill (%d)", skill);
1209 P_SKILL(skill)--; /* drop skill one level */
1210 /* Lost skill might have taken more than one slot; refund rest. */
1211 u.weapon_slots = slots_required(skill) - 1;
1212 /* It might now be possible to advance some other pending
1213 skill by using the refunded slots, but giving a message
1214 to that effect would seem pretty confusing.... */
1220 weapon_type(obj)
1221 struct obj *obj;
1223 /* KMH -- now uses the object table */
1224 int type;
1226 if (!obj)
1227 return P_BARE_HANDED_COMBAT; /* Not using a weapon */
1228 if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS
1229 && obj->oclass != GEM_CLASS)
1230 return P_NONE; /* Not a weapon, weapon-tool, or ammo */
1231 type = objects[obj->otyp].oc_skill;
1232 return (type < 0) ? -type : type;
1236 uwep_skill_type()
1238 if (u.twoweap)
1239 return P_TWO_WEAPON_COMBAT;
1240 return weapon_type(uwep);
1244 * Return hit bonus/penalty based on skill of weapon.
1245 * Treat restricted weapons as unskilled.
1248 weapon_hit_bonus(weapon)
1249 struct obj *weapon;
1251 int type, wep_type, skill, bonus = 0;
1252 static const char bad_skill[] = "weapon_hit_bonus: bad skill %d";
1254 wep_type = weapon_type(weapon);
1255 /* use two weapon skill only if attacking with one of the wielded weapons
1257 type = (u.twoweap && (weapon == uwep || weapon == uswapwep))
1258 ? P_TWO_WEAPON_COMBAT
1259 : wep_type;
1260 if (type == P_NONE) {
1261 bonus = 0;
1262 } else if (type <= P_LAST_WEAPON) {
1263 switch (P_SKILL(type)) {
1264 default:
1265 impossible(bad_skill, P_SKILL(type)); /* fall through */
1266 case P_ISRESTRICTED:
1267 case P_UNSKILLED:
1268 bonus = -4;
1269 break;
1270 case P_BASIC:
1271 bonus = 0;
1272 break;
1273 case P_SKILLED:
1274 bonus = 2;
1275 break;
1276 case P_EXPERT:
1277 bonus = 3;
1278 break;
1280 } else if (type == P_TWO_WEAPON_COMBAT) {
1281 skill = P_SKILL(P_TWO_WEAPON_COMBAT);
1282 if (P_SKILL(wep_type) < skill)
1283 skill = P_SKILL(wep_type);
1284 switch (skill) {
1285 default:
1286 impossible(bad_skill, skill); /* fall through */
1287 case P_ISRESTRICTED:
1288 case P_UNSKILLED:
1289 bonus = -9;
1290 break;
1291 case P_BASIC:
1292 bonus = -7;
1293 break;
1294 case P_SKILLED:
1295 bonus = -5;
1296 break;
1297 case P_EXPERT:
1298 bonus = -3;
1299 break;
1301 } else if (type == P_BARE_HANDED_COMBAT) {
1303 * b.h. m.a.
1304 * unskl: +1 n/a
1305 * basic: +1 +3
1306 * skild: +2 +4
1307 * exprt: +2 +5
1308 * mastr: +3 +6
1309 * grand: +3 +7
1311 bonus = P_SKILL(type);
1312 bonus = max(bonus, P_UNSKILLED) - 1; /* unskilled => 0 */
1313 bonus = ((bonus + 2) * (martial_bonus() ? 2 : 1)) / 2;
1316 /* KMH -- It's harder to hit while you are riding */
1317 if (u.usteed) {
1318 switch (P_SKILL(P_RIDING)) {
1319 case P_ISRESTRICTED:
1320 case P_UNSKILLED:
1321 bonus -= 2;
1322 break;
1323 case P_BASIC:
1324 bonus -= 1;
1325 break;
1326 case P_SKILLED:
1327 break;
1328 case P_EXPERT:
1329 break;
1331 if (u.twoweap)
1332 bonus -= 2;
1335 return bonus;
1339 * Return damage bonus/penalty based on skill of weapon.
1340 * Treat restricted weapons as unskilled.
1343 weapon_dam_bonus(weapon)
1344 struct obj *weapon;
1346 int type, wep_type, skill, bonus = 0;
1348 wep_type = weapon_type(weapon);
1349 /* use two weapon skill only if attacking with one of the wielded weapons
1351 type = (u.twoweap && (weapon == uwep || weapon == uswapwep))
1352 ? P_TWO_WEAPON_COMBAT
1353 : wep_type;
1354 if (type == P_NONE) {
1355 bonus = 0;
1356 } else if (type <= P_LAST_WEAPON) {
1357 switch (P_SKILL(type)) {
1358 default:
1359 impossible("weapon_dam_bonus: bad skill %d", P_SKILL(type));
1360 /* fall through */
1361 case P_ISRESTRICTED:
1362 case P_UNSKILLED:
1363 bonus = -2;
1364 break;
1365 case P_BASIC:
1366 bonus = 0;
1367 break;
1368 case P_SKILLED:
1369 bonus = 1;
1370 break;
1371 case P_EXPERT:
1372 bonus = 2;
1373 break;
1375 } else if (type == P_TWO_WEAPON_COMBAT) {
1376 skill = P_SKILL(P_TWO_WEAPON_COMBAT);
1377 if (P_SKILL(wep_type) < skill)
1378 skill = P_SKILL(wep_type);
1379 switch (skill) {
1380 default:
1381 case P_ISRESTRICTED:
1382 case P_UNSKILLED:
1383 bonus = -3;
1384 break;
1385 case P_BASIC:
1386 bonus = -1;
1387 break;
1388 case P_SKILLED:
1389 bonus = 0;
1390 break;
1391 case P_EXPERT:
1392 bonus = 1;
1393 break;
1395 } else if (type == P_BARE_HANDED_COMBAT) {
1397 * b.h. m.a.
1398 * unskl: 0 n/a
1399 * basic: +1 +3
1400 * skild: +1 +4
1401 * exprt: +2 +6
1402 * mastr: +2 +7
1403 * grand: +3 +9
1405 bonus = P_SKILL(type);
1406 bonus = max(bonus, P_UNSKILLED) - 1; /* unskilled => 0 */
1407 bonus = ((bonus + 1) * (martial_bonus() ? 3 : 1)) / 2;
1410 /* KMH -- Riding gives some thrusting damage */
1411 if (u.usteed && type != P_TWO_WEAPON_COMBAT) {
1412 switch (P_SKILL(P_RIDING)) {
1413 case P_ISRESTRICTED:
1414 case P_UNSKILLED:
1415 break;
1416 case P_BASIC:
1417 break;
1418 case P_SKILLED:
1419 bonus += 1;
1420 break;
1421 case P_EXPERT:
1422 bonus += 2;
1423 break;
1427 return bonus;
1431 * Initialize weapon skill array for the game. Start by setting all
1432 * skills to restricted, then set the skill for every weapon the
1433 * hero is holding, finally reading the given array that sets
1434 * maximums.
1436 void
1437 skill_init(class_skill)
1438 const struct def_skill *class_skill;
1440 struct obj *obj;
1441 int skmax, skill;
1443 /* initialize skill array; by default, everything is restricted */
1444 for (skill = 0; skill < P_NUM_SKILLS; skill++) {
1445 P_SKILL(skill) = P_ISRESTRICTED;
1446 P_MAX_SKILL(skill) = P_ISRESTRICTED;
1447 P_ADVANCE(skill) = 0;
1450 /* Set skill for all weapons in inventory to be basic */
1451 for (obj = invent; obj; obj = obj->nobj) {
1452 /* don't give skill just because of carried ammo, wait until
1453 we see the relevant launcher (prevents an archeologist's
1454 touchstone from inadvertently providing skill in sling) */
1455 if (is_ammo(obj))
1456 continue;
1458 skill = weapon_type(obj);
1459 if (skill != P_NONE)
1460 P_SKILL(skill) = P_BASIC;
1463 /* set skills for magic */
1464 if (Role_if(PM_HEALER) || Role_if(PM_MONK)) {
1465 P_SKILL(P_HEALING_SPELL) = P_BASIC;
1466 } else if (Role_if(PM_PRIEST)) {
1467 P_SKILL(P_CLERIC_SPELL) = P_BASIC;
1468 } else if (Role_if(PM_WIZARD)) {
1469 P_SKILL(P_ATTACK_SPELL) = P_BASIC;
1470 P_SKILL(P_ENCHANTMENT_SPELL) = P_BASIC;
1473 /* walk through array to set skill maximums */
1474 for (; class_skill->skill != P_NONE; class_skill++) {
1475 skmax = class_skill->skmax;
1476 skill = class_skill->skill;
1478 P_MAX_SKILL(skill) = skmax;
1479 if (P_SKILL(skill) == P_ISRESTRICTED) /* skill pre-set */
1480 P_SKILL(skill) = P_UNSKILLED;
1483 /* High potential fighters already know how to use their hands. */
1484 if (P_MAX_SKILL(P_BARE_HANDED_COMBAT) > P_EXPERT)
1485 P_SKILL(P_BARE_HANDED_COMBAT) = P_BASIC;
1487 /* Roles that start with a horse know how to ride it */
1488 if (urole.petnum == PM_PONY)
1489 P_SKILL(P_RIDING) = P_BASIC;
1492 * Make sure we haven't missed setting the max on a skill
1493 * & set advance
1495 for (skill = 0; skill < P_NUM_SKILLS; skill++) {
1496 if (!P_RESTRICTED(skill)) {
1497 if (P_MAX_SKILL(skill) < P_SKILL(skill)) {
1498 impossible("skill_init: curr > max: %s", P_NAME(skill));
1499 P_MAX_SKILL(skill) = P_SKILL(skill);
1501 P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill) - 1);
1505 /* each role has a special spell; allow at least basic for its type
1506 (despite the function name, this works for spell skills too) */
1507 unrestrict_weapon_skill(spell_skilltype(urole.spelspec));
1510 void
1511 setmnotwielded(mon, obj)
1512 register struct monst *mon;
1513 register struct obj *obj;
1515 if (!obj)
1516 return;
1517 if (artifact_light(obj) && obj->lamplit) {
1518 end_burn(obj, FALSE);
1519 if (canseemon(mon))
1520 pline("%s in %s %s %s shining.", The(xname(obj)),
1521 s_suffix(mon_nam(mon)), mbodypart(mon, HAND),
1522 otense(obj, "stop"));
1524 if (MON_WEP(mon) == obj)
1525 MON_NOWEP(mon);
1526 obj->owornmask &= ~W_WEP;
1529 /*weapon.c*/