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