Source:NetHack 3.2.0/spell.c

Below is the full text to spell.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.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.2	96/03/16	*/ 2.   /*	Copyright (c) M. Stephenson 1988			  */ 3.   /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6. 7.   static NEARDATA schar delay;		/* moves left for this spell */ 8.   static NEARDATA struct obj *book;	/* last/current book being xscribed */ 9.    10.   #define spelluses(spell)	spl_book[spell].sp_uses 11.  #define decrnuses(spell)	spl_book[spell].sp_uses-- 12.  #define spellev(spell)		spl_book[spell].sp_lev 13.  #define spellid(spell)		spl_book[spell].sp_id 14.  #define spellname(spell)	OBJ_NAME(objects[spellid(spell)]) 15.  #define spellet(spell)	\ 16.  	((char)((spell < 26) ? ('a' + spell) : ('A' + spell - 26))) 17.   18.   static void FDECL(cursed_book, (int)); 19.  static void FDECL(deadbook, (struct obj *)); 20.  STATIC_PTR int NDECL(learn); 21.  static boolean FDECL(getspell, (int *)); 22.  static boolean FDECL(dospellmenu, (int, int *)); 23.  static int FDECL(percent_success, (int)); 24.   25.   /* The cl_sptmp table lists the class-specific values for tuning 26.   * percent_success. 27.   *  28.    * Reasoning: 29.   *   splcaster, special: 30.   *	A are aware of magic through historical research 31.   *	B abhor magic (Conan finds it "interferes with his animal instincts") 32.   *	C are ignorant to magic 33.   *	E are from a magical realm 34.   *	H are very aware of healing magic through medical research 35.   *	K are moderately aware of healing from Paladin training 36.   *	P are very aware of healing magic through theological research 37.   *	R are moderately aware of magic through trickery 38.   *	S have limited magical awareness, prefering meditation to conjuring 39.   *	T are aware of magic from all the great films they have seen 40.   *	V have limited magical awareness, prefering fighting 41.   *	W are trained mages 42.   *  43.    *	The arms penalty is lessened for trained fighters B, K, S, V - 44.   *	the penalty is its metal interference, not encumberance. 45.   *	The `specspel' is a single spell which is fundamentally easier 46.   *	 for that class to cast. 47.   *  48.    *  specspel, specbon: 49.   *	A map masters (SPE_MAGIC_MAPPING) 50.   *	B fugue/berserker (SPE_HASTE_SELF) 51.   *	C born to dig (SPE_DIG) 52.   *	E infra-like vision (SPE_DETECT_UNSEEN) 53.   *	H to heal (SPE_CURE_SICKNESS) 54.   *	K to turn back evil (SPE_TURN_UNDEAD) 55.   *	P to bless (SPE_REMOVE_CURSE) 56.   *	R to find loot (SPE_DETECT_TREASURE) 57.   *	S to be At One (SPE_CLAIRVOYANCE) 58.   *	T to smile (SPE_CHARM_MONSTER) 59.   *	V control the cold (SPE_CONE_OF_COLD) 60.   *	W all really, but SPE_MAGIC_MISSILE is their party trick 61.   *  62.    *	See percent_success below for more comments. 63.   *  64.    *  uarmbon, uarmsbon, uarmhbon, uarmgbon, uarmfbon: 65.   *	Fighters find body armour & shield a little less limiting. 66.   *	Headgear, Gauntlets and Footwear are not class-specific (but  67.    *	still have an effect, except helm of brilliance, which is designed  68.    *	to permit magic-use). 69.   */  70.   static struct sptmp { 71.  	    char	class;		/* key */ 72.  	    int		splcaster;	/* base spellcasting ability */ 73.  	    int		special;	/* healing spell bonus */ 74.  	    int		uarmsbon;	/* penalty for wearing a (small) shield */ 75.  	    int		uarmbon;	/* penalty for wearing metal armour */ 76.  	    int		statused;	/* which stat is used */ 77.  	    int		specspel;	/* spell the class excels at */ 78.  	    int		specbon;	/* bonus when casting specspel */ 79.  } cl_sptmp[] = { 80.  	    { 'A',  5, 0, 2, 10, A_INT, SPE_MAGIC_MAPPING,   -4 }, 81.  	    { 'B', 14, 0, 0,  8, A_INT, SPE_HASTE_SELF,      -4 }, 82.  	    { 'C', 12, 0, 1,  8, A_INT, SPE_DIG,             -4 }, 83.  	    { 'E',  5, 0, 1, 10, A_INT, SPE_DETECT_UNSEEN,   -4 }, 84.  	    { 'H',  3,-3, 2, 10, A_WIS, SPE_CURE_SICKNESS,   -4 }, 85.  	    { 'K',  8,-2, 0,  9, A_WIS, SPE_TURN_UNDEAD,     -4 }, 86.  	    { 'P',  3,-2, 2, 10, A_WIS, SPE_REMOVE_CURSE,    -4 }, 87.  	    { 'R',  8, 0, 1,  9, A_INT, SPE_DETECT_TREASURE, -4 }, 88.  	    { 'S', 10, 0, 0,  8, A_INT, SPE_CLAIRVOYANCE,    -4 }, 89.  #ifdef TOURIST 90.  	    { 'T',  5, 1, 2, 10, A_INT, SPE_CHARM_MONSTER,   -4 }, 91.  #endif 92.  	    { 'V', 10,-2, 0,  9, A_WIS, SPE_CONE_OF_COLD,    -4 }, 93.  	    { 'W',  1, 0, 3, 10, A_INT, SPE_MAGIC_MISSILE,   -4 }, 94.  	    {   0, 10, 0, 0,  4, A_INT, 0, -3 } 95.  };  96.    97.   #define uarmhbon 4 /* Metal helmets interfere with the mind */ 98.  #define uarmgbon 6 /* Casting channels through the hands */ 99.  #define uarmfbon 2 /* All metal interferes to some degree */ 100.  101.  /* since the spellbook itself doesn't blow up, don't say just "explodes" */ 102. static const char explodes[] = "radiates explosive energy"; 103.  104.  static void 105. cursed_book(lev) 106. 	register int	lev; 107. {  108.  	switch(rn2(lev)) { 109. 	case 0: 110. 		You_feel("a wrenching sensation."); 111. 		tele;		/* teleport him */ 112. 		break; 113. 	case 1: 114. 		You_feel("threatened."); 115. 		aggravate; 116. 		break; 117. 	case 2: 118. 		make_blinded(Blinded + rn1(100,250),TRUE); 119. 		break; 120. 	case 3: 121. 		take_gold; 122. 		break; 123. 	case 4: 124. 		pline("These runes were just too much to comprehend."); 125. 		make_confused(HConfusion + rn1(7,16),FALSE); 126. 		break; 127. 	case 5: 128. 		pline_The("book was coated with contact poison!"); 129. 		if (uarmg) { 130. 		    /* Note: at this writing, there are no corrodeable 131. 		     * gloves in the game. If no one plans on adding 132. 		     * copper gauntlets, most of this could be removed. -3. 133.  		     */  134.  		    if (uarmg->oerodeproof || !is_corrodeable(uarmg)) { 135. 			Your("gloves seem unaffected."); 136. 		    } else if (uarmg->oeroded < MAX_ERODE) { 137. 			Your("gloves corrode%s!",  138.  			     uarmg->oeroded+1 == MAX_ERODE ? " completely" :  139.  			     uarmg->oeroded ? " further" : ""); 140. 			uarmg->oeroded++; 141. 		    } else 142. 			Your("gloves %s completely corroded.",  143.  			     Blind ? "feel" : "look"); 144. 		    break; 145. 		}  146.  		losestr(Poison_resistance ? rn1(2,1) : rn1(4,3)); 147. 		losehp(rnd(Poison_resistance ? 6 : 10), 148.  		       "contact-poisoned spellbook", KILLED_BY_AN); 149. 		break; 150. 	case 6: 151. 		if(Antimagic) { 152. 		    shieldeff(u.ux, u.uy); 153. 		    pline_The("book %s, but you are unharmed!", explodes); 154. 		} else { 155. 		    pline("As you read the book, it %s in your %s!",  156.  			  explodes, body_part(FACE)); 157. 		    losehp (2*rnd(10)+5, "exploding rune", KILLED_BY_AN); 158. 		}  159.  		break; 160. 	default: 161. 		rndcurse; 162. 		break; 163. 	}  164.  	return; 165. }  166.   167.  /* special effects for The Book of the Dead */ 168. static void 169. deadbook(book2) 170. struct obj *book2; 171. {  172.      You("turn the pages of the Book of the Dead..."); 173.     makeknown(SPE_BOOK_OF_THE_DEAD); 174.     if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { 175. 	register struct obj *otmp; 176. 	register boolean arti1_primed = FALSE, arti2_primed = FALSE, 177. 			 arti_cursed = FALSE; 178.  179.  	if(book2->cursed) { 180. 	    pline_The("runes appear scrambled.  You can't read them!"); 181. 	    return; 182. 	}  183.   184.  	if(!u.uhave.bell || !u.uhave.menorah) { 185. 	    pline("A chill runs down your %s.", body_part(SPINE)); 186. 	    if(!u.uhave.bell) You_hear("a faint chime..."); 187. 	    if(!u.uhave.menorah) pline("Vlad's doppelganger is amused."); 188. 	    return; 189. 	}  190.   191.  	for(otmp = invent; otmp; otmp = otmp->nobj) { 192. 	    if(otmp->otyp == CANDELABRUM_OF_INVOCATION &&  193.  	       otmp->spe == 7 && otmp->lamplit) { 194. 		if(!otmp->cursed) arti1_primed = TRUE; 195. 		else arti_cursed = TRUE; 196. 	    }  197.  	    if(otmp->otyp == BELL_OF_OPENING &&  198.  	       (moves - otmp->age) < 5L) { /* you rang it recently */ 199. 		if(!otmp->cursed) arti2_primed = TRUE; 200. 		else arti_cursed = TRUE; 201. 	    }  202.  	}  203.   204.  	if(arti_cursed) { 205. 	    pline_The("invocation fails!"); 206. 	    pline("At least one of your artifacts is cursed..."); 207. 	} else if(arti1_primed && arti2_primed) { 208. 	    mkinvokearea; 209. 	    u.uevent.invoked = 1; 210. 	} else {	/* at least one artifact not prepared properly */ 211. 	    You("have a feeling that %s is amiss...", something); 212. 	    goto raise_dead; 213. 	}  214.  	return; 215.     }  216.   217.      /* when not an invocation situation */ 218.     if(book2->cursed) 219. raise_dead: 220.     {  221.  	register struct monst *mtmp; 222. 	coord mm; 223.  224.  	You("raised the dead!"); 225. 	mm.x = u.ux; 226. 	mm.y = u.uy; 227. 	mkundead(&mm); 228. 	if(!rn2(4)) 229. 	    if ((mtmp = makemon(&mons[PM_MASTER_LICH],u.ux,u.uy)) != 0) { 230. 		mtmp->mpeaceful = 0; 231. 		set_malign(mtmp); 232. 	    }  233.      } else if(book2->blessed) { 234. 	register struct monst *mtmp, *mtmp2; 235.  236.  	for(mtmp = fmon; mtmp; mtmp = mtmp2) { 237. 	    mtmp2 = mtmp->nmon;		/* tamedog changes chain */ 238. 	    if(is_undead(mtmp->data) && cansee(mtmp->mx, mtmp->my)) { 239. 		mtmp->mpeaceful = TRUE; 240. 		if(sgn(mtmp->data->maligntyp) == sgn(u.ualign.type)  241.  		   && distu(mtmp->mx, mtmp->my) < 4) 242. 		    if (mtmp->mtame) 243. 			mtmp->mtame++; 244. 		    else 245. 			(void) tamedog(mtmp, (struct obj *)0); 246. 		else mtmp->mflee = TRUE; 247. 	    }  248.  	}  249.      } else { 250. 	switch(rn2(3)) { 251. 	case 0: 252. 	    Your("ancestors are annoyed with you!"); 253. 	    break; 254. 	case 1: 255. 	    pline_The("headstones in the cemetery begin to move!"); 256. 	    break; 257. 	default: 258. 	    pline("Oh my!  Your name appears in the book!"); 259. 	}  260.      }  261.      return; 262. }  263.   264.  STATIC_PTR int 265. learn 266. {  267.  	int i;  268. short booktype; 269.  270.  	if (delay) {	/* not if (delay++), so at end delay == 0 */ 271. 		delay++; 272. 		return(1); /* still busy */ 273. 	}  274.  	exercise(A_WIS, TRUE);		/* you're studying. */ 275.  	booktype = book->otyp; 276. 	if(booktype == SPE_BOOK_OF_THE_DEAD) { 277. 	    deadbook(book); 278. 	    return(0); 279. 	}  280.   281.  	for (i = 0; i < MAXSPELL; i++)  { 282. 		if (spellid(i) == booktype)  { 283. 			if (book->spestudied >= rnd(30 - spellev(i))) { 284. 			    pline("This spellbook is too faint to be read anymore."); 285. 			    book->otyp = booktype = SPE_BLANK_PAPER; 286. 			    makeknown((int)booktype); 287. 			}  288.  			else if (spelluses(i) < 20 - spellev(i)) { 289. 			    Your("knowledge of that spell is keener."); 290. 			    spl_book[i].sp_uses += 10 - spellev(i); 291. 			    book->spestudied++; 292. 			    exercise(A_WIS, TRUE);	/* extra study */ 293. 			} else 294. 			    You("know that spell quite well already."); 295. 			break; 296. 		} else if (spellid(i) == NO_SPELL)  { 297. 			spl_book[i].sp_id = booktype; 298. 			spl_book[i].sp_lev = objects[booktype].oc_level; 299. 			spl_book[i].sp_uses = 30 - spellev(i); 300. 			book->spestudied++; 301. 			You("add the spell to your repertoire."); 302. 			makeknown((int)booktype); 303. 			break; 304. 		}  305.  	}  306.  	if (i == MAXSPELL) impossible("Too many spells memorized!"); 307.  308.  	if (book->cursed) {	/* maybe a demon cursed it */ 309. 		cursed_book(objects[booktype].oc_level); 310. 	}  311.  	check_unpaid(book); 312. 	book = 0; 313. 	return(0); 314. }  315.   316.  int 317. study_book(spellbook) 318. register struct obj *spellbook; 319. {  320.  	register int	 booktype = spellbook->otyp; 321. 	register boolean confused = (Confusion != 0); 322.  323.  	if (delay && spellbook == book) 324. 		You("continue your efforts to memorize the spell."); 325. 	else { 326. 		switch(booktype)  { 327.  328.  	/* blank spellbook */ 329. 		case SPE_BLANK_PAPER: 330. 			pline("This spellbook is all blank."); 331. 			makeknown(SPE_BLANK_PAPER); 332. 			return(1); 333. 	/* level 1 spells */ 334. 		case SPE_HEALING: 335. 		case SPE_DETECT_MONSTERS: 336. 		case SPE_FORCE_BOLT: 337. 		case SPE_LIGHT: 338. 		case SPE_SLEEP: 339. 		case SPE_KNOCK: 340. 	/* level 2 spells */ 341. 		case SPE_MAGIC_MISSILE: 342. 		case SPE_CONFUSE_MONSTER: 343. 		case SPE_SLOW_MONSTER: 344. 		case SPE_CURE_BLINDNESS: 345. 		case SPE_CREATE_MONSTER: 346. 		case SPE_DETECT_FOOD: 347. 		case SPE_WIZARD_LOCK: 348. 			delay = -objects[booktype].oc_delay; 349. 			break; 350. 	/* level 3 spells */ 351. 		case SPE_HASTE_SELF: 352. 		case SPE_CAUSE_FEAR: 353. 		case SPE_CURE_SICKNESS: 354. 		case SPE_DETECT_UNSEEN: 355. 		case SPE_EXTRA_HEALING: 356. 		case SPE_CHARM_MONSTER: 357. 		case SPE_CLAIRVOYANCE: 358. 	/* level 4 spells */ 359. 		case SPE_LEVITATION: 360. 		case SPE_RESTORE_ABILITY: 361. 		case SPE_INVISIBILITY: 362. 		case SPE_FIREBALL: 363. 		case SPE_DETECT_TREASURE: 364. 			delay = -(objects[booktype].oc_level - 1) * objects[booktype].oc_delay; 365. 			break; 366. 	/* level 5 spells */ 367. 		case SPE_REMOVE_CURSE: 368. 		case SPE_MAGIC_MAPPING: 369. 		case SPE_CONE_OF_COLD: 370. 		case SPE_IDENTIFY: 371. 		case SPE_DIG: 372. 	/* level 6 spells */ 373. 		case SPE_TURN_UNDEAD: 374. 		case SPE_POLYMORPH: 375. 		case SPE_CREATE_FAMILIAR: 376. 		case SPE_TELEPORT_AWAY: 377. 			delay = -objects[booktype].oc_level * objects[booktype].oc_delay; 378. 			break; 379. 	/* level 7 spells */ 380. 		case SPE_CANCELLATION: 381. 		case SPE_FINGER_OF_DEATH: 382. 		case SPE_BOOK_OF_THE_DEAD: 383. 			delay = -8 * objects[booktype].oc_delay; 384. 			break; 385. 	/* impossible */ 386. 		default: 387. 			impossible("Unknown spellbook, %d;", booktype); 388. 		return(0); 389. 		}  390.   391.  		/* Books are often wiser than their readers (Rus.) */ 392. 		if(!spellbook->blessed &&  393.  			spellbook->otyp != SPE_BOOK_OF_THE_DEAD &&  394.  			(spellbook->cursed || 395. 			    rn2(20) > (ACURR(A_INT) + 4 + u.ulevel/2  396.  					- 2*objects[booktype].oc_level))) { 397. 			cursed_book(objects[booktype].oc_level); 398. 			nomul(delay);			/* study time */ 399. 			delay = 0; 400. 			if(!rn2(3)) { 401. 				useup(spellbook); 402. 				pline_The("spellbook crumbles to dust!"); 403. 			}  404.  			return(1); 405. 		}  406.  		else if(confused) { 407. 			if(!rn2(3) &&  408.  			    spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { 409. 				useup(spellbook); 410. 				pline("Being confused you have difficulties in controlling your actions."); 411. 				display_nhwindow(WIN_MESSAGE, FALSE); 412. 				You("accidentally tear the spellbook to pieces."); 413. 			}  414.  			else 415. 				You("find yourself reading the first line over and over again."); 416. 			nomul(delay); 417. 			delay = 0; 418. 			return(1); 419. 		}  420.   421.  		You("begin to %s the runes.",  422.  		    spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" :  423.  		    "memorize"); 424. 	}  425.   426.  	book = spellbook; 427. 	set_occupation(learn, "studying", 0); 428. 	return(1); 429. }  430.   431.  /*  432.   * Return TRUE if a spell was picked, with the spell index in the return 433.  * parameter. Otherwise return FALSE. 434.  */  435.  static boolean 436. getspell(spell_no) 437. 	int *spell_no; 438. {  439.  	int nspells, idx; 440. 	char ilet, lets[BUFSZ], qbuf[QBUFSZ]; 441.  442.  	if (spellid(0) == NO_SPELL)  { 443. 	    You("don't know any spells right now."); 444. 	    return FALSE; 445. 	}  446.  	if (flags.menu_style == MENU_TRADITIONAL) { 447. 	    /* we know there is at least 1 known spell */ 448. 	    for (nspells = 1; nspells < MAXSPELL  449.  			    && spellid(nspells) != NO_SPELL; nspells++) 450. 		continue; 451.  452.  	    if (nspells == 1)  Strcpy(lets, "a"); 453. 	    else if (nspells < 27)  Sprintf(lets, "a-%c", 'a' + nspells - 1); 454. 	    else if (nspells == 27)  Sprintf(lets, "a-z A"); 455. 	    else Sprintf(lets, "a-z A-%c", 'A' + nspells - 27); 456.  457.  	    for  { 458. 		Sprintf(qbuf, "Cast which spell? [%s ?]", lets); 459. 		if ((ilet = yn_function(qbuf, (char *)0, '\0')) == '?') 460. 		    break; 461.  462.  		if (index(quitchars, ilet)) 463. 		    return FALSE; 464.  465.  		if (letter(ilet) && ilet != '@') { 466. 		    /* in a-zA-Z, convert back to an index */ 467. 		    if (lowc(ilet) == ilet)	/* lower case */ 468. 			idx = ilet - 'a'; 469. 		    else 470. 			idx = ilet - 'A' + 26; 471.  472.  		    if (idx < nspells) { 473. 			*spell_no = idx; 474. 			return TRUE; 475. 		    }  476.  		}  477.  		You("don't know that spell."); 478. 	    }  479.  	}  480.  	return dospellmenu(PICK_ONE, spell_no); 481. }  482.   483.  int 484. docast 485. {  486.  	int spell_no; 487.  488.  	if (getspell(&spell_no)) 489. 	    return spelleffects(spell_no, FALSE); 490. 	return 0; 491. }  492.   493.  int 494. spelleffects(spell, atme) 495. int spell; 496. boolean atme; 497. {  498.  	int energy, damage, chance; 499. 	boolean confused = (Confusion != 0); 500. 	struct obj *pseudo; 501.  502.  	/* note that trying to cast it decrements the # of uses,    */ 503. 	/* even if the mage does not have enough food/energy to use */ 504. 	/* the spell */ 505. 	switch (spelluses(spell)) { 506. 		case 0: 507. 		    pline ("Curdled magical energy twists through you..."); 508. 		    pline ("...you have overloaded and burned out this spell."); 509. 		    make_confused((long)spellev(spell) * 3, FALSE); 510. 		    return(0); 511. 		case 1: 512. 		case 2: 513. 		case 3: 514. 		    Your("nerves tingle warningly."); 515. 		    break; 516. 		case 4: 517. 		case 5: 518. 		case 6: 519. 		    pline ("This spell is starting to be over-used."); 520. 		    break; 521. 		default: 522. 		    break; 523. 	}  524.  	decrnuses(spell); 525. 	energy = (spellev(spell) * 5);    /* 5 <= energy <= 35 */ 526. 	  527.  	if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) { 528. 		You("are too hungry to cast that spell."); 529. 		return(0); 530. 	} else if (ACURR(A_STR) < 4)  { 531. 		You("lack the strength to cast spells."); 532. 		return(0); 533. 	} else if(check_capacity( 534. 		"Your concentration falters while carrying so much stuff.")) { 535. 	    return (1); 536. 	} else if (!freehand) { 537. 		Your("arms are not free to cast!"); 538. 		return (0); 539. 	}  540.   541.   542.  	if (u.uhave.amulet) { 543. 		You_feel("the amulet draining your energy away."); 544. 		energy += rnd(2*energy); 545. 	}  546.  	if(energy > u.uen)  { 547. 		You("don't have enough energy to cast that spell."); 548. 		return(0); 549. 	} else { 550. 		if (spellid(spell) != SPE_DETECT_FOOD) { 551. 			int hungr = energy * 2; 552.  553.  			/* don't put player (quite) into fainting from 554. 			 * casting a spell, particularly since they might 555. 			 * not even be hungry at the beginning; however, 556. 			 * this is low enough that they must eat before 557. 			 * casting anything else except detect food 558. 			 */  559.  			if (hungr > u.uhunger-3) 560. 				hungr = u.uhunger-3; 561. 			morehungry(hungr); 562. 		}  563.  	}  564.   565.  	/* u.uen _will_ reduce once here reached */ 566.  567.  	flags.botl = 1; 568.  569.  	chance = percent_success(spell); 570.  571.  	if (confused || (rnd(100) > chance)) { 572. 		You("fail to cast the spell correctly."); 573. 		u.uen -= energy / 2; 574. 		return(1); 575. 	}  576.   577.  	u.uen -= energy; 578. 	exercise(A_WIS, TRUE); 579. /*	pseudo is a temporary "false" object containing the spell stats. */ 580.  	pseudo = mksobj(spellid(spell), FALSE, FALSE); 581. 	pseudo->blessed = pseudo->cursed = 0; 582. 	pseudo->quan = 20L;			/* do not let useup get it */ 583. 	switch(pseudo->otyp)  { 584.  585.  /* These spells are all duplicates of wand effects */ 586. 	case SPE_FORCE_BOLT: 587. 	case SPE_SLEEP: 588. 	case SPE_MAGIC_MISSILE: 589. 	case SPE_KNOCK: 590. 	case SPE_SLOW_MONSTER: 591. 	case SPE_WIZARD_LOCK: 592. 	case SPE_FIREBALL: 593. 	case SPE_CONE_OF_COLD: 594. 	case SPE_DIG: 595. 	case SPE_TURN_UNDEAD: 596. 	case SPE_POLYMORPH: 597. 	case SPE_TELEPORT_AWAY: 598. 	case SPE_CANCELLATION: 599. 	case SPE_FINGER_OF_DEATH: 600. 	case SPE_LIGHT: 601. 	case SPE_DETECT_UNSEEN: 602. 	case SPE_HEALING: 603. 	case SPE_EXTRA_HEALING: 604. 		if (!(objects[pseudo->otyp].oc_dir == NODIR)) { 605. 			if (atme) u.dx = u.dy = u.dz = 0; 606. 			else (void) getdir((char *)0); 607. 			if(!u.dx && !u.dy && !u.dz) { 608. 			    if ((damage = zapyourself(pseudo, TRUE)) != 0) 609. 				losehp(damage,  610.  				     self_pronoun("zapped %sself with a spell", 611. 						  "him"),  612.  				     NO_KILLER_PREFIX); 613. 			} else weffects(pseudo); 614. 		} else weffects(pseudo); 615. 		break; 616. /* These are all duplicates of scroll effects */ 617. 	case SPE_CONFUSE_MONSTER: 618. 	case SPE_DETECT_FOOD: 619. 	case SPE_CAUSE_FEAR: 620. 	case SPE_CHARM_MONSTER: 621. 	case SPE_REMOVE_CURSE: 622. 	case SPE_MAGIC_MAPPING: 623. 	case SPE_CREATE_MONSTER: 624. 	case SPE_IDENTIFY: 625. 		(void) seffects(pseudo); 626. 		break; 627. 	case SPE_HASTE_SELF: 628. 	case SPE_DETECT_TREASURE: 629. 	case SPE_DETECT_MONSTERS: 630. 	case SPE_LEVITATION: 631. 	case SPE_RESTORE_ABILITY: 632. 	case SPE_INVISIBILITY: 633. 		(void) peffects(pseudo); 634. 		break; 635. 	case SPE_CURE_BLINDNESS: 636. 		healup(0, 0, FALSE, TRUE); 637. 		break; 638. 	case SPE_CURE_SICKNESS: 639. 		if (Sick) You("are no longer ill."); 640. 		healup(0, 0, TRUE, FALSE); 641. 		break; 642. 	case SPE_CREATE_FAMILIAR: 643. 		make_familiar((struct obj *)0, u.ux, u.uy); 644. 		break; 645. 	case SPE_CLAIRVOYANCE: 646. 		if (!(HClairvoyant & I_BLOCKED)) 647. 		    do_vicinity_map; 648. 		/* at present, only one thing blocks clairvoyance */ 649. 		else if (uarmh && uarmh->otyp == CORNUTHAUM) 650. 		    You("sense a pointy hat on top of your %s.",  651.  			body_part(HEAD)); 652. 		break; 653. 	default: 654. 		impossible("Unknown spell %d attempted.", spell); 655. 		obfree(pseudo, (struct obj *)0); 656. 		return(0); 657. 	}  658.  	obfree(pseudo, (struct obj *)0);	/* now, get rid of it */ 659. 	return(1); 660. }  661.   662.  void 663. losespells 664. {  665.  	boolean confused = (Confusion != 0); 666. 	int  n, nzap, i;  667. 668. 	book = 0; 669. 	for (n = 0; n < MAXSPELL && spellid(n) != NO_SPELL; n++) 670. 		continue; 671. 	if (n) { 672. 		nzap = rnd(n) + confused ? 1 : 0; 673.  		if (nzap > n) nzap = n;  674. for (i = n - nzap; i < n; i++) { 675. 		    spellid(i) = NO_SPELL; 676. 		    exercise(A_WIS, FALSE);	/* ouch! */ 677.  		}  678.  	}  679.  }  680.   681.  int 682. dovspell 683. {  684.  	int dummy; 685.  686.  	if (spellid(0) == NO_SPELL) 687. 	    You("don't know any spells right now."); 688. 	else 689. 	    (void) dospellmenu(PICK_NONE, &dummy); 690. 	return 0; 691. }  692.   693.  static boolean 694. dospellmenu(how, spell_no) 695. 	int how; 696. 	int *spell_no; 697. {  698.  	winid tmpwin; 699. 	int i, n;  700. char buf[BUFSZ]; 701. 	menu_item *selected; 702. 	anything any; 703.  704.  	tmpwin = create_nhwindow(NHW_MENU); 705. 	start_menu(tmpwin); 706. 	any.a_void = 0;		/* zero out all bits */ 707.  708.  	/*  709.  	 * The correct spacing of the columns depends on the 710. 	 * following that (1) the font is monospaced and (2) 711. 	 * that selection letters are pre-pended to the given 712. 	 * string and are of the form "a - ". 713. 	 *  714.  	 * To do it right would require that we implement columns 715. 	 * in the window-ports (say via a tab character). 716. 	 */  717.  	Sprintf(buf, "%-20s     Level Fail", "Name"); 718. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, buf, MENU_UNSELECTED); 719. 	for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) { 720. 		Sprintf(buf, "%-20s  %2d%s  %3d%%",  721.  			spellname(i), spellev(i),  722.  			spelluses(i) ? " " : "*", 100 - percent_success(i)); 723.  724.  		any.a_int = i+1;	/* must be non-zero */ 725. 		add_menu(tmpwin, NO_GLYPH, &any,  726.  			 spellet(i), 0,buf, MENU_UNSELECTED); 727. 	      }  728.  	end_menu(tmpwin, how == PICK_ONE ? "Choose a spell" :  729.  					   "Currently known spells"); 730.  731.  	n = select_menu(tmpwin, how, &selected); 732. 	destroy_nhwindow(tmpwin); 733. 	if (n > 0) { 734. 		*spell_no = selected[0].item.a_int - 1; 735. 		free((genericptr_t)selected); 736. 		return TRUE; 737. 	}  738.  	return FALSE; 739. }  740.   741.  static int 742. percent_success(spell) 743. int spell; 744. {  745.  	/* Intrinsic and learned ability are combined to calculate 746. 	 * the probability of player's success at cast a given spell. 747. 	 */  748.   749.  	int i, chance, splcaster, special, statused; 750. 	int difficulty; 751.  752.  	/* Calculate intrinsic ability (splcaster) */ 753.  754.  	for (i = 0; cl_sptmp[i].class; i++) 755. 		if (cl_sptmp[i].class == pl_character[0]) break; 756.  757.  	splcaster = cl_sptmp[i].splcaster; 758. 	special = cl_sptmp[i].special; 759.  760.  	if (uarm && is_metallic(uarm)) splcaster += cl_sptmp[i].uarmbon; 761. 	if (uarms) splcaster += cl_sptmp[i].uarmsbon; 762.  763.  	if (uarmh && is_metallic(uarmh) && uarmh->otyp != HELM_OF_BRILLIANCE) 764. 		splcaster += uarmhbon; 765. 	if (uarmg && is_metallic(uarmg)) splcaster += uarmgbon; 766. 	if (uarmf && is_metallic(uarmf)) splcaster += uarmfbon; 767.  768.  	if (spellid(spell) == cl_sptmp[i].specspel) 769. 		splcaster += cl_sptmp[i].specbon; 770.  771.  	statused = ACURR(cl_sptmp[i].statused); 772.  773.  	/* `healing spell' bonus */ 774. 	if (spellid(spell) == SPE_HEALING ||  775.  	    spellid(spell) == SPE_EXTRA_HEALING ||  776.  	    spellid(spell) == SPE_CURE_BLINDNESS ||  777.  	    spellid(spell) == SPE_CURE_SICKNESS ||  778.  	    spellid(spell) == SPE_RESTORE_ABILITY ||  779.  	    spellid(spell) == SPE_REMOVE_CURSE) splcaster += special; 780.  781.  	if (splcaster > 20) splcaster = 20; 782.  783.  	/* Calculate learned ability */ 784.  785.  	/* Players basic likelihood of being able to cast any spell 786. 	 * is based of their `magic' statistic. (Int or Wis) 787. 	 */  788.  	chance = 11 * statused / 2; 789.  790.  	/* High level spells are harder. Easier for higher level casters */ 791. 	difficulty = (spellev(spell) - 1) * 4 - (u.ulevel - 1); 792.  793.  	if (difficulty > 0) { 794. 		/* Player is too low level. Exponential chance reduction */ 795. 		chance -= 7 * difficulty * difficulty; 796. 	} else { 797. 		/* Player is above level. Learning continues, but the 798. 		 * law of diminishing returns sets in quickly for 799. 		 * low-level spells. That is, a player quickly gains 800. 		 * no advantage for raising level. 801. 		 */  802.  		int learning = 15 * -difficulty / spellev(spell); 803. 		chance += learning > 20 ? 20 : learning; 804. 	}  805.   806.  	/* Clamp the chance: >18 stat and advanced learning only help 807. 	 * to a limit, while chances below "hopeless" only raise the 808. 	 * specter of overflowing 16-bit ints (and permit wearing a  809.  	 * shield to raise the chances :-). 810. 	 */  811.  	if (chance < 0) chance = 0; 812. 	if (chance > 120) chance = 120; 813.  814.  	/* Wearing anything but a light shield makes it very awkward 815. 	 * to cast a spell. The penalty is not quite so bad for the 816. 	 * player's class-specific spell. 817. 	 */  818.  	if (uarms && weight(uarms) > (int) objects[SMALL_SHIELD].oc_weight) { 819. 		if (spellid(spell) == cl_sptmp[i].specspel) { 820. 			chance /= 2; 821. 		} else { 822. 			chance /= 4; 823. 		}  824.  	}  825.   826.  	/* Finally, chance (based on player intell/wisdom and level) is  827. * combined with ability (based on player intrinsics and 828.  	 * encumberances). No matter how intelligent/wise and advanced 829. 	 * a player is, intrinsics and encumberance can prevent casting; 830. 	 * and no matter how able, learning is always required. 831. 	 */  832.  	chance = chance * (20-splcaster) / 15 - splcaster; 833.  834.  	/* Clamp to percentile */ 835. 	if (chance > 100) chance = 100; 836. 	if (chance < 0) chance = 0; 837.  838.  	return chance; 839. }  840.   841.  /*spell.c*/