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