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 "mangband.h"
14
15 #define TOGGLE_BIT(WHAT, BIT) (WHAT) ^= (BIT)
16
get_player(player_type * p_ptr,object_type * o_ptr)17 int get_player(player_type *p_ptr, object_type *o_ptr)
18 {
19 /* player_type *p_ptr = Players[Ind]; */
20 bool ok = FALSE;
21 int Ind2;
22
23 char * inscription = ( char *) quark_str(o_ptr->note);
24
25 /* check for a valid inscription */
26 if (inscription == NULL)
27 {
28 msg_print(p_ptr, "Nobody to use the power with.");
29 return 0;
30 }
31
32 /* scan the inscription for @P */
33 while ((*inscription != '\0') && !ok)
34 {
35
36 if (*inscription == '@')
37 {
38 inscription++;
39
40 /* a valid @P has been located */
41 if (*inscription == 'P')
42 {
43 inscription++;
44
45 Ind2 = find_player_name(inscription);
46 if (Ind2) ok = TRUE;
47 }
48 }
49 inscription++;
50 }
51
52 if (!ok)
53 {
54 msg_print(p_ptr, "Player is not on.");
55 return 0;
56 }
57
58 return Ind2;
59 }
60
player_dump(player_type * p_ptr)61 void player_dump(player_type *p_ptr)
62 {
63 char dumpname[42];
64 strnfmt(dumpname, 42, "%s-%s.txt", p_ptr->name, ht_show(&turn,0));
65 file_character_server(p_ptr,dumpname);
66 }
67
68 /*
69 * Set "p_ptr->noise", cap it.
70 */
set_noise(player_type * p_ptr,int v)71 bool set_noise(player_type *p_ptr, int v)
72 {
73 /* Hack -- Force good values */
74 v = (v > 60) ? 60 : (v < 0) ? 0 : v;
75
76 /* Use the value */
77 p_ptr->noise = v;
78
79 return TRUE;
80 }
81
82 /*
83 * Set "p_ptr->blind", notice observable changes
84 *
85 * Note the use of "PU_UN_LITE" and "PU_UN_VIEW", which is needed to
86 * memorize any terrain features which suddenly become "visible".
87 * Note that blindness is currently the only thing which can affect
88 * "player_can_see_bold()".
89 */
set_blind(player_type * p_ptr,int v)90 bool set_blind(player_type *p_ptr, int v)
91 {
92 bool notice = FALSE;
93
94 /* the admin wizard can not be blinded */
95 if (p_ptr->dm_flags & DM_INVULNERABLE) return 1;
96
97 /* Hack -- Force good values */
98 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
99
100 /* Open */
101 if (v)
102 {
103 if (!p_ptr->blind)
104 {
105 msg_format_near(p_ptr, "%s gropes around blindly!", p_ptr->name);
106 msg_print(p_ptr, "You are blind!");
107 sound(p_ptr, MSG_BLIND);
108 notice = TRUE;
109 }
110 }
111
112 /* Shut */
113 else
114 {
115 if (p_ptr->blind)
116 {
117 msg_format_near(p_ptr, "%s can see again.", p_ptr->name);
118 msg_print(p_ptr, "You can see again.");
119 sound(p_ptr, MSG_RECOVER);
120 notice = TRUE;
121 }
122 }
123
124 /* Use the value */
125 p_ptr->blind = v;
126
127 /* Nothing to notice */
128 if (!notice) return (FALSE);
129
130 /* Disturb */
131 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
132
133 /* Forget stuff */
134 p_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
135
136 /* Update stuff */
137 p_ptr->update |= (PU_VIEW | PU_LITE);
138
139 /* Update the monsters */
140 p_ptr->update |= (PU_MONSTERS);
141
142 /* Redraw map */
143 p_ptr->redraw |= (PR_MAP);
144
145 /* Redraw the "blind" */
146 p_ptr->redraw |= (PR_BLIND);
147
148 /* Window stuff */
149 p_ptr->window |= (PW_OVERHEAD);
150
151 /* Handle stuff */
152 handle_stuff(p_ptr);
153
154 /* Result */
155 return (TRUE);
156 }
157
158
159 /*
160 * Set "p_ptr->confused", notice observable changes
161 */
set_confused(player_type * p_ptr,int v)162 bool set_confused(player_type *p_ptr, int v)
163 {
164 bool notice = FALSE;
165
166 /* Hack -- Force good values */
167 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
168
169 /* Open */
170 if (v)
171 {
172 if (!p_ptr->confused)
173 {
174 msg_format_near(p_ptr, "%s appears confused!", p_ptr->name);
175 msg_print(p_ptr, "You are confused!");
176 sound(p_ptr, MSG_CONFUSED);
177 notice = TRUE;
178 }
179 }
180
181 /* Shut */
182 else
183 {
184 if (p_ptr->confused)
185 {
186 msg_print(p_ptr, "You feel less confused now.");
187 sound(p_ptr, MSG_RECOVER);
188 notice = TRUE;
189 }
190 }
191
192 /* Use the value */
193 p_ptr->confused = v;
194
195 /* Nothing to notice */
196 if (!notice) return (FALSE);
197
198 /* Disturb */
199 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
200
201 /* Redraw the "confused" */
202 p_ptr->redraw |= (PR_CONFUSED);
203
204 /* Handle stuff */
205 handle_stuff(p_ptr);
206
207 /* Result */
208 return (TRUE);
209 }
210
211
212 /*
213 * Set "p_ptr->poisoned", notice observable changes
214 */
set_poisoned(player_type * p_ptr,int v)215 bool set_poisoned(player_type *p_ptr, int v)
216 {
217 bool notice = FALSE;
218
219 /* Hack -- Force good values */
220 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
221
222 /* Open */
223 if (v)
224 {
225 if (!p_ptr->poisoned)
226 {
227 msg_print(p_ptr, "You are poisoned!");
228 sound(p_ptr, MSG_POISONED);
229 notice = TRUE;
230 }
231 }
232
233 /* Shut */
234 else
235 {
236 if (p_ptr->poisoned)
237 {
238 msg_print(p_ptr, "You are no longer poisoned.");
239 sound(p_ptr, MSG_RECOVER);
240 notice = TRUE;
241 }
242 }
243
244 /* Use the value */
245 p_ptr->poisoned = v;
246
247 /* Nothing to notice */
248 if (!notice) return (FALSE);
249
250 /* Disturb */
251 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
252
253 /* Redraw the "poisoned" */
254 p_ptr->redraw |= (PR_POISONED);
255
256 /* Handle stuff */
257 handle_stuff(p_ptr);
258
259 /* Result */
260 return (TRUE);
261 }
262
263
264 /*
265 * Set "p_ptr->afraid", notice observable changes
266 */
set_afraid(player_type * p_ptr,int v)267 bool set_afraid(player_type *p_ptr, int v)
268 {
269 bool notice = FALSE;
270
271 /* Hack -- Force good values */
272 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
273
274 /* Open */
275 if (v)
276 {
277 if (!p_ptr->afraid)
278 {
279 msg_format_near(p_ptr, "%s cowers in fear!", p_ptr->name);
280 msg_print(p_ptr, "You are terrified!");
281 sound(p_ptr, MSG_AFRAID);
282 notice = TRUE;
283 }
284 }
285
286 /* Shut */
287 else
288 {
289 if (p_ptr->afraid)
290 {
291 msg_format_near(p_ptr, "%s appears bolder now.", p_ptr->name);
292 msg_print(p_ptr, "You feel bolder now.");
293 sound(p_ptr, MSG_RECOVER);
294 notice = TRUE;
295 }
296 }
297
298 /* Use the value */
299 p_ptr->afraid = v;
300
301 /* Nothing to notice */
302 if (!notice) return (FALSE);
303
304 /* Disturb */
305 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
306
307 /* Redraw the "afraid" */
308 p_ptr->redraw |= (PR_AFRAID);
309
310 /* Handle stuff */
311 handle_stuff(p_ptr);
312
313 /* Result */
314 return (TRUE);
315 }
316
317
318 /*
319 * Set "p_ptr->paralyzed", notice observable changes
320 */
set_paralyzed(player_type * p_ptr,int v)321 bool set_paralyzed(player_type *p_ptr, int v)
322 {
323 bool notice = FALSE;
324
325 /* Hack -- Force good values */
326 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
327
328 /* Open */
329 if (v)
330 {
331 if (!p_ptr->paralyzed)
332 {
333 msg_format_near(p_ptr, "%s becomes rigid!", p_ptr->name);
334 msg_print(p_ptr, "You are paralyzed!");
335 sound(p_ptr, MSG_PARALYZED);
336 notice = TRUE;
337 }
338 }
339
340 /* Shut */
341 else
342 {
343 if (p_ptr->paralyzed)
344 {
345 msg_format_near(p_ptr, "%s can move again.", p_ptr->name);
346 msg_print(p_ptr, "You can move again.");
347 sound(p_ptr, MSG_RECOVER);
348 notice = TRUE;
349 }
350 }
351
352 /* Use the value */
353 p_ptr->paralyzed = v;
354
355 /* Nothing to notice */
356 if (!notice) return (FALSE);
357
358 /* Disturb */
359 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
360
361 /* Redraw the state */
362 p_ptr->redraw |= (PR_STATE);
363
364 /* Handle stuff */
365 handle_stuff(p_ptr);
366
367 /* Result */
368 return (TRUE);
369 }
370
371
372 /*
373 * Set "p_ptr->image", notice observable changes
374 *
375 * Note that we must redraw the map when hallucination changes.
376 */
set_image(player_type * p_ptr,int v)377 bool set_image(player_type *p_ptr, int v)
378 {
379 bool notice = FALSE;
380
381 /* Hack -- Force good values */
382 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
383
384 /* Open */
385 if (v)
386 {
387 if (!p_ptr->image)
388 {
389 msg_print(p_ptr, "You feel drugged!");
390 sound(p_ptr, MSG_DRUGGED);
391 notice = TRUE;
392 }
393 }
394
395 /* Shut */
396 else
397 {
398 if (p_ptr->image)
399 {
400 msg_print(p_ptr, "You can see clearly again.");
401 sound(p_ptr, MSG_RECOVER);
402 notice = TRUE;
403 }
404 }
405
406 /* Use the value */
407 p_ptr->image = v;
408
409 /* Nothing to notice */
410 if (!notice) return (FALSE);
411
412 /* Hack -- update hallucination seed */
413 p_ptr->image_seed++;
414
415 /* Disturb */
416 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
417
418 /* Redraw map */
419 p_ptr->redraw |= (PR_MAP);
420
421 /* Update monsters */
422 p_ptr->update |= (PU_MONSTERS);
423
424 /* Window stuff */
425 p_ptr->window |= (PW_OVERHEAD);
426
427 /* Handle stuff */
428 handle_stuff(p_ptr);
429
430 /* Result */
431 return (TRUE);
432 }
433
434
435 /*
436 * Set "p_ptr->fast", notice observable changes
437 */
set_fast(player_type * p_ptr,int v)438 bool set_fast(player_type *p_ptr, int v)
439 {
440 bool notice = FALSE;
441
442 /* Hack -- Force good values */
443 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
444
445 /* Open */
446 if (v)
447 {
448 if (!p_ptr->fast)
449 {
450 msg_format_near(p_ptr, "%s begins moving faster!", p_ptr->name);
451 msg_print(p_ptr, "You feel yourself moving faster!");
452 sound(p_ptr, MSG_SPEED);
453 notice = TRUE;
454 }
455 }
456
457 /* Shut */
458 else
459 {
460 if (p_ptr->fast)
461 {
462 msg_format_near(p_ptr, "%s slows down.", p_ptr->name);
463 msg_print(p_ptr, "You feel yourself slow down.");
464 sound(p_ptr, MSG_RECOVER);
465 notice = TRUE;
466 }
467 }
468
469 /* Use the value */
470 p_ptr->fast = v;
471
472 /* Nothing to notice */
473 if (!notice) return (FALSE);
474
475 /* Disturb */
476 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
477
478 /* Recalculate bonuses */
479 p_ptr->update |= (PU_BONUS);
480
481 /* Handle stuff */
482 handle_stuff(p_ptr);
483
484 /* Result */
485 return (TRUE);
486 }
487
488
489 /*
490 * Set "p_ptr->slow", notice observable changes
491 */
set_slow(player_type * p_ptr,int v)492 bool set_slow(player_type *p_ptr, int v)
493 {
494 bool notice = FALSE;
495
496 /* Hack -- Force good values */
497 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
498
499 /* Open */
500 if (v)
501 {
502 if (!p_ptr->slow)
503 {
504 msg_format_near(p_ptr, "%s begins moving slower!", p_ptr->name);
505 msg_print(p_ptr, "You feel yourself moving slower!");
506 sound(p_ptr, MSG_SLOW);
507 notice = TRUE;
508 }
509 }
510
511 /* Shut */
512 else
513 {
514 if (p_ptr->slow)
515 {
516 msg_format_near(p_ptr, "%s speeds up.", p_ptr->name);
517 msg_print(p_ptr, "You feel yourself speed up.");
518 sound(p_ptr, MSG_RECOVER);
519 notice = TRUE;
520 }
521 }
522
523 /* Use the value */
524 p_ptr->slow = v;
525
526 /* Nothing to notice */
527 if (!notice) return (FALSE);
528
529 /* Disturb */
530 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
531
532 /* Recalculate bonuses */
533 p_ptr->update |= (PU_BONUS);
534
535 /* Handle stuff */
536 handle_stuff(p_ptr);
537
538 /* Result */
539 return (TRUE);
540 }
541
542
543 /*
544 * Set "p_ptr->shield", notice observable changes
545 */
set_shield(player_type * p_ptr,int v)546 bool set_shield(player_type *p_ptr, 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->shield)
557 {
558 msg_print(p_ptr, "A mystic shield forms around your body!");
559 sound(p_ptr, MSG_SHIELD);
560 notice = TRUE;
561 }
562 }
563
564 /* Shut */
565 else
566 {
567 if (p_ptr->shield)
568 {
569 msg_print(p_ptr, "Your mystic shield crumbles away.");
570 sound(p_ptr, MSG_RECOVER);
571 notice = TRUE;
572 }
573 }
574
575 /* Use the value */
576 p_ptr->shield = v;
577
578 /* Nothing to notice */
579 if (!notice) return (FALSE);
580
581 /* Disturb */
582 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
583
584 /* Recalculate bonuses */
585 p_ptr->update |= (PU_BONUS);
586
587 /* Handle stuff */
588 handle_stuff(p_ptr);
589
590 /* Result */
591 return (TRUE);
592 }
593
594
595
596 /*
597 * Set "p_ptr->blessed", notice observable changes
598 */
set_blessed(player_type * p_ptr,int v)599 bool set_blessed(player_type *p_ptr, int v)
600 {
601 bool notice = FALSE;
602
603 /* Hack -- Force good values */
604 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
605
606 /* Open */
607 if (v)
608 {
609 if (!p_ptr->blessed)
610 {
611 msg_print(p_ptr, "You feel righteous!");
612 sound(p_ptr, MSG_BLESSED);
613 notice = TRUE;
614 }
615 }
616
617 /* Shut */
618 else
619 {
620 if (p_ptr->blessed)
621 {
622 msg_print(p_ptr, "The prayer has expired.");
623 sound(p_ptr, MSG_RECOVER);
624 notice = TRUE;
625 }
626 }
627
628 /* Use the value */
629 p_ptr->blessed = v;
630
631 /* Nothing to notice */
632 if (!notice) return (FALSE);
633
634 /* Disturb */
635 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
636
637 /* Recalculate bonuses */
638 p_ptr->update |= (PU_BONUS);
639
640 /* Handle stuff */
641 handle_stuff(p_ptr);
642
643 /* Result */
644 return (TRUE);
645 }
646
647
648 /*
649 * Set "p_ptr->hero", notice observable changes
650 */
set_hero(player_type * p_ptr,int v)651 bool set_hero(player_type *p_ptr, int v)
652 {
653 bool notice = FALSE;
654
655 /* Hack -- Force good values */
656 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
657
658 /* Open */
659 if (v)
660 {
661 if (!p_ptr->hero)
662 {
663 msg_print(p_ptr, "You feel like a hero!");
664 sound(p_ptr, MSG_HERO);
665 notice = TRUE;
666 }
667 }
668
669 /* Shut */
670 else
671 {
672 if (p_ptr->hero)
673 {
674 msg_print(p_ptr, "The heroism wears off.");
675 sound(p_ptr, MSG_RECOVER);
676 notice = TRUE;
677 }
678 }
679
680 /* Use the value */
681 p_ptr->hero = v;
682
683 /* Nothing to notice */
684 if (!notice) return (FALSE);
685
686 /* Disturb */
687 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
688
689 /* Recalculate bonuses */
690 p_ptr->update |= (PU_BONUS);
691
692 /* Recalculate hitpoints */
693 p_ptr->update |= (PU_HP);
694
695 /* Handle stuff */
696 handle_stuff(p_ptr);
697
698 /* Result */
699 return (TRUE);
700 }
701
702
703 /*
704 * Set "p_ptr->shero", notice observable changes
705 */
set_shero(player_type * p_ptr,int v)706 bool set_shero(player_type *p_ptr, int v)
707 {
708 bool notice = FALSE;
709
710 /* Hack -- Force good values */
711 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
712
713 /* Open */
714 if (v)
715 {
716 if (!p_ptr->shero)
717 {
718 msg_print(p_ptr, "You feel like a killing machine!");
719 sound(p_ptr, MSG_BERSERK);
720 notice = TRUE;
721 }
722 }
723
724 /* Shut */
725 else
726 {
727 if (p_ptr->shero)
728 {
729 msg_print(p_ptr, "You feel less Berserk.");
730 sound(p_ptr, MSG_RECOVER);
731 notice = TRUE;
732 }
733 }
734
735 /* Use the value */
736 p_ptr->shero = v;
737
738 /* Nothing to notice */
739 if (!notice) return (FALSE);
740
741 /* Disturb */
742 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
743
744 /* Recalculate bonuses */
745 p_ptr->update |= (PU_BONUS);
746
747 /* Recalculate hitpoints */
748 p_ptr->update |= (PU_HP);
749
750 /* Handle stuff */
751 handle_stuff(p_ptr);
752
753 /* Result */
754 return (TRUE);
755 }
756
757
758 /*
759 * Set "p_ptr->protevil", notice observable changes
760 */
set_protevil(player_type * p_ptr,int v)761 bool set_protevil(player_type *p_ptr, int v)
762 {
763 bool notice = FALSE;
764
765 /* Hack -- Force good values */
766 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
767
768 /* Open */
769 if (v)
770 {
771 if (!p_ptr->protevil)
772 {
773 msg_print(p_ptr, "You feel safe from evil!");
774 sound(p_ptr, MSG_PROT_EVIL);
775 notice = TRUE;
776 }
777 }
778
779 /* Shut */
780 else
781 {
782 if (p_ptr->protevil)
783 {
784 msg_print(p_ptr, "You no longer feel safe from evil.");
785 sound(p_ptr, MSG_RECOVER);
786 notice = TRUE;
787 }
788 }
789
790 /* Use the value */
791 p_ptr->protevil = v;
792
793 /* Nothing to notice */
794 if (!notice) return (FALSE);
795
796 /* Disturb */
797 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
798
799 /* Handle stuff */
800 handle_stuff(p_ptr);
801
802 /* Result */
803 return (TRUE);
804 }
805
806
807 /*
808 * Set "p_ptr->invuln", notice observable changes
809 */
set_invuln(player_type * p_ptr,int v)810 bool set_invuln(player_type *p_ptr, int v)
811 {
812 bool notice = FALSE;
813
814 /* Hack -- Force good values */
815 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
816
817 /* Open */
818 if (v)
819 {
820 if (!p_ptr->invuln)
821 {
822 msg_print(p_ptr, "You feel invulnerable!");
823 sound(p_ptr, MSG_INVULN);
824 notice = TRUE;
825 }
826 }
827
828 /* Shut */
829 else
830 {
831 if (p_ptr->invuln)
832 {
833 msg_print(p_ptr, "You feel vulnerable once more.");
834 sound(p_ptr, MSG_RECOVER);
835 notice = TRUE;
836 }
837 }
838
839 /* Use the value */
840 p_ptr->invuln = v;
841
842 /* Nothing to notice */
843 if (!notice) return (FALSE);
844
845 /* Disturb */
846 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
847
848 /* Recalculate bonuses */
849 p_ptr->update |= (PU_BONUS);
850
851 /* Handle stuff */
852 handle_stuff(p_ptr);
853
854 /* Result */
855 return (TRUE);
856 }
857
858
859 /*
860 * Set "p_ptr->tim_invis", notice observable changes
861 */
set_tim_invis(player_type * p_ptr,int v)862 bool set_tim_invis(player_type *p_ptr, int v)
863 {
864 bool notice = FALSE;
865
866 /* Hack -- Force good values */
867 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
868
869 /* Open */
870 if (v)
871 {
872 if (!p_ptr->tim_invis)
873 {
874 msg_print(p_ptr, "Your eyes feel very sensitive!");
875 sound(p_ptr, MSG_SEE_INVIS);
876 notice = TRUE;
877 }
878 }
879
880 /* Shut */
881 else
882 {
883 if (p_ptr->tim_invis)
884 {
885 msg_print(p_ptr, "Your eyes feel less sensitive.");
886 sound(p_ptr, MSG_RECOVER);
887 notice = TRUE;
888 }
889 }
890
891 /* Use the value */
892 p_ptr->tim_invis = v;
893
894 /* Nothing to notice */
895 if (!notice) return (FALSE);
896
897 /* Disturb */
898 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
899
900 /* Recalculate bonuses */
901 p_ptr->update |= (PU_BONUS);
902
903 /* Update the monsters */
904 p_ptr->update |= (PU_MONSTERS);
905
906 /* Handle stuff */
907 handle_stuff(p_ptr);
908
909 /* Result */
910 return (TRUE);
911 }
912
913
914 /*
915 * Set "p_ptr->tim_infra", notice observable changes
916 */
set_tim_infra(player_type * p_ptr,int v)917 bool set_tim_infra(player_type *p_ptr, int v)
918 {
919 bool notice = FALSE;
920
921 /* Hack -- Force good values */
922 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
923
924 /* Open */
925 if (v)
926 {
927 if (!p_ptr->tim_infra)
928 {
929 msg_print(p_ptr, "Your eyes begin to tingle!");
930 sound(p_ptr, MSG_INFRARED);
931 notice = TRUE;
932 }
933 }
934
935 /* Shut */
936 else
937 {
938 if (p_ptr->tim_infra)
939 {
940 msg_print(p_ptr, "Your eyes stop tingling.");
941 sound(p_ptr, MSG_RECOVER);
942 notice = TRUE;
943 }
944 }
945
946 /* Use the value */
947 p_ptr->tim_infra = v;
948
949 /* Nothing to notice */
950 if (!notice) return (FALSE);
951
952 /* Disturb */
953 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
954
955 /* Recalculate bonuses */
956 p_ptr->update |= (PU_BONUS);
957
958 /* Update the monsters */
959 p_ptr->update |= (PU_MONSTERS);
960
961 /* Handle stuff */
962 handle_stuff(p_ptr);
963
964 /* Result */
965 return (TRUE);
966 }
967
968
969 /*
970 * Set "p_ptr->oppose_acid", notice observable changes
971 */
set_oppose_acid(player_type * p_ptr,int v)972 bool set_oppose_acid(player_type *p_ptr, int v)
973 {
974 bool notice = FALSE;
975
976 /* Hack -- Force good values */
977 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
978
979 /* Open */
980 if (v)
981 {
982 if (!p_ptr->oppose_acid)
983 {
984 msg_print(p_ptr, "You feel resistant to acid!");
985 sound(p_ptr, MSG_RES_ACID);
986 notice = TRUE;
987 }
988 }
989
990 /* Shut */
991 else
992 {
993 if (p_ptr->oppose_acid)
994 {
995 msg_print(p_ptr, "You feel less resistant to acid.");
996 sound(p_ptr, MSG_RECOVER);
997 notice = TRUE;
998 }
999 }
1000
1001 /* Use the value */
1002 p_ptr->oppose_acid = v;
1003
1004 /* Nothing to notice */
1005 if (!notice) return (FALSE);
1006
1007 /* Disturb */
1008 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1009
1010 p_ptr->redraw |= PR_OPPOSE_ELEMENTS;
1011
1012 /* Handle stuff */
1013 handle_stuff(p_ptr);
1014
1015 /* Result */
1016 return (TRUE);
1017 }
1018
1019
1020 /*
1021 * Set "p_ptr->oppose_elec", notice observable changes
1022 */
set_oppose_elec(player_type * p_ptr,int v)1023 bool set_oppose_elec(player_type *p_ptr, int v)
1024 {
1025 bool notice = FALSE;
1026
1027 /* Hack -- Force good values */
1028 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1029
1030 /* Open */
1031 if (v)
1032 {
1033 if (!p_ptr->oppose_elec)
1034 {
1035 msg_print(p_ptr, "You feel resistant to electricity!");
1036 sound(p_ptr, MSG_RES_ELEC);
1037 notice = TRUE;
1038 }
1039 }
1040
1041 /* Shut */
1042 else
1043 {
1044 if (p_ptr->oppose_elec)
1045 {
1046 msg_print(p_ptr, "You feel less resistant to electricity.");
1047 sound(p_ptr, MSG_RECOVER);
1048 notice = TRUE;
1049 }
1050 }
1051
1052 /* Use the value */
1053 p_ptr->oppose_elec = v;
1054
1055 /* Nothing to notice */
1056 if (!notice) return (FALSE);
1057
1058 /* Disturb */
1059 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1060
1061 p_ptr->redraw |= PR_OPPOSE_ELEMENTS;
1062
1063 /* Handle stuff */
1064 handle_stuff(p_ptr);
1065
1066 /* Result */
1067 return (TRUE);
1068 }
1069
1070
1071 /*
1072 * Set "p_ptr->oppose_fire", notice observable changes
1073 */
set_oppose_fire(player_type * p_ptr,int v)1074 bool set_oppose_fire(player_type *p_ptr, int v)
1075 {
1076 bool notice = FALSE;
1077
1078 /* Hack -- Force good values */
1079 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1080
1081 /* Open */
1082 if (v)
1083 {
1084 if (!p_ptr->oppose_fire)
1085 {
1086 msg_print(p_ptr, "You feel resistant to fire!");
1087 sound(p_ptr, MSG_RES_FIRE);
1088 notice = TRUE;
1089 }
1090 }
1091
1092 /* Shut */
1093 else
1094 {
1095 if (p_ptr->oppose_fire)
1096 {
1097 msg_print(p_ptr, "You feel less resistant to fire.");
1098 sound(p_ptr, MSG_RECOVER);
1099 notice = TRUE;
1100 }
1101 }
1102
1103 /* Use the value */
1104 p_ptr->oppose_fire = v;
1105
1106 /* Nothing to notice */
1107 if (!notice) return (FALSE);
1108
1109 /* Disturb */
1110 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1111
1112 p_ptr->redraw |= PR_OPPOSE_ELEMENTS;
1113
1114 /* Handle stuff */
1115 handle_stuff(p_ptr);
1116
1117 /* Result */
1118 return (TRUE);
1119 }
1120
1121
1122 /*
1123 * Set "p_ptr->oppose_cold", notice observable changes
1124 */
set_oppose_cold(player_type * p_ptr,int v)1125 bool set_oppose_cold(player_type *p_ptr, int v)
1126 {
1127 bool notice = FALSE;
1128
1129 /* Hack -- Force good values */
1130 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1131
1132 /* Open */
1133 if (v)
1134 {
1135 if (!p_ptr->oppose_cold)
1136 {
1137 msg_print(p_ptr, "You feel resistant to cold!");
1138 sound(p_ptr, MSG_RES_COLD);
1139 notice = TRUE;
1140 }
1141 }
1142
1143 /* Shut */
1144 else
1145 {
1146 if (p_ptr->oppose_cold)
1147 {
1148 msg_print(p_ptr, "You feel less resistant to cold.");
1149 sound(p_ptr, MSG_RECOVER);
1150 notice = TRUE;
1151 }
1152 }
1153
1154 /* Use the value */
1155 p_ptr->oppose_cold = v;
1156
1157 /* Nothing to notice */
1158 if (!notice) return (FALSE);
1159
1160 /* Disturb */
1161 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1162
1163 p_ptr->redraw |= PR_OPPOSE_ELEMENTS;
1164
1165 /* Handle stuff */
1166 handle_stuff(p_ptr);
1167
1168 /* Result */
1169 return (TRUE);
1170 }
1171
1172
1173 /*
1174 * Set "p_ptr->oppose_pois", notice observable changes
1175 */
set_oppose_pois(player_type * p_ptr,int v)1176 bool set_oppose_pois(player_type *p_ptr, int v)
1177 {
1178 bool notice = FALSE;
1179
1180 /* Hack -- Force good values */
1181 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1182
1183 /* Open */
1184 if (v)
1185 {
1186 if (!p_ptr->oppose_pois)
1187 {
1188 msg_print(p_ptr, "You feel resistant to poison!");
1189 sound(p_ptr, MSG_RES_POIS);
1190 notice = TRUE;
1191 }
1192 }
1193
1194 /* Shut */
1195 else
1196 {
1197 if (p_ptr->oppose_pois)
1198 {
1199 msg_print(p_ptr, "You feel less resistant to poison.");
1200 sound(p_ptr, MSG_RECOVER);
1201 notice = TRUE;
1202 }
1203 }
1204
1205 /* Use the value */
1206 p_ptr->oppose_pois = v;
1207
1208 /* Nothing to notice */
1209 if (!notice) return (FALSE);
1210
1211 /* Disturb */
1212 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1213
1214 p_ptr->redraw |= PR_OPPOSE_ELEMENTS;
1215
1216 /* Handle stuff */
1217 handle_stuff(p_ptr);
1218
1219 /* Result */
1220 return (TRUE);
1221 }
1222
1223
1224 /*
1225 * Set "p_ptr->stun", notice observable changes
1226 *
1227 * Note the special code to only notice "range" changes.
1228 */
set_stun(player_type * p_ptr,int v)1229 bool set_stun(player_type *p_ptr, int v)
1230 {
1231 int old_aux, new_aux;
1232
1233 bool notice = FALSE;
1234
1235
1236 /* hack -- the admin wizard can not be stunned */
1237 if (p_ptr->dm_flags & DM_INVULNERABLE) return TRUE;
1238
1239 /* Hack -- Force good values */
1240 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1241
1242 /* Knocked out */
1243 if (p_ptr->stun > 100)
1244 {
1245 old_aux = 3;
1246 }
1247
1248 /* Heavy stun */
1249 else if (p_ptr->stun > 50)
1250 {
1251 old_aux = 2;
1252 }
1253
1254 /* Stun */
1255 else if (p_ptr->stun > 0)
1256 {
1257 old_aux = 1;
1258 }
1259
1260 /* None */
1261 else
1262 {
1263 old_aux = 0;
1264 }
1265
1266 /* Knocked out */
1267 if (v > 100)
1268 {
1269 new_aux = 3;
1270 }
1271
1272 /* Heavy stun */
1273 else if (v > 50)
1274 {
1275 new_aux = 2;
1276 }
1277
1278 /* Stun */
1279 else if (v > 0)
1280 {
1281 new_aux = 1;
1282 }
1283
1284 /* None */
1285 else
1286 {
1287 new_aux = 0;
1288 }
1289
1290 /* Increase cut */
1291 if (new_aux > old_aux)
1292 {
1293 /* Describe the state */
1294 switch (new_aux)
1295 {
1296 /* Stun */
1297 case 1:
1298 msg_format_near(p_ptr, "%s appears stunned.", p_ptr->name);
1299 msg_print(p_ptr, "You have been stunned.");
1300 sound(p_ptr, MSG_STUN);
1301 break;
1302
1303 /* Heavy stun */
1304 case 2:
1305 msg_format_near(p_ptr, "%s is very stunned.", p_ptr->name);
1306 msg_print(p_ptr, "You have been heavily stunned.");
1307 sound(p_ptr, MSG_STUN);
1308 break;
1309
1310 /* Knocked out */
1311 case 3:
1312 msg_format_near(p_ptr, "%s has been knocked out.", p_ptr->name);
1313 msg_print(p_ptr, "You have been knocked out.");
1314 sound(p_ptr, MSG_STUN);
1315 break;
1316 }
1317
1318 /* Notice */
1319 notice = TRUE;
1320 }
1321
1322 /* Decrease cut */
1323 else if (new_aux < old_aux)
1324 {
1325 /* Describe the state */
1326 switch (new_aux)
1327 {
1328 /* None */
1329 case 0:
1330 msg_format_near(p_ptr, "%s is no longer stunned.", p_ptr->name);
1331 msg_print(p_ptr, "You are no longer stunned.");
1332 sound(p_ptr, MSG_RECOVER);
1333 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1334 break;
1335 }
1336
1337 /* Notice */
1338 notice = TRUE;
1339 }
1340
1341 /* Use the value */
1342 p_ptr->stun = v;
1343
1344 /* No change */
1345 if (!notice) return (FALSE);
1346
1347 /* Disturb */
1348 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1349
1350 /* Recalculate bonuses */
1351 p_ptr->update |= (PU_BONUS);
1352
1353 /* Redraw the "stun" */
1354 p_ptr->redraw |= (PR_STUN);
1355
1356 /* Handle stuff */
1357 handle_stuff(p_ptr);
1358
1359 /* Result */
1360 return (TRUE);
1361 }
1362
1363
1364 /*
1365 * Set "p_ptr->cut", notice observable changes
1366 *
1367 * Note the special code to only notice "range" changes.
1368 */
set_cut(player_type * p_ptr,int v)1369 bool set_cut(player_type *p_ptr, int v)
1370 {
1371 int old_aux, new_aux;
1372
1373 bool notice = FALSE;
1374
1375 /* Hack -- Force good values */
1376 v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
1377
1378 /* Mortal wound */
1379 if (p_ptr->cut > 1000)
1380 {
1381 old_aux = 7;
1382 }
1383
1384 /* Deep gash */
1385 else if (p_ptr->cut > 200)
1386 {
1387 old_aux = 6;
1388 }
1389
1390 /* Severe cut */
1391 else if (p_ptr->cut > 100)
1392 {
1393 old_aux = 5;
1394 }
1395
1396 /* Nasty cut */
1397 else if (p_ptr->cut > 50)
1398 {
1399 old_aux = 4;
1400 }
1401
1402 /* Bad cut */
1403 else if (p_ptr->cut > 25)
1404 {
1405 old_aux = 3;
1406 }
1407
1408 /* Light cut */
1409 else if (p_ptr->cut > 10)
1410 {
1411 old_aux = 2;
1412 }
1413
1414 /* Graze */
1415 else if (p_ptr->cut > 0)
1416 {
1417 old_aux = 1;
1418 }
1419
1420 /* None */
1421 else
1422 {
1423 old_aux = 0;
1424 }
1425
1426 /* Mortal wound */
1427 if (v > 1000)
1428 {
1429 new_aux = 7;
1430 }
1431
1432 /* Deep gash */
1433 else if (v > 200)
1434 {
1435 new_aux = 6;
1436 }
1437
1438 /* Severe cut */
1439 else if (v > 100)
1440 {
1441 new_aux = 5;
1442 }
1443
1444 /* Nasty cut */
1445 else if (v > 50)
1446 {
1447 new_aux = 4;
1448 }
1449
1450 /* Bad cut */
1451 else if (v > 25)
1452 {
1453 new_aux = 3;
1454 }
1455
1456 /* Light cut */
1457 else if (v > 10)
1458 {
1459 new_aux = 2;
1460 }
1461
1462 /* Graze */
1463 else if (v > 0)
1464 {
1465 new_aux = 1;
1466 }
1467
1468 /* None */
1469 else
1470 {
1471 new_aux = 0;
1472 }
1473
1474 /* Increase cut */
1475 if (new_aux > old_aux)
1476 {
1477 /* Describe the state */
1478 switch (new_aux)
1479 {
1480 /* Graze */
1481 case 1:
1482 msg_print(p_ptr, "You have been given a graze.");
1483 sound(p_ptr, MSG_CUT);
1484 break;
1485
1486 /* Light cut */
1487 case 2:
1488 msg_print(p_ptr, "You have been given a light cut.");
1489 sound(p_ptr, MSG_CUT);
1490 break;
1491
1492 /* Bad cut */
1493 case 3:
1494 msg_print(p_ptr, "You have been given a bad cut.");
1495 sound(p_ptr, MSG_CUT);
1496 break;
1497
1498 /* Nasty cut */
1499 case 4:
1500 msg_print(p_ptr, "You have been given a nasty cut.");
1501 sound(p_ptr, MSG_CUT);
1502 break;
1503
1504 /* Severe cut */
1505 case 5:
1506 msg_print(p_ptr, "You have been given a severe cut.");
1507 sound(p_ptr, MSG_CUT);
1508 break;
1509
1510 /* Deep gash */
1511 case 6:
1512 msg_print(p_ptr, "You have been given a deep gash.");
1513 sound(p_ptr, MSG_CUT);
1514 break;
1515
1516 /* Mortal wound */
1517 case 7:
1518 msg_print(p_ptr, "You have been given a mortal wound.");
1519 sound(p_ptr, MSG_CUT);
1520 break;
1521 }
1522
1523 /* Notice */
1524 notice = TRUE;
1525 }
1526
1527 /* Decrease cut */
1528 else if (new_aux < old_aux)
1529 {
1530 /* Describe the state */
1531 switch (new_aux)
1532 {
1533 /* None */
1534 case 0:
1535 msg_print(p_ptr, "You are no longer bleeding.");
1536 sound(p_ptr, MSG_RECOVER);
1537 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1538 break;
1539 }
1540
1541 /* Notice */
1542 notice = TRUE;
1543 }
1544
1545 /* Use the value */
1546 p_ptr->cut = v;
1547
1548 /* No change */
1549 if (!notice) return (FALSE);
1550
1551 /* Disturb */
1552 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1553
1554 /* Recalculate bonuses */
1555 p_ptr->update |= (PU_BONUS);
1556
1557 /* Redraw the "cut" */
1558 p_ptr->redraw |= (PR_CUT);
1559
1560 /* Handle stuff */
1561 handle_stuff(p_ptr);
1562
1563 /* Result */
1564 return (TRUE);
1565 }
1566
1567
1568 /*
1569 * Set "p_ptr->food", notice observable changes
1570 *
1571 * The "p_ptr->food" variable can get as large as 20000, allowing the
1572 * addition of the most "filling" item, Elvish Waybread, which adds
1573 * 7500 food units, without overflowing the 32767 maximum limit.
1574 *
1575 * Perhaps we should disturb the player with various messages,
1576 * especially messages about hunger status changes. XXX XXX XXX
1577 *
1578 * Digestion of food is handled in "dungeon.c", in which, normally,
1579 * the player digests about 20 food units per 100 game turns, more
1580 * when "fast", more when "regenerating", less with "slow digestion",
1581 * but when the player is "gorged", he digests 100 food units per 10
1582 * game turns, or a full 1000 food units per 100 game turns.
1583 *
1584 * Note that the player's speed is reduced by 10 units while gorged,
1585 * so if the player eats a single food ration (5000 food units) when
1586 * full (15000 food units), he will be gorged for (5000/100)*10 = 500
1587 * game turns, or 500/(100/5) = 25 player turns (if nothing else is
1588 * affecting the player speed).
1589 */
set_food(player_type * p_ptr,int v)1590 bool set_food(player_type *p_ptr, int v)
1591 {
1592 int old_aux, new_aux;
1593
1594 bool notice = FALSE;
1595
1596 /* Hack -- Force good values */
1597 v = (v > 20000) ? 20000 : (v < 0) ? 0 : v;
1598
1599 /* Fainting / Starving */
1600 if (p_ptr->food < PY_FOOD_FAINT)
1601 {
1602 old_aux = 0;
1603 }
1604
1605 /* Weak */
1606 else if (p_ptr->food < PY_FOOD_WEAK)
1607 {
1608 old_aux = 1;
1609 }
1610
1611 /* Hungry */
1612 else if (p_ptr->food < PY_FOOD_ALERT)
1613 {
1614 old_aux = 2;
1615 }
1616
1617 /* Normal */
1618 else if (p_ptr->food < PY_FOOD_FULL)
1619 {
1620 old_aux = 3;
1621 }
1622
1623 /* Full */
1624 else if (p_ptr->food < PY_FOOD_MAX)
1625 {
1626 old_aux = 4;
1627 }
1628
1629 /* Gorged */
1630 else
1631 {
1632 old_aux = 5;
1633 }
1634
1635 /* Fainting / Starving */
1636 if (v < PY_FOOD_FAINT)
1637 {
1638 new_aux = 0;
1639 }
1640
1641 /* Weak */
1642 else if (v < PY_FOOD_WEAK)
1643 {
1644 new_aux = 1;
1645 }
1646
1647 /* Hungry */
1648 else if (v < PY_FOOD_ALERT)
1649 {
1650 new_aux = 2;
1651 }
1652
1653 /* Normal */
1654 else if (v < PY_FOOD_FULL)
1655 {
1656 new_aux = 3;
1657 }
1658
1659 /* Full */
1660 else if (v < PY_FOOD_MAX)
1661 {
1662 new_aux = 4;
1663 }
1664
1665 /* Gorged */
1666 else
1667 {
1668 new_aux = 5;
1669 }
1670
1671 /* Hack -- do not report hunger for ghosts */
1672 if (p_ptr->ghost)
1673 {
1674 old_aux = new_aux;
1675 /* but still refresh to display Full state */
1676 notice = TRUE;
1677 }
1678
1679 /* Food increase */
1680 if (new_aux > old_aux)
1681 {
1682 /* Describe the state */
1683 switch (new_aux)
1684 {
1685 /* Weak */
1686 case 1:
1687 msg_print(p_ptr, "You are still weak.");
1688 break;
1689
1690 /* Hungry */
1691 case 2:
1692 msg_print(p_ptr, "You are still hungry.");
1693 break;
1694
1695 /* Normal */
1696 case 3:
1697 msg_print(p_ptr, "You are no longer hungry.");
1698 break;
1699
1700 /* Full */
1701 case 4:
1702 msg_print(p_ptr, "You are full!");
1703 break;
1704
1705 /* Bloated */
1706 case 5:
1707 msg_print(p_ptr, "You have gorged yourself!");
1708 break;
1709 }
1710
1711 /* Change */
1712 notice = TRUE;
1713 }
1714
1715 /* Food decrease */
1716 else if (new_aux < old_aux)
1717 {
1718 /* Describe the state */
1719 switch (new_aux)
1720 {
1721 /* Fainting / Starving */
1722 case 0:
1723 msg_print(p_ptr, "You are getting faint from hunger!");
1724 sound(p_ptr, MSG_NOTICE);
1725 break;
1726
1727 /* Weak */
1728 case 1:
1729 msg_print(p_ptr, "You are getting weak from hunger!");
1730 sound(p_ptr, MSG_NOTICE);
1731 break;
1732
1733 /* Hungry */
1734 case 2:
1735 msg_print(p_ptr, "You are getting hungry.");
1736 sound(p_ptr, MSG_HUNGRY);
1737 break;
1738
1739 /* Normal */
1740 case 3:
1741 msg_print(p_ptr, "You are no longer full.");
1742 sound(p_ptr, MSG_NOTICE);
1743 break;
1744
1745 /* Full */
1746 case 4:
1747 msg_print(p_ptr, "You are no longer gorged.");
1748 sound(p_ptr, MSG_NOTICE);
1749 break;
1750 }
1751
1752 /* Change */
1753 notice = TRUE;
1754 }
1755
1756 /* Use the value */
1757 p_ptr->food = v;
1758
1759 /* Nothing to notice */
1760 if (!notice) return (FALSE);
1761
1762 /* Disturb */
1763 if (option_p(p_ptr,DISTURB_STATE)) disturb(p_ptr, 0, 0);
1764
1765 /* Recalculate bonuses */
1766 p_ptr->update |= (PU_BONUS);
1767
1768 /* Redraw hunger */
1769 p_ptr->redraw |= (PR_HUNGER);
1770
1771 /* Handle stuff */
1772 handle_stuff(p_ptr);
1773
1774 /* Result */
1775 return (TRUE);
1776 }
1777
1778
1779
1780
1781
1782 /*
1783 * Advance experience levels and print experience
1784 */
check_experience(player_type * p_ptr)1785 void check_experience(player_type *p_ptr)
1786 {
1787 int i;
1788 int old_level;
1789 char buf[80];
1790
1791
1792 /* Note current level */
1793 i = p_ptr->lev;
1794
1795
1796 /* Hack -- lower limit */
1797 if (p_ptr->exp < 0) p_ptr->exp = 0;
1798
1799 /* Hack -- lower limit */
1800 if (p_ptr->max_exp < 0) p_ptr->max_exp = 0;
1801
1802 /* Hack -- upper limit */
1803 if (p_ptr->exp > PY_MAX_EXP) p_ptr->exp = PY_MAX_EXP;
1804
1805 /* Hack -- upper limit */
1806 if (p_ptr->max_exp > PY_MAX_EXP) p_ptr->max_exp = PY_MAX_EXP;
1807
1808
1809 /* Hack -- maintain "max" experience */
1810 if (p_ptr->exp > p_ptr->max_exp) p_ptr->max_exp = p_ptr->exp;
1811
1812 /* Redraw experience */
1813 p_ptr->redraw |= (PR_EXP | PR_LEV);
1814
1815 /* Lose levels while possible */
1816 while ((p_ptr->lev > 1) &&
1817 (p_ptr->exp < (player_exp[p_ptr->lev-2] *
1818 p_ptr->expfact / 100L)))
1819 {
1820 old_level = p_ptr->lev;
1821
1822 /* Lose a level */
1823 p_ptr->lev--;
1824
1825 /* Message */
1826 msg_format(p_ptr, "Dropped back to level %d.", p_ptr->lev);
1827 sprintf(buf, "%s has dropped to level %d.", p_ptr->name, p_ptr->lev);
1828 msg_broadcast(p_ptr, buf);
1829
1830 /* Update some stuff */
1831 p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS);
1832
1833 /* Redraw some stuff */
1834 p_ptr->redraw |= (PR_LEV | PR_TITLE);
1835
1836 /* Hack -- redraw charsheet when falling below level 30 */
1837 if (old_level >= 30 && p_ptr->lev < 30)
1838 p_ptr->redraw |= (PR_OFLAGS);
1839
1840 /* Window stuff */
1841 p_ptr->window |= (PW_PLAYER | PW_SPELL);
1842 }
1843
1844
1845 /* Gain levels while possible */
1846 while ((p_ptr->lev < PY_MAX_LEVEL) &&
1847 (p_ptr->exp >= (player_exp[p_ptr->lev-1] *
1848 p_ptr->expfact / 100L)))
1849 {
1850 old_level = p_ptr->lev;
1851
1852 /* Gain a level */
1853 p_ptr->lev++;
1854
1855 /* Save the highest level */
1856 if (p_ptr->lev > p_ptr->max_plv) p_ptr->max_plv = p_ptr->lev;
1857
1858 /* Sound */
1859 sound(p_ptr, MSG_LEVEL);
1860
1861 /* Message */
1862 msg_format(p_ptr, "Welcome to level %d.", p_ptr->lev);
1863 sprintf(buf, "%s has attained level %d.", p_ptr->name, p_ptr->lev);
1864 msg_broadcast(p_ptr, buf);
1865
1866 /* Record this event in the character history */
1867 if(!(p_ptr->lev % 5))
1868 {
1869 sprintf(buf,"Reached level %d",p_ptr->lev);
1870 log_history_event(p_ptr, buf, TRUE);
1871 }
1872
1873 /* Update some stuff */
1874 p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SPELLS);
1875
1876 /* Redraw some stuff */
1877 p_ptr->redraw |= (PR_LEV | PR_TITLE);
1878
1879 /* Hack -- redraw charsheet on level 30 */
1880 if (old_level < 30 && p_ptr->lev >= 30)
1881 p_ptr->redraw |= (PR_OFLAGS);
1882
1883 /* Window stuff */
1884 p_ptr->window |= (PW_PLAYER | PW_SPELL);
1885 }
1886
1887 /* Update stuff */
1888 update_stuff(p_ptr);
1889 }
1890
1891
1892 /*
1893 * Gain experience
1894 */
gain_exp(player_type * p_ptr,s32b amount)1895 void gain_exp(player_type *p_ptr, s32b amount)
1896 {
1897 /* Gain some experience */
1898 p_ptr->exp += amount;
1899
1900 /* Slowly recover from experience drainage */
1901 if (p_ptr->exp < p_ptr->max_exp)
1902 {
1903 /* Gain max experience (10%) */
1904 p_ptr->max_exp += amount / 10;
1905 }
1906
1907 /* Check Experience */
1908 check_experience(p_ptr);
1909 }
1910
1911
1912 /*
1913 * Lose experience
1914 */
lose_exp(player_type * p_ptr,s32b amount)1915 void lose_exp(player_type *p_ptr, s32b amount)
1916 {
1917 /* Never drop below zero experience */
1918 if (amount > p_ptr->exp) amount = p_ptr->exp;
1919
1920 /* Lose some experience */
1921 p_ptr->exp -= amount;
1922
1923 /* Check Experience */
1924 check_experience(p_ptr);
1925 }
1926
1927
1928
1929
1930 /*
1931 * Hack -- Return the "automatic coin type" of a monster race
1932 * Used to allocate proper treasure when "Creeping coins" die
1933 *
1934 * XXX XXX XXX Note the use of actual "monster names"
1935 */
get_coin_type(monster_race * r_ptr)1936 static int get_coin_type(monster_race *r_ptr)
1937 {
1938 cptr name = (r_name + r_ptr->name);
1939
1940 /* Analyze "coin" monsters */
1941 if (r_ptr->d_char == '$')
1942 {
1943 /* Look for textual clues */
1944 if (strstr(name, " copper ")) return (2);
1945 if (strstr(name, " silver ")) return (5);
1946 if (strstr(name, " gold ")) return (10);
1947 if (strstr(name, " mithril ")) return (16);
1948 if (strstr(name, " adamantite ")) return (17);
1949
1950 /* Look for textual clues */
1951 if (strstr(name, "Copper ")) return (2);
1952 if (strstr(name, "Silver ")) return (5);
1953 if (strstr(name, "Gold ")) return (10);
1954 if (strstr(name, "Mithril ")) return (16);
1955 if (strstr(name, "Adamantite ")) return (17);
1956 }
1957
1958 /* Assume nothing */
1959 return (0);
1960 }
1961
1962
1963 /*
1964 * Handle the "death" of a monster.
1965 *
1966 * Disperse treasures centered at the monster location based on the
1967 * various flags contained in the monster flags fields.
1968 *
1969 * Check for "Quest" completion when a quest monster is killed.
1970 *
1971 * Note that only the player can induce "monster_death()" on Uniques.
1972 * Thus (for now) all Quest monsters should be Uniques.
1973 *
1974 * Note that in a few, very rare, circumstances, killing Morgoth
1975 * may result in the Iron Crown of Morgoth crushing the Lead-Filled
1976 * Mace "Grond", since the Iron Crown is more important.
1977 */
1978
1979
monster_death(player_type * p_ptr,int m_idx)1980 void monster_death(player_type *p_ptr, int m_idx)
1981 {
1982 player_type *q_ptr = p_ptr;
1983
1984 int i, j, y, x, ny, nx, Depth;
1985
1986 int dump_item = 0;
1987 int dump_gold = 0;
1988
1989 int number = 0;
1990 int total = 0;
1991
1992 s16b this_o_idx, next_o_idx = 0;
1993 object_type *i_ptr;
1994 object_type object_type_body;
1995
1996 char buf[160];
1997 char logbuf[160];
1998
1999 cave_type *c_ptr;
2000
2001 monster_type *m_ptr = &m_list[m_idx];
2002
2003 monster_race *r_ptr = &r_info[m_ptr->r_idx];
2004
2005
2006 bool good = (r_ptr->flags1 & RF1_DROP_GOOD) ? TRUE : FALSE;
2007 bool great = (r_ptr->flags1 & RF1_DROP_GREAT) ? TRUE : FALSE;
2008
2009 bool do_gold = (!(r_ptr->flags1 & RF1_ONLY_ITEM));
2010 bool do_item = (!(r_ptr->flags1 & RF1_ONLY_GOLD));
2011
2012 bool unique = (r_ptr->flags1 & RF1_UNIQUE) ? TRUE : FALSE;
2013 bool questor = (r_ptr->flags1 & RF1_QUESTOR) ? TRUE : FALSE;
2014 bool winner = (r_ptr->flags1 & RF1_DROP_CHOSEN) ? TRUE : FALSE;
2015 bool share = cfg_party_share_kill;
2016
2017 int force_coin = get_coin_type(r_ptr);
2018
2019 u16b quark = 0;
2020
2021
2022 /* Get the location */
2023 y = m_ptr->fy;
2024 x = m_ptr->fx;
2025 Depth = m_ptr->dun_depth;
2026
2027 /* Determine how much we can drop */
2028 if ((r_ptr->flags1 & RF1_DROP_60) && (randint0(100) < 60)) number++;
2029 if ((r_ptr->flags1 & RF1_DROP_90) && (randint0(100) < 90)) number++;
2030 if (r_ptr->flags1 & RF1_DROP_1D2) number += damroll(1, 2);
2031 if (r_ptr->flags1 & RF1_DROP_2D2) number += damroll(2, 2);
2032 if (r_ptr->flags1 & RF1_DROP_3D2) number += damroll(3, 2);
2033 if (r_ptr->flags1 & RF1_DROP_4D2) number += damroll(4, 2);
2034
2035 /* Hack -- inscribe items that a unique drops */
2036 if (unique)
2037 {
2038 quark = quark_add(r_name + r_ptr->name);
2039 }
2040
2041 /* Drop some objects */
2042 for (j = 0; j < number; j++)
2043 {
2044 /* Try 20 times per item, increasing range */
2045 for (i = 0; i < 20; ++i)
2046 {
2047 int d = (i + 14) / 15;
2048
2049 /* Pick a "correct" location */
2050 scatter(Depth, &ny, &nx, y, x, d, 0);
2051
2052 /* Must be "clean" floor grid */
2053 if (!cave_clean_bold(Depth, ny, nx)) continue;
2054
2055 /* Access the grid */
2056 c_ptr = &cave[Depth][ny][nx];
2057
2058 /* Hack -- handle creeping coins */
2059 coin_type = force_coin;
2060
2061 /* Average dungeon and monster levels */
2062 object_level = (Depth + r_ptr->level) / 2;
2063
2064 /* Place Gold */
2065 if (do_gold && (!do_item || (randint0(100) < 50)))
2066 {
2067 place_gold(Depth, ny, nx);
2068 /*if (player_can_see_bold(p_ptr, ny, nx))*/ dump_gold++;
2069 }
2070
2071 /* Place Object */
2072 else
2073 {
2074 object_type *j_ptr = place_object(Depth, ny, nx, good, great, 0);
2075 /* Set special origin */
2076 if (j_ptr)
2077 {
2078 j_ptr->origin = ORIGIN_DROP;
2079 j_ptr->origin_xtra = m_ptr->r_idx;
2080 j_ptr->note = quark;
2081 }
2082 /*if (player_can_see_bold(p_ptr, ny, nx))*/ dump_item++;
2083 }
2084
2085 /* Reset the object level */
2086 object_level = Depth;
2087
2088 /* Reset "coin" type */
2089 coin_type = 0;
2090
2091 break;
2092 }
2093 }
2094
2095 /* Drop objects being carried */
2096 for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
2097 {
2098 object_type *o_ptr;
2099
2100 /* Get the object */
2101 o_ptr = &o_list[this_o_idx];
2102
2103 /* Get the next object */
2104 next_o_idx = o_ptr->next_o_idx;
2105
2106 /* Get local object */
2107 i_ptr = &object_type_body;
2108
2109 /* Copy the object */
2110 object_copy(i_ptr, o_ptr);
2111
2112 /* Delete the object */
2113 delete_object_idx(this_o_idx);
2114
2115 /* Paranoia */
2116 i_ptr->held_m_idx = 0;
2117 i_ptr->next_o_idx = 0;
2118
2119 /* Drop it */
2120 drop_near(i_ptr, -1, Depth, y, x);
2121 }
2122
2123 /* Forget objects */
2124 m_ptr->hold_o_idx = 0;
2125
2126 /* Determine players involved in killing */
2127 total = party_mark_members(p_ptr, m_idx);
2128
2129 /* Unshare winners and questors */
2130 if (winner && !cfg_party_share_win) share = FALSE;
2131 if (questor && !cfg_party_share_quest) share = FALSE;
2132
2133 /* Take note of the killer (message) */
2134 if (unique)
2135 {
2136 /* default message */
2137 sprintf(buf,"%s was slain by %s.",(r_name + r_ptr->name), p_ptr->name);
2138 msg_print(p_ptr, buf);
2139 sprintf(logbuf,"Killed %s",(r_name + r_ptr->name));
2140
2141 /* party version */
2142 if (total > 1)
2143 {
2144 sprintf(buf, "%s was slain by %s.",(r_name + r_ptr->name),parties[p_ptr->party].name);
2145 sprintf(logbuf,"Helped to kill %s",(r_name + r_ptr->name));
2146 }
2147
2148 /* Tell every player */
2149 msg_broadcast(p_ptr, buf);
2150
2151 /* Record this kill in the event history */
2152 log_history_event(p_ptr, logbuf, TRUE);
2153 }
2154
2155 /* Perform various tasks for several players */
2156 total = 0; /* reset counter for quests */
2157 for (i = 1; i <= NumPlayers; i++)
2158 {
2159 q_ptr = Players[i];
2160 if (q_ptr->in_hack)
2161 {
2162 bool visible = (q_ptr->mon_vis[m_idx] || unique);
2163
2164 /* Take note of the killer (message) */
2165 if (unique && !same_player(q_ptr, p_ptr))
2166 {
2167 /*log_history_event(q_ptr, logbuf);*/
2168 }
2169 /* Take note of any dropped treasure */
2170 if (visible && (dump_item || dump_gold))
2171 {
2172 /* Take notes on treasure */
2173 lore_treasure(q_ptr, m_idx, dump_item, dump_gold);
2174 }
2175 /* Death count */
2176 if ((share || same_player(q_ptr, p_ptr)))
2177 {
2178 /* In lore array */
2179 if (visible)
2180 {
2181 /* Grab pointer */
2182 monster_lore *l_ptr = q_ptr->l_list + m_ptr->r_idx;
2183
2184 /* Count kills this life */
2185 if (l_ptr->pkills < MAX_SHORT) l_ptr->pkills++;
2186
2187 /* Count kills in all lives */
2188 if (l_ptr->tkills < MAX_SHORT) l_ptr->tkills++;
2189 }
2190 /* Remember */
2191 if (q_ptr->r_killed[m_ptr->r_idx] < 1000)
2192 q_ptr->r_killed[m_ptr->r_idx]++;
2193 }
2194 /* Mega-Hack -- drop "winner" treasures AND set winners */
2195 if (winner && (share || same_player(q_ptr, p_ptr)))
2196 {
2197 /* Hack -- an "object holder" */
2198 object_type prize;
2199
2200 /* Mega-Hack -- Prepare to make "Grond" */
2201 invcopy(&prize, lookup_kind(TV_HAFTED, SV_GROND));
2202
2203 /* Mega-Hack -- Mark this item as "Grond" */
2204 prize.name1 = ART_GROND;
2205 prize.note = quark;
2206
2207 /* Mega-Hack -- Actually create "Grond" */
2208 apply_magic(Depth, &prize, -1, TRUE, TRUE, TRUE);
2209
2210 /* Drop it in the dungeon */
2211 drop_near(&prize, -1, Depth, y, x);
2212
2213
2214 /* Mega-Hack -- Prepare to make "Morgoth" */
2215 invcopy(&prize, lookup_kind(TV_CROWN, SV_MORGOTH));
2216
2217 /* Mega-Hack -- Mark this item as "Morgoth" */
2218 prize.name1 = ART_MORGOTH;
2219 prize.note = quark;
2220
2221 /* Mega-Hack -- Actually create "Morgoth" */
2222 apply_magic(Depth, &prize, -1, TRUE, TRUE, TRUE);
2223
2224 /* Drop it in the dungeon */
2225 drop_near(&prize, -1, Depth, y, x);
2226
2227 /* Total winner */
2228 q_ptr->total_winner = TRUE;
2229
2230 /* Redraw the "title" */
2231 q_ptr->redraw |= (PR_TITLE);
2232
2233 /* Congratulations */
2234 msg_print(q_ptr, "*** CONGRATULATIONS ***");
2235 msg_print(q_ptr, "You have won the game!");
2236 msg_print(q_ptr, "You may retire (commit suicide) when you are ready.");
2237
2238 /* "Winner dump" */
2239 (void)strcpy(q_ptr->died_from_list, "winner");
2240 player_dump(q_ptr);
2241
2242 /* Set his retire_timer if neccecary */
2243 if (cfg_retire_timer >= 0)
2244 {
2245 q_ptr->retire_timer = cfg_retire_timer;
2246 }
2247 /* Hack -- instantly retire any new winners if neccecary */
2248 if (cfg_retire_timer == 0)
2249 {
2250 do_cmd_suicide(q_ptr);
2251 }
2252 }
2253 /* Process "Quest Monsters" */
2254 if (questor && (share || same_player(q_ptr, p_ptr)))
2255 {
2256 /* Hack -- Mark quests as complete */
2257 for (j = 0; j < MAX_Q_IDX; j++)
2258 {
2259 /* Hack -- note completed quests */
2260 if (q_ptr->q_list[j].level == r_ptr->level) q_ptr->q_list[j].level = 0;
2261
2262 /* Count incomplete quests */
2263 if (q_ptr->q_list[j].level) total++;
2264 }
2265 }
2266 }
2267 }
2268
2269 /* Only need stairs after "Quest Monsters" */
2270 if (!questor) return;
2271
2272 /* Need some stairs */
2273 {
2274 /* Stagger around */
2275 while (!cave_valid_bold(Depth, y, x))
2276 {
2277 int d = 1;
2278
2279 /* Pick a location */
2280 scatter(Depth, &ny, &nx, y, x, d, 0);
2281
2282 /* Stagger */
2283 y = ny; x = nx;
2284 }
2285
2286 /* Delete any old object XXX XXX XXX */
2287 delete_object(Depth, y, x);
2288
2289 /* Explain the stairway */
2290 msg_print(p_ptr, "A magical stairway appears...");
2291
2292 /* Access the grid */
2293 c_ptr = &cave[Depth][y][x];
2294
2295 /* Create stairs down */
2296 c_ptr->feat = FEAT_MORE;
2297
2298 /* (Re)Set starting location for people coming up */
2299 level_up_y[Depth] = y;
2300 level_up_x[Depth] = x;
2301
2302 /* Note the spot */
2303 note_spot_depth(Depth, y, x);
2304
2305 /* Draw the spot */
2306 everyone_lite_spot(Depth, y, x);
2307
2308 /* Remember to update everything */
2309 p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTERS);
2310 }
2311 }
2312
2313
2314 /* Find player on arena "a", who is not player "p_ptr" */
pick_arena_opponent(player_type * p_ptr,int a)2315 int pick_arena_opponent(player_type *p_ptr, int a)
2316 {
2317 #if 1
2318 int i, found = -1, count = 0;
2319 /* Count other players in this arena */
2320 for (i = 1; i <= NumPlayers; i++)
2321 {
2322 if (Players[i]->arena_num == a)
2323 {
2324 /* Found some one */
2325 if (!same_player(p_ptr, Players[i]))
2326 {
2327 count++;
2328 found = i;
2329 }
2330 }
2331 }
2332 if (count > 1) found = -2;
2333 #else
2334 int y,x,Depth = arenas[a].depth;
2335 /* Paranoia */
2336 if (!cave[Depth]) return -1;
2337
2338 for (y = arenas[a].y_1; y < arenas[a].y_2; y++)
2339 {
2340 for (x = arenas[a].x_1; x < arenas[a].x_2; x++)
2341 {
2342 if (cave[Depth][y][x].m_idx < 0)
2343 {
2344 /* Found some one */
2345 if (Ind != (0-cave[Depth][y][x].m_idx))
2346 return (0-cave[Depth][y][x].m_idx);
2347 }
2348 }
2349 }
2350 #endif
2351 /* No one found */
2352 return found;
2353 }
2354 /* Find arena by those coordinates */
pick_arena(int Depth,int y,int x)2355 int pick_arena(int Depth, int y, int x)
2356 {
2357 int i;
2358 for (i = 0; i < num_arenas; i++)
2359 {
2360 if (arenas[i].depth != Depth) continue;
2361 if (x < arenas[i].x_1 || x > arenas[i].x_2) continue;
2362 if (y < arenas[i].y_1 || y > arenas[i].y_2) continue;
2363
2364 /* Found */
2365 return i;
2366 }
2367
2368 /* Failure */
2369 return -1;
2370 }
2371 /*
2372 * Access Arena (Player touches it's wall in "py","px")
2373 */
access_arena(player_type * p_ptr,int py,int px)2374 void access_arena(player_type *p_ptr, int py, int px) {
2375 int a, tmp_id = -1, tmp_count = 0;
2376
2377 /* Allready inside one */
2378 if (p_ptr->arena_num != -1)
2379 {
2380 a = p_ptr->arena_num;
2381 tmp_count++;
2382 }
2383 else
2384 {
2385 a = pick_arena(p_ptr->dun_depth, py, px);
2386 }
2387
2388 /* Count other players in this arena */
2389 if ((tmp_id = pick_arena_opponent(p_ptr, a)) != -1)
2390 {
2391 tmp_count++;
2392 }
2393 if (tmp_id == -2) tmp_count++;
2394
2395 /* Player tries to leave the arena */
2396 if (p_ptr->arena_num == a)
2397 {
2398 /* If he is alone, leave */
2399 if (tmp_count < 2)
2400 {
2401 msg_print(p_ptr, "You leave the arena.");
2402 p_ptr->arena_num = -1;
2403 teleport_player(p_ptr, 1);
2404 }
2405 else
2406 msg_print(p_ptr, "There is a wall blocking your way.");
2407 }
2408 /* Player tries to enter the arena */
2409 else
2410 {
2411 /* If arena is not 'full' -- Enter it */
2412 if (tmp_count < 2)
2413 {
2414 msg_print(p_ptr, "You enter an ancient fighting pit.");
2415 teleport_player_to(p_ptr, arenas[a].y_1+1+randint1(arenas[a].y_2-arenas[a].y_1-2) , arenas[a].x_1+1+randint1(arenas[a].x_2-arenas[a].x_1-2) );
2416 p_ptr->arena_num = a;
2417 }
2418 else
2419 msg_print(p_ptr, "Arena is currently occupied.");
2420
2421 /* Both players are ready! */
2422 if (tmp_count == 1)
2423 {
2424 /* Declare hostility */
2425 add_hostility(p_ptr, Players[tmp_id]->name);
2426 add_hostility(Players[tmp_id], p_ptr->name);
2427 }
2428 }
2429
2430
2431 }
2432 /* Cleanup after PvP Fight in the arena */
evacuate_arena(player_type * p_ptr)2433 void evacuate_arena(player_type *p_ptr) {
2434 char buf[100];
2435 int a, tmp_id = 0;
2436 buf[0] = '\0';
2437 a = p_ptr->arena_num;
2438 tmp_id = pick_arena_opponent(p_ptr, a);
2439
2440 /* Loser */
2441 if (tmp_id != -1 && !same_player(Players[tmp_id], p_ptr))
2442 {
2443 /* Get winner */
2444 player_type *q_ptr = Players[tmp_id];
2445
2446 /* Friendship */
2447 remove_hostility(q_ptr, p_ptr->name);
2448 remove_hostility(p_ptr, q_ptr->name);
2449
2450 /* Messages */
2451 sprintf(buf, "You knock %s out.", p_ptr->name);
2452 msg_print(q_ptr, buf);
2453 sprintf(buf, "%s was defeated by %s.", p_ptr->name, q_ptr->name);
2454 msg_broadcast(NULL, buf); //Notice broadcast
2455 msg_print(p_ptr, "You recover oneself outside the arena.");
2456 msg_print(q_ptr, "You gloriously leave the arena.");
2457
2458 /* Heal */
2459 q_ptr->chp = Players[tmp_id]->mhp - 1;
2460 q_ptr->chp_frac = 0;
2461 q_ptr->redraw |= PR_HP;
2462
2463 /* Teleport */
2464 q_ptr->arena_num = -1;
2465 teleport_player(q_ptr, 20);
2466 }
2467
2468 /* Winner */
2469 {
2470 /* Heal */
2471 p_ptr->chp = p_ptr->mhp - 1;
2472 p_ptr->chp_frac = 0;
2473 p_ptr->redraw |= PR_HP;
2474
2475 /* Teleport */
2476 p_ptr->arena_num = -1;
2477 teleport_player(p_ptr, 20);
2478 }
2479 }
2480
2481
2482 /*
2483 * Handle the death of a player and drop their stuff.
2484 */
2485
2486 /* Bring back to life the uniques player slew */
ressurect_uniques(player_type * p_ptr)2487 void ressurect_uniques(player_type *p_ptr)
2488 {
2489 u32b uniques;
2490 int i;
2491
2492 /* Bring back to life the uniques he slew */
2493 for (i = 1; i < z_info->r_max; i++)
2494 {
2495 monster_race *r_ptr = &r_info[i];
2496
2497 /* Check for unique-ness */
2498 if (!(r_ptr->flags1 & RF1_UNIQUE))
2499 continue;
2500
2501 /* Never respawn Morgoth */
2502 if (r_ptr->flags1 & RF1_DROP_CHOSEN)
2503 continue;
2504
2505 /* If we have killed this unique, bring it back */
2506 if (p_ptr->r_killed[i])
2507 {
2508 /* Bring back if unique_depth > our_max_depth - 35% */
2509 uniques = p_ptr->max_dlv-((p_ptr->max_dlv*11468)>>15);
2510 if (r_ptr->level > uniques )
2511 {
2512 cheat(format("r_ptr->level = %d, uniques = %d\n",r_ptr->level,(int)uniques));
2513 p_ptr->r_killed[i] = 0;
2514
2515 /* Tell the player */
2516 msg_format(p_ptr, "%s rises from the dead!",(r_name + r_ptr->name));
2517 }
2518 }
2519 }
2520 }
2521
2522 /* Drop all inventory */
player_strip(player_type * p_ptr,bool gold,bool objects,bool artifacts,bool protect)2523 void player_strip(player_type *p_ptr, bool gold, bool objects, bool artifacts, bool protect)
2524 {
2525 char o_inscribe[80];
2526 s16b item_weight = 0;
2527 int i;
2528
2529 /* Drop gold if player has any */
2530 if (gold && p_ptr->au)
2531 {
2532 /* Put the player's gold in the overflow slot */
2533 invcopy(&p_ptr->inventory[INVEN_PACK], lookup_kind(TV_GOLD,SV_PLAYER_GOLD));
2534
2535 /* Drop no more than 32000 gold */
2536 if (p_ptr->au > 32000) p_ptr->au = 32000;
2537
2538 /* Set the amount */
2539 p_ptr->inventory[INVEN_PACK].pval = p_ptr->au;
2540 }
2541
2542 /* No more gold */
2543 p_ptr->au = 0;
2544
2545
2546 /* Setup the sorter */
2547 ang_sort_comp = ang_sort_comp_value;
2548 ang_sort_swap = ang_sort_swap_value;
2549
2550 /* Sort the player's inventory according to value */
2551 ang_sort(p_ptr, p_ptr->inventory, NULL, INVEN_TOTAL);
2552
2553 /* Starting with the most valuable, drop things one by one */
2554 for (i = 0; i < INVEN_TOTAL; i++)
2555 {
2556 /* Make sure we have an object */
2557 if (p_ptr->inventory[i].k_idx == 0) continue;
2558
2559 /* Handle artifacts */
2560 if (true_artifact_p(&p_ptr->inventory[i]))
2561 {
2562 /* Can't drop em */
2563 if (!artifacts)
2564 {
2565 /* Mark as unfound */
2566 a_info[p_ptr->inventory[i].name1].cur_num = 0;
2567 a_info[p_ptr->inventory[i].name1].owner_name = 0;
2568 a_info[p_ptr->inventory[i].name1].owner_id = 0;
2569 continue;
2570 }
2571 }
2572 /* Hack -- do not drop objects */
2573 else if (!objects) continue;
2574
2575 /* Hack - reinscribe with name */
2576 if (protect)
2577 {
2578 my_strcpy(o_inscribe, "!* - ", 80);
2579 my_strcat(o_inscribe, p_ptr->name, 80);
2580 p_ptr->inventory[i].note = quark_add(o_inscribe);
2581 } else p_ptr->inventory[i].note = quark_add(p_ptr->name);
2582
2583 /* Drop this one */
2584 item_weight = p_ptr->inventory[i].weight * p_ptr->inventory[i].number;
2585 drop_near(&p_ptr->inventory[i], 0, p_ptr->dun_depth, p_ptr->py, p_ptr->px);
2586
2587 /* Be careful if the item was destroyed when we dropped it */
2588 if (!p_ptr->inventory[i].k_idx)
2589 {
2590 p_ptr->total_weight -= item_weight;
2591 /* If it was an artifact, mark it as unfound */
2592 if (true_artifact_p(&p_ptr->inventory[i]))
2593 {
2594 a_info[p_ptr->inventory[i].name1].cur_num = 0;
2595 a_info[p_ptr->inventory[i].name1].owner_name = 0;
2596 a_info[p_ptr->inventory[i].name1].owner_id = 0;
2597 }
2598 }
2599 else
2600 {
2601 /* We dropped the item on the floor */
2602 inven_item_increase(p_ptr, i, -p_ptr->inventory[i].number);
2603 }
2604 /* forget about it */
2605 WIPE(&p_ptr->inventory[i], object_type);
2606 }
2607
2608 /* He is carrying nothing */
2609 p_ptr->equip_cnt = 0;
2610 p_ptr->inven_cnt = 0;
2611 }
2612
2613 /* Destroy the character completely */
player_funeral(player_type * p_ptr,char * reason)2614 void player_funeral(player_type *p_ptr, char *reason)
2615 {
2616 int i;
2617
2618 /* Disown any houses he owns */
2619 for(i=0; i< num_houses; i++)
2620 {
2621 if (house_owned_by(p_ptr, i))
2622 {
2623 disown_house(i);
2624 }
2625 }
2626
2627 /* Remove him from his party -APD- */
2628 if (p_ptr->party)
2629 {
2630 /* He leaves */
2631 party_leave(p_ptr);
2632 }
2633
2634 /* Kill him */
2635 p_ptr->death = TRUE;
2636
2637 /* One less player here */
2638 players_on_depth[p_ptr->dun_depth]--;
2639
2640 /* Remove him from the player name database */
2641 delete_player_name(p_ptr->name);
2642
2643 /* Put him on the high score list */
2644 add_high_score(p_ptr);
2645
2646 /* Get rid of him */
2647 player_disconnect(p_ptr, reason); /* Disconnect client */
2648 player_leave(p_ptr->Ind); /* Remove from playerlist */
2649
2650 /* Done */
2651 return;
2652 }
2653
2654
2655 /* Handle player death, cheating it when nessecary */
2656 /* HACKED to handle fruit bat -APD- */
player_death(player_type * p_ptr)2657 void player_death(player_type *p_ptr)
2658 {
2659 bool drop_items;
2660 char buf[1024];
2661 bool hide = dm_flag_p(p_ptr, SECRET_PRESENCE);
2662 buf[0] = '\0';
2663
2664 /* HACK -- Do not proccess while changing levels */
2665 if (p_ptr->new_level_flag == TRUE) return;
2666
2667 /* Sound */
2668 sound(p_ptr, MSG_DEATH);
2669
2670 /** Cheat death **/
2671
2672 /* Hack -- Don't die in Arena! */
2673 if (p_ptr->arena_num != -1)
2674 {
2675 p_ptr->death = FALSE;
2676 msg_print(p_ptr, "You lose consciousness.");
2677 evacuate_arena(p_ptr);
2678 return;
2679 }
2680
2681 /* Hack -- DM can't die */
2682 if (dm_flag_p(p_ptr, INVULNERABLE))
2683 {
2684 p_ptr->death = FALSE;
2685 p_ptr->chp = p_ptr->chp_frac = 0;
2686 return;
2687 }
2688
2689 /** DIE **/
2690
2691 /* Note death */
2692 if (!p_ptr->ghost)
2693 {
2694 log_history_event(p_ptr, format("Was killed by %s", p_ptr->died_from), FALSE);
2695 msg_print(p_ptr, "You die.");
2696 msg_print(p_ptr, NULL);
2697 }
2698 else
2699 {
2700 /* log_history_event(p_ptr, format("Destroyed by %s", p_ptr->died_from), TRUE); */
2701 msg_print(p_ptr, "Your incorporeal body fades away - FOREVER.");
2702 msg_print(p_ptr, NULL);
2703 }
2704
2705 /* Bring back all the uniques he slew */
2706 ressurect_uniques(p_ptr);
2707
2708 /* Handle suicide */
2709 if (!p_ptr->alive)
2710 {
2711 if (!p_ptr->total_winner)
2712 sprintf(buf, "%s committed suicide.", p_ptr->name);
2713 else
2714 sprintf(buf, "The unbeatable %s has retired to a warm, sunny climate.", p_ptr->name);
2715
2716 /* Don't announce level 1 suicides */
2717 if (p_ptr->lev < 2) hide = TRUE;
2718
2719 /* Tell players */
2720 if (!hide) msg_broadcast(p_ptr, buf);
2721
2722 /* Release artifacts */
2723 player_strip(p_ptr, FALSE, FALSE, FALSE, FALSE);
2724
2725 /* Get rid of him */
2726 player_funeral(p_ptr, "Commited suicide");
2727
2728 /* Done */
2729 return;
2730 }
2731
2732 /* Destroy ghosts */
2733 if (p_ptr->ghost)
2734 {
2735 /* Tell players */
2736 if (!hide) msg_broadcast(p_ptr, format("%s's ghost was destroyed by %s.", p_ptr->name, p_ptr->died_from));
2737
2738 /* Get rid of him */
2739 player_funeral(p_ptr, format("Killed by %s", p_ptr->died_from));
2740
2741 /* Done */
2742 return;
2743 }
2744
2745 /* Normal death */
2746 if (p_ptr->fruit_bat == -1)
2747 sprintf(buf, "%s was turned into a fruit bat by %s!", p_ptr->name, p_ptr->died_from);
2748 else if (!cfg_ironman && option_p(p_ptr, NO_GHOST)) /* Notice bravery */
2749 sprintf(buf, "The brave hero %s the level %i %s %s was killed by %s.",
2750 p_ptr->name, p_ptr->lev,
2751 p_name + p_info[p_ptr->prace].name,
2752 c_name + c_info[p_ptr->pclass].name, p_ptr->died_from);
2753 /* sprintf(buf, "The brave hero %s was killed by %s.", p_ptr->name, p_ptr->died_from); */
2754 else
2755 sprintf(buf, "%s the level %i %s %s was killed by %s.",
2756 p_ptr->name, p_ptr->lev,
2757 p_name + p_info[p_ptr->prace].name,
2758 c_name + c_info[p_ptr->pclass].name, p_ptr->died_from);
2759 /* sprintf(buf, "%s was killed by %s.", p_ptr->name, p_ptr->died_from); */
2760
2761 /* Tell the players */
2762 if (!hide) msg_broadcast(p_ptr, buf);
2763
2764 /* Character dump here, before we start dropping items */
2765 player_dump(p_ptr);
2766
2767 /* Drop (or destroy?) items */
2768 drop_items = TRUE;
2769 /* Ironmen/Brave players destroy their items on death: */
2770 if (cfg_ironman || option_p(p_ptr, NO_GHOST))
2771 {
2772 drop_items = FALSE;
2773 }
2774
2775 /* Drop all items on floor */
2776 player_strip(p_ptr, drop_items, drop_items, drop_items, FALSE);
2777
2778 /* Last chance to survive death: */
2779 if (cfg_ironman || option_p(p_ptr, NO_GHOST))
2780 {
2781 /* Get rid of him */
2782 player_funeral(p_ptr, format("Killed by %s", p_ptr->died_from));
2783
2784 /* Done */
2785 return;
2786 }
2787
2788 /** Survived death **/
2789
2790 /* Give him his hit points back */
2791 p_ptr->mhp = p_ptr->lev + 2;
2792 p_ptr->chp = p_ptr->mhp;
2793 p_ptr->chp_frac = 0;
2794
2795 /* Ghost! */
2796 if (p_ptr->fruit_bat != -1)
2797 {
2798 /* Tell him */
2799 msg_format(p_ptr, "You have been killed by %s.", p_ptr->died_from);
2800
2801 /* Turn him into a ghost */
2802 p_ptr->ghost = 1;
2803
2804 /* Teleport him */
2805 teleport_player(p_ptr, 200);
2806 }
2807
2808 /* Cure him from various maladies */
2809 if (p_ptr->image) (void)set_image(p_ptr, 0);
2810 if (p_ptr->blind) (void)set_blind(p_ptr, 0);
2811 if (p_ptr->paralyzed) (void)set_paralyzed(p_ptr, 0);
2812 if (p_ptr->confused) (void)set_confused(p_ptr, 0);
2813 if (p_ptr->poisoned) (void)set_poisoned(p_ptr, 0);
2814 if (p_ptr->stun) (void)set_stun(p_ptr, 0);
2815 if (p_ptr->cut) (void)set_cut(p_ptr, 0);
2816 if (p_ptr->shero) (void)set_shero(p_ptr, 0);
2817 if (p_ptr->fruit_bat != -1) (void)set_food(p_ptr, PY_FOOD_MAX - 1);
2818 else p_ptr->fruit_bat = 2;
2819
2820 /* Remove the death flag */
2821 p_ptr->death = 0;
2822
2823 /* Cancel any WOR spells */
2824 p_ptr->word_recall = 0;
2825
2826 /* Update bonus */
2827 p_ptr->update |= (PU_BONUS | PU_HP);
2828
2829 /* Redraw */
2830 p_ptr->redraw |= (PR_HP | PR_GOLD | PR_BASIC | PR_OFLAGS );
2831
2832 /* Notice */
2833 p_ptr->notice |= (PN_COMBINE | PN_REORDER);
2834
2835 /* Redraw Inven/Equip */
2836 p_ptr->redraw_inven |= (0xFFFFFFFFFFFFFFFFLL);
2837
2838 /* Windows */
2839 p_ptr->window |= (PW_SPELL);
2840 }
2841
2842 /*
2843 * Resurrect a player
2844 */
2845
2846 /* To prevent people from ressurecting too many times, I am modifying this to give
2847 everyone 1 "freebie", and then to have a p_ptr->level % chance of failing to
2848 ressurect and have your ghost be destroyed.
2849
2850 -APD-
2851
2852 Hmm, haven't gotten around to doing this yet...
2853 */
2854
resurrect_player(player_type * p_ptr)2855 void resurrect_player(player_type *p_ptr)
2856 {
2857 /* Hack -- the dungeon master can not ressurect */
2858 if (is_dm_p(p_ptr)) return;
2859
2860 /* Reset ghost flag */
2861 p_ptr->ghost = 0;
2862
2863 /* Count resurrections */
2864 p_ptr->lives++;
2865
2866 /* Lose some experience */
2867 p_ptr->max_exp -= p_ptr->max_exp / 2;
2868 p_ptr->exp -= p_ptr->exp / 2;
2869 check_experience(p_ptr);
2870
2871 /* If we resurrect in town, we get a little cash */
2872 if (!p_ptr->dun_depth && p_ptr->lev >= 5)
2873 {
2874 p_ptr->au = 100;
2875 }
2876
2877 /* Log event */
2878 log_history_event(p_ptr, "Resurrected", FALSE);
2879
2880 /* Message */
2881 msg_print(p_ptr, "You feel life return to your body.");
2882
2883 /* Show the change to others as needed */
2884 everyone_lite_spot(p_ptr->dun_depth, p_ptr->py, p_ptr->px);
2885
2886 /* Redraw */
2887 p_ptr->redraw |= (PR_BASIC | PR_OFLAGS);
2888
2889 /* Update */
2890 p_ptr->update |= (PU_BONUS);
2891
2892 /* Window */
2893 p_ptr->window |= (PW_SPELL);
2894 }
2895
2896
2897 /*
2898 * Decreases monsters hit points, handling monster death.
2899 *
2900 * We return TRUE if the monster has been killed (and deleted).
2901 *
2902 * We announce monster death (using an optional "death message"
2903 * if given, and a otherwise a generic killed/destroyed message).
2904 *
2905 * Only "physical attacks" can induce the "You have slain" message.
2906 * Missile and Spell attacks will induce the "dies" message, or
2907 * various "specialized" messages. Note that "You have destroyed"
2908 * and "is destroyed" are synonyms for "You have slain" and "dies".
2909 *
2910 * Hack -- unseen monsters yield "You have killed it." message.
2911 *
2912 * Added fear (DGK) and check whether to print fear messages -CWS
2913 *
2914 * Genericized name, sex, and capitilization -BEN-
2915 *
2916 * As always, the "ghost" processing is a total hack.
2917 *
2918 * Hack -- we "delay" fear messages by passing around a "fear" flag.
2919 *
2920 * XXX XXX XXX Consider decreasing monster experience over time, say,
2921 * by using "(m_exp * m_lev * (m_lev)) / (p_lev * (m_lev + n_killed))"
2922 * instead of simply "(m_exp * m_lev) / (p_lev)", to make the first
2923 * monster worth more than subsequent monsters. This would also need
2924 * to induce changes in the monster recall code.
2925 */
mon_take_hit(player_type * p_ptr,int m_idx,int dam,bool * fear,cptr note)2926 bool mon_take_hit(player_type *p_ptr, int m_idx, int dam, bool *fear, cptr note)
2927 {
2928 monster_type *m_ptr = &m_list[m_idx];
2929
2930 monster_race *r_ptr = &r_info[m_ptr->r_idx];
2931
2932 s32b new_exp, new_exp_frac;
2933
2934 /* Killing an unique multiple times is cheezy! */
2935 bool cheeze = ((r_ptr->flags1 & RF1_UNIQUE) && p_ptr->r_killed[m_ptr->r_idx]);
2936
2937 /* Handle calling this when the monster is no longer there */
2938 if (m_idx == 0) return TRUE;
2939
2940 /* Remember that he hurt it */
2941 p_ptr->mon_hrt[m_idx] = TRUE;
2942
2943 /* Redraw (later) if needed */
2944 update_health(m_idx);
2945
2946 /* Wake it up */
2947 m_ptr->csleep = 0;
2948
2949 /* Hurt it */
2950 m_ptr->hp -= dam;
2951
2952 /* It is dead now */
2953 if (m_ptr->hp < 0)
2954 {
2955 char m_name[80];
2956
2957 /* Assume normal death sound */
2958 int soundfx = MSG_KILL;
2959
2960 /* Play a special sound if the monster was unique */
2961 if (r_ptr->flags1 & RF1_UNIQUE)
2962 {
2963 /* Mega-Hack -- Morgoth -- see monster_death() */
2964 if (r_ptr->flags1 & RF1_DROP_CHOSEN)
2965 soundfx = MSG_KILL_KING;
2966 else
2967 soundfx = MSG_KILL_UNIQUE;
2968 }
2969
2970 /* Extract monster name */
2971 monster_desc(p_ptr, m_name, m_idx, 0);
2972
2973 /* Make a sound */
2974 sound(p_ptr, soundfx);
2975
2976 /* Death by Missile/Spell attack */
2977 if (note)
2978 {
2979 msg_format_near(p_ptr, "%^s%s", m_name, note);
2980 msg_format(p_ptr, "%^s%s", m_name, note);
2981 }
2982
2983 /* Death by physical attack -- invisible monster */
2984 else if (!p_ptr->mon_vis[m_idx])
2985 {
2986 msg_format_near(p_ptr, "%s has killed %s.", p_ptr->name, m_name);
2987 msg_format(p_ptr, "You have killed %s.", m_name);
2988 }
2989
2990 /* Death by Physical attack -- non-living monster */
2991 else if ((r_ptr->flags3 & RF3_DEMON) ||
2992 (r_ptr->flags3 & RF3_UNDEAD) ||
2993 (r_ptr->flags2 & RF2_STUPID) ||
2994 (strchr("Evg", r_ptr->d_char)))
2995 {
2996 msg_format_near(p_ptr, "%s has destroyed %s.", p_ptr->name, m_name);
2997 msg_format(p_ptr, "You have destroyed %s.", m_name);
2998 }
2999
3000 /* Death by Physical attack -- living monster */
3001 else
3002 {
3003 msg_format_near(p_ptr, "%s has slain %s.", p_ptr->name, m_name);
3004 msg_format(p_ptr, "You have slain %s.", m_name);
3005 }
3006
3007 /* Cheezy kills give neither xp nor loot! */
3008 if (cheeze)
3009 {
3010 /* Cheezy escape mega-hack */
3011 delete_monster_idx(m_idx);
3012 (*fear) = FALSE;
3013 return (TRUE);
3014 }
3015
3016 /* HACK -- Breeders give no XP */
3017 if (!(r_ptr->flags2 & RF2_MULTIPLY))
3018 {
3019 /* Split experience if in a party */
3020 if (p_ptr->party && cfg_party_share_exp)
3021 {
3022 party_gain_exp(p_ptr, p_ptr->party, (long)r_ptr->mexp * r_ptr->level, m_idx);
3023 }
3024 /* Single-player */
3025 else
3026 {
3027 /* Give some experience */
3028 new_exp = ((long)r_ptr->mexp * r_ptr->level) / p_ptr->lev;
3029 new_exp_frac = ((((long)r_ptr->mexp * r_ptr->level) % p_ptr->lev)
3030 * 0x10000L / p_ptr->lev) + p_ptr->exp_frac;
3031
3032 /* Keep track of experience */
3033 if (new_exp_frac >= 0x10000L)
3034 {
3035 new_exp++;
3036 p_ptr->exp_frac = new_exp_frac - 0x10000L;
3037 }
3038 else
3039 {
3040 p_ptr->exp_frac = new_exp_frac;
3041 }
3042
3043 /* Gain experience */
3044 gain_exp(p_ptr, new_exp);
3045 }
3046 }
3047
3048 /* Generate treasure */
3049 monster_death(p_ptr, m_idx);
3050
3051 /* When the player kills a Unique, it stays dead */
3052 //if (r_ptr->flags1 & RF1_UNIQUE) r_ptr->max_num = 0;
3053
3054 /* Recall even invisible uniques or winners */
3055 if (p_ptr->mon_vis[m_idx] || (r_ptr->flags1 & RF1_UNIQUE))
3056 {
3057 /* Count kills by all players */
3058 if (r_ptr->r_tkills < MAX_SHORT) r_ptr->r_tkills++;
3059
3060 /* Hack -- Auto-recall */
3061 monster_race_track(p_ptr, m_ptr->r_idx);
3062 }
3063
3064 /* Delete the monster */
3065 delete_monster_idx(m_idx);
3066
3067 /* Not afraid */
3068 (*fear) = FALSE;
3069
3070 /* Monster is dead */
3071 return (TRUE);
3072 }
3073
3074 /* New MAnghack: reveal mimics */
3075 if (m_ptr->mimic_k_idx)
3076 {
3077 reveal_mimic(m_idx);
3078 }
3079
3080 #ifdef ALLOW_FEAR
3081
3082 /* Mega-Hack -- Pain cancels fear */
3083 if (m_ptr->monfear && (dam > 0))
3084 {
3085 int tmp = randint1(dam);
3086
3087 /* Cure a little fear */
3088 if (tmp < m_ptr->monfear)
3089 {
3090 /* Reduce fear */
3091 m_ptr->monfear -= tmp;
3092 }
3093
3094 /* Cure all the fear */
3095 else
3096 {
3097 /* Cure fear */
3098 m_ptr->monfear = 0;
3099
3100 /* No more fear */
3101 (*fear) = FALSE;
3102 }
3103 }
3104
3105 /* Sometimes a monster gets scared by damage */
3106 if (!m_ptr->monfear && !(r_ptr->flags3 & RF3_NO_FEAR))
3107 {
3108 int percentage;
3109
3110 /* Percentage of fully healthy */
3111 percentage = (100L * m_ptr->hp) / m_ptr->maxhp;
3112
3113 /*
3114 * Run (sometimes) if at 10% or less of max hit points,
3115 * or (usually) when hit for half its current hit points
3116 */
3117 if (((percentage <= 10) && (randint0(10) < percentage)) ||
3118 ((dam >= m_ptr->hp) && (randint0(100) < 80)))
3119 {
3120 /* Hack -- note fear */
3121 (*fear) = TRUE;
3122
3123 /* XXX XXX XXX Hack -- Add some timed fear */
3124 m_ptr->monfear = (randint1(10) +
3125 (((dam >= m_ptr->hp) && (percentage > 7)) ?
3126 20 : ((11 - percentage) * 5)));
3127 }
3128 }
3129
3130 #endif
3131
3132 /* Not dead yet */
3133 return (FALSE);
3134 }
3135
3136
3137
3138 /*
3139 * Calculates current boundaries
3140 * Called below and from "do_cmd_locate()".
3141 */
panel_bounds(player_type * p_ptr)3142 void panel_bounds(player_type *p_ptr)
3143 {
3144 p_ptr->panel_row_min = (p_ptr->panel_row * p_ptr->screen_hgt) / 2;
3145 if (p_ptr->panel_row_min + p_ptr->screen_hgt > p_ptr->cur_hgt) p_ptr->panel_row_min = p_ptr->cur_hgt - p_ptr->screen_hgt;
3146 p_ptr->panel_row_max = p_ptr->panel_row_min + p_ptr->screen_hgt - 1;
3147 p_ptr->panel_row_prt = p_ptr->panel_row_min;
3148 p_ptr->panel_col_min = (p_ptr->panel_col * p_ptr->screen_wid) / 2;
3149 if (p_ptr->panel_col_min + p_ptr->screen_wid > p_ptr->cur_wid) p_ptr->panel_col_min = p_ptr->cur_wid - p_ptr->screen_wid;
3150 p_ptr->panel_col_max = p_ptr->panel_col_min + p_ptr->screen_wid - 1;
3151 p_ptr->panel_col_prt = p_ptr->panel_col_min;
3152 }
3153
3154
3155
3156 /*
3157 * Given an row (y) and col (x), this routine detects when a move
3158 * off the screen has occurred and figures new borders. -RAK-
3159 *
3160 * "Update" forces a "full update" to take place.
3161 *
3162 * The map is reprinted if necessary, and "TRUE" is returned.
3163 */
verify_panel(player_type * p_ptr)3164 void verify_panel(player_type *p_ptr)
3165 {
3166 int y = p_ptr->py;
3167 int x = p_ptr->px;
3168
3169 int prow = p_ptr->panel_row;
3170 int pcol = p_ptr->panel_col;
3171
3172 /* Scroll screen when 2 grids from top/bottom edge */
3173 if ((y < p_ptr->panel_row_min + 2) || (y > p_ptr->panel_row_max - 2))
3174 {
3175 prow = ((y - p_ptr->screen_hgt / 4) / (p_ptr->screen_hgt / 2));
3176 if (prow == p_ptr->panel_row) /* no change, let's try again */
3177 {
3178 if ((y < p_ptr->panel_row_min + 2)) prow--;
3179 else prow++;
3180 }
3181 if (prow > p_ptr->max_panel_rows) prow = p_ptr->max_panel_rows;
3182 else if (prow < 0) prow = 0;
3183 }
3184
3185 /* Scroll screen when 4 grids from left/right edge */
3186 if ((x < p_ptr->panel_col_min + 4) || (x > p_ptr->panel_col_max - 4))
3187 {
3188 pcol = ((x - p_ptr->screen_wid / 4) / (p_ptr->screen_wid / 2));
3189 if (pcol == p_ptr->panel_col) /* no change, let's try again */
3190 {
3191 if ((x < p_ptr->panel_col_min + 4)) pcol--;
3192 else pcol++;
3193 }
3194 if (pcol > p_ptr->max_panel_cols) pcol = p_ptr->max_panel_cols;
3195 else if (pcol < 0) pcol = 0;
3196 }
3197
3198 /* Check for "no change" */
3199 if ((prow == p_ptr->panel_row) && (pcol == p_ptr->panel_col)) return;
3200
3201 /* Hack -- optional disturb on "panel change" */
3202 if (option_p(p_ptr,DISTURB_PANEL)) disturb(p_ptr, 0, 0);
3203
3204 /* Save the new panel info */
3205 p_ptr->panel_row = prow;
3206 p_ptr->panel_col = pcol;
3207
3208 /* Recalculate the boundaries */
3209 panel_bounds(p_ptr);
3210
3211 /* Update stuff */
3212 p_ptr->update |= (PU_MONSTERS);
3213
3214 /* Redraw map */
3215 p_ptr->redraw |= (PR_MAP);
3216
3217 /* Window stuff */
3218 p_ptr->window |= (PW_OVERHEAD | PW_MAP);
3219 }
setup_panel(player_type * p_ptr,bool adjust)3220 void setup_panel(player_type *p_ptr, bool adjust)
3221 {
3222 /* Set the player's "panel" information */
3223 p_ptr->max_panel_rows = (MAX_HGT / p_ptr->screen_hgt) * 2 - 2;
3224 p_ptr->max_panel_cols = (MAX_WID / p_ptr->screen_wid) * 2 - 2;
3225
3226 /* Hack -- allow 'panel' leftovers */
3227 while (MAX_WID * 2 - (p_ptr->max_panel_cols + 2) * p_ptr->screen_wid > 0) p_ptr->max_panel_cols++;
3228 while (MAX_HGT * 2 - (p_ptr->max_panel_rows + 2) * p_ptr->screen_hgt > 0) p_ptr->max_panel_rows++;
3229
3230 /* Restore dungeon width (might've been overwritten by other displays) */
3231 p_ptr->cur_hgt = MAX_HGT;
3232 p_ptr->cur_wid = MAX_WID;
3233
3234 /* Skip rest */
3235 if (!adjust) return;
3236
3237 /* Set current */
3238 p_ptr->panel_row = ((p_ptr->py - p_ptr->screen_hgt / 4) / (p_ptr->screen_hgt / 2));
3239 if (p_ptr->panel_row > p_ptr->max_panel_rows) p_ptr->panel_row = p_ptr->max_panel_rows;
3240 else if (p_ptr->panel_row < 0) p_ptr->panel_row = 0;
3241 p_ptr->panel_col = ((p_ptr->px - p_ptr->screen_wid / 4) / (p_ptr->screen_wid / 2));
3242 if (p_ptr->panel_col > p_ptr->max_panel_cols) p_ptr->panel_col = p_ptr->max_panel_cols;
3243 else if (p_ptr->panel_col < 0) p_ptr->panel_col = 0;
3244
3245 /* Set the rest of the panel information */
3246 panel_bounds(p_ptr);
3247 }
adjust_panel(player_type * p_ptr,int y,int x)3248 bool adjust_panel(player_type *p_ptr, int y, int x)
3249 {
3250 int x2, y2;
3251
3252 /* Start at current panel */
3253 y2 = p_ptr->panel_row;
3254 x2 = p_ptr->panel_col;
3255
3256 if (x < p_ptr->panel_col_min) x2--;
3257 if (x > p_ptr->panel_col_max) x2++;
3258
3259 if (y < p_ptr->panel_row_min) y2--;
3260 if (y > p_ptr->panel_row_max) y2++;
3261
3262 /* Verify the row */
3263 if (y2 > p_ptr->max_panel_rows) y2 = p_ptr->max_panel_rows;
3264 else if (y2 < 0) y2 = 0;
3265
3266 /* Verify the col */
3267 if (x2 > p_ptr->max_panel_cols) x2 = p_ptr->max_panel_cols;
3268 else if (x2 < 0) x2 = 0;
3269
3270 if (x2 != p_ptr->panel_col || y2 != p_ptr->panel_row)
3271 {
3272 p_ptr->panel_row = y2;
3273 p_ptr->panel_col = x2;
3274
3275 panel_bounds(p_ptr);
3276
3277 /* Redraw map */
3278 p_ptr->redraw |= (PR_MAP);
3279 // p_ptr->window |= (PW_OVERHEAD | PW_MAP);
3280
3281 return TRUE;
3282 }
3283 return FALSE;
3284 }
3285
3286 /*
3287 * Heatlh description (unhurt, wounded, etc)
3288 */
look_health_desc(bool living,s16b chp,s16b mhp)3289 cptr look_health_desc(bool living, s16b chp, s16b mhp)
3290 {
3291 int perc;
3292
3293 /* Healthy */
3294 if (chp >= mhp)
3295 {
3296 /* No damage */
3297 return (living ? "unhurt" : "undamaged");
3298 }
3299
3300
3301 /* Calculate a health "percentage" */
3302 perc = 100L * chp / mhp;
3303
3304 if (perc >= 60)
3305 {
3306 return (living ? "somewhat wounded" : "somewhat damaged");
3307 }
3308
3309 if (perc >= 25)
3310 {
3311 return (living ? "wounded" : "damaged");
3312 }
3313
3314 if (perc >= 10)
3315 {
3316 return (living ? "badly wounded" : "badly damaged");
3317 }
3318
3319 return (living ? "almost dead" : "almost destroyed");
3320 }
3321
3322 /*
3323 * Player Health Description
3324 */
look_player_desc(int Ind)3325 cptr look_player_desc(int Ind)
3326 {
3327 player_type *p_ptr = Players[Ind];
3328
3329 bool living = TRUE;
3330 static char buf[80];
3331
3332
3333 /* Determine if the player is "living" (vs "undead") */
3334 if (p_ptr->ghost) living = FALSE;
3335
3336 /* Apply health description */
3337 strcpy(buf, look_health_desc(living, p_ptr->chp, p_ptr->mhp));
3338
3339 /* Apply condition descriptions */
3340 if (p_ptr->resting) strcat(buf, ", resting");
3341 if (p_ptr->confused) strcat(buf, ", confused");
3342 if (p_ptr->afraid) strcat(buf, ", afraid");
3343 if (p_ptr->stun) strcat(buf, ", stunned");
3344
3345 /* Player-specific conditions */
3346 if (p_ptr->paralyzed) strcat(buf, ", paralyzed");
3347
3348 return buf;
3349 }
3350 /*
3351 * Monster health description
3352 */
look_mon_desc(int m_idx)3353 cptr look_mon_desc(int m_idx)
3354 {
3355 monster_type *m_ptr = &m_list[m_idx];
3356 monster_race *r_ptr = &r_info[m_ptr->r_idx];
3357
3358 bool living = TRUE;
3359 static char buf[80];
3360
3361
3362 /* Determine if the monster is "living" (vs "undead") */
3363 if (r_ptr->flags3 & RF3_UNDEAD) living = FALSE;
3364 if (r_ptr->flags3 & RF3_DEMON) living = FALSE;
3365 if (strchr("Egv", r_ptr->d_char)) living = FALSE;
3366
3367 /* Apply health description */
3368 strcpy(buf, look_health_desc(living, m_ptr->hp, m_ptr->maxhp));
3369
3370 /* Apply condition descriptions */
3371 if (m_ptr->csleep) strcat(buf, ", asleep");
3372 if (m_ptr->confused) strcat(buf, ", confused");
3373 if (m_ptr->monfear) strcat(buf, ", afraid");
3374 if (m_ptr->stunned) strcat(buf, ", stunned");
3375
3376 return buf;
3377 }
3378
3379
3380
3381
3382 /* returns our max times 100 divided by our current...*/
player_wounded(s16b ind)3383 int player_wounded(s16b ind)
3384 {
3385 player_type *p_ptr = Players[ind];
3386
3387 return ((p_ptr->mhp+1) * 100) / (p_ptr->chp+1);
3388 }
3389 /*
3390 * Sorting hook -- comp -- function -- by "mostly wounded"
3391 *
3392 * We use "u" and "v" to point to arrays of "x" and "y" positions,
3393 * where two players are located.
3394 *
3395 * This is a port of "wounded_player_target_sort()" by -ADA-
3396 * and uses it's "player_wounded()" helper function.
3397 */
mang_sort_comp_wounded(void * player_context,vptr u,vptr v,int a,int b)3398 bool mang_sort_comp_wounded(void* player_context, vptr u, vptr v, int a, int b)
3399 {
3400 player_type *p_ptr = (player_type*)player_context;
3401 byte *x = (byte*)(u);
3402 byte *y = (byte*)(v);
3403
3404 int Depth = p_ptr->dun_depth;
3405 int w1, w2;
3406
3407 s16b idx1 = 0 - cave[Depth][y[a]][x[a]].m_idx;
3408 s16b idx2 = 0 - cave[Depth][y[b]][x[b]].m_idx;
3409
3410 w1 = player_wounded(idx1);
3411 w2 = player_wounded(idx2);
3412
3413 return (w2 <= w1);
3414 }
3415
3416
3417
3418 /*
3419 * Sorting hook -- comp function -- by "distance to player"
3420 *
3421 * We use "u" and "v" to point to arrays of "x" and "y" positions,
3422 * and sort the arrays by double-distance to the player.
3423 * We then compare by "player_wounded()" value.
3424 */
ang_sort_comp_distance(void * player_context,vptr u,vptr v,int a,int b)3425 bool ang_sort_comp_distance(void *player_context, vptr u, vptr v, int a, int b)
3426 {
3427 player_type *p_ptr = (player_type*)player_context;
3428 byte *x = (byte*)(u);
3429 byte *y = (byte*)(v);
3430
3431 int da, db, kx, ky;
3432
3433 /* Absolute distance components */
3434 kx = x[a]; kx -= p_ptr->px; kx = ABS(kx);
3435 ky = y[a]; ky -= p_ptr->py; ky = ABS(ky);
3436
3437 /* Approximate Double Distance to the first point */
3438 da = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx));
3439
3440 /* Absolute distance components */
3441 kx = x[b]; kx -= p_ptr->px; kx = ABS(kx);
3442 ky = y[b]; ky -= p_ptr->py; ky = ABS(ky);
3443
3444 /* Approximate Double Distance to the first point */
3445 db = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx));
3446
3447 /* Compare the distances */
3448 return (da <= db);
3449 }
3450
3451
3452 /*
3453 * Sorting hook -- swap function -- by "distance to player"
3454 *
3455 * We use "u" and "v" to point to arrays of "x" and "y" positions,
3456 * and sort the arrays by distance to the player.
3457 */
ang_sort_swap_distance(void * player_context,vptr u,vptr v,int a,int b)3458 void ang_sort_swap_distance(void* player_context, vptr u, vptr v, int a, int b)
3459 {
3460 player_type *p_ptr = (player_type*)player_context;
3461 byte *x = (byte*)(u);
3462 byte *y = (byte*)(v);
3463
3464 byte temp;
3465
3466 /* Swap "x" */
3467 temp = x[a];
3468 x[a] = x[b];
3469 x[b] = temp;
3470
3471 /* Swap "y" */
3472 temp = y[a];
3473 y[a] = y[b];
3474 y[b] = temp;
3475 }
3476
3477
3478
3479 /*
3480 * Compare the values of two objects.
3481 *
3482 * Pointer "v" should not point to anything (it isn't used, anyway).
3483 */
ang_sort_comp_value(void * player_context,vptr u,vptr v,int a,int b)3484 bool ang_sort_comp_value(void* player_context, vptr u, vptr v, int a, int b)
3485 {
3486 player_type *p_ptr = (player_type*)player_context;
3487 object_type *inven = (object_type *)u;
3488 s32b va, vb;
3489
3490 if (inven[a].tval && inven[b].tval)
3491 {
3492 va = object_value(p_ptr, &inven[a]);
3493 vb = object_value(p_ptr, &inven[b]);
3494
3495 return (va >= vb);
3496 }
3497
3498 if (inven[a].tval)
3499 return FALSE;
3500
3501 return TRUE;
3502 }
3503
3504
ang_sort_swap_value(void * player_context,vptr u,vptr v,int a,int b)3505 void ang_sort_swap_value(void* player_context, vptr u, vptr v, int a, int b)
3506 {
3507 player_type *p_ptr = (player_type*)player_context;
3508 object_type *x = (object_type *)u;
3509 object_type temp;
3510
3511 temp = x[a];
3512 x[a] = x[b];
3513 x[b] = temp;
3514 }
3515
3516
3517
3518 /*** Targetting Code ***/
3519
3520
3521 /*
3522 * Determine is a monster makes a reasonable target
3523 *
3524 * The concept of "targetting" was stolen from "Morgul" (?)
3525 *
3526 * The player can target any location, or any "target-able" monster.
3527 *
3528 * Currently, a monster is "target_able" if it is visible, and if
3529 * the player can hit it with a projection, and the player is not
3530 * hallucinating. This allows use of "use closest target" macros.
3531 *
3532 * Future versions may restrict the ability to target "trappers"
3533 * and "mimics", but the semantics is a little bit weird.
3534 */
target_able(player_type * p_ptr,int m_idx)3535 bool target_able(player_type *p_ptr, int m_idx)
3536 {
3537 player_type *q_ptr;
3538 monster_type *m_ptr;
3539
3540 /* Check for OK monster */
3541 if (m_idx > 0)
3542 {
3543 /* Acquire pointer */
3544 m_ptr = &m_list[m_idx];
3545
3546 /* Monster must be visible */
3547 if (!p_ptr->mon_vis[m_idx]) return (FALSE);
3548
3549 /* Monster must be projectable */
3550 if (!projectable(p_ptr->dun_depth, p_ptr->py, p_ptr->px, m_ptr->fy, m_ptr->fx)) return (FALSE);
3551
3552 /* Hack -- no targeting hallucinations */
3553 if (p_ptr->image) return (FALSE);
3554
3555 /* XXX XXX XXX Hack -- Never target trappers */
3556 /* if (CLEAR_ATTR && CLEAR_CHAR) return (FALSE); */
3557
3558 /* Assume okay */
3559 return (TRUE);
3560 }
3561
3562 /* Check for OK player */
3563 if (m_idx < 0)
3564 {
3565 /* Acquire pointer */
3566 q_ptr = Players[0 - m_idx];
3567
3568 /* Paranoia check -- require a valid player */
3569 if ((0 - m_idx) >= MAX_PLAYERS) return (FALSE);
3570 if (!q_ptr) return (FALSE);
3571
3572 /* Players must be on same depth */
3573 if (p_ptr->dun_depth != q_ptr->dun_depth) return (FALSE);
3574
3575 /* Player must be visible */
3576 if (!player_can_see_bold(p_ptr, q_ptr->py, q_ptr->px)) return (FALSE);
3577
3578 /* Player must be projectable */
3579 if (!projectable(p_ptr->dun_depth, p_ptr->py, p_ptr->px, q_ptr->py, q_ptr->px)) return (FALSE);
3580
3581 /* Hack -- no targetting hallucinations */
3582 if (p_ptr->image) return (FALSE);
3583
3584 /* Assume okay */
3585 return (TRUE);
3586 }
3587
3588 /* Assume no target */
3589 return (FALSE);
3590 }
3591
3592
3593
3594
3595 /*
3596 * Update (if necessary) and verify (if possible) the target.
3597 *
3598 * We return TRUE if the target is "okay" and FALSE otherwise.
3599 */
target_okay(player_type * p_ptr)3600 bool target_okay(player_type *p_ptr)
3601 {
3602 /* No target */
3603 if (!p_ptr->target_set) return (FALSE);
3604
3605 /* Accept stationary targets */
3606 if (p_ptr->target_who == 0) return (TRUE);
3607
3608 /* Check moving monsters */
3609 if (p_ptr->target_who > 0)
3610 {
3611 /* Accept reasonable targets */
3612 if (target_able(p_ptr, p_ptr->target_who))
3613 {
3614 monster_type *m_ptr = &m_list[p_ptr->target_who];
3615
3616 /* Acquire monster location */
3617 p_ptr->target_row = m_ptr->fy;
3618 p_ptr->target_col = m_ptr->fx;
3619
3620 /* Good target */
3621 return (TRUE);
3622 }
3623 }
3624
3625 /* Check moving players */
3626 if (p_ptr->target_who < 0)
3627 {
3628
3629 /* Accept reasonable targets */
3630 if (target_able(p_ptr, p_ptr->target_who))
3631 {
3632 player_type *q_ptr = Players[0 - p_ptr->target_who];
3633
3634 /*
3635 Paranoia Check, require Valid Player.
3636 This was causing target_able to explode
3637 with a set, but invalid q_ptr...
3638 --Crimson
3639 */
3640
3641 if ((0 - p_ptr->target_who) >= MAX_PLAYERS) {
3642 return (FALSE);
3643 }
3644 if (!q_ptr) return (FALSE);
3645
3646 /* Acquire player location */
3647 p_ptr->target_row = q_ptr->py;
3648 p_ptr->target_col = q_ptr->px;
3649
3650 /* Good target */
3651 return (TRUE);
3652 }
3653 }
3654
3655 /* Assume no target */
3656 return (FALSE);
3657 }
3658
3659 /*
3660 * Reset player's look_index to a closest target from given X/Y position.
3661 *
3662 * Returns 999 on failure.
3663 */
target_set_index(player_type * p_ptr,int y,int x)3664 int target_set_index(player_type *p_ptr, int y, int x)
3665 {
3666 int bd = 999;
3667 int i, t;
3668
3669 /* Reset */
3670 p_ptr->look_index = 0;
3671 bd = 999;
3672
3673 /* Pick a nearby target */
3674 for (i = 0; i < p_ptr->target_n; i++)
3675 {
3676 t = distance(y, x, p_ptr->target_y[i], p_ptr->target_x[i]);
3677
3678 /* Pick closest */
3679 if (t < bd)
3680 {
3681 p_ptr->look_index = i;
3682 bd = t;
3683 }
3684 }
3685
3686 return bd;
3687 }
3688
3689 /*
3690 * Set the target to a monster (or nobody)
3691 */
target_set_monster(player_type * p_ptr,int m_idx)3692 void target_set_monster(player_type *p_ptr, int m_idx)
3693 {
3694 /* Acceptable target */
3695 if ((m_idx != 0) && target_able(p_ptr, m_idx))
3696 {
3697 /* Save target info */
3698 p_ptr->target_set = TRUE;
3699 p_ptr->target_who = m_idx;
3700 /* Monster */
3701 if (m_idx > 0)
3702 {
3703 monster_type *m_ptr = &m_list[m_idx];
3704 p_ptr->target_row = m_ptr->fy;
3705 p_ptr->target_col = m_ptr->fx;
3706 }
3707 else
3708 {
3709 player_type *q_ptr = Players[0 - m_idx];
3710 p_ptr->target_row = q_ptr->py;
3711 p_ptr->target_col = q_ptr->px;
3712 }
3713 }
3714
3715 /* Clear target */
3716 else
3717 {
3718 /* Reset target info */
3719 p_ptr->target_set = FALSE;
3720 p_ptr->target_who = 0;
3721 p_ptr->target_row = 0;
3722 p_ptr->target_col = 0;
3723 }
3724 }
3725
3726 /*
3727 * Set the target to a location
3728 */
target_set_location(player_type * p_ptr,int y,int x)3729 void target_set_location(player_type *p_ptr, int y, int x)
3730 {
3731 int Depth = p_ptr->dun_depth;
3732 /* Legal target */
3733 //if (in_bounds_fully(y, x))
3734 if (in_bounds(Depth, y, x))
3735 {
3736 /* Save target info */
3737 p_ptr->target_set = TRUE;
3738 p_ptr->target_who = 0;
3739 p_ptr->target_row = y;
3740 p_ptr->target_col = x;
3741 }
3742
3743 /* Clear target */
3744 else
3745 {
3746 /* Reset target info */
3747 p_ptr->target_set = FALSE;
3748 p_ptr->target_who = 0;
3749 p_ptr->target_row = 0;
3750 p_ptr->target_col = 0;
3751 }
3752 }
3753
3754
3755
3756
3757
3758 /*
3759 * Hack -- help "select" a location (see below)
3760 */
target_pick(player_type * p_ptr,int y1,int x1,int dy,int dx)3761 s16b target_pick(player_type *p_ptr, int y1, int x1, int dy, int dx)
3762 {
3763 int i, v;
3764
3765 int x2, y2, x3, y3, x4, y4;
3766
3767 int b_i = -1, b_v = 9999;
3768
3769
3770 /* Scan the locations */
3771 for (i = 0; i < p_ptr->target_n; i++)
3772 {
3773 /* Point 2 */
3774 x2 = p_ptr->target_x[i];
3775 y2 = p_ptr->target_y[i];
3776
3777 /* Directed distance */
3778 x3 = (x2 - x1);
3779 y3 = (y2 - y1);
3780
3781 /* Verify quadrant */
3782 if (dx && (x3 * dx <= 0)) continue;
3783 if (dy && (y3 * dy <= 0)) continue;
3784
3785 /* Absolute distance */
3786 x4 = ABS(x3);
3787 y4 = ABS(y3);
3788
3789 /* Verify quadrant */
3790 if (dy && !dx && (x4 > y4)) continue;
3791 if (dx && !dy && (y4 > x4)) continue;
3792
3793 /* Approximate Double Distance */
3794 v = ((x4 > y4) ? (x4 + x4 + y4) : (y4 + y4 + x4));
3795
3796 /* XXX XXX XXX Penalize location */
3797
3798 /* Track best */
3799 if ((b_i >= 0) && (v >= b_v)) continue;
3800
3801 /* Track best */
3802 b_i = i; b_v = v;
3803 }
3804
3805 /* Result */
3806 return (b_i);
3807 }
3808
3809 /*
3810 * Hack -- determine if a given location is "interesting"
3811 */
target_set_interactive_accept(player_type * p_ptr,int y,int x)3812 static bool target_set_interactive_accept(player_type *p_ptr, int y, int x)
3813 {
3814 cave_type *c_ptr;
3815
3816 int Depth = p_ptr->dun_depth;
3817
3818 /* Examine the grid */
3819 c_ptr = &cave[Depth][y][x];
3820
3821 /* Player himself */
3822 if (c_ptr->m_idx < 0 && same_player(Players[0 - c_ptr->m_idx], p_ptr)) return (TRUE);
3823
3824 /* Handle hallucination */
3825 if (p_ptr->image) return (FALSE);
3826
3827
3828 /* Visible players */
3829 if (c_ptr->m_idx < 0)
3830 {
3831 /* Visible monsters */
3832 if (p_ptr->play_vis[0 - c_ptr->m_idx]) return (TRUE);
3833 }
3834
3835 /* Visible monsters */
3836 if (c_ptr->m_idx > 0)
3837 {
3838 /* Visible monsters */
3839 if (p_ptr->mon_vis[c_ptr->m_idx]) return (TRUE);
3840 }
3841
3842 /* Objects */
3843 if (c_ptr->o_idx)
3844 {
3845 /* Memorized object */
3846 if (p_ptr->obj_vis[c_ptr->o_idx]) return (TRUE);
3847 }
3848 #if 0
3849 /* Scan all objects in the grid */
3850 for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr))
3851 {
3852 /* Memorized object */
3853 if (o_ptr->marked) return (TRUE);
3854 }
3855 #endif
3856 /* Interesting memorized features */
3857 if (p_ptr->cave_flag[y][x] & (CAVE_MARK))
3858 {
3859 /* Notice glyphs */
3860 if (c_ptr->feat == FEAT_GLYPH) return (TRUE);
3861
3862 /* Notice doors */
3863 if (c_ptr->feat == FEAT_OPEN) return (TRUE);
3864 if (c_ptr->feat == FEAT_BROKEN) return (TRUE);
3865 if (c_ptr->feat == FEAT_HOME_OPEN) return (TRUE);
3866
3867 /* Notice stairs */
3868 if (c_ptr->feat == FEAT_LESS) return (TRUE);
3869 if (c_ptr->feat == FEAT_MORE) return (TRUE);
3870
3871 /* Notice shops */
3872 if ((c_ptr->feat >= FEAT_SHOP_HEAD) &&
3873 (c_ptr->feat <= FEAT_SHOP_TAIL)) return (TRUE);
3874 if ((c_ptr->feat >= FEAT_HOME_HEAD) &&
3875 (c_ptr->feat <= FEAT_HOME_TAIL)) return (TRUE);
3876
3877 /* Notice traps */
3878 if ((c_ptr->feat >= FEAT_TRAP_HEAD) &&
3879 (c_ptr->feat <= FEAT_TRAP_TAIL)) return (TRUE);
3880
3881 /* Notice doors */
3882 if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
3883 (c_ptr->feat <= FEAT_DOOR_TAIL)) return (TRUE);
3884
3885 /* Notice rubble */
3886 if (c_ptr->feat == FEAT_RUBBLE) return (TRUE);
3887
3888 /* Notice veins with treasure */
3889 if (c_ptr->feat == FEAT_MAGMA_K) return (TRUE);
3890 if (c_ptr->feat == FEAT_QUARTZ_K) return (TRUE);
3891 }
3892
3893 /* Nope */
3894 return (FALSE);
3895 }
3896
3897
3898 /*
3899 * Prepare the "temp" array for "target_interactive_set"
3900 *
3901 * Return the number of target_able monsters in the set.
3902 */
target_set_interactive_prepare(player_type * p_ptr,int mode)3903 static void target_set_interactive_prepare(player_type *p_ptr, int mode)
3904 {
3905 int y, x;
3906 int old_y, old_x;
3907 bool smooth = FALSE;
3908
3909 int Depth = p_ptr->dun_depth;
3910
3911 /* HACK -- Smoothly adjust index */
3912 if ((p_ptr->target_flag & TARGET_GRID) && p_ptr->target_n && (p_ptr->look_index <= p_ptr->target_n))
3913 {
3914 old_y = p_ptr->target_y[p_ptr->look_index];
3915 old_x = p_ptr->target_x[p_ptr->look_index];
3916 smooth = TRUE;
3917 }
3918
3919 /* Reset "temp" array */
3920 p_ptr->target_n = 0;
3921
3922 /* Scan the current panel */
3923 for (y = p_ptr->panel_row_min; y <= p_ptr->panel_row_max; y++)
3924 {
3925 for (x = p_ptr->panel_col_min; x <= p_ptr->panel_col_max; x++)
3926 {
3927 int m_idx;
3928
3929 /* Check bounds */
3930 if (!in_bounds(Depth, y, x)) continue;//bounds_fully
3931
3932 /* Require line of sight, unless "look" is "expanded" */
3933 if (!option_p(p_ptr,EXPAND_LOOK) && !player_has_los_bold(p_ptr, y, x)) continue;
3934
3935 /* Require "interesting" contents */
3936 if (!target_set_interactive_accept(p_ptr, y, x)) continue;
3937
3938 /* Special modes */
3939 if (mode & (TARGET_KILL))
3940 {
3941 /* Must contain someone */
3942 if (!((m_idx = cave[Depth][y][x].m_idx) != 0)) continue;
3943
3944 /* Must be a targettable someone */
3945 if (!target_able(p_ptr, m_idx)) continue;
3946
3947 /* If it's a player, he must not target self */
3948 if (m_idx < 0 && (same_player(Players[0 - m_idx], p_ptr))) continue;
3949
3950 /* If it's a player, he must not be friendly */
3951 if (m_idx < 0 && (!pvp_okay(p_ptr, Players[0 - m_idx], 0) && !check_hostile(p_ptr, Players[0 - m_idx]))) continue;
3952 }
3953 else if (mode & (TARGET_FRND))
3954 {
3955 /* Must contain player */
3956 if (!((m_idx = cave[Depth][y][x].m_idx) < 0)) continue;
3957
3958 /* Not self */
3959 if (same_player(p_ptr, Players[0 - m_idx])) continue;
3960
3961 /* Must be a targettable player */
3962 if (!target_able(p_ptr, m_idx)) continue;
3963
3964 /* Must be friendly player */
3965 if (pvp_okay(p_ptr, Players[0 - m_idx], 0) || check_hostile(Players[0 - m_idx], p_ptr)) continue;
3966 }
3967
3968 /* Save the location */
3969 p_ptr->target_x[p_ptr->target_n] = x;
3970 p_ptr->target_y[p_ptr->target_n] = y;
3971 p_ptr->target_n++;
3972 }
3973 }
3974
3975 /* Set the sort hooks */
3976 ang_sort_comp = ( mode & TARGET_FRND ?
3977 mang_sort_comp_wounded
3978 : ang_sort_comp_distance);
3979 ang_sort_swap = ang_sort_swap_distance;
3980
3981 /* Sort the positions */
3982 ang_sort(p_ptr, p_ptr->target_x, p_ptr->target_y, p_ptr->target_n);
3983
3984 /* HACK -- Smoothly adjust index (continued) */
3985 if (smooth)
3986 {
3987 target_set_index(p_ptr, old_y, old_x);
3988 }
3989
3990 /* Flip index if it's too large */
3991 if (p_ptr->look_index > p_ptr->target_n)
3992 p_ptr->look_index = 0;
3993 }
3994
3995
3996 /*
3997 * Examine a grid, return a keypress.
3998 *
3999 * The "mode" argument contains the "TARGET_LOOK" bit flag, which
4000 * indicates that the "space" key should scan through the contents
4001 * of the grid, instead of simply returning immediately. This lets
4002 * the "look" command get complete information, without making the
4003 * "target" command annoying.
4004 *
4005 * The "info" argument contains the "commands" which should be shown
4006 * inside the "[xxx]" text. This string must never be empty, or grids
4007 * containing monsters will be displayed with an extra comma.
4008 *
4009 * Note that if a monster is in the grid, we update both the monster
4010 * recall info and the health bar info to track that monster.
4011 *
4012 * This function correctly handles multiple objects per grid, and objects
4013 * and terrain features in the same grid, though the latter never happens.
4014 *
4015 * This function must handle blindness/hallucination.
4016 */
target_set_interactive_aux(player_type * p_ptr,int y,int x,int mode,cptr info)4017 static void target_set_interactive_aux(player_type *p_ptr, int y, int x, int mode, cptr info)
4018 {
4019 cptr s1, s2, s3, i1;
4020
4021 bool force_recall;
4022
4023 int feat;
4024 int m_idx;
4025 int o_idx;
4026 int h;
4027
4028 byte out_win = NTERM_WIN_NONE;
4029 char out_val[256];
4030 char x_name[80];
4031 cptr name;
4032
4033 int Depth = p_ptr->dun_depth;
4034
4035 /* Default message */
4036 s1 = "You see ";
4037 s2 = "";
4038 s3 = "";
4039 i1 = "";
4040 force_recall = FALSE;
4041
4042 if (!(mode & TARGET_LOOK))
4043 {
4044 s1 = "";
4045 }
4046
4047 /* Creature on grid (monster or player) */
4048 m_idx = cave[Depth][y][x].m_idx;
4049
4050 /* Object on grid */
4051 o_idx = cave[Depth][y][x].o_idx;
4052
4053 /* The player */
4054 if ((m_idx < 0) && (same_player(Players[0 - m_idx], p_ptr)))
4055 {
4056 /* Description */
4057 s1 = "You are ";
4058
4059 /* Preposition */
4060 s2 = "on ";
4061 }
4062
4063 /* Hack -- hallucination */
4064 if (p_ptr->image)
4065 {
4066 name = "something strange";
4067 }
4068
4069 /* Visible player */
4070 else if (m_idx < 0 && p_ptr->play_vis[0 - m_idx])
4071 {
4072 player_type *q_ptr = Players[0 - m_idx];
4073
4074 /* Hack -- health bar for this player */
4075 health_track(p_ptr, m_idx);
4076
4077 /* Hack -- track cursor for this player */
4078 if (!(p_ptr->target_flag & TARGET_GRID))
4079 cursor_track(p_ptr, m_idx);
4080
4081 /* Describe player */
4082 if (q_ptr->ghost)
4083 strnfmt(x_name, sizeof(x_name), "a ghost of %s (%s)",
4084 q_ptr->name, look_player_desc(0 - m_idx) );
4085 else
4086 strnfmt(x_name, sizeof(x_name), "%s, the %s %s (%s)",
4087 q_ptr->name, p_name + p_info[q_ptr->prace].name,
4088 c_text + q_ptr->cp_ptr->title[(q_ptr->lev-1)/5],
4089 look_player_desc(0 - m_idx) );
4090
4091 name = x_name;
4092 i1 = "r,";
4093
4094 /* Hack -- show "player recall" */
4095 if (p_ptr->target_flag & TARGET_READ)
4096 {
4097 /* Hack -- cancel monster tracking */
4098 monster_race_track(p_ptr, 0);
4099 /* Hack -- call descriptive function */
4100 do_cmd_monster_desc_aux(p_ptr, m_idx, TRUE);
4101 /* Hack -- pop up immediatly */
4102 force_recall = TRUE;
4103 }
4104 }
4105
4106 /* Visible monster */
4107 else if (m_idx > 0 && p_ptr->mon_vis[m_idx])
4108 {
4109 monster_type *m_ptr = &m_list[m_idx];
4110 char m_name[80];
4111
4112 /* Get the monster name ("a kobold") */
4113 monster_desc(p_ptr, m_name, m_idx, 0);
4114
4115 /* Hack -- track this monster race */
4116 monster_race_track(p_ptr, m_ptr->r_idx);
4117
4118 /* Hack -- health bar for this monster */
4119 health_track(p_ptr, m_idx);
4120
4121 /* Hack -- track cursor fo this monster */
4122 if (!(p_ptr->target_flag & TARGET_GRID))
4123 cursor_track(p_ptr, m_idx);
4124
4125 /* Hack -- handle stuff */
4126 handle_stuff(p_ptr);
4127
4128 /* Describe the monster */
4129 strnfmt(x_name, sizeof(x_name), "%s (%s)",
4130 m_name, look_mon_desc(m_idx) );
4131
4132 name = x_name;
4133 i1 = "r,";
4134
4135 /* Notify about recall instead of prompt */
4136 if (p_ptr->target_flag & TARGET_READ)
4137 {
4138 force_recall = TRUE;
4139 }
4140 }
4141
4142 /* Visible Object */
4143 else if (o_idx > 0 && p_ptr->obj_vis[o_idx])
4144 {
4145 object_type *o_ptr = &o_list[o_idx];
4146
4147 /* Obtain an object description */
4148 object_desc(p_ptr, x_name, sizeof(x_name), o_ptr, TRUE, 3);
4149
4150 name = x_name;
4151 }
4152
4153 /* Terrain feature if needed */
4154 else
4155 {
4156 /* Feature (apply "mimic") */
4157 feat = f_info[cave[Depth][y][x].feat].mimic;
4158
4159 /* Require knowledge about grid, or ability to see grid */
4160 if (!(p_ptr->cave_flag[y][x] & (CAVE_MARK)) && !player_can_see_bold(p_ptr, y,x))
4161 {
4162 /* Forget feature */
4163 feat = FEAT_NONE;
4164 }
4165
4166 name = f_name + f_info[feat].name;
4167
4168 /* Hack -- handle unknown grids */
4169 if (feat == FEAT_NONE) name = "unknown grid";// || feat <= FEAT_INVIS
4170
4171 /* Pick a prefix */
4172 if (*s2 && (feat >= FEAT_DOOR_HEAD)) s2 = "in ";
4173
4174 /* Hack -- handle wilderness features */
4175 if (*s2 && (
4176 (feat == FEAT_DRAWBRIDGE) ||
4177 (feat == FEAT_LOGS) ||
4178 (feat == FEAT_MUD) ||
4179 (feat == FEAT_CROP) ||
4180 (feat >= FEAT_CROP_HEAD && feat <= FEAT_CROP_TAIL)
4181 )) s2 = "on ";
4182
4183 /* Pick proper indefinite article */
4184 s3 = (is_a_vowel(name[0])) ? "an " : "a ";
4185
4186 /* Hack -- some features need no article */
4187 if ((
4188 (feat == FEAT_GRASS) ||
4189 (feat == FEAT_WATER) ||
4190 (feat == FEAT_DIRT) ||
4191 (feat == FEAT_LOOSE_DIRT) ||
4192 (feat == FEAT_CROP) ||
4193 (feat >= FEAT_CROP_HEAD && feat <= FEAT_CROP_TAIL)
4194 )) s3 = "";
4195
4196 /* Hack -- special introduction for store doors */
4197 if ((feat >= FEAT_SHOP_HEAD) && (feat <= FEAT_SHOP_TAIL))
4198 {
4199 s3 = "the entrance to the ";
4200 }
4201
4202 /* Hack -- player houses and shops */
4203 if ((feat >= FEAT_HOME_HEAD) && (feat <= FEAT_HOME_TAIL))
4204 {
4205 if ((h = pick_house(Depth, y, x)) != -1)
4206 {
4207 if (!STRZERO(houses[h].owned))
4208 {
4209 char h_name[80];
4210 s3 = "the entrance to ";
4211 if (!strcmp(houses[h].owned, p_ptr->name))
4212 strcpy(x_name, "Your ");
4213 else
4214 strnfmt(x_name, sizeof(x_name), "%s's ", houses[h].owned);
4215 if (!houses[h].strength)
4216 strcat(x_name, "Home");
4217 else
4218 {
4219 get_player_store_name(h, h_name); //"Store"
4220 strcat(x_name, h_name);
4221 }
4222 name = x_name;
4223 }
4224 else
4225 {
4226 s3 = "a door to ";
4227 name = "foreign house";
4228 }
4229 }
4230 }
4231 }
4232
4233 /* Hack -- Force Recall */
4234 if (force_recall)
4235 {
4236 if (p_ptr->stream_hgt[STREAM_MONSTER_TEXT])
4237 {
4238 out_win = NTERM_WIN_MONSTER;
4239 }
4240 else
4241 {
4242 out_win = NTERM_WIN_SPECIAL;
4243 }
4244 }
4245
4246 /* Prepare the message */
4247 strnfmt(out_val, sizeof(out_val),
4248 "%s%s%s%s [%s%s]", s1, s2, s3, name, i1, info);
4249 if (is_dm_p(p_ptr))
4250 my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val));
4251 /* Hack -- capitalize */
4252 if (islower(out_val[0])) out_val[0] = toupper(out_val[0]);
4253
4254 /* Tell the client */
4255 send_target_info(p_ptr, x - p_ptr->panel_col_prt, y - p_ptr->panel_row_prt, out_win, out_val);
4256
4257 /* Done */
4258 return;
4259 }
4260
4261 /*
4262 * Given a "source" and "target" location, extract a "direction",
4263 * which will move one step from the "source" towards the "target".
4264 *
4265 * Note that we use "diagonal" motion whenever possible.
4266 *
4267 * We return "5" if no motion is needed.
4268 */
motion_dir(int y1,int x1,int y2,int x2)4269 int motion_dir(int y1, int x1, int y2, int x2)
4270 {
4271 /* No movement required */
4272 if ((y1 == y2) && (x1 == x2)) return (5);
4273
4274 /* South or North */
4275 if (x1 == x2) return ((y1 < y2) ? 2 : 8);
4276
4277 /* East or West */
4278 if (y1 == y2) return ((x1 < x2) ? 6 : 4);
4279
4280 /* South-east or South-west */
4281 if (y1 < y2) return ((x1 < x2) ? 3 : 1);
4282
4283 /* North-east or North-west */
4284 if (y1 > y2) return ((x1 < x2) ? 9 : 7);
4285
4286 /* Paranoia */
4287 return (5);
4288 }
4289
4290
4291
4292 /*
4293 * Extract a direction (or zero) from a character
4294 */
target_dir(char ch)4295 int target_dir(char ch)
4296 {
4297 int d = 0;
4298
4299 /* Already a direction? */
4300 if (isdigit((unsigned char)ch))
4301 {
4302 d = D2I(ch);
4303 }
4304 else
4305 {
4306
4307 }
4308
4309 /* Paranoia */
4310 if (d == 5) d = 0;
4311
4312 /* Return direction */
4313 return (d);
4314 }
4315
4316
4317
4318 /*
4319 * Handle "target" and "look".
4320 *
4321 * Currently, when "flag" is true, that is, when
4322 * "interesting" grids are being used, and a directional key is used, we
4323 * only scroll by a single panel, in the direction requested, and check
4324 * for any interesting grids on that panel. The "correct" solution would
4325 * actually involve scanning a larger set of grids, including ones in
4326 * panels which are adjacent to the one currently scanned, but this is
4327 * overkill for this function. XXX XXX
4328 *
4329 * Hack -- targetting/observing an "outer border grid" may induce
4330 * problems, so this is not currently allowed.
4331 *
4332 * The player can use the direction keys to move among "interesting"
4333 * grids in a heuristic manner, or the "space", "+", and "-" keys to
4334 * move through the "interesting" grids in a sequential manner, or
4335 * can enter "location" mode, and use the direction keys to move one
4336 * grid at a time in any direction. The "t" (set target) command will
4337 * only target a monster (as opposed to a location) if the monster is
4338 * target_able and the "interesting" mode is being used.
4339 *
4340 * The current grid is described using the "look" method above, and
4341 * a new command may be entered at any time, but note that if the
4342 * "TARGET_LOOK" bit flag is set (or if we are in "location" mode,
4343 * where "space" has no obvious meaning) then "space" will scan
4344 * through the description of the current grid until done, instead
4345 * of immediately jumping to the next "interesting" grid. This
4346 * allows the "target" command to retain its old semantics.
4347 *
4348 * The "*", "+", and "-" keys may always be used to jump immediately
4349 * to the next (or previous) interesting grid, in the proper mode.
4350 *
4351 * The "return" key may always be used to scan through a complete
4352 * grid description (forever).
4353 *
4354 * This command will cancel any old target, even if used from
4355 * inside the "look" command.
4356 */
target_set_interactive(player_type * p_ptr,int mode,char query)4357 bool target_set_interactive(player_type *p_ptr, int mode, char query)
4358 {
4359 int py = p_ptr->py;
4360 int px = p_ptr->px;
4361
4362 int i, d, bd, Depth;
4363
4364 int y = py;
4365 int x = px;
4366
4367 bool done = FALSE;
4368 bool prompt_arb = FALSE; /* Display info about arbitary grid */
4369 bool prompt_int = FALSE; /* Display info about interesting grid */
4370
4371 char info[80];
4372 int old_target = 0;
4373 int old_target_x = -1;
4374 int old_target_y = -1;
4375
4376 /* Hack -- remember "Old Target" */
4377 if (!(mode & TARGET_LOOK) && option_p(p_ptr,USE_OLD_TARGET) && p_ptr->target_set)
4378 {
4379 if (p_ptr->target_who)
4380 {
4381 old_target = p_ptr->target_who;
4382 }
4383 else
4384 {
4385 old_target_x = p_ptr->target_col;
4386 old_target_y = p_ptr->target_row;
4387 }
4388 }
4389
4390 /* Cancel target */
4391 target_set_monster(p_ptr, 0);
4392
4393
4394 /* Cancel tracking */
4395 /* health_track(p_ptr, 0); */
4396 cursor_track(p_ptr, 0);
4397
4398 /* Start near the player */
4399 if (query == '\0')
4400 {
4401 p_ptr->target_flag &= ~TARGET_GRID;
4402 p_ptr->look_index = 0;
4403 p_ptr->look_y = py;
4404 p_ptr->look_x = px;
4405 }
4406
4407 /* Prepare the "temp" array */
4408 target_set_interactive_prepare(p_ptr, mode);
4409
4410 /* Hack -- restore "Old Target" if it's still ok */
4411 if (!(p_ptr->target_flag & TARGET_GRID) && old_target && p_ptr->target_n)
4412 {
4413 Depth = p_ptr->dun_depth;
4414 for (i = 0; i < p_ptr->target_n; i++)
4415 {
4416 y = p_ptr->target_y[i];
4417 x = p_ptr->target_x[i];
4418 if ((cave[Depth][y][x].m_idx == old_target) && target_able(p_ptr, cave[Depth][y][x].m_idx))
4419 {
4420 p_ptr->look_index = i;
4421 break;
4422 }
4423 }
4424 }
4425
4426 /* No usable targets, but we had a previous grid target */
4427 if (!(p_ptr->target_flag & TARGET_GRID) && !p_ptr->target_n
4428 && old_target_x > -1 && old_target_y > -1 && query == '\0')
4429 {
4430 /* Switch to manual targeting */
4431 p_ptr->target_flag |= TARGET_GRID;
4432 p_ptr->look_x = old_target_x;
4433 p_ptr->look_y = old_target_y;
4434 }
4435 else
4436
4437 /* No targets */
4438 if (!(p_ptr->target_flag & TARGET_GRID) && !p_ptr->target_n)
4439 {
4440 #ifdef NOTARGET_PROMPT
4441 if (!(query == ESCAPE || query == 'q'))
4442 send_target_info(p_ptr, p_ptr->px - p_ptr->panel_col_prt, p_ptr->py - p_ptr->panel_row_prt,
4443 NTERM_WIN_NONE, "Nothing to target. [p, ESC]");
4444 if (query != 'p')
4445 return FALSE;
4446 #else
4447 /* "Emulate Angband" Hack -- switch to manual targeting */
4448 query = 'p';
4449 #endif
4450 }
4451
4452 /* Toggle recall (and cancel further query tests) */
4453 if (p_ptr->target_flag & TARGET_READ)
4454 {
4455 if ((query == '\n') || (query == '\r') ||
4456 (query == ' ' && (mode & TARGET_LOOK)))
4457 {
4458 p_ptr->target_flag &= ~TARGET_READ;
4459 query = '\0';
4460 }
4461 }
4462 else if (query == 'r')
4463 {
4464 p_ptr->target_flag |= TARGET_READ;
4465 query = '\0';
4466 }
4467
4468
4469 /* Interesting grids */
4470 if (!(p_ptr->target_flag & TARGET_GRID))// && p_ptr->target_n)
4471 {
4472 /* By default we DO prompt */
4473 prompt_int = TRUE;
4474
4475 /* Assume no "direction" */
4476 d = 0;
4477
4478 /* Shortcuts: */
4479 y = p_ptr->target_y[p_ptr->look_index];
4480 x = p_ptr->target_x[p_ptr->look_index];
4481
4482 /* DM Hook! */
4483 master_new_hook(p_ptr, query, y, x);
4484
4485 /* Analyze */
4486 switch (query)
4487 {
4488 case '\0':
4489 break;
4490 case ESCAPE:
4491 case 'q':
4492 {
4493 prompt_int = FALSE;
4494 done = TRUE;
4495 break;
4496 }
4497
4498 case ' ':
4499 case '(':
4500 case '*':
4501 case '+':
4502 {
4503 if (++p_ptr->look_index == p_ptr->target_n)
4504 {
4505 p_ptr->look_index = 0;
4506 if (!option_p(p_ptr,EXPAND_LOOK)) done = TRUE;
4507 }
4508 break;
4509 }
4510
4511 case '-':
4512 {
4513 if (p_ptr->look_index-- == 0)
4514 {
4515 p_ptr->look_index = p_ptr->target_n - 1;
4516 if (!option_p(p_ptr,EXPAND_LOOK)) done = TRUE;
4517 }
4518 break;
4519 }
4520
4521 case 'p':
4522 {
4523 /* Recenter around player */
4524 verify_panel(p_ptr);
4525
4526 /* Handle stuff */
4527 handle_stuff(p_ptr);
4528
4529 y = py;
4530 x = px;
4531 }
4532 /* fallthrough */
4533 case 'o':
4534 {
4535 p_ptr->look_y = y;
4536 p_ptr->look_x = x;
4537
4538 p_ptr->target_flag |= TARGET_GRID;
4539 prompt_arb = TRUE;
4540 prompt_int = FALSE;
4541 break;
4542 }
4543
4544 case 'm':
4545 {
4546 break;
4547 }
4548
4549 case 't':
4550 case '5':
4551 case '0':
4552 case '.':
4553 {
4554 int Depth = p_ptr->dun_depth;
4555 int m_idx = cave[Depth][y][x].m_idx;
4556
4557 if ((m_idx != 0) && target_able(p_ptr, m_idx))
4558 {
4559 health_track(p_ptr, m_idx);
4560 target_set_monster(p_ptr, m_idx);
4561 }
4562 else
4563 {
4564 done = TRUE;
4565 }
4566 done = TRUE;
4567 break;
4568 }
4569
4570 case 'g':
4571 {
4572 do_cmd_pathfind(p_ptr, y, x);
4573 done = TRUE;
4574 break;
4575 }
4576
4577 default:
4578 {
4579 /* Extract direction */
4580 d = target_dir(query);
4581
4582 /* Oops */
4583 //if (!d) bell("Illegal command for target mode!");
4584
4585 break;
4586 }
4587 }
4588
4589 /* Hack -- move around */
4590 if (d)
4591 {
4592 y = p_ptr->target_y[p_ptr->look_index];
4593 x = p_ptr->target_x[p_ptr->look_index];
4594
4595 /* Find a new interesting grid" */
4596 i = target_pick(p_ptr, y, x, ddy[d], ddx[d]);
4597
4598 /* Use interesting grid if found */
4599 if (i >= 0) p_ptr->look_index = i;
4600 }
4601 }
4602
4603 /* Arbitrary grids */
4604 else
4605 {
4606 /* Assume prompt is needed */
4607 prompt_arb = TRUE;
4608
4609 /* Assume no direction */
4610 d = 0;
4611
4612 /* DM Hook! */
4613 master_new_hook(p_ptr, query, p_ptr->look_y, p_ptr->look_x);
4614
4615 /* Analyze the keypress */
4616 switch (query)
4617 {
4618 case '\0':
4619 break;
4620 case ESCAPE:
4621 case 'q':
4622 {
4623 done = TRUE;
4624 break;
4625 }
4626
4627 case ' ':
4628 case '(':
4629 case '*':
4630 case '+':
4631 case '-':
4632 {
4633 break;
4634 }
4635
4636 case 'p':
4637 {
4638 /* Recenter around player */
4639 verify_panel(p_ptr);
4640
4641 /* Handle stuff */
4642 handle_stuff(p_ptr);
4643
4644 p_ptr->look_y = py;
4645 p_ptr->look_x = px;
4646 }
4647
4648 case 'o':
4649 {
4650 break;
4651 }
4652
4653 case 'm':
4654 {
4655 p_ptr->target_flag &= ~TARGET_GRID;
4656
4657 bd = target_set_index(p_ptr, p_ptr->look_y, p_ptr->look_x);
4658
4659 /* Nothing interesting */
4660 if (bd == 999) p_ptr->target_flag |= TARGET_GRID;
4661 else
4662 {
4663 prompt_int = TRUE;
4664 prompt_arb = FALSE;
4665 }
4666
4667 break;
4668 }
4669
4670 case 't':
4671 case '5':
4672 case '0':
4673 case '.':
4674 {
4675 target_set_location(p_ptr, p_ptr->look_y, p_ptr->look_x);
4676 done = TRUE;
4677 break;
4678 }
4679
4680 case 'g':
4681 {
4682 do_cmd_pathfind(p_ptr, p_ptr->look_y, p_ptr->look_x);
4683 done = TRUE;
4684 break;
4685 }
4686
4687 default:
4688 {
4689 /* Extract a direction */
4690 d = target_dir(query);
4691
4692 /* Oops */
4693 //if (!d) bell("Illegal command for target mode!");
4694
4695 break;
4696 }
4697 }
4698
4699 /* Handle "direction" */
4700 if (d)
4701 {
4702 int dungeon_hgt = MAX_HGT;
4703 int dungeon_wid = MAX_WID;
4704
4705 /* Move */
4706 p_ptr->look_x += ddx[d];
4707 p_ptr->look_y += ddy[d];
4708
4709 /* Slide into legality */
4710 if (p_ptr->look_x >= dungeon_wid - 1) p_ptr->look_x--;
4711 else if (p_ptr->look_x <= 0) p_ptr->look_x++;
4712
4713 /* Slide into legality */
4714 if (p_ptr->look_y >= dungeon_hgt - 1) p_ptr->look_y--;
4715 else if (p_ptr->look_y <= 0) p_ptr->look_y++;
4716
4717 /* Adjust panel if needed */
4718 if (adjust_panel(p_ptr, p_ptr->look_y, p_ptr->look_x))
4719 {
4720 /* Handle stuff */
4721 handle_stuff(p_ptr);
4722
4723 /* Recalculate interesting grids */
4724 target_set_interactive_prepare(p_ptr, mode);
4725 }
4726 }
4727 }
4728
4729 if (prompt_int)
4730 {
4731 y = p_ptr->target_y[p_ptr->look_index];
4732 x = p_ptr->target_x[p_ptr->look_index];
4733 Depth = p_ptr->dun_depth;
4734
4735 /* Allow target */
4736 if ((cave[Depth][y][x].m_idx != 0) && target_able(p_ptr, cave[Depth][y][x].m_idx))
4737 {
4738 strcpy(info, "q,t,p,o,+,-,<dir>");
4739 }
4740
4741 /* Dis-allow target */
4742 else
4743 {
4744 strcpy(info, "q,p,o,+,-,<dir>");
4745 }
4746
4747 /* Adjust panel if needed */
4748 if (adjust_panel(p_ptr, y, x))
4749 {
4750 /* Handle stuff */
4751 handle_stuff(p_ptr);
4752 }
4753 }
4754
4755 if (prompt_arb)
4756 {
4757 y = p_ptr->look_y;
4758 x = p_ptr->look_x;
4759
4760 /* Default prompt */
4761 strcpy(info, "q,t,p,m,+,-,<dir>");
4762 }
4763
4764 if (prompt_arb || prompt_int)
4765 {
4766 /* Describe and Prompt */
4767 target_set_interactive_aux(p_ptr, y, x, mode, info);
4768
4769 /* Cancel tracking */
4770 /* health_track(0); */
4771 }
4772
4773 if (done)
4774 {
4775 /* Forget list of targets */
4776 p_ptr->target_n = 0;
4777
4778 /* Clear the top line */
4779 // prt("", 0, 0);
4780
4781 /* Recenter around player */
4782 verify_panel(p_ptr);
4783
4784 /* Handle stuff */
4785 handle_stuff(p_ptr);
4786 }
4787
4788 /* Failure to set target */
4789 if (!p_ptr->target_set) return (FALSE);
4790
4791 /* Success */
4792 return (TRUE);
4793 }
4794
4795
4796 /*
4797 * This function will try to guess an appropriate action for
4798 * "target_set_interactive", pick a fake keypress and, call it.
4799 *
4800 * For example, if we need to set target, the 't' keypress will
4801 * be fed into the targeting code, as if the user pressed 't'.
4802 *
4803 * For "hovering mouse" effect, we use keys 'm' and 'o', which
4804 * do (mostly) nothing.
4805
4806 * "mod" should contain MCURSOR_XXX bitflags, with the following meanings:
4807 * (MCURSOR_META) -- when set, it means the 0x0F bits of the "mod"
4808 * specify "look_mode" (one of NTARGET_XXX defines)
4809 * (MCURSOR_xMB) -- unused, per above.
4810 * (MCURSOR_KTRL) -- player want to accept the target.
4811 */
target_set_interactive_mouse(player_type * p_ptr,int mod,int y,int x)4812 bool target_set_interactive_mouse(player_type *p_ptr, int mod, int y, int x)
4813 {
4814 bool accept = (mod & MCURSOR_KTRL) ? TRUE : FALSE;
4815 int look_mode = (mod & 0x0F);
4816 char key = '\xff';
4817
4818 /* Adjust coordinates */
4819 x = x + p_ptr->panel_col_min;
4820 y = y + p_ptr->panel_row_min;
4821
4822 /* Clip to panel bounds */
4823 if (x < p_ptr->panel_col_min) x = p_ptr->panel_col_min;
4824 if (y < p_ptr->panel_row_min) y = p_ptr->panel_row_min;
4825 if (x > p_ptr->panel_col_max) x = p_ptr->panel_col_max;
4826 if (y > p_ptr->panel_row_max) y = p_ptr->panel_row_max;
4827
4828 /* Player is in "arbitrary grids" mode */
4829 if ((p_ptr->target_flag & TARGET_GRID))
4830 {
4831 /* Set new values */
4832 p_ptr->look_x = x;
4833 p_ptr->look_y = y;
4834
4835 key = 'o';
4836
4837 if (accept)
4838 {
4839 key = 't';
4840 }
4841 }
4842 /* Player is in "interesting grids" mode */
4843 else
4844 {
4845 int i;
4846 int found_index = -1;
4847 int last_dist = -1;
4848 /* Hack -- populate target_*[] arrays so we can iterate */
4849 target_set_interactive(p_ptr, look_mode, 'm');
4850 for (i = 0; i < p_ptr->target_n; i++)
4851 {
4852 int oy = p_ptr->target_y[i];
4853 int ox = p_ptr->target_x[i];
4854 int dist = distance(y, x, oy, ox);
4855 if (dist < last_dist || last_dist == -1)
4856 {
4857 found_index = i;
4858 last_dist = dist;
4859 }
4860 }
4861 /* If nothing was found, do nothing */
4862 if (found_index == -1) return FALSE;
4863
4864 /* Set new value */
4865 p_ptr->look_index = found_index;
4866
4867 key = 'm';
4868
4869 if (accept)
4870 {
4871 key = 't';
4872 }
4873 }
4874
4875 /* We now have a proper look mode and a fake key */
4876 /* Lets feed our interactive targeter */
4877 return target_set_interactive(p_ptr, look_mode, key);
4878 }
4879
4880
4881 /*
4882 * Get an "aiming direction" from the user.
4883 *
4884 * The "dir" is loaded with 1,2,3,4,6,7,8,9 for "actual direction", and
4885 * "5" for "current target", and "0" for "entry aborted".
4886 *
4887 * Note that confusion over-rides any (explicit?) user choice.
4888 *
4889 * We just ask the client to send us a direction, unless we are confused --KLJ--
4890 */
get_aim_dir(player_type * p_ptr,int * dp)4891 bool get_aim_dir(player_type *p_ptr, int *dp)
4892 {
4893 int dir = 0;
4894
4895 /* Global direction */
4896 dir = p_ptr->command_dir;
4897 p_ptr->command_dir = 0;
4898
4899 /* Hack -- auto-target if requested */
4900 if (option_p(p_ptr,USE_OLD_TARGET)
4901 && dir == 5 && !target_okay(p_ptr)) dir = 0;
4902
4903 /* No direction -- Ask */
4904 if (!dir)
4905 {
4906 /* Ask player */
4907 Send_direction(Ind);
4908
4909 /* Cancel aiming */
4910 return (FALSE);
4911 }
4912
4913 /* Check for confusion */
4914 if (p_ptr->confused)
4915 {
4916 /* Random direction */
4917 dir = ddd[randint0(8)];
4918 }
4919
4920 /* Save direction */
4921 (*dp) = dir;
4922
4923 return (TRUE);
4924 }
4925
4926
get_item(player_type * p_ptr,int * cp,byte tval_hook)4927 bool get_item(player_type *p_ptr, int *cp, byte tval_hook)
4928 {
4929 int item = 0;
4930
4931 /* Ready */
4932 item = p_ptr->command_arg;
4933 p_ptr->command_arg = -2;
4934
4935 /* No item -- Ask */
4936 if (item == -2)
4937 {
4938 /* Ask player */
4939 Send_item_request(p_ptr, tval_hook);
4940
4941 /* Cancel selection (for now) */
4942 return (FALSE);
4943 }
4944
4945 /* Save item */
4946 (*cp) = item;
4947
4948 return (TRUE);
4949 }
4950
4951
4952 /*
4953 * Request a "movement" direction (1,2,3,4,6,7,8,9) from the user,
4954 * and place it into "command_dir", unless we already have one.
4955 *
4956 * This function should be used for all "repeatable" commands, such as
4957 * run, walk, open, close, bash, disarm, spike, tunnel, etc.
4958 *
4959 * This function tracks and uses the "global direction", and uses
4960 * that as the "desired direction", to which "confusion" is applied.
4961 */
4962 #if 0
4963 bool get_rep_dir(int *dp)
4964 {
4965 int dir;
4966
4967
4968 /* Global direction */
4969 dir = command_dir;
4970
4971 /* Get a direction */
4972 while (!dir)
4973 {
4974 char ch;
4975
4976 /* Get a command (or Cancel) */
4977 if (!get_com("Direction (Escape to cancel)? ", &ch)) break;
4978
4979 /* Look up the direction */
4980 dir = keymap_dirs[ch & 0x7F];
4981
4982 /* Oops */
4983 if (!dir) bell();
4984 }
4985
4986 /* Keep the given direction */
4987 *dp = dir;
4988
4989 /* Aborted */
4990 if (!dir) return (FALSE);
4991
4992 /* Save the direction */
4993 command_dir = dir;
4994
4995 /* Apply "confusion" */
4996 if (p_ptr->confused)
4997 {
4998 /* Warn the user XXX XXX XXX */
4999 /* msg_print("You are confused."); */
5000
5001 /* Standard confusion */
5002 if (randint0(100) < 75)
5003 {
5004 /* Random direction */
5005 *dp = ddd[randint0(8)];
5006 }
5007 }
5008
5009 /* A "valid" direction was entered */
5010 return (TRUE);
5011 }
5012 #endif
5013
5014 /*
5015 * Apply confusion, if needed, to a direction
5016 *
5017 * Display a message and return TRUE if direction changes.
5018 */
confuse_dir(bool confused,int * dp)5019 bool confuse_dir(bool confused, int *dp)
5020 {
5021 int dir;
5022
5023 /* Default */
5024 dir = (*dp);
5025
5026 /* Apply "confusion" */
5027 if (confused)
5028 {
5029 /* Apply confusion XXX XXX XXX */
5030 if ((dir == 5) || (randint0(100) < 75))
5031 {
5032 /* Random direction */
5033 dir = ddd[randint0(8)];
5034 }
5035 }
5036
5037 /* Notice confusion */
5038 if ((*dp) != dir)
5039 {
5040 /* Warn the user */
5041 /* msg_print("You are confused."); */
5042
5043 /* Save direction */
5044 (*dp) = dir;
5045
5046 /* Confused */
5047 return (TRUE);
5048 }
5049
5050 /* Not confused */
5051 return (FALSE);
5052 }
5053
5054 /* this has finally earned its own function, to make it easy for restoration to do this also */
5055
do_scroll_life(player_type * p_ptr)5056 bool do_scroll_life(player_type *p_ptr)
5057 {
5058 int x, y;
5059 for (y = -1; y <= 1; y++)
5060 {
5061 for (x = -1; x <= 1; x++)
5062 {
5063 player_type *q_ptr = player_on_cave(p_ptr->dun_depth, p_ptr->py + y, p_ptr->px + x);
5064
5065 if (q_ptr && (cave_floor_bold(p_ptr->dun_depth, p_ptr->py + y, p_ptr->px + x)))
5066 {
5067 if (q_ptr->ghost)
5068 {
5069 resurrect_player(q_ptr);
5070 return TRUE;
5071 }
5072 }
5073 }
5074 }
5075 /* we did nore ressurect anyone */
5076 return FALSE;
5077 }
5078
5079
5080 /* modified above function to instead restore XP... used in priest spell rememberence */
do_restoreXP_other(player_type * p_ptr)5081 bool do_restoreXP_other(player_type *p_ptr)
5082 {
5083 int x, y;
5084 for (y = -1; y <= 1; y++)
5085 {
5086 for (x = -1; x <= 1; x++)
5087 {
5088 player_type *q_ptr = player_on_cave(p_ptr->dun_depth, p_ptr->py + y, p_ptr->px + x);
5089 if (q_ptr)
5090 {
5091 if (q_ptr->exp < q_ptr->max_exp)
5092 {
5093 restore_level(q_ptr);
5094 return TRUE;
5095 }
5096 }
5097 }
5098 }
5099 /* we did nore ressurect anyone */
5100 return FALSE;
5101 }
5102
5103
5104 /* Hack -- since the framerate has been boosted by five times since version
5105 * 0.6.0 to make game movement more smooth, we return the old level speed
5106 * times five to keep the same movement rate.
5107 */
5108
level_speed(int Depth)5109 u32b level_speed(int Depth)
5110 {
5111 if (Depth <= 0) return level_speeds[0]*5;
5112 else return level_speeds[Depth]*5;
5113 }
5114
5115 /* Hack -- return TRUE if there are monsters in LoS, FALSE otherwise. */
monsters_in_los(player_type * p_ptr)5116 bool monsters_in_los(player_type *p_ptr)
5117 {
5118 int i;
5119 bool los;
5120 /* If nothing in LoS */
5121 los = FALSE;
5122 for (i = 1; i < m_max; i++)
5123 {
5124 /* Check this monster */
5125 if ((p_ptr->mon_los[i] && !m_list[i].csleep))
5126 {
5127 los = TRUE;
5128 break;
5129 }
5130 }
5131 /* Hostile players count as monsters */
5132 if (!los) for (i = 1; i <= NumPlayers; i++)
5133 {
5134 player_type *q_ptr = Players[i];
5135 if (same_player(q_ptr, p_ptr)) continue; /* Skip self */
5136
5137 if (p_ptr->conn <= -1) break; /* Can't check hostility */
5138
5139 /* Check this player */
5140 if ((p_ptr->play_los[i]) && !q_ptr->paralyzed)
5141 {
5142 if (check_hostile(p_ptr, q_ptr))
5143 {
5144 los = TRUE;
5145 break;
5146 }
5147 }
5148 }
5149 return los;
5150 }
5151
5152 /* Determine the speed of a given players "time bubble" and return a percentage
5153 * scaling factor which should be applied to any amount of energy granted to
5154 * players/monsters within the bubble.
5155 *
5156 * We check this player and then any other players recursively, the time of the
5157 * slowest bubble below normal time overrules other adjoining bubbles. This is
5158 * to support the senario where a long chain of players may be stood just within
5159 * each others range. Forming a time bubble chain. :)
5160 *
5161 * When calling this function pass slowest as zero, which acts as a flag
5162 * that this is the main call, not a recursive call.
5163 */
base_time_factor(player_type * p_ptr,int slowest)5164 int base_time_factor(player_type *p_ptr, int slowest)
5165 {
5166 player_type * q_ptr;
5167 int i, dist, health, timefactor;
5168 bool los;
5169
5170 /* If this is the initial call, reset all players time bubble check */
5171 if(!slowest)
5172 {
5173 for (i = 1; i <= NumPlayers; i++)
5174 {
5175 q_ptr = Players[i];
5176 if(q_ptr) q_ptr->bubble_checked = FALSE;
5177 }
5178 }
5179
5180 /* Normal time scale */
5181 timefactor = NORMAL_TIME;
5182
5183 /* What's our percentage health? */
5184 health = (p_ptr->chp * 100) / p_ptr->mhp;
5185
5186 /* Don't allow time to slow asymptotically towards infinity */
5187 if(health < MIN_TIME_SCALE) health = MIN_TIME_SCALE;
5188
5189 /* Scale depending on health if HP are low enough */
5190 if(health <= p_ptr->hitpoint_warn * 10)
5191 #ifdef CONSTANT_TIME_FACTOR
5192 timefactor = timefactor / CONSTANT_TIME_FACTOR;
5193 #else
5194 timefactor = timefactor * ((float)health / 100);
5195 #endif
5196
5197 /* If nothing in LoS */
5198 los = monsters_in_los(p_ptr);
5199
5200 /* Hack -- prevent too much manual slowdown */
5201 if (p_ptr->hitpoint_warn > 9 && !los) timefactor = NORMAL_TIME;
5202
5203 /* Resting speeds up time disregarding health time scaling */
5204 if (p_ptr->resting && !los) timefactor = MAX_TIME_SCALE;
5205
5206 /* Running speeds up time */
5207 if (p_ptr->running && !los) timefactor = RUNNING_FACTOR;
5208
5209
5210 /* If this is a check for another player give way to their time
5211 * bubble if we aren't doing anything important */
5212 if(slowest && (timefactor == NORMAL_TIME))
5213 {
5214 if(!los)
5215 {
5216 /* We don't really care about our time */
5217 timefactor = MAX_TIME_SCALE;
5218 }
5219 }
5220
5221 /* We have checked our time bubble */
5222 p_ptr->bubble_checked = TRUE;
5223
5224 /* Check all other players within our range */
5225 for (i = 1; i <= NumPlayers; i++)
5226 {
5227 q_ptr = Players[i];
5228 /* Only check them if they haven't already been checked */
5229 if(q_ptr && (!q_ptr->bubble_checked))
5230 {
5231 /* Skip him if he's on a different dungeon level */
5232 if (q_ptr->dun_depth != p_ptr->dun_depth) continue;
5233
5234 /* How far away is he? */
5235 dist = distance(p_ptr->py, p_ptr->px, q_ptr->py, q_ptr->px);
5236
5237 /* Skip him if he's too far away */
5238 if(dist > MAX_SIGHT) continue;
5239
5240 /* Find the slowest time bubble chain we are part of */
5241 slowest = base_time_factor(q_ptr, timefactor);
5242
5243 /* Use the slowest time bubble */
5244 if(slowest < timefactor) timefactor = slowest;
5245 }
5246 }
5247
5248 return timefactor;
5249 }
5250
5251 /*
5252 * Determine the given players current time factor.
5253 */
time_factor(player_type * p_ptr)5254 int time_factor(player_type *p_ptr)
5255 {
5256 int timefactor, scale;
5257
5258 /* Normal time scale, 100% */
5259 scale = NORMAL_TIME;
5260
5261 /* Forget all about time scaling in town */
5262 if(!p_ptr->dun_depth) return scale;
5263
5264
5265 /* Determine our time scaling factor */
5266 timefactor = base_time_factor(p_ptr, 0);
5267
5268 /* Scale our time by our bubbles time factor */
5269 scale = scale * ((float)timefactor / 100);
5270
5271 return scale;
5272 }
5273
5274 /* MOTD, Summary, TOMBSTONE utils */
show_motd(player_type * p_ptr)5275 void show_motd(player_type *p_ptr)
5276 {
5277 int i, k;
5278 byte old_term;
5279
5280 /* Copy to info buffer */
5281 for (i = 0; i < 24; i++)
5282 {
5283 for (k = 0; k < 80; k++)
5284 {
5285 p_ptr->info[i][k].a = TERM_WHITE;
5286 p_ptr->info[i][k].c = text_screen[0][i * 80 + k];
5287 }
5288 }
5289
5290 /* Save last dumped line */
5291 p_ptr->last_info_line = i;
5292
5293 /* Save 'current' terminal */
5294 old_term = p_ptr->remote_term;
5295
5296 /* Activte new terminal */
5297 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_SPECIAL);
5298
5299 /* Clear, send */
5300 send_term_info(p_ptr, NTERM_CLEAR, 0);
5301 for (i = 0; i < p_ptr->last_info_line + 1; i++)
5302 Stream_line_p(p_ptr, STREAM_SPECIAL_TEXT, i);
5303
5304 /* Pause and flush */
5305 send_term_info(p_ptr, NTERM_HOLD, NTERM_PAUSE);
5306 send_term_info(p_ptr, NTERM_FLUSH | NTERM_FRESH | NTERM_ICKY, 0);
5307
5308 /* Restore active term */
5309 send_term_info(p_ptr, NTERM_ACTIVATE, old_term);
5310 }
5311
5312 /*
5313 * Centers a string within a 31 character string
5314 */
center_string(char * buf,size_t len,cptr str)5315 static void center_string(char *buf, size_t len, cptr str)
5316 {
5317 int i, j;
5318
5319 /* Total length */
5320 i = strlen(str);
5321
5322 /* Necessary border */
5323 j = 15 - i / 2;
5324
5325 /* Mega-Hack */
5326 strnfmt(buf, len, "%*s%s%*s", j, "", str, 31 - i - j, "");
5327 }
5328 /*
5329 * Display a "tomb-stone"
5330 * this is a verbatim port of "print_tomb" from V309
5331 * //TODO: remove // comments and actually implement those things
5332 */
print_tomb(player_type * p_ptr)5333 static void print_tomb(player_type *p_ptr)
5334 {
5335 int i, k;
5336 cptr p;
5337 char tmp[160];
5338 char buf[1024];
5339
5340 /* Copy to info buffer */
5341 for (i = 0; i < 20; i++)
5342 {
5343 for (k = 0; k < 80; k++)
5344 {
5345 p_ptr->info[i][k].a = TERM_WHITE;
5346 p_ptr->info[i][k].c = text_screen[1][i * 80 + k];
5347 //printf("%c", p_ptr->info[i][k].c);
5348 }
5349 //printf("\n");
5350 }
5351
5352 /* Save last dumped line */
5353 p_ptr->last_info_line = i - 1;
5354
5355 /* King or Queen */
5356 if (p_ptr->total_winner || (p_ptr->lev > PY_MAX_LEVEL))
5357 {
5358 p = "Magnificent";
5359 }
5360
5361 /* Normal */
5362 else
5363 {
5364 p = c_text + p_ptr->cp_ptr->title[(p_ptr->lev - 1) / 5];
5365 }
5366
5367 center_string(buf, sizeof(buf), p_ptr->name);
5368 prt(p_ptr, buf, 6, 11);
5369
5370 center_string(buf, sizeof(buf), "the");
5371 prt(p_ptr, buf, 7, 11);
5372
5373 center_string(buf, sizeof(buf), p);
5374 prt(p_ptr, buf, 8, 11);
5375
5376
5377 center_string(buf, sizeof(buf), c_name + c_info[p_ptr->pclass].name);
5378 prt(p_ptr, buf, 10, 11);
5379
5380 strnfmt(tmp, sizeof(tmp), "Level: %d", (int)p_ptr->lev);
5381 center_string(buf, sizeof(buf), tmp);
5382 prt(p_ptr, buf, 11, 11);
5383
5384 strnfmt(tmp, sizeof(tmp), "Exp: %ld", (long)p_ptr->exp);
5385 center_string(buf, sizeof(buf), tmp);
5386 prt(p_ptr, buf, 12, 11);
5387
5388 strnfmt(tmp, sizeof(tmp), "AU: %ld", (long)p_ptr->au);
5389 center_string(buf, sizeof(buf), tmp);
5390 prt(p_ptr, buf, 13, 11);
5391
5392 strnfmt(tmp, sizeof(tmp), "Killed on Level %d", p_ptr->dun_depth);
5393 center_string(buf, sizeof(buf), tmp);
5394 prt(p_ptr, buf, 14, 11);
5395
5396 strnfmt(tmp, sizeof(tmp), "by %s.", p_ptr->died_from);
5397 center_string(buf, sizeof(buf), tmp);
5398 prt(p_ptr, buf, 15, 11);
5399
5400
5401 //strnfmt(tmp, sizeof(tmp), "%-.24s", ctime(&death_time));
5402 //center_string(buf, sizeof(buf), tmp);
5403 //prt_p(p_ptr, buf, 17, 11);
5404 #ifdef DEBUG
5405 for (i = 0; i < 20; i++)
5406 {
5407 for (k = 0; k < 80; k++)
5408 {
5409 printf("%c", p_ptr->info[i][k].c);
5410 }
5411 printf("\n");
5412 }
5413 #endif
5414 }
show_tombstone(player_type * p_ptr)5415 void show_tombstone(player_type *p_ptr)
5416 {
5417 int i;
5418 byte old_term;
5419
5420 print_tomb(p_ptr);
5421
5422 //send_prepared_info(p_ptr, NTERM_WIN_SPECIAL, STREAM_SPECIAL_TEXT);
5423 //player_type *p_ptr = Players[Ind];
5424 //int i;
5425
5426 /* Save 'current' terminal */
5427 old_term = p_ptr->remote_term;
5428
5429 /* Activte new terminal */
5430 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_SPECIAL);
5431
5432 /* Clear, Send, Refresh */
5433 send_term_info(p_ptr, NTERM_CLEAR, 0);
5434 for (i = 0; i < p_ptr->last_info_line + 1; i++)
5435 Stream_line_p(p_ptr, STREAM_SPECIAL_TEXT, i);
5436 send_term_info(p_ptr, NTERM_FLUSH, 0);
5437
5438 /* Restore active term */
5439 send_term_info(p_ptr, NTERM_ACTIVATE, old_term);
5440 Send_pause(p_ptr);
5441 }
5442
5443 /* these Dungeon Master commands should probably be added somewhere else, but I am
5444 * hacking them together here to start.
5445 */
5446
5447
5448 /* List all 'socials' */
5449 struct social_type
5450 {
5451 cptr name;
5452 int min_victim_position;
5453
5454 /* No argument was supplied */
5455 cptr char_no_arg;
5456 cptr others_no_arg;
5457
5458 /* An argument was there, and a victim was found */
5459 cptr char_found; /* if NULL, read no further, ignore args */
5460 cptr others_found;
5461 cptr vict_found;
5462 } *socials;
5463 int max_socials = 0; /* Store total number of socials */
wipe_socials()5464 void wipe_socials()
5465 {
5466 int i;
5467 /*** Free ***/
5468 for (i = 0; i < max_socials; i++)
5469 {
5470 string_ifree(socials[i].name);
5471 string_ifree(socials[i].char_no_arg);
5472 string_ifree(socials[i].others_no_arg);
5473 string_ifree(socials[i].char_found);
5474 string_ifree(socials[i].others_found);
5475 string_ifree(socials[i].vict_found);
5476 }
5477 FREE(socials);
5478 }
boot_socials()5479 void boot_socials()
5480 {
5481 ang_file* fp;
5482 char buf[1024];
5483 static bool initialised = FALSE;
5484 int curr = -1, barr = 0; /* current social, and current line ('barrel') */
5485 /*** Load the ascii template file ***/
5486
5487 /* Build the filename */
5488 path_build(buf, 1024, ANGBAND_DIR_EDIT, "socials.txt");
5489
5490 /* Open the file */
5491 fp = file_open(buf, MODE_READ, -1);
5492
5493 /* Parse it */
5494 if (!fp)
5495 {
5496 plog("Cannot open 'socials.txt' file.");
5497 return;
5498 }
5499
5500 /* Parse the file */
5501 while (file_getl(fp, buf, 1024))
5502 {
5503 /* Skip comments and blank lines */
5504 if (!buf[0] || (buf[0] == '#')) continue;
5505
5506 /* Verify correct "colon" format */
5507 if (buf[1] != ':') continue;
5508
5509 /* Array size */
5510 if (buf[0] == 'Z')
5511 {
5512 int len;
5513
5514 /* Scan for the value */
5515 if (1 != sscanf(buf+2, "%d", &len)) break;
5516
5517 /*** Init ***/
5518 C_MAKE(socials, len, struct social_type);
5519 initialised = TRUE;
5520 max_socials = len;
5521 continue;
5522 }
5523 if (!initialised) break;
5524
5525 /* New social */
5526 if (buf[0] == 'N')
5527 {
5528 int pos;
5529 char name[60];
5530
5531 /* Scan for the values */
5532 if (2 != sscanf(buf+2, "%d:%s", &pos, name)) break;
5533
5534 /* Advance */
5535 curr += 1;
5536 barr = 0;
5537
5538 /* Error */
5539 if (curr >= max_socials) break;
5540
5541 /* Save */
5542 socials[curr].name = string_make(name);
5543 socials[curr].min_victim_position = pos;
5544 socials[curr].char_no_arg = socials[curr].others_no_arg =
5545 socials[curr].char_found = socials[curr].others_found =
5546 socials[curr].vict_found = NULL;
5547 }
5548 if (curr == -1) break;
5549
5550 /* Single line (assign acording to 'barrel') */
5551 if (buf[0] == 'L')
5552 {
5553 if (!STRZERO(buf+2))
5554 switch(barr)
5555 {
5556 case 0:
5557 socials[curr].char_no_arg = string_make(buf+2);
5558 break;
5559 case 1:
5560 socials[curr].others_no_arg = string_make(buf+2);
5561 break;
5562 case 2:
5563 socials[curr].char_found = string_make(buf+2);
5564 break;
5565 case 3:
5566 socials[curr].others_found = string_make(buf+2);
5567 break;
5568 case 4:
5569 socials[curr].vict_found = string_make(buf+2);
5570 break;
5571 default:
5572 break;
5573 }
5574 if (++barr > 4) barr = 0;
5575 }
5576 /* "Multi-message" substitute for 'L' */
5577 if (buf[0] == 'F' || buf[0] == 'E')
5578 {
5579 char chars[MSG_LEN];
5580 char others[MSG_LEN];
5581 char victs[MSG_LEN];
5582 int i, j1 = 0, j2 = 0, j3 = 0;
5583 bool y = FALSE;
5584 for (i = 2; i < strlen(buf); i++)
5585 {
5586 if (buf[i] == '$')
5587 {
5588 others[j2++] = '%';
5589 others[j2++] = 's';
5590 if ((y = !y) == TRUE)
5591 {
5592 chars[j1++] = 'Y';
5593 chars[j1++] = 'o';
5594 chars[j1++] = 'u';
5595 victs[j3++] = '%';
5596 victs[j3++] = 's';
5597 }
5598 else
5599 {
5600 chars[j1++] = '%';
5601 chars[j1++] = 's';
5602 victs[j3++] = 'y';
5603 victs[j3++] = 'o';
5604 victs[j3++] = 'u';
5605 }
5606 continue;
5607 }
5608 if (buf[i] == '~')
5609 {
5610 others[j2++] = 's';
5611 victs[j3++] = 's';
5612 continue;
5613 }
5614 chars[j1++] = buf[i];
5615 others[j2++] = buf[i];
5616 victs[j3++] = buf[i];
5617 }
5618 chars[j1] = '\0';
5619 others[j2] = '\0';
5620 victs[j3] = '\0';
5621 if (buf[0] == 'E')
5622 {
5623 socials[curr].char_found = string_make(chars);
5624 socials[curr].others_found = string_make(others);
5625 socials[curr].vict_found = string_make(victs);
5626 barr = 0;
5627 }
5628 if (buf[0] == 'F')
5629 {
5630 socials[curr].char_no_arg = string_make(chars);
5631 socials[curr].others_no_arg = string_make(others);
5632 barr = 2;
5633 }
5634 }
5635 }
5636
5637 /* Close it */
5638 file_close(fp);
5639 }
show_socials(player_type * p_ptr)5640 void show_socials(player_type *p_ptr)
5641 {
5642 struct social_type *s_ptr;
5643 int i, j, b, bi;
5644 char out_val[80];
5645 byte flag;
5646
5647 j = b = bi = 0;
5648
5649 /* Check each social */
5650 for (i = 0; i < max_socials; i++)
5651 {
5652 s_ptr = &socials[i];
5653
5654 /* Format information */
5655 sprintf(out_val, " %c) %-30s",
5656 I2A(j), s_ptr->name);
5657
5658 /* Prepare flag */
5659 flag = (PY_SPELL_LEARNED | PY_SPELL_WORKED);
5660
5661 if (s_ptr->min_victim_position != 0)
5662 flag |= PY_SPELL_PROJECT;
5663
5664 if (s_ptr->min_victim_position < 0)
5665 flag |= PY_SPELL_AIM;
5666
5667 /* Send it */
5668 send_spell_info(p_ptr, 12 + b, bi, flag, 0, out_val);
5669 j++;
5670 bi++;
5671
5672 /* Next book */
5673 if (bi >= SPELLS_PER_BOOK)
5674 {
5675 j = 0;
5676 bi = 0;
5677 b++;
5678 }
5679 }
5680 }
5681 static cptr ddd_names[10] =
5682 {"", "south-east", "south", "south-west", "east",
5683 "", "west", "north-east", "north", "north-west" };
5684 /* Perform a 'social' action */
do_cmd_social(player_type * p_ptr,int dir,int i)5685 void do_cmd_social(player_type *p_ptr, int dir, int i)
5686 {
5687 struct social_type *s_ptr;
5688 bool m_catch = FALSE;
5689
5690 /* Ghosts don't socialize */
5691 if (p_ptr->ghost || p_ptr->fruit_bat) return;
5692
5693 /* Adjust index */
5694 if (i >= SPELL_PROJECTED)
5695 {
5696 i -= SPELL_PROJECTED;
5697 m_catch = TRUE;
5698 }
5699
5700 /* Check bounds */
5701 if ((i < 0) || (i >= max_socials)) return;
5702
5703 s_ptr = &socials[i];
5704
5705 if (m_catch && s_ptr->min_victim_position != 0)
5706 {
5707 int d, x, y, target;
5708 if (dir != 5 && VALID_DIR(dir))
5709 {
5710 y = p_ptr->py;
5711 x = p_ptr->px;
5712 target = 0;
5713 for (d=1;;d++)
5714 {
5715 y += ddy[dir];
5716 x += ddx[dir];
5717 if (!in_bounds(p_ptr->dun_depth, y, x)) break;
5718 if ((target = cave[p_ptr->dun_depth][y][x].m_idx)) break;
5719 }
5720 }
5721 else if (!target_okay(p_ptr)) {return;}
5722 else
5723 {
5724 target = p_ptr->target_who;
5725 y = p_ptr->target_row;
5726 x = p_ptr->target_col;
5727 d = distance(p_ptr->py, p_ptr->px, y, x);
5728 }
5729 if (target && (s_ptr->min_victim_position < 1 || d <= s_ptr->min_victim_position))
5730 {
5731 char victim[80];
5732 if (target > 0)
5733 {
5734 monster_desc(p_ptr, victim, target, 0);
5735 if (s_ptr->others_found)
5736 msg_format_complex_near(p_ptr, p_ptr, MSG_SOCIAL,
5737 s_ptr->others_found, p_ptr->name, victim);
5738 }
5739 if (target < 0)
5740 {
5741 sprintf(victim, "%s", Players[0 - target]->name);
5742 if (s_ptr->others_found)
5743 msg_format_complex_near(p_ptr, Players[0-target], MSG_SOCIAL,
5744 s_ptr->others_found, p_ptr->name, victim);
5745 if (s_ptr->vict_found)
5746 msg_format_type(Players[0 - target], MSG_SOCIAL,
5747 s_ptr->vict_found, p_ptr->name);
5748 }
5749 if (s_ptr->char_found)
5750 msg_format_type(p_ptr, MSG_SOCIAL, s_ptr->char_found, victim);
5751 }
5752 }
5753 else
5754 {
5755 if (s_ptr->char_no_arg)
5756 msg_format_type(p_ptr, MSG_SOCIAL, s_ptr->char_no_arg, ddd_names[dir]);
5757 if (s_ptr->others_no_arg)
5758 msg_format_complex_near(p_ptr, p_ptr, MSG_SOCIAL, s_ptr->others_no_arg, p_ptr->name, ddd_names[dir]);
5759 }
5760 }
5761
describe_player(player_type * q_ptr,player_type * p_ptr)5762 void describe_player(player_type *q_ptr, player_type *p_ptr)
5763 {
5764 object_type *o_ptr;
5765 char buf[240];
5766 char *s;
5767
5768 int i, j = 0;
5769
5770 bool spoilers = (q_ptr->dm_flags & DM_SEE_PLAYERS ? TRUE : FALSE);
5771 bool is_rogue = (c_info[q_ptr->pclass].flags & CF_STEALING_IMPROV ? TRUE : FALSE);
5772
5773 /* Describe name */
5774 text_out(p_ptr->name);
5775 text_out(", the ");
5776 text_out(c_text + p_ptr->cp_ptr->title[(p_ptr->lev-1)/5]);
5777 text_out(".\n ");
5778 s = p_name + p_info[p_ptr->prace].name;
5779 sprintf(buf, "%s is %s %s ",
5780 (p_ptr->male ? "He" : "She"),
5781 is_a_vowel(tolower(s[0])) ? "an" : "a", s);
5782 text_out(buf);
5783 text_out_c(c_info[p_ptr->pclass].attr, c_name + c_info[p_ptr->pclass].name);
5784 text_out(". ");
5785 /* text_out("\n "); */
5786
5787
5788 /* Describe Equipment */
5789 for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
5790 {
5791 byte old_ident;
5792 char o_name[80];
5793 o_ptr = &p_ptr->inventory[i];
5794
5795 if (!o_ptr->tval) continue;
5796
5797 /* Note! Only rogues can see jewelry */
5798 if (!spoilers && !is_rogue && (i == INVEN_NECK || i == INVEN_LEFT || i == INVEN_RIGHT)) continue;
5799
5800 /* HACK! Remove ident */
5801 old_ident = o_ptr->ident;
5802 if (!spoilers)
5803 o_ptr->ident = 0;
5804
5805 /* Extract name */
5806 object_desc(p_ptr, o_name, sizeof(o_name), o_ptr, TRUE, (spoilers ? 4 : 0));
5807
5808 /* Restore original ident */
5809 o_ptr->ident = old_ident;
5810
5811 /* Prepare string */
5812 strcpy(buf, describe_use(0, i));
5813 s = strstr(buf, "%");
5814 *s = '\0'; s += 2;
5815
5816 /* Very first mention of equipment */
5817 if (!j)
5818 {
5819 text_out((p_ptr->male ? "He" : "She"));
5820 text_out(" is ");
5821 j = 1;
5822 }
5823 else
5824 {
5825 /*buf[0] = toupper(buf[0]);*/
5826 text_out(", ");
5827 }
5828
5829 /* Append */
5830 text_out(buf);
5831 /* text_out_c(object_attr(o_ptr), o_name); //intersting effect */
5832 text_out_c(p_ptr->tval_attr[o_ptr->tval % 128], o_name);
5833 sprintf(o_name, s, (p_ptr->male ? "his" : "her"));
5834 text_out(o_name);
5835 }
5836 if (j) text_out(". ");
5837
5838
5839 /* Describe History */
5840 my_strcpy(buf, p_ptr->descrip, sizeof(buf));
5841 s = strtok(buf, " \n");
5842 while (s)
5843 {
5844 text_out(s);
5845 text_out(" ");
5846 s = strtok(NULL, " \n");
5847 }
5848 text_out("\n");
5849 }
5850
snapshot_player(player_type * p_ptr,int who)5851 void snapshot_player(player_type *p_ptr, int who)
5852 {
5853 player_type *q_ptr = Players[who];
5854 cave_view_type status[80];
5855 int x1,y1, y, x;
5856 char c, tc;
5857 byte a, ta;
5858
5859 /* Determine boundaries */
5860 x1 = MAX(0, p_ptr->px - 40);
5861 y1 = MAX(0, p_ptr->py - 13);
5862 if ((x = MAX_WID - (x1 + 80)) < 0) { x1 += x; }
5863 if ((y = MAX_HGT - (y1 + 23)) < 0) { y1 += y; }
5864
5865 /* Draw! */
5866
5867 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_MAP);
5868 send_term_info(p_ptr, NTERM_CLEAR, 1);
5869
5870 for (y = 0; y < 23; y++)
5871 {
5872 for (x = 0; x < 80; x++)
5873 {
5874 map_info(q_ptr, y1+y, x1+x, &a, &c, &ta, &tc, FALSE);
5875 stream_char_raw(p_ptr, BGMAP_STREAM_p(p_ptr), y, x, a, c, ta, tc);
5876 }
5877 }
5878
5879 c_prt_status_line(q_ptr, status, 80);
5880 for (x = 0; x < 80; x++)
5881 {
5882 Send_char_p(p_ptr, x, y, status[x].a, status[x].c);
5883 }
5884
5885 y = player_pict(p_ptr, q_ptr);
5886 a = PICT_A(y);
5887 c = PICT_C(y);
5888 stream_char_raw(p_ptr, BGMAP_STREAM_p(p_ptr), p_ptr->py-y1, p_ptr->px-x1, a, c, a, c);
5889
5890 send_term_info(p_ptr, NTERM_FRESH, 0);
5891 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_SPECIAL);
5892 }
5893
preview_vault(player_type * p_ptr,int v_idx)5894 void preview_vault(player_type *p_ptr, int v_idx)
5895 {
5896 vault_type *v_ptr = &v_info[v_idx];
5897
5898 cptr t;
5899 byte feat, a;
5900 char c;
5901 int dy, dx;
5902
5903 int w, h;
5904
5905 /* Make sure we don't write out of bounds */
5906 w = p_ptr->stream_wid[STREAM_BGMAP_ASCII];
5907 h = MIN(v_ptr->hgt, p_ptr->stream_hgt[STREAM_BGMAP_ASCII]);
5908
5909 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_MAP);
5910 send_term_info(p_ptr, NTERM_CLEAR, 1);
5911
5912 for (t = v_text + v_ptr->text, dy = 0; dy < h; dy++)
5913 {
5914 for (dx = 0; dx < w; dx++)
5915 {
5916 if (dx >= w) continue;
5917
5918 a = TERM_WHITE; feat = 0;
5919
5920 if (dx < v_ptr->wid)
5921 {
5922 c = *t;
5923 switch (c)
5924 {
5925 case '.': feat = FEAT_FLOOR; break;
5926 case '%': feat = FEAT_WALL_OUTER; break;
5927 case '#': feat = FEAT_WALL_INNER; break;
5928 case 'X': feat = FEAT_PERM_INNER; break;
5929 case '^': feat = FEAT_TRAP_HEAD+6; break;
5930 case '+': feat = FEAT_DOOR_HEAD; break;
5931 case '*': a = TERM_ORANGE; break;
5932 case '&': case '@': a = TERM_RED; break;
5933 case '9': case '8': case ',': a = TERM_YELLOW; break;
5934 }
5935 t++;
5936 }
5937 else c = ' ';
5938
5939 if (feat)
5940 {
5941 /*feature_type *f_ptr = &f_info[feat];
5942 c = f_ptr->x_char;
5943 a = f_ptr->x_attr;*/
5944 c = p_ptr->f_char[feat];
5945 a = p_ptr->f_attr[feat];
5946 }
5947
5948 stream_char_raw(p_ptr, BGMAP_STREAM_p(p_ptr), dy, dx, a, c, 0, 0);//a, c);
5949 }
5950 while (dx < v_ptr->wid)
5951 {
5952 dx++;
5953 t++;
5954 }
5955 }
5956
5957 send_term_info(p_ptr, NTERM_FRESH, 0);
5958 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_SPECIAL);
5959 }
5960
5961 /**
5962 **
5963 ** DUNGEON MASTER MENU
5964 **
5965 **/
5966 #define DM_PAGES 7
5967 #define DM_PAGE_WORLD 0
5968 #define DM_PAGE_PLAYER 1
5969 #define DM_PAGE_LEVEL 2
5970 #define DM_PAGE_FEATURE 3
5971 #define DM_PAGE_MONSTER 4
5972 #define DM_PAGE_VAULT 5
5973 #define DM_PAGE_ITEM 6
5974 #define DM_PAGE_PLOT 7
5975 #define MASTER_SELECT 0x10000000
5976 #define MASTER_BRUSH 0x20000000
5977 static cptr dm_pages[DM_PAGES+1] =
5978 {
5979 "World",
5980 "Player",
5981 "Level",
5982 "Build",
5983 "Summon",
5984 "Encounter",
5985 "Forge",
5986 "Plot", /* not really a page; brush */
5987 };
5988 /*
5989 * ACCESS TO DM PAGES! Notice 2 slots for each page:
5990 * triggering either grants access.
5991 */
5992 static u32b dm_access[DM_PAGES*2] =
5993 {
5994 (DM___MENU),(DM_IS_MASTER),
5995 (DM_CAN_ASSIGN),(DM_CAN_MUTATE_SELF),
5996 (DM_LEVEL_CONTROL),(DM_IS_MASTER),
5997 (DM_CAN_BUILD),(DM_IS_MASTER),
5998 (DM_CAN_SUMMON),(DM_IS_MASTER),
5999 (DM_CAN_GENERATE | DM_CAN_BUILD),(DM_IS_MASTER),
6000 (DM_CAN_GENERATE),(DM_IS_MASTER),
6001 };
6002 /* This "table" is used to provide XTRA2 descriptions */
6003 static cptr extra_mods[][12] =
6004 {
6005 {"None"},
6006 {"Sustain STR", "Sustain DEX", "Sustain CON", "Sustain INT", "Sustain WIS", "Sustain CHR"},
6007 {"Poison", "Fear", "Light", "Dark", "Blindness", "Confusion", "Sound", "Shards", "Nexus", "Nether", "Chaos", "Disen"},
6008 {"Slow Digestion", "Feather Falling", "Permanent Lite", "Regeneration", "Telepathy", "See Invisible", "Free Action", "Hold Life"}
6009 };
6010 /* Names for each DM flag */
6011 static cptr dm_flags_str[32] =
6012 {
6013 "Dungeon Master",
6014 "Presence Hidden",
6015 "Change Self",
6016 "Change Others",
6017 "Build Menu",
6018 "Level Menu",
6019 "Summon Menu",
6020 "Generate Menu",
6021 "Monster Friend",
6022 "*Invulnerable*",
6023 "Ghostly Hands",
6024 "Ghostly Body",
6025 "Never Disturbed",
6026 "See Level",
6027 "See Monsters",
6028 "See Players",
6029 "Landlord",
6030 "Keep Lite",
6031 "Can Reset Items",
6032 "Artifact Master",
6033 "(unused)",
6034 "(unused)",
6035 "(unused)",
6036 "(unused)",
6037 "(unused)",
6038 "(unused)",
6039 "(unused)",
6040 "(unused)",
6041 "(unused)",
6042 "(unused)",
6043 "(unused)",
6044 "(unused)",
6045 };
6046 /* Possible Filters.
6047 * Those are used to fill lists in the "master_fill_..." functions. */
6048 #define FILT_ANIMAL 0x00010000
6049 #define FILT_DEMON 0x00200000
6050 #define FILT_UNDEAD 0x00400000
6051 #define FILT_DRAGON 0x00800000
6052 #define FILT_UNIQUE 0x08000000
6053 #define FILT_ORC 0x10000000
6054 #define FILT___EGO (FILT_WEAPON | FILT_GEAR)
6055 #define FILT___ANY 0xFFFF0000
6056 #define FILT_REVERS 0x00008000
6057 #define SORT_REVERS 0x00004000
6058 #define FILT_EGO 0x00010000
6059 #define FILT_WEAPON 0x00020000
6060 #define FILT_GEAR 0x00040000
6061 #define FILT_POTION 0x00100000
6062 #define FILT_SCROLL 0x00200000
6063 #define FILT_FOOD 0x00400000
6064 #define FILT_MAGIC 0x00800000
6065 /* Fill monsters and object using the constants above.
6066 * NOTE: Uses p_ptr->target_idx array to store the outcome - this is dangerous.*/
master_fill_objects(player_type * p_ptr,u32b how)6067 void master_fill_objects(player_type *p_ptr, u32b how)
6068 {
6069 int i, n, j = 0;
6070 for (i = 0; i < z_info->k_max; i++)
6071 {
6072 object_kind *k_ptr = &k_info[i];
6073 bool okay = (how & FILT___ANY ? FALSE : TRUE);
6074 if ((how & FILT_EGO) && !(how & FILT_REVERS)) break;
6075 if ((how & FILT_WEAPON) &&
6076 (k_ptr->tval == TV_SWORD || k_ptr->tval == TV_HAFTED || k_ptr->tval == TV_POLEARM ||
6077 k_ptr->tval == TV_BOW || k_ptr->tval == TV_DIGGING))
6078 okay = TRUE;
6079 if ((how & FILT_GEAR) &&
6080 (k_ptr->tval == TV_SOFT_ARMOR || k_ptr->tval == TV_HARD_ARMOR || k_ptr->tval == TV_DRAG_ARMOR ||
6081 k_ptr->tval == TV_SHIELD || k_ptr->tval == TV_HELM || k_ptr->tval == TV_CROWN ||
6082 k_ptr->tval == TV_CLOAK || k_ptr->tval == TV_GLOVES || k_ptr->tval == TV_BOOTS))
6083 okay = TRUE;
6084 if ((how & FILT_MAGIC) &&
6085 (k_ptr->tval == TV_WAND || k_ptr->tval == TV_STAFF || k_ptr->tval == TV_ROD))
6086 okay = TRUE;
6087 if ((how & FILT_SCROLL) && (k_ptr->tval == TV_SCROLL)) okay = TRUE;
6088 if ((how & FILT_POTION) && (k_ptr->tval == TV_POTION)) okay = TRUE;
6089 if ((how & FILT_FOOD) && (k_ptr->tval == TV_FOOD)) okay = TRUE;
6090 if (okay == ((how & FILT___ANY) && (how & FILT_REVERS) ? TRUE : FALSE)) continue;
6091 p_ptr->target_idx[j] = i;
6092 j++;
6093 }
6094 for (i = 1; i < z_info->e_max; i++)
6095 {
6096 ego_item_type *e_ptr = &e_info[i];
6097 bool okay = (how & FILT___EGO ? FALSE : TRUE);
6098 if ((how & FILT_EGO) && (how & FILT_REVERS)) break;
6099 for (n = 0; n < EGO_TVALS_MAX; n++)
6100 {
6101 if ((how & FILT_WEAPON) &&
6102 (e_ptr->tval[n] == TV_SWORD || e_ptr->tval[n] == TV_HAFTED || e_ptr->tval[n] == TV_POLEARM ||
6103 e_ptr->tval[n] == TV_BOW || e_ptr->tval[n] == TV_DIGGING ))
6104 okay = TRUE;
6105 if ((how & FILT_GEAR) &&
6106 (e_ptr->tval[n] == TV_SOFT_ARMOR || e_ptr->tval[n] == TV_HARD_ARMOR || e_ptr->tval[n] == TV_DRAG_ARMOR ||
6107 e_ptr->tval[n] == TV_SHIELD || e_ptr->tval[n] == TV_HELM || e_ptr->tval[n] == TV_CROWN ||
6108 e_ptr->tval[n] == TV_CLOAK || e_ptr->tval[n] == TV_GLOVES || e_ptr->tval[n] == TV_BOOTS))
6109 okay = TRUE;
6110 }
6111 if (okay == ((how & FILT___EGO) && (how & FILT_REVERS) ? TRUE : FALSE)) continue;
6112 p_ptr->target_idx[j] = 0 - i;
6113 j++;
6114 }
6115 /* Save number ! */
6116 p_ptr->target_n = j;
6117 }
master_fill_monsters(player_type * p_ptr,u32b how)6118 void master_fill_monsters(player_type *p_ptr, u32b how)
6119 {
6120 int i, n;
6121 u32b why = how;
6122
6123 #define MASTER_COMPARE_MONSTER(TYPE) \
6124 if ( (how & FILT_ ## TYPE) && (summon_specific_okay_aux(i, SUMMON_ ## TYPE) == (how & FILT_REVERS ? TRUE : FALSE)) ) \
6125 continue
6126
6127 if (how & FILT___ANY)
6128 {
6129 for (i = 0, n = 0; i < z_info->r_max; i++)
6130 {
6131 MASTER_COMPARE_MONSTER(UNIQUE);
6132 MASTER_COMPARE_MONSTER(UNDEAD);
6133 MASTER_COMPARE_MONSTER(DEMON);
6134 MASTER_COMPARE_MONSTER(DRAGON);
6135 MASTER_COMPARE_MONSTER(ORC);
6136 MASTER_COMPARE_MONSTER(ANIMAL);
6137
6138 p_ptr->target_idx[n++] = i;
6139 }
6140 }
6141 else for (i = 0, n = z_info->r_max; i < n; i++)
6142 p_ptr->target_idx[i] = i;
6143
6144 /* Save number ! */
6145 p_ptr->target_n = n;
6146
6147 if (!why) return;
6148
6149 /* Select the sort method */
6150 ang_sort_comp = ang_sort_comp_monsters;
6151 ang_sort_swap = ang_sort_swap_u16b;
6152
6153 /* Sort! */
6154 ang_sort(p_ptr, p_ptr->target_idx, &why, p_ptr->target_n);
6155
6156 /* Switch ascending/descending */
6157 if (why & SORT_REVERS) for (i = 0; i < n / 2; i++)
6158 {
6159 why = p_ptr->target_idx[i];
6160 p_ptr->target_idx[i] = p_ptr->target_idx[n - 1 - i];
6161 p_ptr->target_idx[n - 1 - i] = why;
6162 }
6163 }
6164 /*
6165 * Helper function for "do_cmd_dungeon_master". Utilizes same
6166 * "switch/DM_PAGE" (See below). Search the list by string,
6167 * supports offset.
6168 */
master_search_for(player_type * p_ptr,s16b what,cptr needle,s16b offset)6169 s16b master_search_for(player_type *p_ptr, s16b what, cptr needle, s16b offset)
6170 {
6171 int i;
6172 s16b before = -1;
6173 s16b after = -1;
6174
6175 bool exact = FALSE;
6176 int len = strlen(needle);
6177
6178 if (needle[0] == '^')
6179 {
6180 exact = TRUE;
6181 needle++; len--;
6182 }
6183
6184 #define MASTER_SEARCH_COMPARE(HAYSTACK) \
6185 if ((exact && !my_strnicmp((HAYSTACK), needle, len)) || \
6186 (!exact && my_stristr((HAYSTACK), needle)) ) \
6187 { \
6188 if (i <= offset) \
6189 { \
6190 if (before == -1) before = i; \
6191 } \
6192 else \
6193 { \
6194 after = i; break; \
6195 } \
6196 }
6197
6198 switch (what)
6199 {
6200 case DM_PAGE_PLAYER:
6201 for (i = 0; i < NumPlayers; i++)
6202 {
6203 player_type *q_ptr = Players[i+1];
6204 MASTER_SEARCH_COMPARE(q_ptr->name);
6205 }
6206 break;
6207 case DM_PAGE_FEATURE:
6208 for (i = 0; i < z_info->f_max; i++)
6209 {
6210 feature_type *f_ptr = &f_info[i];
6211 MASTER_SEARCH_COMPARE(f_name + f_ptr->name);
6212 }
6213 break;
6214 case DM_PAGE_MONSTER:
6215 for (i = 0; i < p_ptr->target_n; i++)
6216 {
6217 monster_race *r_ptr = &r_info[p_ptr->target_idx[i]];
6218 MASTER_SEARCH_COMPARE(r_name + r_ptr->name);
6219 }
6220 break;
6221 case DM_PAGE_VAULT:
6222 for (i = 0; i < z_info->v_max; i++)
6223 {
6224 vault_type *v_ptr = &v_info[i];
6225 MASTER_SEARCH_COMPARE(v_name + v_ptr->name);
6226 }
6227 break;
6228 case DM_PAGE_ITEM:
6229 for (i = 0; i < p_ptr->target_n; i++)
6230 {
6231 if (p_ptr->target_idx[i] < 0)
6232 {
6233 ego_item_type *e_ptr = &e_info[0 - p_ptr->target_idx[i]];
6234 MASTER_SEARCH_COMPARE(e_name + e_ptr->name);
6235 }
6236 else
6237 {
6238 object_kind *k_ptr = &k_info[p_ptr->target_idx[i]];
6239 MASTER_SEARCH_COMPARE(k_name + k_ptr->name);
6240 }
6241 }
6242 }
6243
6244 if (after == -1)
6245 {
6246 if (before == -1)
6247 {
6248 return offset;
6249 }
6250 return before;
6251 }
6252 return after;
6253
6254 }
6255 /*
6256 * Given the slot number, hook id and hook arguments, fills the
6257 * string with a human-readable description.
6258 */
master_hook_desc(char * buf,byte i,byte hook,u32b args)6259 void master_hook_desc(char *buf, byte i, byte hook, u32b args)
6260 {
6261 char nums[MASTER_MAX_HOOKS] = "xazv";
6262 *(buf++) = nums[i];
6263 *(buf++) = ':';
6264 *(buf++) = ' ';
6265 if (hook)
6266 {
6267 strcpy(buf, dm_pages[hook]);
6268 buf+= strlen(dm_pages[hook]);
6269 *(buf++) = ' ';
6270 switch (hook)
6271 {
6272 case DM_PAGE_FEATURE:strcpy(buf, f_name + f_info[args].name); break;
6273 case DM_PAGE_MONSTER:strcpy(buf, r_name + r_info[args].name); break;
6274 case DM_PAGE_VAULT:strcpy(buf, v_name + v_info[args].name); break;
6275 case DM_PAGE_PLOT:
6276 {
6277 byte x1, y1, x2, y2;
6278 x1 = (args >> 0) & 0xFF;
6279 y1 = (args >> 8) & 0xFF;
6280 x2 = (args >> 16) & 0xFF;
6281 y2 = (args >> 24);
6282 strnfmt(buf, 20, "Selection %02dx%02d", ABS(x2-x1), ABS(y2-y1));
6283 }
6284 break;
6285 }
6286 }
6287 else
6288 {
6289 strcpy(buf, "<none>");
6290 }
6291 }
6292 /*
6293 * Dungeon Master Menu
6294 *
6295 * This is the main function to handle the DM menu.
6296 *
6297 * Menu handling consists of those stages:
6298 *
6299 * INPUT
6300 * (Common input) - navigate tabs
6301 * (Page input) - each page has it's own set of keypresses
6302 * OUTPUT
6303 * (Header) - displays page names
6304 * (Content) - page-specific contents, own for each page
6305 * Commonly, content is as follows:
6306 * (List) - a sortable/searchable list of elements
6307 * (Sidebar) - quick actions for page/element
6308 * (Selection) - currently selected list element
6309 * (Error) - if there was an error, shows it
6310 * (Footer) - displays hooks
6311 *
6312 * Most interesting, for adding new features, are the "Page input"
6313 * and "Content" sections, the rest handle the menu itself.
6314 *
6315 * Note that a "switch (current_page)" is employed several times during
6316 * the course of this routine, with DM_PAGE_XXX defines as arguments.
6317 * This should probably be separated into different functions.
6318 *
6319 * Note that each keypress, even uncounted for, makes whole screen
6320 * redraw itself and send a new copy over network.
6321 *
6322 */
do_cmd_dungeon_master(player_type * p_ptr,char query)6323 void do_cmd_dungeon_master(player_type *p_ptr, char query)
6324 {
6325 static char numero[5];
6326 char buf[80], *s = NULL;
6327 int old_tab, skip_line, old_line;
6328 int i, j, x, y;
6329 int hgt = p_ptr->stream_hgt[STREAM_SPECIAL_TEXT];
6330 bool access = FALSE;
6331 bool prompt_hooks = TRUE;
6332 cptr error = NULL;
6333
6334 /* Done */
6335 if (query == ESCAPE)
6336 {
6337 p_ptr->special_file_type = SPECIAL_FILE_NONE;
6338 return;
6339 }
6340
6341 /* Init */
6342 if (!query)
6343 {
6344 /* Go to first page */
6345 p_ptr->interactive_next = 0;
6346 /* Reset list */
6347 p_ptr->interactive_line = 0;
6348 p_ptr->interactive_size = 0;
6349 /* Reset argument */
6350 p_ptr->master_parm = 0;
6351 }
6352
6353 /* Notice changes */
6354 old_tab = p_ptr->interactive_next;
6355 old_line = p_ptr->interactive_line;
6356
6357 /** Common Input **/
6358 switch (query)
6359 {
6360 /* Navigate HOOKS */
6361 case ' ': p_ptr->master_flag++; break; /* Next */
6362 case 'x': p_ptr->master_flag = 0; break; /* Jump to hook */
6363 case 'a': p_ptr->master_flag = 1; break; /* Jump to hook */
6364 case 'z': p_ptr->master_flag = 2; break; /* Jump to hook */
6365 case 'v': p_ptr->master_flag = 3; break; /* Jump to hook */
6366 /* ACTION! Delete Hooks: */
6367 case '\b': /* Backspace -- same as Del */
6368 case 127: p_ptr->master_hook[p_ptr->master_flag] = 0; break; /* Del */
6369
6370 /* Navigate PAGES */
6371 case '6': p_ptr->interactive_next++; break; /* Right */
6372 case '4': p_ptr->interactive_next--; break; /* Left */
6373 case '@': /* Jump to + Select ('Edit Self')*/
6374 old_tab = p_ptr->interactive_next = DM_PAGE_PLAYER;
6375 p_ptr->interactive_line = p_ptr->Ind - 1;
6376 p_ptr->master_parm = p_ptr->id;
6377 break;
6378
6379 /* Navigate LIST */
6380 case '8': p_ptr->interactive_line--; break; /* Up */
6381 case '2': p_ptr->interactive_line++; break; /* Down */
6382 case '9': p_ptr->interactive_line -= 20; break; /* PgUp */
6383 case '3': p_ptr->interactive_line += 20; break; /* PgDn */
6384 case '7': p_ptr->interactive_line = 0; break; /* Home */
6385 case '1': p_ptr->interactive_line = p_ptr->interactive_size; break; /* End? */
6386 case '#': /* Goto */
6387 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Goto line: ", "", TERM_WHITE, TERM_WHITE)) return;
6388 p_ptr->interactive_line = atoi(buf);
6389 break;
6390 case '/': /* Find */
6391 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Search: ", "", TERM_WHITE, TERM_WHITE)) return;
6392 p_ptr->interactive_line = master_search_for(p_ptr, p_ptr->interactive_next, buf, p_ptr->interactive_line);
6393 break;
6394 }
6395 /* Additional Input: */
6396 for (i = 0; i < DM_PAGES; i++)
6397 {
6398 /* Provide shortcuts for each "Page" as Ctrl+"p" */
6399 if (query == KTRL(tolower(dm_pages[i][0])))
6400 {
6401 p_ptr->interactive_next = i;
6402 break;
6403 }
6404 }
6405
6406 /* Page & Hook Boundaries */
6407 if (p_ptr->interactive_next <= 0)
6408 p_ptr->interactive_next = 0;
6409 if (p_ptr->interactive_next > DM_PAGES - 1)
6410 p_ptr->interactive_next = DM_PAGES - 1;
6411 if (p_ptr->master_flag >= MASTER_MAX_HOOKS)
6412 p_ptr->master_flag = 0;
6413
6414 /* Changed page (Sub-Init!) */
6415 if (old_tab != p_ptr->interactive_next)
6416 {
6417 /* Reset list */
6418 p_ptr->interactive_line = 0;
6419 p_ptr->interactive_size = 0;
6420 /* Reset argument */
6421 p_ptr->master_parm = 0;
6422 }
6423
6424 /* Hack -- deny keypress */
6425 access = (dm_access[p_ptr->interactive_next * 2] & p_ptr->dm_flags) ||
6426 (dm_access[p_ptr->interactive_next * 2 + 1] & p_ptr->dm_flags);
6427 if (!access) query = 0;
6428
6429 /** Input **/
6430 switch (p_ptr->interactive_next)
6431 {
6432 case DM_PAGE_PLAYER:
6433 if (query == '\r')
6434 {
6435 if (p_ptr->interactive_line < NumPlayers)
6436 {
6437 y = p_ptr->interactive_line + 1; /* Note +1! */
6438 if (!same_player(Players[y], p_ptr) && !dm_flag_p(p_ptr,CAN_ASSIGN))
6439 {
6440 error = "Can't change other players";
6441 break;
6442 }
6443 if (same_player(Players[y], p_ptr) && !dm_flag_p(p_ptr,CAN_MUTATE_SELF))
6444 {
6445 error = "Can't change self";
6446 break;
6447 }
6448 p_ptr->master_parm = Players[y]->id;
6449 /*HACK:*/
6450 do_cmd_monster_desc_aux(p_ptr, 0 - y, TRUE);
6451 if (dm_flag_p(p_ptr,SEE_PLAYERS))
6452 snapshot_player(p_ptr, y);
6453 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_SPECIAL);
6454 }
6455 }
6456 /* For selected player: */
6457 if (p_ptr->master_parm)
6458 {
6459 player_type *q_ptr;
6460 y = find_player(p_ptr->master_parm);
6461 if (!y) break;
6462 q_ptr = Players[y];
6463 switch (query)
6464 {
6465 case 'W':
6466 if (same_player(q_ptr, p_ptr)) { error = "Can't wrath self"; break; }
6467 if (!askfor_aux(p_ptr, query, buf, 1, 0,
6468 format("Are you sure you want to call wrath on %s ? [y/n]", q_ptr->name),
6469 "*", TERM_WHITE, TERM_WHITE)) return;
6470 if (buf[0] != 'y' && buf[0] != 'Y') break;
6471 debug(format("%s invokes wrath on %s", p_ptr->name, q_ptr->name));
6472 take_hit(q_ptr, 1000, "a small kobold");
6473 break;
6474 case 'K':
6475 if (same_player(q_ptr, p_ptr)) { error = "Can't kick self"; break; }
6476 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Enter reason for Kick or ESC: ", "", TERM_WHITE, TERM_WHITE)) return;
6477 if (STRZERO(buf)) break;
6478 debug(format("%s kicks %s (reason:%s)", p_ptr->name, q_ptr->name, buf));
6479 player_disconnect(q_ptr, "kicked out");
6480 break;
6481 case 'I':
6482 if (same_player(q_ptr, p_ptr)) { error = "Can't invoke self"; break; }
6483 if (q_ptr->dun_depth == p_ptr->dun_depth ) { teleport_player_to(q_ptr, p_ptr->py, p_ptr->px); break; }
6484 if (!askfor_aux(p_ptr, query, buf, 1, 0,
6485 format("Recall %s to your depth ? [y/n]", q_ptr->name),
6486 "*", TERM_WHITE, TERM_WHITE)) return;
6487 if (buf[0] != 'y' && buf[0] != 'Y') break;
6488 debug(format("%s invokes %s to lev %d", p_ptr->name, q_ptr->name, p_ptr->dun_depth));
6489 msg_print(q_ptr, "The air about you becomes charged...");
6490 msg_format_complex_near(q_ptr, q_ptr, MSG_PY_MISC, "The air about %s becomes charged...", q_ptr->name);
6491 q_ptr->word_recall = 1;
6492 q_ptr->recall_depth = p_ptr->dun_depth;
6493 break;
6494 case '-': case '_':
6495 q_ptr->cur_lite = --q_ptr->old_lite;
6496 break;
6497 case '=': case '+':
6498 q_ptr->cur_lite = ++q_ptr->old_lite;
6499 break;
6500 case 'G':
6501 q_ptr->ghost = 1 - q_ptr->ghost;
6502 break;
6503 case 'C':
6504 q_ptr->noscore = 1 - q_ptr->noscore;
6505 break;
6506 case 'V':
6507 q_ptr->invuln = (q_ptr->invuln ? 0 : -1);
6508 break;
6509 default:
6510 if (isalpha(query))
6511 {
6512 x = A2I(query) - 1;
6513 if (x >= 0 && x <= 20)
6514 {
6515 if (!same_player(q_ptr, p_ptr) && !(p_ptr->dm_flags & (0x1L << x)))
6516 { error = "Can't assign unmastered power"; break; }
6517 TOGGLE_BIT(q_ptr->dm_flags, (0x1L << x));
6518 }
6519 }
6520 break;
6521 }
6522 }
6523 break;
6524 case DM_PAGE_LEVEL:
6525 {
6526 switch (query)
6527 {
6528 case 'S': players_on_depth[p_ptr->dun_depth] = count_players(p_ptr->dun_depth) + 1; break;
6529 case 'U': players_on_depth[p_ptr->dun_depth] = count_players(p_ptr->dun_depth); break;
6530 #ifdef HAVE_DIRENT_H
6531 case 'I':
6532 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Really import selected file ? [y/n]", "*", TERM_WHITE, TERM_WHITE)) return;
6533 if (STRZERO(buf)) break;
6534 p_ptr->master_parm = p_ptr->interactive_line + 1;
6535 break;
6536 #else
6537 case 'I':
6538 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Filename: ", "", TERM_WHITE, TERM_WHITE)) return;
6539 if (STRZERO(buf)) break;
6540 if (my_strnicmp(&buf[0], "server-", 7))
6541 {
6542 error = "Incorrect filename. Must have 'server-something' format!";
6543 }
6544 else if (!rd_dungeon_special_ext(p_ptr->dun_depth, &buf[0]))
6545 {
6546 error = "File not found";
6547 }
6548 else
6549 {
6550 players_on_depth[p_ptr->dun_depth] = count_players(p_ptr->dun_depth);
6551 msg_format(p_ptr, "Loading file '%s'", &buf[0]);
6552 debug(format("* %s imports lev %d from file '%s'", p_ptr->name, p_ptr->dun_depth, buf));
6553 }
6554
6555 break;
6556 #endif
6557 case 'E':
6558
6559 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Filename: ", "", TERM_WHITE, TERM_WHITE)) return;
6560 if (my_strnicmp(&buf[0], "server-", 7))
6561 {
6562 error = "Incorrect filename. Must have 'server-something' format!";
6563 }
6564 else if (!wr_dungeon_special_ext(p_ptr->dun_depth, &buf[0]))
6565 {
6566 error = "Failed to write a file";
6567 }
6568 else
6569 {
6570 msg_format(p_ptr, "Saved file '%s'", &buf[0]);
6571 debug(format("* %s exports lev %d into file '%s'", p_ptr->name, p_ptr->dun_depth, buf));
6572 }
6573
6574 break;
6575 }
6576 }
6577 break;
6578 case DM_PAGE_FEATURE:
6579 s = (char*)1; /* TRUE */
6580 switch (query)
6581 {
6582 /* QUICK! */
6583 case 'm': p_ptr->interactive_line = FEAT_MAGMA; break;
6584 case 'w': p_ptr->interactive_line = FEAT_WALL_EXTRA; break;
6585 case 'p': p_ptr->interactive_line = FEAT_PERM_EXTRA; break;
6586 case 'f': p_ptr->interactive_line = FEAT_FLOOR; break;
6587 case 'g': p_ptr->interactive_line = FEAT_GRASS; break;
6588 case 'd': p_ptr->interactive_line = FEAT_DIRT; break;
6589 case 't': p_ptr->interactive_line = FEAT_TREE; break;
6590 case 'T': p_ptr->interactive_line = FEAT_EVIL_TREE; break;
6591 case '\r': break; /* ! */
6592 default: s = NULL; break;
6593 }
6594 /* Start Building! */
6595 if (s)
6596 {
6597 p_ptr->master_hook[p_ptr->master_flag] = DM_PAGE_FEATURE;
6598 p_ptr->master_args[p_ptr->master_flag] = p_ptr->interactive_line;
6599 }
6600 break;
6601 case DM_PAGE_MONSTER:
6602 switch (query)
6603 {
6604 /* SORT */
6605 case 'd': TOGGLE_BIT(p_ptr->master_parm, SORT_LEVEL); break;
6606 case 'e': TOGGLE_BIT(p_ptr->master_parm, SORT_EXP); break;
6607 case 'r': TOGGLE_BIT(p_ptr->master_parm, SORT_RARITY); break;
6608 case 't': TOGGLE_BIT(p_ptr->master_parm, SORT_RICH); break;
6609 case 'u': TOGGLE_BIT(p_ptr->master_parm, SORT_UNIQUE); break;
6610 case 'q': TOGGLE_BIT(p_ptr->master_parm, SORT_QUEST); break;
6611 case 'f': TOGGLE_BIT(p_ptr->master_parm, SORT_REVERS); break;
6612 case 'F': TOGGLE_BIT(p_ptr->master_parm, FILT_REVERS); break;
6613 case 'Q': TOGGLE_BIT(p_ptr->master_parm, FILT_UNIQUE); break;
6614 case 'G': TOGGLE_BIT(p_ptr->master_parm, FILT_UNDEAD); break;
6615 case 'U': TOGGLE_BIT(p_ptr->master_parm, FILT_DEMON); break;
6616 case 'D': TOGGLE_BIT(p_ptr->master_parm, FILT_DRAGON); break;
6617 case 'O': TOGGLE_BIT(p_ptr->master_parm, FILT_ORC); break;
6618 case 'A': TOGGLE_BIT(p_ptr->master_parm, FILT_ANIMAL); break;
6619 case '\r':
6620 {
6621 /* Start Summoning! */
6622 p_ptr->master_hook[p_ptr->master_flag] = DM_PAGE_MONSTER;
6623 p_ptr->master_args[p_ptr->master_flag] = p_ptr->target_idx[p_ptr->interactive_line];
6624 break;
6625 }
6626 }
6627 /* PREPARE */
6628 master_fill_monsters(p_ptr, p_ptr->master_parm);
6629 p_ptr->interactive_size = p_ptr->target_n - 1;
6630 break;
6631 case DM_PAGE_VAULT:
6632 if (query == '\r')
6633 {
6634 /* Start Building! */
6635 p_ptr->master_hook[p_ptr->master_flag] = DM_PAGE_VAULT;
6636 p_ptr->master_args[p_ptr->master_flag] = p_ptr->interactive_line;
6637 }
6638 break;
6639 case DM_PAGE_ITEM:
6640 switch (query)
6641 {
6642 /* SORT */
6643 case '*': TOGGLE_BIT(p_ptr->master_parm, FILT_EGO); break;
6644 case '\\':
6645 case '|': TOGGLE_BIT(p_ptr->master_parm, FILT_WEAPON); break;
6646 case '(': case ')': case '[':
6647 case ']': TOGGLE_BIT(p_ptr->master_parm, FILT_GEAR); break;
6648 case '-': TOGGLE_BIT(p_ptr->master_parm, FILT_MAGIC); break;
6649 case '!': TOGGLE_BIT(p_ptr->master_parm, FILT_POTION); break;
6650 case '?': TOGGLE_BIT(p_ptr->master_parm, FILT_SCROLL); break;
6651 case ',': TOGGLE_BIT(p_ptr->master_parm, FILT_FOOD); break;
6652 case 'F': TOGGLE_BIT(p_ptr->master_parm, FILT_REVERS); break;
6653 /* FORGE */
6654 case 'n':
6655 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Quantity: ", "", TERM_WHITE, TERM_WHITE)) return;
6656 p_ptr->inventory[0].number = atoi(buf);
6657 break;
6658 case 'r':
6659 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Base Armor Class: ", "", TERM_WHITE, TERM_WHITE)) return;
6660 p_ptr->inventory[0].ac = atoi(buf);
6661 break;
6662 case 'R':
6663 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Magic Armor Bonus: ", "", TERM_WHITE, TERM_WHITE)) return;
6664 p_ptr->inventory[0].to_a = atoi(buf);
6665 break;
6666 case 'h':
6667 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Magic To-Hit Bonus: ", "", TERM_WHITE, TERM_WHITE)) return;
6668 p_ptr->inventory[0].to_h = atoi(buf);
6669 break;
6670 case 'd':
6671 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Magic To-Dam Bonus: ", "", TERM_WHITE, TERM_WHITE)) return;
6672 p_ptr->inventory[0].to_d = atoi(buf);
6673 break;
6674 case 'p':
6675 if (!askfor_aux(p_ptr, query, buf, 1, 0, "<Pval>: ", "", TERM_WHITE, TERM_WHITE)) return;
6676 p_ptr->inventory[0].pval = atoi(buf);
6677 break;
6678 case 'E':
6679 p_ptr->inventory[0].xtra2++;
6680 break;
6681 case 'e':
6682 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Hidden Ability: ", "", TERM_WHITE, TERM_WHITE)) return;
6683 p_ptr->inventory[0].xtra2 = atoi(buf);
6684 break;
6685 case 'D':
6686 if (!askfor_aux(p_ptr, query, buf, 1, 0, "Damage Dice (2d6): ", "", TERM_WHITE, TERM_WHITE)) return;
6687 s = strtok(buf, "d");
6688 p_ptr->inventory[0].dd = atoi(s);
6689 s = strtok(NULL, "d");
6690 p_ptr->inventory[0].ds = atoi(s);
6691 break;
6692 case '\r':
6693 i = p_ptr->target_idx[p_ptr->interactive_line];
6694 if (i >= 0)
6695 {
6696 /* Copy Base Kind */
6697 object_kind *k_ptr = &k_info[i];
6698 p_ptr->inventory[0].k_idx = i;
6699 p_ptr->inventory[0].tval = k_ptr->tval;
6700 p_ptr->inventory[0].sval = k_ptr->sval;
6701 p_ptr->inventory[0].pval = k_ptr->pval;
6702 p_ptr->inventory[0].ds = k_ptr->ds;
6703 p_ptr->inventory[0].dd = k_ptr->dd;
6704 p_ptr->inventory[0].name2 = 0;
6705 p_ptr->inventory[0].xtra2 = 0;
6706 p_ptr->inventory[0].origin = ORIGIN_CHEAT;
6707 p_ptr->inventory[0].origin_depth = p_ptr->dun_depth;
6708 p_ptr->inventory[0].origin_player = 0;
6709 if (is_dm_p(p_ptr)) p_ptr->inventory[0].origin = ORIGIN_FLOOR;
6710 }
6711 else
6712 {
6713 /* Assign Ego Kind */
6714 ego_item_type *e_ptr = &e_info[0 - i];
6715 for (j = 0; j < EGO_TVALS_MAX; j++)
6716 {
6717 if (p_ptr->inventory[0].tval == e_ptr->tval[j] &&
6718 p_ptr->inventory[0].tval >= e_ptr->min_sval[j] &&
6719 p_ptr->inventory[0].tval <= e_ptr->max_sval[j])
6720 {
6721 p_ptr->inventory[0].name2 = 0 - i;
6722 }
6723 }
6724 }
6725 break;
6726 }
6727 /* Hack -- refresh forge slot */
6728 p_ptr->redraw_inven |= (1 << 0);
6729 /* PREPARE */
6730 master_fill_objects(p_ptr, p_ptr->master_parm);
6731 p_ptr->interactive_size = p_ptr->target_n - 1;
6732 break;
6733 }
6734
6735 /* List Boundaries */
6736 if (p_ptr->interactive_line <= 0)
6737 p_ptr->interactive_line = 0;
6738 if (p_ptr->interactive_line > p_ptr->interactive_size)
6739 p_ptr->interactive_line = p_ptr->interactive_size;
6740
6741 /** Output **/
6742 clear_from(p_ptr, 0);
6743
6744 /* Header */
6745 for (i = 0, x = 3, y = 0; i < DM_PAGES; i++)
6746 {
6747 byte attr = TERM_SLATE;
6748 j = strlen(dm_pages[i]);
6749 if (x + j >= 80) { x = 3; y++; }
6750 if (i == p_ptr->interactive_next) attr = TERM_L_BLUE;
6751 c_prt(p_ptr, attr, dm_pages[i], y, x);
6752 x += j + 3;
6753 }
6754
6755 hgt = MAX(2, hgt - (y + 9));
6756
6757 skip_line = p_ptr->interactive_line - hgt / 2;
6758 if (skip_line < 0) skip_line = 0;
6759 if (skip_line > p_ptr->interactive_size - hgt)
6760 skip_line = p_ptr->interactive_size - hgt;
6761
6762 #define MASTER_COMMON_LIMIT() \
6763 byte attr = TERM_SLATE; \
6764 if (i < skip_line) continue; \
6765 if (j > hgt) break; \
6766 if (i == p_ptr->interactive_line) attr = TERM_L_BLUE
6767
6768 #define MASTER_DUMP_I() \
6769 strnfmt(numero, 4, "%03d ", i); \
6770 c_prt(p_ptr, attr, numero, 2 + j, 1);
6771
6772 #define MASTER_DUMP_AC(A,C) \
6773 numero[0] = (C); numero[1] = '\0'; \
6774 c_prt(p_ptr, (A), numero, 2 + j, 6);
6775
6776 #define OBJECT_TVAL_ATTR(O_PTR) \
6777 p_ptr->tval_attr[(O_PTR)->tval % 128]
6778
6779 /* Content */
6780 if (!access)
6781 {
6782 c_prt(p_ptr, TERM_RED, "Access Denied", 12, 33);
6783 }
6784 else
6785 {
6786 switch (p_ptr->interactive_next)
6787 {
6788 case DM_PAGE_WORLD:
6789
6790 c_prt(p_ptr, TERM_WHITE, "HELLO WORLD :)", 5, 5);
6791
6792 /* Sidebar */
6793 j = 2; numero[0] = '^'; numero[2] = ')'; numero[3] = '\0';
6794 c_prt(p_ptr, TERM_WHITE, "Quickbar: ", j++, 60);
6795 for (i = 0; i < DM_PAGES; i++)
6796 {
6797 numero[1] = dm_pages[i][0];
6798 c_prt(p_ptr, TERM_L_WHITE, numero, j, 59);
6799 c_prt(p_ptr, TERM_L_WHITE, dm_pages[i], j++, 62);
6800 }
6801 c_prt(p_ptr, TERM_L_WHITE, "@)Edit Self", j++, 60);
6802
6803 break;
6804
6805 case DM_PAGE_PLAYER:
6806
6807 for (i = 0, j = 0, y = 0; i < NumPlayers; i++)
6808 {
6809 player_type *q_ptr = Players[i+1];
6810 MASTER_COMMON_LIMIT();
6811 if (q_ptr->id == p_ptr->master_parm)
6812 {
6813 /* Selected */
6814 attr = TERM_WHITE;
6815 y = i+1;
6816 }
6817 numero[0] = (dm_flag_p(q_ptr,CAN_MUTATE_SELF) ? '@' :
6818 (dm_flag_p(q_ptr,CAN_ASSIGN) || is_dm_p(q_ptr) ? '%' :
6819 (q_ptr->dm_flags ? '+' : ' ')));
6820 numero[1] = '\0';
6821 c_prt(p_ptr, attr, numero, 2 + j, 1);
6822 c_prt(p_ptr, attr, q_ptr->name, 2 + j++, 3);
6823 }
6824
6825 p_ptr->interactive_size = NumPlayers - 1;
6826
6827 /* Footer (Selection) */
6828 if (y)
6829 {
6830 player_type *q_ptr = Players[y];
6831 if (2 + (j++) >= hgt) prompt_hooks = FALSE;
6832
6833 c_prt(p_ptr, (q_ptr->ghost ? TERM_WHITE : TERM_L_WHITE), "G) ghost", 2 + j, 0);
6834 c_prt(p_ptr, (q_ptr->noscore ? TERM_WHITE : TERM_L_WHITE), "C) cheater", 2 + j, 19);
6835 c_prt(p_ptr, (q_ptr->invuln ? TERM_WHITE : TERM_L_WHITE), "V) invuln", 2 + j - 1, 19);
6836
6837 c_prt(p_ptr, TERM_SLATE, "Actions: W)wrath K)kick I)invoke", 2 + j - 1, 38);
6838 c_prt(p_ptr, TERM_SLATE, format("Lite: -) %d +)", q_ptr->cur_lite), 2 + j, 38);
6839
6840 j++;
6841 for (i = 0, y = 0; i < 4; i++)
6842 {
6843 for (x = 0; x < 5; x++)
6844 {
6845 c_prt(p_ptr, (q_ptr->dm_flags & (0x1L << y) ? TERM_WHITE : TERM_L_WHITE), format("%c) %s",
6846 index_to_label(y+1), dm_flags_str[y]), 2 + j + x, i * 19);
6847
6848 y++;
6849 }
6850 }
6851 }
6852
6853 break;
6854
6855 case DM_PAGE_LEVEL:
6856 {
6857 #ifdef HAVE_DIRENT_H
6858 DIR *dip;
6859 struct dirent *dit;
6860 #endif
6861 int dun_players = players_on_depth[p_ptr->dun_depth];
6862 int num_players = count_players(p_ptr->dun_depth);
6863 #ifdef HAVE_DIRENT_H
6864 if ((dip = opendir(ANGBAND_DIR_SAVE)) != NULL)
6865 {
6866 for (i = 0, j = 0; (dit = readdir(dip)) != NULL; i++)
6867 {
6868 MASTER_COMMON_LIMIT();
6869
6870 if (my_strnicmp(dit->d_name, "server.", 7)) { i--; continue; }
6871
6872 MASTER_DUMP_I()
6873
6874 c_prt(p_ptr, attr, dit->d_name, 2 + j, 5);
6875 j++;
6876
6877 if (p_ptr->master_parm && p_ptr->master_parm - 1 == i)
6878 {
6879 msg_format(p_ptr, "Loading file '%s'", dit->d_name);
6880 rd_dungeon_special_ext(p_ptr->dun_depth, dit->d_name);
6881 players_on_depth[p_ptr->dun_depth] = num_players;
6882 }
6883 }
6884 closedir(dip); /* Don't care about error */
6885 }
6886 #else
6887 i = 1;
6888 #endif
6889 p_ptr->interactive_size = i - 1;
6890
6891 /* Sidebar */
6892 j = 2;
6893 c_prt(p_ptr, TERM_WHITE, "Action: ", j++, 60);
6894 c_prt(p_ptr, TERM_L_WHITE, "I)Import", j++, 60);
6895 c_prt(p_ptr, TERM_L_WHITE, "E)Export", j++, 60);
6896 c_prt(p_ptr, (dun_players > num_players ? TERM_WHITE : TERM_L_WHITE), "S)Static", j++, 60);
6897 c_prt(p_ptr, (dun_players <= num_players ? TERM_WHITE : TERM_L_WHITE), "U)Unstatic", j++, 60);
6898
6899 break;
6900 }
6901
6902 case DM_PAGE_FEATURE:
6903
6904 for (i = 0, j = 0; i < z_info->f_max; i++)
6905 {
6906 feature_type *f_ptr = &f_info[i];
6907
6908 MASTER_COMMON_LIMIT();
6909 MASTER_DUMP_I()
6910 MASTER_DUMP_AC(f_ptr->d_attr, f_ptr->d_char);
6911
6912 c_prt(p_ptr, attr, f_name + f_ptr->name, 2 + j++, 8);
6913 }
6914
6915 p_ptr->interactive_size = z_info->f_max - 1;
6916
6917 /* Sidebar */
6918 j = 2;
6919 c_prt(p_ptr, TERM_WHITE, "Quickbar: ", j++, 60);
6920 c_prt(p_ptr, TERM_L_WHITE, "f)floor", j++, 60);
6921 c_prt(p_ptr, TERM_L_WHITE, "w)wall", j++, 60);
6922 c_prt(p_ptr, TERM_L_WHITE, "p)permawall", j++, 60);
6923 c_prt(p_ptr, TERM_L_WHITE, "m)magmawall", j++, 60);
6924 c_prt(p_ptr, TERM_L_WHITE, "g)grass", j++, 60);
6925 c_prt(p_ptr, TERM_L_WHITE, "d)dirt", j++, 60);
6926 c_prt(p_ptr, TERM_L_WHITE, "T)evil t)tree", j++, 60);
6927
6928 break;
6929
6930 case DM_PAGE_MONSTER:
6931
6932 for (i = 0, j = 0; i < p_ptr->target_n; i++)
6933 {
6934 monster_race *r_ptr = &r_info[p_ptr->target_idx[i]];
6935
6936 MASTER_COMMON_LIMIT();
6937 MASTER_DUMP_I()
6938 MASTER_DUMP_AC(r_ptr->d_attr, r_ptr->d_char);
6939
6940 c_prt(p_ptr, attr, r_name + r_ptr->name, 2 + j++, 8);
6941 }
6942
6943 p_ptr->interactive_size = p_ptr->target_n - 1;
6944
6945 monster_race_track(p_ptr, p_ptr->target_idx[p_ptr->interactive_line]);
6946
6947 /* Sidebar */
6948 c_prt(p_ptr, TERM_WHITE, "Sort by: ", 2, 60);
6949 c_prt(p_ptr, (p_ptr->master_parm & SORT_UNIQUE ? TERM_WHITE : TERM_L_WHITE ), "u)unique ", 7, 60);
6950 c_prt(p_ptr, (p_ptr->master_parm & SORT_QUEST ? TERM_WHITE : TERM_L_WHITE ), "q)quest ", 8, 60);
6951 c_prt(p_ptr, (p_ptr->master_parm & SORT_RICH ? TERM_WHITE : TERM_L_WHITE ), "t)treasure ", 6, 60);
6952 c_prt(p_ptr, (p_ptr->master_parm & SORT_LEVEL ? TERM_WHITE : TERM_L_WHITE ), "d)depth ", 3, 60);
6953 c_prt(p_ptr, (p_ptr->master_parm & SORT_EXP ? TERM_WHITE : TERM_L_WHITE ), "e)exp ", 4, 60);
6954 c_prt(p_ptr, (p_ptr->master_parm & SORT_RARITY ? TERM_WHITE : TERM_L_WHITE ), "r)rarity ", 5, 60);
6955 c_prt(p_ptr, (p_ptr->master_parm & SORT_REVERS ? TERM_WHITE : TERM_L_WHITE ), "f)flip ", 9, 60);
6956 c_prt(p_ptr, TERM_WHITE, "Filter: ", 11, 60);
6957 c_prt(p_ptr, (p_ptr->master_parm & FILT_UNIQUE ? TERM_WHITE : TERM_L_WHITE ), "Q)unique ", 12, 60);
6958 c_prt(p_ptr, (p_ptr->master_parm & FILT_UNDEAD ? TERM_WHITE : TERM_L_WHITE ), "G)undead ", 13, 60);
6959 c_prt(p_ptr, (p_ptr->master_parm & FILT_DEMON ? TERM_WHITE : TERM_L_WHITE ), "U)demon ", 14, 60);
6960 c_prt(p_ptr, (p_ptr->master_parm & FILT_DRAGON ? TERM_WHITE : TERM_L_WHITE ), "D)dragon ", 15, 60);
6961 c_prt(p_ptr, (p_ptr->master_parm & FILT_ORC ? TERM_WHITE : TERM_L_WHITE ), "O)orc ", 16, 60);
6962 c_prt(p_ptr, (p_ptr->master_parm & FILT_ANIMAL ? TERM_WHITE : TERM_L_WHITE ), "A)animal ", 17, 60);
6963 c_prt(p_ptr, (p_ptr->master_parm & FILT_REVERS ? TERM_WHITE : TERM_L_WHITE ), "F)flip ", 18, 60);
6964
6965 break;
6966
6967 case DM_PAGE_VAULT:
6968
6969 for (i = 0, j = 0; i < z_info->v_max; i++)
6970 {
6971 vault_type *v_ptr = &v_info[i];
6972
6973 MASTER_COMMON_LIMIT();
6974 MASTER_DUMP_I()
6975 MASTER_DUMP_AC(v_ptr->typ, (v_ptr->typ == 8 ? 'G' : (v_ptr->typ == 7 ? 'L' : '?')));
6976
6977 c_prt(p_ptr, attr, v_name + v_ptr->name, 2 + j++, 8);
6978 }
6979
6980 p_ptr->interactive_size = z_info->v_max - 1;
6981
6982 if (old_line != p_ptr->interactive_line)
6983 preview_vault(p_ptr, p_ptr->interactive_line);
6984
6985 break;
6986
6987 case DM_PAGE_ITEM:
6988
6989 for (i = 0, j = 0; i < p_ptr->target_n; i++)
6990 {
6991 MASTER_COMMON_LIMIT();
6992 MASTER_DUMP_I()
6993
6994 if (p_ptr->target_idx[i] >= 0)
6995 {
6996 /* Base Kind */
6997 object_kind *k_ptr = &k_info[p_ptr->target_idx[i]];
6998 byte obj_attr = k_ptr->flavor ? flavor_info[k_ptr->flavor].d_attr : k_ptr->d_attr;
6999 MASTER_DUMP_AC(obj_attr, k_ptr->d_char);
7000 c_prt(p_ptr, attr, k_name + k_ptr->name, 2 + j++, 8);
7001 }
7002 else
7003 {
7004 /* Ego Item */
7005 ego_item_type *e_ptr = &e_info[0 - p_ptr->target_idx[i]];
7006 for (x = 0; x < EGO_TVALS_MAX; x++)
7007 {
7008 numero[1] = '\0';
7009 numero[0] = p_ptr->tval_char[e_ptr->tval[x]];
7010 c_prt(p_ptr, p_ptr->tval_attr[e_ptr->tval[x]], numero, 2 + j, 5 + x);
7011 }
7012 c_prt(p_ptr, attr, e_name + e_ptr->name, 2 + j++, 9);
7013 }
7014 }
7015
7016 p_ptr->interactive_size = p_ptr->target_n - 1;
7017
7018 if (1) /* ? Display Object even if it's buggy ? */
7019 {
7020 j++;
7021 prompt_hooks = FALSE;
7022 /* Extract Name */
7023 object_desc(p_ptr, buf, sizeof(buf), &p_ptr->inventory[0], TRUE, 3);
7024
7025 /* Print it */
7026 c_prt(p_ptr, OBJECT_TVAL_ATTR(&p_ptr->inventory[0]), buf, 2 + j++, 1);
7027
7028 /* Obtain XTRA2 modifier */
7029 if (p_ptr->inventory[0].name2)
7030 {
7031 ego_item_type *e_ptr = &e_info[p_ptr->inventory[0].name2];
7032 int xtra_mod = 0;
7033 byte xtra_val = 0;
7034
7035 if (e_ptr->xtra == EGO_XTRA_SUSTAIN) { xtra_val = 1; xtra_mod = OBJECT_XTRA_SIZE_SUSTAIN; }
7036 else if (e_ptr->xtra == EGO_XTRA_POWER ) { xtra_val = 2; xtra_mod = OBJECT_XTRA_SIZE_RESIST; }
7037 else if (e_ptr->xtra == EGO_XTRA_ABILITY) { xtra_val = 3; xtra_mod = OBJECT_XTRA_SIZE_POWER; }
7038 else { xtra_val = 0; xtra_mod = 1; }
7039 if (p_ptr->inventory[0].xtra2 >= xtra_mod) p_ptr->inventory[0].xtra2 %= xtra_mod;
7040 c_prt(p_ptr, TERM_L_WHITE, "Hidden Abilitiy: ", 2 + j, 1);
7041 c_prt(p_ptr, TERM_L_WHITE, extra_mods[xtra_val][p_ptr->inventory[0].xtra2], 2 + j++, 18);
7042 }
7043 }
7044
7045 /* Sidebar */
7046 j = 2;
7047 c_prt(p_ptr, TERM_WHITE, "Action: ", j++, 60);
7048 c_prt(p_ptr, TERM_L_WHITE, "n)number", j++, 60);
7049 c_prt(p_ptr, TERM_L_WHITE, "r)ac R)to ac", j++, 60);
7050 c_prt(p_ptr, TERM_L_WHITE, "D)dice ", j++, 60);
7051 c_prt(p_ptr, TERM_L_WHITE, "to h)it d)am", j++, 60);
7052 c_prt(p_ptr, TERM_L_WHITE, "p)pval ", j++, 60);
7053 c_prt(p_ptr, TERM_L_WHITE, "e/E)ability ", j++, 60);
7054 j++;
7055 c_prt(p_ptr, TERM_WHITE, "Filter: ", j++, 60);
7056 c_prt(p_ptr, (p_ptr->master_parm & FILT_EGO ? TERM_WHITE : TERM_L_WHITE ), "*)ego ", j++, 60);
7057 c_prt(p_ptr, (p_ptr->master_parm & FILT_WEAPON ? TERM_WHITE : TERM_L_WHITE ), "|)weapon ", j++, 60);
7058 c_prt(p_ptr, (p_ptr->master_parm & FILT_GEAR ? TERM_WHITE : TERM_L_WHITE ), "])armor ", j++, 60);
7059 c_prt(p_ptr, (p_ptr->master_parm & FILT_MAGIC ? TERM_WHITE : TERM_L_WHITE ), "-)magic ", j++, 60);
7060 c_prt(p_ptr, (p_ptr->master_parm & FILT_SCROLL ? TERM_WHITE : TERM_L_WHITE ), "?)scroll ", j++, 60);
7061 c_prt(p_ptr, (p_ptr->master_parm & FILT_POTION ? TERM_WHITE : TERM_L_WHITE ), "!)potion ", j++, 60);
7062 c_prt(p_ptr, (p_ptr->master_parm & FILT_FOOD ? TERM_WHITE : TERM_L_WHITE ), ",)food ", j++, 60);
7063 c_prt(p_ptr, (p_ptr->master_parm & FILT_REVERS ? TERM_WHITE : TERM_L_WHITE ), "F)flip ", j++, 60);
7064
7065 break;
7066 }
7067 }
7068
7069 /** Common: **/
7070 /* Error */
7071 if (error)
7072 {
7073 c_prt(p_ptr, TERM_RED, error, 1, 1);
7074 }
7075
7076 /* Footer */
7077 if (prompt_hooks)
7078 {
7079 j = hgt + 5;
7080 c_prt(p_ptr, TERM_L_DARK, "RET) Select |", j++, 1);
7081 c_prt(p_ptr, TERM_L_DARK, "SPC) Next |", j++, 1);
7082 c_prt(p_ptr, TERM_L_DARK, "DEL) Clear |", j++, 1);
7083 c_prt(p_ptr, TERM_L_DARK, "ESC) Done |", j++, 1);
7084 j -= 4;
7085 for (i = 0; i < MASTER_MAX_HOOKS; i++)
7086 {
7087 byte attr = TERM_L_WHITE;
7088 if (!p_ptr->master_hook[i]) attr = TERM_L_DARK;
7089 if (i == p_ptr->master_flag) attr = TERM_L_BLUE;
7090 master_hook_desc(&buf[0], i, p_ptr->master_hook[i], p_ptr->master_args[i]);
7091 c_prt(p_ptr, attr, buf, j, 20);
7092 j++;
7093 }
7094 }
7095
7096 /* STREAM_SPECIAL_TEXT is defined as being "20" rows of height. The reason for this
7097 * is that we use it on client-side "file perusal", which eats out 4 rows.
7098 * (It shows the header, i.e. "Known Uniques" and a footer "[press space to avance]"
7099 * and "borders" around those, so, 4 rows.)
7100 *
7101 * However, for the DM menu we want all the lines we can get. So I'm adding 2 more.
7102 * As far as I can tell, this SHOULD NOT and CAN NOT work. But for some reason it does,
7103 * so there we go. Probably mangling some buffers in the process, and probably will
7104 * stop working in the future.
7105 */
7106 #define WEIRD_EXTRA_HACK 2
7107
7108 /* Send */
7109 send_term_info(p_ptr, NTERM_CLEAR, 0);
7110 for (i = 0; i < p_ptr->stream_hgt[STREAM_SPECIAL_TEXT] + WEIRD_EXTRA_HACK; i++)
7111 {
7112 Stream_line_p(p_ptr, STREAM_SPECIAL_MIXED, i);
7113 }
7114 send_term_info(p_ptr, NTERM_FLUSH | NTERM_CLEAR | NTERM_ICKY, 0);
7115
7116 }
7117
7118 /* Hack -- describe currently used hooks as fake status line */
master_desc_all(player_type * p_ptr)7119 void master_desc_all(player_type *p_ptr)
7120 {
7121 byte ok[MASTER_MAX_HOOKS];
7122 int i, n = 0, l, j = p_ptr->screen_hgt+1;
7123 char buf[80];
7124
7125 for (i = 0; i < MASTER_MAX_HOOKS; i++)
7126 {
7127 if (p_ptr->master_hook[i]) ok[n++] = i;
7128 }
7129 if (!n) return;
7130
7131 l = p_ptr->screen_wid / n;
7132 if (l <= 0) return;
7133
7134 clear_line(p_ptr, j);
7135 for (i = 0; i < n; i++)
7136 {
7137 master_hook_desc(&buf[0], ok[i], p_ptr->master_hook[ok[i]], p_ptr->master_args[ok[i]]);
7138 buf[l] = '\0';
7139 c_prt(p_ptr, (p_ptr->master_flag == ok[i] ? TERM_WHITE : (i % 2 ? TERM_SLATE : TERM_L_DARK)), buf, j, i * (l+1));
7140 }
7141 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_SPECIAL);
7142 Stream_line_p(p_ptr, STREAM_SPECIAL_TEXT, j);
7143 send_term_info(p_ptr, NTERM_FLUSH, j);
7144 send_term_info(p_ptr, NTERM_ACTIVATE, NTERM_WIN_OVERHEAD);
7145 }
7146
7147 /* Auxilary functon for "master_new_hook", performs actual action */
master_new_hook_aux(player_type * p_ptr,byte hook_type,s16b oy,s16b ox)7148 void master_new_hook_aux(player_type *p_ptr, byte hook_type, s16b oy, s16b ox)
7149 {
7150 int Depth = p_ptr->dun_depth;
7151
7152 /* Hack -- Delete Monster/Object */
7153 if (hook_type == 127)
7154 {
7155 cave_type *c_ptr = &cave[Depth][oy][ox];
7156 if (dm_flag_p(p_ptr, CAN_GENERATE) ||
7157 dm_flag_p(p_ptr, OBJECT_CONTROL))
7158 {
7159 delete_object(Depth, oy, ox);
7160 }
7161 if (c_ptr->m_idx > 0 && dm_flag_p(p_ptr, CAN_SUMMON))
7162 {
7163 delete_monster_idx(c_ptr->m_idx);
7164 }
7165 everyone_lite_spot(Depth, oy, ox);
7166 return;
7167 }
7168
7169 switch(p_ptr->master_hook[hook_type])
7170 {
7171 case DM_PAGE_VAULT:
7172 {
7173 vault_type *v_ptr = &v_info[p_ptr->master_args[hook_type]];
7174 if (dm_flag_p(p_ptr, CAN_GENERATE))
7175 build_vault(Depth, oy, ox, v_ptr->hgt, v_ptr->wid, v_text + v_ptr->text);
7176 break;
7177 }
7178 case DM_PAGE_FEATURE:
7179 {
7180 cave_type *c_ptr = &cave[Depth][oy][ox];
7181 if (dm_flag_p(p_ptr, CAN_BUILD))
7182 c_ptr->feat = (byte)p_ptr->master_args[hook_type];
7183 break;
7184 }
7185 case DM_PAGE_MONSTER:
7186 {
7187 if (dm_flag_p(p_ptr, CAN_SUMMON))
7188 place_monster_aux(Depth, oy, ox, p_ptr->master_args[hook_type], FALSE, TRUE);
7189 }
7190 break;
7191 }
7192
7193 everyone_lite_spot(Depth, oy, ox);
7194
7195 }
7196 /*
7197 * New dungeon master hook function. Determines hook type, selects a brush,
7198 * does some hacky things such as selection and copy & paste and actually
7199 * calls "master_new_hook_aux".
7200 */
master_new_hook(player_type * p_ptr,char hook_q,s16b oy,s16b ox)7201 void master_new_hook(player_type *p_ptr, char hook_q, s16b oy, s16b ox)
7202 {
7203 int Depth = p_ptr->dun_depth;
7204
7205 cave_type *c_ptr = &cave[Depth][oy][ox];
7206 byte hook_type = 0;
7207 byte x1, x2, y1, y2, xs, ys;
7208
7209 #define MASTER_CONFIRM_AC(A,C,Y,X) \
7210 Send_tile(p_ptr, (X) - p_ptr->panel_col_min, (Y) - p_ptr->panel_row_min, (A), (C), (A), (C))
7211
7212 /* Find selection */
7213 if (p_ptr->master_parm & MASTER_SELECT)
7214 {
7215 xs = (p_ptr->master_parm >> 0) & 0xFF;
7216 ys = (p_ptr->master_parm >> 8) & 0xFF;
7217 if (ys <= oy)
7218 { y1 = ys; y2 = oy; }
7219 else { y1 = oy; y2 = ys; }
7220 if (xs <= ox)
7221 { x1 = xs; x2 = ox; }
7222 else { x1 = ox; x2 = xs; }
7223 }
7224
7225 switch (hook_q)
7226 {
7227 case 'k': case 127: case '\b': hook_type = 128; break; /* Del */
7228 case 's': /* Select */
7229
7230 p_ptr->master_parm = (MASTER_SELECT | (u32b)ox | ((u32b)oy << 8));
7231
7232 MASTER_CONFIRM_AC(TERM_YELLOW, '&', oy, ox);
7233
7234 break;
7235 case 'c': /* Pick */
7236
7237 if (p_ptr->master_parm & MASTER_SELECT)
7238 {
7239 p_ptr->master_hook[3] = DM_PAGE_PLOT;
7240 p_ptr->master_args[3] = ((u32b)x1 | ((u32b)y1 << 8) | ((u32b)x2 << 16) | ((u32b)y2 << 24));
7241
7242 MASTER_CONFIRM_AC(TERM_YELLOW, '&', ys, xs);
7243 MASTER_CONFIRM_AC(TERM_YELLOW, '&', ys, ox);
7244 MASTER_CONFIRM_AC(TERM_YELLOW, '&', oy, xs);
7245 }
7246 else
7247 {
7248 if (c_ptr->m_idx > 0)
7249 {
7250 p_ptr->master_hook[3] = DM_PAGE_MONSTER;
7251 p_ptr->master_args[3] = m_list[c_ptr->m_idx].r_idx;
7252 }
7253 else
7254 {
7255 p_ptr->master_hook[3] = DM_PAGE_FEATURE;
7256 p_ptr->master_args[3] = c_ptr->feat;
7257 }
7258 }
7259
7260 MASTER_CONFIRM_AC(TERM_YELLOW, '^', oy, ox);
7261 p_ptr->master_parm = 0;
7262
7263 break;
7264 case 'x': hook_type = 1; break;
7265 case 'a': hook_type = 2; break;
7266 case 'v': hook_type = 4; break;
7267 case 'z': TOGGLE_BIT(p_ptr->master_parm, MASTER_BRUSH); break;
7268 default: if (p_ptr->master_parm & MASTER_BRUSH) hook_type = 3; break; /* z */
7269 }
7270
7271 /* Success */
7272 if (hook_type--)
7273 {
7274 if ((hook_type <= MASTER_MAX_HOOKS)
7275 && (p_ptr->master_hook[hook_type] == DM_PAGE_PLOT))
7276 {
7277 byte old_hook = p_ptr->master_hook[hook_type];
7278 u32b old_args = p_ptr->master_args[hook_type];
7279 s16b tmp;
7280
7281 x1 = (old_args >> 0) & 0xFF;
7282 y1 = (old_args >> 8) & 0xFF;
7283 x2 = (old_args >> 16) & 0xFF;
7284 y2 = (old_args >> 24);
7285
7286 ox = ox - x1;
7287 oy = oy - y1;
7288
7289 if ((tmp = MAX_WID - 2 - x2 - ox) < 0) x2 += tmp;
7290 if ((tmp = MAX_HGT - 2 - y2 - oy) < 0) y2 += tmp;
7291
7292 p_ptr->master_parm = 0;
7293
7294 for (ys = y1; ys <= y2; ys++)
7295 {
7296 for (xs = x1; xs <= x2; xs++)
7297 {
7298 master_new_hook(p_ptr, 'c', ys, xs);
7299 master_new_hook_aux(p_ptr, hook_type, ys+oy, xs+ox);
7300 }
7301 }
7302 p_ptr->master_hook[hook_type] = old_hook;
7303 p_ptr->master_args[hook_type] = old_args;
7304 }
7305 else if (p_ptr->master_parm & MASTER_SELECT)
7306 {
7307 for (ys = y1; ys <= y2; ys++)
7308 {
7309 for (xs = x1; xs <= x2; xs++)
7310 {
7311 master_new_hook_aux(p_ptr, hook_type, ys, xs);
7312 }
7313 }
7314
7315 MASTER_CONFIRM_AC(TERM_YELLOW, '#', y1, x1);
7316 MASTER_CONFIRM_AC(TERM_YELLOW, '#', y2, x2);
7317
7318 p_ptr->master_parm = 0;
7319 }
7320 else
7321 {
7322 master_new_hook_aux(p_ptr, hook_type, oy, ox);
7323 }
7324 }
7325 master_desc_all(p_ptr);
7326 }
7327