Source:NetHack 3.0.0/spell.c

Below is the full text to spell.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.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.0	88/09/18 2.    *  3.     *	Copyright (c) M. Stepheneon 1988 4.    */  5.    /* NetHack may be freely redistributed. See license for details. */ 6.     7.    #include "hack.h"  8.    #ifdef SPELLS 9.   static schar delay;		/* moves left for this spell */ 10.  static struct obj *book;	/* last/current book being xscribed */ 11.   12.   #ifdef HARD 13.  #define spelluses(spell)	spl_book[spell-1].sp_uses 14.  #define decrnuses(spell)	spl_book[spell-1].sp_uses-- 15.  #endif /* HARD */ 16.  #define spellev(spell)		spl_book[spell-1].sp_lev 17.  #define spellname(spell)	objects[spl_book[spell-1].sp_id].oc_name 18.  #define spellid(spell)		spl_book[spell-1].sp_id 19.   20.   static void 21.  cursed_book(level) 22.  	register int	level; 23.  {  24.   	switch(rn2(level)) { 25.  	case 0: 26.  		You("feel a wrenching sensation."); 27.  		tele;		/* teleport him */ 28.  		break; 29.  	case 1: 30.  		You("feel threatened."); 31.  		aggravate; 32.  		break; 33.  	case 2: 34.  		make_blinded(Blinded + rn1(100,250),TRUE); 35.  		break; 36.  	case 3: 37.  		take_gold; 38.  		break; 39.  	case 4: 40.  		pline("These runes were just too much to comprehend."); 41.  		make_confused(HConfusion + rn1(7,16),FALSE); 42.  		break; 43.  	case 5: 44.  		pline("The book was coated with contact poison!"); 45.  		if (uarmg) { 46.  		    if (uarmg->rustfree) 47.  			Your("gloves seem unaffected."); 48.  		    else if (uarmg->spe > -6) { 49.  			Your("gloves corrode!"); 50.  			uarmg->spe--; 51.  		    } else 52.  			Your("gloves look quite corroded."); 53.  		    break; 54.  		}  55.   		if(Poison_resistance) { 56.  		    losestr(rn1(1,2)); 57.  		    losehp(rnd(6), "contact poison"); 58.  		} else { 59.  		    losestr(rn1(4,3)); 60.  		    losehp(rnd(10), "contact poison"); 61.  		}  62.   		break; 63.  	case 6: 64.  		if(Antimagic) { 65.  		    shieldeff(u.ux, u.uy); 66.  		    pline("The book explodes, but you are unharmed!"); 67.  		} else { 68.  		    pline("As you read the book, it explodes in your %s!",  69.   			body_part(FACE)); 70.  		    losehp (2*rnd(10)+5, "exploding rune"); 71.  		}  72.   		break; 73.  	default: 74.  		rndcurse; 75.  		break; 76.  	}  77.   	return; 78.  }  79.    80.   static int 81.  learn 82.  {  83.   	register int	i; 84.  	register unsigned booktype; 85.   86.   	if (delay) {	/* not if (delay++), so at end delay == 0 */ 87.  		delay++; 88.  		return(1); /* still busy */ 89.  	}  90.    91.   	booktype = book->otyp; 92.  	for (i = 0; i < MAXSPELL; i++)  { 93.  		if (spl_book[i].sp_id == booktype)  { 94.  #ifdef HARD 95.  			Your("knowledge of that spell is keener."); 96.  			spl_book[i].sp_uses += rn1(3,8-spl_book[i].sp_lev); 97.  #else 98.  			pline("Oh, you already know that one!"); 99.  #endif 100. 			break; 101. 		} else if (spl_book[i].sp_id == NO_SPELL)  { 102. 			spl_book[i].sp_id = booktype; 103. 			spl_book[i].sp_lev = objects[booktype].spl_lev; 104. 			spl_book[i].sp_flags = objects[booktype].bits; 105. #ifdef HARD 106. 			/* spells have 2 .. 10-level uses. */ 107.  			/* ie 2 or 3 uses w/ most potent */ 108. 			spl_book[i].sp_uses = rn1(3,8-spl_book[i].sp_lev); 109. #endif 110. 			You("add the spell to your repertoire."); 111. 			makeknown(booktype); 112. 			break; 113. 		}  114.  	}  115.  	if (i == MAXSPELL) impossible("Too many spells memorized!"); 116.  117.  	if (book->cursed) {	/* maybe a demon cursed it */ 118. 		cursed_book(objects[booktype].spl_lev); 119. 	}  120.   121.  	useup(book); 122. 	book = 0; 123. 	return(0); 124. }  125.   126.  int 127. study_book(spellbook) 128. register struct obj *spellbook; 129. {  130.  	register int	 booktype = spellbook->otyp; 131. 	register boolean oops	  = !spellbook->blessed && (spellbook->cursed ||  132.  rn2(20) > (ACURR(A_INT) + 4 + (int)(u.ulevel/2) - 2*objects[booktype].spl_lev)); 133.  134.  	if (delay && spellbook == book) 135. 		You("continue your efforts to memorize the spell."); 136. 	else { 137. 		switch(booktype)  { 138.  139.  /* level 1 spells */ 140. 	case SPE_HEALING: 141. 	case SPE_DETECT_MONSTERS: 142. 	case SPE_FORCE_BOLT: 143. 	case SPE_LIGHT: 144. 	case SPE_SLEEP: 145. 	case SPE_KNOCK: 146. /* level 2 spells */ 147. 	case SPE_MAGIC_MISSILE: 148. 	case SPE_CONFUSE_MONSTER: 149. 	case SPE_SLOW_MONSTER: 150. 	case SPE_CURE_BLINDNESS: 151. 	case SPE_CREATE_MONSTER: 152. 	case SPE_DETECT_FOOD: 153. 	case SPE_WIZARD_LOCK: 154. 		delay = -objects[booktype].oc_delay; 155. 		break; 156. /* level 3 spells */ 157. 	case SPE_HASTE_SELF: 158. 	case SPE_CAUSE_FEAR: 159. 	case SPE_CURE_SICKNESS: 160. 	case SPE_DETECT_UNSEEN: 161. 	case SPE_EXTRA_HEALING: 162. 	case SPE_CHARM_MONSTER: 163. 	case SPE_CLAIRVOYANCE: 164. /* level 4 spells */ 165. 	case SPE_LEVITATION: 166. 	case SPE_RESTORE_ABILITY: 167. 	case SPE_INVISIBILITY: 168. 	case SPE_FIREBALL: 169. 	case SPE_DETECT_TREASURE: 170. 		delay = -(objects[booktype].spl_lev - 1) * objects[booktype].oc_delay; 171. 		break; 172. /* level 5 spells */ 173. 	case SPE_REMOVE_CURSE: 174. 	case SPE_MAGIC_MAPPING: 175. 	case SPE_CONE_OF_COLD: 176. 	case SPE_IDENTIFY: 177. 	case SPE_DIG: 178. /* level 6 spells */ 179. 	case SPE_TURN_UNDEAD: 180. 	case SPE_POLYMORPH: 181. 	case SPE_CREATE_FAMILIAR: 182. 	case SPE_TELEPORT_AWAY: 183. 		delay = -objects[booktype].spl_lev * objects[booktype].oc_delay; 184. 		break; 185. /* level 7 spells */ 186. 	case SPE_CANCELLATION: 187. 	case SPE_FINGER_OF_DEATH: 188. 	case SPE_GENOCIDE: 189. 		delay = -8 * objects[booktype].oc_delay; 190. 		break; 191. /* impossible */ 192. 	default: 193. 		impossible("Unknown spellbook, %d;", booktype); 194. 		return(0); 195. 	}  196.   197.  		if (oops) { 198. 			cursed_book(objects[booktype].spl_lev); 199. 			nomul(delay);			/* study time */ 200. 			delay = 0; 201. 			useup(spellbook); 202. 			return(1); 203. 		}  204.   205.  		You("begin to memorize the runes."); 206. 	}  207.   208.  	book = spellbook; 209. 	set_occupation(learn, "studying", 0); 210. 	return(1); 211. }  212.   213.  static int 214. getspell  { 215.  216.  	register int	maxs, ilet, i;  217. char	 lets[BUFSZ], buf[BUFSZ]; 218.  219.  	if (spl_book[0].sp_id == NO_SPELL)  { 220.  221.  		You("don't know any spells right now."); 222. 		return(0); 223. 	} else  { 224.  225.  	    for(maxs = 1; (maxs < MAXSPELL) && (spl_book[maxs].sp_id != NO_SPELL); maxs++); 226. 	    if (maxs >= MAXSPELL)  { 227.  228.  		impossible("Too many spells memorized."); 229. 		return(0); 230. 	    }  231.   232.  	    for(i = 0; (i < maxs) && (i < 26); buf[++i] = 0)  buf[i] = 'a' + i;  233. for(i = 26; (i < maxs) && (i < 52); buf[++i] = 0) buf[i] = 'A' + i - 26; 234.  235.  	    if (maxs == 1)  Strcpy(lets, "a"); 236. 	    else if (maxs < 27)  Sprintf(lets, "a-%c", 'a' + maxs - 1); 237. 	    else if (maxs == 27)  Sprintf(lets, "a-z A"); 238. 	    else Sprintf(lets, "a-z A-%c", 'A' + maxs - 27); 239. 	    for  { 240.  241.  		pline("Cast which spell? [%s ?] ", lets); 242. 		if ((ilet = readchar) == '?')  { 243. 			(void) dovspell; 244. 			continue; 245. 		} else if ((ilet == '\033')||(ilet == '\n')||(ilet == ' ')) 246. 			return(0); 247. 		else for(i = 0; buf[i] != 0; i++)  if(ilet == buf[i])  return(++i); 248. 		You("don't know that spell."); 249. 	    }  250.  	}  251.  }  252.   253.  int 254. docast 255. {  256.  	register int	 spell; 257.  258.  	spell = getspell; 259. 	if (!spell) return(0); 260.  261.  	return(spelleffects(spell,FALSE)); 262. }  263.   264.  int 265. spelleffects(spell,atme) 266. register int spell; 267. boolean atme; 268. {  269.  	register int energy, damage; 270. #ifdef HARD 271. 	boolean confused = (Confusion != 0); 272. #endif 273. 	struct obj *pseudo; 274.  275.  #ifdef HARD 276. 	/* note that trying to cast it decrements the # of uses,    */ 277. 	/* even if the mage does not have enough food/energy to use */ 278. 	/* the spell */ 279. 	switch (spelluses(spell)) { 280. 		case 0: 281. 		    pline ("That spell is too hard to recall at the moment."); 282. 		    return(0); 283. 		case 1: 284. 		    pline ("You can barely remember the runes of this spell."); 285. 		    break; 286. 		case 2: 287. 		    pline ("This spell is starting to be over-used."); 288. 		    break; 289. 		default: 290. 		    break; 291. 	}  292.  	decrnuses(spell); 293. #endif 294. 	energy = spellev(spell); 295. 	if (u.uhave_amulet) { 296. 		You("feel the amulet draining your energy away."); 297. 		energy *= rnd(6); 298. 	}  299.  	if(energy > u.uen)  { 300. 		You("are too weak to cast that spell."); 301. 		return(0); 302. 	} else	if ((u.uhunger <= 100 && spell != SPE_DETECT_FOOD) ||  303.  						(ACURR(A_STR) < 6))  { 304. 		You("lack the strength for that spell."); 305. 		return(0); 306. 	} else	{ 307. 		if (spell != SPE_DETECT_FOOD) 308. 			morehungry(energy * 10); 309. 		u.uen -= energy; 310. 	}  311.  	flags.botl = 1; 312.  313.  #ifdef HARD 314. 	if (confused ||  315.  	    ((int)(ACURR(A_INT) + u.uluck) - 3 * spellev(spell)) < 0) { 316.  317.  		if (Hallucination) 318. 			pline("Far out... a light show!"); 319. 		else	pline("The air around you crackles as you goof up."); 320. 		return(0); 321. 	}  322.  #endif 323.  324.  /*	pseudo is a temporary "false" object containing the spell stats. */ 325.  	pseudo = mksobj(spellid(spell),FALSE); 326. 	pseudo->blessed = pseudo->cursed = 0; 327. 	pseudo->quan = 20;			/* do not let useup get it */ 328. 	switch(pseudo->otyp)  { 329.  330.  /* These spells are all duplicates of wand effects */ 331. 	case SPE_FORCE_BOLT: 332. 	case SPE_SLEEP: 333. 	case SPE_MAGIC_MISSILE: 334. 	case SPE_KNOCK: 335. 	case SPE_SLOW_MONSTER: 336. 	case SPE_WIZARD_LOCK: 337. 	case SPE_FIREBALL: 338. 	case SPE_CONE_OF_COLD: 339. 	case SPE_DIG: 340. 	case SPE_TURN_UNDEAD: 341. 	case SPE_POLYMORPH: 342. 	case SPE_TELEPORT_AWAY: 343. 	case SPE_CANCELLATION: 344. 	case SPE_FINGER_OF_DEATH: 345. 	case SPE_LIGHT: 346. 	case SPE_DETECT_UNSEEN: 347. 		if (!(objects[pseudo->otyp].bits & NODIR)) { 348. 			if (atme) u.dx = u.dy = u.dz = 0; 349. 			else (void) getdir(1); 350. 			if(!u.dx && !u.dy && !u.dz) { 351. 			    if((damage = zapyourself(pseudo))) 352. 				losehp(damage, "self-inflicted injury"); 353. 			} else	weffects(pseudo); 354. 		} else weffects(pseudo); 355. 		break; 356. /* These are all duplicates of scroll effects */ 357. 	case SPE_CONFUSE_MONSTER: 358. 	case SPE_DETECT_FOOD: 359. 	case SPE_CAUSE_FEAR: 360. 	case SPE_CHARM_MONSTER: 361. 	case SPE_REMOVE_CURSE: 362. 	case SPE_MAGIC_MAPPING: 363. 	case SPE_CREATE_MONSTER: 364. 	case SPE_IDENTIFY: 365. 	case SPE_GENOCIDE: 366. 		(void) seffects(pseudo); 367. 		break; 368. 	case SPE_HASTE_SELF: 369. 	case SPE_DETECT_TREASURE: 370. 	case SPE_DETECT_MONSTERS: 371. 	case SPE_LEVITATION: 372. 	case SPE_RESTORE_ABILITY: 373. 	case SPE_INVISIBILITY: 374. 		(void) peffects(pseudo); 375. 		break; 376. 	case SPE_HEALING: 377. 		You("feel a bit better."); 378. 		healup(rnd(8), 0, 0, 0); 379. 		break; 380. 	case SPE_CURE_BLINDNESS: 381. 		healup(0, 0, 0, 1); 382. 		break; 383. 	case SPE_CURE_SICKNESS: 384. 		You("are no longer ill."); 385. 		healup(0, 0, 1, 0); 386. 		break; 387. 	case SPE_EXTRA_HEALING: 388. 		You("feel a fair bit better."); 389. 		healup(d(2,8), 1, 0, 0); 390. 		break; 391. 	case SPE_CREATE_FAMILIAR: 392. 		make_familiar((struct obj *)0); 393. 		break; 394. 	case SPE_CLAIRVOYANCE: 395. 		do_vicinity_map; 396. 		break; 397. 	default: 398. 		impossible("Unknown spell %d attempted.", spell); 399. 		obfree(pseudo, (struct obj *)0); 400. 		return(0); 401. 	}  402.  	obfree(pseudo, (struct obj *)0);	/* now, get rid of it */ 403. 	return(1); 404. }  405.   406.  void 407. losespells { 408. 	register boolean confused = (Confusion != 0); 409. 	register int	 n, nzap, i;  410. 411. 	book = 0; 412. 	for(n = 0;(spl_book[n].sp_id != NO_SPELL) && (n < MAXSPELL); n++); 413. 	if (!n) return; 414. 	if (n < MAXSPELL) { 415. 		nzap = rnd(n); 416. 		if (nzap < n) nzap += confused; 417. 		for (i = 0; i < nzap; i++) spl_book[n-i-1].sp_id = NO_SPELL; 418. 	} else impossible("Too many spells memorized!"); 419. 	return; 420. }  421.   422.  static char 423. spellet(spl) 424. {  425.  	return (spl < 27) ? ('a' + spl - 1) : ('A' + spl - 27); 426. }  427.   428.  int 429. dovspell { 430.  431.  	register int maxs, i;  432. char    buf[BUFSZ], any[BUFSZ]; 433.  434.  	if (spl_book[0].sp_id == NO_SPELL)  { 435.  436.  		You("don't know any spells right now."); 437. 		return 0; 438. 	}  439.   440.  	for(maxs = 1; (maxs < MAXSPELL) && (spl_book[maxs].sp_id != NO_SPELL); maxs++); 441. 	if (maxs >= MAXSPELL)  { 442.  443.  		impossible("Too many spells memorized."); 444. 		return 0; 445. 	}  446.  	morc = 0;		/* just to be sure */ 447. 	cornline(0, "Currently known spells:"); 448.  449.  	for(i = 1; i <= maxs; i++) { 450.  451.  #ifdef HARD 452. 		Sprintf(buf, "%c %c %s (%d)",  453.  			spellet(i), (spelluses(i)) ? '-' : '*',  454.  			spellname(i), spellev(i)); 455. #else 456. 		Sprintf(buf, "%c %s (%d)",  457.  			spellet(i),  458.  			spellname(i), spellev(i)); 459. #endif 460. 		cornline(1, buf); 461. 		any[i-1] = spellet(i); 462.   	}  463.  	any[i-1] = 0; 464. 	cornline(2, any); 465.  466.  	return 0; 467. }  468.   469.   470.  #endif /* SPELLS /**/