abstract
| - Below is the full text to weapon.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.0/weapon.c#line123]], for example. Warning! This is the source code from an old release. For the latest release, see Source code 1. /* SCCS Id: @(#)weapon.c 3.2 96/03/03 */ 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. #ifdef WEAPON_SKILLS 13. #ifndef OVLB 14. 15. STATIC_DCL NEARDATA const short skill_names_indices[]; 16. STATIC_DCL NEARDATA const char *odd_skill_names[]; 17. 18. #else /* OVLB */ 19. 20. STATIC_OVL NEARDATA const short skill_names_indices[P_NUM_SKILLS] = { 21. DAGGER, KNIFE, AXE, PICK_AXE, 22. SHORT_SWORD, BROADSWORD, LONG_SWORD, TWO_HANDED_SWORD, 23. SCIMITAR, PN_SABER, CLUB, MACE, 24. MORNING_STAR, FLAIL, WAR_HAMMER, QUARTERSTAFF, 25. PN_POLEARMS, SPEAR, JAVELIN, TRIDENT, 26. LANCE, BOW, SLING, CROSSBOW, 27. DART, SHURIKEN, BOOMERANG, BULLWHIP, 28. UNICORN_HORN, PN_TWO_WEAPON_COMBAT, 29. PN_BARE_HANDED_COMBAT, PN_MARTIAL_ARTS 30. }; 31. 32. STATIC_OVL NEARDATA const char *odd_skill_names[] = { 33. "polearms", "two weapon combat", "bare handed combat", 34. "martial arts", "saber" 35. }; 36. 37. #endif /* OVLB */ 38. #ifdef OVL1 39. 40. static char *FDECL(skill_level_name, (int,char *)); 41. static int FDECL(slots_required, (int)); 42. static boolean FDECL(can_advance, (int)); 43. static void FDECL(skill_advance, (int)); 44. 45. #endif /* OVL1 */ 46. 47. #define P_NAME(type) (skill_names_indices[type] < NUM_OBJECTS ? \ 48. OBJ_NAME(objects[skill_names_indices[type]]) : \ 49. odd_skill_names[skill_names_indices[type] - NUM_OBJECTS]) 50. #endif /* WEAPON_SKILLS */ 51. 52. #ifdef OVLB 53. 54. static NEARDATA const char kebabable[] = { 55. S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0' 56. }; 57. 58. /* 59. * hitval returns an integer representing the "to hit" bonuses 60. * of "otmp" against the monster. 61. */ 62. int 63. hitval(otmp, mon) 64. struct obj *otmp; 65. struct monst *mon; 66. { 67. int tmp = 0; 68. struct permonst *ptr = mon->data; 69. boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)); 70. 71. if (Is_weapon) 72. tmp += otmp->spe; 73. 74. /* Put weapon specific "to hit" bonuses in below: */ 75. tmp += objects[otmp->otyp].oc_hitbon; 76. #ifdef WEAPON_SKILLS 77. tmp += weapon_hit_bonus(otmp); /* weapon skill */ 78. #endif /* WEAPON_SKILLS */ 79. 80. /* Put weapon vs. monster type "to hit" bonuses in below: */ 81. 82. /* Blessed weapons used against undead or demons */ 83. if (Is_weapon && otmp->blessed && 84. (is_demon(ptr) || is_undead(ptr))) tmp += 2; 85. 86. if (objects[otmp->otyp].oc_wepcat == WEP_SPEAR && 87. index(kebabable, ptr->mlet)) tmp += 2; 88. 89. /* trident is highly effective against swimmers */ 90. if (otmp->otyp == TRIDENT && is_swimmer(ptr)) { 91. if (is_pool(mon->mx, mon->my)) tmp += 4; 92. else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE) tmp += 2; 93. } 94. 95. /* pick-axe used against xorns and earth elementals */ 96. if ((otmp->otyp == PICK_AXE || otmp->otyp == DWARVISH_MATTOCK) && 97. (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2; 98. 99. /* Check specially named weapon "to hit" bonuses */ 100. if (otmp->oartifact) tmp += spec_abon(otmp, mon); 101. 102. return tmp; 103. } 104. 105. /* 106. * dmgval returns an integer representing the damage bonuses 107. * of "otmp" against the monster. 108. */ 109. int 110. dmgval(otmp, mon) 111. struct obj *otmp; 112. struct monst *mon; 113. { 114. int tmp = 0, otyp = otmp->otyp; 115. struct permonst *ptr = mon->data; 116. boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)); 117. 118. if (otyp == CREAM_PIE) return 0; 119. 120. if (bigmonst(ptr)) { 121. if (objects[otyp].oc_wldam) 122. tmp = rnd(objects[otyp].oc_wldam); 123. switch (otyp) { 124. case CROSSBOW_BOLT: 125. case MORNING_STAR: 126. case PARTISAN: 127. case RUNESWORD: 128. case ELVEN_BROADSWORD: 129. case BROADSWORD: tmp++; break; 130. 131. case FLAIL: 132. case RANSEUR: 133. case VOULGE: tmp += rnd(4); break; 134. 135. case ACID_VENOM: 136. case HALBERD: 137. case SPETUM: tmp += rnd(6); break; 138. 139. case BATTLE_AXE: 140. case BARDICHE: 141. case TRIDENT: tmp += d(2,4); break; 142. 143. case TSURUGI: 144. case DWARVISH_MATTOCK: 145. case TWO_HANDED_SWORD: tmp += d(2,6); break; 146. } 147. } else { 148. if (objects[otyp].oc_wsdam) 149. tmp = rnd(objects[otyp].oc_wsdam); 150. switch (otyp) { 151. case CROSSBOW_BOLT: 152. case MACE: 153. case WAR_HAMMER: 154. case FLAIL: 155. case SPETUM: 156. case TRIDENT: tmp++; break; 157. 158. case BATTLE_AXE: 159. case BARDICHE: 160. case BILL_GUISARME: 161. case GUISARME: 162. case LUCERN_HAMMER: 163. case MORNING_STAR: 164. case RANSEUR: 165. case BROADSWORD: 166. case ELVEN_BROADSWORD: 167. case RUNESWORD: 168. case VOULGE: tmp += rnd(4); break; 169. 170. case ACID_VENOM: tmp += rnd(6); break; 171. } 172. } 173. if (Is_weapon) 174. tmp += otmp->spe; 175. 176. if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr)) 177. /* thick skinned/scaled creatures don't feel it */ 178. tmp = 0; 179. if (ptr == &mons[PM_SHADE] && objects[otyp].oc_material != SILVER) 180. tmp = 0; 181. 182. /* Put weapon vs. monster type damage bonuses in below: */ 183. if (Is_weapon || otmp->oclass == GEM_CLASS) { 184. int bonus = 0; 185. 186. if (otmp->blessed && (is_undead(ptr) || is_demon(ptr))) 187. bonus += rnd(4); 188. if ((otyp == AXE || otyp == BATTLE_AXE) && is_wooden(ptr)) 189. bonus += rnd(4); 190. if (objects[otyp].oc_material == SILVER && hates_silver(ptr)) 191. bonus += rnd(20); 192. 193. /* if the weapon is going to get a double damage bonus, adjust 194. this bonus so that effectively it's added after the doubling */ 195. if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25) 196. bonus = (bonus + 1) / 2; 197. 198. tmp += bonus; 199. } 200. 201. if (tmp > 0) { 202. tmp -= otmp->oeroded; 203. if (tmp < 1) tmp = 1; 204. } 205. 206. return(tmp); 207. } 208. 209. #endif /* OVLB */ 210. #ifdef OVL0 211. 212. static struct obj *FDECL(oselect, (struct monst *,int)); 213. #define Oselect(x) if ((otmp = oselect(mtmp, x)) != 0) return(otmp); 214. 215. static struct obj * 216. oselect(mtmp, x) 217. struct monst *mtmp; 218. int x; 219. { 220. struct obj *otmp; 221. 222. for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { 223. if (otmp->otyp == x && 224. /* never select non-cockatrice corpses */ 225. !(x == CORPSE && otmp->corpsenm != PM_COCKATRICE) && 226. (!otmp->oartifact || touch_artifact(otmp,mtmp))) 227. return otmp; 228. } 229. return (struct obj *)0; 230. } 231. 232. static NEARDATA const int rwep[] = 233. { DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN, 234. SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW, 235. CROSSBOW_BOLT, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE, ROCK, 236. LOADSTONE, LUCKSTONE, DART, /* BOOMERANG, */ CREAM_PIE 237. /* note: CREAM_PIE should NOT be #ifdef KOPS */ 238. }; 239. 240. static struct obj *propellor; 241. 242. struct obj * 243. select_rwep(mtmp) /* select a ranged weapon for the monster */ 244. register struct monst *mtmp; 245. { 246. register struct obj *otmp; 247. int i; 248. 249. #ifdef KOPS 250. char mlet = mtmp->data->mlet; 251. #endif 252. 253. propellor = &zeroobj; 254. #ifdef KOPS 255. if(mlet == S_KOP) /* pies are first choice for Kops */ 256. Oselect(CREAM_PIE); 257. #endif 258. if(throws_rocks(mtmp->data)) /* ...boulders for giants */ 259. Oselect(BOULDER); 260. 261. /* 262. * other than these two specific cases, always select the 263. * most potent ranged weapon to hand. 264. */ 265. for (i = 0; i < SIZE(rwep); i++) { 266. int prop; 267. 268. propellor = &zeroobj; 269. /* shooting gems from slings; this goes just before the darts */ 270. if (rwep[i]==DART && !likes_gems(mtmp->data) 271. && (propellor = m_carrying(mtmp, SLING))) { 272. for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) { 273. if(otmp->oclass==GEM_CLASS && 274. (otmp->otyp != LOADSTONE || !otmp->cursed)) 275. return(otmp); 276. } 277. } 278. prop = (objects[rwep[i]]).w_propellor; 279. if (prop > 0) { 280. switch (prop) { 281. case WP_BOW: 282. propellor = (oselect(mtmp, YUMI)); 283. if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW)); 284. if (!propellor) propellor = (oselect(mtmp, BOW)); 285. if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW)); 286. break; 287. case WP_SLING: 288. propellor = (oselect(mtmp, SLING)); 289. break; 290. case WP_CROSSBOW: 291. propellor = (oselect(mtmp, CROSSBOW)); 292. } 293. if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor 294. && mtmp->weapon_check == NO_WEAPON_WANTED) 295. propellor = 0; 296. } 297. /* propellor = obj, propellor to use 298. * propellor = &zeroobj, doesn't need a propellor 299. * propellor = 0, needed one and didn't have one 300. */ 301. if (propellor != 0) { 302. /* Note: cannot use m_carrying for loadstones, since it will 303. * always select the first object of a type, and maybe the 304. * monster is carrying two but only the first is unthrowable. 305. */ 306. if (rwep[i] != LOADSTONE) { 307. /* Don't throw a cursed weapon-in-hand */ 308. if ((otmp = oselect(mtmp, rwep[i])) 309. && (!otmp->cursed || otmp != MON_WEP(mtmp))) 310. return(otmp); 311. } else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) { 312. if (otmp->otyp == LOADSTONE && !otmp->cursed) 313. return otmp; 314. } 315. } 316. } 317. 318. /* failure */ 319. return (struct obj *)0; 320. } 321. 322. /* Weapons in order of preference */ 323. static NEARDATA short hwep[] = { 324. CORPSE, /* cockatrice corpse */ 325. TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE, 326. KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD, 327. ELVEN_BROADSWORD, BROADSWORD, LUCERN_HAMMER, SCIMITAR, SILVER_SABER, 328. HALBERD, PARTISAN, LANCE, FAUCHARD, BILL_GUISARME, BEC_DE_CORBIN, 329. GUISARME, RANSEUR, SPETUM, VOULGE, BARDICHE, MORNING_STAR, GLAIVE, 330. ELVEN_SHORT_SWORD, DWARVISH_SHORT_SWORD, SHORT_SWORD, 331. ORCISH_SHORT_SWORD, MACE, AXE, DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, 332. ORCISH_SPEAR, FLAIL, BULLWHIP, QUARTERSTAFF, JAVELIN, AKLYS, CLUB, 333. PICK_AXE, 334. #ifdef KOPS 335. RUBBER_HOSE, 336. #endif /* KOPS */ 337. WAR_HAMMER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, ATHAME, SCALPEL, 338. KNIFE, WORM_TOOTH 339. }; 340. 341. struct obj * 342. select_hwep(mtmp) /* select a hand to hand weapon for the monster */ 343. register struct monst *mtmp; 344. { 345. register struct obj *otmp; 346. register int i; 347. boolean strong = strongmonst(mtmp->data); 348. boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0; 349. 350. /* prefer artifacts to everything else */ 351. for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) { 352. if (otmp->oclass == WEAPON_CLASS 353. && otmp->oartifact && touch_artifact(otmp,mtmp) 354. && ((strong && !wearing_shield) 355. || !objects[otmp->otyp].oc_bimanual)) 356. return otmp; 357. } 358. 359. if(is_giant(mtmp->data)) /* giants just love to use clubs */ 360. Oselect(CLUB); 361. 362. /* only strong monsters can wield big (esp. long) weapons */ 363. /* big weapon is basically the same as bimanual */ 364. /* all monsters can wield the remaining weapons */ 365. for (i = 0; i < SIZE(hwep); i++) 366. if (((strong && !wearing_shield) 367. || !objects[hwep[i]].oc_bimanual) && 368. (objects[hwep[i]].oc_material != SILVER 369. || !hates_silver(mtmp->data))) 370. Oselect(hwep[i]); 371. 372. /* failure */ 373. return (struct obj *)0; 374. } 375. 376. /* Called after polymorphing a monster, robbing it, etc.... Monsters 377. * otherwise never unwield stuff on their own. Shouldn't print messages. 378. */ 379. void 380. possibly_unwield(mon) 381. register struct monst *mon; 382. { 383. register struct obj *obj; 384. struct obj *mw_tmp; 385. 386. if (!(mw_tmp = MON_WEP(mon))) 387. return; 388. for(obj=mon->minvent; obj; obj=obj->nobj) 389. if (obj == mw_tmp) break; 390. if (!obj) { /* The weapon was stolen or destroyed */ 391. MON_NOWEP(mon); 392. mon->weapon_check = NEED_WEAPON; 393. return; 394. } 395. if (!attacktype(mon->data, AT_WEAP)) { 396. mw_tmp->owornmask &= ~W_WEP; 397. MON_NOWEP(mon); 398. mon->weapon_check = NO_WEAPON_WANTED; 399. obj_extract_self(obj); 400. /* flooreffects unnecessary, can't wield boulders */ 401. place_object(obj, mon->mx, mon->my); 402. stackobj(obj); 403. if (cansee(mon->mx, mon->my)) { 404. pline("%s drops %s.", Monnam(mon), 405. distant_name(obj, doname)); 406. newsym(mon->mx, mon->my); 407. } 408. return; 409. } 410. /* The remaining case where there is a change is where a monster 411. * is polymorphed into a stronger/weaker monster with a different 412. * choice of weapons. This has no parallel for players. It can 413. * be handled by waiting until mon_wield_item is actually called. 414. * Though the monster still wields the wrong weapon until then, 415. * this is OK since the player can't see it. 416. * Note that if there is no change, setting the check to NEED_WEAPON 417. * is harmless. 418. * Possible problem: big monster with big cursed weapon gets 419. * polymorphed into little monster. But it's not quite clear how to 420. * handle this anyway.... 421. */ 422. mon->weapon_check = NEED_WEAPON; 423. } 424. 425. /* Let a monster try to wield a weapon, based on mon->weapon_check. 426. * Returns 1 if the monster took time to do it, 0 if it did not. 427. */ 428. int 429. mon_wield_item(mon) 430. register struct monst *mon; 431. { 432. struct obj *obj; 433. 434. /* This case actually should never happen */ 435. if (mon->weapon_check == NO_WEAPON_WANTED) return 0; 436. 437. switch(mon->weapon_check) { 438. case NEED_HTH_WEAPON: 439. obj = select_hwep(mon); 440. break; 441. case NEED_RANGED_WEAPON: 442. (void)select_rwep(mon); 443. obj = propellor; 444. break; 445. case NEED_PICK_AXE: 446. obj = m_carrying(mon, PICK_AXE); 447. break; 448. default: impossible("weapon_check %d for %s?", 449. mon->weapon_check, mon_nam(mon)); 450. return 0; 451. } 452. if (obj && obj != &zeroobj) { 453. struct obj *mw_tmp = MON_WEP(mon); 454. if (mw_tmp && mw_tmp->otyp == obj->otyp) { 455. /* already wielding it */ 456. mon->weapon_check = NEED_WEAPON; 457. return 0; 458. } 459. /* Actually, this isn't necessary--as soon as the monster 460. * wields the weapon, the weapon welds itself, so the monster 461. * can know it's cursed and needn't even bother trying. 462. * Still.... 463. */ 464. if (mw_tmp && mw_tmp->cursed && mw_tmp->otyp != CORPSE) { 465. if (canseemon(mon)) { 466. char welded_buf[BUFSZ]; 467. 468. Sprintf(welded_buf, "%s welded to %s hand%s", 469. (mw_tmp->quan == 1L) ? "is" : "are", 470. his[pronoun_gender(mon)], 471. objects[mw_tmp->otyp].oc_bimanual ? "s" : ""); 472. 473. if (obj->otyp == PICK_AXE) { 474. pline("Since %s weapon%s %s,", 475. s_suffix(mon_nam(mon)), 476. plur(mw_tmp->quan), welded_buf); 477. pline("%s cannot wield that %s.", 478. mon_nam(mon), xname(obj)); 479. } else { 480. pline("%s tries to wield %s.", Monnam(mon), 481. doname(obj)); 482. pline("%s %s %s!", 483. s_suffix(Monnam(mon)), 484. xname(mw_tmp), welded_buf); 485. } 486. mw_tmp->bknown = 1; 487. } 488. mon->weapon_check = NO_WEAPON_WANTED; 489. return 1; 490. } 491. mon->mw = obj; /* wield obj */ 492. if (mw_tmp) mw_tmp->owornmask &= ~W_WEP; 493. mon->weapon_check = NEED_WEAPON; 494. if (canseemon(mon)) { 495. pline("%s wields %s!", Monnam(mon), doname(obj)); 496. if (obj->cursed && obj->otyp != CORPSE) { 497. pline("%s %s to %s hand!", 498. The(xname(obj)), 499. (obj->quan == 1L) ? "welds itself" 500. : "weld themselves", 501. s_suffix(mon_nam(mon))); 502. obj->bknown = 1; 503. } 504. } 505. obj->owornmask = W_WEP; 506. return 1; 507. } 508. mon->weapon_check = NEED_WEAPON; 509. return 0; 510. } 511. 512. int 513. abon() /* attack bonus for strength & dexterity */ 514. { 515. int sbon; 516. register int str = ACURR(A_STR), dex = ACURR(A_DEX); 517. 518. if (u.umonnum >= LOW_PM) return(adj_lev(&mons[u.umonnum]) - 3); 519. if (str < 6) sbon = -2; 520. else if (str < 8) sbon = -1; 521. else if (str < 17) sbon = 0; 522. else if (str < 69) sbon = 1; /* up to 18/50 */ 523. else if (str < 118) sbon = 2; 524. else sbon = 3; 525. 526. /* Game tuning kludge: make it a bit easier for a low level character to hit */ 527. sbon += (u.ulevel < 3) ? 1 : 0; 528. 529. if (dex < 4) return(sbon-3); 530. else if (dex < 6) return(sbon-2); 531. else if (dex < 8) return(sbon-1); 532. else if (dex < 14) return(sbon); 533. else return(sbon + dex-14); 534. } 535. 536. #endif /* OVL0 */ 537. #ifdef OVL1 538. 539. int 540. dbon() /* damage bonus for strength */ 541. { 542. register int str = ACURR(A_STR); 543. 544. if (u.umonnum >= LOW_PM) return(0); 545. 546. if (str < 6) return(-1); 547. else if (str < 16) return(0); 548. else if (str < 18) return(1); 549. else if (str == 18) return(2); /* up to 18 */ 550. else if (str < 94) return(3); /* up to 18/75 */ 551. else if (str < 109) return(4); /* up to 18/90 */ 552. else if (str < 118) return(5); /* up to 18/99 */ 553. else return(6); 554. } 555. 556. 557. #ifdef WEAPON_SKILLS 558. 559. /* copy the skill level name into the given buffer */ 560. static char * 561. skill_level_name(skill, buf) 562. int skill; 563. char *buf; 564. { 565. const char *ptr; 566. 567. if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT) { 568. switch (P_SKILL(skill)) { 569. case P_UNSKILLED: ptr = "Unskilled"; break; 570. case P_BASIC: ptr = "Basic"; break; 571. case P_SKILLED: ptr = "Skilled"; break; 572. case P_EXPERT: ptr = "Expert"; break; 573. default: ptr = "Unknown?"; break; 574. } 575. Strcpy(buf, ptr); 576. } else { 577. Sprintf(buf, "%d", P_SKILL(skill)); 578. } 579. return buf; 580. } 581. 582. /* return the # of slots required to advance the skill */ 583. static int 584. slots_required(skill) 585. int skill; 586. { 587. /* The more difficult the training, the more slots it takes. */ 588. if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT) 589. return P_SKILL(skill); 590. 591. return (P_SKILL(skill) > 5) ? 2 : 1; /* unarmed or martial */ 592. } 593. 594. /* return true if this skill can be advanced */ 595. static boolean 596. can_advance(skill) 597. int skill; 598. { 599. return !P_RESTRICTED(skill) 600. && P_SKILL(skill) < P_MAX_SKILL(skill) 601. && P_ADVANCE(skill) >= 602. (unsigned) practice_needed_to_advance(P_SKILL(skill)) 603. && u.skills_advanced < P_SKILL_LIMIT 604. && u.weapon_slots >= slots_required(skill); 605. } 606. 607. /* `#qualifications' extended command */ 608. int 609. check_weapon_skills() 610. { 611. int i, len, name_length; 612. char buf[BUFSIZ], buf2[BUFSIZ]; 613. winid tmpwin; 614. 615. tmpwin = create_nhwindow(NHW_MENU); 616. putstr(tmpwin, 0, "Current Skills:"); 617. putstr(tmpwin, 0, ""); 618. 619. /* Find longest available skill name. */ 620. for (name_length = 0, i = 0; i < P_NUM_SKILLS; i++) 621. if (!P_RESTRICTED(i) && (len = strlen(P_NAME(i))) > name_length) 622. name_length = len; 623. 624. /* list the skills, indicating which ones could be advanced */ 625. for (i = 0; i < P_NUM_SKILLS; i++) { 626. if (P_RESTRICTED(i)) continue; 627. #if 1 628. if (i == P_TWO_WEAPON_COMBAT) continue; 629. #endif 630. 631. /* sigh, this assumes a monospaced font */ 632. if (wizard) 633. Sprintf(buf2, "%-*s %c%-9s %4d(%4d)", name_length, P_NAME(i), 634. can_advance(i) ? '*' : ' ', 635. skill_level_name(i, buf), 636. P_ADVANCE(i), practice_needed_to_advance(P_SKILL(i))); 637. else 638. Sprintf(buf2, "%-*s %c[%s]", name_length, P_NAME(i), 639. can_advance(i) ? '*' : ' ', 640. skill_level_name(i, buf)); 641. putstr(tmpwin, 0, buf2); 642. } 643. 644. display_nhwindow(tmpwin, TRUE); 645. destroy_nhwindow(tmpwin); 646. return 0; 647. } 648. 649. static void 650. skill_advance(skill) 651. int skill; 652. { 653. You("are now more skilled in %s.", P_NAME(skill)); 654. u.weapon_slots -= slots_required(skill); 655. P_SKILL(skill)++; 656. u.skill_record[u.skills_advanced++] = skill; 657. } 658. 659. /* `#enhance' extended command */ 660. int 661. select_weapon_skill() 662. { 663. int i, n, mark, len, longest; 664. char buf[BUFSIZ], buf2[BUFSIZ]; 665. menu_item *selected; 666. anything any; 667. winid win; 668. 669. /* count # of skills we can advance */ 670. for (longest = mark = n = i = 0; i < P_NUM_SKILLS; i++) 671. if (can_advance(i)) { 672. if ((len = strlen(P_NAME(i))) > longest) longest = len; 673. mark = i; /* in case we can only advance one */ 674. n++; 675. } 676. 677. if (n == 0) { 678. You("are not able to advance any skill right now."); 679. return 0; 680. } 681. 682. if (n != 1) { 683. /* ask which skill to advance */ 684. win = create_nhwindow(NHW_MENU); 685. start_menu(win); 686. any.a_void = 0; 687. for (i = 0; i < P_NUM_SKILLS; i++) { 688. if (!can_advance(i)) continue; 689. 690. if (i <= P_LAST_WEAPON || i == P_TWO_WEAPON_COMBAT) 691. (void) skill_level_name(i, buf2); 692. else 693. Sprintf(buf2, "%d", slots_required(i)); 694. 695. /* assume monospaced font */ 696. Sprintf(buf, "%-*s [%s]", longest, P_NAME(i), buf2); 697. any.a_int = i + 1; /* must be non-zero */ 698. #if 1 699. if (i == P_TWO_WEAPON_COMBAT) continue; 700. #endif 701. add_menu(win, NO_GLYPH, &any, 0, 0, buf, MENU_UNSELECTED); 702. } 703. 704. end_menu(win, "Pick a skill to advance:"); 705. n = select_menu(win, PICK_ONE, &selected); 706. destroy_nhwindow(win); 707. if (n <= 0) return 0; /* cancelled dialog */ 708. 709. mark = selected[0].item.a_int - 1; /* get item selected */ 710. free((genericptr_t)selected); 711. } 712. 713. skill_advance(mark); 714. return 0; 715. } 716. 717. /* 718. * Change from restricted to unrestricted, allowing P_BASIC as max. This 719. * function may be called with with P_NO_TYPE. Used in pray.c. 720. */ 721. void 722. unrestrict_weapon_skill(skill) 723. int skill; 724. { 725. if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) { 726. P_SKILL(skill) = P_UNSKILLED; 727. P_MAX_SKILL(skill) = P_BASIC; 728. P_ADVANCE(skill) = 0; 729. } 730. } 731. 732. #endif /* WEAPON_SKILLS */ 733. 734. #endif /* OVL1 */ 735. #ifdef OVLB 736. 737. #ifdef WEAPON_SKILLS 738. 739. void 740. add_weapon_skill() 741. { 742. u.weapon_slots++; 743. } 744. 745. void 746. lose_weapon_skill() 747. { 748. int skill; 749. 750. /* deduct first from unused slots, then from last placed slot, if any */ 751. if (u.weapon_slots) { 752. u.weapon_slots--; 753. } else if (u.skills_advanced) { 754. skill = u.skill_record[--u.skills_advanced]; 755. if (P_SKILL(skill) <= P_UNSKILLED) 756. panic("lose_weapon_skill"); 757. 758. P_SKILL(skill)--; /* drop skill one level */ 759. 760. /* Some skills take more than one slot, refund the rest. */ 761. if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT) 762. u.weapon_slots = P_SKILL(skill) - 1; 763. else if (P_SKILL(skill) >= 5) 764. u.weapon_slots = 1; 765. } 766. } 767. 768. int 769. weapon_type(obj) 770. struct obj *obj; 771. { 772. int type; 773. 774. if (obj) { 775. switch (obj->otyp) { 776. case DAGGER: case ELVEN_DAGGER: 777. case ORCISH_DAGGER: case ATHAME: 778. type = P_DAGGER; break; 779. case KNIFE: case STILETTO: 780. case WORM_TOOTH: case CRYSKNIFE: 781. case SCALPEL: 782. type = P_KNIFE; break; 783. case AXE: case BATTLE_AXE: 784. type = P_AXE; break; 785. case DWARVISH_MATTOCK: 786. case PICK_AXE: 787. type = P_PICK_AXE; break; 788. case SHORT_SWORD: case ELVEN_SHORT_SWORD: 789. case ORCISH_SHORT_SWORD: case DWARVISH_SHORT_SWORD: 790. type = P_SHORT_SWORD; break; 791. case BROADSWORD: case ELVEN_BROADSWORD: 792. case RUNESWORD: 793. type = P_BROAD_SWORD; break; 794. case LONG_SWORD: case KATANA: 795. type = P_LONG_SWORD; break; 796. case TWO_HANDED_SWORD: case TSURUGI: 797. type = P_TWO_HANDED_SWORD; break; 798. case SCIMITAR: 799. type = P_SCIMITAR; break; 800. case SILVER_SABER: 801. type = P_SABER; break; 802. case CLUB: case AKLYS: 803. type = P_CLUB; break; 804. case MACE: 805. type = P_MACE; break; 806. case MORNING_STAR: 807. type = P_MORNING_STAR; break; 808. case FLAIL: 809. type = P_FLAIL; break; 810. case WAR_HAMMER: 811. type = P_HAMMER; break; 812. case QUARTERSTAFF: 813. type = P_QUARTERSTAFF; break; 814. case PARTISAN: case RANSEUR: 815. case SPETUM: case GLAIVE: 816. case HALBERD: case BARDICHE: 817. case VOULGE: case FAUCHARD: 818. case GUISARME: case BILL_GUISARME: 819. case LUCERN_HAMMER: case BEC_DE_CORBIN: 820. type = P_POLEARMS; break; 821. case SPEAR: case ELVEN_SPEAR: 822. case ORCISH_SPEAR: case DWARVISH_SPEAR: 823. type = P_SPEAR; break; 824. case JAVELIN: 825. type = P_JAVELIN; break; 826. case LANCE: 827. type = P_LANCE; break; 828. case BOW: case ELVEN_BOW: 829. case ORCISH_BOW: case YUMI: 830. type = P_BOW; break; 831. case SLING: 832. type = P_SLING; break; 833. case CROSSBOW: 834. type = P_CROSSBOW; break; 835. case DART: 836. type = P_DART; break; 837. case SHURIKEN: 838. type = P_SHURIKEN; break; 839. case BOOMERANG: 840. type = P_BOOMERANG; break; 841. case BULLWHIP: 842. #ifdef KOPS 843. case RUBBER_HOSE: 844. #endif 845. type = P_WHIP; break; 846. case UNICORN_HORN: 847. type = P_UNICORN_HORN; break; 848. default: 849. type = P_NO_TYPE; break; 850. } 851. return type; 852. } 853. 854. /* No object is one of these. */ 855. return P_RESTRICTED(P_BARE_HANDED_COMBAT) ? P_MARTIAL_ARTS : 856. P_BARE_HANDED_COMBAT; 857. } 858. 859. /* 860. * Return hit bonus/penalty based on skill of weapon. 861. * Treat restricted weapons as unskilled. 862. */ 863. int 864. weapon_hit_bonus(weapon) 865. struct obj *weapon; 866. { 867. int type, bonus = 0; 868. static const char bad_skill[] = "weapon_hit_bonus: bad skill %d"; 869. 870. type = weapon_type(weapon); 871. if (type == P_NO_TYPE) { 872. bonus = 0; 873. } else if (type <= P_LAST_WEAPON) { 874. switch (P_SKILL(type)) { 875. default: impossible(bad_skill, P_SKILL(type)); /* fall through */ 876. case P_ISRESTRICTED: 877. case P_UNSKILLED: bonus = -4; break; 878. case P_BASIC: bonus = 0; break; 879. case P_SKILLED: bonus = 2; break; 880. case P_EXPERT: bonus = 3; break; 881. } 882. } else if (type == P_TWO_WEAPON_COMBAT) { 883. switch (P_SKILL(type)) { 884. default: impossible(bad_skill, P_SKILL(type)); /* fall through */ 885. case P_ISRESTRICTED: 886. case P_UNSKILLED: bonus = -9; break; 887. case P_BASIC: bonus = -7; break; 888. case P_SKILLED: bonus = -5; break; 889. case P_EXPERT: bonus = -3; break; 890. } 891. } else if (type == P_BARE_HANDED_COMBAT) { 892. bonus = (P_SKILL(type) + 1) / 2; /* restricted == 0 */ 893. } else if (type == P_MARTIAL_ARTS) { 894. bonus = (P_SKILL(type) + 1) * 2 / 3; /* restricted == 0 */ 895. } 896. return bonus; 897. } 898. 899. /* 900. * Return damage bonus/penalty based on skill of weapon. 901. * Treat restricted weapons as unskilled. 902. */ 903. int 904. weapon_dam_bonus(weapon) 905. struct obj *weapon; 906. { 907. int type, bonus = 0; 908. 909. type = weapon_type(weapon); 910. if (type == P_NO_TYPE) { 911. bonus = 0; 912. } else if (P_RESTRICTED(type) || type <= P_LAST_WEAPON) { 913. switch (P_SKILL(type)) { 914. default: impossible("weapon_dam_bonus: bad skill %d",P_SKILL(type)); 915. /* fall through */ 916. case P_ISRESTRICTED: 917. case P_UNSKILLED: bonus = -2; break; 918. case P_BASIC: bonus = 0; break; 919. case P_SKILLED: bonus = 1; break; 920. case P_EXPERT: bonus = 2; break; 921. } 922. } else if (type == P_BARE_HANDED_COMBAT && P_SKILL(type)) { 923. bonus = P_SKILL(type) / 2; 924. } else if (type == P_MARTIAL_ARTS && P_SKILL(type)) { 925. bonus = P_SKILL(type) * 2 / 3; 926. } 927. return bonus; 928. } 929. 930. /* 931. * Initialize weapon skill array for the game. Start by setting all 932. * skills to restricted, then set the skill for every weapon the 933. * hero is holding, finally reading the given array that sets 934. * maximums. 935. */ 936. void 937. skill_init(class_skill) 938. struct def_skill *class_skill; 939. { 940. struct obj *obj; 941. int skmax, skill; 942. 943. /* initialize skill array; by default, everything is restricted */ 944. for (skill = 0; skill < P_NUM_SKILLS; skill++) { 945. P_SKILL(skill) = P_ISRESTRICTED; 946. P_MAX_SKILL(skill) = P_ISRESTRICTED; 947. P_ADVANCE(skill) = 0; 948. } 949. 950. /* set skill for all weapons in inventory to be basic */ 951. for (obj = invent; obj; obj = obj->nobj) { 952. skill = weapon_type(obj); 953. if (skill != P_NO_TYPE) 954. P_SKILL(skill) = P_BASIC; 955. } 956. 957. /* walk through array to set skill maximums */ 958. for (; class_skill->skill != P_NO_TYPE; class_skill++) { 959. skmax = class_skill->skmax; 960. skill = class_skill->skill; 961. 962. P_MAX_SKILL(skill) = skmax; 963. if (P_SKILL(skill) == P_ISRESTRICTED) /* skill pre-set */ 964. P_SKILL(skill) = P_UNSKILLED; 965. } 966. 967. /* 968. * Make sure we haven't missed setting the max on a skill 969. * & set advance 970. */ 971. for (skill = 0; skill < P_NUM_SKILLS; skill++) { 972. if (!P_RESTRICTED(skill)) { 973. if (P_MAX_SKILL(skill) < P_SKILL(skill)) { 974. impossible("skill_init: curr > max: %s", P_NAME(skill)); 975. P_MAX_SKILL(skill) = P_SKILL(skill); 976. } 977. P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill)-1); 978. } 979. } 980. } 981. 982. #endif /* WEAPON_SKILLS */ 983. 984. #endif /* OVLB */ 985. 986. /*weapon.c*/
|