1 /* SCCS Id: @(#)weapon.c 3.4 2002/11/07 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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));
33 STATIC_DCL NEARDATA const short skill_names_indices[];
34 STATIC_DCL NEARDATA const char *odd_skill_names[];
35 STATIC_DCL NEARDATA const char *barehands_or_martial[];
39 STATIC_VAR NEARDATA const short skill_names_indices[P_NUM_SKILLS] = {
40 0, DAGGER, KNIFE, AXE,
41 PICK_AXE, SHORT_SWORD, BROADSWORD, LONG_SWORD,
42 TWO_HANDED_SWORD, SCIMITAR, PN_SABER, CLUB,
43 MACE, MORNING_STAR, FLAIL,
44 PN_HAMMER, QUARTERSTAFF, PN_POLEARMS, SPEAR,
45 JAVELIN, TRIDENT, LANCE, BOW,
46 SLING, CROSSBOW, DART,
47 SHURIKEN, BOOMERANG, PN_WHIP, UNICORN_HORN,
48 PN_ATTACK_SPELL, PN_HEALING_SPELL,
49 PN_DIVINATION_SPELL, PN_ENCHANTMENT_SPELL,
50 PN_CLERIC_SPELL, PN_ESCAPE_SPELL,
52 PN_BARE_HANDED, PN_TWO_WEAPONS,
58 /* note: entry [0] isn't used */
59 STATIC_VAR NEARDATA const char * const odd_skill_names[] = {
61 "bare hands", /* use barehands_or_martial[] instead */
76 /* indexed vis `is_martial() */
77 STATIC_VAR NEARDATA const char * const barehands_or_martial[] = {
78 "bare handed combat", "martial arts"
82 give_may_advance_msg(skill)
85 You_feel("more confident in your %sskills.",
88 skill <= P_LAST_WEAPON ?
90 skill <= P_LAST_SPELL ?
97 STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P));
98 STATIC_DCL boolean FDECL(could_advance, (int));
99 STATIC_DCL boolean FDECL(peaked_skill, (int));
100 STATIC_DCL int FDECL(slots_required, (int));
104 STATIC_DCL char *FDECL(skill_level_name, (int,char *));
105 STATIC_DCL void FDECL(skill_advance, (int));
109 #define P_NAME(type) ((skill_names_indices[type] > 0) ? \
110 OBJ_NAME(objects[skill_names_indices[type]]) : \
111 (type == P_BARE_HANDED_COMBAT) ? \
112 barehands_or_martial[martial_bonus()] : \
113 odd_skill_names[-skill_names_indices[type]])
116 static NEARDATA const char kebabable[] = {
117 S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0'
121 * hitval returns an integer representing the "to hit" bonuses
122 * of "otmp" against the monster.
130 struct permonst *ptr = mon->data;
131 boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
136 /* Put weapon specific "to hit" bonuses in below: */
137 tmp += objects[otmp->otyp].oc_hitbon;
139 /* Put weapon vs. monster type "to hit" bonuses in below: */
141 /* Blessed weapons used against undead or demons */
142 if (Is_weapon && otmp->blessed &&
143 (is_demon(ptr) || is_undead(ptr))) tmp += 2;
145 if (is_spear(otmp) &&
146 index(kebabable, ptr->mlet)) tmp += 2;
148 /* trident is highly effective against swimmers */
149 if (otmp->otyp == TRIDENT && is_swimmer(ptr)) {
150 if (is_pool(mon->mx, mon->my)) tmp += 4;
151 else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE) tmp += 2;
154 /* Picks used against xorns and earth elementals */
156 (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2;
158 #ifdef INVISIBLE_OBJECTS
159 /* Invisible weapons against monsters who can't see invisible */
160 if (otmp->oinvis && !perceives(ptr)) tmp += 3;
163 /* Check specially named weapon "to hit" bonuses */
164 if (otmp->oartifact) tmp += spec_abon(otmp, mon);
169 /* Historical note: The original versions of Hack used a range of damage
170 * which was similar to, but not identical to the damage used in Advanced
171 * Dungeons and Dragons. I figured that since it was so close, I may as well
172 * make it exactly the same as AD&D, adding some more weapons in the process.
173 * This has the advantage that it is at least possible that the player would
174 * already know the damage of at least some of the weapons. This was circa
175 * 1987 and I used the table from Unearthed Arcana until I got tired of typing
176 * them in (leading to something of an imbalance towards weapons early in
177 * alphabetical order). The data structure still doesn't include fields that
178 * fully allow the appropriate damage to be described (there's no way to say
179 * 3d6 or 1d6+1) so we add on the extra damage in dmgval() if the weapon
180 * doesn't do an exact die of damage.
182 * Of course new weapons were added later in the development of Nethack. No
183 * AD&D consistency was kept, but most of these don't exist in AD&D anyway.
185 * Second edition AD&D came out a few years later; luckily it used the same
186 * table. As of this writing (1999), third edition is in progress but not
187 * released. Let's see if the weapon table stays the same. --KAA
188 * October 2000: It didn't. Oh, well.
192 * dmgval returns an integer representing the damage bonuses
193 * of "otmp" against the monster.
200 int tmp = 0, otyp = otmp->otyp;
201 struct permonst *ptr = mon->data;
202 boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
204 if (otyp == CREAM_PIE) return 0;
207 if (objects[otyp].oc_wldam)
208 tmp = rnd(objects[otyp].oc_wldam);
215 case ELVEN_BROADSWORD:
216 case BROADSWORD: tmp++; break;
220 case VOULGE: tmp += rnd(4); break;
224 case SPETUM: tmp += rnd(6); break;
228 case TRIDENT: tmp += d(2,4); break;
231 case DWARVISH_MATTOCK:
232 case TWO_HANDED_SWORD: tmp += d(2,6); break;
235 if (objects[otyp].oc_wsdam)
236 tmp = rnd(objects[otyp].oc_wsdam);
244 case TRIDENT: tmp++; break;
254 case ELVEN_BROADSWORD:
256 case VOULGE: tmp += rnd(4); break;
258 case ACID_VENOM: tmp += rnd(6); break;
263 /* negative enchantment mustn't produce negative damage */
264 if (tmp < 0) tmp = 0;
267 if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr))
268 /* thick skinned/scaled creatures don't feel it */
270 if (ptr == &mons[PM_SHADE] && objects[otyp].oc_material != SILVER)
273 /* "very heavy iron ball"; weight increase is in increments of 160 */
274 if (otyp == HEAVY_IRON_BALL && tmp > 0) {
275 int wt = (int)objects[HEAVY_IRON_BALL].oc_weight;
277 if ((int)otmp->owt > wt) {
278 wt = ((int)otmp->owt - wt) / 160;
280 if (tmp > 25) tmp = 25; /* objects[].oc_wldam */
284 /* Put weapon vs. monster type damage bonuses in below: */
285 if (Is_weapon || otmp->oclass == GEM_CLASS ||
286 otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) {
289 if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
291 if (is_axe(otmp) && is_wooden(ptr))
293 if (objects[otyp].oc_material == SILVER && hates_silver(ptr))
296 /* if the weapon is going to get a double damage bonus, adjust
297 this bonus so that effectively it's added after the doubling */
298 if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25)
299 bonus = (bonus + 1) / 2;
305 /* It's debateable whether a rusted blunt instrument
306 should do less damage than a pristine one, since
307 it will hit with essentially the same impact, but
308 there ought to some penalty for using damaged gear
309 so always subtract erosion even for blunt weapons. */
310 tmp -= greatest_erosion(otmp);
311 if (tmp < 1) tmp = 1;
320 STATIC_DCL struct obj *FDECL(oselect, (struct monst *,int));
321 #define Oselect(x) if ((otmp = oselect(mtmp, x)) != 0) return(otmp);
323 STATIC_OVL struct obj *
330 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
331 if (otmp->otyp == x &&
332 /* never select non-cockatrice corpses */
333 !((x == CORPSE || x == EGG) &&
334 !touch_petrifies(&mons[otmp->corpsenm])) &&
335 (!otmp->oartifact || touch_artifact(otmp,mtmp)))
338 return (struct obj *)0;
341 static NEARDATA const int rwep[] =
342 { DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR,
343 JAVELIN, SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW,
344 ORCISH_ARROW, CROSSBOW_BOLT, SILVER_DAGGER, ELVEN_DAGGER, DAGGER,
345 ORCISH_DAGGER, KNIFE, FLINT, ROCK, LOADSTONE, LUCKSTONE, DART,
346 /* BOOMERANG, */ CREAM_PIE
347 /* note: CREAM_PIE should NOT be #ifdef KOPS */
350 static NEARDATA const int pwep[] =
351 { HALBERD, BARDICHE, SPETUM, BILL_GUISARME, VOULGE, RANSEUR, GUISARME,
352 GLAIVE, LUCERN_HAMMER, BEC_DE_CORBIN, FAUCHARD, PARTISAN, LANCE
355 static struct obj *propellor;
358 select_rwep(mtmp) /* select a ranged weapon for the monster */
359 register struct monst *mtmp;
361 register struct obj *otmp;
365 char mlet = mtmp->data->mlet;
368 propellor = &zeroobj;
369 Oselect(EGG); /* cockatrice egg */
371 if(mlet == S_KOP) /* pies are first choice for Kops */
374 if(throws_rocks(mtmp->data)) /* ...boulders for giants */
377 /* Select polearms first; they do more damage and aren't expendable */
378 /* The limit of 13 here is based on the monster polearm range limit
379 * (defined as 5 in mthrowu.c). 5 corresponds to a distance of 2 in
380 * one direction and 1 in another; one space beyond that would be 3 in
381 * one direction and 2 in another; 3^2+2^2=13.
383 if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 13 && couldsee(mtmp->mx, mtmp->my)) {
384 for (i = 0; i < SIZE(pwep); i++) {
385 /* Only strong monsters can wield big (esp. long) weapons.
386 * Big weapon is basically the same as bimanual.
387 * All monsters can wield the remaining weapons.
389 if (((strongmonst(mtmp->data) && (mtmp->misc_worn_check & W_ARMS) == 0)
390 || !objects[pwep[i]].oc_bimanual) &&
391 (objects[pwep[i]].oc_material != SILVER
392 || !hates_silver(mtmp->data))) {
393 if ((otmp = oselect(mtmp, pwep[i])) != 0) {
394 propellor = otmp; /* force the monster to wield it */
402 * other than these two specific cases, always select the
403 * most potent ranged weapon to hand.
405 for (i = 0; i < SIZE(rwep); i++) {
408 /* shooting gems from slings; this goes just before the darts */
409 /* (shooting rocks is already handled via the rwep[] ordering) */
410 if (rwep[i] == DART && !likes_gems(mtmp->data) &&
411 m_carrying(mtmp, SLING)) { /* propellor */
412 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
413 if (otmp->oclass == GEM_CLASS &&
414 (otmp->otyp != LOADSTONE || !otmp->cursed)) {
415 propellor = m_carrying(mtmp, SLING);
420 /* KMH -- This belongs here so darts will work */
421 propellor = &zeroobj;
423 prop = (objects[rwep[i]]).oc_skill;
427 propellor = (oselect(mtmp, YUMI));
428 if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW));
429 if (!propellor) propellor = (oselect(mtmp, BOW));
430 if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW));
433 propellor = (oselect(mtmp, SLING));
436 propellor = (oselect(mtmp, CROSSBOW));
438 if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor
439 && mtmp->weapon_check == NO_WEAPON_WANTED)
442 /* propellor = obj, propellor to use
443 * propellor = &zeroobj, doesn't need a propellor
444 * propellor = 0, needed one and didn't have one
446 if (propellor != 0) {
447 /* Note: cannot use m_carrying for loadstones, since it will
448 * always select the first object of a type, and maybe the
449 * monster is carrying two but only the first is unthrowable.
451 if (rwep[i] != LOADSTONE) {
452 /* Don't throw a cursed weapon-in-hand or an artifact */
453 if ((otmp = oselect(mtmp, rwep[i])) && !otmp->oartifact
454 && (!otmp->cursed || otmp != MON_WEP(mtmp)))
456 } else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
457 if (otmp->otyp == LOADSTONE && !otmp->cursed)
464 return (struct obj *)0;
467 /* Weapons in order of preference */
468 static const NEARDATA short hwep[] = {
469 CORPSE, /* cockatrice corpse */
470 TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE,
471 KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD,
472 ELVEN_BROADSWORD, BROADSWORD, SCIMITAR, SILVER_SABER,
473 MORNING_STAR, ELVEN_SHORT_SWORD, DWARVISH_SHORT_SWORD, SHORT_SWORD,
474 ORCISH_SHORT_SWORD, MACE, AXE, DWARVISH_SPEAR, SILVER_SPEAR,
475 ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL, BULLWHIP, QUARTERSTAFF,
476 JAVELIN, AKLYS, CLUB, PICK_AXE,
480 WAR_HAMMER, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER,
481 ATHAME, SCALPEL, KNIFE, WORM_TOOTH
485 select_hwep(mtmp) /* select a hand to hand weapon for the monster */
486 register struct monst *mtmp;
488 register struct obj *otmp;
490 boolean strong = strongmonst(mtmp->data);
491 boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0;
493 /* prefer artifacts to everything else */
494 for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) {
495 if (otmp->oclass == WEAPON_CLASS
496 && otmp->oartifact && touch_artifact(otmp,mtmp)
497 && ((strong && !wearing_shield)
498 || !objects[otmp->otyp].oc_bimanual))
502 if(is_giant(mtmp->data)) /* giants just love to use clubs */
505 /* only strong monsters can wield big (esp. long) weapons */
506 /* big weapon is basically the same as bimanual */
507 /* all monsters can wield the remaining weapons */
508 for (i = 0; i < SIZE(hwep); i++) {
509 if (hwep[i] == CORPSE && !(mtmp->misc_worn_check & W_ARMG))
511 if (((strong && !wearing_shield)
512 || !objects[hwep[i]].oc_bimanual) &&
513 (objects[hwep[i]].oc_material != SILVER
514 || !hates_silver(mtmp->data)))
519 return (struct obj *)0;
522 /* Called after polymorphing a monster, robbing it, etc.... Monsters
523 * otherwise never unwield stuff on their own. Might print message.
526 possibly_unwield(mon, polyspot)
530 struct obj *obj, *mw_tmp;
532 if (!(mw_tmp = MON_WEP(mon)))
534 for (obj = mon->minvent; obj; obj = obj->nobj)
535 if (obj == mw_tmp) break;
536 if (!obj) { /* The weapon was stolen or destroyed */
538 mon->weapon_check = NEED_WEAPON;
541 if (!attacktype(mon->data, AT_WEAP)) {
542 setmnotwielded(mon, mw_tmp);
544 mon->weapon_check = NO_WEAPON_WANTED;
545 obj_extract_self(obj);
546 if (cansee(mon->mx, mon->my)) {
547 pline("%s drops %s.", Monnam(mon),
548 distant_name(obj, doname));
549 newsym(mon->mx, mon->my);
551 /* might be dropping object into water or lava */
552 if (!flooreffects(obj, mon->mx, mon->my, "drop")) {
553 if (polyspot) bypass_obj(obj);
554 place_object(obj, mon->mx, mon->my);
559 /* The remaining case where there is a change is where a monster
560 * is polymorphed into a stronger/weaker monster with a different
561 * choice of weapons. This has no parallel for players. It can
562 * be handled by waiting until mon_wield_item is actually called.
563 * Though the monster still wields the wrong weapon until then,
564 * this is OK since the player can't see it. (FIXME: Not okay since
565 * probing can reveal it.)
566 * Note that if there is no change, setting the check to NEED_WEAPON
568 * Possible problem: big monster with big cursed weapon gets
569 * polymorphed into little monster. But it's not quite clear how to
570 * handle this anyway....
572 if (!(mw_tmp->cursed && mon->weapon_check == NO_WEAPON_WANTED))
573 mon->weapon_check = NEED_WEAPON;
577 /* Let a monster try to wield a weapon, based on mon->weapon_check.
578 * Returns 1 if the monster took time to do it, 0 if it did not.
582 register struct monst *mon;
586 /* This case actually should never happen */
587 if (mon->weapon_check == NO_WEAPON_WANTED) return 0;
588 switch(mon->weapon_check) {
589 case NEED_HTH_WEAPON:
590 obj = select_hwep(mon);
592 case NEED_RANGED_WEAPON:
593 (void)select_rwep(mon);
597 obj = m_carrying(mon, PICK_AXE);
598 /* KMH -- allow other picks */
599 if (!obj && !which_armor(mon, W_ARMS))
600 obj = m_carrying(mon, DWARVISH_MATTOCK);
603 /* currently, only 2 types of axe */
604 obj = m_carrying(mon, BATTLE_AXE);
605 if (!obj || which_armor(mon, W_ARMS))
606 obj = m_carrying(mon, AXE);
608 case NEED_PICK_OR_AXE:
609 /* prefer pick for fewer switches on most levels */
610 obj = m_carrying(mon, DWARVISH_MATTOCK);
611 if (!obj) obj = m_carrying(mon, BATTLE_AXE);
612 if (!obj || which_armor(mon, W_ARMS)) {
613 obj = m_carrying(mon, PICK_AXE);
614 if (!obj) obj = m_carrying(mon, AXE);
617 default: impossible("weapon_check %d for %s?",
618 mon->weapon_check, mon_nam(mon));
621 if (obj && obj != &zeroobj) {
622 struct obj *mw_tmp = MON_WEP(mon);
623 if (mw_tmp && mw_tmp->otyp == obj->otyp) {
624 /* already wielding it */
625 mon->weapon_check = NEED_WEAPON;
628 /* Actually, this isn't necessary--as soon as the monster
629 * wields the weapon, the weapon welds itself, so the monster
630 * can know it's cursed and needn't even bother trying.
633 if (mw_tmp && mw_tmp->cursed && mw_tmp->otyp != CORPSE) {
634 if (canseemon(mon)) {
635 char welded_buf[BUFSZ];
636 const char *mon_hand = mbodypart(mon, HAND);
638 if (bimanual(mw_tmp)) mon_hand = makeplural(mon_hand);
639 Sprintf(welded_buf, "%s welded to %s %s",
640 otense(mw_tmp, "are"),
641 mhis(mon), mon_hand);
643 if (obj->otyp == PICK_AXE) {
644 pline("Since %s weapon%s %s,",
645 s_suffix(mon_nam(mon)),
646 plur(mw_tmp->quan), welded_buf);
647 pline("%s cannot wield that %s.",
648 mon_nam(mon), xname(obj));
650 pline("%s tries to wield %s.", Monnam(mon),
653 s_suffix(Monnam(mon)),
654 xname(mw_tmp), welded_buf);
658 mon->weapon_check = NO_WEAPON_WANTED;
661 mon->mw = obj; /* wield obj */
662 setmnotwielded(mon, mw_tmp);
663 mon->weapon_check = NEED_WEAPON;
664 if (canseemon(mon)) {
665 pline("%s wields %s!", Monnam(mon), doname(obj));
666 if (obj->cursed && obj->otyp != CORPSE) {
667 pline("%s %s to %s %s!",
668 Tobjnam(obj, "weld"),
669 is_plural(obj) ? "themselves" : "itself",
670 s_suffix(mon_nam(mon)), mbodypart(mon,HAND));
674 if (artifact_light(obj) && !obj->lamplit) {
675 begin_burn(obj, FALSE);
677 pline("%s brilliantly in %s %s!",
678 Tobjnam(obj, "glow"),
679 s_suffix(mon_nam(mon)), mbodypart(mon,HAND));
681 obj->owornmask = W_WEP;
684 mon->weapon_check = NEED_WEAPON;
689 abon() /* attack bonus for strength & dexterity */
692 int str = ACURR(A_STR), dex = ACURR(A_DEX);
694 if (Upolyd) return(adj_lev(&mons[u.umonnum]) - 3);
695 if (str < 6) sbon = -2;
696 else if (str < 8) sbon = -1;
697 else if (str < 17) sbon = 0;
698 else if (str <= STR18(50)) sbon = 1; /* up to 18/50 */
699 else if (str < STR18(100)) sbon = 2;
702 /* Game tuning kludge: make it a bit easier for a low level character to hit */
703 sbon += (u.ulevel < 3) ? 1 : 0;
705 if (dex < 4) return(sbon-3);
706 else if (dex < 6) return(sbon-2);
707 else if (dex < 8) return(sbon-1);
708 else if (dex < 14) return(sbon);
709 else return(sbon + dex-14);
716 dbon() /* damage bonus for strength */
718 int str = ACURR(A_STR);
720 if (Upolyd) return(0);
722 if (str < 6) return(-1);
723 else if (str < 16) return(0);
724 else if (str < 18) return(1);
725 else if (str == 18) return(2); /* up to 18 */
726 else if (str <= STR18(75)) return(3); /* up to 18/75 */
727 else if (str <= STR18(90)) return(4); /* up to 18/90 */
728 else if (str < STR18(100)) return(5); /* up to 18/99 */
733 /* copy the skill level name into the given buffer */
735 skill_level_name(skill, buf)
741 switch (P_SKILL(skill)) {
742 case P_UNSKILLED: ptr = "Unskilled"; break;
743 case P_BASIC: ptr = "Basic"; break;
744 case P_SKILLED: ptr = "Skilled"; break;
745 case P_EXPERT: ptr = "Expert"; break;
746 /* these are for unarmed combat/martial arts only */
747 case P_MASTER: ptr = "Master"; break;
748 case P_GRAND_MASTER: ptr = "Grand Master"; break;
749 default: ptr = "Unknown"; break;
755 /* return the # of slots required to advance the skill */
757 slots_required(skill)
760 int tmp = P_SKILL(skill);
762 /* The more difficult the training, the more slots it takes.
763 * unskilled -> basic 1
765 * skilled -> expert 3
767 if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT)
770 /* Fewer slots used up for unarmed or martial.
771 * unskilled -> basic 1
773 * skilled -> expert 2
775 * master -> grand master 3
777 return (tmp + 1) / 2;
780 /* return true if this skill can be advanced */
783 can_advance(skill, speedy)
787 return !P_RESTRICTED(skill)
788 && P_SKILL(skill) < P_MAX_SKILL(skill) && (
790 (wizard && speedy) ||
793 (unsigned) practice_needed_to_advance(P_SKILL(skill))
794 && u.skills_advanced < P_SKILL_LIMIT
795 && u.weapon_slots >= slots_required(skill)));
798 /* return true if this skill could be advanced if more slots were available */
803 return !P_RESTRICTED(skill)
804 && P_SKILL(skill) < P_MAX_SKILL(skill) && (
806 (unsigned) practice_needed_to_advance(P_SKILL(skill))
807 && u.skills_advanced < P_SKILL_LIMIT));
810 /* return true if this skill has reached its maximum and there's been enough
811 practice to become eligible for the next step if that had been possible */
816 return !P_RESTRICTED(skill)
817 && P_SKILL(skill) >= P_MAX_SKILL(skill) && (
819 (unsigned) practice_needed_to_advance(P_SKILL(skill))));
826 u.weapon_slots -= slots_required(skill);
828 u.skill_record[u.skills_advanced++] = skill;
829 /* subtly change the advance message to indicate no more advancement */
830 You("are now %s skilled in %s.",
831 P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more",
835 const static struct skill_range {
839 { P_FIRST_H_TO_H, P_LAST_H_TO_H, "Fighting Skills" },
840 { P_FIRST_WEAPON, P_LAST_WEAPON, "Weapon Skills" },
841 { P_FIRST_SPELL, P_LAST_SPELL, "Spellcasting Skills" },
845 * The `#enhance' extended command. What we _really_ would like is
846 * to keep being able to pick things to advance until we couldn't any
847 * more. This is currently not possible -- the menu code has no way
848 * to call us back for instant action. Even if it did, we would also need
849 * to be able to update the menu since selecting one item could make
850 * others unselectable.
853 enhance_weapon_skill()
855 int pass, i, n, len, longest,
856 to_advance, eventually_advance, maxxed_cnt;
857 char buf[BUFSZ], sklnambuf[BUFSZ];
862 boolean speedy = FALSE;
865 if (wizard && yn("Advance skills without practice?") == 'y')
870 /* find longest available skill name, count those that can advance */
871 to_advance = eventually_advance = maxxed_cnt = 0;
872 for (longest = 0, i = 0; i < P_NUM_SKILLS; i++) {
873 if (P_RESTRICTED(i)) continue;
874 if ((len = strlen(P_NAME(i))) > longest)
876 if (can_advance(i, speedy)) to_advance++;
877 else if (could_advance(i)) eventually_advance++;
878 else if (peaked_skill(i)) maxxed_cnt++;
881 win = create_nhwindow(NHW_MENU);
884 /* start with a legend if any entries will be annotated
885 with "*" or "#" below */
886 if (eventually_advance > 0 || maxxed_cnt > 0) {
888 if (eventually_advance > 0) {
890 "(Skill%s flagged by \"*\" may be enhanced %s.)",
891 plur(eventually_advance),
892 (u.ulevel < MAXULEV) ?
893 "when you're more experienced" :
894 "if skill slots become available");
895 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
896 buf, MENU_UNSELECTED);
898 if (maxxed_cnt > 0) {
900 "(Skill%s flagged by \"#\" cannot be enhanced any further.)",
902 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
903 buf, MENU_UNSELECTED);
905 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
906 "", MENU_UNSELECTED);
909 /* List the skills, making ones that could be advanced
910 selectable. List the miscellaneous skills first.
911 Possible future enhancement: list spell skills before
912 weapon skills for spellcaster roles. */
913 for (pass = 0; pass < SIZE(skill_ranges); pass++)
914 for (i = skill_ranges[pass].first;
915 i <= skill_ranges[pass].last; i++) {
916 /* Print headings for skill types */
918 if (i == skill_ranges[pass].first)
919 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
920 skill_ranges[pass].name, MENU_UNSELECTED);
922 if (P_RESTRICTED(i)) continue;
924 * Sigh, this assumes a monospaced font unless
925 * iflags.menu_tab_sep is set in which case it puts
926 * tabs between columns.
927 * The 12 is the longest skill level name.
928 * The " " is room for a selection letter and dash, "a - ".
930 if (can_advance(i, speedy))
931 prefix = ""; /* will be preceded by menu choice */
932 else if (could_advance(i))
934 else if (peaked_skill(i))
937 prefix = (to_advance + eventually_advance +
938 maxxed_cnt > 0) ? " " : "";
939 (void) skill_level_name(i, sklnambuf);
942 if (!iflags.menu_tab_sep)
943 Sprintf(buf, " %s%-*s %-12s %5d(%4d)",
944 prefix, longest, P_NAME(i), sklnambuf,
946 practice_needed_to_advance(P_SKILL(i)));
948 Sprintf(buf, " %s%s\t%s\t%5d(%4d)",
949 prefix, P_NAME(i), sklnambuf,
951 practice_needed_to_advance(P_SKILL(i)));
955 if (!iflags.menu_tab_sep)
956 Sprintf(buf, " %s %-*s [%s]",
957 prefix, longest, P_NAME(i), sklnambuf);
959 Sprintf(buf, " %s%s\t[%s]",
960 prefix, P_NAME(i), sklnambuf);
962 any.a_int = can_advance(i, speedy) ? i+1 : 0;
963 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
964 buf, MENU_UNSELECTED);
967 Strcpy(buf, (to_advance > 0) ? "Pick a skill to advance:" :
970 if (wizard && !speedy)
971 Sprintf(eos(buf), " (%d slot%s available)",
972 u.weapon_slots, plur(u.weapon_slots));
975 n = select_menu(win, to_advance ? PICK_ONE : PICK_NONE, &selected);
976 destroy_nhwindow(win);
978 n = selected[0].item.a_int - 1; /* get item selected */
979 free((genericptr_t)selected);
981 /* check for more skills able to advance, if so then .. */
982 for (n = i = 0; i < P_NUM_SKILLS; i++) {
983 if (can_advance(i, speedy)) {
984 if (!speedy) You_feel("you could be more dangerous!");
990 } while (speedy && n > 0);
995 * Change from restricted to unrestricted, allowing P_BASIC as max. This
996 * function may be called with with P_NONE. Used in pray.c.
999 unrestrict_weapon_skill(skill)
1002 if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) {
1003 P_SKILL(skill) = P_UNSKILLED;
1004 P_MAX_SKILL(skill) = P_BASIC;
1005 P_ADVANCE(skill) = 0;
1013 use_skill(skill,degree)
1017 boolean advance_before;
1019 if (skill != P_NONE && !P_RESTRICTED(skill)) {
1020 advance_before = can_advance(skill, FALSE);
1021 P_ADVANCE(skill)+=degree;
1022 if (!advance_before && can_advance(skill, FALSE))
1023 give_may_advance_msg(skill);
1029 int n; /* number of slots to gain; normally one */
1031 int i, before, after;
1033 for (i = 0, before = 0; i < P_NUM_SKILLS; i++)
1034 if (can_advance(i, FALSE)) before++;
1035 u.weapon_slots += n;
1036 for (i = 0, after = 0; i < P_NUM_SKILLS; i++)
1037 if (can_advance(i, FALSE)) after++;
1039 give_may_advance_msg(P_NONE);
1043 lose_weapon_skill(n)
1044 int n; /* number of slots to lose; normally one */
1049 /* deduct first from unused slots, then from last placed slot, if any */
1050 if (u.weapon_slots) {
1052 } else if (u.skills_advanced) {
1053 skill = u.skill_record[--u.skills_advanced];
1054 if (P_SKILL(skill) <= P_UNSKILLED)
1055 panic("lose_weapon_skill (%d)", skill);
1056 P_SKILL(skill)--; /* drop skill one level */
1057 /* Lost skill might have taken more than one slot; refund rest. */
1058 u.weapon_slots = slots_required(skill) - 1;
1059 /* It might now be possible to advance some other pending
1060 skill by using the refunded slots, but giving a message
1061 to that effect would seem pretty confusing.... */
1070 /* KMH -- now uses the object table */
1074 /* Not using a weapon */
1075 return (P_BARE_HANDED_COMBAT);
1076 if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS &&
1077 obj->oclass != GEM_CLASS)
1078 /* Not a weapon, weapon-tool, or ammo */
1080 type = objects[obj->otyp].oc_skill;
1081 return ((type < 0) ? -type : type);
1088 return P_TWO_WEAPON_COMBAT;
1089 return weapon_type(uwep);
1093 * Return hit bonus/penalty based on skill of weapon.
1094 * Treat restricted weapons as unskilled.
1097 weapon_hit_bonus(weapon)
1100 int type, wep_type, skill, bonus = 0;
1101 static const char bad_skill[] = "weapon_hit_bonus: bad skill %d";
1103 wep_type = weapon_type(weapon);
1104 /* use two weapon skill only if attacking with one of the wielded weapons */
1105 type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ?
1106 P_TWO_WEAPON_COMBAT : wep_type;
1107 if (type == P_NONE) {
1109 } else if (type <= P_LAST_WEAPON) {
1110 switch (P_SKILL(type)) {
1111 default: impossible(bad_skill, P_SKILL(type)); /* fall through */
1112 case P_ISRESTRICTED:
1113 case P_UNSKILLED: bonus = -4; break;
1114 case P_BASIC: bonus = 0; break;
1115 case P_SKILLED: bonus = 2; break;
1116 case P_EXPERT: bonus = 3; break;
1118 } else if (type == P_TWO_WEAPON_COMBAT) {
1119 skill = P_SKILL(P_TWO_WEAPON_COMBAT);
1120 if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type);
1122 default: impossible(bad_skill, skill); /* fall through */
1123 case P_ISRESTRICTED:
1124 case P_UNSKILLED: bonus = -9; break;
1125 case P_BASIC: bonus = -7; break;
1126 case P_SKILLED: bonus = -5; break;
1127 case P_EXPERT: bonus = -3; break;
1129 } else if (type == P_BARE_HANDED_COMBAT) {
1139 bonus = P_SKILL(type);
1140 bonus = max(bonus,P_UNSKILLED) - 1; /* unskilled => 0 */
1141 bonus = ((bonus + 2) * (martial_bonus() ? 2 : 1)) / 2;
1145 /* KMH -- It's harder to hit while you are riding */
1147 switch (P_SKILL(P_RIDING)) {
1148 case P_ISRESTRICTED:
1149 case P_UNSKILLED: bonus -= 2; break;
1150 case P_BASIC: bonus -= 1; break;
1151 case P_SKILLED: break;
1152 case P_EXPERT: break;
1154 if (u.twoweap) bonus -= 2;
1162 * Return damage bonus/penalty based on skill of weapon.
1163 * Treat restricted weapons as unskilled.
1166 weapon_dam_bonus(weapon)
1169 int type, wep_type, skill, bonus = 0;
1171 wep_type = weapon_type(weapon);
1172 /* use two weapon skill only if attacking with one of the wielded weapons */
1173 type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ?
1174 P_TWO_WEAPON_COMBAT : wep_type;
1175 if (type == P_NONE) {
1177 } else if (type <= P_LAST_WEAPON) {
1178 switch (P_SKILL(type)) {
1179 default: impossible("weapon_dam_bonus: bad skill %d",P_SKILL(type));
1181 case P_ISRESTRICTED:
1182 case P_UNSKILLED: bonus = -2; break;
1183 case P_BASIC: bonus = 0; break;
1184 case P_SKILLED: bonus = 1; break;
1185 case P_EXPERT: bonus = 2; break;
1187 } else if (type == P_TWO_WEAPON_COMBAT) {
1188 skill = P_SKILL(P_TWO_WEAPON_COMBAT);
1189 if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type);
1192 case P_ISRESTRICTED:
1193 case P_UNSKILLED: bonus = -3; break;
1194 case P_BASIC: bonus = -1; break;
1195 case P_SKILLED: bonus = 0; break;
1196 case P_EXPERT: bonus = 1; break;
1198 } else if (type == P_BARE_HANDED_COMBAT) {
1208 bonus = P_SKILL(type);
1209 bonus = max(bonus,P_UNSKILLED) - 1; /* unskilled => 0 */
1210 bonus = ((bonus + 1) * (martial_bonus() ? 3 : 1)) / 2;
1214 /* KMH -- Riding gives some thrusting damage */
1215 if (u.usteed && type != P_TWO_WEAPON_COMBAT) {
1216 switch (P_SKILL(P_RIDING)) {
1217 case P_ISRESTRICTED:
1218 case P_UNSKILLED: break;
1219 case P_BASIC: break;
1220 case P_SKILLED: bonus += 1; break;
1221 case P_EXPERT: bonus += 2; break;
1230 * Initialize weapon skill array for the game. Start by setting all
1231 * skills to restricted, then set the skill for every weapon the
1232 * hero is holding, finally reading the given array that sets
1236 skill_init(class_skill)
1237 const struct def_skill *class_skill;
1242 /* initialize skill array; by default, everything is restricted */
1243 for (skill = 0; skill < P_NUM_SKILLS; skill++) {
1244 P_SKILL(skill) = P_ISRESTRICTED;
1245 P_MAX_SKILL(skill) = P_ISRESTRICTED;
1246 P_ADVANCE(skill) = 0;
1249 /* Set skill for all weapons in inventory to be basic */
1250 for (obj = invent; obj; obj = obj->nobj) {
1251 skill = weapon_type(obj);
1252 if (skill != P_NONE)
1253 P_SKILL(skill) = P_BASIC;
1256 /* set skills for magic */
1257 if (Role_if(PM_HEALER) || Role_if(PM_MONK)) {
1258 P_SKILL(P_HEALING_SPELL) = P_BASIC;
1259 } else if (Role_if(PM_PRIEST)) {
1260 P_SKILL(P_CLERIC_SPELL) = P_BASIC;
1261 } else if (Role_if(PM_WIZARD)) {
1262 P_SKILL(P_ATTACK_SPELL) = P_BASIC;
1263 P_SKILL(P_ENCHANTMENT_SPELL) = P_BASIC;
1266 /* walk through array to set skill maximums */
1267 for (; class_skill->skill != P_NONE; class_skill++) {
1268 skmax = class_skill->skmax;
1269 skill = class_skill->skill;
1271 P_MAX_SKILL(skill) = skmax;
1272 if (P_SKILL(skill) == P_ISRESTRICTED) /* skill pre-set */
1273 P_SKILL(skill) = P_UNSKILLED;
1276 /* High potential fighters already know how to use their hands. */
1277 if (P_MAX_SKILL(P_BARE_HANDED_COMBAT) > P_EXPERT)
1278 P_SKILL(P_BARE_HANDED_COMBAT) = P_BASIC;
1280 /* Roles that start with a horse know how to ride it */
1282 if (urole.petnum == PM_PONY)
1283 P_SKILL(P_RIDING) = P_BASIC;
1287 * Make sure we haven't missed setting the max on a skill
1290 for (skill = 0; skill < P_NUM_SKILLS; skill++) {
1291 if (!P_RESTRICTED(skill)) {
1292 if (P_MAX_SKILL(skill) < P_SKILL(skill)) {
1293 impossible("skill_init: curr > max: %s", P_NAME(skill));
1294 P_MAX_SKILL(skill) = P_SKILL(skill);
1296 P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill)-1);
1302 setmnotwielded(mon,obj)
1303 register struct monst *mon;
1304 register struct obj *obj;
1307 if (artifact_light(obj) && obj->lamplit) {
1308 end_burn(obj, FALSE);
1310 pline("%s in %s %s %s glowing.", The(xname(obj)),
1311 s_suffix(mon_nam(mon)), mbodypart(mon,HAND),
1312 otense(obj, "stop"));
1314 obj->owornmask &= ~W_WEP;