1 /* File: effects.c */
2
3 /* Purpose: effects of various "objects" */
4
5 /*
6 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
7 *
8 * This software may be copied and distributed for educational, research, and
9 * not for profit purposes provided that this copyright and statement are
10 * included in all such copies.
11 */
12
13 #include "angband.h"
14
15 /*
16 * Set "p_ptr->blind", notice observable changes
17 */
set_blind(int v)18 static bool set_blind(int v)
19 {
20 bool notice = FALSE;
21
22 /* Hack -- Force good values */
23 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
24
25 /* Open */
26 if (v)
27 {
28 if (!p_ptr->tim.blind)
29 {
30 msgf("You are blind!");
31 notice = TRUE;
32
33 chg_virtue(V_ENLIGHTEN, -1);
34 }
35 }
36
37 /* Shut */
38 else
39 {
40 if (p_ptr->tim.blind)
41 {
42 msgf("You can see again.");
43 notice = TRUE;
44 }
45 }
46
47 /* Use the value */
48 p_ptr->tim.blind = v;
49
50 /* Redraw status bar */
51 p_ptr->redraw |= (PR_STATUS);
52
53 /* Nothing to notice */
54 if (!notice) return (FALSE);
55
56 /* Disturb */
57 if (disturb_state) disturb(FALSE);
58
59 /* Fully update the visuals - hack set torch to be radius 0 */
60 p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_TORCH);
61
62 /* Redraw map */
63 p_ptr->redraw |= (PR_MAP);
64
65 /* Redraw the "blind" */
66 p_ptr->redraw |= (PR_BLIND);
67
68 /* Window stuff */
69 p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
70
71 /* Handle stuff */
72 handle_stuff();
73
74 /* Result */
75 return (TRUE);
76 }
77
78 /*
79 * Increase the blind counter
80 */
inc_blind(int v)81 bool inc_blind(int v)
82 {
83 return(set_blind(p_ptr->tim.blind + v));
84 }
85
86 /*
87 * No more blindness
88 */
clear_blind(void)89 bool clear_blind(void)
90 {
91 return(set_blind(0));
92 }
93
94
95 /*
96 * Set "p_ptr->confused", notice observable changes
97 */
set_confused(int v)98 static bool set_confused(int v)
99 {
100 bool notice = FALSE;
101
102 /* Hack -- Force good values */
103 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
104
105 /* Open */
106 if (v)
107 {
108 if (!p_ptr->tim.confused)
109 {
110 msgf("You are confused!");
111 notice = TRUE;
112
113 chg_virtue(V_HARMONY, -1);
114 }
115 }
116
117 /* Shut */
118 else
119 {
120 if (p_ptr->tim.confused)
121 {
122 msgf("You feel less confused now.");
123 notice = TRUE;
124 }
125 }
126
127 /* Use the value */
128 p_ptr->tim.confused = v;
129
130 /* Redraw status bar */
131 p_ptr->redraw |= (PR_STATUS);
132
133 /* Nothing to notice */
134 if (!notice) return (FALSE);
135
136 /* Disturb */
137 if (disturb_state) disturb(FALSE);
138
139 /* Redraw the "confused" */
140 p_ptr->redraw |= (PR_CONFUSED);
141
142 /* Handle stuff */
143 handle_stuff();
144
145 /* Result */
146 return (TRUE);
147 }
148
149
150 /*
151 * Increase the confusion counter
152 */
inc_confused(int v)153 bool inc_confused(int v)
154 {
155 return(set_confused(p_ptr->tim.confused + v));
156 }
157
158
159 /*
160 * No more confusion
161 */
clear_confused(void)162 bool clear_confused(void)
163 {
164 return(set_confused(0));
165 }
166
167
168 /*
169 * Set "p_ptr->poisoned", notice observable changes
170 */
set_poisoned(int v)171 static bool set_poisoned(int v)
172 {
173 bool notice = FALSE;
174
175 /* Hack -- Force good values */
176 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
177
178 /* Open */
179 if (v)
180 {
181 if (!p_ptr->tim.poisoned)
182 {
183 msgf("You are poisoned!");
184 notice = TRUE;
185 }
186 }
187
188 /* Shut */
189 else
190 {
191 if (p_ptr->tim.poisoned)
192 {
193 msgf("You are no longer poisoned.");
194 notice = TRUE;
195 }
196 }
197
198 /* Use the value */
199 p_ptr->tim.poisoned = v;
200
201 /* Nothing to notice */
202 if (!notice) return (FALSE);
203
204 /* Disturb */
205 if (disturb_state) disturb(FALSE);
206
207 /* Redraw the "poisoned" */
208 p_ptr->redraw |= (PR_POISONED);
209
210 /* Handle stuff */
211 handle_stuff();
212
213 /* Result */
214 return (TRUE);
215 }
216
217 /*
218 * Increase the poison counter
219 */
inc_poisoned(int v)220 bool inc_poisoned(int v)
221 {
222 return(set_poisoned(p_ptr->tim.poisoned + v));
223 }
224
225
226 /*
227 * No more poison
228 */
clear_poisoned(void)229 bool clear_poisoned(void)
230 {
231 return(set_poisoned(0));
232 }
233
234
235 /*
236 * Set "p_ptr->afraid", notice observable changes
237 */
set_afraid(int v)238 static bool set_afraid(int v)
239 {
240 bool notice = FALSE;
241
242 /* Hack -- Force good values */
243 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
244
245 /* Open */
246 if (v)
247 {
248 if (!p_ptr->tim.afraid)
249 {
250 msgf("You are terrified!");
251 notice = TRUE;
252
253 chg_virtue(V_VALOUR, -1);
254 }
255 }
256
257 /* Shut */
258 else
259 {
260 if (p_ptr->tim.afraid)
261 {
262 msgf("You feel bolder now.");
263 notice = TRUE;
264 }
265 }
266
267 /* Use the value */
268 p_ptr->tim.afraid = v;
269
270 /* Nothing to notice */
271 if (!notice) return (FALSE);
272
273 /* Disturb */
274 if (disturb_state) disturb(FALSE);
275
276 /* Redraw the "afraid" */
277 p_ptr->redraw |= (PR_AFRAID);
278
279 /* Handle stuff */
280 handle_stuff();
281
282 /* Result */
283 return (TRUE);
284 }
285
286
287 /*
288 * Increase the afraid counter
289 */
inc_afraid(int v)290 bool inc_afraid(int v)
291 {
292 return(set_afraid(p_ptr->tim.afraid + v));
293 }
294
295
296 /*
297 * No more fear
298 */
clear_afraid(void)299 bool clear_afraid(void)
300 {
301 return(set_afraid(0));
302 }
303
304 /*
305 * Set "p_ptr->paralyzed", notice observable changes
306 */
set_paralyzed(int v)307 static bool set_paralyzed(int v)
308 {
309 bool notice = FALSE;
310
311 /* Hack -- Force good values */
312 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
313
314 /* Open */
315 if (v)
316 {
317 if (!p_ptr->tim.paralyzed)
318 {
319 msgf("You are paralyzed!");
320 notice = TRUE;
321 }
322 }
323
324 /* Shut */
325 else
326 {
327 if (p_ptr->tim.paralyzed)
328 {
329 msgf("You can move again.");
330 notice = TRUE;
331 }
332 }
333
334 /* Use the value */
335 p_ptr->tim.paralyzed = v;
336
337 /* Redraw status bar + message*/
338 p_ptr->redraw |= (PR_STATUS);
339
340 /* Nothing to notice */
341 if (!notice) return (FALSE);
342
343 /* Disturb */
344 if (disturb_state) disturb(FALSE);
345
346 /* Redraw the state */
347 p_ptr->redraw |= (PR_STATE | PR_SPEED);
348
349 /* Handle stuff */
350 handle_stuff();
351
352 /* Result */
353 return (TRUE);
354 }
355
356
357 /*
358 * Increase the paralyzed counter
359 */
inc_paralyzed(int v)360 bool inc_paralyzed(int v)
361 {
362 return(set_paralyzed(p_ptr->tim.paralyzed + v));
363 }
364
365
366 /*
367 * No more paralyzation
368 */
clear_paralyzed(void)369 bool clear_paralyzed(void)
370 {
371 return(set_paralyzed(0));
372 }
373
374
375 /*
376 * Set "p_ptr->image", notice observable changes
377 *
378 * Note that we must redraw the map when hallucination changes.
379 */
set_image(int v)380 static bool set_image(int v)
381 {
382 bool notice = FALSE;
383
384 /* Hack -- Force good values */
385 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
386
387 /* Open */
388 if (v)
389 {
390 if (!p_ptr->tim.image)
391 {
392 msgf("Oh, wow! Everything looks so cosmic now!");
393 notice = TRUE;
394
395 /* Update the monster vis window */
396 p_ptr->window |= PW_VISIBLE;
397 }
398 }
399
400 /* Shut */
401 else
402 {
403 if (p_ptr->tim.image)
404 {
405 msgf("You can see clearly again.");
406 notice = TRUE;
407
408 /* Update the monster vis window */
409 p_ptr->window |= PW_VISIBLE;
410 }
411 }
412
413 /* Use the value */
414 p_ptr->tim.image = v;
415
416 /* Redraw status bar */
417 p_ptr->redraw |= (PR_STATUS);
418
419 /* Nothing to notice */
420 if (!notice) return (FALSE);
421
422 /* Disturb */
423 if (disturb_state) disturb(FALSE);
424
425 /* Redraw map */
426 p_ptr->redraw |= (PR_MAP);
427
428 /* Update monsters */
429 p_ptr->update |= (PU_MONSTERS);
430
431 /* Window stuff */
432 p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
433
434 /* Handle stuff */
435 handle_stuff();
436
437 /* Result */
438 return (TRUE);
439 }
440
441 /*
442 * Increase the image counter
443 */
inc_image(int v)444 bool inc_image(int v)
445 {
446 return(set_image(p_ptr->tim.image + v));
447 }
448
449
450 /*
451 * No more hallucination
452 */
clear_image(void)453 bool clear_image(void)
454 {
455 return(set_image(0));
456 }
457
458
459 /*
460 * Set "p_ptr->fast", notice observable changes
461 */
set_fast(int v)462 static bool set_fast(int v)
463 {
464 bool notice = FALSE;
465
466 /* Hack -- Force good values */
467 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
468
469 /* Open */
470 if (v)
471 {
472 if (!p_ptr->tim.fast)
473 {
474 msgf("You feel yourself moving faster!");
475 notice = TRUE;
476
477 chg_virtue(V_PATIENCE, -1);
478 chg_virtue(V_DILIGENCE, 1);
479 }
480 }
481
482 /* Shut */
483 else
484 {
485 if (p_ptr->tim.fast)
486 {
487 msgf("You feel yourself slow down.");
488 notice = TRUE;
489 }
490 }
491
492 /* Use the value */
493 p_ptr->tim.fast = v;
494
495 /* Redraw status bar */
496 p_ptr->redraw |= (PR_STATUS);
497
498 /* Nothing to notice */
499 if (!notice) return (FALSE);
500
501 /* Disturb */
502 if (disturb_state) disturb(FALSE);
503
504 /* Recalculate bonuses */
505 p_ptr->update |= (PU_BONUS);
506
507 /* Handle stuff */
508 handle_stuff();
509
510 /* Result */
511 return (TRUE);
512 }
513
514
515 /*
516 * Increase the "fast" counter.
517 *
518 * Hack - only increase speed a little bit if already hasted.
519 */
inc_fast(int v)520 bool inc_fast(int v)
521 {
522 /* Haste */
523 if ((!p_ptr->tim.fast) || (v < 0))
524 {
525 return (set_fast(p_ptr->tim.fast + v));
526 }
527 else
528 {
529 return (set_fast(p_ptr->tim.fast + randint1(5)));
530 }
531 }
532
533
534 /*
535 * No more increased speed
536 */
clear_fast(void)537 bool clear_fast(void)
538 {
539 return(set_fast(0));
540 }
541
542
543 /*
544 * Set "p_ptr->slow", notice observable changes
545 */
set_slow(int v)546 static bool set_slow(int v)
547 {
548 bool notice = FALSE;
549
550 /* Hack -- Force good values */
551 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
552
553 /* Open */
554 if (v)
555 {
556 if (!p_ptr->tim.slow)
557 {
558 msgf("You feel yourself moving slower!");
559 notice = TRUE;
560 }
561 }
562
563 /* Shut */
564 else
565 {
566 if (p_ptr->tim.slow)
567 {
568 msgf("You feel yourself speed up.");
569 notice = TRUE;
570 }
571 }
572
573 /* Use the value */
574 p_ptr->tim.slow = v;
575
576 /* Redraw status bar */
577 p_ptr->redraw |= (PR_STATUS);
578
579 /* Nothing to notice */
580 if (!notice) return (FALSE);
581
582 /* Disturb */
583 if (disturb_state) disturb(FALSE);
584
585 /* Recalculate bonuses */
586 p_ptr->update |= (PU_BONUS);
587
588 /* Handle stuff */
589 handle_stuff();
590
591 /* Result */
592 return (TRUE);
593 }
594
595
596 /*
597 * Increase the "slow" counter
598 */
inc_slow(int v)599 bool inc_slow(int v)
600 {
601 return(set_slow(p_ptr->tim.slow + v));
602 }
603
604
605 /*
606 * No more "slowness"
607 */
clear_slow(void)608 bool clear_slow(void)
609 {
610 return(set_slow(0));
611 }
612
613 /*
614 * Increment "p_ptr->shield", notice observable changes
615 */
inc_shield(int v)616 bool inc_shield(int v)
617 {
618 bool notice = FALSE;
619
620 /* What will the new value be? */
621 v = v + p_ptr->tim.shield;
622
623 /* Hack -- Force good values */
624 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
625
626 /* Open */
627 if (v)
628 {
629 if (!p_ptr->tim.shield)
630 {
631 msgf("Your skin turns to stone.");
632 notice = TRUE;
633 }
634 }
635
636 /* Shut */
637 else
638 {
639 if (p_ptr->tim.shield)
640 {
641 msgf("Your skin returns to normal.");
642 notice = TRUE;
643 }
644 }
645
646 /* Use the value */
647 p_ptr->tim.shield = v;
648
649 /* Redraw status bar */
650 p_ptr->redraw |= (PR_STATUS);
651
652 /* Nothing to notice */
653 if (!notice) return (FALSE);
654
655 /* Disturb */
656 if (disturb_state) disturb(FALSE);
657
658 /* Recalculate bonuses */
659 p_ptr->update |= (PU_BONUS);
660
661 /* Handle stuff */
662 handle_stuff();
663
664 /* Result */
665 return (TRUE);
666 }
667
668
669
670 /*
671 * Increment "p_ptr->blessed", notice observable changes
672 */
inc_blessed(int v)673 bool inc_blessed(int v)
674 {
675 bool notice = FALSE;
676
677 /* What will the new value be? */
678 v = v + p_ptr->tim.blessed;
679
680 /* Hack -- Force good values */
681 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
682
683 /* Open */
684 if (v)
685 {
686 if (!p_ptr->tim.blessed)
687 {
688 msgf("You feel righteous!");
689 notice = TRUE;
690 }
691 }
692
693 /* Shut */
694 else
695 {
696 if (p_ptr->tim.blessed)
697 {
698 msgf("The prayer has expired.");
699 notice = TRUE;
700 }
701 }
702
703 /* Use the value */
704 p_ptr->tim.blessed = v;
705
706 /* Redraw status bar */
707 p_ptr->redraw |= (PR_STATUS);
708
709 /* Nothing to notice */
710 if (!notice) return (FALSE);
711
712 /* Disturb */
713 if (disturb_state) disturb(FALSE);
714
715 /* Recalculate bonuses */
716 p_ptr->update |= (PU_BONUS);
717
718 /* Handle stuff */
719 handle_stuff();
720
721 /* Result */
722 return (TRUE);
723 }
724
725
726 /*
727 * Increment "p_ptr->hero", notice observable changes
728 */
inc_hero(int v)729 bool inc_hero(int v)
730 {
731 bool notice = FALSE;
732
733 /* What will the new value be? */
734 v = v + p_ptr->tim.hero;
735
736 /* Hack -- Force good values */
737 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
738
739 /* Open */
740 if (v)
741 {
742 if (!p_ptr->tim.hero)
743 {
744 msgf("You feel like a hero!");
745 notice = TRUE;
746 }
747 }
748
749 /* Shut */
750 else
751 {
752 if (p_ptr->tim.hero)
753 {
754 msgf("The heroism wears off.");
755 notice = TRUE;
756 }
757 }
758
759 /* Use the value */
760 p_ptr->tim.hero = v;
761
762 /* Redraw status bar */
763 p_ptr->redraw |= (PR_STATUS);
764
765 /* Nothing to notice */
766 if (!notice) return (FALSE);
767
768 /* Disturb */
769 if (disturb_state) disturb(FALSE);
770
771 /* Recalculate bonuses */
772 p_ptr->update |= (PU_BONUS);
773
774 /* Recalculate hitpoints */
775 p_ptr->update |= (PU_HP);
776
777 /* Handle stuff */
778 handle_stuff();
779
780 /* Result */
781 return (TRUE);
782 }
783
784
785 /*
786 * Increment "p_ptr->shero", notice observable changes
787 */
inc_shero(int v)788 bool inc_shero(int v)
789 {
790 bool notice = FALSE;
791
792 /* What will the new value be? */
793 v = v + p_ptr->tim.shero;
794
795 /* Hack -- Force good values */
796 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
797
798 /* Open */
799 if (v)
800 {
801 if (!p_ptr->tim.shero)
802 {
803 msgf("You feel like a killing machine!");
804 notice = TRUE;
805 }
806 }
807
808 /* Shut */
809 else
810 {
811 if (p_ptr->tim.shero)
812 {
813 msgf("You feel less Berserk.");
814 notice = TRUE;
815 }
816 }
817
818 /* Use the value */
819 p_ptr->tim.shero = v;
820
821 /* Redraw status bar */
822 p_ptr->redraw |= (PR_STATUS);
823
824 /* Nothing to notice */
825 if (!notice) return (FALSE);
826
827 /* Disturb */
828 if (disturb_state) disturb(FALSE);
829
830 /* Recalculate bonuses */
831 p_ptr->update |= (PU_BONUS);
832
833 /* Recalculate hitpoints */
834 p_ptr->update |= (PU_HP);
835
836 /* Handle stuff */
837 handle_stuff();
838
839 /* Result */
840 return (TRUE);
841 }
842
843
844 /*
845 * Increment "p_ptr->protevil", notice observable changes
846 */
inc_protevil(int v)847 bool inc_protevil(int v)
848 {
849 bool notice = FALSE;
850
851 /* What will the new value be? */
852 v = v + p_ptr->tim.protevil;
853
854 /* Hack -- Force good values */
855 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
856
857 /* Open */
858 if (v)
859 {
860 if (!p_ptr->tim.protevil)
861 {
862 msgf("You feel safe from evil!");
863 notice = TRUE;
864 }
865 }
866
867 /* Shut */
868 else
869 {
870 if (p_ptr->tim.protevil)
871 {
872 msgf("You no longer feel safe from evil.");
873 notice = TRUE;
874 }
875 }
876
877 /* Use the value */
878 p_ptr->tim.protevil = v;
879
880 /* Redraw status bar */
881 p_ptr->redraw |= (PR_STATUS);
882
883 /* Nothing to notice */
884 if (!notice) return (FALSE);
885
886 /* Disturb */
887 if (disturb_state) disturb(FALSE);
888
889 /* Handle stuff */
890 handle_stuff();
891
892 /* Result */
893 return (TRUE);
894 }
895
896 /*
897 * Increment "p_ptr->wraith_form", notice observable changes
898 */
inc_wraith_form(int v)899 bool inc_wraith_form(int v)
900 {
901 bool notice = FALSE;
902
903 /* What will the new value be? */
904 v = v + p_ptr->tim.wraith_form;
905
906 /* Hack -- Force good values */
907 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
908
909 /* Open */
910 if (v)
911 {
912 if (!p_ptr->tim.wraith_form)
913 {
914 msgf
915 ("You leave the physical world and turn into a wraith-being!");
916 notice = TRUE;
917
918 /* Redraw map */
919 p_ptr->redraw |= (PR_MAP);
920
921 /* Update monsters */
922 p_ptr->update |= (PU_MONSTERS);
923
924 /* Window stuff */
925 p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
926 }
927 }
928
929 /* Shut */
930 else
931 {
932 if (p_ptr->tim.wraith_form)
933 {
934 msgf("You feel opaque.");
935 notice = TRUE;
936
937 /* Redraw map */
938 p_ptr->redraw |= (PR_MAP);
939
940 /* Update monsters */
941 p_ptr->update |= (PU_MONSTERS);
942
943 /* Window stuff */
944 p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
945 }
946 }
947
948 /* Use the value */
949 p_ptr->tim.wraith_form = v;
950
951 /* Redraw status bar */
952 p_ptr->redraw |= (PR_STATUS);
953
954 /* Nothing to notice */
955 if (!notice) return (FALSE);
956
957 /* Disturb */
958 if (disturb_state) disturb(FALSE);
959
960 /* Recalculate bonuses */
961 p_ptr->update |= (PU_BONUS);
962
963 /* Handle stuff */
964 handle_stuff();
965
966 /* Result */
967 return (TRUE);
968
969 }
970
971
972 /*
973 * Increment "p_ptr->invuln", notice observable changes
974 */
inc_invuln(int v)975 bool inc_invuln(int v)
976 {
977 bool notice = FALSE;
978
979 /* What will the new value be? */
980 v = v + p_ptr->tim.invuln;
981
982 /* Hack -- Force good values */
983 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
984
985 /* Open */
986 if (v)
987 {
988 if (!p_ptr->tim.invuln)
989 {
990 msgf("Invulnerability!");
991 notice = TRUE;
992
993 chg_virtue(V_TEMPERANCE, -5);
994 chg_virtue(V_HONOUR, -5);
995 chg_virtue(V_SACRIFICE, -5);
996 chg_virtue(V_VALOUR, -10);
997
998 /* Redraw map */
999 p_ptr->redraw |= (PR_MAP);
1000
1001 /* Update monsters */
1002 p_ptr->update |= (PU_MONSTERS);
1003
1004 /* Window stuff */
1005 p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
1006 }
1007 }
1008
1009 /* Shut */
1010 else
1011 {
1012 if (p_ptr->tim.invuln)
1013 {
1014 msgf("The invulnerability wears off.");
1015 notice = TRUE;
1016
1017 /* Redraw map */
1018 p_ptr->redraw |= (PR_MAP);
1019
1020 /* Update monsters */
1021 p_ptr->update |= (PU_MONSTERS);
1022
1023 /* Window stuff */
1024 p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
1025 }
1026 }
1027
1028 /* Use the value */
1029 p_ptr->tim.invuln = v;
1030
1031 /* Redraw status bar */
1032 p_ptr->redraw |= (PR_STATUS);
1033
1034 /* Nothing to notice */
1035 if (!notice) return (FALSE);
1036
1037 /* Disturb */
1038 if (disturb_state) disturb(FALSE);
1039
1040 /* Recalculate bonuses */
1041 p_ptr->update |= (PU_BONUS);
1042
1043 /* Handle stuff */
1044 handle_stuff();
1045
1046 /* Result */
1047 return (TRUE);
1048 }
1049
1050
1051 /*
1052 * Set "p_ptr->tim.esp", notice observable changes
1053 */
set_tim_esp(int v)1054 static bool set_tim_esp(int v)
1055 {
1056 bool notice = FALSE;
1057
1058 /* Hack -- Force good values */
1059 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1060
1061 /* Open */
1062 if (v)
1063 {
1064 if (!p_ptr->tim.esp)
1065 {
1066 msgf("You feel your consciousness expand!");
1067 notice = TRUE;
1068 }
1069 }
1070
1071 /* Shut */
1072 else
1073 {
1074 if (p_ptr->tim.esp)
1075 {
1076 msgf("Your consciousness contracts again.");
1077 notice = TRUE;
1078 }
1079 }
1080
1081 /* Use the value */
1082 p_ptr->tim.esp = v;
1083
1084 /* Redraw status bar */
1085 p_ptr->redraw |= (PR_STATUS);
1086
1087 /* Nothing to notice */
1088 if (!notice) return (FALSE);
1089
1090 /* Disturb */
1091 if (disturb_state) disturb(FALSE);
1092
1093 /* Recalculate bonuses */
1094 p_ptr->update |= (PU_BONUS);
1095
1096 /* Update the monsters */
1097 p_ptr->update |= (PU_MONSTERS);
1098
1099 /* Window stuff */
1100 p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
1101
1102
1103 /* Handle stuff */
1104 handle_stuff();
1105
1106 /* Result */
1107 return (TRUE);
1108 }
1109
1110 /*
1111 * Increase the "esp" counter
1112 */
inc_tim_esp(int v)1113 bool inc_tim_esp(int v)
1114 {
1115 return(set_tim_esp(p_ptr->tim.esp + v));
1116 }
1117
1118
1119 /*
1120 * No more "esp"
1121 */
clear_tim_esp(void)1122 bool clear_tim_esp(void)
1123 {
1124 return(set_tim_esp(0));
1125 }
1126
1127
1128 /*
1129 * Increment "p_ptr->tim_invis", notice observable changes
1130 */
inc_tim_invis(int v)1131 bool inc_tim_invis(int v)
1132 {
1133 bool notice = FALSE;
1134
1135 /* What will the new value be? */
1136 v = v + p_ptr->tim.invis;
1137
1138 /* Hack -- Force good values */
1139 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1140
1141 /* Open */
1142 if (v)
1143 {
1144 if (!p_ptr->tim.invis)
1145 {
1146 msgf("Your eyes feel very sensitive!");
1147 notice = TRUE;
1148 }
1149 }
1150
1151 /* Shut */
1152 else
1153 {
1154 if (p_ptr->tim.invis)
1155 {
1156 msgf("Your eyes feel less sensitive.");
1157 notice = TRUE;
1158 }
1159 }
1160
1161 /* Use the value */
1162 p_ptr->tim.invis = v;
1163
1164 /* Redraw status bar */
1165 p_ptr->redraw |= (PR_STATUS);
1166
1167 /* Nothing to notice */
1168 if (!notice) return (FALSE);
1169
1170 /* Disturb */
1171 if (disturb_state) disturb(FALSE);
1172
1173 /* Recalculate bonuses */
1174 p_ptr->update |= (PU_BONUS);
1175
1176 /* Update the monsters */
1177 p_ptr->update |= (PU_MONSTERS);
1178
1179 /* Handle stuff */
1180 handle_stuff();
1181
1182 /* Result */
1183 return (TRUE);
1184 }
1185
1186
1187 /*
1188 * Increment "p_ptr->tim_infra", notice observable changes
1189 */
inc_tim_infra(int v)1190 bool inc_tim_infra(int v)
1191 {
1192 bool notice = FALSE;
1193
1194 /* What will the new value be? */
1195 v = v + p_ptr->tim.invuln;
1196
1197 /* Hack -- Force good values */
1198 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1199
1200 /* Open */
1201 if (v)
1202 {
1203 if (!p_ptr->tim.infra)
1204 {
1205 msgf("Your eyes begin to tingle!");
1206 notice = TRUE;
1207 }
1208 }
1209
1210 /* Shut */
1211 else
1212 {
1213 if (p_ptr->tim.infra)
1214 {
1215 msgf("Your eyes stop tingling.");
1216 notice = TRUE;
1217 }
1218 }
1219
1220 /* Use the value */
1221 p_ptr->tim.infra = v;
1222
1223 /* Redraw status bar */
1224 p_ptr->redraw |= (PR_STATUS);
1225
1226 /* Nothing to notice */
1227 if (!notice) return (FALSE);
1228
1229 /* Disturb */
1230 if (disturb_state) disturb(FALSE);
1231
1232 /* Recalculate bonuses */
1233 p_ptr->update |= (PU_BONUS);
1234
1235 /* Update the monsters */
1236 p_ptr->update |= (PU_MONSTERS);
1237
1238 /* Handle stuff */
1239 handle_stuff();
1240
1241 /* Result */
1242 return (TRUE);
1243 }
1244
1245
1246 /*
1247 * Increment "p_ptr->oppose_acid", notice observable changes
1248 */
inc_oppose_acid(int v)1249 bool inc_oppose_acid(int v)
1250 {
1251 bool notice = FALSE;
1252
1253 /* What will the new value be? */
1254 v = v + p_ptr->tim.oppose_acid;
1255
1256 /* Hack -- Force good values */
1257 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1258
1259 /* Open */
1260 if (v)
1261 {
1262 if (!p_ptr->tim.oppose_acid)
1263 {
1264 msgf("You feel resistant to acid!");
1265 notice = TRUE;
1266 }
1267 }
1268
1269 /* Shut */
1270 else
1271 {
1272 if (p_ptr->tim.oppose_acid)
1273 {
1274 msgf("You feel less resistant to acid.");
1275 notice = TRUE;
1276 }
1277 }
1278
1279 /* Use the value */
1280 p_ptr->tim.oppose_acid = v;
1281
1282 /* Redraw status bar */
1283 p_ptr->redraw |= (PR_STATUS);
1284
1285 /* Nothing to notice */
1286 if (!notice) return (FALSE);
1287
1288 /* Disturb */
1289 if (disturb_state) disturb(FALSE);
1290
1291 /* Handle stuff */
1292 handle_stuff();
1293
1294 /* Result */
1295 return (TRUE);
1296 }
1297
1298
1299 /*
1300 * Increment "p_ptr->oppose_elec", notice observable changes
1301 */
inc_oppose_elec(int v)1302 bool inc_oppose_elec(int v)
1303 {
1304 bool notice = FALSE;
1305
1306 /* What will the new value be? */
1307 v = v + p_ptr->tim.oppose_elec;
1308
1309 /* Hack -- Force good values */
1310 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1311
1312 /* Open */
1313 if (v)
1314 {
1315 if (!p_ptr->tim.oppose_elec)
1316 {
1317 msgf("You feel resistant to electricity!");
1318 notice = TRUE;
1319 }
1320 }
1321
1322 /* Shut */
1323 else
1324 {
1325 if (p_ptr->tim.oppose_elec)
1326 {
1327 msgf("You feel less resistant to electricity.");
1328 notice = TRUE;
1329 }
1330 }
1331
1332 /* Use the value */
1333 p_ptr->tim.oppose_elec = v;
1334
1335 /* Redraw status bar */
1336 p_ptr->redraw |= (PR_STATUS);
1337
1338 /* Nothing to notice */
1339 if (!notice) return (FALSE);
1340
1341 /* Disturb */
1342 if (disturb_state) disturb(FALSE);
1343
1344 /* Handle stuff */
1345 handle_stuff();
1346
1347 /* Result */
1348 return (TRUE);
1349 }
1350
1351
1352 /*
1353 * Increment "p_ptr->oppose_fire", notice observable changes
1354 */
inc_oppose_fire(int v)1355 bool inc_oppose_fire(int v)
1356 {
1357 bool notice = FALSE;
1358
1359 /* What will the new value be? */
1360 v = v + p_ptr->tim.oppose_fire;
1361
1362 /* Hack -- Force good values */
1363 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1364
1365 /* Open */
1366 if (v)
1367 {
1368 if (!p_ptr->tim.oppose_fire)
1369 {
1370 msgf("You feel resistant to fire!");
1371 notice = TRUE;
1372 }
1373 }
1374
1375 /* Shut */
1376 else
1377 {
1378 if (p_ptr->tim.oppose_fire)
1379 {
1380 msgf("You feel less resistant to fire.");
1381 notice = TRUE;
1382 }
1383 }
1384
1385 /* Use the value */
1386 p_ptr->tim.oppose_fire = v;
1387
1388 /* Redraw status bar */
1389 p_ptr->redraw |= (PR_STATUS);
1390
1391 /* Nothing to notice */
1392 if (!notice) return (FALSE);
1393
1394 /* Disturb */
1395 if (disturb_state) disturb(FALSE);
1396
1397 /* Handle stuff */
1398 handle_stuff();
1399
1400 /* Result */
1401 return (TRUE);
1402 }
1403
1404
1405 /*
1406 * Increment "p_ptr->oppose_cold", notice observable changes
1407 */
inc_oppose_cold(int v)1408 bool inc_oppose_cold(int v)
1409 {
1410 bool notice = FALSE;
1411
1412 /* What will the new value be? */
1413 v = v + p_ptr->tim.oppose_cold;
1414
1415 /* Hack -- Force good values */
1416 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1417
1418 /* Open */
1419 if (v)
1420 {
1421 if (!p_ptr->tim.oppose_cold)
1422 {
1423 msgf("You feel resistant to cold!");
1424 notice = TRUE;
1425 }
1426 }
1427
1428 /* Shut */
1429 else
1430 {
1431 if (p_ptr->tim.oppose_cold)
1432 {
1433 msgf("You feel less resistant to cold.");
1434 notice = TRUE;
1435 }
1436 }
1437
1438 /* Use the value */
1439 p_ptr->tim.oppose_cold = v;
1440
1441 /* Redraw status bar */
1442 p_ptr->redraw |= (PR_STATUS);
1443
1444 /* Nothing to notice */
1445 if (!notice) return (FALSE);
1446
1447 /* Disturb */
1448 if (disturb_state) disturb(FALSE);
1449
1450 /* Handle stuff */
1451 handle_stuff();
1452
1453 /* Result */
1454 return (TRUE);
1455 }
1456
1457
1458 /*
1459 * Increment "p_ptr->oppose_pois", notice observable changes
1460 */
inc_oppose_pois(int v)1461 bool inc_oppose_pois(int v)
1462 {
1463 bool notice = FALSE;
1464
1465 /* What will the new value be? */
1466 v = v + p_ptr->tim.oppose_pois;
1467
1468 /* Hack -- Force good values */
1469 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1470
1471 /* Open */
1472 if (v)
1473 {
1474 if (!p_ptr->tim.oppose_pois)
1475 {
1476 msgf("You feel resistant to poison!");
1477 notice = TRUE;
1478 }
1479 }
1480
1481 /* Shut */
1482 else
1483 {
1484 if (p_ptr->tim.oppose_pois)
1485 {
1486 msgf("You feel less resistant to poison.");
1487 notice = TRUE;
1488 }
1489 }
1490
1491 /* Use the value */
1492 p_ptr->tim.oppose_pois = v;
1493
1494 /* Redraw status bar */
1495 p_ptr->redraw |= (PR_STATUS);
1496
1497 /* Nothing to notice */
1498 if (!notice) return (FALSE);
1499
1500 /* Disturb */
1501 if (disturb_state) disturb(FALSE);
1502
1503 /* Handle stuff */
1504 handle_stuff();
1505
1506 /* Result */
1507 return (TRUE);
1508 }
1509
1510
1511 /*
1512 * Helper functions to test resistance status for the various elements
1513 *
1514 * These return a value from 0 to 200 indicating how much damage you
1515 * take from an element, as a percentage of normal damage.
1516 */
1517
1518 static int resist_table[12] = {3, 5, 7, 11, 16, 22, 33, 50, 66, 100, 150, 200};
1519
1520 /*
1521 * Acid resist level
1522 */
res_acid_lvl(void)1523 int res_acid_lvl(void)
1524 {
1525 int level = 9;
1526
1527 if (FLAG(p_ptr, TR_IM_ACID)) return (0);
1528
1529 if (FLAG(p_ptr, TR_RES_ACID)) level -= 3;
1530 if (p_ptr->tim.oppose_acid) level -= 3;
1531 if (FLAG(p_ptr, TR_HURT_ACID)) level += 2;
1532
1533 if (level < 0) level = 0;
1534 if (level > 11) level = 11;
1535
1536 return resist_table[level];;
1537 }
1538
1539 /*
1540 * Electricity resist level
1541 */
res_elec_lvl(void)1542 int res_elec_lvl(void)
1543 {
1544 int level = 9;
1545
1546 if (FLAG(p_ptr, TR_IM_ELEC)) return (0);
1547
1548 if (FLAG(p_ptr, TR_RES_ELEC)) level -= 3;
1549 if (p_ptr->tim.oppose_elec) level -= 3;
1550 if (FLAG(p_ptr, TR_HURT_ELEC)) level += 2;
1551
1552 if (level < 0) level = 0;
1553 if (level > 11) level = 11;
1554
1555 return resist_table[level];;
1556 }
1557
1558 /*
1559 * Fire resist level
1560 */
res_fire_lvl(void)1561 int res_fire_lvl(void)
1562 {
1563 int level = 9;
1564
1565 if (FLAG(p_ptr, TR_IM_FIRE)) return (0);
1566
1567 if (FLAG(p_ptr, TR_RES_FIRE)) level -= 3;
1568 if (p_ptr->tim.oppose_fire) level -= 3;
1569 if (FLAG(p_ptr, TR_HURT_FIRE)) level += 2;
1570
1571 if (level < 0) level = 0;
1572 if (level > 11) level = 11;
1573
1574 return resist_table[level];;
1575 }
1576
1577 /*
1578 * Cold resist level
1579 */
res_cold_lvl(void)1580 int res_cold_lvl(void)
1581 {
1582 int level = 9;
1583
1584 if (FLAG(p_ptr, TR_IM_COLD)) return (0);
1585
1586 if (FLAG(p_ptr, TR_RES_COLD)) level -= 3;
1587 if (p_ptr->tim.oppose_cold) level -= 3;
1588 if (FLAG(p_ptr, TR_HURT_COLD)) level += 2;
1589
1590 if (level < 0) level = 0;
1591 if (level > 11) level = 11;
1592
1593 return resist_table[level];;
1594 }
1595
1596 /*
1597 * Poison resist level
1598 */
res_pois_lvl(void)1599 int res_pois_lvl(void)
1600 {
1601 int level = 9;
1602
1603 if (FLAG(p_ptr, TR_IM_POIS)) return (0);
1604
1605 if (FLAG(p_ptr, TR_RES_POIS)) level -= 3;
1606 if (p_ptr->tim.oppose_pois) level -= 3;
1607
1608 if (level < 0) level = 0;
1609 if (level > 11) level = 11;
1610
1611 return resist_table[level];;
1612 }
1613
1614 /*
1615 * Apply resistance to damage
1616 */
resist(int dam,int (* f_func)(void))1617 int resist(int dam, int (*f_func) (void))
1618 {
1619 /* Invulnerability */
1620 if (p_ptr->tim.invuln) return (0);
1621
1622 /* Use the function we were passed, and round up the damage */
1623 return ((dam * f_func() + 99) / 100);
1624 }
1625
1626
1627 /*
1628 * Acid has hit the player, attempt to affect some armor.
1629 *
1630 * Note that the "base armor" of an object never changes.
1631 *
1632 * If any armor is damaged (or resists), the player takes less damage.
1633 */
minus_ac(void)1634 static int minus_ac(void)
1635 {
1636 object_type *o_ptr = NULL;
1637
1638 /* Pick a (possibly empty) inventory slot */
1639 switch (randint1(6))
1640 {
1641 case 1:
1642 {
1643 o_ptr = &p_ptr->equipment[EQUIP_BODY];
1644 break;
1645 }
1646 case 2:
1647 {
1648 o_ptr = &p_ptr->equipment[EQUIP_ARM];
1649 break;
1650 }
1651 case 3:
1652 {
1653 o_ptr = &p_ptr->equipment[EQUIP_OUTER];
1654 break;
1655 }
1656 case 4:
1657 {
1658 o_ptr = &p_ptr->equipment[EQUIP_HANDS];
1659 break;
1660 }
1661 case 5:
1662 {
1663 o_ptr = &p_ptr->equipment[EQUIP_HEAD];
1664 break;
1665 }
1666 case 6:
1667 {
1668 o_ptr = &p_ptr->equipment[EQUIP_FEET];
1669 break;
1670 }
1671 }
1672
1673 /* Nothing to damage */
1674 if (!o_ptr->k_idx) return (FALSE);
1675
1676 /* No damage left to be done */
1677 if (o_ptr->ac + o_ptr->to_a <= 0) return (FALSE);
1678
1679
1680 /* Object resists */
1681 if (FLAG(o_ptr, TR_IGNORE_ACID))
1682 {
1683 msgf("Your %v is unaffected!", OBJECT_FMT(o_ptr, FALSE, 0));
1684
1685 return (TRUE);
1686 }
1687
1688 /* Message */
1689 msgf("Your %v is damaged!", OBJECT_FMT(o_ptr, FALSE, 0));
1690
1691 /* Damage the item */
1692 o_ptr->to_a--;
1693
1694 /* Calculate bonuses */
1695 p_ptr->update |= (PU_BONUS);
1696
1697 /* Window stuff */
1698 p_ptr->window |= (PW_EQUIP | PW_PLAYER);
1699
1700 /* Item was damaged */
1701 return (TRUE);
1702 }
1703
1704
1705 /*
1706 * Hurt the player with Acid
1707 */
acid_dam(int dam,cptr kb_str)1708 bool acid_dam(int dam, cptr kb_str)
1709 {
1710 int inv;
1711
1712 dam = resist(dam, res_acid_lvl);
1713
1714 /* Total Immunity? */
1715 if (dam <= 0) return (FALSE);
1716
1717 inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
1718
1719 if ((res_acid_lvl() > 50) && one_in_(HURT_CHANCE))
1720 (void)do_dec_stat(A_CHR);
1721
1722 /* If any armor gets hit, defend the player */
1723 if (minus_ac()) dam = (dam + 1) / 2;
1724
1725 /* Take damage */
1726 take_hit(dam, kb_str);
1727
1728 /* Inventory damage */
1729 if (res_acid_lvl() > 25)
1730 (void)inven_damage(set_acid_destroy, inv);
1731
1732 /* Obvious */
1733 return (TRUE);
1734 }
1735
1736
1737 /*
1738 * Hurt the player with electricity
1739 */
elec_dam(int dam,cptr kb_str)1740 bool elec_dam(int dam, cptr kb_str)
1741 {
1742 int inv;
1743
1744 dam = resist(dam, res_elec_lvl);
1745
1746 /* Total immunity */
1747 if (dam <= 0) return (FALSE);
1748
1749 inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
1750
1751 if ((res_elec_lvl() > 50) && one_in_(HURT_CHANCE))
1752 (void)do_dec_stat(A_DEX);
1753
1754 /* Take damage */
1755 take_hit(dam, kb_str);
1756
1757 /* Inventory damage */
1758 if (res_acid_lvl() > 25)
1759 (void)inven_damage(set_elec_destroy, inv);
1760
1761 /* Obvious */
1762 return (TRUE);
1763 }
1764
1765
1766 /*
1767 * Hurt the player with Fire
1768 */
fire_dam(int dam,cptr kb_str)1769 bool fire_dam(int dam, cptr kb_str)
1770 {
1771 int inv;
1772
1773 dam = resist(dam, res_fire_lvl);
1774
1775 /* Totally immune? */
1776 if (dam <= 0) return (FALSE);
1777
1778 inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
1779
1780 if ((res_fire_lvl() > 50) && one_in_(HURT_CHANCE))
1781 (void)do_dec_stat(A_STR);
1782
1783 /* Take damage */
1784 take_hit(dam, kb_str);
1785
1786 /* Inventory damage */
1787 if (res_fire_lvl() > 25)
1788 (void)inven_damage(set_fire_destroy, inv);
1789
1790 /* Obvious */
1791 return (TRUE);
1792 }
1793
1794
1795 /*
1796 * Hurt the player with Cold
1797 */
cold_dam(int dam,cptr kb_str)1798 bool cold_dam(int dam, cptr kb_str)
1799 {
1800 int inv;
1801
1802 dam = resist(dam, res_cold_lvl);
1803
1804 /* Total immunity? */
1805 if (dam <= 0) return (FALSE);
1806
1807 inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
1808
1809 if ((res_cold_lvl() > 50) && one_in_(HURT_CHANCE))
1810 (void)do_dec_stat(A_STR);
1811
1812 /* Take damage */
1813 take_hit(dam, kb_str);
1814
1815 /* Inventory damage */
1816 if (res_cold_lvl() > 25)
1817 (void)inven_damage(set_cold_destroy, inv);
1818
1819 /* Obvious */
1820 return (TRUE);
1821 }
1822
1823
1824 /*
1825 * Hurt the player with Poison
1826 *
1827 * Hack - this should probably take a second argument
1828 * to add to the poison counter
1829 */
pois_dam(int dam,cptr kb_str,int pois)1830 bool pois_dam(int dam, cptr kb_str, int pois)
1831 {
1832 dam = resist(dam, res_pois_lvl);
1833
1834 /* Totally immune? */
1835 if (dam <= 0) return (FALSE);
1836
1837 if ((res_pois_lvl() > 50) && one_in_(HURT_CHANCE))
1838 (void)do_dec_stat(A_CON);
1839
1840 /* Take damage */
1841 take_hit(dam, kb_str);
1842
1843 /* Add poison to counter */
1844 if (res_pois_lvl() > 25)
1845 {
1846 pois = resist(pois, res_pois_lvl);
1847 inc_poisoned(pois);
1848 }
1849
1850 /* Obvious */
1851 return (TRUE);
1852 }
1853
1854
1855 /*
1856 * Set "p_ptr->stun", notice observable changes
1857 *
1858 * Note the special code to only notice "range" changes.
1859 */
set_stun(int v)1860 static bool set_stun(int v)
1861 {
1862 int old_aux, new_aux;
1863 bool notice = FALSE;
1864
1865
1866 /* Hack -- Force good values */
1867 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1868
1869 /*
1870 * Golems cannot be stunned when they are being used as a
1871 * "training" class. However, when they are being used in
1872 * a hard game - they lose this advantage. (Golems are
1873 * designed for newbies - not scummers.)
1874 */
1875 if ((p_ptr->rp.prace == RACE_GOLEM) &&
1876 !(ironman_shops || ironman_downward || ironman_nightmare))
1877 {
1878 v = 0;
1879 }
1880
1881 /* Knocked out */
1882 if (p_ptr->tim.stun > 100)
1883 {
1884 old_aux = 3;
1885 }
1886
1887 /* Heavy stun */
1888 else if (p_ptr->tim.stun > 50)
1889 {
1890 old_aux = 2;
1891 }
1892
1893 /* Stun */
1894 else if (p_ptr->tim.stun > 0)
1895 {
1896 old_aux = 1;
1897 }
1898
1899 /* None */
1900 else
1901 {
1902 old_aux = 0;
1903 }
1904
1905 /* Knocked out */
1906 if (v > 100)
1907 {
1908 new_aux = 3;
1909 }
1910
1911 /* Heavy stun */
1912 else if (v > 50)
1913 {
1914 new_aux = 2;
1915 }
1916
1917 /* Stun */
1918 else if (v > 0)
1919 {
1920 new_aux = 1;
1921 }
1922
1923 /* None */
1924 else
1925 {
1926 new_aux = 0;
1927 }
1928
1929 /* Increase cut */
1930 if (new_aux > old_aux)
1931 {
1932 /* Describe the state */
1933 switch (new_aux)
1934 {
1935 case 1:
1936 {
1937 /* Stun */
1938 msgf("You have been stunned.");
1939 break;
1940 }
1941
1942 case 2:
1943 {
1944 /* Heavy stun */
1945 msgf("You have been heavily stunned.");
1946 break;
1947 }
1948
1949 case 3:
1950 {
1951 /* Knocked out */
1952 msgf("You have been knocked out.");
1953 break;
1954 }
1955 }
1956
1957 /*
1958 * XXX XXX Hack -
1959 * Mindcrafters cannot get this effect when
1960 * casting a spell. It really doesn't make sense.
1961 * Unfortunately, there is no way to know if this is
1962 * the case... so it is disabled in all circumstances
1963 * if you are a Mindcrafter. (Perhaps it can be
1964 * explained away by their "superior mental skills" or
1965 * something...
1966 */
1967 if ((randint1(1000) < v || one_in_(16)) &&
1968 (!(p_ptr->rp.pclass == CLASS_MINDCRAFTER)))
1969 {
1970 msgf("A vicious blow hits your head.");
1971 if (one_in_(3))
1972 {
1973 if (!(FLAG(p_ptr, TR_SUST_INT))) (void)do_dec_stat(A_INT);
1974 if (!(FLAG(p_ptr, TR_SUST_WIS))) (void)do_dec_stat(A_WIS);
1975 }
1976 else if (one_in_(2))
1977 {
1978 if (!(FLAG(p_ptr, TR_SUST_INT))) (void)do_dec_stat(A_INT);
1979 }
1980 else
1981 {
1982 if (!(FLAG(p_ptr, TR_SUST_WIS))) (void)do_dec_stat(A_WIS);
1983 }
1984 }
1985
1986 /* Notice */
1987 notice = TRUE;
1988 }
1989
1990 /* Decrease cut */
1991 else if (new_aux < old_aux)
1992 {
1993 /* Describe the state */
1994 switch (new_aux)
1995 {
1996 case 0:
1997 {
1998 /* None */
1999 msgf("You are no longer stunned.");
2000 if (disturb_state) disturb(FALSE);
2001 break;
2002 }
2003 }
2004
2005 /* Notice */
2006 notice = TRUE;
2007 }
2008
2009 /* Use the value */
2010 p_ptr->tim.stun = v;
2011
2012 /* No change */
2013 if (!notice) return (FALSE);
2014
2015 /* Disturb */
2016 if (disturb_state) disturb(FALSE);
2017
2018 /* Recalculate bonuses */
2019 p_ptr->update |= (PU_BONUS);
2020
2021 /* Redraw the "stun" */
2022 p_ptr->redraw |= (PR_STUN);
2023
2024 /* Handle stuff */
2025 handle_stuff();
2026
2027 /* Result */
2028 return (TRUE);
2029 }
2030
2031
2032 /*
2033 * Increase the "stun" counter
2034 */
inc_stun(int v)2035 bool inc_stun(int v)
2036 {
2037 return(set_stun(p_ptr->tim.stun + v));
2038 }
2039
2040
2041 /*
2042 * No more "stun"
2043 */
clear_stun(void)2044 bool clear_stun(void)
2045 {
2046 return(set_stun(0));
2047 }
2048
2049
2050 /*
2051 * Set "p_ptr->cut", notice observable changes
2052 *
2053 * Note the special code to only notice "range" changes.
2054 */
set_cut(int v)2055 static bool set_cut(int v)
2056 {
2057 int old_aux, new_aux;
2058
2059 bool notice = FALSE;
2060
2061 /* Hack -- Force good values */
2062 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
2063
2064 if (p_ptr->rp.prace == RACE_GOLEM ||
2065 p_ptr->rp.prace == RACE_SKELETON ||
2066 p_ptr->rp.prace == RACE_SPECTRE ||
2067 (p_ptr->rp.prace == RACE_ZOMBIE && p_ptr->lev > 11))
2068 v = 0;
2069
2070 /* Mortal wound */
2071 if (p_ptr->tim.cut > 1000)
2072 {
2073 old_aux = 7;
2074 }
2075
2076 /* Deep gash */
2077 else if (p_ptr->tim.cut > 200)
2078 {
2079 old_aux = 6;
2080 }
2081
2082 /* Severe cut */
2083 else if (p_ptr->tim.cut > 100)
2084 {
2085 old_aux = 5;
2086 }
2087
2088 /* Nasty cut */
2089 else if (p_ptr->tim.cut > 50)
2090 {
2091 old_aux = 4;
2092 }
2093
2094 /* Bad cut */
2095 else if (p_ptr->tim.cut > 25)
2096 {
2097 old_aux = 3;
2098 }
2099
2100 /* Light cut */
2101 else if (p_ptr->tim.cut > 10)
2102 {
2103 old_aux = 2;
2104 }
2105
2106 /* Graze */
2107 else if (p_ptr->tim.cut > 0)
2108 {
2109 old_aux = 1;
2110 }
2111
2112 /* None */
2113 else
2114 {
2115 old_aux = 0;
2116 }
2117
2118 /* Mortal wound */
2119 if (v > 1000)
2120 {
2121 new_aux = 7;
2122 }
2123
2124 /* Deep gash */
2125 else if (v > 200)
2126 {
2127 new_aux = 6;
2128 }
2129
2130 /* Severe cut */
2131 else if (v > 100)
2132 {
2133 new_aux = 5;
2134 }
2135
2136 /* Nasty cut */
2137 else if (v > 50)
2138 {
2139 new_aux = 4;
2140 }
2141
2142 /* Bad cut */
2143 else if (v > 25)
2144 {
2145 new_aux = 3;
2146 }
2147
2148 /* Light cut */
2149 else if (v > 10)
2150 {
2151 new_aux = 2;
2152 }
2153
2154 /* Graze */
2155 else if (v > 0)
2156 {
2157 new_aux = 1;
2158 }
2159
2160 /* None */
2161 else
2162 {
2163 new_aux = 0;
2164 }
2165
2166 /* Increase cut */
2167 if (new_aux > old_aux)
2168 {
2169 /* Describe the state */
2170 switch (new_aux)
2171 {
2172 case 1:
2173 {
2174 /* Graze */
2175 msgf("You have been given a graze.");
2176 break;
2177 }
2178
2179 case 2:
2180 {
2181 /* Light cut */
2182 msgf("You have been given a light cut.");
2183 break;
2184 }
2185
2186 case 3:
2187 {
2188 /* Bad cut */
2189 msgf("You have been given a bad cut.");
2190 break;
2191 }
2192
2193 case 4:
2194 {
2195 /* Nasty cut */
2196 msgf("You have been given a nasty cut.");
2197 break;
2198 }
2199
2200 case 5:
2201 {
2202 /* Severe cut */
2203 msgf("You have been given a severe cut.");
2204 break;
2205 }
2206
2207 case 6:
2208 {
2209 /* Deep gash */
2210 msgf("You have been given a deep gash.");
2211 break;
2212 }
2213
2214 case 7:
2215 {
2216 /* Mortal wound */
2217 msgf("You have been given a mortal wound.");
2218 break;
2219 }
2220 }
2221
2222 /* Notice */
2223 notice = TRUE;
2224
2225 if (randint1(1000) < v || one_in_(16))
2226 {
2227 if (!(FLAG(p_ptr, TR_SUST_CHR)))
2228 {
2229 msgf("You have been horribly scarred.");
2230
2231 (void)do_dec_stat(A_CHR);
2232 }
2233 }
2234 }
2235
2236 /* Decrease cut */
2237 else if (new_aux < old_aux)
2238 {
2239 /* Describe the state */
2240 switch (new_aux)
2241 {
2242 case 0:
2243 {
2244 /* None */
2245 msgf("You are no longer bleeding.");
2246 if (disturb_state) disturb(FALSE);
2247 break;
2248 }
2249 }
2250
2251 /* Notice */
2252 notice = TRUE;
2253 }
2254
2255 /* Use the value */
2256 p_ptr->tim.cut = v;
2257
2258 /* No change */
2259 if (!notice) return (FALSE);
2260
2261 /* Disturb */
2262 if (disturb_state) disturb(FALSE);
2263
2264 /* Recalculate bonuses */
2265 p_ptr->update |= (PU_BONUS);
2266
2267 /* Redraw the "cut" */
2268 p_ptr->redraw |= (PR_CUT);
2269
2270 /* Handle stuff */
2271 handle_stuff();
2272
2273 /* Result */
2274 return (TRUE);
2275 }
2276
2277
2278 /*
2279 * Increase the "cut" counter
2280 */
inc_cut(int v)2281 bool inc_cut(int v)
2282 {
2283 return(set_cut(p_ptr->tim.cut + v));
2284 }
2285
2286
2287 /*
2288 * No more "cuts"
2289 */
clear_cut(void)2290 bool clear_cut(void)
2291 {
2292 return(set_cut(0));
2293 }
2294
2295
2296 /*
2297 * Set "p_ptr->food", notice observable changes
2298 *
2299 * The "p_ptr->food" variable can get as large as 20000, allowing the
2300 * addition of the most "filling" item, Elvish Waybread, which adds
2301 * 7500 food units, without overflowing the 32767 maximum limit.
2302 *
2303 * Perhaps we should disturb the player with various messages,
2304 * especially messages about hunger status changes. XXX XXX XXX
2305 *
2306 * Digestion of food is handled in "dungeon.c", in which, normally,
2307 * the player digests about 20 food units per 100 game turns, more
2308 * when "fast", more when "regenerating", less with "slow digestion",
2309 * but when the player is "gorged", he digests 100 food units per 10
2310 * game turns, or a full 1000 food units per 100 game turns.
2311 *
2312 * Note that the player's speed is reduced by 10 units while gorged,
2313 * so if the player eats a single food ration (5000 food units) when
2314 * full (15000 food units), he will be gorged for (5000/100)*10 = 500
2315 * game turns, or 500/(100/5) = 25 player turns (if nothing else is
2316 * affecting the player speed).
2317 */
set_food(int v)2318 bool set_food(int v)
2319 {
2320 int old_aux, new_aux;
2321
2322 bool notice = FALSE;
2323
2324 /* Hack -- Force good values */
2325 v = (v > 20000) ? 20000 : (v < 0) ? 0 : v;
2326
2327 /* Fainting / Starving */
2328 if (p_ptr->food < PY_FOOD_FAINT)
2329 {
2330 old_aux = 0;
2331 }
2332
2333 /* Weak */
2334 else if (p_ptr->food < PY_FOOD_WEAK)
2335 {
2336 old_aux = 1;
2337 }
2338
2339 /* Hungry */
2340 else if (p_ptr->food < PY_FOOD_ALERT)
2341 {
2342 old_aux = 2;
2343 }
2344
2345 /* Normal */
2346 else if (p_ptr->food < PY_FOOD_FULL)
2347 {
2348 old_aux = 3;
2349 }
2350
2351 /* Full */
2352 else if (p_ptr->food < PY_FOOD_MAX)
2353 {
2354 old_aux = 4;
2355 }
2356
2357 /* Gorged */
2358 else
2359 {
2360 old_aux = 5;
2361 }
2362
2363 /* Fainting / Starving */
2364 if (v < PY_FOOD_FAINT)
2365 {
2366 new_aux = 0;
2367 }
2368
2369 /* Weak */
2370 else if (v < PY_FOOD_WEAK)
2371 {
2372 new_aux = 1;
2373 }
2374
2375 /* Hungry */
2376 else if (v < PY_FOOD_ALERT)
2377 {
2378 new_aux = 2;
2379 }
2380
2381 /* Normal */
2382 else if (v < PY_FOOD_FULL)
2383 {
2384 new_aux = 3;
2385 }
2386
2387 /* Full */
2388 else if (v < PY_FOOD_MAX)
2389 {
2390 new_aux = 4;
2391 }
2392
2393 /* Gorged */
2394 else
2395 {
2396 new_aux = 5;
2397 }
2398
2399 if (old_aux < 1 && new_aux > 0)
2400 chg_virtue(V_PATIENCE, 2);
2401 else if (old_aux < 3 && (old_aux != new_aux))
2402 chg_virtue(V_PATIENCE, 1);
2403 if (old_aux == 2)
2404 chg_virtue(V_TEMPERANCE, 1);
2405 if (old_aux == 0)
2406 chg_virtue(V_TEMPERANCE, -1);
2407
2408 /* Food increase */
2409 if (new_aux > old_aux)
2410 {
2411 /* Describe the state */
2412 switch (new_aux)
2413 {
2414 case 1:
2415 {
2416 /* Weak */
2417 msgf("You are still weak.");
2418 break;
2419 }
2420
2421 case 2:
2422 {
2423 /* Hungry */
2424 msgf("You are still hungry.");
2425 break;
2426 }
2427
2428 case 3:
2429 {
2430 /* Normal */
2431 msgf("You are no longer hungry.");
2432 break;
2433 }
2434
2435 case 4:
2436 {
2437 /* Full */
2438 msgf("You are full!");
2439 break;
2440 }
2441
2442 case 5:
2443 {
2444 /* Bloated */
2445 msgf("You have gorged yourself!");
2446
2447 chg_virtue(V_HARMONY, -1);
2448 chg_virtue(V_PATIENCE, -1);
2449 chg_virtue(V_TEMPERANCE, -2);
2450 break;
2451 }
2452 }
2453
2454 /* Change */
2455 notice = TRUE;
2456 }
2457
2458 /* Food decrease */
2459 else if (new_aux < old_aux)
2460 {
2461 /* Describe the state */
2462 switch (new_aux)
2463 {
2464 case 0:
2465 {
2466 /* Fainting / Starving */
2467 msgf("You are getting faint from hunger!");
2468 break;
2469 }
2470
2471 case 1:
2472 {
2473 /* Weak */
2474 msgf("You are getting weak from hunger!");
2475 break;
2476 }
2477
2478 case 2:
2479 {
2480 /* Hungry */
2481 msgf("You are getting hungry.");
2482 break;
2483 }
2484
2485 case 3:
2486 {
2487 /* Normal */
2488 msgf("You are no longer full.");
2489 break;
2490 }
2491
2492 case 4:
2493 {
2494 /* Full */
2495 msgf("You are no longer gorged.");
2496 break;
2497 }
2498 }
2499
2500 /* Change */
2501 notice = TRUE;
2502 }
2503
2504 /* Use the value */
2505 p_ptr->food = v;
2506
2507 /* Nothing to notice */
2508 if (!notice) return (FALSE);
2509
2510 /* Disturb */
2511 if (disturb_state) disturb(FALSE);
2512
2513 /* Recalculate bonuses */
2514 p_ptr->update |= (PU_BONUS);
2515
2516 /* Redraw hunger */
2517 p_ptr->redraw |= (PR_HUNGER);
2518
2519 /* Handle stuff */
2520 handle_stuff();
2521
2522 /* Result */
2523 return (TRUE);
2524 }
2525
2526 /*
2527 * Increases a stat by one randomized level -RAK-
2528 *
2529 * Note that this function (used by stat potions) now restores
2530 * the stat BEFORE increasing it.
2531 */
inc_stat(int stat)2532 bool inc_stat(int stat)
2533 {
2534 int value, gain;
2535 int min_gain, max_gain;
2536
2537 int cap = stat_cap(stat);
2538
2539 /* Then augment the current/max stat */
2540 value = p_ptr->stat[stat].cur;
2541
2542 /* Cannot go above limit */
2543 if (value < cap)
2544 {
2545 min_gain = (cap - value) / 6;
2546 max_gain = (cap - value) / 3;
2547
2548 if (min_gain > 5) min_gain = 5;
2549 if (min_gain < 1) min_gain = 1;
2550 if (max_gain > 20) max_gain = 20;
2551 if (max_gain < 1) max_gain = 1;
2552
2553 gain = rand_range(min_gain, max_gain);
2554 value += gain;
2555
2556 /* Save the new value */
2557 p_ptr->stat[stat].cur = value;
2558
2559 /* Bring up the maximum too */
2560 if (value > p_ptr->stat[stat].max)
2561 {
2562 p_ptr->stat[stat].max = value;
2563 }
2564
2565 /* Recalculate bonuses */
2566 p_ptr->update |= (PU_BONUS);
2567
2568 /* Success */
2569 return (TRUE);
2570 }
2571
2572 /* Nothing to gain */
2573 return (FALSE);
2574 }
2575
2576
2577
2578 /*
2579 * Decreases a stat by an amount indended to vary from 0 to 100 percent.
2580 *
2581 * Amount could be a little higher in extreme cases to mangle very high
2582 * stats from massive assaults. -CWS
2583 *
2584 * Note that "permanent" means that the *given* amount is permanent,
2585 * not that the new value becomes permanent. This may not work exactly
2586 * as expected, due to "weirdness" in the algorithm, but in general,
2587 * if your stat is already drained, the "max" value will not drop all
2588 * the way down to the "cur" value.
2589 */
dec_stat(int stat,int amount,int permanent)2590 bool dec_stat(int stat, int amount, int permanent)
2591 {
2592 int cur, max, same, res = FALSE;
2593
2594
2595 /* Acquire current value */
2596 cur = p_ptr->stat[stat].cur;
2597 max = p_ptr->stat[stat].max;
2598
2599 /* Note when the values are identical */
2600 same = (cur == max);
2601
2602 /* Damage "current" value */
2603 if (cur > 30)
2604 {
2605 if (cur > 30 && amount > 90) cur -= rand_range(3, cur / 10);
2606 if (cur > 30 && amount > 50) cur -= rand_range(3, cur / 10);
2607 if (cur > 30 && amount > 20) cur -= rand_range(3, cur / 10);
2608 if (cur > 30) cur -= rand_range(3, cur / 10);
2609
2610 /* Prevent illegal values */
2611 if (cur < 30) cur = 30;
2612
2613 /* Something happened */
2614 if (cur != p_ptr->stat[stat].cur) res = TRUE;
2615 }
2616
2617 /* Damage "max" value */
2618 if (permanent && (max > 30))
2619 {
2620 chg_virtue(V_SACRIFICE, 1);
2621 if (stat == A_WIS || stat == A_INT)
2622 chg_virtue(V_ENLIGHTEN, -2);
2623
2624 if (max > 30 && amount > 90) max -= rand_range(3, max / 10);
2625 if (max > 30 && amount > 50) max -= rand_range(3, max / 10);
2626 if (max > 30 && amount > 20) max -= rand_range(3, max / 10);
2627 if (max > 30) max -= rand_range(3, max / 10);
2628
2629 /* Hack -- keep it clean */
2630 if (same || (max < cur)) max = cur;
2631
2632 /* Something happened */
2633 if (max != p_ptr->stat[stat].max) res = TRUE;
2634 }
2635
2636 /* Apply changes */
2637 if (res)
2638 {
2639 /* Actually set the stat to its new value. */
2640 p_ptr->stat[stat].cur = cur;
2641 p_ptr->stat[stat].max = max;
2642
2643 /* Recalculate bonuses */
2644 p_ptr->update |= (PU_BONUS);
2645 }
2646
2647 /* Done */
2648 return (res);
2649 }
2650
2651
2652 /*
2653 * Restore a stat. Return TRUE only if this actually makes a difference.
2654 */
res_stat(int stat)2655 bool res_stat(int stat)
2656 {
2657 /* Restore if needed */
2658 if (p_ptr->stat[stat].cur != p_ptr->stat[stat].max)
2659 {
2660 /* Restore */
2661 p_ptr->stat[stat].cur = p_ptr->stat[stat].max;
2662
2663 /* Recalculate bonuses */
2664 p_ptr->update |= (PU_BONUS);
2665
2666 /* Success */
2667 return (TRUE);
2668 }
2669
2670 /* Nothing to restore */
2671 return (FALSE);
2672 }
2673
2674
2675 /*
2676 * Increase players hit points, notice effects
2677 */
hp_player(int num)2678 bool hp_player(int num)
2679 {
2680 /* Healing needed */
2681 if (p_ptr->chp < p_ptr->mhp)
2682 {
2683 chg_virtue(V_CHANCE, -1);
2684 if ((num > 0) && (p_ptr->chp < (p_ptr->mhp / 3)))
2685 chg_virtue(V_TEMPERANCE, 1);
2686
2687 /* Gain hitpoints */
2688 p_ptr->chp += num;
2689
2690 /* Enforce maximum */
2691 if (p_ptr->chp >= p_ptr->mhp)
2692 {
2693 p_ptr->chp = p_ptr->mhp;
2694 p_ptr->chp_frac = 0;
2695 }
2696
2697 /* Redraw */
2698 p_ptr->redraw |= (PR_HP);
2699
2700 /* Window stuff */
2701 p_ptr->window |= (PW_PLAYER);
2702
2703 /* Heal 0-4 */
2704 if (num < 5)
2705 {
2706 msgf("You feel a little better.");
2707 }
2708
2709 /* Heal 5-14 */
2710 else if (num < 15)
2711 {
2712 msgf("You feel better.");
2713 }
2714
2715 /* Heal 15-34 */
2716 else if (num < 35)
2717 {
2718 msgf("You feel much better.");
2719 }
2720
2721 /* Heal 35+ */
2722 else
2723 {
2724 msgf("You feel very good.");
2725 }
2726
2727 /* Notice */
2728 return (TRUE);
2729 }
2730
2731 /* Ignore */
2732 return (FALSE);
2733 }
2734
2735
2736 /*
2737 * Array of stat "descriptions"
2738 */
2739 static cptr desc_stat_pos[] =
2740 {
2741 "strong",
2742 "smart",
2743 "wise",
2744 "dextrous",
2745 "healthy",
2746 "cute"
2747 };
2748
2749
2750 /*
2751 * Array of stat "descriptions"
2752 */
2753 static cptr desc_stat_neg[] =
2754 {
2755 "weak",
2756 "stupid",
2757 "naive",
2758 "clumsy",
2759 "sickly",
2760 "ugly"
2761 };
2762
2763
2764 /*
2765 * Lose a "point"
2766 */
do_dec_stat(int stat)2767 bool do_dec_stat(int stat)
2768 {
2769 bool sust = FALSE;
2770
2771 /* Access the "sustain" */
2772 switch (stat)
2773 {
2774 case A_STR:
2775 {
2776 if (FLAG(p_ptr, TR_SUST_STR)) sust = TRUE;
2777 break;
2778 }
2779 case A_INT:
2780 {
2781 if (FLAG(p_ptr, TR_SUST_INT)) sust = TRUE;
2782 break;
2783 }
2784 case A_WIS:
2785 {
2786 if (FLAG(p_ptr, TR_SUST_WIS)) sust = TRUE;
2787 break;
2788 }
2789 case A_DEX:
2790 {
2791 if (FLAG(p_ptr, TR_SUST_DEX)) sust = TRUE;
2792 break;
2793 }
2794 case A_CON:
2795 {
2796 if (FLAG(p_ptr, TR_SUST_CON)) sust = TRUE;
2797 break;
2798 }
2799 case A_CHR:
2800 {
2801 if (FLAG(p_ptr, TR_SUST_CHR)) sust = TRUE;
2802 break;
2803 }
2804 }
2805
2806 /* Sustain */
2807 if (sust && !(ironman_nightmare && one_in_(13)))
2808 {
2809 /* Message */
2810 msgf("You feel %s for a moment, but the feeling passes.",
2811 desc_stat_neg[stat]);
2812
2813 /* Notice effect */
2814 return (TRUE);
2815 }
2816
2817 /* Attempt to reduce the stat */
2818 if (dec_stat(stat, 10, (ironman_nightmare && !one_in_(13))))
2819 {
2820 /* Message */
2821 msgf("You feel very %s.", desc_stat_neg[stat]);
2822
2823 /* Notice effect */
2824 return (TRUE);
2825 }
2826
2827 /* Nothing obvious */
2828 return (FALSE);
2829 }
2830
2831
2832 /*
2833 * Restore lost "points" in a stat
2834 */
do_res_stat(int stat)2835 bool do_res_stat(int stat)
2836 {
2837 /* Attempt to increase */
2838 if (res_stat(stat))
2839 {
2840 /* Message */
2841 msgf("You feel less %s.", desc_stat_neg[stat]);
2842
2843 /* Notice */
2844 return (TRUE);
2845 }
2846
2847 /* Nothing obvious */
2848 return (FALSE);
2849 }
2850
2851
2852 /*
2853 * Gain a "point" in a stat
2854 */
do_inc_stat(int stat)2855 bool do_inc_stat(int stat)
2856 {
2857 bool res;
2858
2859 /* Restore strength */
2860 res = res_stat(stat);
2861
2862 /* Attempt to increase */
2863 if (inc_stat(stat))
2864 {
2865 if (stat == A_WIS)
2866 {
2867 chg_virtue(V_ENLIGHTEN, 1);
2868 chg_virtue(V_FAITH, 1);
2869 }
2870 else if (stat == A_INT)
2871 {
2872 chg_virtue(V_KNOWLEDGE, 1);
2873 chg_virtue(V_ENLIGHTEN, 1);
2874 }
2875 else if (stat == A_CON)
2876 chg_virtue(V_VITALITY, 1);
2877
2878 /* Message */
2879 msgf("Wow! You feel very %s!", desc_stat_pos[stat]);
2880
2881 /* Notice */
2882 return (TRUE);
2883 }
2884
2885 /* Restoration worked */
2886 if (res)
2887 {
2888 /* Message */
2889 msgf("You feel less %s.", desc_stat_neg[stat]);
2890
2891 /* Notice */
2892 return (TRUE);
2893 }
2894
2895 /* Nothing obvious */
2896 return (FALSE);
2897 }
2898
2899
2900 /*
2901 * Restores any drained experience
2902 */
restore_level(void)2903 bool restore_level(void)
2904 {
2905 /* Restore experience */
2906 if (p_ptr->exp < p_ptr->max_exp)
2907 {
2908 /* Message */
2909 msgf("You feel your life energies returning.");
2910
2911 /* Restore the experience */
2912 p_ptr->exp = p_ptr->max_exp;
2913
2914 /* Check the experience */
2915 check_experience();
2916
2917 /* Did something */
2918 return (TRUE);
2919 }
2920
2921 /* No effect */
2922 return (FALSE);
2923 }
2924
2925
2926 /*
2927 * Forget everything
2928 */
lose_all_info(void)2929 bool lose_all_info(void)
2930 {
2931 int i, k;
2932
2933 object_type *o_ptr;
2934
2935 chg_virtue(V_KNOWLEDGE, -5);
2936 chg_virtue(V_ENLIGHTEN, -5);
2937
2938 /* Forget info about equipment */
2939 for (i = 0; i < EQUIP_MAX; i++)
2940 {
2941 o_ptr = &p_ptr->equipment[i];
2942
2943 /* Skip non-objects */
2944 if (!o_ptr->k_idx) continue;
2945
2946 /* Allow "protection" if know all the flags... */
2947 if (object_known_full(o_ptr)) continue;
2948
2949 /* Remove "default inscriptions" */
2950 o_ptr->feeling = FEEL_NONE;
2951
2952 /* Hack -- Clear the "empty" flag */
2953 o_ptr->info &= ~(OB_EMPTY);
2954
2955 /* Hack -- Clear the "known" flag */
2956 o_ptr->info &= ~(OB_KNOWN);
2957
2958 /* Hack -- Clear the "felt" flag */
2959 o_ptr->info &= ~(OB_SENSE);
2960 }
2961
2962 /* Forget info about objects */
2963 OBJ_ITT_START (p_ptr->inventory, o_ptr)
2964 {
2965 /* Allow "protection" if know all the flags... */
2966 if (object_known_full(o_ptr)) continue;
2967
2968 /* Remove "default inscriptions" */
2969 o_ptr->feeling = FEEL_NONE;
2970
2971 /* Hack -- Clear the "empty" flag */
2972 o_ptr->info &= ~(OB_EMPTY);
2973
2974 /* Hack -- Clear the "known" flag */
2975 o_ptr->info &= ~(OB_KNOWN);
2976
2977 /* Hack -- Clear the "felt" flag */
2978 o_ptr->info &= ~(OB_SENSE);
2979 }
2980 OBJ_ITT_END;
2981
2982 /* Hack - Remove all knowledge about objects */
2983
2984 /* Scan the object kinds */
2985 for (k = 1; k < z_info->k_max; k++)
2986 {
2987 object_kind *k_ptr = &k_info[k];
2988
2989 /* Forget flavored items, with saving throw */
2990 if (k_ptr->flavor && !player_save(k_ptr->level - 50))
2991 {
2992 /* Forget knowledge */
2993 k_ptr->aware = FALSE;
2994 k_ptr->tried = FALSE;
2995 }
2996 }
2997
2998 /* Recalculate bonuses */
2999 p_ptr->update |= (PU_BONUS);
3000
3001 /* Window stuff */
3002 p_ptr->window |= (PW_PLAYER);
3003
3004 /* Notice changes */
3005 notice_item();
3006
3007 /* Mega-Hack -- Forget the map */
3008 wiz_dark();
3009
3010 /* It worked */
3011 return (TRUE);
3012 }
3013
3014
do_poly_wounds(void)3015 void do_poly_wounds(void)
3016 {
3017 /* Changed to always provide at least _some_ healing */
3018 s16b wounds = p_ptr->tim.cut;
3019 s16b hit_p = (p_ptr->mhp - p_ptr->chp);
3020 s16b change = damroll(p_ptr->lev, 5);
3021 bool Nasty_effect = (one_in_(5));
3022
3023 if (!(wounds || hit_p || Nasty_effect)) return;
3024
3025 msgf("Your wounds are polymorphed into less serious ones.");
3026 (void)hp_player(change);
3027 if (Nasty_effect)
3028 {
3029 msgf("A new wound was created!");
3030 take_hit(change / 2, "a polymorphed wound");
3031 (void)set_cut(change);
3032 }
3033 else
3034 {
3035 (void)set_cut(p_ptr->tim.cut - (change / 2));
3036 }
3037 }
3038
3039
do_poly_self(void)3040 void do_poly_self(void)
3041 {
3042 int i;
3043 int power = p_ptr->lev;
3044
3045 msgf("You feel a change coming over you...");
3046
3047 chg_virtue(V_CHANCE, 1);
3048
3049 if ((power > randint0(20)) && one_in_(3))
3050 {
3051 char effect_msg[80] = "";
3052 int old_race, new_race, expfact, goalexpfact;
3053
3054 /* Some form of racial polymorph... */
3055 power -= 10;
3056
3057 if ((power > randint0(5)) && one_in_(4))
3058 {
3059 /* sex change */
3060 power -= 2;
3061
3062 if (p_ptr->rp.psex == SEX_MALE)
3063 {
3064 p_ptr->rp.psex = SEX_FEMALE;
3065 sp_ptr = &sex_info[p_ptr->rp.psex];
3066 strnfmt(effect_msg, 80, "female ");
3067 }
3068 else
3069 {
3070 p_ptr->rp.psex = SEX_MALE;
3071 sp_ptr = &sex_info[p_ptr->rp.psex];
3072 strnfmt(effect_msg, 80, "male ");
3073 }
3074 }
3075
3076 if ((power > randint0(30)) && one_in_(5))
3077 {
3078 int tmp = 0;
3079
3080 /* Harmful deformity */
3081 power -= 15;
3082
3083 while (tmp < A_MAX)
3084 {
3085 if (one_in_(2))
3086 {
3087 (void)dec_stat(tmp, rand_range(6, 12), one_in_(3));
3088 power -= 1;
3089 }
3090 tmp++;
3091 }
3092
3093 /* Deformities are discriminated against! */
3094 (void)dec_stat(A_CHR, randint1(6), TRUE);
3095
3096 if (effect_msg[0])
3097 {
3098 strnfmt(effect_msg, 80, "deformed %s ", effect_msg);
3099 }
3100 else
3101 {
3102 strnfmt(effect_msg, 80, "deformed ");
3103 }
3104 }
3105
3106 while ((power > randint0(20)) && one_in_(10))
3107 {
3108 /* Polymorph into a less mutated form */
3109 power -= 10;
3110
3111 if (!lose_mutation(0))
3112 msgf("You feel oddly normal.");
3113 }
3114
3115 /*
3116 * Restrict the race choices by exp penalty so
3117 * weak polymorph always means weak race
3118 */
3119 if (power < 0)
3120 goalexpfact = 100;
3121 else
3122 goalexpfact = 100 + 3 * randint0(power);
3123
3124 do
3125 {
3126 new_race = randint0(MAX_RACES);
3127 expfact = race_info[new_race].r_exp;
3128 }
3129 while ((new_race == p_ptr->rp.prace) && (expfact > goalexpfact));
3130
3131 if (!effect_msg[0])
3132 {
3133 msgf("You turn into a%s %s!",
3134 (((new_race == RACE_AMBERITE) ||
3135 (new_race == RACE_ELF) ||
3136 (new_race == RACE_IMP)) ? "n" : ""),
3137 race_info[new_race].title);
3138 }
3139 else
3140 {
3141 msgf("You turn into a %s%s!", effect_msg,
3142 race_info[new_race].title);
3143 }
3144
3145 chg_virtue(V_CHANCE, 2);
3146
3147 old_race = p_ptr->rp.prace;
3148 p_ptr->rp.prace = new_race;
3149 rp_ptr = &race_info[p_ptr->rp.prace];
3150
3151 /* Adjust the stats */
3152 for (i = 0; i < A_MAX; i++)
3153 {
3154 int change;
3155
3156 /* Calculate the difference between the races */
3157 change = rp_ptr->r_adj[i] - race_info[old_race].r_adj[i];
3158
3159 /* Adjust current stat */
3160 p_ptr->stat[i].cur = adjust_stat(i, p_ptr->stat[i].cur, change);
3161
3162 /* Adjust maximum stat */
3163 p_ptr->stat[i].max = adjust_stat(i, p_ptr->stat[i].max, change);
3164 }
3165
3166 /* Experience factor */
3167 p_ptr->expfact = rp_ptr->r_exp + cp_ptr->c_exp;
3168
3169 /* Calculate the height/weight for males */
3170 if (p_ptr->rp.psex == SEX_MALE)
3171 {
3172 p_ptr->rp.ht = Rand_normal(rp_ptr->m_b_ht, rp_ptr->m_m_ht);
3173 p_ptr->rp.wt = Rand_normal(rp_ptr->m_b_wt, rp_ptr->m_m_wt);
3174 }
3175
3176 /* Calculate the height/weight for females */
3177 else if (p_ptr->rp.psex == SEX_FEMALE)
3178 {
3179 p_ptr->rp.ht = Rand_normal(rp_ptr->f_b_ht, rp_ptr->f_m_ht);
3180 p_ptr->rp.wt = Rand_normal(rp_ptr->f_b_wt, rp_ptr->f_m_wt);
3181 }
3182
3183 check_experience();
3184 p_ptr->max_lev = p_ptr->lev;
3185
3186 p_ptr->redraw |= (PR_BASIC);
3187
3188 p_ptr->update |= (PU_BONUS);
3189
3190 handle_stuff();
3191 lite_spot(p_ptr->px, p_ptr->py);
3192 }
3193
3194 if ((power > randint0(30)) && one_in_(6))
3195 {
3196 int tmp = 0;
3197
3198 /* Abomination! */
3199 power -= 20;
3200
3201 msgf("Your internal organs are rearranged!");
3202 while (tmp < A_MAX)
3203 {
3204 (void)dec_stat(tmp, rand_range(6, 12), one_in_(3));
3205 tmp++;
3206 }
3207 if (one_in_(6))
3208 {
3209 msgf("You find living difficult in your present form!");
3210 take_hit(damroll(randint1(10), p_ptr->lev), "a lethal mutation");
3211 power -= 10;
3212 }
3213 }
3214
3215 if ((power > randint0(20)) && one_in_(4))
3216 {
3217 power -= 10;
3218
3219 do_cmd_rerate();
3220 }
3221
3222 while ((power > randint0(15)) && one_in_(3))
3223 {
3224 power -= 7;
3225 (void)gain_mutation(0);
3226 }
3227
3228 if (power > randint0(5))
3229 {
3230 power -= 5;
3231 do_poly_wounds();
3232 }
3233
3234 /* Note: earlier deductions may have left power < 0 already. */
3235 while (power > 0)
3236 {
3237 mutate_player();
3238 power--;
3239 }
3240
3241 /* Hack - reset visuals so the player's tile can change */
3242 reset_visuals();
3243 }
3244
3245
3246 /*
3247 * Decreases players hit points and sets death flag if necessary
3248 *
3249 * XXX XXX XXX Invulnerability needs to be changed into a "shield"
3250 *
3251 * XXX XXX XXX Hack -- this function allows the user to save (or quit)
3252 * the game when he dies, since the "You die." message is shown before
3253 * setting the player to "dead".
3254 */
take_hit(int damage,cptr hit_from)3255 void take_hit(int damage, cptr hit_from)
3256 {
3257 int old_chp = p_ptr->chp;
3258
3259 bool pen_invuln = FALSE;
3260
3261 char death_message[1024];
3262
3263 int warning = (p_ptr->mhp * hitpoint_warn / 10);
3264
3265
3266 /* Paranoia */
3267 if (p_ptr->state.is_dead) return;
3268
3269 /* Disturb */
3270 disturb(TRUE);
3271
3272 /* Mega-Hack -- Apply "invulnerability" */
3273 if (p_ptr->tim.invuln && (damage < 9000))
3274 {
3275 if (one_in_(PENETRATE_INVULNERABILITY))
3276 {
3277 pen_invuln = TRUE;
3278 }
3279 else
3280 {
3281 return;
3282 }
3283 }
3284
3285 if (p_ptr->tim.wraith_form)
3286 {
3287 damage /= 10;
3288 if ((damage == 0) && one_in_(10)) damage = 1;
3289 }
3290
3291 /* Hurt the player */
3292 p_ptr->chp -= damage;
3293
3294 /* Display the hitpoints */
3295 p_ptr->redraw |= (PR_HP);
3296
3297 /* Window stuff */
3298 p_ptr->window |= (PW_PLAYER);
3299
3300 /* Do not skip the message */
3301 p_ptr->state.skip_more = FALSE;
3302
3303 if (pen_invuln)
3304 msgf("The attack penetrates your shield of invulnerability!");
3305
3306 if (!(p_ptr->tim.invuln) || (pen_invuln))
3307 {
3308 if (p_ptr->chp == 0)
3309 {
3310 chg_virtue(V_SACRIFICE, 1);
3311 chg_virtue(V_CHANCE, 2);
3312 }
3313 }
3314
3315 /* Dead player */
3316 if (p_ptr->chp < 0)
3317 {
3318 int len;
3319
3320 /* Sound */
3321 sound(SOUND_DEATH);
3322
3323 chg_virtue(V_SACRIFICE, 10);
3324
3325 /* Hack -- Note death */
3326 if (!last_words)
3327 {
3328 msgf(MSGT_DEATH, "You die.");
3329 message_flush();
3330 }
3331 else
3332 {
3333 if (!get_rnd_line("death.txt", 0, death_message))
3334 msgf(death_message);
3335 }
3336
3337 /* Note cause of death */
3338 len = strnfmt(p_ptr->state.died_from, 80, hit_from);
3339
3340 if (p_ptr->tim.image) strnfcat(p_ptr->state.died_from, 80, &len, "(?)");
3341
3342 /* No longer a winner */
3343 p_ptr->state.total_winner = FALSE;
3344
3345 /* Leaving */
3346 p_ptr->state.leaving = TRUE;
3347
3348 /* Note death */
3349 p_ptr->state.is_dead = TRUE;
3350
3351 if (get_check("Dump the screen? "))
3352 {
3353 do_cmd_save_screen();
3354 }
3355
3356 /* Dead */
3357 return;
3358 }
3359
3360 /* Hitpoint warning */
3361 if (p_ptr->chp <= warning)
3362 {
3363 /* Hack -- bell on first notice */
3364 if (old_chp > warning)
3365 {
3366 /* Alert */
3367 bell("Low hitpoint warning!");
3368
3369 if (emergency_stop)
3370 {
3371 /* Show all the messages */
3372 message_flush();
3373
3374 /* Alert the user to the problem */
3375 put_fstr(0, 0, "Emergency stop. Press 'c' to continue.");
3376
3377 /* Wait for acknowledgement */
3378 while (inkey() != 'c') ;
3379
3380 disturb(TRUE);
3381 }
3382 }
3383
3384 sound(SOUND_WARN);
3385
3386 /* Message */
3387 msgf(MSGT_HITPOINT_WARN, "*** LOW HITPOINT WARNING! ***");
3388 message_flush();
3389 }
3390 }
3391
3392
3393 /*
3394 * Gain experience
3395 */
gain_exp(s32b amount)3396 void gain_exp(s32b amount)
3397 {
3398 /* Gain some experience */
3399 p_ptr->exp += amount;
3400
3401 /* Slowly recover from experience drainage */
3402 if (p_ptr->exp < p_ptr->max_exp)
3403 {
3404 /* Gain max experience (20%) (was 10%) */
3405 p_ptr->max_exp += amount / 5;
3406 }
3407
3408 /* Check Experience */
3409 check_experience();
3410 }
3411
3412
3413 /*
3414 * Lose experience
3415 */
lose_exp(s32b amount)3416 void lose_exp(s32b amount)
3417 {
3418 /* Never drop below zero experience */
3419 if (amount > p_ptr->exp) amount = p_ptr->exp;
3420
3421 /* Lose some experience */
3422 p_ptr->exp -= amount;
3423
3424 /* Check Experience */
3425 check_experience();
3426 }
3427
3428 /*
3429 * Make some noise
3430 */
make_noise(byte amount)3431 void make_noise(byte amount)
3432 {
3433 int total = amount + p_ptr->state.noise_level;
3434
3435 /* Paranoia (watching for overflow) */
3436 if (total > MONSTER_FLOW_DEPTH)
3437 {
3438 total = MONSTER_FLOW_DEPTH;
3439 }
3440
3441 /* Update the flow if this gets too high */
3442 if (total >= 3 * MONSTER_FLOW_DEPTH / 4)
3443 {
3444 p_ptr->update |= PU_FLOW;
3445 }
3446
3447 /* Save the new noise level */
3448 p_ptr->state.noise_level = (byte)total;
3449 }
3450
3451
3452 /*
3453 * Various notice 'blah' functions
3454 */
3455
3456
3457 /*
3458 * Change an item in the inventory
3459 */
notice_inven(void)3460 void notice_inven(void)
3461 {
3462 /* Combine / Reorder the pack (later) */
3463 p_ptr->notice |= (PN_COMBINE | PN_REORDER);
3464
3465 /* Window stuff */
3466 p_ptr->window |= (PW_INVEN);
3467 }
3468
3469
3470 /*
3471 * Change an item in the equipment
3472 */
notice_equip(void)3473 void notice_equip(void)
3474 {
3475 /* Window stuff */
3476 p_ptr->window |= (PW_EQUIP);
3477 }
3478
3479
3480 /*
3481 * Change an item somewhere
3482 */
notice_item(void)3483 void notice_item(void)
3484 {
3485 notice_inven();
3486 notice_equip();
3487 }
3488
3489
3490 /*
3491 * Something has happened to disturb the player.
3492 *
3493 * The arg indicates a major disturbance, which affects search.
3494 *
3495 * All disturbance cancels repeated commands, resting, and running.
3496 */
disturb(bool stop_search)3497 void disturb(bool stop_search)
3498 {
3499 /* Cancel repeated commands */
3500 if (p_ptr->cmd.rep)
3501 {
3502 /* Cancel */
3503 p_ptr->cmd.rep = 0;
3504
3505 /* Redraw the state (later) */
3506 p_ptr->redraw |= (PR_STATE);
3507 }
3508
3509 /* Cancel Resting */
3510 if (p_ptr->state.resting)
3511 {
3512 /* Cancel */
3513 p_ptr->state.resting = 0;
3514
3515 /* Redraw the state (later) */
3516 p_ptr->redraw |= (PR_STATE);
3517 }
3518
3519 /* Cancel running */
3520 if (p_ptr->state.running)
3521 {
3522 /* Cancel */
3523 p_ptr->state.running = 0;
3524
3525 /* Check for new panel if appropriate */
3526 if (center_player && avoid_center) verify_panel();
3527
3528 /* Calculate torch radius */
3529 p_ptr->update |= (PU_TORCH);
3530 }
3531
3532 /* Cancel searching if requested */
3533 if (stop_search && p_ptr->state.searching)
3534 {
3535 /* Cancel */
3536 p_ptr->state.searching = FALSE;
3537
3538 /* Recalculate bonuses */
3539 p_ptr->update |= (PU_BONUS);
3540
3541 /* Redraw the state */
3542 p_ptr->redraw |= (PR_STATE);
3543 }
3544
3545 /* Flush the input if requested */
3546 if (flush_disturb) flush();
3547 }
3548
3549