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