1 /* NetHack 3.6 spell.c $NHDT-Date: 1450584420 2015/12/20 04:07:00 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.75 $ */
2 /* Copyright (c) M. Stephenson 1988 */
3 /* NetHack may be freely redistributed. See license for details. */
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 */
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) */
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))
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)))
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
,
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));
48 /* The roles[] table lists the role-specific values for tuning
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
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.
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
87 * See percent_success() below for more comments.
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).
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 */
100 /* since the spellbook itself doesn't blow up, don't say just "explodes" */
101 static const char explodes
[] = "radiates explosive energy";
103 /* convert a letter into a number in the range 0..51, or -1 if not a letter */
105 spell_let_to_idx(ilet
)
111 if (indx
>= 0 && indx
< 26)
114 if (indx
>= 0 && indx
< 26)
119 /* TRUE: book should be destroyed by caller */
125 int lev
= objects
[bp
->otyp
].oc_level
;
130 You_feel("a wrenching sensation.");
131 tele(); /* teleport him */
134 You_feel("threatened.");
138 make_blinded(Blinded
+ rn1(100, 250), TRUE
);
144 pline("These runes were just too much to comprehend.");
145 make_confused(HConfusion
+ rn1(7, 16), FALSE
);
148 pline_The("book was coated with contact poison!");
150 erode_obj(uarmg
, "gloves", ERODE_CORRODE
, EF_GREASE
| EF_VERBOSE
);
153 /* temp disable in_use; death should not destroy the book */
154 was_in_use
= bp
->in_use
;
156 losestr(Poison_resistance
? rn1(2, 1) : rn1(4, 3));
157 losehp(rnd(Poison_resistance
? 6 : 10), "contact-poisoned spellbook",
159 bp
->in_use
= was_in_use
;
163 shieldeff(u
.ux
, u
.uy
);
164 pline_The("book %s, but you are unharmed!", explodes
);
166 pline("As you read the book, it %s in your %s!", explodes
,
168 dmg
= 2 * rnd(10) + 5;
169 losehp(Maybe_Half_Phys(dmg
), "exploding rune", KILLED_BY_AN
);
179 /* study while confused: returns TRUE if the book is destroyed */
181 confused_book(spellbook
)
182 struct obj
*spellbook
;
184 boolean gone
= FALSE
;
186 if (!rn2(3) && spellbook
->otyp
!= SPE_BOOK_OF_THE_DEAD
) {
187 spellbook
->in_use
= TRUE
; /* in case called from learn */
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
)
198 You("find yourself reading the %s line over and over again.",
199 spellbook
== context
.spbook
.book
? "next" : "first");
204 /* special effects for The Book of the Dead */
209 struct monst
*mtmp
, *mtmp2
;
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" */
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
,
222 pline_The("runes appear scrambled. You can't read them!");
226 if (!u
.uhave
.bell
|| !u
.uhave
.menorah
) {
227 pline("A chill runs down your %s.", body_part(SPINE
));
229 You_hear("a faint chime...");
230 if (!u
.uhave
.menorah
)
231 pline("Vlad's doppelganger is amused.");
235 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
236 if (otmp
->otyp
== CANDELABRUM_OF_INVOCATION
&& otmp
->spe
== 7
243 if (otmp
->otyp
== BELL_OF_OPENING
244 && (moves
- otmp
->age
) < 5L) { /* you rang it recently */
253 pline_The("invocation fails!");
254 pline("At least one of your artifacts is cursed...");
255 } else if (arti1_primed
&& arti2_primed
) {
257 (unsigned) d(2, 6); /* time til next intervene() */
259 /* successful invocation */
261 u
.uevent
.invoked
= 1;
262 /* in case you haven't killed the Wizard yet, behave as if
264 u
.uevent
.udemigod
= 1; /* wizdead() */
265 if (!u
.udg_cnt
|| u
.udg_cnt
> soon
)
267 } else { /* at least one artifact not prepared properly */
268 You("have a feeling that %s is amiss...", something
);
274 /* when not an invocation situation */
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
,
282 || (mtmp
= makemon(&mons
[PM_NALFESHNEE
], u
.ux
, u
.uy
,
283 NO_MINVENT
)) != 0)) {
287 /* next handle the affect on things you're carrying */
288 (void) unturn_dead(&youmonst
);
289 /* last place some monsters around you */
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
))
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)
305 if (mtmp
->mtame
< 20)
308 (void) tamedog(mtmp
, (struct obj
*) 0);
310 monflee(mtmp
, 0, FALSE
, TRUE
);
316 Your("ancestors are annoyed with you!");
319 pline_The("headstones in the cemetery begin to move!");
322 pline("Oh my! Your name appears in the book!");
328 /* 'book' has just become cursed; if we're reading it and realize it is
329 now cursed, interrupt */
334 if (occupation
== learn
&& context
.spbook
.book
== book
335 && book
->cursed
&& book
->bknown
&& multi
>= 0)
345 boolean costly
= TRUE
;
346 struct obj
*book
= context
.spbook
.book
;
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";
358 context
.spbook
.delay
= 0;
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 */
366 exercise(A_WIS
, TRUE
); /* you're studying. */
367 booktype
= book
->otyp
;
368 if (booktype
== SPE_BOOK_OF_THE_DEAD
) {
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
)
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
);
392 } else { /* spellknow(i) <= KEEN/10 */
393 Your("knowledge of %s is %s.", splname
,
394 spellknow(i
) ? "keener" : "restored");
397 exercise(A_WIS
, TRUE
); /* extra study */
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
);
413 spl_book
[i
].sp_id
= booktype
;
414 spl_book
[i
].sp_lev
= objects
[booktype
].oc_level
;
417 You(i
> 0 ? "add %s to your repertoire." : "learn %s.", splname
);
419 makeknown((int) booktype
);
422 if (book
->cursed
) { /* maybe a demon cursed it */
423 if (cursed_book(book
)) {
425 context
.spbook
.book
= 0;
426 context
.spbook
.o_id
= 0;
432 context
.spbook
.book
= 0;
433 context
.spbook
.o_id
= 0;
438 study_book(spellbook
)
439 register struct obj
*spellbook
;
441 int booktype
= spellbook
->otyp
;
442 boolean confused
= (Confusion
!= 0);
443 boolean too_hard
= FALSE
;
445 /* attempting to read dull book may make hero fall asleep */
446 if (!confused
&& !Sleep_resistance
447 && !strcmp(OBJ_DESCR(objects
[booktype
]), "dull")) {
449 int dullbook
= rnd(25) - ACURR(A_WIS
);
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
);
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.",
461 dullbook
+= rnd(2 * objects
[booktype
].oc_level
);
462 fall_asleep(-dullbook
, TRUE
);
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");
474 /* KMH -- Simplified this code */
475 if (booktype
== SPE_BLANK_PAPER
) {
476 pline("This spellbook is all blank.");
482 if (booktype
== SPE_NOVEL
) {
483 /* Obtain current Terry Pratchett book title */
484 const char *tribtitle
= noveltitle(&spellbook
->novelidx
);
486 if (read_tribute("books", tribtitle
, 0, (char *) 0, 0,
488 u
.uconduct
.literate
++;
489 check_unpaid(spellbook
);
491 if (!u
.uevent
.read_tribute
) {
492 /* give bonus of 20 xp and 4*20+0 pts */
493 more_experienced(20, 0);
495 u
.uevent
.read_tribute
= 1; /* only once */
501 switch (objects
[booktype
].oc_level
) {
504 context
.spbook
.delay
= -objects
[booktype
].oc_delay
;
508 context
.spbook
.delay
= -(objects
[booktype
].oc_level
- 1)
509 * objects
[booktype
].oc_delay
;
513 context
.spbook
.delay
=
514 -objects
[booktype
].oc_level
* objects
[booktype
].oc_delay
;
517 context
.spbook
.delay
= -8 * objects
[booktype
].oc_delay
;
520 impossible("Unknown spellbook level %d, book %d;",
521 objects
[booktype
].oc_level
, booktype
);
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
) {
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);
536 /* only wizards know if a spell is too difficult */
537 if (Role_if(PM_WIZARD
) && read_ability
< 20 && !confused
) {
541 "This spellbook is %sdifficult to comprehend. Continue?",
542 (read_ability
< 12 ? "very " : ""));
543 if (yn(qbuf
) != 'y') {
544 spellbook
->in_use
= FALSE
;
548 /* its up to random luck now */
549 if (rnd(20) > read_ability
) {
556 boolean gone
= cursed_book(spellbook
);
558 nomul(context
.spbook
.delay
); /* study time */
559 multi_reason
= "reading a book";
561 context
.spbook
.delay
= 0;
562 if (gone
|| !rn2(3)) {
564 pline_The("spellbook crumbles to dust!");
565 if (!objects
[spellbook
->otyp
].oc_name_known
566 && !objects
[spellbook
->otyp
].oc_uname
)
570 spellbook
->in_use
= FALSE
;
572 } else if (confused
) {
573 if (!confused_book(spellbook
)) {
574 spellbook
->in_use
= FALSE
;
576 nomul(context
.spbook
.delay
);
577 multi_reason
= "reading a book";
579 context
.spbook
.delay
= 0;
582 spellbook
->in_use
= FALSE
;
584 You("begin to %s the runes.",
585 spellbook
->otyp
== SPE_BOOK_OF_THE_DEAD
? "recite" : "memorize");
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);
595 /* a spellbook has been destroyed or the character has changed levels;
596 the stored address for the current book is no longer valid */
601 if (obj
== context
.spbook
.book
) {
602 context
.spbook
.book
= (struct obj
*) 0;
603 context
.spbook
.o_id
= 0;
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 */
611 book_substitution(old_obj
, new_obj
)
612 struct obj
*old_obj
, *new_obj
;
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
;
621 /* called from moveloop() */
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.
632 for (i
= 0; i
< MAXSPELL
&& spellid(i
) != NO_SPELL
; i
++)
638 /* return True if spellcasting is inhibited;
639 only covers a small subset of reasons why casting won't work */
643 /* rejections which take place before selecting a particular spell */
645 You("are too impaired to cast a spell.");
647 } else if (!freehand()) {
648 /* Note: !freehand() occurs when weapon and shield (or two-handed
649 * weapon) are welded to hands, so "arms" probably doesn't need
650 * to be makeplural(bodypart(ARM)).
652 * But why isn't lack of free arms (for gesturing) an issue when
653 * poly'd hero has no limbs?
655 Your("arms are not free to cast!");
662 * Return TRUE if a spell was picked, with the spell index in the return
663 * parameter. Otherwise return FALSE.
670 char ilet
, lets
[BUFSZ
], qbuf
[QBUFSZ
];
672 if (spellid(0) == NO_SPELL
) {
673 You("don't know any spells right now.");
677 return FALSE
; /* no spell chosen */
679 if (flags
.menu_style
== MENU_TRADITIONAL
) {
680 /* we know there is at least 1 known spell */
681 for (nspells
= 1; nspells
< MAXSPELL
&& spellid(nspells
) != NO_SPELL
;
687 else if (nspells
< 27)
688 Sprintf(lets
, "a-%c", 'a' + nspells
- 1);
689 else if (nspells
== 27)
690 Sprintf(lets
, "a-zA");
691 /* this assumes that there are at most 52 spells... */
693 Sprintf(lets
, "a-zA-%c", 'A' + nspells
- 27);
696 Sprintf(qbuf
, "Cast which spell? [%s *?]", lets
);
697 ilet
= yn_function(qbuf
, (char *) 0, '\0');
698 if (ilet
== '*' || ilet
== '?')
699 break; /* use menu mode */
700 if (index(quitchars
, ilet
))
703 idx
= spell_let_to_idx(ilet
);
704 if (idx
< 0 || idx
>= nspells
) {
705 You("don't know that spell.");
706 continue; /* ask again */
712 return dospellmenu("Choose which spell to cast", SPELLMENU_CAST
,
716 /* the 'Z' command -- cast a spell */
722 if (getspell(&spell_no
))
723 return spelleffects(spell_no
, FALSE
);
727 STATIC_OVL
const char *
728 spelltypemnemonic(skill
)
734 case P_HEALING_SPELL
:
736 case P_DIVINATION_SPELL
:
738 case P_ENCHANTMENT_SPELL
:
739 return "enchantment";
747 impossible("Unknown spell skill, %d;", skill
);
753 spell_skilltype(booktype
)
756 return objects
[booktype
].oc_skill
;
762 int l
= u
.ulevel
, loglev
= 0,
763 gain
, natac
= u
.uac
+ u
.uspellprot
;
764 /* note: u.uspellprot is subtracted when find_ac() factors it into u.uac,
765 so adding here factors it back out
766 (versions prior to 3.6 had this backwards) */
768 /* loglev=log2(u.ulevel)+1 (1..5) */
774 /* The more u.uspellprot you already have, the less you get,
775 * and the better your natural ac, the less you get.
777 * LEVEL AC SPELLPROT from successive SPE_PROTECTION casts
781 * 2-3 10 0, 2, 4, 5, 6, 7, 8
782 * 2-3 0 0, 2, 4, 5, 6
784 * 4-7 10 0, 3, 6, 8, 9, 10, 11, 12
785 * 4-7 0 0, 3, 5, 7, 8, 9
787 * 7-15 -10 0, 3, 5, 6
788 * 8-15 10 0, 4, 7, 10, 12, 13, 14, 15, 16
789 * 8-15 0 0, 4, 7, 9, 10, 11, 12
790 * 8-15 -10 0, 4, 6, 7, 8
791 * 16-30 10 0, 5, 9, 12, 14, 16, 17, 18, 19, 20
792 * 16-30 0 0, 5, 9, 11, 13, 14, 15
793 * 16-30 -10 0, 5, 8, 9, 10
795 natac
= (10 - natac
) / 10; /* convert to positive and scale down */
796 gain
= loglev
- (int) u
.uspellprot
/ (4 - min(3, natac
));
801 const char *hgolden
= hcolor(NH_GOLDEN
), *atmosphere
;
804 pline_The("%s haze around you becomes more dense.", hgolden
);
806 rmtyp
= levl
[u
.ux
][u
.uy
].typ
;
807 atmosphere
= u
.uswallow
808 ? ((u
.ustuck
->data
== &mons
[PM_FOG_CLOUD
])
810 : is_whirly(u
.ustuck
->data
)
812 : is_animal(u
.ustuck
->data
)
824 pline_The("%s around you begins to shimmer with %s haze.",
825 atmosphere
, an(hgolden
));
828 u
.uspellprot
+= gain
;
829 u
.uspmtime
= (P_SKILL(spell_skilltype(SPE_PROTECTION
)) == P_EXPERT
)
832 u
.usptime
= u
.uspmtime
;
835 Your("skin feels warm for a moment.");
839 /* attempting to cast a forgotten spell will cause disorientation */
841 spell_backfire(spell
)
844 long duration
= (long) ((spellev(spell
) + 1) * 3), /* 6..24 */
845 old_stun
= (HStun
& TIMEOUT
), old_conf
= (HConfusion
& TIMEOUT
);
847 /* Prior to 3.4.1, only effect was confusion; it still predominates.
849 * 3.6.0: this used to override pre-existing confusion duration
850 * (cases 0..8) and pre-existing stun duration (cases 4..9);
851 * increase them instead. (Hero can no longer cast spells while
852 * Stunned, so the potential increment to stun duration here is
853 * just hypothetical.)
860 make_confused(old_conf
+ duration
, FALSE
); /* 40% */
865 make_confused(old_conf
+ 2L * duration
/ 3L, FALSE
); /* 30% */
866 make_stunned(old_stun
+ duration
/ 3L, FALSE
);
870 make_stunned(old_stun
+ 2L * duration
/ 3L, FALSE
); /* 20% */
871 make_confused(old_conf
+ duration
/ 3L, FALSE
);
874 make_stunned(old_stun
+ duration
, FALSE
); /* 10% */
881 spelleffects(spell
, atme
)
885 int energy
, damage
, chance
, n
, intell
;
886 int skill
, role_skill
;
887 boolean confused
= (Confusion
!= 0);
888 boolean physical_damage
= FALSE
;
893 * Reject attempting to cast while stunned or with no free hands.
894 * Already done in getspell() to stop casting before choosing
895 * which spell, but duplicated here for cases where spelleffects()
896 * gets called directly for ^T without intrinsic teleport capability
897 * or #turn for non-priest/non-knight.
898 * (There's no duplication of messages; when the rejection takes
899 * place in getspell(), we don't get called.)
901 if (rejectcasting()) {
902 return 0; /* no time elapses */
906 * Spell casting no longer affects knowledge of the spell. A
907 * decrement of spell knowledge is done every turn.
909 if (spellknow(spell
) <= 0) {
910 Your("knowledge of this spell is twisted.");
911 pline("It invokes nightmarish images in your mind...");
912 spell_backfire(spell
);
914 } else if (spellknow(spell
) <= KEEN
/ 200) { /* 100 turns left */
915 You("strain to recall the spell.");
916 } else if (spellknow(spell
) <= KEEN
/ 40) { /* 500 turns left */
917 You("have difficulty remembering the spell.");
918 } else if (spellknow(spell
) <= KEEN
/ 20) { /* 1000 turns left */
919 Your("knowledge of this spell is growing faint.");
920 } else if (spellknow(spell
) <= KEEN
/ 10) { /* 2000 turns left */
921 Your("recall of this spell is gradually fading.");
923 energy
= (spellev(spell
) * 5); /* 5 <= energy <= 35 */
925 if (u
.uhunger
<= 10 && spellid(spell
) != SPE_DETECT_FOOD
) {
926 You("are too hungry to cast that spell.");
928 } else if (ACURR(A_STR
) < 4 && spellid(spell
) != SPE_RESTORE_ABILITY
) {
929 You("lack the strength to cast spells.");
931 } else if (check_capacity(
932 "Your concentration falters while carrying so much stuff.")) {
936 if (u
.uhave
.amulet
) {
937 You_feel("the amulet draining your energy away.");
938 energy
+= rnd(2 * energy
);
940 if (energy
> u
.uen
) {
941 You("don't have enough energy to cast that spell.");
944 if (spellid(spell
) != SPE_DETECT_FOOD
) {
945 int hungr
= energy
* 2;
947 /* If hero is a wizard, their current intelligence
948 * (bonuses + temporary + current)
949 * affects hunger reduction in casting a spell.
950 * 1. int = 17-18 no reduction
951 * 2. int = 16 1/4 hungr
952 * 3. int = 15 1/2 hungr
953 * 4. int = 1-14 normal reduction
954 * The reason for this is:
955 * a) Intelligence affects the amount of exertion
957 * b) Wizards have spent their life at magic and
958 * understand quite well how to cast spells.
960 intell
= acurr(A_INT
);
961 if (!Role_if(PM_WIZARD
))
982 /* don't put player (quite) into fainting from
983 * casting a spell, particularly since they might
984 * not even be hungry at the beginning; however,
985 * this is low enough that they must eat before
986 * casting anything else except detect food
988 if (hungr
> u
.uhunger
- 3)
989 hungr
= u
.uhunger
- 3;
994 chance
= percent_success(spell
);
995 if (confused
|| (rnd(100) > chance
)) {
996 You("fail to cast the spell correctly.");
1004 exercise(A_WIS
, TRUE
);
1005 /* pseudo is a temporary "false" object containing the spell stats */
1006 pseudo
= mksobj(spellid(spell
), FALSE
, FALSE
);
1007 pseudo
->blessed
= pseudo
->cursed
= 0;
1008 pseudo
->quan
= 20L; /* do not let useup get it */
1010 * Find the skill the hero has in a spell type category.
1011 * See spell_skilltype for categories.
1013 skill
= spell_skilltype(pseudo
->otyp
);
1014 role_skill
= P_SKILL(skill
);
1016 switch (pseudo
->otyp
) {
1018 * At first spells act as expected. As the hero increases in skill
1019 * with the appropriate spell type, some spells increase in their
1020 * effects, e.g. more damage, further distance, and so on, without
1021 * additional cost to the spellcaster.
1024 case SPE_CONE_OF_COLD
:
1025 if (role_skill
>= P_SKILLED
) {
1031 if (!u
.dx
&& !u
.dy
&& !u
.dz
) {
1032 if ((damage
= zapyourself(pseudo
, TRUE
)) != 0) {
1034 Sprintf(buf
, "zapped %sself with a spell",
1036 losehp(damage
, buf
, NO_KILLER_PREFIX
);
1040 pseudo
->otyp
- SPE_MAGIC_MISSILE
+ 10,
1041 spell_damage_bonus(u
.ulevel
/ 2 + 1), 0,
1042 (pseudo
->otyp
== SPE_CONE_OF_COLD
)
1046 u
.dx
= cc
.x
+ rnd(3) - 2;
1047 u
.dy
= cc
.y
+ rnd(3) - 2;
1048 if (!isok(u
.dx
, u
.dy
) || !cansee(u
.dx
, u
.dy
)
1049 || IS_STWALL(levl
[u
.dx
][u
.dy
].typ
) || u
.uswallow
) {
1050 /* Spell is reflected back to center */
1057 } /* else fall through... */
1059 /* these spells are all duplicates of wand effects */
1060 case SPE_FORCE_BOLT
:
1061 physical_damage
= TRUE
;
1064 case SPE_MAGIC_MISSILE
:
1066 case SPE_SLOW_MONSTER
:
1067 case SPE_WIZARD_LOCK
:
1069 case SPE_TURN_UNDEAD
:
1071 case SPE_TELEPORT_AWAY
:
1072 case SPE_CANCELLATION
:
1073 case SPE_FINGER_OF_DEATH
:
1075 case SPE_DETECT_UNSEEN
:
1077 case SPE_EXTRA_HEALING
:
1078 case SPE_DRAIN_LIFE
:
1079 case SPE_STONE_TO_FLESH
:
1080 if (!(objects
[pseudo
->otyp
].oc_dir
== NODIR
)) {
1082 u
.dx
= u
.dy
= u
.dz
= 0;
1083 } else if (!getdir((char *) 0)) {
1084 /* getdir cancelled, re-use previous direction */
1086 * FIXME: reusing previous direction only makes sense
1087 * if there is an actual previous direction. When there
1088 * isn't one, the spell gets cast at self which is rarely
1089 * what the player intended. Unfortunately, the way
1090 * spelleffects() is organized means that aborting with
1091 * "nevermind" is not an option.
1093 pline_The("magical energy is released!");
1095 if (!u
.dx
&& !u
.dy
&& !u
.dz
) {
1096 if ((damage
= zapyourself(pseudo
, TRUE
)) != 0) {
1099 Sprintf(buf
, "zapped %sself with a spell", uhim());
1100 if (physical_damage
)
1101 damage
= Maybe_Half_Phys(damage
);
1102 losehp(damage
, buf
, NO_KILLER_PREFIX
);
1108 update_inventory(); /* spell may modify inventory */
1111 /* these are all duplicates of scroll effects */
1112 case SPE_REMOVE_CURSE
:
1113 case SPE_CONFUSE_MONSTER
:
1114 case SPE_DETECT_FOOD
:
1115 case SPE_CAUSE_FEAR
:
1117 /* high skill yields effect equivalent to blessed scroll */
1118 if (role_skill
>= P_SKILLED
)
1119 pseudo
->blessed
= 1;
1121 case SPE_CHARM_MONSTER
:
1122 case SPE_MAGIC_MAPPING
:
1123 case SPE_CREATE_MONSTER
:
1124 (void) seffects(pseudo
);
1127 /* these are all duplicates of potion effects */
1128 case SPE_HASTE_SELF
:
1129 case SPE_DETECT_TREASURE
:
1130 case SPE_DETECT_MONSTERS
:
1131 case SPE_LEVITATION
:
1132 case SPE_RESTORE_ABILITY
:
1133 /* high skill yields effect equivalent to blessed potion */
1134 if (role_skill
>= P_SKILLED
)
1135 pseudo
->blessed
= 1;
1137 case SPE_INVISIBILITY
:
1138 (void) peffects(pseudo
);
1140 /* end of potion-like spells */
1142 case SPE_CURE_BLINDNESS
:
1143 healup(0, 0, FALSE
, TRUE
);
1145 case SPE_CURE_SICKNESS
:
1147 You("are no longer ill.");
1149 make_slimed(0L, "The slime disappears!");
1150 healup(0, 0, TRUE
, FALSE
);
1152 case SPE_CREATE_FAMILIAR
:
1153 (void) make_familiar((struct obj
*) 0, u
.ux
, u
.uy
, FALSE
);
1155 case SPE_CLAIRVOYANCE
:
1156 if (!BClairvoyant
) {
1157 if (role_skill
>= P_SKILLED
)
1158 pseudo
->blessed
= 1; /* detect monsters as well as map */
1159 do_vicinity_map(pseudo
);
1160 /* at present, only one thing blocks clairvoyance */
1161 } else if (uarmh
&& uarmh
->otyp
== CORNUTHAUM
)
1162 You("sense a pointy hat on top of your %s.", body_part(HEAD
));
1164 case SPE_PROTECTION
:
1168 if (!jump(max(role_skill
, 1)))
1169 pline1(nothing_happens
);
1172 impossible("Unknown spell %d attempted.", spell
);
1173 obfree(pseudo
, (struct obj
*) 0);
1177 /* gain skill for successful cast */
1178 use_skill(skill
, spellev(spell
));
1180 obfree(pseudo
, (struct obj
*) 0); /* now, get rid of it */
1186 spell_aim_step(arg
, x
, y
)
1187 genericptr_t arg UNUSED
;
1192 if (!ZAP_POS(levl
[x
][y
].typ
)
1193 && !(IS_DOOR(levl
[x
][y
].typ
) && (levl
[x
][y
].doormask
& D_ISOPEN
)))
1198 /* Choose location where spell takes effect. */
1206 pline("You're joking! In this weather?");
1208 } else if (Is_waterlevel(&u
.uz
)) {
1209 You("had better wait for the sun to come out.");
1213 pline("Where do you want to cast the spell?");
1216 if (getpos(&cc
, TRUE
, "the desired position") < 0)
1217 return 0; /* user pressed ESC */
1218 /* The number of moves from hero to where the spell drops.*/
1219 if (distmin(u
.ux
, u
.uy
, cc
.x
, cc
.y
) > 10) {
1220 pline_The("spell dissipates over the distance!");
1222 } else if (u
.uswallow
) {
1223 pline_The("spell is cut short!");
1224 exercise(A_WIS
, FALSE
); /* What were you THINKING! */
1228 } else if ((!cansee(cc
.x
, cc
.y
)
1229 && (!(mtmp
= m_at(cc
.x
, cc
.y
)) || !canspotmon(mtmp
)))
1230 || IS_STWALL(levl
[cc
.x
][cc
.y
].typ
)) {
1231 Your("mind fails to lock onto that location!");
1238 walk_path(&uc
, &cc
, spell_aim_step
, (genericptr_t
) 0);
1245 /* forget a random selection of known spells due to amnesia;
1246 they used to be lost entirely, as if never learned, but now we
1247 just set the memory retention to zero so that they can't be cast */
1253 /* in case reading has been interrupted earlier, discard context */
1254 context
.spbook
.book
= 0;
1255 context
.spbook
.o_id
= 0;
1256 /* count the number of known spells */
1257 for (n
= 0; n
< MAXSPELL
; ++n
)
1258 if (spellid(n
) == NO_SPELL
)
1261 /* lose anywhere from zero to all known spells;
1262 if confused, use the worse of two die rolls */
1269 /* good Luck might ameliorate spell loss */
1270 if (nzap
> 1 && !rnl(7))
1274 * Forget 'nzap' out of 'n' known spells by setting their memory
1275 * retention to zero. Every spell has the same probability to be
1276 * forgotten, even if its retention is already zero.
1278 * Perhaps we should forget the corresponding book too?
1280 * (3.4.3 removed spells entirely from the list, but always did
1281 * so from its end, so the 'nzap' most recently learned spells
1282 * were the ones lost by default. Player had sort control over
1283 * the list, so could move the most useful spells to front and
1284 * only lose them if 'nzap' turned out to be a large value.
1286 * Discarding from the end of the list had the virtue of making
1287 * casting letters for lost spells become invalid and retaining
1288 * the original letter for the ones which weren't lost, so there
1289 * was no risk to the player of accidentally casting the wrong
1290 * spell when using a letter that was in use prior to amnesia.
1291 * That wouldn't be the case if we implemented spell loss spread
1292 * throughout the list of known spells; every spell located past
1293 * the first lost spell would end up with new letter assigned.)
1295 for (i
= 0; nzap
> 0; ++i
) {
1296 /* when nzap is small relative to the number of spells left,
1297 the chance to lose spell [i] is small; as the number of
1298 remaining candidates shrinks, the chance per candidate
1299 gets bigger; overall, exactly nzap entries are affected */
1300 if (rn2(n
- i
) < nzap
) {
1301 /* lose access to spell [i] */
1304 /* also forget its book */
1305 forget_single_object(spellid(i
));
1307 /* and abuse wisdom */
1308 exercise(A_WIS
, FALSE
);
1309 /* there's now one less spell slated to be forgotten */
1316 * Allow player to sort the list of known spells. Manually swapping
1317 * pairs of them becomes very tedious once the list reaches two pages.
1319 * Possible extensions:
1320 * provide means for player to control ordering of skill classes;
1321 * provide means to supply value N such that first N entries stick
1322 * while rest of list is being sorted;
1323 * make chosen sort order be persistent such that when new spells
1324 * are learned, they get inserted into sorted order rather than be
1325 * appended to the end of the list?
1327 static const char *spl_sortchoices
[] = {
1328 "by casting letter",
1329 #define SORTBY_LETTER 0
1331 #define SORTBY_ALPHA 1
1332 "by level, low to high",
1333 #define SORTBY_LVL_LO 2
1334 "by level, high to low",
1335 #define SORTBY_LVL_HI 3
1336 "by skill group, alphabetized within each group",
1337 #define SORTBY_SKL_AL 4
1338 "by skill group, low to high level within group",
1339 #define SORTBY_SKL_LO 5
1340 "by skill group, high to low level within group",
1341 #define SORTBY_SKL_HI 6
1342 "maintain current ordering",
1343 #define SORTBY_CURRENT 7
1344 /* a menu choice rather than a sort choice */
1345 "reassign casting letters to retain current order",
1346 #define SORTRETAINORDER 8
1348 static int spl_sortmode
= 0; /* index into spl_sortchoices[] */
1349 static int *spl_orderindx
= 0; /* array of spl_book[] indices */
1351 /* qsort callback routine */
1352 STATIC_PTR
int CFDECLSPEC
1353 spell_cmp(vptr1
, vptr2
)
1354 const genericptr vptr1
;
1355 const genericptr vptr2
;
1358 * gather up all of the possible parameters except spell name
1359 * in advance, even though some might not be needed:
1360 * indx. = spl_orderindx[] index into spl_book[];
1361 * otyp. = spl_book[] index into objects[];
1362 * levl. = spell level;
1363 * skil. = skill group aka spell class.
1365 int indx1
= *(int *) vptr1
, indx2
= *(int *) vptr2
,
1366 otyp1
= spl_book
[indx1
].sp_id
, otyp2
= spl_book
[indx2
].sp_id
,
1367 levl1
= objects
[otyp1
].oc_level
, levl2
= objects
[otyp2
].oc_level
,
1368 skil1
= objects
[otyp1
].oc_skill
, skil2
= objects
[otyp2
].oc_skill
;
1370 switch (spl_sortmode
) {
1372 return indx1
- indx2
;
1377 return levl1
- levl2
;
1381 return levl2
- levl1
;
1385 return skil1
- skil2
;
1389 return skil1
- skil2
;
1391 return levl1
- levl2
;
1395 return skil1
- skil2
;
1397 return levl2
- levl1
;
1399 case SORTBY_CURRENT
:
1401 return (vptr1
< vptr2
) ? -1
1402 : (vptr1
> vptr2
); /* keep current order */
1404 /* tie-breaker for most sorts--alphabetical by spell name */
1405 return strcmpi(OBJ_NAME(objects
[otyp1
]), OBJ_NAME(objects
[otyp2
]));
1408 /* sort the index used for display order of the "view known spells"
1409 list (sortmode == SORTBY_xxx), or sort the spellbook itself to make
1410 the current display order stick (sortmode == SORTRETAINORDER) */
1415 #if defined(SYSV) || defined(DGUX)
1421 if (spl_sortmode
== SORTBY_CURRENT
)
1423 for (n
= 0; n
< MAXSPELL
&& spellid(n
) != NO_SPELL
; ++n
)
1426 return; /* not enough entries to need sorting */
1428 if (!spl_orderindx
) {
1429 /* we haven't done any sorting yet; list is in casting order */
1430 if (spl_sortmode
== SORTBY_LETTER
/* default */
1431 || spl_sortmode
== SORTRETAINORDER
)
1433 /* allocate enough for full spellbook rather than just N spells */
1434 spl_orderindx
= (int *) alloc(MAXSPELL
* sizeof(int));
1435 for (i
= 0; i
< MAXSPELL
; i
++)
1436 spl_orderindx
[i
] = i
;
1439 if (spl_sortmode
== SORTRETAINORDER
) {
1440 struct spell tmp_book
[MAXSPELL
];
1442 /* sort spl_book[] rather than spl_orderindx[];
1443 this also updates the index to reflect the new ordering (we
1444 could just free it since that ordering becomes the default) */
1445 for (i
= 0; i
< MAXSPELL
; i
++)
1446 tmp_book
[i
] = spl_book
[spl_orderindx
[i
]];
1447 for (i
= 0; i
< MAXSPELL
; i
++)
1448 spl_book
[i
] = tmp_book
[i
], spl_orderindx
[i
] = i
;
1449 spl_sortmode
= SORTBY_LETTER
; /* reset */
1453 /* usual case, sort the index rather than the spells themselves */
1454 qsort((genericptr_t
) spl_orderindx
, n
, sizeof *spl_orderindx
, spell_cmp
);
1458 /* called if the [sort spells] entry in the view spells menu gets chosen */
1463 menu_item
*selected
;
1468 tmpwin
= create_nhwindow(NHW_MENU
);
1470 any
= zeroany
; /* zero out all bits */
1472 for (i
= 0; i
< SIZE(spl_sortchoices
); i
++) {
1473 if (i
== SORTRETAINORDER
) {
1474 let
= 'z'; /* assumes fewer than 26 sort choices... */
1475 /* separate final choice from others with a blank line */
1477 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "",
1483 add_menu(tmpwin
, NO_GLYPH
, &any
, let
, 0, ATR_NONE
, spl_sortchoices
[i
],
1484 (i
== spl_sortmode
) ? MENU_SELECTED
: MENU_UNSELECTED
);
1486 end_menu(tmpwin
, "View known spells list sorted");
1488 n
= select_menu(tmpwin
, PICK_ONE
, &selected
);
1489 destroy_nhwindow(tmpwin
);
1491 choice
= selected
[0].item
.a_int
- 1;
1492 /* skip preselected entry if we have more than one item chosen */
1493 if (n
> 1 && choice
== spl_sortmode
)
1494 choice
= selected
[1].item
.a_int
- 1;
1495 free((genericptr_t
) selected
);
1496 spl_sortmode
= choice
;
1502 /* the '+' command -- view known spells */
1508 struct spell spl_tmp
;
1510 if (spellid(0) == NO_SPELL
) {
1511 You("don't know any spells right now.");
1513 while (dospellmenu("Currently known spells",
1514 SPELLMENU_VIEW
, &splnum
)) {
1515 if (splnum
== SPELLMENU_SORT
) {
1516 if (spellsortmenu())
1519 Sprintf(qbuf
, "Reordering spells; swap '%c' with",
1521 if (!dospellmenu(qbuf
, splnum
, &othnum
))
1524 spl_tmp
= spl_book
[splnum
];
1525 spl_book
[splnum
] = spl_book
[othnum
];
1526 spl_book
[othnum
] = spl_tmp
;
1530 if (spl_orderindx
) {
1531 free((genericptr_t
) spl_orderindx
);
1534 spl_sortmode
= SORTBY_LETTER
; /* 0 */
1539 dospellmenu(prompt
, splaction
, spell_no
)
1541 int splaction
; /* SPELLMENU_CAST, SPELLMENU_VIEW, or spl_book[] index */
1545 int i
, n
, how
, splnum
;
1546 char buf
[BUFSZ
], retentionbuf
[24];
1548 menu_item
*selected
;
1551 tmpwin
= create_nhwindow(NHW_MENU
);
1553 any
= zeroany
; /* zero out all bits */
1556 * The correct spacing of the columns when not using
1557 * tab separation depends on the following:
1558 * (1) that the font is monospaced, and
1559 * (2) that selection letters are pre-pended to the
1560 * given string and are of the form "a - ".
1562 if (!iflags
.menu_tab_sep
) {
1563 Sprintf(buf
, "%-20s Level %-12s Fail Retention", " Name",
1565 fmt
= "%-20s %2d %-12s %3d%% %9s";
1567 Sprintf(buf
, "Name\tLevel\tCategory\tFail\tRetention");
1568 fmt
= "%s\t%-d\t%s\t%-d%%\t%s";
1570 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
, buf
,
1572 for (i
= 0; i
< MAXSPELL
&& spellid(i
) != NO_SPELL
; i
++) {
1573 splnum
= !spl_orderindx
? i
: spl_orderindx
[i
];
1574 Sprintf(buf
, fmt
, spellname(splnum
), spellev(splnum
),
1575 spelltypemnemonic(spell_skilltype(spellid(splnum
))),
1576 100 - percent_success(splnum
),
1577 spellretention(splnum
, retentionbuf
));
1579 any
.a_int
= splnum
+ 1; /* must be non-zero */
1580 add_menu(tmpwin
, NO_GLYPH
, &any
, spellet(splnum
), 0, ATR_NONE
, buf
,
1581 (splnum
== splaction
) ? MENU_SELECTED
: MENU_UNSELECTED
);
1584 if (splaction
== SPELLMENU_VIEW
) {
1585 if (spellid(1) == NO_SPELL
) {
1586 /* only one spell => nothing to swap with */
1589 /* more than 1 spell, add an extra menu entry */
1590 any
.a_int
= SPELLMENU_SORT
+ 1;
1591 add_menu(tmpwin
, NO_GLYPH
, &any
, '+', 0, ATR_NONE
,
1592 "[sort spells]", MENU_UNSELECTED
);
1595 end_menu(tmpwin
, prompt
);
1597 n
= select_menu(tmpwin
, how
, &selected
);
1598 destroy_nhwindow(tmpwin
);
1600 *spell_no
= selected
[0].item
.a_int
- 1;
1601 /* menu selection for `PICK_ONE' does not
1602 de-select any preselected entry */
1603 if (n
> 1 && *spell_no
== splaction
)
1604 *spell_no
= selected
[1].item
.a_int
- 1;
1605 free((genericptr_t
) selected
);
1606 /* default selection of preselected spell means that
1607 user chose not to swap it with anything */
1608 if (*spell_no
== splaction
)
1611 } else if (splaction
>= 0) {
1612 /* explicit de-selection of preselected spell means that
1613 user is still swapping but not for the current spell */
1614 *spell_no
= splaction
;
1621 percent_success(spell
)
1624 /* Intrinsic and learned ability are combined to calculate
1625 * the probability of player's success at cast a given spell.
1627 int chance
, splcaster
, special
, statused
;
1631 /* Calculate intrinsic ability (splcaster) */
1633 splcaster
= urole
.spelbase
;
1634 special
= urole
.spelheal
;
1635 statused
= ACURR(urole
.spelstat
);
1637 if (uarm
&& is_metallic(uarm
))
1638 splcaster
+= (uarmc
&& uarmc
->otyp
== ROBE
) ? urole
.spelarmr
/ 2
1640 else if (uarmc
&& uarmc
->otyp
== ROBE
)
1641 splcaster
-= urole
.spelarmr
;
1643 splcaster
+= urole
.spelshld
;
1645 if (uarmh
&& is_metallic(uarmh
) && uarmh
->otyp
!= HELM_OF_BRILLIANCE
)
1646 splcaster
+= uarmhbon
;
1647 if (uarmg
&& is_metallic(uarmg
))
1648 splcaster
+= uarmgbon
;
1649 if (uarmf
&& is_metallic(uarmf
))
1650 splcaster
+= uarmfbon
;
1652 if (spellid(spell
) == urole
.spelspec
)
1653 splcaster
+= urole
.spelsbon
;
1655 /* `healing spell' bonus */
1656 if (spellid(spell
) == SPE_HEALING
|| spellid(spell
) == SPE_EXTRA_HEALING
1657 || spellid(spell
) == SPE_CURE_BLINDNESS
1658 || spellid(spell
) == SPE_CURE_SICKNESS
1659 || spellid(spell
) == SPE_RESTORE_ABILITY
1660 || spellid(spell
) == SPE_REMOVE_CURSE
)
1661 splcaster
+= special
;
1666 /* Calculate learned ability */
1668 /* Players basic likelihood of being able to cast any spell
1669 * is based of their `magic' statistic. (Int or Wis)
1671 chance
= 11 * statused
/ 2;
1674 * High level spells are harder. Easier for higher level casters.
1675 * The difficulty is based on the hero's level and their skill level
1676 * in that spell type.
1678 skill
= P_SKILL(spell_skilltype(spellid(spell
)));
1679 skill
= max(skill
, P_UNSKILLED
) - 1; /* unskilled => 0 */
1681 (spellev(spell
) - 1) * 4 - ((skill
* 6) + (u
.ulevel
/ 3) + 1);
1683 if (difficulty
> 0) {
1684 /* Player is too low level or unskilled. */
1685 chance
-= isqrt(900 * difficulty
+ 2000);
1687 /* Player is above level. Learning continues, but the
1688 * law of diminishing returns sets in quickly for
1689 * low-level spells. That is, a player quickly gains
1690 * no advantage for raising level.
1692 int learning
= 15 * -difficulty
/ spellev(spell
);
1693 chance
+= learning
> 20 ? 20 : learning
;
1696 /* Clamp the chance: >18 stat and advanced learning only help
1697 * to a limit, while chances below "hopeless" only raise the
1698 * specter of overflowing 16-bit ints (and permit wearing a
1699 * shield to raise the chances :-).
1706 /* Wearing anything but a light shield makes it very awkward
1707 * to cast a spell. The penalty is not quite so bad for the
1708 * player's role-specific spell.
1710 if (uarms
&& weight(uarms
) > (int) objects
[SMALL_SHIELD
].oc_weight
) {
1711 if (spellid(spell
) == urole
.spelspec
) {
1718 /* Finally, chance (based on player intell/wisdom and level) is
1719 * combined with ability (based on player intrinsics and
1720 * encumbrances). No matter how intelligent/wise and advanced
1721 * a player is, intrinsics and encumbrance can prevent casting;
1722 * and no matter how able, learning is always required.
1724 chance
= chance
* (20 - splcaster
) / 15 - splcaster
;
1726 /* Clamp to percentile */
1736 spellretention(idx
, outbuf
)
1740 long turnsleft
, percent
, accuracy
;
1743 skill
= P_SKILL(spell_skilltype(spellid(idx
)));
1744 skill
= max(skill
, P_UNSKILLED
); /* restricted same as unskilled */
1745 turnsleft
= spellknow(idx
);
1746 *outbuf
= '\0'; /* lint suppression */
1748 if (turnsleft
< 1L) {
1749 /* spell has expired; hero can't successfully cast it anymore */
1750 Strcpy(outbuf
, "(gone)");
1751 } else if (turnsleft
>= (long) KEEN
) {
1752 /* full retention, first turn or immediately after reading book */
1753 Strcpy(outbuf
, "100%");
1756 * Retention is displayed as a range of percentages of
1757 * amount of time left until memory of the spell expires;
1758 * the precision of the range depends upon hero's skill
1760 * expert: 2% intervals; 1-2, 3-4, ..., 99-100;
1761 * skilled: 5% intervals; 1-5, 6-10, ..., 95-100;
1762 * basic: 10% intervals; 1-10, 11-20, ..., 91-100;
1763 * unskilled: 25% intervals; 1-25, 26-50, 51-75, 76-100.
1765 * At the low end of each range, a value of N% really means
1766 * (N-1)%+1 through N%; so 1% is "greater than 0, at most 200".
1767 * KEEN is a multiple of 100; KEEN/100 loses no precision.
1769 percent
= (turnsleft
- 1L) / ((long) KEEN
/ 100L) + 1L;
1771 (skill
== P_EXPERT
) ? 2L : (skill
== P_SKILLED
)
1773 : (skill
== P_BASIC
) ? 10L : 25L;
1774 /* round up to the high end of this range */
1775 percent
= accuracy
* ((percent
- 1L) / accuracy
+ 1L);
1776 Sprintf(outbuf
, "%ld%%-%ld%%", percent
- accuracy
+ 1L, percent
);
1781 /* Learn a spell during creation of the initial inventory */
1786 int i
, otyp
= obj
->otyp
;
1788 for (i
= 0; i
< MAXSPELL
; i
++)
1789 if (spellid(i
) == NO_SPELL
|| spellid(i
) == otyp
)
1792 if (i
== MAXSPELL
) {
1793 impossible("Too many spells memorized!");
1794 } else if (spellid(i
) != NO_SPELL
) {
1795 /* initial inventory shouldn't contain duplicate spellbooks */
1796 impossible("Spell %s already known.", OBJ_NAME(objects
[otyp
]));
1798 spl_book
[i
].sp_id
= otyp
;
1799 spl_book
[i
].sp_lev
= objects
[otyp
].oc_level
;