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. */
6 * This module contains code for calculation of "to hit" and damage
7 * bonuses for any given weapon used, as well as weapons selection
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)
19 #define PN_HAMMER (-6)
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"
54 give_may_advance_msg(skill
)
57 You_feel("more confident in your %sskills.",
58 skill
== P_NONE
? "" : skill
<= P_LAST_WEAPON
60 : skill
<= P_LAST_SPELL
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) */
89 int skill
= weapon_type(obj
);
90 const char *descr
= P_NAME(skill
);
92 /* assorted special cases */
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
;
106 descr
= (obj
->otyp
== ROCK
|| is_graystone(obj
))
108 /* avoid "rock"; what about known glass? */
109 : (obj
->oclass
== GEM_CLASS
)
111 /* in case somebody adds odd sling ammo */
112 : def_oc_syms
[(int) obj
->oclass
].name
;
123 if (obj
->otyp
== GRAPPLING_HOOK
)
127 /* even if "dwarvish mattock" hasn't been discovered yet */
128 if (obj
->otyp
== DWARVISH_MATTOCK
)
134 return makesingular(descr
);
138 * hitval returns an integer representing the "to hit" bonuses
139 * of "otmp" against the monster.
147 struct permonst
*ptr
= mon
->data
;
148 boolean Is_weapon
= (otmp
->oclass
== WEAPON_CLASS
|| is_weptool(otmp
));
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
)))
163 if (is_spear(otmp
) && index(kebabable
, ptr
->mlet
))
166 /* trident is highly effective against swimmers */
167 if (otmp
->otyp
== TRIDENT
&& is_swimmer(ptr
)) {
168 if (is_pool(mon
->mx
, mon
->my
))
170 else if (ptr
->mlet
== S_EEL
|| ptr
->mlet
== S_SNAKE
)
174 /* Picks used against xorns and earth elementals */
175 if (is_pick(otmp
) && (passes_walls(ptr
) && thick_skinned(ptr
)))
178 /* Check specially named weapon "to hit" bonuses */
180 tmp
+= spec_abon(otmp
, mon
);
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.
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
)
224 if (objects
[otyp
].oc_wldam
)
225 tmp
= rnd(objects
[otyp
].oc_wldam
);
232 case ELVEN_BROADSWORD
:
256 case DWARVISH_MATTOCK
:
257 case TWO_HANDED_SWORD
:
262 if (objects
[otyp
].oc_wsdam
)
263 tmp
= rnd(objects
[otyp
].oc_wsdam
);
283 case ELVEN_BROADSWORD
:
296 /* negative enchantment mustn't produce negative damage */
301 if (objects
[otyp
].oc_material
<= LEATHER
&& thick_skinned(ptr
))
302 /* thick skinned/scaled creatures don't feel it */
304 if (ptr
== &mons
[PM_SHADE
] && !shade_glare(otmp
))
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
;
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
) {
325 && (is_undead(ptr
) || is_demon(ptr
) || is_vampshifter(mon
)))
327 if (is_axe(otmp
) && is_wooden(ptr
))
329 if (objects
[otyp
].oc_material
== SILVER
&& mon_hates_silver(mon
))
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;
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
);
354 STATIC_DCL
struct obj
*FDECL(oselect
, (struct monst
*, int));
356 if ((otmp = oselect(mtmp, x)) != 0) \
359 STATIC_OVL
struct obj
*
366 for (otmp
= mtmp
->minvent
; otmp
; otmp
= otmp
->nobj
) {
368 /* never select non-cockatrice corpses */
369 && !((x
== CORPSE
|| x
== EGG
)
370 && !touch_petrifies(&mons
[otmp
->corpsenm
]))
371 && (!otmp
->oartifact
|| touch_artifact(otmp
, mtmp
)))
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
,
391 static struct obj
*propellor
;
393 /* select a ranged weapon for the monster */
396 register struct monst
*mtmp
;
398 register struct obj
*otmp
;
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 */
409 if (throws_rocks(mtmp
->data
)) /* ...boulders for giants */
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 */
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
++) {
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
);
463 /* KMH -- This belongs here so darts will work */
464 propellor
= &zeroobj
;
466 prop
= (objects
[rwep
[i
]]).oc_skill
;
470 propellor
= (oselect(mtmp
, YUMI
));
472 propellor
= (oselect(mtmp
, ELVEN_BOW
));
474 propellor
= (oselect(mtmp
, BOW
));
476 propellor
= (oselect(mtmp
, ORCISH_BOW
));
479 propellor
= (oselect(mtmp
, SLING
));
482 propellor
= (oselect(mtmp
, CROSSBOW
));
484 if ((otmp
= MON_WEP(mtmp
)) && mwelded(otmp
) && otmp
!= propellor
485 && mtmp
->weapon_check
== NO_WEAPON_WANTED
)
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
)))
503 for (otmp
= mtmp
->minvent
; otmp
; otmp
= otmp
->nobj
) {
504 if (otmp
->otyp
== LOADSTONE
&& !otmp
->cursed
)
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 */
530 register struct monst
*mtmp
;
532 register struct obj
*otmp
;
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
))
546 if (is_giant(mtmp
->data
)) /* giants just love to use clubs */
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
))
556 if (((strong
&& !wearing_shield
) || !objects
[hwep
[i
]].oc_bimanual
)
557 && (objects
[hwep
[i
]].oc_material
!= SILVER
558 || !mon_hates_silver(mtmp
)))
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.
570 possibly_unwield(mon
, polyspot
)
574 struct obj
*obj
, *mw_tmp
;
576 if (!(mw_tmp
= MON_WEP(mon
)))
578 for (obj
= mon
->minvent
; obj
; obj
= obj
->nobj
)
581 if (!obj
) { /* The weapon was stolen or destroyed */
583 mon
->weapon_check
= NEED_WEAPON
;
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")) {
598 place_object(obj
, mon
->mx
, mon
->my
);
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
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
;
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.
626 register struct monst
*mon
;
630 /* This case actually should never happen */
631 if (mon
->weapon_check
== NO_WEAPON_WANTED
)
633 switch (mon
->weapon_check
) {
634 case NEED_HTH_WEAPON
:
635 obj
= select_hwep(mon
);
637 case NEED_RANGED_WEAPON
:
638 (void) select_rwep(mon
);
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
);
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
);
653 case NEED_PICK_OR_AXE
:
654 /* prefer pick for fewer switches on most levels */
655 obj
= m_carrying(mon
, DWARVISH_MATTOCK
);
657 obj
= m_carrying(mon
, BATTLE_AXE
);
658 if (!obj
|| which_armor(mon
, W_ARMS
)) {
659 obj
= m_carrying(mon
, PICK_AXE
);
661 obj
= m_carrying(mon
, AXE
);
665 impossible("weapon_check %d for %s?", mon
->weapon_check
,
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
;
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.
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
),
697 pline("%s tries to wield %s.", Monnam(mon
), doname(obj
));
698 pline("%s %s!", Yname2(mw_tmp
), welded_buf
);
702 mon
->weapon_check
= NO_WEAPON_WANTED
;
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
));
717 if (artifact_light(obj
) && !obj
->lamplit
) {
718 begin_burn(obj
, FALSE
);
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
;
727 mon
->weapon_check
= NEED_WEAPON
;
731 /* force monster to stop wielding current weapon, if any */
736 struct obj
*mwep
= MON_WEP(mon
);
739 setmnotwielded(mon
, mwep
);
740 mon
->weapon_check
= NEED_WEAPON
;
744 /* attack bonus for strength & dexterity */
749 int str
= ACURR(A_STR
), dex
= ACURR(A_DEX
);
752 return (adj_lev(&mons
[u
.umonnum
]) - 3);
759 else if (str
<= STR18(50))
760 sbon
= 1; /* up to 18/50 */
761 else if (str
< STR18(100))
766 /* Game tuning kludge: make it a bit easier for a low level character to
768 sbon
+= (u
.ulevel
< 3) ? 1 : 0;
779 return (sbon
+ dex
- 14);
782 /* damage bonus for strength */
786 int str
= ACURR(A_STR
);
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 */
809 /* increase a towel's wetness */
811 wet_a_towel(obj
, amt
, verbose
)
813 int amt
; /* positive: new value; negative: increment by -amt; zero: no-op */
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
) {
821 const char *wetness
= (newspe
< 3)
822 ? (!obj
->spe
? "damp" : "damper")
823 : (!obj
->spe
? "wet" : "wetter");
826 pline("%s gets %s.", Yobjnam2(obj
, (const char *) 0),
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 */
838 unweapon
= !is_wet_towel(obj
);
841 /* decrease a towel's wetness */
843 dry_a_towel(obj
, amt
, verbose
)
845 int amt
; /* positive: new value; negative: decrement by -amt; zero: no-op */
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
) {
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 */
867 unweapon
= !is_wet_towel(obj
);
870 /* copy the skill level name into the given buffer */
872 skill_level_name(skill
, buf
)
878 switch (P_SKILL(skill
)) {
891 /* these are for unarmed combat/martial arts only */
896 ptr
= "Grand Master";
906 /* return the # of slots required to advance the skill */
908 slots_required(skill
)
911 int tmp
= P_SKILL(skill
);
913 /* The more difficult the training, the more slots it takes.
914 * unskilled -> basic 1
916 * skilled -> expert 3
918 if (skill
<= P_LAST_WEAPON
|| skill
== P_TWO_WEAPON_COMBAT
)
921 /* Fewer slots used up for unarmed or martial.
922 * unskilled -> basic 1
924 * skilled -> expert 2
926 * master -> grand master 3
928 return (tmp
+ 1) / 2;
931 /* return true if this skill can be advanced */
934 can_advance(skill
, speedy
)
938 if (P_RESTRICTED(skill
)
939 || P_SKILL(skill
) >= P_MAX_SKILL(skill
)
940 || u
.skills_advanced
>= P_SKILL_LIMIT
)
943 if (wizard
&& speedy
)
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 */
956 if (P_RESTRICTED(skill
)
957 || P_SKILL(skill
) >= P_MAX_SKILL(skill
)
958 || u
.skills_advanced
>= P_SKILL_LIMIT
)
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 */
971 if (P_RESTRICTED(skill
))
974 return (boolean
) (P_SKILL(skill
) >= P_MAX_SKILL(skill
)
975 && ((int) P_ADVANCE(skill
)
976 >= practice_needed_to_advance(P_SKILL(skill
))));
983 u
.weapon_slots
-= slots_required(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",
992 static const struct skill_range
{
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
];
1015 menu_item
*selected
;
1018 boolean speedy
= FALSE
;
1020 if (wizard
&& yn("Advance skills without practice?") == 'y')
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
))
1029 if ((len
= strlen(P_NAME(i
))) > longest
)
1031 if (can_advance(i
, speedy
))
1033 else if (could_advance(i
))
1034 eventually_advance
++;
1035 else if (peaked_skill(i
))
1039 win
= create_nhwindow(NHW_MENU
);
1042 /* start with a legend if any entries will be annotated
1043 with "*" or "#" below */
1044 if (eventually_advance
> 0 || maxxed_cnt
> 0) {
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
,
1055 if (maxxed_cnt
> 0) {
1057 "(Skill%s flagged by \"#\" cannot be enhanced any further.)",
1059 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
,
1062 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "",
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
;
1073 /* Print headings for skill types */
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
))
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
))
1092 else if (peaked_skill(i
))
1096 (to_advance
+ eventually_advance
+ maxxed_cnt
> 0)
1099 (void) skill_level_name(i
, sklnambuf
);
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
)));
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
)));
1110 if (!iflags
.menu_tab_sep
)
1111 Sprintf(buf
, " %s %-*s [%s]", prefix
, longest
,
1112 P_NAME(i
), sklnambuf
);
1114 Sprintf(buf
, " %s%s\t[%s]", prefix
, P_NAME(i
),
1117 any
.a_int
= can_advance(i
, speedy
) ? i
+ 1 : 0;
1118 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
,
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
));
1128 n
= select_menu(win
, to_advance
? PICK_ONE
: PICK_NONE
, &selected
);
1129 destroy_nhwindow(win
);
1131 n
= selected
[0].item
.a_int
- 1; /* get item selected */
1132 free((genericptr_t
) selected
);
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
)) {
1138 You_feel("you could be more dangerous!");
1144 } while (speedy
&& n
> 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.
1153 unrestrict_weapon_skill(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;
1164 use_skill(skill
, 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
);
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
))
1187 u
.weapon_slots
+= n
;
1188 for (i
= 0, after
= 0; i
< P_NUM_SKILLS
; i
++)
1189 if (can_advance(i
, FALSE
))
1192 give_may_advance_msg(P_NONE
);
1196 lose_weapon_skill(n
)
1197 int n
; /* number of slots to lose; normally one */
1202 /* deduct first from unused slots then from last placed one, if any */
1203 if (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.... */
1223 /* KMH -- now uses the object table */
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
;
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
)
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
1260 if (type
== P_NONE
) {
1262 } else if (type
<= P_LAST_WEAPON
) {
1263 switch (P_SKILL(type
)) {
1265 impossible(bad_skill
, P_SKILL(type
)); /* fall through */
1266 case P_ISRESTRICTED
:
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
);
1286 impossible(bad_skill
, skill
); /* fall through */
1287 case P_ISRESTRICTED
:
1301 } else if (type
== P_BARE_HANDED_COMBAT
) {
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 */
1318 switch (P_SKILL(P_RIDING
)) {
1319 case P_ISRESTRICTED
:
1339 * Return damage bonus/penalty based on skill of weapon.
1340 * Treat restricted weapons as unskilled.
1343 weapon_dam_bonus(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
1354 if (type
== P_NONE
) {
1356 } else if (type
<= P_LAST_WEAPON
) {
1357 switch (P_SKILL(type
)) {
1359 impossible("weapon_dam_bonus: bad skill %d", P_SKILL(type
));
1361 case P_ISRESTRICTED
:
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
);
1381 case P_ISRESTRICTED
:
1395 } else if (type
== P_BARE_HANDED_COMBAT
) {
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
:
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
1437 skill_init(class_skill
)
1438 const struct def_skill
*class_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) */
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
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
));
1511 setmnotwielded(mon
, obj
)
1512 register struct monst
*mon
;
1513 register struct obj
*obj
;
1517 if (artifact_light(obj
) && obj
->lamplit
) {
1518 end_burn(obj
, FALSE
);
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
)
1526 obj
->owornmask
&= ~W_WEP
;