OSDN Git Service

add gitignore
[nethackexpress/trunk.git] / src / spell.c
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
7 static NEARDATA schar delay;            /* moves left for this spell */
8 static 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
23 STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P));
24 STATIC_DCL boolean FDECL(cursed_book, (struct obj *bp));
25 STATIC_DCL boolean FDECL(confused_book, (struct obj *));
26 STATIC_DCL void FDECL(deadbook, (struct obj *));
27 STATIC_PTR int NDECL(learn);
28 STATIC_DCL boolean FDECL(getspell, (int *));
29 STATIC_DCL boolean FDECL(dospellmenu, (const char *,int,int *));
30 STATIC_DCL int FDECL(percent_success, (int));
31 STATIC_DCL int NDECL(throwspell);
32 STATIC_DCL void NDECL(cast_protection);
33 STATIC_DCL void FDECL(spell_backfire, (int));
34 STATIC_DCL const char *FDECL(spelltypemnemonic, (int));
35 STATIC_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" */
91 static 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 */
94 STATIC_OVL int
95 spell_let_to_idx(ilet)
96 char 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 */
108 STATIC_OVL boolean
109 cursed_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 */
178 STATIC_OVL boolean
179 confused_book(spellbook)
180 struct 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 */
203 STATIC_OVL void
204 deadbook(book2)
205 struct 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) {
266 raise_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
315 STATIC_PTR int
316 learn()
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
389 int
390 study_book(spellbook)
391 register 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 */
499 void
500 book_disappears(obj)
501 struct 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 */
509 void
510 book_substitution(old_obj, new_obj)
511 struct obj *old_obj, *new_obj;
512 {
513         if (old_obj == book) book = new_obj;
514 }
515
516 /* called from moveloop() */
517 void
518 age_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  */
537 STATIC_OVL boolean
538 getspell(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 */
580 int
581 docast()
582 {
583         int spell_no;
584
585         if (getspell(&spell_no))
586             return spelleffects(spell_no, FALSE);
587         return 0;
588 }
589
590 STATIC_OVL const char *
591 spelltypemnemonic(skill)
592 int 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
615 int
616 spell_skilltype(booktype)
617 int booktype;
618 {
619         return (objects[booktype].oc_skill);
620 }
621
622 STATIC_OVL void
623 cast_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 */
684 STATIC_OVL void
685 spell_backfire(spell)
686 int 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
712 int
713 spelleffects(spell, atme)
714 int spell;
715 boolean 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. */
967 STATIC_OVL int
968 throwspell()
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
1003 void
1004 losespells()
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 */
1023 int
1024 dovspell()
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
1047 STATIC_OVL boolean
1048 dospellmenu(prompt, splaction, spell_no)
1049 const char *prompt;
1050 int splaction;  /* SPELLMENU_CAST, SPELLMENU_VIEW, or spl_book[] index */
1051 int *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. */
1118 STATIC_OVL int
1119 isqrt(val)
1120 int 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
1132 STATIC_OVL int
1133 percent_success(spell)
1134 int 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 */
1241 void
1242 initialspell(obj)
1243 struct 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*/