Source:SLASH'EM 0.0.7E7F2/spell.c

Below is the full text to spell.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/spell.c#line123 ]], for example.

The latest source code for vanilla NetHack is at Source code.

1.   /*	SCCS Id: @(#)spell.c	3.4	2003/01/17	*/ 2.   /*	Copyright (c) M. Stephenson 1988			  */ 3.   /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6.    #include "edog.h"  7. 8.   /* Are now ints */ 9.   static NEARDATA int delay;            /* moves left for this spell */ 10.  static NEARDATA int end_delay;        /* when to stop studying */ 11.  static NEARDATA struct obj *book;	/* last/current book being xscribed */ 12.   13.   /* spellmenu arguments; 0 thru n-1 used as spl_book[] index when swapping */ 14.  #define SPELLMENU_CAST (-2) 15.  #define SPELLMENU_VIEW (-1) 16.   17.   #define KEEN 		10000	/* memory increase reading the book */ 18.  #define CAST_BOOST 	  500	/* memory increase for successful casting */ 19.  #define MAX_KNOW 	70000	/* Absolute Max timeout */ 20.  #define MAX_CAN_STUDY 	60000	/* Can study while timeout is less than */ 21.   22.   #define MAX_STUDY_TIME 	  300	/* Max time for one study session */ 23.  #define MAX_SPELL_STUDY    30	/* Uses before spellbook crumbles */ 24.   25.   #define spellknow(spell)	spl_book[spell].sp_know 26.   27.   #define incrnknow(spell)        spl_book[spell].sp_know = ((spl_book[spell].sp_know < 1) ? KEEN \  28.   				 : ((spl_book[spell].sp_know + KEEN) > MAX_KNOW) ? MAX_KNOW \  29.   				 : spl_book[spell].sp_know + KEEN) 30.  #define boostknow(spell,boost)  spl_book[spell].sp_know = ((spl_book[spell].sp_know + boost > MAX_KNOW) ? MAX_KNOW \  31.   				 : spl_book[spell].sp_know + boost) 32.   33.   #define spellev(spell)		spl_book[spell].sp_lev 34.  #define spellid(spell)          spl_book[spell].sp_id 35.  #define spellname(spell)	OBJ_NAME(objects[spellid(spell)]) 36.  #define spellet(spell)	\ 37.  	((char)((spell < 26) ? ('a' + spell) : \ 38.  	        (spell < 52) ? ('A' + spell - 26) : \ 39.  		(spell < 62) ? ('0' + spell - 52) : 0 )) 40.   41.   STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P)); 42.  STATIC_DCL boolean FDECL(cursed_book, (struct obj *bp)); 43.  STATIC_DCL boolean FDECL(confused_book, (struct obj *)); 44.  STATIC_DCL void FDECL(deadbook, (struct obj *)); 45.  STATIC_PTR int NDECL(learn); 46.  STATIC_DCL void NDECL(do_reset_learn); 47.  STATIC_DCL boolean FDECL(getspell, (int *)); 48.  STATIC_DCL boolean FDECL(dospellmenu, (const char *,int,int *)); 49.  STATIC_DCL int FDECL(percent_success, (int)); 50.  STATIC_DCL void NDECL(cast_protection); 51.  STATIC_DCL void FDECL(spell_backfire, (int)); 52.  STATIC_DCL const char *FDECL(spelltypemnemonic, (int)); 53.  STATIC_DCL int FDECL(isqrt, (int)); 54.   55.   /* The roles[] table lists the role-specific values for tuning 56.   * percent_success. 57.   *  58.    * Reasoning: 59.   *   splcaster, special: 60.   *	Arc are aware of magic through historical research 61.   *	Bar abhor magic (Conan finds it "interferes with his animal instincts") 62.   *	Cav are ignorant to magic 63.   *	Hea are very aware of healing magic through medical research 64.   *	Kni are moderately aware of healing from Paladin training 65.   *	Mon use magic to attack and defend in lieu of weapons and armor 66.   *	Pri are very aware of healing magic through theological research 67.   *	Ran avoid magic, preferring to fight unseen and unheard 68.   *	Rog are moderately aware of magic through trickery 69.   *	Sam have limited magical awareness, prefering meditation to conjuring 70.   *	Tou are aware of magic from all the great films they have seen 71.   *	Val have limited magical awareness, prefering fighting 72.   *	Wiz are trained mages 73.   *  74.    *	The arms penalty is lessened for trained fighters Bar, Kni, Ran, 75.   *	Sam, Val - 76.   *	the penalty is its metal interference, not encumbrance. 77.   *	The `spelspec' is a single spell which is fundamentally easier 78.   *	 for that role to cast. 79.   *  80.    *  spelspec, spelsbon: 81.   *	Arc map masters (SPE_MAGIC_MAPPING) 82.   *	Bar fugue/berserker (SPE_HASTE_SELF) 83.   *	Cav born to dig (SPE_DIG) 84.   *	Hea to heal (SPE_CURE_SICKNESS) 85.   *	Kni to turn back evil (SPE_TURN_UNDEAD) 86.   *	Mon to preserve their abilities (SPE_RESTORE_ABILITY) 87.   *	Pri to bless (SPE_REMOVE_CURSE) 88.   *	Ran to hide (SPE_INVISIBILITY) 89.   *	Rog to find loot (SPE_DETECT_TREASURE) 90.   *	Sam to be At One (SPE_CLAIRVOYANCE) 91.   *	Tou to smile (SPE_CHARM_MONSTER) 92.   *	Val control lightning (SPE_LIGHTNING) 93.   *	Wiz all really, but SPE_MAGIC_MISSILE is their party trick 94.   *	Yeo guard doors (SPE_KNOCK) 95.   *  96.    *	See percent_success below for more comments. 97.   *  98.    *  uarmbon, uarmsbon, uarmhbon, uarmgbon, uarmfbon: 99.   *	Fighters find body armour & shield a little less limiting. 100.  *	Headgear, Gauntlets and Footwear are not role-specific (but  101.   *	still have an effect, except helm of brilliance, which is designed  102.   *	to permit magic-use). 103.  */  104.   105.  #define uarmhbon 4 /* Metal helmets interfere with the mind */ 106. #define uarmgbon 6 /* Casting channels through the hands */ 107. #define uarmfbon 2 /* All metal interferes to some degree */ 108.  109.  /* since the spellbook itself doesn't blow up, don't say just "explodes" */ 110. static const char explodes[] = "radiates explosive energy"; 111.  112.  /* convert an alnum into a number in the range 0..61, or -1 if not an alnum */ 113. STATIC_OVL int 114. spell_let_to_idx(ilet) 115. char ilet; 116. {  117.      int indx; 118.  119.      indx = ilet - 'a'; 120.     if (indx >= 0 && indx < 26) return indx; 121.     indx = ilet - 'A'; 122.     if (indx >= 0 && indx < 26) return indx + 26; 123.     indx = ilet - '0'; 124.     if (indx >= 0 && indx < 10) return indx + 52; 125.     return -1; 126. }  127.   128.  /* TRUE: book should be destroyed by caller */ 129. STATIC_OVL boolean 130. cursed_book(bp) 131. 	struct obj *bp; 132. {  133.  	int lev = objects[bp->otyp].oc_level; 134.  135.  	switch(rn2(lev)) { 136. 	case 0: 137. 		You_feel("a wrenching sensation."); 138. 		tele;		/* teleport him */ 139. 		break; 140. 	case 1: 141. 		You_feel("threatened."); 142. 		aggravate; 143. 		break; 144. 	case 2: 145. 		/* [Tom] lowered this (used to be 100,250) */ 146. 		make_blinded(Blinded + rn1(50,25),TRUE); 147. 		break; 148. 	case 3: 149. 		take_gold; 150. 		break; 151. 	case 4: 152. 		pline("These runes were just too much to comprehend."); 153. 		make_confused(HConfusion + rn1(7,16),FALSE); 154. 		break; 155. 	case 5: 156. 		pline_The("book was coated with contact poison!"); 157. 		if (uarmg) { 158. 		    if (uarmg->oerodeproof || !is_corrodeable(uarmg)) { 159. 			Your("gloves seem unaffected."); 160. 		    } else if (uarmg->oeroded2 < MAX_ERODE) { 161. 			if (uarmg->greased) { 162. 			    grease_protect(uarmg, "gloves", &youmonst); 163. 			} else { 164. 			    Your("gloves corrode%s!",  165.  				 uarmg->oeroded2+1 == MAX_ERODE ?  166.  				 " completely" : uarmg->oeroded2 ?  167.  				 " further" : ""); 168. 			    uarmg->oeroded2++; 169. 			}  170.  		    } else 171. 			Your("gloves %s completely corroded.",  172.  			     Blind ? "feel" : "look"); 173. 		    break; 174. 		}  175.  		/* temp disable in_use; death should not destroy the book */ 176. 		bp->in_use = FALSE; 177. 		losestr(Poison_resistance ? rn1(2,1) : rn1(4,3)); 178. 		losehp(rnd(Poison_resistance ? 6 : 10), 179.  		       "contact-poisoned spellbook", KILLED_BY_AN); 180. 		bp->in_use = TRUE; 181. 		break; 182. 	case 6: 183. 		if(Antimagic) { 184. 		    shieldeff(u.ux, u.uy); 185. 		    pline_The("book %s, but you are unharmed!", explodes); 186. 		} else { 187. 		    pline("As you read the book, it %s in your %s!",  188.  			  explodes, body_part(FACE)); 189. 		    losehp(2*rnd(10)+5, "exploding rune", KILLED_BY_AN); 190. 		}  191.  		return TRUE; 192. 	default: 193. 		rndcurse; 194. 		break; 195. 	}  196.  	return FALSE; 197. }  198.   199.  /* study while confused: returns TRUE if the book is destroyed */ 200. STATIC_OVL boolean 201. confused_book(spellbook) 202. struct obj *spellbook; 203. {  204.  	boolean gone = FALSE; 205.  206.  	if (!rn2(3) && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { 207. 	    spellbook->in_use = TRUE;	/* in case called from learn */ 208. 	    pline(  209.  	"Being confused you have difficulties in controlling your actions."); 210. 	    display_nhwindow(WIN_MESSAGE, FALSE); 211. 	    You("accidentally tear the spellbook to pieces."); 212. 	    if (!objects[spellbook->otyp].oc_name_known &&  213.  		!objects[spellbook->otyp].oc_uname) 214. 		docall(spellbook); 215. 	    if (carried(spellbook)) useup(spellbook); 216. 	    else useupf(spellbook, 1L); 217. 	    gone = TRUE; 218. 	} else { 219. 	    You("find yourself reading the %s line over and over again.",  220.  		spellbook == book ? "next" : "first"); 221. 	}  222.  	return gone; 223. }  224.   225.  /* special effects for The Book of the Dead */ 226. STATIC_OVL void 227. deadbook(book2) 228. struct obj *book2; 229. {  230.      struct monst *mtmp, *mtmp2; 231.     coord mm; 232.  233.      You("turn the pages of the Book of the Dead..."); 234.     makeknown(SPE_BOOK_OF_THE_DEAD); 235.     /* KMH -- Need ->known to avoid "_a_ Book of the Dead" */ 236.     book2->known = 1; 237.     if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { 238. 	register struct obj *otmp; 239. 	register boolean arti1_primed = FALSE, arti2_primed = FALSE, 240. 			 arti_cursed = FALSE; 241.  242.  	if(book2->cursed) { 243. 	    pline_The("runes appear scrambled.  You can't read them!"); 244. 	    return; 245. 	}  246.   247.  	if(!u.uhave.bell || !u.uhave.menorah) { 248. 	    pline("A chill runs down your %s.", body_part(SPINE)); 249. 	    if(!u.uhave.bell) You_hear("a faint chime..."); 250. 	    if(!u.uhave.menorah) pline("Vlad's doppelganger is amused."); 251. 	    return; 252. 	}  253.   254.  	for(otmp = invent; otmp; otmp = otmp->nobj) { 255. 	    if(otmp->otyp == CANDELABRUM_OF_INVOCATION &&  256.  	       otmp->spe == 7 && otmp->lamplit) { 257. 		if(!otmp->cursed) arti1_primed = TRUE; 258. 		else arti_cursed = TRUE; 259. 	    }  260.  	    if(otmp->otyp == BELL_OF_OPENING &&  261.  	       (moves - otmp->age) < 5L) { /* you rang it recently */ 262. 		if(!otmp->cursed) arti2_primed = TRUE; 263. 		else arti_cursed = TRUE; 264. 	    }  265.  	}  266.   267.  	if(arti_cursed) { 268. 	    pline_The("invocation fails!"); 269. 	    pline("At least one of your artifacts is cursed..."); 270. 	} else if(arti1_primed && arti2_primed) { 271. 	    unsigned soon = (unsigned) d(2,6);	/* time til next intervene */ 272.  273.  	    /* successful invocation */ 274. 	    mkinvokearea; 275. 	    u.uevent.invoked = 1; 276. 	    /* in case you haven't killed the Wizard yet, behave as if  277. you just did */ 278. 	    u.uevent.udemigod = 1;	/* wizdead */ 279. 	    if (!u.udg_cnt || u.udg_cnt > soon) u.udg_cnt = soon; 280. 	} else {	/* at least one artifact not prepared properly */ 281. 	    You("have a feeling that %s is amiss...", something); 282. 	    goto raise_dead; 283. 	}  284.  	return; 285.     }  286.   287.      /* when not an invocation situation */ 288.     if (book2->cursed) { 289. raise_dead: 290.  291.  	You("raised the dead!"); 292. 	/* first maybe place a dangerous adversary */ 293. 	if (!rn2(3) && ((mtmp = makemon(&mons[PM_MASTER_LICH], 294. 					u.ux, u.uy, NO_MINVENT)) != 0 || 295. 			(mtmp = makemon(&mons[PM_NALFESHNEE], 296. 					u.ux, u.uy, NO_MINVENT)) != 0)) { 297. 	    mtmp->mpeaceful = 0; 298. 	    set_malign(mtmp); 299. 	}  300.  	/* next handle the affect on things you're carrying */ 301. 	(void) unturn_dead(&youmonst); 302. 	/* last place some monsters around you */ 303. 	mm.x = u.ux; 304. 	mm.y = u.uy; 305. 	mkundead(&mm, TRUE, NO_MINVENT); 306.     } else if(book2->blessed) { 307. 	for(mtmp = fmon; mtmp; mtmp = mtmp2) { 308. 	    mtmp2 = mtmp->nmon;		/* tamedog changes chain */ 309. 	    if (DEADMONSTER(mtmp)) continue; 310.  311.  	    if (is_undead(mtmp->data) && cansee(mtmp->mx, mtmp->my)) { 312. 		mtmp->mpeaceful = TRUE; 313. 		if(sgn(mtmp->data->maligntyp) == sgn(u.ualign.type)  314.  		   && distu(mtmp->mx, mtmp->my) < 4) 315. 		    if (mtmp->mtame) { 316. 			if (mtmp->mtame < 20) 317. 			    mtmp->mtame++; 318. 		    } else 319. 			(void) tamedog(mtmp, (struct obj *)0); 320. 		else monflee(mtmp, 0, FALSE, TRUE); 321. 	    }  322.  	}  323.      } else { 324. 	switch(rn2(3)) { 325. 	case 0: 326. 	    Your("ancestors are annoyed with you!"); 327. 	    break; 328. 	case 1: 329. 	    pline_The("headstones in the cemetery begin to move!"); 330. 	    break; 331. 	default: 332. 	    pline("Oh my!  Your name appears in the book!"); 333. 	}  334.      }  335.      return; 336. }  337.   338.  STATIC_PTR int 339. learn 340. {  341.  	int i;  342. short booktype; 343. 	char splname[BUFSZ]; 344. 	boolean costly = TRUE; 345.  346.  	if (!book || !(carried(book) || 347. 		(book->where == OBJ_FLOOR &&  348.  			book->ox == u.ux && book->oy == u.uy))) { 349. 	    /* maybe it was stolen or polymorphed? */ 350.  	    do_reset_learn; 351. 	    return(0); 352. 	}  353.  	/* JDS: lenses give 50% faster reading; 33% smaller read time */ 354. 	if (delay < end_delay && ublindf && ublindf->otyp == LENSES && rn2(2)) 355. 	    delay++; 356. 	if (Confusion) {		/* became confused while learning */ 357. 	    (void) confused_book(book); 358. 	    book = 0;			/* no longer studying */ 359. 	    nomul(delay - end_delay);	/* remaining delay is uninterrupted */ 360. 	    delay = end_delay; 361. 	    return(0); 362. 	}  363.  	if (delay < end_delay) {    /* not if (delay++), so at end delay == 0 */ 364. 	    delay++; 365. 	    return(1); /* still busy */ 366. 	}  367.  	exercise(A_WIS, TRUE);		/* you're studying. */ 368.  	booktype = book->otyp; 369. 	if(booktype == SPE_BOOK_OF_THE_DEAD) { 370. 	    deadbook(book); 371. 	    return(0); 372. 	}  373.   374.  	Sprintf(splname, objects[booktype].oc_name_known ?  375.  			"\"%s\"" : "the \"%s\" spell",  376.  		OBJ_NAME(objects[booktype])); 377. 	for (i = 0; i < MAXSPELL; i++)  { 378. 		if (spellid(i) == booktype)  { 379. 			if (book->spestudied > MAX_SPELL_STUDY) { 380. 			    pline("This spellbook is too faint to be read anymore."); 381. 			    book->otyp = booktype = SPE_BLANK_PAPER; 382. 			} else if (spellknow(i) <= MAX_CAN_STUDY) { 383. 			    Your("knowledge of that spell is keener."); 384. 			    incrnknow(i); 385. 			    book->spestudied++; 386. 			    if (end_delay) { 387. 			    	boostknow(i,  388.  				  end_delay * (book->spe > 0 ? 20 : 10)); 389.  				use_skill(spell_skilltype(book->otyp),  390.  				  end_delay / (book->spe > 0 ? 10 : 20)); 391.  			    }  392.  			    exercise(A_WIS, TRUE);      /* extra study */ 393. 			} else { /* MAX_CAN_STUDY < spellknow(i) <= MAX_SPELL_STUDY */ 394. 			    You("know %s quite well already.", splname); 395. 			    costly = FALSE; 396. 			}  397.  			/* make book become known even when spell is already 398. 			   known, in case amnesia made you forget the book */ 399. 			makeknown((int)booktype); 400. 			break; 401. 		} else if (spellid(i) == NO_SPELL)  { 402. 			spl_book[i].sp_id = booktype; 403. 			spl_book[i].sp_lev = objects[booktype].oc_level; 404. 			incrnknow(i); 405. 			book->spestudied++; 406. 			You("have keen knowledge of the spell."); 407. 			You(i > 0 ? "add %s to your repertoire." : "learn %s.",  408.  			    splname); 409. 			makeknown((int)booktype); 410. 			break; 411. 		}  412.  	}  413.  	if (i == MAXSPELL) impossible("Too many spells memorized!"); 414.  415.  	if (book->cursed) {	/* maybe a demon cursed it */ 416. 	    if (cursed_book(book)) { 417. 		if (carried(book)) useup(book); 418. 		else useupf(book, 1L); 419. 		book = 0; 420. 		return 0; 421. 	    }  422.  	}  423.  	if (costly) check_unpaid(book); 424. 	book = 0; 425. 	return(0); 426. }  427.   428.  int 429. study_book(spellbook) 430. register struct obj *spellbook; 431. {  432.  	register int	 booktype = spellbook->otyp; 433. 	register boolean confused = (Confusion != 0); 434. 	boolean too_hard = FALSE; 435.  436.  	if (delay && !confused && spellbook == book &&  437.  		    /* handle the sequence: start reading, get interrupted,  438.  		       have book become erased somehow, resume reading it */  439.  		    booktype != SPE_BLANK_PAPER) { 440. 		You("continue your efforts to memorize the spell."); 441. 	} else { 442. 		/* KMH -- Simplified this code */ 443. 		if (booktype == SPE_BLANK_PAPER) { 444. 			pline("This spellbook is all blank."); 445. 			makeknown(booktype); 446. 			return(1); 447. 		}  448.  		if (spellbook->spe && confused) { 449. 		    check_unpaid_usage(spellbook, TRUE); 450. 		    consume_obj_charge(spellbook, FALSE); 451. 		    pline_The("words on the page seem to glow faintly purple."); 452. 		    You_cant("quite make them out."); 453. 		    return 1; 454. 		}  455.   456.  		switch (objects[booktype].oc_level) { 457. 		 case 1: 458. 		 case 2: 459. 			delay = -objects[booktype].oc_delay; 460. 			break; 461. 		 case 3: 462. 		 case 4: 463. 			delay = -(objects[booktype].oc_level - 1) * 464. 				objects[booktype].oc_delay; 465. 			break; 466. 		 case 5: 467. 		 case 6: 468. 			delay = -objects[booktype].oc_level * 469. 				objects[booktype].oc_delay; 470. 			break; 471. 		 case 7: 472. 			delay = -8 * objects[booktype].oc_delay; 473. 			break; 474. 		 default: 475. 			impossible("Unknown spellbook level %d, book %d;",  476.  				objects[booktype].oc_level, booktype); 477. 			return 0; 478. 		}  479.   480.  		/* Books are often wiser than their readers (Rus.) */ 481. 		spellbook->in_use = TRUE; 482. 		if (!spellbook->blessed &&  483.  		    spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { 484. 		    if (spellbook->cursed) { 485. 			too_hard = TRUE; 486. 		    } else { 487. 			/* uncursed - chance to fail */ 488. 			int read_ability = ACURR(A_INT) + 4 + u.ulevel/2 489. 			    - 2*objects[booktype].oc_level 490. 			    + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0); 491. 			/* only wizards know if a spell is too difficult */ 492. 			if (Role_if(PM_WIZARD) && read_ability < 20 &&  493.  			    !confused && !spellbook->spe) { 494. 			    char qbuf[QBUFSZ]; 495. 			    Sprintf(qbuf,  496.  		      "This spellbook is %sdifficult to comprehend. Continue?",  497.  				    (read_ability < 12 ? "very " : "")); 498. 			    if (yn(qbuf) != 'y') { 499. 				spellbook->in_use = FALSE; 500. 				return(1); 501. 			    }  502.  			}  503.  			/* its up to random luck now */ 504. 			if (rnd(20) > read_ability) { 505. 			    too_hard = TRUE; 506. 			}  507.  		    }  508.  		}  509.   510.  		if (too_hard && (spellbook->cursed || !spellbook->spe)) { 511. 		    boolean gone = cursed_book(spellbook); 512.  513.  		    nomul(delay);			/* study time */ 514. 		    delay = 0; 515. 		    if(gone || !rn2(3)) { 516. 			if (!gone) pline_The("spellbook crumbles to dust!"); 517. 			if (!objects[spellbook->otyp].oc_name_known &&  518.  				!objects[spellbook->otyp].oc_uname) 519. 			    docall(spellbook); 520. 				if (carried(spellbook)) useup(spellbook); 521. 				else useupf(spellbook, 1L); 522. 		    } else 523. 			spellbook->in_use = FALSE; 524. 		    return(1); 525. 		} else if (confused) { 526. 		    if (!confused_book(spellbook)) { 527. 			spellbook->in_use = FALSE; 528. 		    }  529.  		    nomul(delay); 530. 		    delay = 0; 531. 		    return(1); 532. 		}  533.  		spellbook->in_use = FALSE; 534.  535.  		/* The glowing words make studying easier */ 536. 		if (spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { 537. 		    delay *= 2; 538. 		    if (spellbook->spe) { 539. 			check_unpaid_usage(spellbook, TRUE); 540. 			consume_obj_charge(spellbook, FALSE); 541. 			pline_The("words on the page seem to glow faintly."); 542. 			if (!too_hard) 543. 			    delay /= 3; 544. 		    }  545.  		}  546.  		end_delay = 0;  /* Changed if multi != 0 */ 547.  548.  #ifdef DEBUG 549. 		pline("Delay: %i", delay); 550. #endif 551. 		if (multi) { 552. 			/* Count == practice reading :) */  553.  	        	char qbuf[QBUFSZ];  554.  	        	  555.  	        	if (multi + 1 > MAX_STUDY_TIME) multi = MAX_STUDY_TIME - 1;  556.  	        	Sprintf(qbuf, "Study for at least %i turns?", (multi+1));  557.  			if (ynq(qbuf) != 'y') {  558.  				multi = 0;  559.  				return(1);  560.  			}  561.  			if ((--multi) > (-delay)) end_delay = multi + delay;  562.  			multi = 0;  563.  #ifdef DEBUG  564.  			pline("end_delay: %i", end_delay);  565.  #endif  566.  		}  567.   568.  		You("begin to %s the runes.", 569. 		    spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" : 570. 		    "memorize");  571.  	}  572.   573.  	book = spellbook;  574.  	set_occupation(learn, "studying", 0);  575.  	return(1);  576.  }  577.   578.  /* a spellbook has been destroyed or the character has changed levels;  579.     the stored address for the current book is no longer valid */  580.  void  581.  book_disappears(obj)  582.  struct obj *obj;  583.  {  584.  	if (obj == book) book = (struct obj *)0;  585.  }  586.   587.  /* renaming an object usually results in it having a different address;  588.     so the sequence start reading, get interrupted, name the book, resume  589.     reading would read the "new" book from scratch */  590.  void  591.  book_substitution(old_obj, new_obj)  592.  struct obj *old_obj, *new_obj;  593.  {  594.  	if (old_obj == book) book = new_obj;  595.  }  596.   597.  static void  598.  do_reset_learn  599.  {  600.  	stop_occupation;  601. } 602.   603.  /* called from moveloop */ 604. void 605. age_spells 606. {  607.  	int i;  608. /* 609.  	 * The time relative to the hero (a pass through move  610.  	 * loop) causes all spell knowledge to be decremented. 611. 	 * The hero's speed, rest status, conscious status etc. 612. 	 * does not alter the loss of memory. 613. 	 */  614.  	for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) 615. 	    if (spellknow(i)) 616. 		decrnknow(i); 617. 	return; 618. }  619.   620.  /*  621.   * Return TRUE if a spell was picked, with the spell index in the return 622.  * parameter. Otherwise return FALSE. 623.  */  624.  STATIC_OVL boolean 625. getspell(spell_no) 626. 	int *spell_no; 627. {  628.  	int nspells, idx; 629. 	char ilet, lets[BUFSZ], qbuf[QBUFSZ]; 630.  631.  	if (spellid(0) == NO_SPELL)  { 632. 	    You("don't know any spells right now."); 633. 	    return FALSE; 634. 	}  635.  	if (flags.menu_style == MENU_TRADITIONAL) { 636. 	    /* we know there is at least 1 known spell */ 637. 	    for (nspells = 1; nspells < MAXSPELL  638.  			    && spellid(nspells) != NO_SPELL; nspells++) 639. 		continue; 640.  641.  	    if (nspells == 1)  Strcpy(lets, "a"); 642. 	    else if (nspells < 27)  Sprintf(lets, "a-%c", 'a' + nspells - 1); 643. 	    else if (nspells == 27)  Sprintf(lets, "a-z A"); 644. 	    else if (nspells < 53) 645. 		Sprintf(lets, "a-z A-%c", 'A' + nspells - 27); 646. 	    else if (nspells == 53)  Sprintf(lets, "a-z A-Z 0"); 647. 	    else if (nspells < 62) 648. 		Sprintf(lets, "a-z A-Z 0-%c", '0' + nspells - 53); 649. 	    else  Sprintf(lets, "a-z A-Z 0-9"); 650.  651.  	    for  { 652. 		Sprintf(qbuf, "Cast which spell? [%s ?]", lets); 653. 		if ((ilet = yn_function(qbuf, (char *)0, '\0')) == '?') 654. 		    break; 655.  656.  		if (index(quitchars, ilet)) 657. 		    return FALSE; 658.  659.  		idx = spell_let_to_idx(ilet); 660. 		if (idx >= 0 && idx < nspells) { 661. 		    *spell_no = idx; 662. 		    return TRUE; 663. 		} else 664. 		    You("don't know that spell."); 665. 	    }  666.  	}  667.  	return dospellmenu("Choose which spell to cast",  668.  			   SPELLMENU_CAST, spell_no); 669. }  670.   671.  /* the 'Z' command -- cast a spell */ 672. int 673. docast 674. {  675.  	int spell_no; 676.  677.  	if (getspell(&spell_no)) 678. 	    return spelleffects(spell_no, FALSE); 679. 	return 0; 680. }  681.   682.  STATIC_OVL const char* 683. spelltypemnemonic(int skill) 684. {  685.  	switch (skill) { 686. 	    case P_ATTACK_SPELL: 687. 	        return " attack"; 688. 	    case P_HEALING_SPELL: 689. 		return "healing"; 690. 	    case P_DIVINATION_SPELL: 691. 	        return " divine"; 692. 	    case P_ENCHANTMENT_SPELL: 693. 	        return "enchant"; 694. 		case P_PROTECTION_SPELL: 695. 	        return "protect"; 696. 	    case P_BODY_SPELL: 697. 	        return "   body"; 698. 	    case P_MATTER_SPELL: 699. 	        return " matter"; 700. 	    default: 701. 		impossible("Unknown spell skill, %d;", skill); 702. 		return ""; 703. 	}  704.  }  705.   706.  int 707. spell_skilltype(booktype) 708. int booktype; 709. {  710.  	return (objects[booktype].oc_skill); 711. }  712.   713.  STATIC_OVL void 714. cast_protection 715. {  716.  	int loglev = 0; 717. 	int l = u.ulevel; 718. 	int natac = u.uac - u.uspellprot; 719. 	int gain; 720.  721.  	/* loglev=log2(u.ulevel)+1 (1..5) */ 722. 	while (l) { 723. 	    loglev++; 724. 	    l /= 2; 725. 	}  726.   727.  	/* The more u.uspellprot you already have, the less you get, 728. 	 * and the better your natural ac, the less you get. 729. 	 *  730.  	 *	LEVEL AC    SPELLPROT from sucessive SPE_PROTECTION casts 731. 	 *      1     10    0,  1,  2,  3,  4  732.  	 *      1      0    0,  1,  2,  3  733.  	 *      1    -10    0,  1,  2  734.  	 *      2-3   10    0,  2,  4,  5,  6,  7,  8  735.  	 *      2-3    0    0,  2,  4,  5,  6  736.  	 *      2-3  -10    0,  2,  3,  4  737.  	 *      4-7   10    0,  3,  6,  8,  9, 10, 11, 12  738.  	 *      4-7    0    0,  3,  5,  7,  8,  9  739.  	 *      4-7  -10    0,  3,  5,  6  740.  	 *      7-15 -10    0,  3,  5,  6  741.  	 *      8-15  10    0,  4,  7, 10, 12, 13, 14, 15, 16  742.  	 *      8-15   0    0,  4,  7,  9, 10, 11, 12  743.  	 *      8-15 -10    0,  4,  6,  7,  8  744.  	 *     16-30  10    0,  5,  9, 12, 14, 16, 17, 18, 19, 20  745.  	 *     16-30   0    0,  5,  9, 11, 13, 14, 15  746.  	 *     16-30 -10    0,  5,  8,  9, 10  747.  	 */  748.  	gain = loglev - (int)u.uspellprot / (4 - min(3,(10 - natac)/10)); 749.  750.  	if (gain > 0) { 751. 	    if (!Blind) { 752. 		const char *hgolden = hcolor(NH_GOLDEN); 753.  754.  		if (u.uspellprot) 755. 		    pline_The("%s haze around you becomes more dense.",  756.  			      hgolden); 757. 		else 758. 		    pline_The("%s around you begins to shimmer with %s haze.",  759.  			/*[ what about being inside solid rock while polyd? ]*/  760.  			(Underwater || Is_waterlevel(&u.uz)) ? "water" : "air",  761.  			      an(hgolden)); 762. 	    }  763.  	    u.uspellprot += gain; 764. 	    u.uspmtime = 765. 		P_SKILL(spell_skilltype(SPE_PROTECTION)) == P_EXPERT ? 20 : 10; 766.  	    if (!u.usptime) 767. 		u.usptime = u.uspmtime; 768. 	    find_ac; 769. 	} else { 770. 	    Your("skin feels warm for a moment."); 771. 	}  772.  }  773.   774.  /* attempting to cast a forgotten spell will cause disorientation */ 775. STATIC_OVL void 776. spell_backfire(spell) 777. int spell; 778. {  779.      long duration = (long)((spellev(spell) + 1) * 3);	 /* 6..24 */ 780.  781.      /* prior to 3.4.1, the only effect was confusion; it still predominates */ 782.     switch (rn2(10)) { 783.     case 0: 784.     case 1: 785.     case 2: 786.     case 3: make_confused(duration, FALSE);			/* 40% */ 787. 	    break; 788.     case 4: 789.     case 5: 790.     case 6: make_confused(2L * duration / 3L, FALSE);		/* 30% */ 791. 	    make_stunned(duration / 3L, FALSE); 792. 	    break; 793.     case 7: 794.     case 8: make_stunned(2L * duration / 3L, FALSE);		/* 20% */ 795. 	    make_confused(duration / 3L, FALSE); 796. 	    break; 797.     case 9: make_stunned(duration, FALSE);			/* 10% */ 798. 	    break; 799.     }  800.      return; 801. }  802.   803.  int 804. spelleffects(spell, atme) 805. int spell; 806. boolean atme; 807. {  808.  	int energy, damage, chance, n, intell; 809. 	int hungr; 810. 	int skill, role_skill; 811. 	boolean confused = (Confusion != 0); 812. 	struct obj *pseudo; 813.  814.  	/*  815.  	 * Find the skill the hero has in a spell type category. 816. 	 * See spell_skilltype for categories. 817. 	 */  818.  	skill = spell_skilltype(spellid(spell)); 819. 	role_skill = P_SKILL(skill); 820.  821.  	/*  822.  	 * Spell casting no longer affects knowledge of the spell. A 823. * decrement of spell knowledge is done every turn. 824. 	 */  825.  	if (spellknow(spell) <= 0) { 826. 	    Your("knowledge of this spell is twisted."); 827. 	    pline("It invokes nightmarish images in your mind..."); 828. 	    spell_backfire(spell); 829. 	    return(0); 830. 	} else if (spellknow(spell) <= 100) { 831. 	    You("strain to recall the spell."); 832. 	} else if (spellknow(spell) <= 1000) { 833. 	    Your("knowledge of this spell is growing faint."); 834. 	}  835.  	energy = (spellev(spell) * 5);    /* 5 <= energy <= 35 */ 836.  837.  	if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) { 838. 		You("are too hungry to cast that spell."); 839. 		return(0); 840. 	} else if (ACURR(A_STR) < 4)  { 841. 		You("lack the strength to cast spells."); 842. 		return(0); 843. 	} else if(check_capacity( 844. 		"Your concentration falters while carrying so much stuff.")) { 845. 	    return (1); 846. 	} else if (!freehand) { 847. 		Your("arms are not free to cast!"); 848. 		return (0); 849. 	}  850.   851.  	if (u.uhave.amulet) { 852. 		You_feel("the amulet draining your energy away."); 853. 		energy += rnd(2*energy); 854. 	}  855.  		if (spellid(spell) != SPE_DETECT_FOOD) { 856. 		hungr = energy * 2; 857.  858.  			/* If hero is a wizard, their current intelligence 859. 			 * (bonuses + temporary + current) 860. 			 * affects hunger reduction in casting a spell. 861. 			 * 1. int = 17-18 no reduction 862. 			 * 2. int = 16    1/4 hungr 863. 			 * 3. int = 15    1/2 hungr 864. 			 * 4. int = 1-14  normal reduction 865. 			 * The reason for this is: 866. 			 * a) Intelligence affects the amount of exertion  867.  			 * in thinking.  868.  			 * b) Wizards have spent their life at magic and 869. 			 * understand quite well how to cast spells. 870. 			 */  871.  			intell = acurr(A_INT); 872. 			if (!Role_if(PM_WIZARD)) intell = 10; 873. 			switch (intell) { 874. 				case 25: case 24: case 23: case 22: 875. 				case 21: case 20: case 19: case 18: 876. 				case 17: hungr = 0; break; 877. 				case 16: hungr /= 4; break; 878. 				case 15: hungr /= 2; break; 879. 			}  880.  	}  881.  	else 882. 		hungr = 0; 883. 			/* don't put player (quite) into fainting from 884. 			 * casting a spell, particularly since they might 885. 			 * not even be hungry at the beginning; however, 886. 			 * this is low enough that they must eat before 887. 			 * casting anything else except detect food 888. 			 */  889.  			if (hungr > u.uhunger-3) 890. 				hungr = u.uhunger-3; 891. 	if (energy > u.uen)  { 892. 		You("don't have enough energy to cast that spell."); 893. 		/* WAC/ALI Experts can override with HP/hunger loss */ 894. 		if ((role_skill >= P_SKILLED) && (yn("Continue?") == 'y')) { 895. 			energy -= u.uen; 896. 			hungr += energy * 2; 897. 			if (hungr > u.uhunger - 1) 898. 				hungr = u.uhunger - 1; 899. 			losehp(energy,"spellcasting exhaustion", KILLED_BY); 900. 			if (role_skill < P_EXPERT) exercise(A_WIS, FALSE); 901. 			energy = u.uen; 902. 		} else 903. 			return 0; 904. 	}  905.  	morehungry(hungr); 906.  907.  	chance = percent_success(spell); 908. 	if (confused || (rnd(100) > chance)) { 909. 		pline("You fail to cast the spell correctly."); 910.  911.  #ifdef ALLEG_FX 912.                 if (iflags.usealleg) alleg_aura(u.ux, u.uy, P_ATTACK_SPELL-1); 913. #endif 914.  915.  		u.uen -= (energy / 2); 916. 		flags.botl = 1; 917. 		return(1); 918. 	}  919.   920.  	u.uen -= energy; 921. 	  922.  	flags.botl = 1; 923. 	exercise(A_WIS, TRUE); 924.  925.  	/* pseudo is a temporary "false" object containing the spell stats. */ 926.  	pseudo = mksobj(spellid(spell), FALSE, FALSE); 927. 	pseudo->blessed = pseudo->cursed = 0; 928. 	pseudo->quan = 20L;			/* do not let useup get it */ 929.  930.  	/* WAC -- If skilled enough,  will act like a blessed version */ 931. 	if (role_skill >= P_SKILLED) 932. 		pseudo->blessed = 1; 933.  934.  #ifdef ALLEG_FX 935.         if (iflags.usealleg) alleg_aura(u.ux, u.uy, skill); 936. #endif 937. 	switch(pseudo->otyp)  { 938. 	/*  939.  	 * At first spells act as expected. As the hero increases in skill 940. 	 * with the appropriate spell type, some spells increase in their 941. 	 * effects, e.g. more damage, further distance, and so on, without 942. 	 * additional cost to the spellcaster. 943. 	 */  944.  	case SPE_MAGIC_MISSILE: 945. 	case SPE_FIREBALL: 946. 	case SPE_CONE_OF_COLD: 947. 	case SPE_LIGHTNING: 948. 	case SPE_ACID_STREAM: 949. 	case SPE_POISON_BLAST: 950. 		if (tech_inuse(T_SIGIL_TEMPEST)) { 951. 		    weffects(pseudo); 952. 		    break; 953. 		} /* else fall through... */ 954.  	/* these spells are all duplicates of wand effects */ 955. 	case SPE_FORCE_BOLT: 956. 	case SPE_SLEEP: 957. 	case SPE_KNOCK: 958. 	case SPE_SLOW_MONSTER: 959. 	case SPE_WIZARD_LOCK: 960. 	case SPE_DIG: 961. 	case SPE_TURN_UNDEAD: 962. 	case SPE_POLYMORPH: 963. 	case SPE_TELEPORT_AWAY: 964. 	case SPE_CANCELLATION: 965. 	case SPE_FINGER_OF_DEATH: 966. 	case SPE_LIGHT: 967. 	case SPE_DETECT_UNSEEN: 968. 	case SPE_HEALING: 969. 	case SPE_EXTRA_HEALING: 970. 	case SPE_DRAIN_LIFE: 971. 	case SPE_STONE_TO_FLESH: 972. 		if (!(objects[pseudo->otyp].oc_dir == NODIR)) { 973. 			if (atme) u.dx = u.dy = u.dz = 0; 974. 			else if (!getdir((char *)0)) { 975. 			    /* getdir cancelled, re-use previous direction */ 976. 			    pline_The("magical energy is released!"); 977. 			}  978.  			if(!u.dx && !u.dy && !u.dz) { 979. 			    if ((damage = zapyourself(pseudo, TRUE)) != 0) { 980. 				char buf[BUFSZ]; 981. 				Sprintf(buf, "zapped %sself with a spell", uhim); 982. 				losehp(damage, buf, NO_KILLER_PREFIX); 983. 			    }  984.  			} else weffects(pseudo); 985. 		} else weffects(pseudo); 986. 		update_inventory;	/* spell may modify inventory */ 987. 		break; 988. 	/* these are all duplicates of scroll effects */ 989. 	case SPE_REMOVE_CURSE: 990. 	case SPE_CONFUSE_MONSTER: 991. 	case SPE_DETECT_FOOD: 992. 	case SPE_CAUSE_FEAR: 993. #if 0 994. 		/* high skill yields effect equivalent to blessed scroll */ 995. 		if (role_skill >= P_SKILLED) pseudo->blessed = 1; 996. #endif 997. 		/* fall through */ 998. 	case SPE_CHARM_MONSTER: 999. 	case SPE_MAGIC_MAPPING: 1000. 	case SPE_CREATE_MONSTER: 1001. 	case SPE_IDENTIFY: 1002. 	case SPE_COMMAND_UNDEAD: 1003. 	case SPE_SUMMON_UNDEAD: 1004. 		(void) seffects(pseudo); 1005. 		break; 1006. 1007. 	case SPE_ENCHANT_WEAPON: 1008. 	case SPE_ENCHANT_ARMOR: 1009. 		if (role_skill >= P_EXPERT) n = 8; 1010. 		else if (role_skill >= P_SKILLED) n = 10; 1011. 		else if (role_skill >= P_BASIC) n = 12; 1012. 		else n = 14;	/* Unskilled or restricted */ 1013. 		if (!rn2(n)) { 1014. 		   pseudo->blessed = 0; 1015. 		   (void) seffects(pseudo); 1016. 		} else 1017. 		   Your("enchantment failed!"); 1018. 		break; 1019. 1020. 	/* these are all duplicates of potion effects */ 1021. 	case SPE_HASTE_SELF: 1022. 	case SPE_DETECT_TREASURE: 1023. 	case SPE_DETECT_MONSTERS: 1024. 	case SPE_LEVITATION: 1025. 	case SPE_RESTORE_ABILITY: 1026. #if 0 1027. 		/* high skill yields effect equivalent to blessed potion */ 1028. 		if (role_skill >= P_SKILLED) pseudo->blessed = 1; 1029. #endif 1030. 		/* fall through */ 1031. 	case SPE_INVISIBILITY: 1032. 		(void) peffects(pseudo); 1033. 		break; 1034. 	case SPE_CURE_BLINDNESS: 1035. 		healup(0, 0, FALSE, TRUE); 1036. 		break; 1037. 	case SPE_CURE_SICKNESS: 1038. 		if (Sick) You("are no longer ill."); 1039. 		if (Slimed) { 1040. 		   pline_The("slime disappears!"); 1041. 		   Slimed = 0; 1042. 		 /* flags.botl = 1; -- healup handles this */ 1043. 		} 1044. 		healup(0, 0, TRUE, FALSE); 1045. 		break; 1046. 	case SPE_CREATE_FAMILIAR: 1047. 		(void) make_familiar((struct obj *)0, u.ux, u.uy, FALSE); 1048. 		break; 1049. 	case SPE_CLAIRVOYANCE: 1050. 		if (!BClairvoyant) 1051. 		   do_vicinity_map; 1052. 		/* at present, only one thing blocks clairvoyance */ 1053. 		else if (uarmh && uarmh->otyp == CORNUTHAUM) 1054. 		   You("sense a pointy hat on top of your %s.",  1055. 			body_part(HEAD)); 1056. 		break; 1057. 	case SPE_PROTECTION: 1058. 		cast_protection; 1059. 		break; 1060. 	case SPE_JUMPING: 1061. 		if (!jump(max(role_skill,1))) 1062. 			pline(nothing_happens); 1063. 		break; 1064. 	case SPE_RESIST_POISON: 1065. 		if(!(HPoison_resistance & INTRINSIC)) { 1066. 			You("feel healthy ..... for the moment at least."); 1067. 			incr_itimeout(&HPoison_resistance, rn1(1000, 500) + 1068. 				spell_damage_bonus(spellid(spell))*100); 1069. 		} else pline(nothing_happens);	/* Already have as intrinsic */ 1070. 		break; 1071. 	case SPE_RESIST_SLEEP: 1072. 		if(!(HSleep_resistance & INTRINSIC)) { 1073. 			if (Hallucination) 1074. 				pline("Too much coffee!"); 1075. 			else 1076. 				You("no longer feel tired."); 1077. 			incr_itimeout(&HSleep_resistance, rn1(1000, 500) + 1078. 				spell_damage_bonus(spellid(spell))*100); 1079. 		} else pline(nothing_happens);	/* Already have as intrinsic */ 1080. 		break; 1081. 	case SPE_ENDURE_COLD: 1082. 		if(!(HCold_resistance & INTRINSIC)) { 1083. 			You("feel warmer."); 1084. 			incr_itimeout(&HCold_resistance, rn1(1000, 500) + 1085. 				spell_damage_bonus(spellid(spell))*100); 1086. 		} else pline(nothing_happens);	/* Already have as intrinsic */ 1087. 		break; 1088. 	case SPE_ENDURE_HEAT: 1089. 		if(!(HFire_resistance & INTRINSIC)) { 1090. 			if (Hallucination) 1091. 				pline("Excellent! You feel, like, totally cool!"); 1092. 			else 1093. 				You("feel colder."); 1094. 			incr_itimeout(&HFire_resistance, rn1(1000, 500) + 1095. 				spell_damage_bonus(spellid(spell))*100); 1096. 		} else pline(nothing_happens);	/* Already have as intrinsic */ 1097. 		break; 1098. 	case SPE_INSULATE: 1099. 		if(!(HShock_resistance & INTRINSIC)) { 1100. 			if (Hallucination) 1101. 				pline("Bummer! You've been grounded!"); 1102. 			else 1103. 				You("are not at all shocked by this feeling."); 1104. 			incr_itimeout(&HShock_resistance, rn1(1000, 500) + 1105. 				spell_damage_bonus(spellid(spell))*100); 1106. 		} else pline(nothing_happens);	/* Already have as intrinsic */ 1107. 		break; 1108. 	case SPE_ENLIGHTEN: 1109. 		You("feel self-knowledgeable..."); 1110. 		display_nhwindow(WIN_MESSAGE, FALSE); 1111. 		enlightenment(FALSE); 1112. 		pline("The feeling subsides."); 1113. 		exercise(A_WIS, TRUE); 1114. 		break; 1115. 1116. 	/* WAC -- new spells */ 1117. 	case SPE_FLAME_SPHERE: 1118. 	case SPE_FREEZE_SPHERE: 1119. 	{	register int cnt = 1; 1120. 		struct monst *mtmp; 1121. 1122.  1123. 		if (role_skill >= P_SKILLED) cnt += (role_skill - P_BASIC); 1124. 		while(cnt--) { 1125. 			mtmp = make_helper((pseudo->otyp == SPE_FLAME_SPHERE) ? 1126. 					PM_FLAMING_SPHERE : PM_FREEZING_SPHERE, u.ux, u.uy); 1127. 			if (!mtmp) continue; 1128. 			mtmp->mtame = 10; 1129. 			mtmp->mhpmax = mtmp->mhp = 1; 1130. 			mtmp->isspell = mtmp->uexp = TRUE; 1131. 		} /* end while... */ 1132. 		break; 1133. 	} 1134.  1135. 	/* KMH -- new spells */ 1136. 	case SPE_PASSWALL: 1137. 		if (!Passes_walls) 1138. 			You_feel("ethereal."); 1139. 		incr_itimeout(&HPasses_walls, rn1(100, 50)); 1140. 		break; 1141. 1142. 	default: 1143. 		impossible("Unknown spell %d attempted.", spell); 1144. 		obfree(pseudo, (struct obj *)0); 1145. 		return(0); 1146. 	} 1147.  1148. 	/* gain skill for successful cast */ 1149. 	use_skill(skill, spellev(spell)); 1150. 1151. 	/* WAC successful casting increases solidity of knowledge */ 1152. 	boostknow(spell,CAST_BOOST); 1153. 1154. 	obfree(pseudo, (struct obj *)0);	/* now, get rid of it */ 1155. 	return(1); 1156. } 1157.  1158.  1159. void 1160. losespells 1161. { 1162. 	boolean confused = (Confusion != 0); 1163. 	int n, nzap, i;  1164. 1165. 	book = 0; 1166. 	for (n = 0; n < MAXSPELL && spellid(n) != NO_SPELL; n++) 1167. 		continue; 1168. 	if (n) { 1169. 		nzap = rnd(n) + confused ? 1 : 0; 1170. 		if (nzap > n) nzap = n;  1171. for (i = n - nzap; i < n; i++) { 1172. 		   spellid(i) = NO_SPELL; 1173. 		   exercise(A_WIS, FALSE);	/* ouch! */ 1174. 		}  1175. 	}  1176. }  1177.  1178.  1179. /* the '+' command -- view known spells */ 1180. int 1181. dovspell 1182. { 1183. 	char qbuf[QBUFSZ]; 1184. 	int splnum, othnum; 1185. 	struct spell spl_tmp; 1186. 1187. 	if (spellid(0) == NO_SPELL) 1188. 	   You("don't know any spells right now."); 1189. 	else { 1190. 	   while (dospellmenu("Currently known spells", 1191. 			      SPELLMENU_VIEW, &splnum)) { 1192. 		Sprintf(qbuf, "Reordering spells; swap '%s' with", 1193. 			spellname(splnum)); 1194. 		if (!dospellmenu(qbuf, splnum, &othnum)) break; 1195. 1196. 		spl_tmp = spl_book[splnum]; 1197. 		spl_book[splnum] = spl_book[othnum]; 1198. 		spl_book[othnum] = spl_tmp; 1199. 	   }  1200. 	}  1201. 	return 0; 1202. } 1203.  1204. STATIC_OVL boolean 1205. dospellmenu(prompt, splaction, spell_no) 1206. const char *prompt; 1207. int splaction;	/* SPELLMENU_CAST, SPELLMENU_VIEW, or spl_book[] index */ 1208. int *spell_no; 1209. { 1210. 	winid tmpwin; 1211. 	int i, n, how; 1212. 	char buf[BUFSZ]; 1213. 	menu_item *selected; 1214. 	anything any; 1215. 1216. 	tmpwin = create_nhwindow(NHW_MENU); 1217. 	start_menu(tmpwin); 1218. 	any.a_void = 0;		/* zero out all bits */ 1219. 1220. 	/*  1221. 	 * The correct spacing of the columns depends on the 1222. 	 * following that (1) the font is monospaced and (2) 1223. 	 * that selection letters are pre-pended to the given 1224. 	 * string and are of the form "a - ". 1225. 	 * 1226. 	 * To do it right would require that we implement columns 1227. 	 * in the window-ports (say via a tab character). 1228. 	 */ 1229. 	if (!iflags.menu_tab_sep) 1230. 		Sprintf(buf, "%-20s    Level  %-12s Fail", "    Name", "Category"); 1231. 	else 1232. 		Sprintf(buf, "Name\tLevel\tCategory\tFail"); 1233. 	if (flags.menu_style == MENU_TRADITIONAL) 1234. 		Strcat(buf, iflags.menu_tab_sep ? "\tKey" : " Key"); 1235. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED); 1236. 	for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) { 1237. 		Sprintf(buf, iflags.menu_tab_sep ? 1238. 			"%s\t%-d%s\t%s\t%-d%%" : "%-20s  %2d%s   %-12s %3d%%",  1239. 			spellname(i), spellev(i),  1240. 			spellknow(i) ? " " : "*",  1241. 			spelltypemnemonic(spell_skilltype(spellid(i))),  1242. 			100 - percent_success(i)); 1243. 		if (flags.menu_style == MENU_TRADITIONAL) 1244. 			Sprintf(eos(buf), iflags.menu_tab_sep ? 1245. 				"\t%c" : "%4c ", spellet(i) ? spellet(i) : ' '); 1246. 1247. 		any.a_int = i+1;	/* must be non-zero */ 1248. 		add_menu(tmpwin, NO_GLYPH, &any, 1249. 			 0, 0, ATR_NONE, buf,  1250. 			 (i == splaction) ? MENU_SELECTED : MENU_UNSELECTED); 1251. 	     }  1252. 	end_menu(tmpwin, prompt); 1253. 1254. 	how = PICK_ONE; 1255. 	if (splaction == SPELLMENU_VIEW && spellid(1) == NO_SPELL) 1256. 	   how = PICK_NONE;	/* only one spell => nothing to swap with */ 1257. 	n = select_menu(tmpwin, how, &selected); 1258. 	destroy_nhwindow(tmpwin); 1259. 	if (n > 0) { 1260. 		*spell_no = selected[0].item.a_int - 1; 1261. 		/* menu selection for `PICK_ONE' does not 1262. 		  de-select any preselected entry */ 1263. 		if (n > 1 && *spell_no == splaction) 1264. 		   *spell_no = selected[1].item.a_int - 1; 1265. 		free((genericptr_t)selected); 1266. 		/* default selection of preselected spell means that 1267. 		  user chose not to swap it with anything */ 1268. 		if (*spell_no == splaction) return FALSE; 1269. 		return TRUE; 1270. 	} else if (splaction >= 0) { 1271. 	   /* explicit de-selection of preselected spell means that 1272. 	      user is still swapping but not for the current spell */ 1273. 	   *spell_no = splaction; 1274. 	   return TRUE; 1275. 	} 1276. 	return FALSE; 1277. } 1278.  1279. /* Integer square root function without using floating point. */ 1280. STATIC_OVL int 1281. isqrt(val) 1282. int val; 1283. { 1284.     int rt = 0; 1285.    int odd = 1; 1286.    while(val >= odd) { 1287. 	val = val-odd; 1288. 	odd = odd+2; 1289. 	rt = rt + 1; 1290.    }  1291.     return rt; 1292. } 1293.  1294.  1295. STATIC_OVL int 1296. percent_success(spell) 1297. int spell; 1298. { 1299. 	/* Intrinsic and learned ability are combined to calculate 1300. 	 * the probability of player's success at cast a given spell. 1301. 	 */ 1302. 	int chance, splcaster, special, statused; 1303. 	int difficulty; 1304. 	int skill; 1305. 1306. 	splcaster = urole.spelbase; 1307. 	special = urole.spelheal; 1308. 	statused = ACURR(urole.spelstat); 1309. 1310. 	/* Calculate armor penalties */ 1311. 	if (uarm && !(uarm->otyp == ROBE || 1312. 		     uarm->otyp == ROBE_OF_POWER || 1313. 		     uarm->otyp == ROBE_OF_PROTECTION)) 1314. 	   splcaster += 5; 1315. 1316. 	/* Robes are body armour in SLASH'EM */ 1317. 	if (uarm && is_metallic(uarm)) 1318. 	   splcaster += /*(uarmc && uarmc->otyp == ROBE) ? 1319. 		urole.spelarmr/2 : */urole.spelarmr; 1320. 	else if (uarmc && uarmc->otyp == ROBE) 1321. 	   splcaster -= urole.spelarmr; 1322. 	if (uarms) splcaster += urole.spelshld; 1323. 1324. 	if (uarmh && is_metallic(uarmh) && uarmh->otyp != HELM_OF_BRILLIANCE) 1325. 		splcaster += uarmhbon; 1326. 	if (uarmg && is_metallic(uarmg)) splcaster += uarmgbon; 1327. 	if (uarmf && is_metallic(uarmf)) splcaster += uarmfbon; 1328. 1329. 	if (spellid(spell) == urole.spelspec) 1330. 		splcaster += urole.spelsbon; 1331. 1332. 	/* `healing spell' bonus */ 1333. 	if (spell_skilltype(spellid(spell)) == P_HEALING_SPELL) 1334. 		splcaster += special; 1335. 1336. 	if (uarm && uarm->otyp == ROBE_OF_POWER) splcaster -= 3; 1337. 	if (splcaster < 5) splcaster = 5; 1338. 	if (splcaster > 20) splcaster = 20; 1339. 1340. 	/* Calculate learned ability */ 1341. 1342. 	/* Players basic likelihood of being able to cast any spell 1343. 	 * is based of their `magic' statistic. (Int or Wis) 1344. 	 */ 1345. 	chance = 11 * statused / 2; 1346. 1347. 	/*  1348. 	 * High level spells are harder. Easier for higher level casters. 1349. 	 * The difficulty is based on the hero's level and their skill level 1350. 	 * in that spell type. 1351. 	 */ 1352. 	skill = P_SKILL(spell_skilltype(spellid(spell))); 1353. 	skill = max(skill,P_UNSKILLED) - 1;	/* unskilled => 0 */ 1354. 	difficulty= (spellev(spell)-1) * 4 - ((skill * 6) + (u.ulevel/3) + 1); 1355. 1356. 	if (difficulty > 0) { 1357. 		/* Player is too low level or unskilled. */ 1358. 		chance -= isqrt(900 * difficulty + 2000); 1359. 	} else { 1360. 		/* Player is above level. Learning continues, but the 1361. 		 * law of diminishing returns sets in quickly for 1362. 		 * low-level spells. That is, a player quickly gains 1363. 		 * no advantage for raising level. 1364. 		 */ 1365. 		int learning = 15 * -difficulty / spellev(spell); 1366. 		chance += learning > 20 ? 20 : learning; 1367. 	} 1368.  1369. 	/* Clamp the chance: >18 stat and advanced learning only help 1370. 	 * to a limit, while chances below "hopeless" only raise the 1371. 	 * specter of overflowing 16-bit ints (and permit wearing a 1372. 	 * shield to raise the chances :-). 1373. 	 */ 1374. 	if (chance < 0) chance = 0; 1375. 	if (chance > 120) chance = 120; 1376. 1377. 	/* Wearing anything but a light shield makes it very awkward 1378. 	 * to cast a spell. The penalty is not quite so bad for the 1379. 	 * player's class-specific spell. 1380. 	 */ 1381. 	if (uarms && weight(uarms) > (int) objects[SMALL_SHIELD].oc_weight) { 1382. 		if (spellid(spell) == urole.spelspec) { 1383. 			chance /= 2; 1384. 		} else { 1385. 			chance /= 4; 1386. 		} 1387. 	}  1388.  1389. 	/* Finally, chance (based on player intell/wisdom and level) is  1390. * combined with ability (based on player intrinsics and 1391. 	 * encumbrances). No matter how intelligent/wise and advanced 1392. 	 * a player is, intrinsics and encumbrance can prevent casting; 1393. 	 * and no matter how able, learning is always required. 1394. 	 */ 1395. 	chance = chance * (20-splcaster) / 15 - splcaster; 1396. 1397. 	/* Clamp to percentile */ 1398. 	if (chance > 100) chance = 100; 1399. 	if (chance < 0) chance = 0; 1400. 1401. 	return chance; 1402. } 1403.  1404. /* Learn a spell during creation of the initial inventory */ 1405. void 1406. initialspell(obj) 1407. struct obj *obj; 1408. { 1409. 	int i;  1410. 1411. 	for (i = 0; i < MAXSPELL; i++) { 1412. 	   if (spellid(i) == obj->otyp) { 1413. 	        pline("Error: Spell %s already known.",  1414. 	         		OBJ_NAME(objects[obj->otyp])); 1415. 	        return; 1416. 	   }  1417. 	    if (spellid(i) == NO_SPELL)  { 1418. 	       spl_book[i].sp_id = obj->otyp; 1419. 	       spl_book[i].sp_lev = objects[obj->otyp].oc_level; 1420. 	       incrnknow(i); 1421. 	       return; 1422. 	   }  1423. 	}  1424. 	impossible("Too many spells memorized!"); 1425. 	return; 1426. } 1427.  1428. boolean 1429. studyspell 1430. { 1431. 	/*Vars are for studying spells 'W', 'F', 'I', 'N'*/ 1432. 	int spell_no; 1433. 1434. 	if (getspell(&spell_no)) { 1435. 		if (spellknow(spell_no) <= 0) { 1436. 			You("are unable to focus your memory of the spell."); 1437. 			return (FALSE); 1438. 		} else if (spellknow(spell_no) <= 1000) { 1439. 			Your("focus and reinforce your memory of the spell."); 1440. 			incrnknow(spell_no); 1441. 			exercise(A_WIS, TRUE);     /* extra study */ 1442. 			return (TRUE); 1443. 		} else /* 1000 < spellknow(spell_no) <= 5000 */ 1444. 			You("know that spell quite well already."); 1445. 	} 1446. 	return (FALSE); 1447. } 1448.  1449. /*spell.c*/