root/trunk/src/cmd5.c

Revision 918, 13.9 kB (checked in by takkaria, 4 months ago)

Use consistent newlines everywhere, and also set the svn:eol-style property to native on all text files.

  • Property svn:eol-style set to native
Line 
1 /*
2  * File: cmd5.c
3  * Purpose: Spell and prayer casting/praying
4  *
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  *
7  * This work is free software; you can redistribute it and/or modify it
8  * under the terms of either:
9  *
10  * a) the GNU General Public License as published by the Free Software
11  *    Foundation, version 2, or
12  *
13  * b) the "Angband licence":
14  *    This software may be copied and distributed for educational, research,
15  *    and not for profit purposes provided that this copyright and statement
16  *    are included in all such copies.  Other copyrights may also apply.
17  */
18 #include "angband.h"
19 #include "tvalsval.h"
20
21
22 /*
23  * Returns chance of failure for a spell
24  */
25 s16b spell_chance(int spell)
26 {
27         int chance, minfail;
28
29         const magic_type *s_ptr;
30
31
32         /* Paranoia -- must be literate */
33         if (!cp_ptr->spell_book) return (100);
34
35         /* Get the spell */
36         s_ptr = &mp_ptr->info[spell];
37
38         /* Extract the base spell failure rate */
39         chance = s_ptr->sfail;
40
41         /* Reduce failure rate by "effective" level adjustment */
42         chance -= 3 * (p_ptr->lev - s_ptr->slevel);
43
44         /* Reduce failure rate by INT/WIS adjustment */
45         chance -= adj_mag_stat[p_ptr->stat_ind[cp_ptr->spell_stat]];
46
47         /* Not enough mana to cast */
48         if (s_ptr->smana > p_ptr->csp)
49         {
50                 chance += 5 * (s_ptr->smana - p_ptr->csp);
51         }
52
53         /* Extract the minimum failure rate */
54         minfail = adj_mag_fail[p_ptr->stat_ind[cp_ptr->spell_stat]];
55
56         /* Non mage/priest characters never get better than 5 percent */
57         if (!(cp_ptr->flags & CF_ZERO_FAIL))
58         {
59                 if (minfail < 5) minfail = 5;
60         }
61
62         /* Priest prayer penalty for "edged" weapons (before minfail) */
63         if (p_ptr->icky_wield)
64         {
65                 chance += 25;
66         }
67
68         /* Minimum failure rate */
69         if (chance < minfail) chance = minfail;
70
71         /* Stunning makes spells harder (after minfail) */
72         if (p_ptr->timed[TMD_STUN] > 50) chance += 25;
73         else if (p_ptr->timed[TMD_STUN]) chance += 15;
74
75         /* Amnesia makes spells fail half the time */
76         if (p_ptr->timed[TMD_AMNESIA]) chance *= 2;
77
78         /* Always a 5 percent chance of working */
79         if (chance > 95) chance = 95;
80
81         /* Return the chance */
82         return (chance);
83 }
84
85
86
87 /*
88  * Determine if a spell is "okay" for the player to cast or study
89  * The spell must be legible, not forgotten, and also, to cast,
90  * it must be known, and to study, it must not be known.
91  * When browsing a book, all legible spells are okay.
92  */
93 bool spell_okay(int spell, bool known, bool browse)
94 {
95         const magic_type *s_ptr;
96
97         /* Get the spell */
98         s_ptr = &mp_ptr->info[spell];
99
100         /* Spell is illegible */
101         if (s_ptr->slevel >= 99) return (FALSE);
102
103         /* Spell is too hard */
104         if (s_ptr->slevel > p_ptr->lev) return (browse);
105
106         /* Spell is forgotten */
107         if (p_ptr->spell_flags[spell] & PY_SPELL_FORGOTTEN)
108         {
109                 /* Never okay */
110                 return (!browse);
111         }
112
113         /* Spell is learned */
114         if (p_ptr->spell_flags[spell] & PY_SPELL_LEARNED)
115         {
116                 /* Okay to cast or browse, not to study */
117                 return (known || browse);
118         }
119
120         /* Okay to study or browse, not to cast */
121         return (!known || browse);
122 }
123
124
125 /*
126  * Print a list of spells (for browsing or casting or viewing).
127  */
128 static void print_spells(const byte *spells, int num, int y, int x)
129 {
130         int i, spell;
131
132         const magic_type *s_ptr;
133
134         char help[20];
135         char out_val[160];
136
137         const char *comment = help;
138
139         byte line_attr;
140
141         /* Title the list */
142         prt("", y, x);
143         put_str("Name", y, x + 5);
144         put_str("Lv Mana Fail Info", y, x + 35);
145
146         /* Dump the spells */
147         for (i = 0; i < num; i++)
148         {
149                 /* Get the spell index */
150                 spell = spells[i];
151
152                 /* Get the spell info */
153                 s_ptr = &mp_ptr->info[spell];
154
155                 /* Skip illegible spells */
156                 if (s_ptr->slevel >= 99)
157                 {
158                         strnfmt(out_val, sizeof(out_val), "  %c) %-30s", I2A(i), "(illegible)");
159                         c_prt(TERM_L_DARK, out_val, y + i + 1, x);
160                         continue;
161                 }
162
163                 /* Get extra info */
164                 get_spell_info(cp_ptr->spell_book, spell, help, sizeof(help));
165
166                 /* Assume spell is known and tried */
167                 comment = help;
168                 line_attr = TERM_WHITE;
169
170                 /* Analyze the spell */
171                 if (p_ptr->spell_flags[spell] & PY_SPELL_FORGOTTEN)
172                 {
173                         comment = " forgotten";
174                         line_attr = TERM_YELLOW;
175                 }
176                 else if (!(p_ptr->spell_flags[spell] & PY_SPELL_LEARNED))
177                 {
178                         if (s_ptr->slevel <= p_ptr->lev)
179                         {
180                                 comment = " unknown";
181                                 line_attr = TERM_L_BLUE;
182                         }
183                         else
184                         {
185                                 comment = " difficult";
186                                 line_attr = TERM_RED;
187                         }
188                 }
189                 else if (!(p_ptr->spell_flags[spell] & PY_SPELL_WORKED))
190                 {
191                         comment = " untried";
192                         line_attr = TERM_L_GREEN;
193                 }
194
195                 /* Dump the spell --(-- */
196                 strnfmt(out_val, sizeof(out_val), "  %c) %-30s%2d %4d %3d%%%s",
197                         I2A(i), get_spell_name(cp_ptr->spell_book, spell),
198                         s_ptr->slevel, s_ptr->smana, spell_chance(spell), comment);
199                 c_prt(line_attr, out_val, y + i + 1, x);
200         }
201
202         /* Clear the bottom line */
203         prt("", y + i + 1, x);
204 }
205
206
207
208 /*
209  * Allow user to choose a spell/prayer from the given book.
210  *
211  * Returns -1 if the user hits escape.
212  * Returns -2 if there are no legal choices.
213  * Returns a valid spell otherwise.
214  *
215  * The "prompt" should be "cast", "recite", "study", or "browse"
216  * The "known" should be TRUE for cast/pray, FALSE for study
217  * The "browse" should be TRUE for browse, FALSE for cast/pray/study
218  */
219 int get_spell(const object_type *o_ptr, cptr prompt, bool known, bool browse)
220 {
221         int i;
222
223         int spell;
224         int num = 0;
225
226         byte spells[PY_MAX_SPELLS];
227
228         bool verify;
229
230         bool flag, redraw, okay;
231         char choice;
232
233         const magic_type *s_ptr;
234
235         char out_val[160];
236
237         cptr p = ((cp_ptr->spell_book == TV_MAGIC_BOOK) ? "spell" : "prayer");
238
239         int result;
240
241         /* Get the spell, if available */
242         if (repeat_pull(&result))
243         {
244                 /* Verify the spell */
245                 if (spell_okay(result, known, browse))
246                 {
247                         /* Success */
248                         return (result);
249                 }
250                 else
251                 {
252                         /* Invalid repeat - reset it */
253                         repeat_clear();
254                 }
255         }
256
257         /* Extract spells */
258         for (i = 0; i < SPELLS_PER_BOOK; i++)
259         {
260                 spell = get_spell_index(o_ptr, i);
261
262                 /* Collect this spell */
263                 if (spell != -1) spells[num++] = spell;
264         }
265
266         /* Assume no usable spells */
267         okay = FALSE;
268
269         /* Check for "okay" spells */
270         for (i = 0; i < num; i++)
271         {
272                 /* Look for "okay" spells */
273                 if (spell_okay(spells[i], known, browse)) okay = TRUE;
274         }
275
276         /* No available spells */
277         if (!okay) return (-2);
278
279
280         /* Nothing chosen yet */
281         flag = FALSE;
282
283         /* No redraw yet */
284         redraw = FALSE;
285
286         /* Hack -- when browsing a book, start with list shown */
287         if (browse || OPT(show_lists))
288         {
289                 /* Show list */
290                 redraw = TRUE;
291
292                 /* Save screen */
293                 screen_save();
294
295                 /* Display a list of spells */
296                 print_spells(spells, num, 1, 20);
297         }
298
299         /* Build a prompt (accept all spells) */
300         strnfmt(out_val, sizeof(out_val), "(%^ss a-%c%s, ESC=exit) %^s which %s? ",
301                 p, I2A(num - 1), (OPT(show_lists) ? "" : ", *=List"), prompt, p);
302
303         /* Get a spell from the user */
304         while (!flag && get_com(out_val, &choice))
305         {
306                 /* Request redraw */
307                 if (!OPT(show_lists) &&
308                     ((choice == ' ') || (choice == '*') || (choice == '?')))
309                 {
310                         /* Hide the list */
311                         if (redraw)
312                         {
313                                 /* Load screen */
314                                 screen_load();
315
316                                 /* Hide list */
317                                 redraw = FALSE;
318                         }
319
320                         /* Show the list */
321                         else
322                         {
323                                 /* Show list */
324                                 redraw = TRUE;
325
326                                 /* Save screen */
327                                 screen_save();
328
329                                 /* Display a list of spells */
330                                 print_spells(spells, num, 1, 20);
331                         }
332
333                         /* Ask again */
334                         continue;
335                 }
336
337
338                 /* Note verify */
339                 verify = (isupper((unsigned char)choice) ? TRUE : FALSE);
340
341                 /* Lowercase */
342                 choice = tolower((unsigned char)choice);
343
344                 /* Extract request */
345                 i = (islower((unsigned char)choice) ? A2I(choice) : -1);
346
347                 /* Totally Illegal */
348                 if ((i < 0) || (i >= num))
349                 {
350                         bell("Illegal spell choice!");
351                         continue;
352                 }
353
354                 /* Save the spell index */
355                 spell = spells[i];
356
357                 /* Require "okay" spells */
358                 if (!spell_okay(spell, known, browse))
359                 {
360                         bell("Illegal spell choice!");
361                         msg_format("You may not %s that %s.", prompt, p);
362                         continue;
363                 }
364
365                 /* Verify it */
366                 if (verify)
367                 {
368                         char tmp_val[160];
369
370                         /* Get the spell */
371                         s_ptr = &mp_ptr->info[spell];
372
373                         /* Prompt */
374                         strnfmt(tmp_val, sizeof(tmp_val), "%^s %s (%d mana, %d%% fail)? ",
375                                 prompt, get_spell_name(cp_ptr->spell_book, spell),
376                                 s_ptr->smana, spell_chance(spell));
377
378                         /* Belay that order */
379                         if (!get_check(tmp_val)) continue;
380                 }
381
382                 /* Stop the loop */
383                 flag = TRUE;
384         }
385
386
387         /* Restore the screen */
388         if (redraw)
389         {
390                 /* Load screen */
391                 screen_load();
392         }
393
394
395         /* Abort if needed */
396         if (!flag) return (-1);
397
398         repeat_push(spell);
399
400         /* Success */
401         return (spell);
402 }
403
404
405
406 /*
407  * View the detailed description for a selected spell.
408  */
409 static void browse_spell(int spell)
410 {
411         const magic_type *s_ptr;
412
413         char out_val[160];
414         char help[20];
415
416         const char *comment = help;
417
418         byte line_attr;
419
420
421         /* Redirect output to the screen */
422         text_out_hook = text_out_to_screen;
423
424         /* Save the screen */
425         screen_save();
426
427         /* Get the magic and spell info */
428         s_ptr = &mp_ptr->info[spell];
429
430         /* Get extra info */
431         get_spell_info(cp_ptr->spell_book, spell, help, sizeof(help));
432
433         /* Assume spell is known and tried */
434         line_attr = TERM_WHITE;
435
436         /* Analyze the spell */
437         if (p_ptr->spell_flags[spell] & PY_SPELL_FORGOTTEN)
438         {
439                 comment = " forgotten";
440                 line_attr = TERM_YELLOW;
441         }
442         else if (!(p_ptr->spell_flags[spell] & PY_SPELL_LEARNED))
443         {
444                 if (s_ptr->slevel <= p_ptr->lev)
445                 {
446                         comment = " unknown";
447                         line_attr = TERM_L_BLUE;
448                 }
449                 else
450                 {
451                         comment = " difficult";
452                         line_attr = TERM_RED;
453                 }
454         }
455         else if (!(p_ptr->spell_flags[spell] & PY_SPELL_WORKED))
456         {
457                 comment = " untried";
458                 line_attr = TERM_L_GREEN;
459         }
460
461         /* Show spell name and comment (if any) on first line of screen */
462         if (streq(comment, ""))
463         {
464                 strnfmt(out_val, sizeof(out_val), "%^s",
465                     get_spell_name(cp_ptr->spell_book, spell));
466         }
467         else
468         {
469                 strnfmt(out_val, sizeof(out_val), "%^s (%s)",
470                     get_spell_name(cp_ptr->spell_book, spell),
471                     /* Hack -- skip leading space */
472                     ++comment);
473         }
474
475         /* Print, in colour */
476         text_out_c(line_attr, out_val);
477
478         /* Display the spell description */
479         text_out("\n\n   ");
480
481         text_out(s_text + s_info[(cp_ptr->spell_book == TV_MAGIC_BOOK) ? spell : spell + PY_MAX_SPELLS].text);
482         text_out_c(TERM_L_BLUE, "\n\n[Press any key to continue]\n");
483
484         /* Wait for input */
485         (void)anykey();
486
487         /* Load screen */
488         screen_load();
489 }
490
491
492 void do_cmd_browse_aux(const object_type *o_ptr)
493 {
494         int spell;
495
496
497         /* Track the object kind */
498         object_kind_track(o_ptr->k_idx);
499
500         /* Hack -- Handle stuff */
501         handle_stuff();
502
503
504         /* Continue to browse spells until player hits ESC */
505         while (1)
506         {
507                 /* Ask for a spell */
508                 spell = get_spell(o_ptr, "browse", TRUE, TRUE);
509                 if (spell < 0) break;
510
511                 /* Browse the spell */
512                 browse_spell(spell);
513         }
514 }
515
516
517 /*
518  * Choose a new spell from the book.
519  */
520 int spell_choose_new(const object_type *o_ptr)
521 {
522         int i, k = 0;
523         int gift = -1;
524        
525         cptr p = ((cp_ptr->spell_book == TV_MAGIC_BOOK) ? "spell" : "prayer");
526
527         /* Mage -- Learn a selected spell */
528         if (cp_ptr->flags & CF_CHOOSE_SPELLS)
529         {
530                 return get_spell(o_ptr, "study", FALSE, FALSE);
531         }
532
533         /* Extract spells */
534         for (i = 0; i < SPELLS_PER_BOOK; i++)
535         {
536                 int spell = get_spell_index(o_ptr, i);
537
538                 /* Skip non-OK spells */
539                 if (spell == -1) continue;
540                 if (!spell_okay(spell, FALSE, FALSE)) continue;
541
542                 /* Apply the randomizer */
543                 if ((++k > 1) && (randint0(k) != 0)) continue;
544
545                 /* Track it */
546                 gift = spell;
547         }
548
549         /* Nothing to study */
550         if (gift < 0)
551                 msg_format("You cannot learn any %ss in that book.", p);
552
553         return gift;
554 }
555
556 /*
557  * Learn the specified spell.
558  */
559 void spell_learn(int spell)
560 {
561         int i;
562         cptr p = ((cp_ptr->spell_book == TV_MAGIC_BOOK) ? "spell" : "prayer");
563
564         /* Learn the spell */
565         p_ptr->spell_flags[spell] |= PY_SPELL_LEARNED;
566
567         /* Find the next open entry in "spell_order[]" */
568         for (i = 0; i < PY_MAX_SPELLS; i++)
569         {
570                 /* Stop at the first empty space */
571                 if (p_ptr->spell_order[i] == 99) break;
572         }
573
574         /* Add the spell to the known list */
575         p_ptr->spell_order[i] = spell;
576
577         /* Mention the result */
578         message_format(MSG_STUDY, 0, "You have learned the %s of %s.",
579                    p, get_spell_name(cp_ptr->spell_book, spell));
580
581         /* One less spell available */
582         p_ptr->new_spells--;
583
584         /* Message if needed */
585         if (p_ptr->new_spells)
586         {
587                 /* Message */
588                 msg_format("You can learn %d more %s%s.",
589                            p_ptr->new_spells, p, PLURAL(p_ptr->new_spells));
590         }
591
592         /* Redraw Study Status */
593         p_ptr->redraw |= (PR_STUDY | PR_OBJECT);
594 }
595
596
597 /* Cas the specified spell */
598 bool spell_cast(int spell)
599 {
600         int chance;
601         const magic_type *s_ptr;
602
603     cptr p = ((cp_ptr->spell_book == TV_MAGIC_BOOK) ?
604                   "cast this spell" :
605                   "recite this prayer");
606
607
608         /* Get the spell */
609         s_ptr = &mp_ptr->info[spell];
610
611
612         /* Verify "dangerous" spells */
613         if (s_ptr->smana > p_ptr->csp)
614         {
615                 /* Warning */
616                 msg_format("You do not have enough mana to %s.", p);
617
618                 /* Flush input */
619                 flush();
620
621                 /* Verify */
622                 if (!get_check("Attempt it anyway? ")) return FALSE;
623         }
624
625
626         /* Spell failure chance */
627         chance = spell_chance(spell);
628
629         /* Failed spell */
630         if (randint0(100) < chance)
631         {
632                 if (flush_failure) flush();
633                 msg_print("You failed to concentrate hard enough!");
634         }
635
636         /* Process spell */
637         else
638         {
639                 /* Cast the spell */
640                 if (!cast_spell(cp_ptr->spell_book, spell)) return FALSE;
641
642                 /* A spell was cast */
643                 sound(MSG_SPELL);
644                 if (!(p_ptr->spell_flags[spell] & PY_SPELL_WORKED))
645                 {
646                         int e = s_ptr->sexp;
647
648                         /* The spell worked */
649                         p_ptr->spell_flags[spell] |= PY_SPELL_WORKED;
650
651                         /* Gain experience */
652                         gain_exp(e * s_ptr->slevel);
653
654                         /* Redraw object recall */
655                         p_ptr->redraw |= (PR_OBJECT);
656                 }
657         }
658
659         /* Sufficient mana */
660         if (s_ptr->smana <= p_ptr->csp)
661         {
662                 /* Use some mana */
663                 p_ptr->csp -= s_ptr->smana;
664         }
665
666         /* Over-exert the player */
667         else
668         {
669                 int oops = s_ptr->smana - p_ptr->csp;
670
671                 /* No mana left */
672                 p_ptr->csp = 0;
673                 p_ptr->csp_frac = 0;
674
675                 /* Message */
676                 msg_print("You faint from the effort!");
677
678                 /* Hack -- Bypass free action */
679                 (void)inc_timed(TMD_PARALYZED, randint1(5 * oops + 1));
680
681                 /* Damage CON (possibly permanently) */
682                 if (randint0(100) < 50)
683                 {
684                         bool perm = (randint0(100) < 25);
685
686                         /* Message */
687                         msg_print("You have damaged your health!");
688
689                         /* Reduce constitution */
690                         (void)dec_stat(A_CON, 15 + randint1(10), perm);
691                 }
692         }
693
694         /* Redraw mana */
695         p_ptr->redraw |= (PR_MANA);
696
697         return TRUE;
698 }
Note: See TracBrowser for help on using the browser.