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