1 /* NetHack 3.6	spell.c	$NHDT-Date: 1546565814 2019/01/04 01:36:54 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.88 $ */
2 /*      Copyright (c) M. Stephenson 1988                          */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "hack.h"
6 
7 /* spellmenu arguments; 0 thru n-1 used as spl_book[] index when swapping */
8 #define SPELLMENU_CAST (-2)
9 #define SPELLMENU_VIEW (-1)
10 #define SPELLMENU_SORT (MAXSPELL) /* special menu entry */
11 
12 /* spell retention period, in turns; at 10% of this value, player becomes
13    eligible to reread the spellbook and regain 100% retention (the threshold
14    used to be 1000 turns, which was 10% of the original 10000 turn retention
15    period but didn't get adjusted when that period got doubled to 20000) */
16 #define KEEN 20000
17 /* x: need to add 1 when used for reading a spellbook rather than for hero
18    initialization; spell memory is decremented at the end of each turn,
19    including the turn on which the spellbook is read; without the extra
20    increment, the hero used to get cheated out of 1 turn of retention */
21 #define incrnknow(spell, x) (spl_book[spell].sp_know = KEEN + (x))
22 
23 #define spellev(spell) spl_book[spell].sp_lev
24 #define spellname(spell) OBJ_NAME(objects[spellid(spell)])
25 #define spellet(spell) \
26     ((char) ((spell < 26) ? ('a' + spell) : ('A' + spell - 26)))
27 
28 STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P));
29 STATIC_DCL boolean FDECL(cursed_book, (struct obj * bp));
30 STATIC_DCL boolean FDECL(confused_book, (struct obj *));
31 STATIC_DCL void FDECL(deadbook, (struct obj *));
32 STATIC_PTR int NDECL(learn);
33 STATIC_DCL boolean NDECL(rejectcasting);
34 STATIC_DCL boolean FDECL(getspell, (int *));
35 STATIC_PTR int FDECL(CFDECLSPEC spell_cmp, (const genericptr,
36                                             const genericptr));
37 STATIC_DCL void NDECL(sortspells);
38 STATIC_DCL boolean NDECL(spellsortmenu);
39 STATIC_DCL boolean FDECL(dospellmenu, (const char *, int, int *));
40 STATIC_DCL int FDECL(percent_success, (int));
41 STATIC_DCL char *FDECL(spellretention, (int, char *));
42 STATIC_DCL int NDECL(throwspell);
43 STATIC_DCL void NDECL(cast_protection);
44 STATIC_DCL void FDECL(spell_backfire, (int));
45 STATIC_DCL const char *FDECL(spelltypemnemonic, (int));
46 STATIC_DCL boolean FDECL(spell_aim_step, (genericptr_t, int, int));
47 
48 /* The roles[] table lists the role-specific values for tuning
49  * percent_success().
50  *
51  * Reasoning:
52  *   spelbase, spelheal:
53  *      Arc are aware of magic through historical research
54  *      Bar abhor magic (Conan finds it "interferes with his animal instincts")
55  *      Cav are ignorant to magic
56  *      Hea are very aware of healing magic through medical research
57  *      Kni are moderately aware of healing from Paladin training
58  *      Mon use magic to attack and defend in lieu of weapons and armor
59  *      Pri are very aware of healing magic through theological research
60  *      Ran avoid magic, preferring to fight unseen and unheard
61  *      Rog are moderately aware of magic through trickery
62  *      Sam have limited magical awareness, preferring meditation to conjuring
63  *      Tou are aware of magic from all the great films they have seen
64  *      Val have limited magical awareness, preferring fighting
65  *      Wiz are trained mages
66  *
67  *      The arms penalty is lessened for trained fighters Bar, Kni, Ran,
68  *      Sam, Val -- the penalty is its metal interference, not encumbrance.
69  *      The `spelspec' is a single spell which is fundamentally easier
70  *      for that role to cast.
71  *
72  *  spelspec, spelsbon:
73  *      Arc map masters (SPE_MAGIC_MAPPING)
74  *      Bar fugue/berserker (SPE_HASTE_SELF)
75  *      Cav born to dig (SPE_DIG)
76  *      Hea to heal (SPE_CURE_SICKNESS)
77  *      Kni to turn back evil (SPE_TURN_UNDEAD)
78  *      Mon to preserve their abilities (SPE_RESTORE_ABILITY)
79  *      Pri to bless (SPE_REMOVE_CURSE)
80  *      Ran to hide (SPE_INVISIBILITY)
81  *      Rog to find loot (SPE_DETECT_TREASURE)
82  *      Sam to be At One (SPE_CLAIRVOYANCE)
83  *      Tou to smile (SPE_CHARM_MONSTER)
84  *      Val control the cold (SPE_CONE_OF_COLD)
85  *      Wiz all really, but SPE_MAGIC_MISSILE is their party trick
86  *
87  *      See percent_success() below for more comments.
88  *
89  *  uarmbon, uarmsbon, uarmhbon, uarmgbon, uarmfbon:
90  *      Fighters find body armour & shield a little less limiting.
91  *      Headgear, Gauntlets and Footwear are not role-specific (but
92  *      still have an effect, except helm of brilliance, which is designed
93  *      to permit magic-use).
94  */
95 
96 #define uarmhbon 4 /* Metal helmets interfere with the mind */
97 #define uarmgbon 6 /* Casting channels through the hands */
98 #define uarmfbon 2 /* All metal interferes to some degree */
99 
100 /* since the spellbook itself doesn't blow up, don't say just "explodes" */
101 static const char explodes[] = "radiates explosive energy";
102 
103 /* convert a letter into a number in the range 0..51, or -1 if not a letter */
104 STATIC_OVL int
spell_let_to_idx(ilet)105 spell_let_to_idx(ilet)
106 char ilet;
107 {
108     int indx;
109 
110     indx = ilet - 'a';
111     if (indx >= 0 && indx < 26)
112         return indx;
113     indx = ilet - 'A';
114     if (indx >= 0 && indx < 26)
115         return indx + 26;
116     return -1;
117 }
118 
119 /* TRUE: book should be destroyed by caller */
120 STATIC_OVL boolean
cursed_book(bp)121 cursed_book(bp)
122 struct obj *bp;
123 {
124     boolean was_in_use;
125     int lev = objects[bp->otyp].oc_level;
126     int dmg = 0;
127 
128     switch (rn2(lev)) {
129     case 0:
130         You_feel("a wrenching sensation.");
131         tele(); /* teleport him */
132         break;
133     case 1:
134         You_feel("threatened.");
135         aggravate();
136         break;
137     case 2:
138         make_blinded(Blinded + rn1(100, 250), TRUE);
139         break;
140     case 3:
141         take_gold();
142         break;
143     case 4:
144         pline("These runes were just too much to comprehend.");
145         make_confused(HConfusion + rn1(7, 16), FALSE);
146         break;
147     case 5:
148         pline_The("book was coated with contact poison!");
149         if (uarmg) {
150             erode_obj(uarmg, "gloves", ERODE_CORRODE, EF_GREASE | EF_VERBOSE);
151             break;
152         }
153         /* temp disable in_use; death should not destroy the book */
154         was_in_use = bp->in_use;
155         bp->in_use = FALSE;
156         losestr(Poison_resistance ? rn1(2, 1) : rn1(4, 3));
157         losehp(rnd(Poison_resistance ? 6 : 10), "contact-poisoned spellbook",
158                KILLED_BY_AN);
159         bp->in_use = was_in_use;
160         break;
161     case 6:
162         if (Antimagic) {
163             shieldeff(u.ux, u.uy);
164             pline_The("book %s, but you are unharmed!", explodes);
165         } else {
166             pline("As you read the book, it %s in your %s!", explodes,
167                   body_part(FACE));
168             dmg = 2 * rnd(10) + 5;
169             losehp(Maybe_Half_Phys(dmg), "exploding rune", KILLED_BY_AN);
170         }
171         return TRUE;
172     default:
173         rndcurse();
174         break;
175     }
176     return FALSE;
177 }
178 
179 /* study while confused: returns TRUE if the book is destroyed */
180 STATIC_OVL boolean
confused_book(spellbook)181 confused_book(spellbook)
182 struct obj *spellbook;
183 {
184     boolean gone = FALSE;
185 
186     if (!rn2(3) && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) {
187         spellbook->in_use = TRUE; /* in case called from learn */
188         pline(
189          "Being confused you have difficulties in controlling your actions.");
190         display_nhwindow(WIN_MESSAGE, FALSE);
191         You("accidentally tear the spellbook to pieces.");
192         if (!objects[spellbook->otyp].oc_name_known
193             && !objects[spellbook->otyp].oc_uname)
194             docall(spellbook);
195         useup(spellbook);
196         gone = TRUE;
197     } else {
198         You("find yourself reading the %s line over and over again.",
199             spellbook == context.spbook.book ? "next" : "first");
200     }
201     return gone;
202 }
203 
204 /* special effects for The Book of the Dead */
205 STATIC_OVL void
deadbook(book2)206 deadbook(book2)
207 struct obj *book2;
208 {
209     struct monst *mtmp, *mtmp2;
210     coord mm;
211 
212     You("turn the pages of the Book of the Dead...");
213     makeknown(SPE_BOOK_OF_THE_DEAD);
214     /* KMH -- Need ->known to avoid "_a_ Book of the Dead" */
215     book2->known = 1;
216     if (invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
217         register struct obj *otmp;
218         register boolean arti1_primed = FALSE, arti2_primed = FALSE,
219                          arti_cursed = FALSE;
220 
221         if (book2->cursed) {
222             pline_The("runes appear scrambled.  You can't read them!");
223             return;
224         }
225 
226         if (!u.uhave.bell || !u.uhave.menorah) {
227             pline("A chill runs down your %s.", body_part(SPINE));
228             if (!u.uhave.bell)
229                 You_hear("a faint chime...");
230             if (!u.uhave.menorah)
231                 pline("Vlad's doppelganger is amused.");
232             return;
233         }
234 
235         for (otmp = invent; otmp; otmp = otmp->nobj) {
236             if (otmp->otyp == CANDELABRUM_OF_INVOCATION && otmp->spe == 7
237                 && otmp->lamplit) {
238                 if (!otmp->cursed)
239                     arti1_primed = TRUE;
240                 else
241                     arti_cursed = TRUE;
242             }
243             if (otmp->otyp == BELL_OF_OPENING
244                 && (moves - otmp->age) < 5L) { /* you rang it recently */
245                 if (!otmp->cursed)
246                     arti2_primed = TRUE;
247                 else
248                     arti_cursed = TRUE;
249             }
250         }
251 
252         if (arti_cursed) {
253             pline_The("invocation fails!");
254             pline("At least one of your artifacts is cursed...");
255         } else if (arti1_primed && arti2_primed) {
256             unsigned soon =
257                 (unsigned) d(2, 6); /* time til next intervene() */
258 
259             /* successful invocation */
260             mkinvokearea();
261             u.uevent.invoked = 1;
262             /* in case you haven't killed the Wizard yet, behave as if
263                you just did */
264             u.uevent.udemigod = 1; /* wizdead() */
265             if (!u.udg_cnt || u.udg_cnt > soon)
266                 u.udg_cnt = soon;
267         } else { /* at least one artifact not prepared properly */
268             You("have a feeling that %s is amiss...", something);
269             goto raise_dead;
270         }
271         return;
272     }
273 
274     /* when not an invocation situation */
275     if (book2->cursed) {
276     raise_dead:
277 
278         You("raised the dead!");
279         /* first maybe place a dangerous adversary */
280         if (!rn2(3) && ((mtmp = makemon(&mons[PM_MASTER_LICH], u.ux, u.uy,
281                                         NO_MINVENT)) != 0
282                         || (mtmp = makemon(&mons[PM_NALFESHNEE], u.ux, u.uy,
283                                            NO_MINVENT)) != 0)) {
284             mtmp->mpeaceful = 0;
285             set_malign(mtmp);
286         }
287         /* next handle the affect on things you're carrying */
288         (void) unturn_dead(&youmonst);
289         /* last place some monsters around you */
290         mm.x = u.ux;
291         mm.y = u.uy;
292         mkundead(&mm, TRUE, NO_MINVENT);
293     } else if (book2->blessed) {
294         for (mtmp = fmon; mtmp; mtmp = mtmp2) {
295             mtmp2 = mtmp->nmon; /* tamedog() changes chain */
296             if (DEADMONSTER(mtmp))
297                 continue;
298 
299             if ((is_undead(mtmp->data) || is_vampshifter(mtmp))
300                 && cansee(mtmp->mx, mtmp->my)) {
301                 mtmp->mpeaceful = TRUE;
302                 if (sgn(mtmp->data->maligntyp) == sgn(u.ualign.type)
303                     && distu(mtmp->mx, mtmp->my) < 4)
304                     if (mtmp->mtame) {
305                         if (mtmp->mtame < 20)
306                             mtmp->mtame++;
307                     } else
308                         (void) tamedog(mtmp, (struct obj *) 0);
309                 else
310                     monflee(mtmp, 0, FALSE, TRUE);
311             }
312         }
313     } else {
314         switch (rn2(3)) {
315         case 0:
316             Your("ancestors are annoyed with you!");
317             break;
318         case 1:
319             pline_The("headstones in the cemetery begin to move!");
320             break;
321         default:
322             pline("Oh my!  Your name appears in the book!");
323         }
324     }
325     return;
326 }
327 
328 /* 'book' has just become cursed; if we're reading it and realize it is
329    now cursed, interrupt */
330 void
book_cursed(book)331 book_cursed(book)
332 struct obj *book;
333 {
334     if (occupation == learn && context.spbook.book == book
335         && book->cursed && book->bknown && multi >= 0)
336         stop_occupation();
337 }
338 
339 STATIC_PTR int
learn(VOID_ARGS)340 learn(VOID_ARGS)
341 {
342     int i;
343     short booktype;
344     char splname[BUFSZ];
345     boolean costly = TRUE;
346     struct obj *book = context.spbook.book;
347 
348     /* JDS: lenses give 50% faster reading; 33% smaller read time */
349     if (context.spbook.delay && ublindf && ublindf->otyp == LENSES && rn2(2))
350         context.spbook.delay++;
351     if (Confusion) { /* became confused while learning */
352         (void) confused_book(book);
353         context.spbook.book = 0; /* no longer studying */
354         context.spbook.o_id = 0;
355         nomul(context.spbook.delay); /* remaining delay is uninterrupted */
356         multi_reason = "reading a book";
357         nomovemsg = 0;
358         context.spbook.delay = 0;
359         return 0;
360     }
361     if (context.spbook.delay) {
362         /* not if (context.spbook.delay++), so at end delay == 0 */
363         context.spbook.delay++;
364         return 1; /* still busy */
365     }
366     exercise(A_WIS, TRUE); /* you're studying. */
367     booktype = book->otyp;
368     if (booktype == SPE_BOOK_OF_THE_DEAD) {
369         deadbook(book);
370         return 0;
371     }
372 
373     Sprintf(splname,
374             objects[booktype].oc_name_known ? "\"%s\"" : "the \"%s\" spell",
375             OBJ_NAME(objects[booktype]));
376     for (i = 0; i < MAXSPELL; i++)
377         if (spellid(i) == booktype || spellid(i) == NO_SPELL)
378             break;
379 
380     if (i == MAXSPELL) {
381         impossible("Too many spells memorized!");
382     } else if (spellid(i) == booktype) {
383         /* normal book can be read and re-read a total of 4 times */
384         if (book->spestudied > MAX_SPELL_STUDY) {
385             pline("This spellbook is too faint to be read any more.");
386             book->otyp = booktype = SPE_BLANK_PAPER;
387             /* reset spestudied as if polymorph had taken place */
388             book->spestudied = rn2(book->spestudied);
389         } else if (spellknow(i) > KEEN / 10) {
390             You("know %s quite well already.", splname);
391             costly = FALSE;
392         } else { /* spellknow(i) <= KEEN/10 */
393             Your("knowledge of %s is %s.", splname,
394                  spellknow(i) ? "keener" : "restored");
395             incrnknow(i, 1);
396             book->spestudied++;
397             exercise(A_WIS, TRUE); /* extra study */
398         }
399         /* make book become known even when spell is already
400            known, in case amnesia made you forget the book */
401         makeknown((int) booktype);
402     } else { /* (spellid(i) == NO_SPELL) */
403         /* for a normal book, spestudied will be zero, but for
404            a polymorphed one, spestudied will be non-zero and
405            one less reading is available than when re-learning */
406         if (book->spestudied >= MAX_SPELL_STUDY) {
407             /* pre-used due to being the product of polymorph */
408             pline("This spellbook is too faint to read even once.");
409             book->otyp = booktype = SPE_BLANK_PAPER;
410             /* reset spestudied as if polymorph had taken place */
411             book->spestudied = rn2(book->spestudied);
412         } else {
413             spl_book[i].sp_id = booktype;
414             spl_book[i].sp_lev = objects[booktype].oc_level;
415             incrnknow(i, 1);
416             book->spestudied++;
417             You(i > 0 ? "add %s to your repertoire." : "learn %s.", splname);
418         }
419         makeknown((int) booktype);
420     }
421 
422     if (book->cursed) { /* maybe a demon cursed it */
423         if (cursed_book(book)) {
424             useup(book);
425             context.spbook.book = 0;
426             context.spbook.o_id = 0;
427             return 0;
428         }
429     }
430     if (costly)
431         check_unpaid(book);
432     context.spbook.book = 0;
433     context.spbook.o_id = 0;
434     return 0;
435 }
436 
437 int
study_book(spellbook)438 study_book(spellbook)
439 register struct obj *spellbook;
440 {
441     int booktype = spellbook->otyp;
442     boolean confused = (Confusion != 0);
443     boolean too_hard = FALSE;
444 
445     /* attempting to read dull book may make hero fall asleep */
446     if (!confused && !Sleep_resistance
447         && !strcmp(OBJ_DESCR(objects[booktype]), "dull")) {
448         const char *eyes;
449         int dullbook = rnd(25) - ACURR(A_WIS);
450 
451         /* adjust chance if hero stayed awake, got interrupted, retries */
452         if (context.spbook.delay && spellbook == context.spbook.book)
453             dullbook -= rnd(objects[booktype].oc_level);
454 
455         if (dullbook > 0) {
456             eyes = body_part(EYE);
457             if (eyecount(youmonst.data) > 1)
458                 eyes = makeplural(eyes);
459             pline("This book is so dull that you can't keep your %s open.",
460                   eyes);
461             dullbook += rnd(2 * objects[booktype].oc_level);
462             fall_asleep(-dullbook, TRUE);
463             return 1;
464         }
465     }
466 
467     if (context.spbook.delay && !confused && spellbook == context.spbook.book
468         /* handle the sequence: start reading, get interrupted, have
469            context.spbook.book become erased somehow, resume reading it */
470         && booktype != SPE_BLANK_PAPER) {
471         You("continue your efforts to %s.",
472             (booktype == SPE_NOVEL) ? "read the novel" : "memorize the spell");
473     } else {
474         /* KMH -- Simplified this code */
475         if (booktype == SPE_BLANK_PAPER) {
476             pline("This spellbook is all blank.");
477             makeknown(booktype);
478             return 1;
479         }
480 
481         /* 3.6 tribute */
482         if (booktype == SPE_NOVEL) {
483             /* Obtain current Terry Pratchett book title */
484             const char *tribtitle = noveltitle(&spellbook->novelidx);
485 
486             if (read_tribute("books", tribtitle, 0, (char *) 0, 0,
487                              spellbook->o_id)) {
488                 u.uconduct.literate++;
489                 check_unpaid(spellbook);
490                 makeknown(booktype);
491                 if (!u.uevent.read_tribute) {
492                     /* give bonus of 20 xp and 4*20+0 pts */
493                     more_experienced(20, 0);
494                     newexplevel();
495                     u.uevent.read_tribute = 1; /* only once */
496                 }
497             }
498             return 1;
499         }
500 
501         switch (objects[booktype].oc_level) {
502         case 1:
503         case 2:
504             context.spbook.delay = -objects[booktype].oc_delay;
505             break;
506         case 3:
507         case 4:
508             context.spbook.delay = -(objects[booktype].oc_level - 1)
509                                    * objects[booktype].oc_delay;
510             break;
511         case 5:
512         case 6:
513             context.spbook.delay =
514                 -objects[booktype].oc_level * objects[booktype].oc_delay;
515             break;
516         case 7:
517             context.spbook.delay = -8 * objects[booktype].oc_delay;
518             break;
519         default:
520             impossible("Unknown spellbook level %d, book %d;",
521                        objects[booktype].oc_level, booktype);
522             return 0;
523         }
524 
525         /* Books are often wiser than their readers (Rus.) */
526         spellbook->in_use = TRUE;
527         if (!spellbook->blessed && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) {
528             if (spellbook->cursed) {
529                 too_hard = TRUE;
530             } else {
531                 /* uncursed - chance to fail */
532                 int read_ability = ACURR(A_INT) + 4 + u.ulevel / 2
533                                    - 2 * objects[booktype].oc_level
534                              + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0);
535 
536                 /* only wizards know if a spell is too difficult */
537                 if (Role_if(PM_WIZARD) && read_ability < 20 && !confused) {
538                     char qbuf[QBUFSZ];
539 
540                     Sprintf(qbuf,
541                     "This spellbook is %sdifficult to comprehend.  Continue?",
542                             (read_ability < 12 ? "very " : ""));
543                     if (yn(qbuf) != 'y') {
544                         spellbook->in_use = FALSE;
545                         return 1;
546                     }
547                 }
548                 /* its up to random luck now */
549                 if (rnd(20) > read_ability) {
550                     too_hard = TRUE;
551                 }
552             }
553         }
554 
555         if (too_hard) {
556             boolean gone = cursed_book(spellbook);
557 
558             nomul(context.spbook.delay); /* study time */
559             multi_reason = "reading a book";
560             nomovemsg = 0;
561             context.spbook.delay = 0;
562             if (gone || !rn2(3)) {
563                 if (!gone)
564                     pline_The("spellbook crumbles to dust!");
565                 if (!objects[spellbook->otyp].oc_name_known
566                     && !objects[spellbook->otyp].oc_uname)
567                     docall(spellbook);
568                 useup(spellbook);
569             } else
570                 spellbook->in_use = FALSE;
571             return 1;
572         } else if (confused) {
573             if (!confused_book(spellbook)) {
574                 spellbook->in_use = FALSE;
575             }
576             nomul(context.spbook.delay);
577             multi_reason = "reading a book";
578             nomovemsg = 0;
579             context.spbook.delay = 0;
580             return 1;
581         }
582         spellbook->in_use = FALSE;
583 
584         You("begin to %s the runes.",
585             spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" : "memorize");
586     }
587 
588     context.spbook.book = spellbook;
589     if (context.spbook.book)
590         context.spbook.o_id = context.spbook.book->o_id;
591     set_occupation(learn, "studying", 0);
592     return 1;
593 }
594 
595 /* a spellbook has been destroyed or the character has changed levels;
596    the stored address for the current book is no longer valid */
597 void
book_disappears(obj)598 book_disappears(obj)
599 struct obj *obj;
600 {
601     if (obj == context.spbook.book) {
602         context.spbook.book = (struct obj *) 0;
603         context.spbook.o_id = 0;
604     }
605 }
606 
607 /* renaming an object usually results in it having a different address;
608    so the sequence start reading, get interrupted, name the book, resume
609    reading would read the "new" book from scratch */
610 void
book_substitution(old_obj,new_obj)611 book_substitution(old_obj, new_obj)
612 struct obj *old_obj, *new_obj;
613 {
614     if (old_obj == context.spbook.book) {
615         context.spbook.book = new_obj;
616         if (context.spbook.book)
617             context.spbook.o_id = context.spbook.book->o_id;
618     }
619 }
620 
621 /* called from moveloop() */
622 void
age_spells()623 age_spells()
624 {
625     int i;
626     /*
627      * The time relative to the hero (a pass through move
628      * loop) causes all spell knowledge to be decremented.
629      * The hero's speed, rest status, conscious status etc.
630      * does not alter the loss of memory.
631      */
632     for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++)
633         if (spellknow(i))
634             decrnknow(i);
635     return;
636 }
637 
638 /* return True if spellcasting is inhibited;
639    only covers a small subset of reasons why casting won't work */
640 STATIC_OVL boolean
rejectcasting()641 rejectcasting()
642 {
643     /* rejections which take place before selecting a particular spell */
644     if (Stunned) {
645         You("are too impaired to cast a spell.");
646         return TRUE;
647     } else if (!can_chant(&youmonst)) {
648         You("are unable to chant the incantation.");
649         return TRUE;
650     } else if (!freehand()) {
651         /* Note: !freehand() occurs when weapon and shield (or two-handed
652          * weapon) are welded to hands, so "arms" probably doesn't need
653          * to be makeplural(bodypart(ARM)).
654          *
655          * But why isn't lack of free arms (for gesturing) an issue when
656          * poly'd hero has no limbs?
657          */
658         Your("arms are not free to cast!");
659         return TRUE;
660     }
661     return FALSE;
662 }
663 
664 /*
665  * Return TRUE if a spell was picked, with the spell index in the return
666  * parameter.  Otherwise return FALSE.
667  */
668 STATIC_OVL boolean
getspell(spell_no)669 getspell(spell_no)
670 int *spell_no;
671 {
672     int nspells, idx;
673     char ilet, lets[BUFSZ], qbuf[QBUFSZ];
674 
675     if (spellid(0) == NO_SPELL) {
676         You("don't know any spells right now.");
677         return FALSE;
678     }
679     if (rejectcasting())
680         return FALSE; /* no spell chosen */
681 
682     if (flags.menu_style == MENU_TRADITIONAL) {
683         /* we know there is at least 1 known spell */
684         for (nspells = 1; nspells < MAXSPELL && spellid(nspells) != NO_SPELL;
685              nspells++)
686             continue;
687 
688         if (nspells == 1)
689             Strcpy(lets, "a");
690         else if (nspells < 27)
691             Sprintf(lets, "a-%c", 'a' + nspells - 1);
692         else if (nspells == 27)
693             Sprintf(lets, "a-zA");
694         /* this assumes that there are at most 52 spells... */
695         else
696             Sprintf(lets, "a-zA-%c", 'A' + nspells - 27);
697 
698         for (;;) {
699             Sprintf(qbuf, "Cast which spell? [%s *?]", lets);
700             ilet = yn_function(qbuf, (char *) 0, '\0');
701             if (ilet == '*' || ilet == '?')
702                 break; /* use menu mode */
703             if (index(quitchars, ilet))
704                 return FALSE;
705 
706             idx = spell_let_to_idx(ilet);
707             if (idx < 0 || idx >= nspells) {
708                 You("don't know that spell.");
709                 continue; /* ask again */
710             }
711             *spell_no = idx;
712             return TRUE;
713         }
714     }
715     return dospellmenu("Choose which spell to cast", SPELLMENU_CAST,
716                        spell_no);
717 }
718 
719 /* the 'Z' command -- cast a spell */
720 int
docast()721 docast()
722 {
723     int spell_no;
724 
725     if (getspell(&spell_no))
726         return spelleffects(spell_no, FALSE);
727     return 0;
728 }
729 
730 STATIC_OVL const char *
spelltypemnemonic(skill)731 spelltypemnemonic(skill)
732 int skill;
733 {
734     switch (skill) {
735     case P_ATTACK_SPELL:
736         return "attack";
737     case P_HEALING_SPELL:
738         return "healing";
739     case P_DIVINATION_SPELL:
740         return "divination";
741     case P_ENCHANTMENT_SPELL:
742         return "enchantment";
743     case P_CLERIC_SPELL:
744         return "clerical";
745     case P_ESCAPE_SPELL:
746         return "escape";
747     case P_MATTER_SPELL:
748         return "matter";
749     default:
750         impossible("Unknown spell skill, %d;", skill);
751         return "";
752     }
753 }
754 
755 int
spell_skilltype(booktype)756 spell_skilltype(booktype)
757 int booktype;
758 {
759     return objects[booktype].oc_skill;
760 }
761 
762 STATIC_OVL void
cast_protection()763 cast_protection()
764 {
765     int l = u.ulevel, loglev = 0,
766         gain, natac = u.uac + u.uspellprot;
767     /* note: u.uspellprot is subtracted when find_ac() factors it into u.uac,
768        so adding here factors it back out
769        (versions prior to 3.6 had this backwards) */
770 
771     /* loglev=log2(u.ulevel)+1 (1..5) */
772     while (l) {
773         loglev++;
774         l /= 2;
775     }
776 
777     /* The more u.uspellprot you already have, the less you get,
778      * and the better your natural ac, the less you get.
779      *
780      *  LEVEL AC    SPELLPROT from successive SPE_PROTECTION casts
781      *      1     10    0,  1,  2,  3,  4
782      *      1      0    0,  1,  2,  3
783      *      1    -10    0,  1,  2
784      *      2-3   10    0,  2,  4,  5,  6,  7,  8
785      *      2-3    0    0,  2,  4,  5,  6
786      *      2-3  -10    0,  2,  3,  4
787      *      4-7   10    0,  3,  6,  8,  9, 10, 11, 12
788      *      4-7    0    0,  3,  5,  7,  8,  9
789      *      4-7  -10    0,  3,  5,  6
790      *      7-15 -10    0,  3,  5,  6
791      *      8-15  10    0,  4,  7, 10, 12, 13, 14, 15, 16
792      *      8-15   0    0,  4,  7,  9, 10, 11, 12
793      *      8-15 -10    0,  4,  6,  7,  8
794      *     16-30  10    0,  5,  9, 12, 14, 16, 17, 18, 19, 20
795      *     16-30   0    0,  5,  9, 11, 13, 14, 15
796      *     16-30 -10    0,  5,  8,  9, 10
797      */
798     natac = (10 - natac) / 10; /* convert to positive and scale down */
799     gain = loglev - (int) u.uspellprot / (4 - min(3, natac));
800 
801     if (gain > 0) {
802         if (!Blind) {
803             int rmtyp;
804             const char *hgolden = hcolor(NH_GOLDEN), *atmosphere;
805 
806             if (u.uspellprot) {
807                 pline_The("%s haze around you becomes more dense.", hgolden);
808             } else {
809                 rmtyp = levl[u.ux][u.uy].typ;
810                 atmosphere = u.uswallow
811                                 ? ((u.ustuck->data == &mons[PM_FOG_CLOUD])
812                                    ? "mist"
813                                    : is_whirly(u.ustuck->data)
814                                       ? "maelstrom"
815                                       : is_animal(u.ustuck->data)
816                                          ? "maw"
817                                          : "ooze")
818                                 : (u.uinwater
819                                    ? hliquid("water")
820                                    : (rmtyp == CLOUD)
821                                       ? "cloud"
822                                       : IS_TREE(rmtyp)
823                                          ? "vegetation"
824                                          : IS_STWALL(rmtyp)
825                                             ? "stone"
826                                             : "air");
827                 pline_The("%s around you begins to shimmer with %s haze.",
828                           atmosphere, an(hgolden));
829             }
830         }
831         u.uspellprot += gain;
832         u.uspmtime = (P_SKILL(spell_skilltype(SPE_PROTECTION)) == P_EXPERT)
833                         ? 20 : 10;
834         if (!u.usptime)
835             u.usptime = u.uspmtime;
836         find_ac();
837     } else {
838         Your("skin feels warm for a moment.");
839     }
840 }
841 
842 /* attempting to cast a forgotten spell will cause disorientation */
843 STATIC_OVL void
spell_backfire(spell)844 spell_backfire(spell)
845 int spell;
846 {
847     long duration = (long) ((spellev(spell) + 1) * 3), /* 6..24 */
848          old_stun = (HStun & TIMEOUT), old_conf = (HConfusion & TIMEOUT);
849 
850     /* Prior to 3.4.1, only effect was confusion; it still predominates.
851      *
852      * 3.6.0: this used to override pre-existing confusion duration
853      * (cases 0..8) and pre-existing stun duration (cases 4..9);
854      * increase them instead.   (Hero can no longer cast spells while
855      * Stunned, so the potential increment to stun duration here is
856      * just hypothetical.)
857      */
858     switch (rn2(10)) {
859     case 0:
860     case 1:
861     case 2:
862     case 3:
863         make_confused(old_conf + duration, FALSE); /* 40% */
864         break;
865     case 4:
866     case 5:
867     case 6:
868         make_confused(old_conf + 2L * duration / 3L, FALSE); /* 30% */
869         make_stunned(old_stun + duration / 3L, FALSE);
870         break;
871     case 7:
872     case 8:
873         make_stunned(old_stun + 2L * duration / 3L, FALSE); /* 20% */
874         make_confused(old_conf + duration / 3L, FALSE);
875         break;
876     case 9:
877         make_stunned(old_stun + duration, FALSE); /* 10% */
878         break;
879     }
880     return;
881 }
882 
883 int
spelleffects(spell,atme)884 spelleffects(spell, atme)
885 int spell;
886 boolean atme;
887 {
888     int energy, damage, chance, n, intell;
889     int otyp, skill, role_skill, res = 0;
890     boolean confused = (Confusion != 0);
891     boolean physical_damage = FALSE;
892     struct obj *pseudo;
893     coord cc;
894 
895     /*
896      * Reject attempting to cast while stunned or with no free hands.
897      * Already done in getspell() to stop casting before choosing
898      * which spell, but duplicated here for cases where spelleffects()
899      * gets called directly for ^T without intrinsic teleport capability
900      * or #turn for non-priest/non-knight.
901      * (There's no duplication of messages; when the rejection takes
902      * place in getspell(), we don't get called.)
903      */
904     if (rejectcasting()) {
905         return 0; /* no time elapses */
906     }
907 
908     /*
909      * Spell casting no longer affects knowledge of the spell. A
910      * decrement of spell knowledge is done every turn.
911      */
912     if (spellknow(spell) <= 0) {
913         Your("knowledge of this spell is twisted.");
914         pline("It invokes nightmarish images in your mind...");
915         spell_backfire(spell);
916         return 1;
917     } else if (spellknow(spell) <= KEEN / 200) { /* 100 turns left */
918         You("strain to recall the spell.");
919     } else if (spellknow(spell) <= KEEN / 40) { /* 500 turns left */
920         You("have difficulty remembering the spell.");
921     } else if (spellknow(spell) <= KEEN / 20) { /* 1000 turns left */
922         Your("knowledge of this spell is growing faint.");
923     } else if (spellknow(spell) <= KEEN / 10) { /* 2000 turns left */
924         Your("recall of this spell is gradually fading.");
925     }
926     /*
927      *  Note: dotele() also calculates energy use and checks nutrition
928      *  and strength requirements; it any of these change, update it too.
929      */
930     energy = (spellev(spell) * 5); /* 5 <= energy <= 35 */
931 
932     if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) {
933         You("are too hungry to cast that spell.");
934         return 0;
935     } else if (ACURR(A_STR) < 4 && spellid(spell) != SPE_RESTORE_ABILITY) {
936         You("lack the strength to cast spells.");
937         return 0;
938     } else if (check_capacity(
939                 "Your concentration falters while carrying so much stuff.")) {
940         return 1;
941     }
942 
943     /* if the cast attempt is already going to fail due to insufficient
944        energy (ie, u.uen < energy), the Amulet's drain effect won't kick
945        in and no turn will be consumed; however, when it does kick in,
946        the attempt may fail due to lack of energy after the draining, in
947        which case a turn will be used up in addition to the energy loss */
948     if (u.uhave.amulet && u.uen >= energy) {
949         You_feel("the amulet draining your energy away.");
950         /* this used to be 'energy += rnd(2 * energy)' (without 'res'),
951            so if amulet-induced cost was more than u.uen, nothing
952            (except the "don't have enough energy" message) happened
953            and player could just try again (and again and again...);
954            now we drain some energy immediately, which has a
955            side-effect of not increasing the hunger aspect of casting */
956         u.uen -= rnd(2 * energy);
957         if (u.uen < 0)
958             u.uen = 0;
959         context.botl = 1;
960         res = 1; /* time is going to elapse even if spell doesn't get cast */
961     }
962 
963     if (energy > u.uen) {
964         You("don't have enough energy to cast that spell.");
965         return res;
966     } else {
967         if (spellid(spell) != SPE_DETECT_FOOD) {
968             int hungr = energy * 2;
969 
970             /* If hero is a wizard, their current intelligence
971              * (bonuses + temporary + current)
972              * affects hunger reduction in casting a spell.
973              * 1. int = 17-18 no reduction
974              * 2. int = 16    1/4 hungr
975              * 3. int = 15    1/2 hungr
976              * 4. int = 1-14  normal reduction
977              * The reason for this is:
978              * a) Intelligence affects the amount of exertion
979              * in thinking.
980              * b) Wizards have spent their life at magic and
981              * understand quite well how to cast spells.
982              */
983             intell = acurr(A_INT);
984             if (!Role_if(PM_WIZARD))
985                 intell = 10;
986             switch (intell) {
987             case 25:
988             case 24:
989             case 23:
990             case 22:
991             case 21:
992             case 20:
993             case 19:
994             case 18:
995             case 17:
996                 hungr = 0;
997                 break;
998             case 16:
999                 hungr /= 4;
1000                 break;
1001             case 15:
1002                 hungr /= 2;
1003                 break;
1004             }
1005             /* don't put player (quite) into fainting from
1006              * casting a spell, particularly since they might
1007              * not even be hungry at the beginning; however,
1008              * this is low enough that they must eat before
1009              * casting anything else except detect food
1010              */
1011             if (hungr > u.uhunger - 3)
1012                 hungr = u.uhunger - 3;
1013             morehungry(hungr);
1014         }
1015     }
1016 
1017     chance = percent_success(spell);
1018     if (confused || (rnd(100) > chance)) {
1019         You("fail to cast the spell correctly.");
1020         u.uen -= energy / 2;
1021         context.botl = 1;
1022         return 1;
1023     }
1024 
1025     u.uen -= energy;
1026     context.botl = 1;
1027     exercise(A_WIS, TRUE);
1028     /* pseudo is a temporary "false" object containing the spell stats */
1029     pseudo = mksobj(spellid(spell), FALSE, FALSE);
1030     pseudo->blessed = pseudo->cursed = 0;
1031     pseudo->quan = 20L; /* do not let useup get it */
1032     /*
1033      * Find the skill the hero has in a spell type category.
1034      * See spell_skilltype for categories.
1035      */
1036     otyp = pseudo->otyp;
1037     skill = spell_skilltype(otyp);
1038     role_skill = P_SKILL(skill);
1039 
1040     switch (otyp) {
1041     /*
1042      * At first spells act as expected.  As the hero increases in skill
1043      * with the appropriate spell type, some spells increase in their
1044      * effects, e.g. more damage, further distance, and so on, without
1045      * additional cost to the spellcaster.
1046      */
1047     case SPE_FIREBALL:
1048     case SPE_CONE_OF_COLD:
1049         if (role_skill >= P_SKILLED) {
1050             if (throwspell()) {
1051                 cc.x = u.dx;
1052                 cc.y = u.dy;
1053                 n = rnd(8) + 1;
1054                 while (n--) {
1055                     if (!u.dx && !u.dy && !u.dz) {
1056                         if ((damage = zapyourself(pseudo, TRUE)) != 0) {
1057                             char buf[BUFSZ];
1058                             Sprintf(buf, "zapped %sself with a spell",
1059                                     uhim());
1060                             losehp(damage, buf, NO_KILLER_PREFIX);
1061                         }
1062                     } else {
1063                         explode(u.dx, u.dy,
1064                                 otyp - SPE_MAGIC_MISSILE + 10,
1065                                 spell_damage_bonus(u.ulevel / 2 + 1), 0,
1066                                 (otyp == SPE_CONE_OF_COLD)
1067                                    ? EXPL_FROSTY
1068                                    : EXPL_FIERY);
1069                     }
1070                     u.dx = cc.x + rnd(3) - 2;
1071                     u.dy = cc.y + rnd(3) - 2;
1072                     if (!isok(u.dx, u.dy) || !cansee(u.dx, u.dy)
1073                         || IS_STWALL(levl[u.dx][u.dy].typ) || u.uswallow) {
1074                         /* Spell is reflected back to center */
1075                         u.dx = cc.x;
1076                         u.dy = cc.y;
1077                     }
1078                 }
1079             }
1080             break;
1081         } /* else */
1082         /*FALLTHRU*/
1083 
1084     /* these spells are all duplicates of wand effects */
1085     case SPE_FORCE_BOLT:
1086         physical_damage = TRUE;
1087     /*FALLTHRU*/
1088     case SPE_SLEEP:
1089     case SPE_MAGIC_MISSILE:
1090     case SPE_KNOCK:
1091     case SPE_SLOW_MONSTER:
1092     case SPE_WIZARD_LOCK:
1093     case SPE_DIG:
1094     case SPE_TURN_UNDEAD:
1095     case SPE_POLYMORPH:
1096     case SPE_TELEPORT_AWAY:
1097     case SPE_CANCELLATION:
1098     case SPE_FINGER_OF_DEATH:
1099     case SPE_LIGHT:
1100     case SPE_DETECT_UNSEEN:
1101     case SPE_HEALING:
1102     case SPE_EXTRA_HEALING:
1103     case SPE_DRAIN_LIFE:
1104     case SPE_STONE_TO_FLESH:
1105         if (objects[otyp].oc_dir != NODIR) {
1106             if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) {
1107                 /* healing and extra healing are actually potion effects,
1108                    but they've been extended to take a direction like wands */
1109                 if (role_skill >= P_SKILLED)
1110                     pseudo->blessed = 1;
1111             }
1112             if (atme) {
1113                 u.dx = u.dy = u.dz = 0;
1114             } else if (!getdir((char *) 0)) {
1115                 /* getdir cancelled, re-use previous direction */
1116                 /*
1117                  * FIXME:  reusing previous direction only makes sense
1118                  * if there is an actual previous direction.  When there
1119                  * isn't one, the spell gets cast at self which is rarely
1120                  * what the player intended.  Unfortunately, the way
1121                  * spelleffects() is organized means that aborting with
1122                  * "nevermind" is not an option.
1123                  */
1124                 pline_The("magical energy is released!");
1125             }
1126             if (!u.dx && !u.dy && !u.dz) {
1127                 if ((damage = zapyourself(pseudo, TRUE)) != 0) {
1128                     char buf[BUFSZ];
1129 
1130                     Sprintf(buf, "zapped %sself with a spell", uhim());
1131                     if (physical_damage)
1132                         damage = Maybe_Half_Phys(damage);
1133                     losehp(damage, buf, NO_KILLER_PREFIX);
1134                 }
1135             } else
1136                 weffects(pseudo);
1137         } else
1138             weffects(pseudo);
1139         update_inventory(); /* spell may modify inventory */
1140         break;
1141 
1142     /* these are all duplicates of scroll effects */
1143     case SPE_REMOVE_CURSE:
1144     case SPE_CONFUSE_MONSTER:
1145     case SPE_DETECT_FOOD:
1146     case SPE_CAUSE_FEAR:
1147     case SPE_IDENTIFY:
1148         /* high skill yields effect equivalent to blessed scroll */
1149         if (role_skill >= P_SKILLED)
1150             pseudo->blessed = 1;
1151     /*FALLTHRU*/
1152     case SPE_CHARM_MONSTER:
1153     case SPE_MAGIC_MAPPING:
1154     case SPE_CREATE_MONSTER:
1155         (void) seffects(pseudo);
1156         break;
1157 
1158     /* these are all duplicates of potion effects */
1159     case SPE_HASTE_SELF:
1160     case SPE_DETECT_TREASURE:
1161     case SPE_DETECT_MONSTERS:
1162     case SPE_LEVITATION:
1163     case SPE_RESTORE_ABILITY:
1164         /* high skill yields effect equivalent to blessed potion */
1165         if (role_skill >= P_SKILLED)
1166             pseudo->blessed = 1;
1167     /*FALLTHRU*/
1168     case SPE_INVISIBILITY:
1169         (void) peffects(pseudo);
1170         break;
1171     /* end of potion-like spells */
1172 
1173     case SPE_CURE_BLINDNESS:
1174         healup(0, 0, FALSE, TRUE);
1175         break;
1176     case SPE_CURE_SICKNESS:
1177         if (Sick)
1178             You("are no longer ill.");
1179         if (Slimed)
1180             make_slimed(0L, "The slime disappears!");
1181         healup(0, 0, TRUE, FALSE);
1182         break;
1183     case SPE_CREATE_FAMILIAR:
1184         (void) make_familiar((struct obj *) 0, u.ux, u.uy, FALSE);
1185         break;
1186     case SPE_CLAIRVOYANCE:
1187         if (!BClairvoyant) {
1188             if (role_skill >= P_SKILLED)
1189                 pseudo->blessed = 1; /* detect monsters as well as map */
1190             do_vicinity_map(pseudo);
1191         /* at present, only one thing blocks clairvoyance */
1192         } else if (uarmh && uarmh->otyp == CORNUTHAUM)
1193             You("sense a pointy hat on top of your %s.", body_part(HEAD));
1194         break;
1195     case SPE_PROTECTION:
1196         cast_protection();
1197         break;
1198     case SPE_JUMPING:
1199         if (!jump(max(role_skill, 1)))
1200             pline1(nothing_happens);
1201         break;
1202     default:
1203         impossible("Unknown spell %d attempted.", spell);
1204         obfree(pseudo, (struct obj *) 0);
1205         return 0;
1206     }
1207 
1208     /* gain skill for successful cast */
1209     use_skill(skill, spellev(spell));
1210 
1211     obfree(pseudo, (struct obj *) 0); /* now, get rid of it */
1212     return 1;
1213 }
1214 
1215 /*ARGSUSED*/
1216 STATIC_OVL boolean
spell_aim_step(arg,x,y)1217 spell_aim_step(arg, x, y)
1218 genericptr_t arg UNUSED;
1219 int x, y;
1220 {
1221     if (!isok(x,y))
1222         return FALSE;
1223     if (!ZAP_POS(levl[x][y].typ)
1224         && !(IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & D_ISOPEN)))
1225         return FALSE;
1226     return TRUE;
1227 }
1228 
1229 /* Choose location where spell takes effect. */
1230 STATIC_OVL int
throwspell()1231 throwspell()
1232 {
1233     coord cc, uc;
1234     struct monst *mtmp;
1235 
1236     if (u.uinwater) {
1237         pline("You're joking!  In this weather?");
1238         return 0;
1239     } else if (Is_waterlevel(&u.uz)) {
1240         You("had better wait for the sun to come out.");
1241         return 0;
1242     }
1243 
1244     pline("Where do you want to cast the spell?");
1245     cc.x = u.ux;
1246     cc.y = u.uy;
1247     if (getpos(&cc, TRUE, "the desired position") < 0)
1248         return 0; /* user pressed ESC */
1249     /* The number of moves from hero to where the spell drops.*/
1250     if (distmin(u.ux, u.uy, cc.x, cc.y) > 10) {
1251         pline_The("spell dissipates over the distance!");
1252         return 0;
1253     } else if (u.uswallow) {
1254         pline_The("spell is cut short!");
1255         exercise(A_WIS, FALSE); /* What were you THINKING! */
1256         u.dx = 0;
1257         u.dy = 0;
1258         return 1;
1259     } else if ((!cansee(cc.x, cc.y)
1260                 && (!(mtmp = m_at(cc.x, cc.y)) || !canspotmon(mtmp)))
1261                || IS_STWALL(levl[cc.x][cc.y].typ)) {
1262         Your("mind fails to lock onto that location!");
1263         return 0;
1264     }
1265 
1266     uc.x = u.ux;
1267     uc.y = u.uy;
1268 
1269     walk_path(&uc, &cc, spell_aim_step, (genericptr_t) 0);
1270 
1271     u.dx = cc.x;
1272     u.dy = cc.y;
1273     return 1;
1274 }
1275 
1276 /* add/hide/remove/unhide teleport-away on behalf of dotelecmd() to give
1277    more control to behavior of ^T when used in wizard mode */
1278 int
tport_spell(what)1279 tport_spell(what)
1280 int what;
1281 {
1282     static struct tport_hideaway {
1283         struct spell savespell;
1284         int tport_indx;
1285     } save_tport;
1286     int i;
1287 /* also defined in teleport.c */
1288 #define NOOP_SPELL  0
1289 #define HIDE_SPELL  1
1290 #define ADD_SPELL   2
1291 #define UNHIDESPELL 3
1292 #define REMOVESPELL 4
1293 
1294     for (i = 0; i < MAXSPELL; i++)
1295         if (spellid(i) == SPE_TELEPORT_AWAY || spellid(i) == NO_SPELL)
1296             break;
1297     if (i == MAXSPELL) {
1298         impossible("tport_spell: spellbook full");
1299         /* wizard mode ^T is not able to honor player's menu choice */
1300     } else if (spellid(i) == NO_SPELL) {
1301         if (what == HIDE_SPELL || what == REMOVESPELL) {
1302             save_tport.tport_indx = MAXSPELL;
1303         } else if (what == UNHIDESPELL) {
1304             /*assert( save_tport.savespell.sp_id == SPE_TELEPORT_AWAY );*/
1305             spl_book[save_tport.tport_indx] = save_tport.savespell;
1306             save_tport.tport_indx = MAXSPELL; /* burn bridge... */
1307         } else if (what == ADD_SPELL) {
1308             save_tport.savespell = spl_book[i];
1309             save_tport.tport_indx = i;
1310             spl_book[i].sp_id = SPE_TELEPORT_AWAY;
1311             spl_book[i].sp_lev = objects[SPE_TELEPORT_AWAY].oc_level;
1312             spl_book[i].sp_know = KEEN;
1313             return REMOVESPELL; /* operation needed to reverse */
1314         }
1315     } else { /* spellid(i) == SPE_TELEPORT_AWAY */
1316         if (what == ADD_SPELL || what == UNHIDESPELL) {
1317             save_tport.tport_indx = MAXSPELL;
1318         } else if (what == REMOVESPELL) {
1319             /*assert( i == save_tport.tport_indx );*/
1320             spl_book[i] = save_tport.savespell;
1321             save_tport.tport_indx = MAXSPELL;
1322         } else if (what == HIDE_SPELL) {
1323             save_tport.savespell = spl_book[i];
1324             save_tport.tport_indx = i;
1325             spl_book[i].sp_id = NO_SPELL;
1326             return UNHIDESPELL; /* operation needed to reverse */
1327         }
1328     }
1329     return NOOP_SPELL;
1330 }
1331 
1332 /* forget a random selection of known spells due to amnesia;
1333    they used to be lost entirely, as if never learned, but now we
1334    just set the memory retention to zero so that they can't be cast */
1335 void
losespells()1336 losespells()
1337 {
1338     int n, nzap, i;
1339 
1340     /* in case reading has been interrupted earlier, discard context */
1341     context.spbook.book = 0;
1342     context.spbook.o_id = 0;
1343     /* count the number of known spells */
1344     for (n = 0; n < MAXSPELL; ++n)
1345         if (spellid(n) == NO_SPELL)
1346             break;
1347 
1348     /* lose anywhere from zero to all known spells;
1349        if confused, use the worse of two die rolls */
1350     nzap = rn2(n + 1);
1351     if (Confusion) {
1352         i = rn2(n + 1);
1353         if (i > nzap)
1354             nzap = i;
1355     }
1356     /* good Luck might ameliorate spell loss */
1357     if (nzap > 1 && !rnl(7))
1358         nzap = rnd(nzap);
1359 
1360     /*
1361      * Forget 'nzap' out of 'n' known spells by setting their memory
1362      * retention to zero.  Every spell has the same probability to be
1363      * forgotten, even if its retention is already zero.
1364      *
1365      * Perhaps we should forget the corresponding book too?
1366      *
1367      * (3.4.3 removed spells entirely from the list, but always did
1368      * so from its end, so the 'nzap' most recently learned spells
1369      * were the ones lost by default.  Player had sort control over
1370      * the list, so could move the most useful spells to front and
1371      * only lose them if 'nzap' turned out to be a large value.
1372      *
1373      * Discarding from the end of the list had the virtue of making
1374      * casting letters for lost spells become invalid and retaining
1375      * the original letter for the ones which weren't lost, so there
1376      * was no risk to the player of accidentally casting the wrong
1377      * spell when using a letter that was in use prior to amnesia.
1378      * That wouldn't be the case if we implemented spell loss spread
1379      * throughout the list of known spells; every spell located past
1380      * the first lost spell would end up with new letter assigned.)
1381      */
1382     for (i = 0; nzap > 0; ++i) {
1383         /* when nzap is small relative to the number of spells left,
1384            the chance to lose spell [i] is small; as the number of
1385            remaining candidates shrinks, the chance per candidate
1386            gets bigger; overall, exactly nzap entries are affected */
1387         if (rn2(n - i) < nzap) {
1388             /* lose access to spell [i] */
1389             spellknow(i) = 0;
1390 #if 0
1391             /* also forget its book */
1392             forget_single_object(spellid(i));
1393 #endif
1394             /* and abuse wisdom */
1395             exercise(A_WIS, FALSE);
1396             /* there's now one less spell slated to be forgotten */
1397             --nzap;
1398         }
1399     }
1400 }
1401 
1402 /*
1403  * Allow player to sort the list of known spells.  Manually swapping
1404  * pairs of them becomes very tedious once the list reaches two pages.
1405  *
1406  * Possible extensions:
1407  *      provide means for player to control ordering of skill classes;
1408  *      provide means to supply value N such that first N entries stick
1409  *      while rest of list is being sorted;
1410  *      make chosen sort order be persistent such that when new spells
1411  *      are learned, they get inserted into sorted order rather than be
1412  *      appended to the end of the list?
1413  */
1414 enum spl_sort_types {
1415     SORTBY_LETTER = 0,
1416     SORTBY_ALPHA,
1417     SORTBY_LVL_LO,
1418     SORTBY_LVL_HI,
1419     SORTBY_SKL_AL,
1420     SORTBY_SKL_LO,
1421     SORTBY_SKL_HI,
1422     SORTBY_CURRENT,
1423     SORTRETAINORDER,
1424 
1425     NUM_SPELL_SORTBY
1426 };
1427 
1428 static const char *spl_sortchoices[NUM_SPELL_SORTBY] = {
1429     "by casting letter",
1430     "alphabetically",
1431     "by level, low to high",
1432     "by level, high to low",
1433     "by skill group, alphabetized within each group",
1434     "by skill group, low to high level within group",
1435     "by skill group, high to low level within group",
1436     "maintain current ordering",
1437     /* a menu choice rather than a sort choice */
1438     "reassign casting letters to retain current order",
1439 };
1440 static int spl_sortmode = 0;   /* index into spl_sortchoices[] */
1441 static int *spl_orderindx = 0; /* array of spl_book[] indices */
1442 
1443 /* qsort callback routine */
1444 STATIC_PTR int CFDECLSPEC
spell_cmp(vptr1,vptr2)1445 spell_cmp(vptr1, vptr2)
1446 const genericptr vptr1;
1447 const genericptr vptr2;
1448 {
1449     /*
1450      * gather up all of the possible parameters except spell name
1451      * in advance, even though some might not be needed:
1452      *  indx. = spl_orderindx[] index into spl_book[];
1453      *  otyp. = spl_book[] index into objects[];
1454      *  levl. = spell level;
1455      *  skil. = skill group aka spell class.
1456      */
1457     int indx1 = *(int *) vptr1, indx2 = *(int *) vptr2,
1458         otyp1 = spl_book[indx1].sp_id, otyp2 = spl_book[indx2].sp_id,
1459         levl1 = objects[otyp1].oc_level, levl2 = objects[otyp2].oc_level,
1460         skil1 = objects[otyp1].oc_skill, skil2 = objects[otyp2].oc_skill;
1461 
1462     switch (spl_sortmode) {
1463     case SORTBY_LETTER:
1464         return indx1 - indx2;
1465     case SORTBY_ALPHA:
1466         break;
1467     case SORTBY_LVL_LO:
1468         if (levl1 != levl2)
1469             return levl1 - levl2;
1470         break;
1471     case SORTBY_LVL_HI:
1472         if (levl1 != levl2)
1473             return levl2 - levl1;
1474         break;
1475     case SORTBY_SKL_AL:
1476         if (skil1 != skil2)
1477             return skil1 - skil2;
1478         break;
1479     case SORTBY_SKL_LO:
1480         if (skil1 != skil2)
1481             return skil1 - skil2;
1482         if (levl1 != levl2)
1483             return levl1 - levl2;
1484         break;
1485     case SORTBY_SKL_HI:
1486         if (skil1 != skil2)
1487             return skil1 - skil2;
1488         if (levl1 != levl2)
1489             return levl2 - levl1;
1490         break;
1491     case SORTBY_CURRENT:
1492     default:
1493         return (vptr1 < vptr2) ? -1
1494                                : (vptr1 > vptr2); /* keep current order */
1495     }
1496     /* tie-breaker for most sorts--alphabetical by spell name */
1497     return strcmpi(OBJ_NAME(objects[otyp1]), OBJ_NAME(objects[otyp2]));
1498 }
1499 
1500 /* sort the index used for display order of the "view known spells"
1501    list (sortmode == SORTBY_xxx), or sort the spellbook itself to make
1502    the current display order stick (sortmode == SORTRETAINORDER) */
1503 STATIC_OVL void
sortspells()1504 sortspells()
1505 {
1506     int i;
1507 #if defined(SYSV) || defined(DGUX)
1508     unsigned n;
1509 #else
1510     int n;
1511 #endif
1512 
1513     if (spl_sortmode == SORTBY_CURRENT)
1514         return;
1515     for (n = 0; n < MAXSPELL && spellid(n) != NO_SPELL; ++n)
1516         continue;
1517     if (n < 2)
1518         return; /* not enough entries to need sorting */
1519 
1520     if (!spl_orderindx) {
1521         /* we haven't done any sorting yet; list is in casting order */
1522         if (spl_sortmode == SORTBY_LETTER /* default */
1523             || spl_sortmode == SORTRETAINORDER)
1524             return;
1525         /* allocate enough for full spellbook rather than just N spells */
1526         spl_orderindx = (int *) alloc(MAXSPELL * sizeof(int));
1527         for (i = 0; i < MAXSPELL; i++)
1528             spl_orderindx[i] = i;
1529     }
1530 
1531     if (spl_sortmode == SORTRETAINORDER) {
1532         struct spell tmp_book[MAXSPELL];
1533 
1534         /* sort spl_book[] rather than spl_orderindx[];
1535            this also updates the index to reflect the new ordering (we
1536            could just free it since that ordering becomes the default) */
1537         for (i = 0; i < MAXSPELL; i++)
1538             tmp_book[i] = spl_book[spl_orderindx[i]];
1539         for (i = 0; i < MAXSPELL; i++)
1540             spl_book[i] = tmp_book[i], spl_orderindx[i] = i;
1541         spl_sortmode = SORTBY_LETTER; /* reset */
1542         return;
1543     }
1544 
1545     /* usual case, sort the index rather than the spells themselves */
1546     qsort((genericptr_t) spl_orderindx, n, sizeof *spl_orderindx, spell_cmp);
1547     return;
1548 }
1549 
1550 /* called if the [sort spells] entry in the view spells menu gets chosen */
1551 STATIC_OVL boolean
spellsortmenu()1552 spellsortmenu()
1553 {
1554     winid tmpwin;
1555     menu_item *selected;
1556     anything any;
1557     char let;
1558     int i, n, choice;
1559 
1560     tmpwin = create_nhwindow(NHW_MENU);
1561     start_menu(tmpwin);
1562     any = zeroany; /* zero out all bits */
1563 
1564     for (i = 0; i < SIZE(spl_sortchoices); i++) {
1565         if (i == SORTRETAINORDER) {
1566             let = 'z'; /* assumes fewer than 26 sort choices... */
1567             /* separate final choice from others with a blank line */
1568             any.a_int = 0;
1569             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
1570                      MENU_UNSELECTED);
1571         } else {
1572             let = 'a' + i;
1573         }
1574         any.a_int = i + 1;
1575         add_menu(tmpwin, NO_GLYPH, &any, let, 0, ATR_NONE, spl_sortchoices[i],
1576                  (i == spl_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
1577     }
1578     end_menu(tmpwin, "View known spells list sorted");
1579 
1580     n = select_menu(tmpwin, PICK_ONE, &selected);
1581     destroy_nhwindow(tmpwin);
1582     if (n > 0) {
1583         choice = selected[0].item.a_int - 1;
1584         /* skip preselected entry if we have more than one item chosen */
1585         if (n > 1 && choice == spl_sortmode)
1586             choice = selected[1].item.a_int - 1;
1587         free((genericptr_t) selected);
1588         spl_sortmode = choice;
1589         return TRUE;
1590     }
1591     return FALSE;
1592 }
1593 
1594 /* the '+' command -- view known spells */
1595 int
dovspell()1596 dovspell()
1597 {
1598     char qbuf[QBUFSZ];
1599     int splnum, othnum;
1600     struct spell spl_tmp;
1601 
1602     if (spellid(0) == NO_SPELL) {
1603         You("don't know any spells right now.");
1604     } else {
1605         while (dospellmenu("Currently known spells",
1606                            SPELLMENU_VIEW, &splnum)) {
1607             if (splnum == SPELLMENU_SORT) {
1608                 if (spellsortmenu())
1609                     sortspells();
1610             } else {
1611                 Sprintf(qbuf, "Reordering spells; swap '%c' with",
1612                         spellet(splnum));
1613                 if (!dospellmenu(qbuf, splnum, &othnum))
1614                     break;
1615 
1616                 spl_tmp = spl_book[splnum];
1617                 spl_book[splnum] = spl_book[othnum];
1618                 spl_book[othnum] = spl_tmp;
1619             }
1620         }
1621     }
1622     if (spl_orderindx) {
1623         free((genericptr_t) spl_orderindx);
1624         spl_orderindx = 0;
1625     }
1626     spl_sortmode = SORTBY_LETTER; /* 0 */
1627     return 0;
1628 }
1629 
1630 STATIC_OVL boolean
dospellmenu(prompt,splaction,spell_no)1631 dospellmenu(prompt, splaction, spell_no)
1632 const char *prompt;
1633 int splaction; /* SPELLMENU_CAST, SPELLMENU_VIEW, or spl_book[] index */
1634 int *spell_no;
1635 {
1636     winid tmpwin;
1637     int i, n, how, splnum;
1638     char buf[BUFSZ], retentionbuf[24];
1639     const char *fmt;
1640     menu_item *selected;
1641     anything any;
1642 
1643     tmpwin = create_nhwindow(NHW_MENU);
1644     start_menu(tmpwin);
1645     any = zeroany; /* zero out all bits */
1646 
1647     /*
1648      * The correct spacing of the columns when not using
1649      * tab separation depends on the following:
1650      * (1) that the font is monospaced, and
1651      * (2) that selection letters are pre-pended to the
1652      * given string and are of the form "a - ".
1653      */
1654     if (!iflags.menu_tab_sep) {
1655         Sprintf(buf, "%-20s     Level %-12s Fail Retention", "    Name",
1656                 "Category");
1657         fmt = "%-20s  %2d   %-12s %3d%% %9s";
1658     } else {
1659         Sprintf(buf, "Name\tLevel\tCategory\tFail\tRetention");
1660         fmt = "%s\t%-d\t%s\t%-d%%\t%s";
1661     }
1662     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf,
1663              MENU_UNSELECTED);
1664     for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) {
1665         splnum = !spl_orderindx ? i : spl_orderindx[i];
1666         Sprintf(buf, fmt, spellname(splnum), spellev(splnum),
1667                 spelltypemnemonic(spell_skilltype(spellid(splnum))),
1668                 100 - percent_success(splnum),
1669                 spellretention(splnum, retentionbuf));
1670 
1671         any.a_int = splnum + 1; /* must be non-zero */
1672         add_menu(tmpwin, NO_GLYPH, &any, spellet(splnum), 0, ATR_NONE, buf,
1673                  (splnum == splaction) ? MENU_SELECTED : MENU_UNSELECTED);
1674     }
1675     how = PICK_ONE;
1676     if (splaction == SPELLMENU_VIEW) {
1677         if (spellid(1) == NO_SPELL) {
1678             /* only one spell => nothing to swap with */
1679             how = PICK_NONE;
1680         } else {
1681             /* more than 1 spell, add an extra menu entry */
1682             any.a_int = SPELLMENU_SORT + 1;
1683             add_menu(tmpwin, NO_GLYPH, &any, '+', 0, ATR_NONE,
1684                      "[sort spells]", MENU_UNSELECTED);
1685         }
1686     }
1687     end_menu(tmpwin, prompt);
1688 
1689     n = select_menu(tmpwin, how, &selected);
1690     destroy_nhwindow(tmpwin);
1691     if (n > 0) {
1692         *spell_no = selected[0].item.a_int - 1;
1693         /* menu selection for `PICK_ONE' does not
1694            de-select any preselected entry */
1695         if (n > 1 && *spell_no == splaction)
1696             *spell_no = selected[1].item.a_int - 1;
1697         free((genericptr_t) selected);
1698         /* default selection of preselected spell means that
1699            user chose not to swap it with anything */
1700         if (*spell_no == splaction)
1701             return FALSE;
1702         return TRUE;
1703     } else if (splaction >= 0) {
1704         /* explicit de-selection of preselected spell means that
1705            user is still swapping but not for the current spell */
1706         *spell_no = splaction;
1707         return TRUE;
1708     }
1709     return FALSE;
1710 }
1711 
1712 STATIC_OVL int
percent_success(spell)1713 percent_success(spell)
1714 int spell;
1715 {
1716     /* Intrinsic and learned ability are combined to calculate
1717      * the probability of player's success at cast a given spell.
1718      */
1719     int chance, splcaster, special, statused;
1720     int difficulty;
1721     int skill;
1722 
1723     /* Calculate intrinsic ability (splcaster) */
1724 
1725     splcaster = urole.spelbase;
1726     special = urole.spelheal;
1727     statused = ACURR(urole.spelstat);
1728 
1729     if (uarm && is_metallic(uarm))
1730         splcaster += (uarmc && uarmc->otyp == ROBE) ? urole.spelarmr / 2
1731                                                     : urole.spelarmr;
1732     else if (uarmc && uarmc->otyp == ROBE)
1733         splcaster -= urole.spelarmr;
1734     if (uarms)
1735         splcaster += urole.spelshld;
1736 
1737     if (uarmh && is_metallic(uarmh) && uarmh->otyp != HELM_OF_BRILLIANCE)
1738         splcaster += uarmhbon;
1739     if (uarmg && is_metallic(uarmg))
1740         splcaster += uarmgbon;
1741     if (uarmf && is_metallic(uarmf))
1742         splcaster += uarmfbon;
1743 
1744     if (spellid(spell) == urole.spelspec)
1745         splcaster += urole.spelsbon;
1746 
1747     /* `healing spell' bonus */
1748     if (spellid(spell) == SPE_HEALING || spellid(spell) == SPE_EXTRA_HEALING
1749         || spellid(spell) == SPE_CURE_BLINDNESS
1750         || spellid(spell) == SPE_CURE_SICKNESS
1751         || spellid(spell) == SPE_RESTORE_ABILITY
1752         || spellid(spell) == SPE_REMOVE_CURSE)
1753         splcaster += special;
1754 
1755     if (splcaster > 20)
1756         splcaster = 20;
1757 
1758     /* Calculate learned ability */
1759 
1760     /* Players basic likelihood of being able to cast any spell
1761      * is based of their `magic' statistic. (Int or Wis)
1762      */
1763     chance = 11 * statused / 2;
1764 
1765     /*
1766      * High level spells are harder.  Easier for higher level casters.
1767      * The difficulty is based on the hero's level and their skill level
1768      * in that spell type.
1769      */
1770     skill = P_SKILL(spell_skilltype(spellid(spell)));
1771     skill = max(skill, P_UNSKILLED) - 1; /* unskilled => 0 */
1772     difficulty =
1773         (spellev(spell) - 1) * 4 - ((skill * 6) + (u.ulevel / 3) + 1);
1774 
1775     if (difficulty > 0) {
1776         /* Player is too low level or unskilled. */
1777         chance -= isqrt(900 * difficulty + 2000);
1778     } else {
1779         /* Player is above level.  Learning continues, but the
1780          * law of diminishing returns sets in quickly for
1781          * low-level spells.  That is, a player quickly gains
1782          * no advantage for raising level.
1783          */
1784         int learning = 15 * -difficulty / spellev(spell);
1785         chance += learning > 20 ? 20 : learning;
1786     }
1787 
1788     /* Clamp the chance: >18 stat and advanced learning only help
1789      * to a limit, while chances below "hopeless" only raise the
1790      * specter of overflowing 16-bit ints (and permit wearing a
1791      * shield to raise the chances :-).
1792      */
1793     if (chance < 0)
1794         chance = 0;
1795     if (chance > 120)
1796         chance = 120;
1797 
1798     /* Wearing anything but a light shield makes it very awkward
1799      * to cast a spell.  The penalty is not quite so bad for the
1800      * player's role-specific spell.
1801      */
1802     if (uarms && weight(uarms) > (int) objects[SMALL_SHIELD].oc_weight) {
1803         if (spellid(spell) == urole.spelspec) {
1804             chance /= 2;
1805         } else {
1806             chance /= 4;
1807         }
1808     }
1809 
1810     /* Finally, chance (based on player intell/wisdom and level) is
1811      * combined with ability (based on player intrinsics and
1812      * encumbrances).  No matter how intelligent/wise and advanced
1813      * a player is, intrinsics and encumbrance can prevent casting;
1814      * and no matter how able, learning is always required.
1815      */
1816     chance = chance * (20 - splcaster) / 15 - splcaster;
1817 
1818     /* Clamp to percentile */
1819     if (chance > 100)
1820         chance = 100;
1821     if (chance < 0)
1822         chance = 0;
1823 
1824     return chance;
1825 }
1826 
1827 STATIC_OVL char *
spellretention(idx,outbuf)1828 spellretention(idx, outbuf)
1829 int idx;
1830 char *outbuf;
1831 {
1832     long turnsleft, percent, accuracy;
1833     int skill;
1834 
1835     skill = P_SKILL(spell_skilltype(spellid(idx)));
1836     skill = max(skill, P_UNSKILLED); /* restricted same as unskilled */
1837     turnsleft = spellknow(idx);
1838     *outbuf = '\0'; /* lint suppression */
1839 
1840     if (turnsleft < 1L) {
1841         /* spell has expired; hero can't successfully cast it anymore */
1842         Strcpy(outbuf, "(gone)");
1843     } else if (turnsleft >= (long) KEEN) {
1844         /* full retention, first turn or immediately after reading book */
1845         Strcpy(outbuf, "100%");
1846     } else {
1847         /*
1848          * Retention is displayed as a range of percentages of
1849          * amount of time left until memory of the spell expires;
1850          * the precision of the range depends upon hero's skill
1851          * in this spell.
1852          *    expert:  2% intervals; 1-2,   3-4,  ...,   99-100;
1853          *   skilled:  5% intervals; 1-5,   6-10, ...,   95-100;
1854          *     basic: 10% intervals; 1-10, 11-20, ...,   91-100;
1855          * unskilled: 25% intervals; 1-25, 26-50, 51-75, 76-100.
1856          *
1857          * At the low end of each range, a value of N% really means
1858          * (N-1)%+1 through N%; so 1% is "greater than 0, at most 200".
1859          * KEEN is a multiple of 100; KEEN/100 loses no precision.
1860          */
1861         percent = (turnsleft - 1L) / ((long) KEEN / 100L) + 1L;
1862         accuracy =
1863             (skill == P_EXPERT) ? 2L : (skill == P_SKILLED)
1864                                            ? 5L
1865                                            : (skill == P_BASIC) ? 10L : 25L;
1866         /* round up to the high end of this range */
1867         percent = accuracy * ((percent - 1L) / accuracy + 1L);
1868         Sprintf(outbuf, "%ld%%-%ld%%", percent - accuracy + 1L, percent);
1869     }
1870     return outbuf;
1871 }
1872 
1873 /* Learn a spell during creation of the initial inventory */
1874 void
initialspell(obj)1875 initialspell(obj)
1876 struct obj *obj;
1877 {
1878     int i, otyp = obj->otyp;
1879 
1880     for (i = 0; i < MAXSPELL; i++)
1881         if (spellid(i) == NO_SPELL || spellid(i) == otyp)
1882             break;
1883 
1884     if (i == MAXSPELL) {
1885         impossible("Too many spells memorized!");
1886     } else if (spellid(i) != NO_SPELL) {
1887         /* initial inventory shouldn't contain duplicate spellbooks */
1888         impossible("Spell %s already known.", OBJ_NAME(objects[otyp]));
1889     } else {
1890         spl_book[i].sp_id = otyp;
1891         spl_book[i].sp_lev = objects[otyp].oc_level;
1892         incrnknow(i, 0);
1893     }
1894     return;
1895 }
1896 
1897 /*spell.c*/
1898