1 /* NetHack 3.6 weapon.c $NHDT-Date: 1446078767 2015/10/29 00:32:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.55 $ */
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
11 /* JNetHack Copyright */
12 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
13 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
14 /* JNetHack may be freely redistributed. See license for details. */
18 /* Categories whose names don't come from OBJ_NAME(objects[type])
20 #define PN_BARE_HANDED (-1) /* includes martial arts */
21 #define PN_TWO_WEAPONS (-2)
22 #define PN_RIDING (-3)
23 #define PN_POLEARMS (-4)
25 #define PN_HAMMER (-6)
27 #define PN_ATTACK_SPELL (-8)
28 #define PN_HEALING_SPELL (-9)
29 #define PN_DIVINATION_SPELL (-10)
30 #define PN_ENCHANTMENT_SPELL (-11)
31 #define PN_CLERIC_SPELL (-12)
32 #define PN_ESCAPE_SPELL (-13)
33 #define PN_MATTER_SPELL (-14)
35 STATIC_DCL void FDECL(give_may_advance_msg, (int));
37 STATIC_VAR NEARDATA const short skill_names_indices[P_NUM_SKILLS] = {
38 0, DAGGER, KNIFE, AXE, PICK_AXE, SHORT_SWORD, BROADSWORD, LONG_SWORD,
39 TWO_HANDED_SWORD, SCIMITAR, PN_SABER, CLUB, MACE, MORNING_STAR, FLAIL,
40 PN_HAMMER, QUARTERSTAFF, PN_POLEARMS, SPEAR, TRIDENT, LANCE, BOW, SLING,
41 CROSSBOW, DART, SHURIKEN, BOOMERANG, PN_WHIP, UNICORN_HORN,
42 PN_ATTACK_SPELL, PN_HEALING_SPELL, PN_DIVINATION_SPELL,
43 PN_ENCHANTMENT_SPELL, PN_CLERIC_SPELL, PN_ESCAPE_SPELL, PN_MATTER_SPELL,
44 PN_BARE_HANDED, PN_TWO_WEAPONS, PN_RIDING
47 /* note: entry [0] isn't used */
48 STATIC_VAR NEARDATA const char *const odd_skill_names[] = {
49 "no skill", "bare hands", /* use barehands_or_martial[] instead */
50 "two weapon combat", "riding", "polearms", "saber", "hammer", "whip",
51 "attack spells", "healing spells", "divination spells",
52 "enchantment spells", "clerical spells", "escape spells", "matter spells",
54 /* indexed vis `is_martial() */
55 STATIC_VAR NEARDATA const char *const barehands_or_martial[] = {
56 "bare handed combat", "martial arts"
60 give_may_advance_msg(skill)
64 You_feel("more confident in your %sskills.",
65 skill == P_NONE ? "" : skill <= P_LAST_WEAPON
67 : skill <= P_LAST_SPELL
71 You("%s
\83X
\83L
\83\8b\82ð
\8d\82\82ß
\82é
\8e©
\90M
\82ª
\97N
\82¢
\82Ä
\82«
\82½
\81D",
72 skill == P_NONE ? "" : skill <= P_LAST_WEAPON
74 : skill <= P_LAST_SPELL
80 STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P));
81 STATIC_DCL boolean FDECL(could_advance, (int));
82 STATIC_DCL boolean FDECL(peaked_skill, (int));
83 STATIC_DCL int FDECL(slots_required, (int));
84 STATIC_DCL char *FDECL(skill_level_name, (int, char *));
85 STATIC_DCL void FDECL(skill_advance, (int));
87 #define P_NAME(type) \
88 ((skill_names_indices[type] > 0) \
89 ? OBJ_NAME(objects[skill_names_indices[type]]) \
90 : (type == P_BARE_HANDED_COMBAT) \
91 ? barehands_or_martial[martial_bonus()] \
92 : odd_skill_names[-skill_names_indices[type]])
94 static NEARDATA const char kebabable[] = { S_XORN, S_DRAGON, S_JABBERWOCK,
95 S_NAGA, S_GIANT, '\0' };
97 /* weapon's skill category name for use as generalized description of weapon;
98 mostly used to shorten "you drop your <weapon>" messages when slippery
99 fingers or polymorph causes hero to involuntarily drop wielded weapon(s) */
104 int skill = weapon_type(obj);
105 const char *descr = P_NAME(skill);
107 /* assorted special cases */
110 /* not a weapon or weptool: use item class name;
111 override class name "food" for corpses, tins, and eggs,
112 "large rock" for statues and boulders, and "tool" for towels */
113 descr = (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG
114 || obj->otyp == STATUE || obj->otyp == BOULDER
115 || obj->otyp == TOWEL)
116 ? OBJ_NAME(objects[obj->otyp])
117 : def_oc_syms[(int) obj->oclass].name;
121 descr = (obj->otyp == ROCK || is_graystone(obj))
123 /* avoid "rock"; what about known glass? */
124 : (obj->oclass == GEM_CLASS)
126 /* in case somebody adds odd sling ammo */
127 : def_oc_syms[(int) obj->oclass].name;
138 if (obj->otyp == GRAPPLING_HOOK)
142 /* even if "dwarvish mattock" hasn't been discovered yet */
143 if (obj->otyp == DWARVISH_MATTOCK)
149 return makesingular(descr);
153 * hitval returns an integer representing the "to hit" bonuses
154 * of "otmp" against the monster.
162 struct permonst *ptr = mon->data;
163 boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
168 /* Put weapon specific "to hit" bonuses in below: */
169 tmp += objects[otmp->otyp].oc_hitbon;
171 /* Put weapon vs. monster type "to hit" bonuses in below: */
173 /* Blessed weapons used against undead or demons */
174 if (Is_weapon && otmp->blessed
175 && (is_demon(ptr) || is_undead(ptr) || is_vampshifter(mon)))
178 if (is_spear(otmp) && index(kebabable, ptr->mlet))
181 /* trident is highly effective against swimmers */
182 if (otmp->otyp == TRIDENT && is_swimmer(ptr)) {
183 if (is_pool(mon->mx, mon->my))
185 else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE)
189 /* Picks used against xorns and earth elementals */
190 if (is_pick(otmp) && (passes_walls(ptr) && thick_skinned(ptr)))
193 /* Check specially named weapon "to hit" bonuses */
195 tmp += spec_abon(otmp, mon);
200 /* Historical note: The original versions of Hack used a range of damage
201 * which was similar to, but not identical to the damage used in Advanced
202 * Dungeons and Dragons. I figured that since it was so close, I may as well
203 * make it exactly the same as AD&D, adding some more weapons in the process.
204 * This has the advantage that it is at least possible that the player would
205 * already know the damage of at least some of the weapons. This was circa
206 * 1987 and I used the table from Unearthed Arcana until I got tired of typing
207 * them in (leading to something of an imbalance towards weapons early in
208 * alphabetical order). The data structure still doesn't include fields that
209 * fully allow the appropriate damage to be described (there's no way to say
210 * 3d6 or 1d6+1) so we add on the extra damage in dmgval() if the weapon
211 * doesn't do an exact die of damage.
213 * Of course new weapons were added later in the development of Nethack. No
214 * AD&D consistency was kept, but most of these don't exist in AD&D anyway.
216 * Second edition AD&D came out a few years later; luckily it used the same
217 * table. As of this writing (1999), third edition is in progress but not
218 * released. Let's see if the weapon table stays the same. --KAA
219 * October 2000: It didn't. Oh, well.
223 * dmgval returns an integer representing the damage bonuses
224 * of "otmp" against the monster.
231 int tmp = 0, otyp = otmp->otyp;
232 struct permonst *ptr = mon->data;
233 boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
235 if (otyp == CREAM_PIE)
239 if (objects[otyp].oc_wldam)
240 tmp = rnd(objects[otyp].oc_wldam);
247 case ELVEN_BROADSWORD:
271 case DWARVISH_MATTOCK:
272 case TWO_HANDED_SWORD:
277 if (objects[otyp].oc_wsdam)
278 tmp = rnd(objects[otyp].oc_wsdam);
298 case ELVEN_BROADSWORD:
311 /* negative enchantment mustn't produce negative damage */
316 if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr))
317 /* thick skinned/scaled creatures don't feel it */
319 if (ptr == &mons[PM_SHADE] && !shade_glare(otmp))
322 /* "very heavy iron ball"; weight increase is in increments of 160 */
323 if (otyp == HEAVY_IRON_BALL && tmp > 0) {
324 int wt = (int) objects[HEAVY_IRON_BALL].oc_weight;
326 if ((int) otmp->owt > wt) {
327 wt = ((int) otmp->owt - wt) / 160;
330 tmp = 25; /* objects[].oc_wldam */
334 /* Put weapon vs. monster type damage bonuses in below: */
335 if (Is_weapon || otmp->oclass == GEM_CLASS || otmp->oclass == BALL_CLASS
336 || otmp->oclass == CHAIN_CLASS) {
340 && (is_undead(ptr) || is_demon(ptr) || is_vampshifter(mon)))
342 if (is_axe(otmp) && is_wooden(ptr))
344 if (objects[otyp].oc_material == SILVER && mon_hates_silver(mon))
347 /* if the weapon is going to get a double damage bonus, adjust
348 this bonus so that effectively it's added after the doubling */
349 if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25)
350 bonus = (bonus + 1) / 2;
356 /* It's debatable whether a rusted blunt instrument
357 should do less damage than a pristine one, since
358 it will hit with essentially the same impact, but
359 there ought to some penalty for using damaged gear
360 so always subtract erosion even for blunt weapons. */
361 tmp -= greatest_erosion(otmp);
369 STATIC_DCL struct obj *FDECL(oselect, (struct monst *, int));
371 if ((otmp = oselect(mtmp, x)) != 0) \
374 STATIC_OVL struct obj *
381 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
383 /* never select non-cockatrice corpses */
384 && !((x == CORPSE || x == EGG)
385 && !touch_petrifies(&mons[otmp->corpsenm]))
386 && (!otmp->oartifact || touch_artifact(otmp, mtmp)))
389 return (struct obj *) 0;
392 static NEARDATA const int rwep[] = {
393 DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN,
394 SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW,
395 CROSSBOW_BOLT, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE,
396 FLINT, ROCK, LOADSTONE, LUCKSTONE, DART,
397 /* BOOMERANG, */ CREAM_PIE
400 static NEARDATA const int pwep[] = { HALBERD, BARDICHE, SPETUM,
401 BILL_GUISARME, VOULGE, RANSEUR,
402 GUISARME, GLAIVE, LUCERN_HAMMER,
403 BEC_DE_CORBIN, FAUCHARD, PARTISAN,
406 static struct obj *propellor;
408 /* select a ranged weapon for the monster */
411 register struct monst *mtmp;
413 register struct obj *otmp;
418 char mlet = mtmp->data->mlet;
420 propellor = &zeroobj;
421 Oselect(EGG); /* cockatrice egg */
422 if (mlet == S_KOP) /* pies are first choice for Kops */
424 if (throws_rocks(mtmp->data)) /* ...boulders for giants */
427 /* Select polearms first; they do more damage and aren't expendable.
428 But don't pick one if monster's weapon is welded, because then
429 we'd never have a chance to throw non-wielding missiles. */
430 /* The limit of 13 here is based on the monster polearm range limit
431 * (defined as 5 in mthrowu.c). 5 corresponds to a distance of 2 in
432 * one direction and 1 in another; one space beyond that would be 3 in
433 * one direction and 2 in another; 3^2+2^2=13.
435 mwep = MON_WEP(mtmp);
436 /* NO_WEAPON_WANTED means we already tried to wield and failed */
437 mweponly = (mwelded(mwep) && mtmp->weapon_check == NO_WEAPON_WANTED);
438 if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 13
439 && couldsee(mtmp->mx, mtmp->my)) {
440 for (i = 0; i < SIZE(pwep); i++) {
441 /* Only strong monsters can wield big (esp. long) weapons.
442 * Big weapon is basically the same as bimanual.
443 * All monsters can wield the remaining weapons.
445 if (((strongmonst(mtmp->data)
446 && (mtmp->misc_worn_check & W_ARMS) == 0)
447 || !objects[pwep[i]].oc_bimanual)
448 && (objects[pwep[i]].oc_material != SILVER
449 || !mon_hates_silver(mtmp))) {
450 if ((otmp = oselect(mtmp, pwep[i])) != 0
451 && (otmp == mwep || !mweponly)) {
452 propellor = otmp; /* force the monster to wield it */
460 * other than these two specific cases, always select the
461 * most potent ranged weapon to hand.
463 for (i = 0; i < SIZE(rwep); i++) {
466 /* shooting gems from slings; this goes just before the darts */
467 /* (shooting rocks is already handled via the rwep[] ordering) */
468 if (rwep[i] == DART && !likes_gems(mtmp->data)
469 && m_carrying(mtmp, SLING)) { /* propellor */
470 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
471 if (otmp->oclass == GEM_CLASS
472 && (otmp->otyp != LOADSTONE || !otmp->cursed)) {
473 propellor = m_carrying(mtmp, SLING);
478 /* KMH -- This belongs here so darts will work */
479 propellor = &zeroobj;
481 prop = (objects[rwep[i]]).oc_skill;
485 propellor = (oselect(mtmp, YUMI));
487 propellor = (oselect(mtmp, ELVEN_BOW));
489 propellor = (oselect(mtmp, BOW));
491 propellor = (oselect(mtmp, ORCISH_BOW));
494 propellor = (oselect(mtmp, SLING));
497 propellor = (oselect(mtmp, CROSSBOW));
499 if ((otmp = MON_WEP(mtmp)) && mwelded(otmp) && otmp != propellor
500 && mtmp->weapon_check == NO_WEAPON_WANTED)
503 /* propellor = obj, propellor to use
504 * propellor = &zeroobj, doesn't need a propellor
505 * propellor = 0, needed one and didn't have one
507 if (propellor != 0) {
508 /* Note: cannot use m_carrying for loadstones, since it will
509 * always select the first object of a type, and maybe the
510 * monster is carrying two but only the first is unthrowable.
512 if (rwep[i] != LOADSTONE) {
513 /* Don't throw a cursed weapon-in-hand or an artifact */
514 if ((otmp = oselect(mtmp, rwep[i])) && !otmp->oartifact
515 && !(otmp == MON_WEP(mtmp) && mwelded(otmp)))
518 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
519 if (otmp->otyp == LOADSTONE && !otmp->cursed)
526 return (struct obj *) 0;
529 /* Weapons in order of preference */
530 static const NEARDATA short hwep[] = {
531 CORPSE, /* cockatrice corpse */
532 TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE,
533 KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD, ELVEN_BROADSWORD,
534 BROADSWORD, SCIMITAR, SILVER_SABER, MORNING_STAR, ELVEN_SHORT_SWORD,
535 DWARVISH_SHORT_SWORD, SHORT_SWORD, ORCISH_SHORT_SWORD, MACE, AXE,
536 DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL,
537 BULLWHIP, QUARTERSTAFF, JAVELIN, AKLYS, CLUB, PICK_AXE, RUBBER_HOSE,
538 WAR_HAMMER, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, ATHAME,
539 SCALPEL, KNIFE, WORM_TOOTH
542 /* select a hand to hand weapon for the monster */
545 register struct monst *mtmp;
547 register struct obj *otmp;
549 boolean strong = strongmonst(mtmp->data);
550 boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0;
552 /* prefer artifacts to everything else */
553 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
554 if (otmp->oclass == WEAPON_CLASS && otmp->oartifact
555 && touch_artifact(otmp, mtmp)
556 && ((strong && !wearing_shield)
557 || !objects[otmp->otyp].oc_bimanual))
561 if (is_giant(mtmp->data)) /* giants just love to use clubs */
564 /* only strong monsters can wield big (esp. long) weapons */
565 /* big weapon is basically the same as bimanual */
566 /* all monsters can wield the remaining weapons */
567 for (i = 0; i < SIZE(hwep); i++) {
568 if (hwep[i] == CORPSE && !(mtmp->misc_worn_check & W_ARMG)
569 && !resists_ston(mtmp))
571 if (((strong && !wearing_shield) || !objects[hwep[i]].oc_bimanual)
572 && (objects[hwep[i]].oc_material != SILVER
573 || !mon_hates_silver(mtmp)))
578 return (struct obj *) 0;
581 /* Called after polymorphing a monster, robbing it, etc.... Monsters
582 * otherwise never unwield stuff on their own. Might print message.
585 possibly_unwield(mon, polyspot)
589 struct obj *obj, *mw_tmp;
591 if (!(mw_tmp = MON_WEP(mon)))
593 for (obj = mon->minvent; obj; obj = obj->nobj)
596 if (!obj) { /* The weapon was stolen or destroyed */
598 mon->weapon_check = NEED_WEAPON;
601 if (!attacktype(mon->data, AT_WEAP)) {
602 setmnotwielded(mon, mw_tmp);
603 mon->weapon_check = NO_WEAPON_WANTED;
604 obj_extract_self(obj);
605 if (cansee(mon->mx, mon->my)) {
607 pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
609 pline("%s
\82Í%s
\82ð
\92u
\82¢
\82½
\81D", Monnam(mon), distant_name(obj, doname));
610 newsym(mon->mx, mon->my);
612 /* might be dropping object into water or lava */
614 if (!flooreffects(obj, mon->mx, mon->my, "drop")) {
616 if (!flooreffects(obj, mon->mx, mon->my, "
\97\8e\82¿
\82é")) {
619 place_object(obj, mon->mx, mon->my);
624 /* The remaining case where there is a change is where a monster
625 * is polymorphed into a stronger/weaker monster with a different
626 * choice of weapons. This has no parallel for players. It can
627 * be handled by waiting until mon_wield_item is actually called.
628 * Though the monster still wields the wrong weapon until then,
629 * this is OK since the player can't see it. (FIXME: Not okay since
630 * probing can reveal it.)
631 * Note that if there is no change, setting the check to NEED_WEAPON
633 * Possible problem: big monster with big cursed weapon gets
634 * polymorphed into little monster. But it's not quite clear how to
635 * handle this anyway....
637 if (!(mwelded(mw_tmp) && mon->weapon_check == NO_WEAPON_WANTED))
638 mon->weapon_check = NEED_WEAPON;
642 /* Let a monster try to wield a weapon, based on mon->weapon_check.
643 * Returns 1 if the monster took time to do it, 0 if it did not.
647 register struct monst *mon;
651 /* This case actually should never happen */
652 if (mon->weapon_check == NO_WEAPON_WANTED)
654 switch (mon->weapon_check) {
655 case NEED_HTH_WEAPON:
656 obj = select_hwep(mon);
658 case NEED_RANGED_WEAPON:
659 (void) select_rwep(mon);
663 obj = m_carrying(mon, PICK_AXE);
664 /* KMH -- allow other picks */
665 if (!obj && !which_armor(mon, W_ARMS))
666 obj = m_carrying(mon, DWARVISH_MATTOCK);
669 /* currently, only 2 types of axe */
670 obj = m_carrying(mon, BATTLE_AXE);
671 if (!obj || which_armor(mon, W_ARMS))
672 obj = m_carrying(mon, AXE);
674 case NEED_PICK_OR_AXE:
675 /* prefer pick for fewer switches on most levels */
676 obj = m_carrying(mon, DWARVISH_MATTOCK);
678 obj = m_carrying(mon, BATTLE_AXE);
679 if (!obj || which_armor(mon, W_ARMS)) {
680 obj = m_carrying(mon, PICK_AXE);
682 obj = m_carrying(mon, AXE);
686 impossible("weapon_check %d for %s?", mon->weapon_check,
690 if (obj && obj != &zeroobj) {
691 struct obj *mw_tmp = MON_WEP(mon);
692 if (mw_tmp && mw_tmp->otyp == obj->otyp) {
693 /* already wielding it */
694 mon->weapon_check = NEED_WEAPON;
697 /* Actually, this isn't necessary--as soon as the monster
698 * wields the weapon, the weapon welds itself, so the monster
699 * can know it's cursed and needn't even bother trying.
702 if (mw_tmp && mwelded(mw_tmp)) {
703 if (canseemon(mon)) {
704 char welded_buf[BUFSZ];
705 const char *mon_hand = mbodypart(mon, HAND);
707 if (bimanual(mw_tmp))
708 mon_hand = makeplural(mon_hand);
710 Sprintf(welded_buf, "%s welded to %s %s",
711 otense(mw_tmp, "are"), mhis(mon), mon_hand);
714 if (obj->otyp == PICK_AXE) {
716 pline("Since %s weapon%s %s,", s_suffix(mon_nam(mon)),
717 plur(mw_tmp->quan), welded_buf);
719 pline("%s
\82Í
\95\90\8aí
\82ð
\8eè
\82É
\82µ
\82æ
\82¤
\82Æ
\82µ
\82½
\82ª
\81C", mon_nam(mon));
722 pline("%s cannot wield that %s.", mon_nam(mon),
725 pline("%s
\82Í%s
\82ð
\91\95\94õ
\82Å
\82«
\82È
\82©
\82Á
\82½
\81D", mon_nam(mon),
730 pline("%s tries to wield %s.", Monnam(mon), doname(obj));
732 pline("%s
\82Í%s
\82ð
\91\95\94õ
\82µ
\82æ
\82¤
\82Æ
\82µ
\82½
\81D", Monnam(mon), doname(obj));
734 pline("%s %s!", Yname2(mw_tmp), welded_buf);
736 pline("%s
\82Í%s
\82ð
\8eè
\82É
\82µ
\82½
\81I", Monnam(mon), xname(mw_tmp));
740 mon->weapon_check = NO_WEAPON_WANTED;
743 mon->mw = obj; /* wield obj */
744 setmnotwielded(mon, mw_tmp);
745 mon->weapon_check = NEED_WEAPON;
746 if (canseemon(mon)) {
748 pline("%s wields %s!", Monnam(mon), doname(obj));
750 pline("%s
\82Í%s
\82ð
\91\95\94õ
\82µ
\82½
\81I", Monnam(mon), doname(obj));
751 if (mwelded(mw_tmp)) {
753 pline("%s %s to %s %s!", Tobjnam(obj, "weld"),
754 is_plural(obj) ? "themselves" : "itself",
755 s_suffix(mon_nam(mon)), mbodypart(mon, HAND));
757 pline("%s
\82Í
\8f\9f\8eè
\82É%s
\82Ì%s
\82É
\91\95\94õ
\82³
\82ê
\82½
\81I",
759 mon_nam(mon), mbodypart(mon, HAND));
764 if (artifact_light(obj) && !obj->lamplit) {
765 begin_burn(obj, FALSE);
768 pline("%s %s in %s %s!", Tobjnam(obj, "shine"),
769 arti_light_description(obj), s_suffix(mon_nam(mon)),
770 mbodypart(mon, HAND));
772 pline("%s
\82Í%s
\82Ì%s
\82Ì
\92\86\82Å%s
\8bP
\82¢
\82½
\81I",
773 xname(obj), mon_nam(mon),
774 mbodypart(mon, HAND), arti_light_description(obj));
777 obj->owornmask = W_WEP;
780 mon->weapon_check = NEED_WEAPON;
784 /* force monster to stop wielding current weapon, if any */
789 struct obj *mwep = MON_WEP(mon);
792 setmnotwielded(mon, mwep);
793 mon->weapon_check = NEED_WEAPON;
797 /* attack bonus for strength & dexterity */
802 int str = ACURR(A_STR), dex = ACURR(A_DEX);
805 return (adj_lev(&mons[u.umonnum]) - 3);
812 else if (str <= STR18(50))
813 sbon = 1; /* up to 18/50 */
814 else if (str < STR18(100))
819 /* Game tuning kludge: make it a bit easier for a low level character to
821 sbon += (u.ulevel < 3) ? 1 : 0;
832 return (sbon + dex - 14);
835 /* damage bonus for strength */
839 int str = ACURR(A_STR);
851 return 2; /* up to 18 */
852 else if (str <= STR18(75))
853 return 3; /* up to 18/75 */
854 else if (str <= STR18(90))
855 return 4; /* up to 18/90 */
856 else if (str < STR18(100))
857 return 5; /* up to 18/99 */
862 /* increase a towel's wetness */
864 wet_a_towel(obj, amt, verbose)
866 int amt; /* positive: new value; negative: increment by -amt; zero: no-op */
869 int newspe = (amt <= 0) ? obj->spe - amt : amt;
871 /* new state is only reported if it's an increase */
872 if (newspe > obj->spe) {
874 const char *wetness = (newspe < 3)
875 ? (!obj->spe ? "damp" : "damper")
876 : (!obj->spe ? "wet" : "wetter");
879 pline("%s gets %s.", Yobjnam2(obj, (const char *) 0),
881 else if (mcarried(obj) && canseemon(obj->ocarry))
882 pline("%s %s gets %s.", s_suffix(Monnam(obj->ocarry)),
883 xname(obj), wetness);
886 obj->spe = min(newspe, 7);
888 /* if hero is wielding this towel, don't give "you begin bashing
889 with your wet towel" message on next attack with it */
891 unweapon = !is_wet_towel(obj);
894 /* decrease a towel's wetness */
896 dry_a_towel(obj, amt, verbose)
898 int amt; /* positive: new value; negative: decrement by -amt; zero: no-op */
901 int newspe = (amt <= 0) ? obj->spe + amt : amt;
903 /* new state is only reported if it's a decrease */
904 if (newspe < obj->spe) {
907 pline("%s dries%s.", Yobjnam2(obj, (const char *) 0),
908 !newspe ? " out" : "");
909 else if (mcarried(obj) && canseemon(obj->ocarry))
910 pline("%s %s drie%s.", s_suffix(Monnam(obj->ocarry)),
911 xname(obj), !newspe ? " out" : "");
914 newspe = min(newspe, 7);
915 obj->spe = max(newspe, 0);
917 /* if hero is wielding this towel and it is now dry, give "you begin
918 bashing with your towel" message on next attack with it */
920 unweapon = !is_wet_towel(obj);
923 /* copy the skill level name into the given buffer */
925 skill_level_name(skill, buf)
931 switch (P_SKILL(skill)) {
936 ptr = "
\8f\89\90S
\8eÒ";
942 ptr = "
\93ü
\96å
\8eÒ";
948 ptr = "
\8fn
\97û
\8eÒ";
954 ptr = "
\83G
\83L
\83X
\83p
\81[
\83g";
956 /* these are for unarmed combat/martial arts only */
961 ptr = "
\83}
\83X
\83^
\81[";
965 ptr = "Grand Master";
967 ptr = "
\83O
\83\89\83\93\83h
\83}
\83X
\83^
\81[";
980 /* return the # of slots required to advance the skill */
982 slots_required(skill)
985 int tmp = P_SKILL(skill);
987 /* The more difficult the training, the more slots it takes.
988 * unskilled -> basic 1
990 * skilled -> expert 3
992 if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT)
995 /* Fewer slots used up for unarmed or martial.
996 * unskilled -> basic 1
998 * skilled -> expert 2
1000 * master -> grand master 3
1002 return (tmp + 1) / 2;
1005 /* return true if this skill can be advanced */
1008 can_advance(skill, speedy)
1012 if (P_RESTRICTED(skill)
1013 || P_SKILL(skill) >= P_MAX_SKILL(skill)
1014 || u.skills_advanced >= P_SKILL_LIMIT)
1017 if (wizard && speedy)
1020 return (boolean) ((int) P_ADVANCE(skill)
1021 >= practice_needed_to_advance(P_SKILL(skill))
1022 && u.weapon_slots >= slots_required(skill));
1025 /* return true if this skill could be advanced if more slots were available */
1027 could_advance(skill)
1030 if (P_RESTRICTED(skill)
1031 || P_SKILL(skill) >= P_MAX_SKILL(skill)
1032 || u.skills_advanced >= P_SKILL_LIMIT)
1035 return (boolean) ((int) P_ADVANCE(skill)
1036 >= practice_needed_to_advance(P_SKILL(skill)));
1039 /* return true if this skill has reached its maximum and there's been enough
1040 practice to become eligible for the next step if that had been possible */
1045 if (P_RESTRICTED(skill))
1048 return (boolean) (P_SKILL(skill) >= P_MAX_SKILL(skill)
1049 && ((int) P_ADVANCE(skill)
1050 >= practice_needed_to_advance(P_SKILL(skill))));
1054 skill_advance(skill)
1057 u.weapon_slots -= slots_required(skill);
1059 u.skill_record[u.skills_advanced++] = skill;
1060 /* subtly change the advance message to indicate no more advancement */
1062 You("are now %s skilled in %s.",
1063 P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more",
1066 Your("%s
\82Ì
\83X
\83L
\83\8b\82ð%s
\8d\82\82ß
\82½
\81D",
1068 P_SKILL(skill) >= P_MAX_SKILL(skill) ? "
\8dÅ
\8d\82\82É" : "
\82³
\82ç
\82É");
1072 static const struct skill_range {
1075 } skill_ranges[] = {
1077 { P_FIRST_H_TO_H, P_LAST_H_TO_H, "Fighting Skills" },
1079 { P_FIRST_H_TO_H, P_LAST_H_TO_H, "
\90í
\82¢
\82Ì
\83X
\83L
\83\8b" },
1081 { P_FIRST_WEAPON, P_LAST_WEAPON, "Weapon Skills" },
1083 { P_FIRST_WEAPON, P_LAST_WEAPON, "
\95\90\8aí
\82Ì
\83X
\83L
\83\8b" },
1085 { P_FIRST_SPELL, P_LAST_SPELL, "Spellcasting Skills" },
1087 { P_FIRST_SPELL, P_LAST_SPELL, "
\96\82\96@
\82Ì
\83X
\83L
\83\8b" },
1091 * The `#enhance' extended command. What we _really_ would like is
1092 * to keep being able to pick things to advance until we couldn't any
1093 * more. This is currently not possible -- the menu code has no way
1094 * to call us back for instant action. Even if it did, we would also need
1095 * to be able to update the menu since selecting one item could make
1096 * others unselectable.
1099 enhance_weapon_skill()
1101 int pass, i, n, len, longest, to_advance, eventually_advance, maxxed_cnt;
1102 char buf[BUFSZ], sklnambuf[BUFSZ];
1104 menu_item *selected;
1107 boolean speedy = FALSE;
1109 if (wizard && yn("Advance skills without practice?") == 'y')
1113 /* find longest available skill name, count those that can advance */
1114 to_advance = eventually_advance = maxxed_cnt = 0;
1115 for (longest = 0, i = 0; i < P_NUM_SKILLS; i++) {
1116 if (P_RESTRICTED(i))
1118 if ((len = strlen(P_NAME(i))) > longest)
1120 if (can_advance(i, speedy))
1122 else if (could_advance(i))
1123 eventually_advance++;
1124 else if (peaked_skill(i))
1128 win = create_nhwindow(NHW_MENU);
1131 /* start with a legend if any entries will be annotated
1132 with "*" or "#" below */
1133 if (eventually_advance > 0 || maxxed_cnt > 0) {
1135 if (eventually_advance > 0) {
1137 Sprintf(buf, "(Skill%s flagged by \"*\" may be enhanced %s.)",
1138 plur(eventually_advance),
1139 (u.ulevel < MAXULEV)
1140 ? "when you're more experienced"
1141 : "if skill slots become available");
1143 Sprintf(buf, "(\"*\"
\82ª
\82Â
\82¢
\82Ä
\82¢
\82é
\83X
\83L
\83\8b\82Í%s
\8d\82\82ß
\82ç
\82ê
\82é
\81D)",
1144 (u.ulevel < MAXULEV)
1145 ? "
\82à
\82Á
\82Æ
\8co
\8c±
\82ð
\82Â
\82ß
\82Î"
1146 : "
\83X
\83L
\83\8b\83X
\83\8d\83b
\83g
\82ª
\8eg
\82¦
\82é
\82æ
\82¤
\82É
\82È
\82ê
\82Î");
1148 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
1151 if (maxxed_cnt > 0) {
1154 "(Skill%s flagged by \"#\" cannot be enhanced any further.)",
1158 "(\"#\"
\82ª
\82Â
\82¢
\82Ä
\82¢
\82é
\83X
\83L
\83\8b\82Í
\82±
\82ê
\88È
\8fã
\8d\82\82ß
\82ç
\82ê
\82È
\82¢
\81D)");
1160 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
1163 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
1167 /* List the skills, making ones that could be advanced
1168 selectable. List the miscellaneous skills first.
1169 Possible future enhancement: list spell skills before
1170 weapon skills for spellcaster roles. */
1171 for (pass = 0; pass < SIZE(skill_ranges); pass++)
1172 for (i = skill_ranges[pass].first; i <= skill_ranges[pass].last;
1174 /* Print headings for skill types */
1176 if (i == skill_ranges[pass].first)
1177 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
1178 skill_ranges[pass].name, MENU_UNSELECTED);
1180 if (P_RESTRICTED(i))
1183 * Sigh, this assumes a monospaced font unless
1184 * iflags.menu_tab_sep is set in which case it puts
1185 * tabs between columns.
1186 * The 12 is the longest skill level name.
1187 * The " " is room for a selection letter and dash, "a - ".
1189 if (can_advance(i, speedy))
1190 prefix = ""; /* will be preceded by menu choice */
1191 else if (could_advance(i))
1193 else if (peaked_skill(i))
1197 (to_advance + eventually_advance + maxxed_cnt > 0)
1200 (void) skill_level_name(i, sklnambuf);
1202 if (!iflags.menu_tab_sep)
1203 Sprintf(buf, " %s%-*s %-12s %5d(%4d)", prefix,
1204 longest, P_NAME(i), sklnambuf, P_ADVANCE(i),
1205 practice_needed_to_advance(P_SKILL(i)));
1207 Sprintf(buf, " %s%s\t%s\t%5d(%4d)", prefix, P_NAME(i),
1208 sklnambuf, P_ADVANCE(i),
1209 practice_needed_to_advance(P_SKILL(i)));
1211 if (!iflags.menu_tab_sep)
1212 Sprintf(buf, " %s %-*s [%s]", prefix, longest,
1213 P_NAME(i), sklnambuf);
1215 Sprintf(buf, " %s%s\t[%s]", prefix, P_NAME(i),
1218 any.a_int = can_advance(i, speedy) ? i + 1 : 0;
1219 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
1224 Strcpy(buf, (to_advance > 0) ? "Pick a skill to advance:"
1225 : "Current skills:");
1227 Strcpy(buf, (to_advance > 0) ? "
\83X
\83L
\83\8b\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢
\81F"
1228 : "
\8c»
\8dÝ
\82Ì
\83X
\83L
\83\8b\81F");
1230 if (wizard && !speedy)
1231 Sprintf(eos(buf), " (%d slot%s available)", u.weapon_slots,
1232 plur(u.weapon_slots));
1234 n = select_menu(win, to_advance ? PICK_ONE : PICK_NONE, &selected);
1235 destroy_nhwindow(win);
1237 n = selected[0].item.a_int - 1; /* get item selected */
1238 free((genericptr_t) selected);
1240 /* check for more skills able to advance, if so then .. */
1241 for (n = i = 0; i < P_NUM_SKILLS; i++) {
1242 if (can_advance(i, speedy)) {
1245 You_feel("you could be more dangerous!");
1247 You("
\82³
\82ç
\82É
\83X
\83L
\83\8b\82ð
\8d\82\82ß
\82é
\82±
\82Æ
\82ª
\82Å
\82«
\82»
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I");
1253 } while (speedy && n > 0);
1258 * Change from restricted to unrestricted, allowing P_BASIC as max. This
1259 * function may be called with with P_NONE. Used in pray.c.
1262 unrestrict_weapon_skill(skill)
1265 if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) {
1266 P_SKILL(skill) = P_UNSKILLED;
1267 P_MAX_SKILL(skill) = P_BASIC;
1268 P_ADVANCE(skill) = 0;
1273 use_skill(skill, degree)
1277 boolean advance_before;
1279 if (skill != P_NONE && !P_RESTRICTED(skill)) {
1280 advance_before = can_advance(skill, FALSE);
1281 P_ADVANCE(skill) += degree;
1282 if (!advance_before && can_advance(skill, FALSE))
1283 give_may_advance_msg(skill);
1289 int n; /* number of slots to gain; normally one */
1291 int i, before, after;
1293 for (i = 0, before = 0; i < P_NUM_SKILLS; i++)
1294 if (can_advance(i, FALSE))
1296 u.weapon_slots += n;
1297 for (i = 0, after = 0; i < P_NUM_SKILLS; i++)
1298 if (can_advance(i, FALSE))
1301 give_may_advance_msg(P_NONE);
1305 lose_weapon_skill(n)
1306 int n; /* number of slots to lose; normally one */
1311 /* deduct first from unused slots then from last placed one, if any */
1312 if (u.weapon_slots) {
1314 } else if (u.skills_advanced) {
1315 skill = u.skill_record[--u.skills_advanced];
1316 if (P_SKILL(skill) <= P_UNSKILLED)
1317 panic("lose_weapon_skill (%d)", skill);
1318 P_SKILL(skill)--; /* drop skill one level */
1319 /* Lost skill might have taken more than one slot; refund rest. */
1320 u.weapon_slots = slots_required(skill) - 1;
1321 /* It might now be possible to advance some other pending
1322 skill by using the refunded slots, but giving a message
1323 to that effect would seem pretty confusing.... */
1332 /* KMH -- now uses the object table */
1336 return P_BARE_HANDED_COMBAT; /* Not using a weapon */
1337 if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS
1338 && obj->oclass != GEM_CLASS)
1339 return P_NONE; /* Not a weapon, weapon-tool, or ammo */
1340 type = objects[obj->otyp].oc_skill;
1341 return (type < 0) ? -type : type;
1348 return P_TWO_WEAPON_COMBAT;
1349 return weapon_type(uwep);
1353 * Return hit bonus/penalty based on skill of weapon.
1354 * Treat restricted weapons as unskilled.
1357 weapon_hit_bonus(weapon)
1360 int type, wep_type, skill, bonus = 0;
1361 static const char bad_skill[] = "weapon_hit_bonus: bad skill %d";
1363 wep_type = weapon_type(weapon);
1364 /* use two weapon skill only if attacking with one of the wielded weapons
1366 type = (u.twoweap && (weapon == uwep || weapon == uswapwep))
1367 ? P_TWO_WEAPON_COMBAT
1369 if (type == P_NONE) {
1371 } else if (type <= P_LAST_WEAPON) {
1372 switch (P_SKILL(type)) {
1374 impossible(bad_skill, P_SKILL(type)); /* fall through */
1375 case P_ISRESTRICTED:
1389 } else if (type == P_TWO_WEAPON_COMBAT) {
1390 skill = P_SKILL(P_TWO_WEAPON_COMBAT);
1391 if (P_SKILL(wep_type) < skill)
1392 skill = P_SKILL(wep_type);
1395 impossible(bad_skill, skill); /* fall through */
1396 case P_ISRESTRICTED:
1410 } else if (type == P_BARE_HANDED_COMBAT) {
1420 bonus = P_SKILL(type);
1421 bonus = max(bonus, P_UNSKILLED) - 1; /* unskilled => 0 */
1422 bonus = ((bonus + 2) * (martial_bonus() ? 2 : 1)) / 2;
1425 /* KMH -- It's harder to hit while you are riding */
1427 switch (P_SKILL(P_RIDING)) {
1428 case P_ISRESTRICTED:
1448 * Return damage bonus/penalty based on skill of weapon.
1449 * Treat restricted weapons as unskilled.
1452 weapon_dam_bonus(weapon)
1455 int type, wep_type, skill, bonus = 0;
1457 wep_type = weapon_type(weapon);
1458 /* use two weapon skill only if attacking with one of the wielded weapons
1460 type = (u.twoweap && (weapon == uwep || weapon == uswapwep))
1461 ? P_TWO_WEAPON_COMBAT
1463 if (type == P_NONE) {
1465 } else if (type <= P_LAST_WEAPON) {
1466 switch (P_SKILL(type)) {
1468 impossible("weapon_dam_bonus: bad skill %d", P_SKILL(type));
1470 case P_ISRESTRICTED:
1484 } else if (type == P_TWO_WEAPON_COMBAT) {
1485 skill = P_SKILL(P_TWO_WEAPON_COMBAT);
1486 if (P_SKILL(wep_type) < skill)
1487 skill = P_SKILL(wep_type);
1490 case P_ISRESTRICTED:
1504 } else if (type == P_BARE_HANDED_COMBAT) {
1514 bonus = P_SKILL(type);
1515 bonus = max(bonus, P_UNSKILLED) - 1; /* unskilled => 0 */
1516 bonus = ((bonus + 1) * (martial_bonus() ? 3 : 1)) / 2;
1519 /* KMH -- Riding gives some thrusting damage */
1520 if (u.usteed && type != P_TWO_WEAPON_COMBAT) {
1521 switch (P_SKILL(P_RIDING)) {
1522 case P_ISRESTRICTED:
1540 * Initialize weapon skill array for the game. Start by setting all
1541 * skills to restricted, then set the skill for every weapon the
1542 * hero is holding, finally reading the given array that sets
1546 skill_init(class_skill)
1547 const struct def_skill *class_skill;
1552 /* initialize skill array; by default, everything is restricted */
1553 for (skill = 0; skill < P_NUM_SKILLS; skill++) {
1554 P_SKILL(skill) = P_ISRESTRICTED;
1555 P_MAX_SKILL(skill) = P_ISRESTRICTED;
1556 P_ADVANCE(skill) = 0;
1559 /* Set skill for all weapons in inventory to be basic */
1560 for (obj = invent; obj; obj = obj->nobj) {
1561 /* don't give skill just because of carried ammo, wait until
1562 we see the relevant launcher (prevents an archeologist's
1563 touchstone from inadvertently providing skill in sling) */
1567 skill = weapon_type(obj);
1568 if (skill != P_NONE)
1569 P_SKILL(skill) = P_BASIC;
1572 /* set skills for magic */
1573 if (Role_if(PM_HEALER) || Role_if(PM_MONK)) {
1574 P_SKILL(P_HEALING_SPELL) = P_BASIC;
1575 } else if (Role_if(PM_PRIEST)) {
1576 P_SKILL(P_CLERIC_SPELL) = P_BASIC;
1577 } else if (Role_if(PM_WIZARD)) {
1578 P_SKILL(P_ATTACK_SPELL) = P_BASIC;
1579 P_SKILL(P_ENCHANTMENT_SPELL) = P_BASIC;
1582 /* walk through array to set skill maximums */
1583 for (; class_skill->skill != P_NONE; class_skill++) {
1584 skmax = class_skill->skmax;
1585 skill = class_skill->skill;
1587 P_MAX_SKILL(skill) = skmax;
1588 if (P_SKILL(skill) == P_ISRESTRICTED) /* skill pre-set */
1589 P_SKILL(skill) = P_UNSKILLED;
1592 /* High potential fighters already know how to use their hands. */
1593 if (P_MAX_SKILL(P_BARE_HANDED_COMBAT) > P_EXPERT)
1594 P_SKILL(P_BARE_HANDED_COMBAT) = P_BASIC;
1596 /* Roles that start with a horse know how to ride it */
1597 if (urole.petnum == PM_PONY)
1598 P_SKILL(P_RIDING) = P_BASIC;
1601 * Make sure we haven't missed setting the max on a skill
1604 for (skill = 0; skill < P_NUM_SKILLS; skill++) {
1605 if (!P_RESTRICTED(skill)) {
1606 if (P_MAX_SKILL(skill) < P_SKILL(skill)) {
1607 impossible("skill_init: curr > max: %s", P_NAME(skill));
1608 P_MAX_SKILL(skill) = P_SKILL(skill);
1610 P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill) - 1);
1616 setmnotwielded(mon, obj)
1617 register struct monst *mon;
1618 register struct obj *obj;
1622 if (artifact_light(obj) && obj->lamplit) {
1623 end_burn(obj, FALSE);
1626 pline("%s in %s %s %s shining.", The(xname(obj)),
1627 s_suffix(mon_nam(mon)), mbodypart(mon, HAND),
1628 otense(obj, "stop"));
1630 pline("%s
\82ª
\8e\9d\82Â%s
\82Ì
\8bP
\82«
\82ª
\8fÁ
\82¦
\82½
\81D",
1631 mon_nam(mon), xname(obj));
1634 if (MON_WEP(mon) == obj)
1636 obj->owornmask &= ~W_WEP;