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