Source:NetHack 3.2.0/spell.c

From NetHackWiki
Revision as of 09:36, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.2.0/spell.c moved to Source:NetHack 3.2.0/spell.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)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*/