Source:NetHack 3.2.0/weapon.c
(Redirected from NetHack 3.2.0/weapon.c)
Jump to navigation
Jump to search
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
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
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*/