abstract
| - Below is the full text to spell.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/spell.c#line123]], for example. Warning! This is the source code from an old release. For the latest release, see Source code 1. /* SCCS Id: @(#)spell.c 3.1 92/12/10 2. /* Copyright (c) M. Stephenson 1988 */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. 5. #include "hack.h" 6. 7. static schar NEARDATA delay; /* moves left for this spell */ 8. static struct obj NEARDATA *book; /* last/current book being xscribed */ 9. 10. #define spelluses(spell) spl_book[spell-1].sp_uses 11. #define decrnuses(spell) spl_book[spell-1].sp_uses-- 12. #define spellev(spell) spl_book[spell-1].sp_lev 13. #define spellname(spell) OBJ_NAME(objects[spl_book[spell-1].sp_id]) 14. #define spellid(spell) spl_book[spell-1].sp_id 15. 16. static void FDECL(cursed_book, (int)); 17. static void FDECL(deadbook, (struct obj *)); 18. STATIC_PTR int NDECL(learn); 19. static int NDECL(getspell); 20. static char FDECL(spellet, (int)); 21. static char NDECL(dospellmenu); 22. 23. static void 24. cursed_book(lev) 25. register int lev; 26. { 27. switch(rn2(lev)) { 28. case 0: 29. You("feel a wrenching sensation."); 30. tele(); /* teleport him */ 31. break; 32. case 1: 33. You("feel threatened."); 34. aggravate(); 35. break; 36. case 2: 37. make_blinded(Blinded + rn1(100,250),TRUE); 38. break; 39. case 3: 40. take_gold(); 41. break; 42. case 4: 43. pline("These runes were just too much to comprehend."); 44. make_confused(HConfusion + rn1(7,16),FALSE); 45. break; 46. case 5: 47. pline("The book was coated with contact poison!"); 48. if (uarmg) { 49. /* Note: at this writing, there are no corrodeable 50. * gloves in the game. If no one plans on adding 51. * copper gauntlets, most of this could be removed. -3. 52. */ 53. if (uarmg->oerodeproof || !is_corrodeable(uarmg)) { 54. Your("gloves seem unaffected."); 55. } else if (uarmg->oeroded < MAX_ERODE) { 56. Your("gloves corrode%s!", 57. uarmg->oeroded+1 == MAX_ERODE ? " completely" : 58. uarmg->oeroded ? " further" : ""); 59. uarmg->oeroded++; 60. } else 61. Your("gloves %s completely corroded.", 62. Blind ? "feel" : "look"); 63. break; 64. } 65. if(Poison_resistance) { 66. losestr(rn1(1,2)); 67. losehp(rnd(6), "contact-poisoned spellbook", KILLED_BY_AN); 68. } else { 69. losestr(rn1(4,3)); 70. losehp(rnd(10), "contact-poisoned spellbook", KILLED_BY_AN); 71. } 72. break; 73. case 6: 74. if(Antimagic) { 75. shieldeff(u.ux, u.uy); 76. pline("The book explodes, but you are unharmed!"); 77. } else { 78. pline("As you read the book, it explodes in your %s!", 79. body_part(FACE)); 80. losehp (2*rnd(10)+5, "exploding rune", KILLED_BY_AN); 81. } 82. break; 83. default: 84. rndcurse(); 85. break; 86. } 87. return; 88. } 89. 90. /* special effects for The Book of the Dead */ 91. static void 92. deadbook(book2) 93. struct obj *book2; 94. { 95. if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { 96. register struct obj *otmp; 97. register boolean arti1_primed = FALSE, arti2_primed = FALSE, 98. arti_cursed = FALSE; 99. 100. if(book2->cursed) { 101. pline("The runes appear scrambled. You can't read them!"); 102. return; 103. } 104. 105. if(!u.uhave.bell || !u.uhave.menorah) { 106. pline("A chill runs down your spine."); 107. if(!u.uhave.bell) You("hear a faint chime..."); 108. if(!u.uhave.menorah) pline("Vlad's doppelganger is amused."); 109. return; 110. } 111. 112. for(otmp = invent; otmp; otmp = otmp->nobj) { 113. if(otmp->otyp == CANDELABRUM_OF_INVOCATION && 114. otmp->spe == 7 && otmp->lamplit) { 115. if(!otmp->cursed) arti1_primed = TRUE; 116. else arti_cursed = TRUE; 117. } 118. if(otmp->otyp == BELL_OF_OPENING && 119. (moves - otmp->age) < 5L) { /* you rang it recently */ 120. if(!otmp->cursed) arti2_primed = TRUE; 121. else arti_cursed = TRUE; 122. } 123. } 124. 125. if(arti_cursed) { 126. pline("The invocation fails!"); 127. pline("At least one of your artifacts is cursed..."); 128. } else if(arti1_primed && arti2_primed) { 129. mkinvokearea(); 130. u.uevent.invoked = 1; 131. } else { /* at least one artifact not prepared properly */ 132. You("have a feeling that something is amiss..."); 133. goto raise_dead; 134. } 135. return; 136. } 137. 138. /* when not an invocation situation */ 139. if(book2->cursed) 140. raise_dead: 141. { 142. register struct monst *mtmp; 143. coord mm; 144. 145. You("raised the dead!"); 146. mm.x = u.ux; 147. mm.y = u.uy; 148. mkundead(&mm); 149. if(!rn2(4)) 150. if(mtmp = makemon(&mons[PM_MASTER_LICH],u.ux,u.uy)) { 151. mtmp->mpeaceful = 0; 152. set_malign(mtmp); 153. } 154. } else if(book2->blessed) { 155. register struct monst *mtmp, *mtmp2; 156. 157. for(mtmp = fmon; mtmp; mtmp = mtmp2) { 158. mtmp2 = mtmp->nmon; /* tamedog() changes chain */ 159. if(is_undead(mtmp->data) && cansee(mtmp->mx, mtmp->my)) { 160. mtmp->mpeaceful = TRUE; 161. if(sgn(mtmp->data->maligntyp) == sgn(u.ualign.type) 162. && distu(mtmp->mx, mtmp->my) < 4) 163. if (mtmp->mtame) 164. mtmp->mtame++; 165. else 166. (void) tamedog(mtmp, (struct obj *)0); 167. else mtmp->mflee = TRUE; 168. } 169. } 170. } else { 171. switch(rn2(3)) { 172. case 0: 173. Your("ancestors are annoyed with you!"); 174. break; 175. case 1: 176. pline("The headstones in the cemetery begin to move!"); 177. break; 178. default: 179. pline("Oh my! Your name appears in the book!"); 180. } 181. } 182. return; 183. } 184. 185. STATIC_PTR 186. int 187. learn() 188. { 189. register int i; 190. register unsigned booktype; 191. 192. if (delay) { /* not if (delay++), so at end delay == 0 */ 193. delay++; 194. return(1); /* still busy */ 195. } 196. exercise(A_WIS, TRUE); /* you're studying. */ 197. booktype = book->otyp; 198. if(booktype == SPE_BOOK_OF_THE_DEAD) { 199. deadbook(book); 200. return(0); 201. } 202. 203. for (i = 0; i < MAXSPELL; i++) { 204. if (spl_book[i].sp_id == booktype) { 205. if (book->spestudied >= rn1(1,8-spl_book[i].sp_lev)) { 206. pline("This spellbook is too faint to be read anymore."); 207. book->otyp = booktype = SPE_BLANK_PAPER; 208. makeknown((int)booktype); 209. } 210. else if (spl_book[i].sp_uses < 11-spl_book[i].sp_lev) { 211. Your("knowledge of that spell is keener."); 212. spl_book[i].sp_uses += rn1(1,9-spl_book[i].sp_lev); 213. book->spestudied++; 214. exercise(A_WIS, TRUE); /* extra study */ 215. } else 216. You("know that spell quite well already."); 217. break; 218. } else if (spl_book[i].sp_id == NO_SPELL) { 219. spl_book[i].sp_id = booktype; 220. spl_book[i].sp_lev = objects[booktype].oc_level; 221. /* spells have 1 .. 9-level uses. */ 222. /* ie 1 or 2 uses w/ most potent */ 223. spl_book[i].sp_uses = rn1(1,9-spl_book[i].sp_lev); 224. book->spestudied++; 225. You("add the spell to your repertoire."); 226. makeknown((int)booktype); 227. break; 228. } 229. } 230. if (i == MAXSPELL) impossible("Too many spells memorized!"); 231. 232. if (book->cursed) { /* maybe a demon cursed it */ 233. cursed_book(objects[booktype].oc_level); 234. } 235. check_unpaid(book); 236. book = 0; 237. return(0); 238. } 239. 240. int 241. study_book(spellbook) 242. register struct obj *spellbook; 243. { 244. register int booktype = spellbook->otyp; 245. register boolean confused = (Confusion != 0); 246. 247. if (delay && spellbook == book) 248. You("continue your efforts to memorize the spell."); 249. else { 250. switch(booktype) { 251. 252. /* blank spellbook */ 253. case SPE_BLANK_PAPER: 254. pline("This spellbook is all blank."); 255. makeknown(SPE_BLANK_PAPER); 256. return(1); 257. /* level 1 spells */ 258. case SPE_HEALING: 259. case SPE_DETECT_MONSTERS: 260. case SPE_FORCE_BOLT: 261. case SPE_LIGHT: 262. case SPE_SLEEP: 263. case SPE_KNOCK: 264. /* level 2 spells */ 265. case SPE_MAGIC_MISSILE: 266. case SPE_CONFUSE_MONSTER: 267. case SPE_SLOW_MONSTER: 268. case SPE_CURE_BLINDNESS: 269. case SPE_CREATE_MONSTER: 270. case SPE_DETECT_FOOD: 271. case SPE_WIZARD_LOCK: 272. delay = -objects[booktype].oc_delay; 273. break; 274. /* level 3 spells */ 275. case SPE_HASTE_SELF: 276. case SPE_CAUSE_FEAR: 277. case SPE_CURE_SICKNESS: 278. case SPE_DETECT_UNSEEN: 279. case SPE_EXTRA_HEALING: 280. case SPE_CHARM_MONSTER: 281. case SPE_CLAIRVOYANCE: 282. /* level 4 spells */ 283. case SPE_LEVITATION: 284. case SPE_RESTORE_ABILITY: 285. case SPE_INVISIBILITY: 286. case SPE_FIREBALL: 287. case SPE_DETECT_TREASURE: 288. delay = -(objects[booktype].oc_level - 1) * objects[booktype].oc_delay; 289. break; 290. /* level 5 spells */ 291. case SPE_REMOVE_CURSE: 292. case SPE_MAGIC_MAPPING: 293. case SPE_CONE_OF_COLD: 294. case SPE_IDENTIFY: 295. case SPE_DIG: 296. /* level 6 spells */ 297. case SPE_TURN_UNDEAD: 298. case SPE_POLYMORPH: 299. case SPE_CREATE_FAMILIAR: 300. case SPE_TELEPORT_AWAY: 301. delay = -objects[booktype].oc_level * objects[booktype].oc_delay; 302. break; 303. /* level 7 spells */ 304. case SPE_CANCELLATION: 305. case SPE_FINGER_OF_DEATH: 306. case SPE_BOOK_OF_THE_DEAD: 307. delay = -8 * objects[booktype].oc_delay; 308. break; 309. /* impossible */ 310. default: 311. impossible("Unknown spellbook, %d;", booktype); 312. return(0); 313. } 314. 315. /* Books are often wiser than their readers (Rus.) */ 316. if(!spellbook->blessed && 317. spellbook->otyp != SPE_BOOK_OF_THE_DEAD && 318. (spellbook->cursed || 319. rn2(20) > (ACURR(A_INT) + 4 + (int)(u.ulevel/2) 320. - 2*objects[booktype].oc_level))) { 321. cursed_book(objects[booktype].oc_level); 322. nomul(delay); /* study time */ 323. delay = 0; 324. if(!rn2(3)) { 325. useup(spellbook); 326. pline("The spellbook crumbles to dust!"); 327. } 328. return(1); 329. } 330. else if(confused) { 331. if(!rn2(3) && 332. spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { 333. useup(spellbook); 334. pline("Being confused you have difficulties in controlling your actions."); 335. display_nhwindow(WIN_MESSAGE, FALSE); 336. You("accidentally tear the spellbook to pieces."); 337. } 338. else 339. You("find yourself reading the first line over and over again."); 340. nomul(delay); 341. delay = 0; 342. return(1); 343. } 344. 345. You("begin to %s the runes.", 346. spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" : 347. "memorize"); 348. } 349. 350. book = spellbook; 351. set_occupation(learn, "studying", 0); 352. return(1); 353. } 354. 355. static int 356. getspell() 357. { 358. register int maxs, ilet, i; 359. char lets[BUFSZ], buf[BUFSZ], qbuf[QBUFSZ]; 360. 361. if (spl_book[0].sp_id == NO_SPELL) { 362. 363. You("don't know any spells right now."); 364. return(0); 365. } else { 366. 367. for(maxs = 1; (maxs < MAXSPELL) && (spl_book[maxs].sp_id != NO_SPELL); maxs++); 368. if (maxs >= MAXSPELL) { 369. 370. impossible("Too many spells memorized."); 371. return(0); 372. } 373. 374. for(i = 0; (i < maxs) && (i < 26); buf[++i] = 0) buf[i] = 'a' + i; 375. for(i = 26; (i < maxs) && (i < 52); buf[++i] = 0) buf[i] = 'A' + i - 26; 376. 377. if (maxs == 1) Strcpy(lets, "a"); 378. else if (maxs < 27) Sprintf(lets, "a-%c", 'a' + maxs - 1); 379. else if (maxs == 27) Sprintf(lets, "a-z A"); 380. else Sprintf(lets, "a-z A-%c", 'A' + maxs - 27); 381. for(;;) { 382. 383. Sprintf(qbuf, "Cast which spell? [%s ?]", lets); 384. if ((ilet = yn_function(qbuf, NULL, '\0')) == '?') { 385. ilet = dospellmenu(); 386. if(!ilet) 387. continue; 388. } 389. if (index(quitchars, ilet)) 390. return(0); 391. else for(i = 0; buf[i] != 0; i++) 392. if(ilet == buf[i]) return(++i); 393. You("don't know that spell."); 394. } 395. } 396. } 397. 398. int 399. docast() 400. { 401. register int spell; 402. 403. spell = getspell(); 404. if (!spell) return(0); 405. 406. return(spelleffects(spell,FALSE)); 407. } 408. 409. int 410. spelleffects(spell,atme) 411. register int spell; 412. boolean atme; 413. { 414. register int energy, damage; 415. boolean confused = (Confusion != 0); 416. struct obj *pseudo; 417. 418. /* note that trying to cast it decrements the # of uses, */ 419. /* even if the mage does not have enough food/energy to use */ 420. /* the spell */ 421. switch (spelluses(spell)) { 422. case 0: 423. pline ("Curdled magical energy twists through you..."); 424. pline ("...you have overloaded and burned out this spell."); 425. make_confused((long)spellev(spell) * 3, FALSE); 426. return(0); 427. case 1: 428. Your("nerves tingle warningly."); 429. break; 430. case 2: 431. pline ("This spell is starting to be over-used."); 432. break; 433. default: 434. break; 435. } 436. decrnuses(spell); 437. energy = spellev(spell) * 7 / 2 - 2; /* 1 <= energy <= 22 */ 438. if (u.uhunger <= 100 && spell != SPE_DETECT_FOOD) { 439. You("are too hungry to cast that spell."); 440. return(0); 441. } else if (ACURR(A_STR) < 6) { 442. You("lack the strength to cast spells."); 443. return(0); 444. } else if(check_capacity( 445. "Your concentration falters while carrying so much stuff.")) { 446. return (1); 447. } 448. 449. if (u.uhave.amulet) { 450. You("feel the amulet draining your energy away."); 451. energy *= rnd(3); 452. } 453. if(energy > u.uen) { 454. You("don't have enough energy to cast that spell."); 455. return(0); 456. } else { 457. if (spell != SPE_DETECT_FOOD) 458. morehungry(energy * 10); 459. u.uen -= energy; 460. } 461. flags.botl = 1; 462. 463. if (confused || 464. ((int)(ACURR(A_INT) + Luck) - 3 * spellev(spell)) < 0) { 465. 466. if (Hallucination) 467. pline("Far out... a light show!"); 468. else pline("The air around you crackles as you goof up."); 469. return(0); 470. } 471. exercise(A_WIS, TRUE); 472. /* pseudo is a temporary "false" object containing the spell stats. */ 473. pseudo = mksobj(spellid(spell), FALSE, FALSE); 474. pseudo->blessed = pseudo->cursed = 0; 475. pseudo->quan = 20L; /* do not let useup get it */ 476. switch(pseudo->otyp) { 477. 478. /* These spells are all duplicates of wand effects */ 479. case SPE_FORCE_BOLT: 480. case SPE_SLEEP: 481. case SPE_MAGIC_MISSILE: 482. case SPE_KNOCK: 483. case SPE_SLOW_MONSTER: 484. case SPE_WIZARD_LOCK: 485. case SPE_FIREBALL: 486. case SPE_CONE_OF_COLD: 487. case SPE_DIG: 488. case SPE_TURN_UNDEAD: 489. case SPE_POLYMORPH: 490. case SPE_TELEPORT_AWAY: 491. case SPE_CANCELLATION: 492. case SPE_FINGER_OF_DEATH: 493. case SPE_LIGHT: 494. case SPE_DETECT_UNSEEN: 495. if (!(objects[pseudo->otyp].oc_dir == NODIR)) { 496. if (atme) u.dx = u.dy = u.dz = 0; 497. else (void) getdir(NULL); 498. if(!u.dx && !u.dy && !u.dz) { 499. if((damage = zapyourself(pseudo))) 500. losehp(damage, 501. self_pronoun("zapped %sself with a spell", "him"), 502. NO_KILLER_PREFIX); 503. } else weffects(pseudo); 504. } else weffects(pseudo); 505. break; 506. /* These are all duplicates of scroll effects */ 507. case SPE_CONFUSE_MONSTER: 508. case SPE_DETECT_FOOD: 509. case SPE_CAUSE_FEAR: 510. case SPE_CHARM_MONSTER: 511. case SPE_REMOVE_CURSE: 512. case SPE_MAGIC_MAPPING: 513. case SPE_CREATE_MONSTER: 514. case SPE_IDENTIFY: 515. (void) seffects(pseudo); 516. break; 517. case SPE_HASTE_SELF: 518. case SPE_DETECT_TREASURE: 519. case SPE_DETECT_MONSTERS: 520. case SPE_LEVITATION: 521. case SPE_RESTORE_ABILITY: 522. case SPE_INVISIBILITY: 523. (void) peffects(pseudo); 524. break; 525. case SPE_HEALING: 526. You("feel a bit better."); 527. healup(rnd(8), 0, FALSE, FALSE); 528. break; 529. case SPE_CURE_BLINDNESS: 530. healup(0, 0, FALSE, TRUE); 531. break; 532. case SPE_CURE_SICKNESS: 533. if (Sick) You("are no longer ill."); 534. healup(0, 0, TRUE, FALSE); 535. break; 536. case SPE_EXTRA_HEALING: 537. You("feel a fair bit better."); 538. healup(d(2,8)+2, 0, FALSE, FALSE); 539. break; 540. case SPE_CREATE_FAMILIAR: 541. make_familiar((struct obj *)0, u.ux, u.uy); 542. break; 543. case SPE_CLAIRVOYANCE: 544. do_vicinity_map(); 545. break; 546. default: 547. impossible("Unknown spell %d attempted.", spell); 548. obfree(pseudo, (struct obj *)0); 549. return(0); 550. } 551. obfree(pseudo, (struct obj *)0); /* now, get rid of it */ 552. return(1); 553. } 554. 555. void 556. losespells() { 557. register boolean confused = (Confusion != 0); 558. register int n, nzap, i; 559. 560. book = 0; 561. for(n = 0;(spl_book[n].sp_id != NO_SPELL) && (n < MAXSPELL); n++); 562. if (!n) return; 563. if (n < MAXSPELL) { 564. nzap = rnd(n); 565. if (nzap < n) nzap += confused; 566. for (i = 0; i < nzap; i++) { 567. spl_book[n-i-1].sp_id = NO_SPELL; 568. exercise(A_WIS, FALSE); /* ouch! */ 569. } 570. } else impossible("Too many spells memorized!"); 571. return; 572. } 573. 574. static char 575. spellet(spl) 576. int spl; 577. { 578. return (spl < 27) ? ('a' + spl - 1) : ('A' + spl - 27); 579. } 580. 581. int 582. dovspell() 583. { 584. (void) dospellmenu(); 585. return 0; 586. } 587. 588. static char 589. dospellmenu() 590. { 591. winid tmpwin; 592. register int maxs, i; 593. char rval; 594. char buf[BUFSZ]; 595. 596. if (spl_book[0].sp_id == NO_SPELL) { 597. 598. You("don't know any spells right now."); 599. return 0; 600. } 601. 602. for(maxs = 1; (maxs < MAXSPELL) && (spl_book[maxs].sp_id != NO_SPELL); maxs++); 603. if (maxs >= MAXSPELL) { 604. 605. impossible("Too many spells memorized."); 606. return 0; 607. } 608. tmpwin = create_nhwindow(NHW_MENU); 609. start_menu(tmpwin); 610. add_menu(tmpwin, 0, 0, "Currently known spells:"); 611. add_menu(tmpwin, 0, 0, ""); 612. 613. for(i = 1; i <= maxs; i++) { 614. Sprintf(buf, "%c %c %s (%d)", 615. spellet(i), (spelluses(i)) ? '-' : '*', 616. spellname(i), spellev(i)); 617. add_menu(tmpwin, spellet(i), 0, buf); 618. } 619. end_menu(tmpwin, '\0', "\033 ", NULL); 620. rval = select_menu(tmpwin); 621. destroy_nhwindow(tmpwin); 622. 623. return rval; 624. } 625. 626. /*spell.c*/
|