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