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