Fandom

Wikihack

Source:SLASH'EM 0.0.7E7F2/spell.c

2,034pages on
this wiki
Add New Page
Talk0

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

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.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.
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*/

Also on Fandom

Random Wiki