1 
2 /* File: maid-grf.c */
3 
4 /* Purpose: Interface for graphical ports */
5 
6 /*
7  * Copyright (c) 2002 S. Fuerst
8  *
9  * This software may be copied and distributed for educational, research, and
10  * not for profit purposes provided that this copyright and statement are
11  * included in all such copies.
12  */
13 
14 #include "angband.h"
15 #include "maid-grf.h"
16 
17 #ifdef SUPPORT_GAMMA
18 
19 /* Table of gamma values */
20 byte gamma_table[256];
21 
22 /* Table of ln(x/256) * 256 for x going from 0 -> 255 */
23 static const s16b gamma_helper[256] =
24 {
25 	0, -1420, -1242, -1138, -1065, -1007, -961, -921, -887, -857, -830, -806,
26 	-783, -762, -744, -726,
27 	-710, -694, -679, -666, -652, -640, -628, -617, -606, -596, -586, -576,
28 	-567, -577, -549, -541,
29 	-532, -525, -517, -509, -502, -495, -488, -482, -475, -469, -463, -457,
30 	-451, -455, -439, -434,
31 	-429, -423, -418, -413, -408, -403, -398, -394, -389, -385, -380, -376,
32 	-371, -367, -363, -359,
33 	-355, -351, -347, -343, -339, -336, -332, -328, -325, -321, -318, -314,
34 	-311, -308, -304, -301,
35 	-298, -295, -291, -288, -285, -282, -279, -276, -273, -271, -268, -265,
36 	-262, -259, -257, -254,
37 	-251, -248, -246, -243, -241, -238, -236, -233, -231, -228, -226, -223,
38 	-221, -219, -216, -214,
39 	-212, -209, -207, -205, -203, -200, -198, -196, -194, -192, -190, -188,
40 	-186, -184, -182, -180,
41 	-178, -176, -174, -172, -170, -168, -166, -164, -162, -160, -158, -156,
42 	-155, -153, -151, -149,
43 	-147, -146, -144, -142, -140, -139, -137, -135, -134, -132, -130, -128,
44 	-127, -125, -124, -122,
45 	-120, -119, -117, -116, -114, -112, -111, -109, -108, -106, -105, -103,
46 	-102, -100, -99, -97,
47 	-96, -95, -93, -92, -90, -89, -87, -86, -85, -83, -82, -80, -79, -78, -76,
48 	-75,
49 	-74, -72, -71, -70, -68, -67, -66, -65, -63, -62, -61, -59, -58, -57, -56,
50 	-54,
51 	-53, -52, -51, -50, -48, -47, -46, -45, -44, -42, -41, -40, -39, -38, -37,
52 	-35,
53 	-34, -33, -32, -31, -30, -29, -27, -26, -25, -24, -23, -22, -21, -20, -19,
54 	-18,
55 	-17, -16, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
56 };
57 
58 
59 /*
60  * Build the gamma table so that floating point isn't needed.
61  *
62  *  ANGBAND_X11_GAMMA is
63  * 256 * (1 / gamma), rounded to integer. A recommended value
64  * is 183, which is an approximation of the Macintosh hardware
65  * gamma of 1.4.
66  *
67  *   gamma	ANGBAND_X11_GAMMA
68  *   -----	-----------------
69  *   1.2	213
70  *   1.25	205
71  *   1.3	197
72  *   1.35	190
73  *   1.4	183
74  *   1.45	177
75  *   1.5	171
76  *   1.6	160
77  *   1.7	151
78  *   ...
79  *
80  * XXX XXX The environment variable, or better,
81  * the interact with colours command should allow users
82  * to specify gamma values (or gamma value * 100).
83  */
build_gamma_table(int gamma)84 void build_gamma_table(int gamma)
85 {
86 	int i, n;
87 
88 	/*
89 	 * value is the current sum.
90 	 * diff is the new term to add to the series.
91 	 */
92 	long value, diff;
93 
94 	/* Paranoia */
95 	if (gamma < 0) gamma = 0;
96 	if (gamma > 255) gamma = 255;
97 
98 	/* Hack - convergence is bad in these cases. */
99 	gamma_table[0] = 0;
100 	gamma_table[255] = 255;
101 
102 	for (i = 1; i < 255; i++)
103 	{
104 		/*
105 		 * Initialise the Taylor series
106 		 *
107 		 * value and diff have been scaled by 256
108 		 */
109 
110 		n = 1;
111 		value = 256 * 256;
112 		diff = ((long)gamma_helper[i]) * (gamma - 256);
113 
114 		while (diff)
115 		{
116 			value += diff;
117 			n++;
118 
119 			/*
120 			 * Use the following identiy to calculate the gamma table.
121 			 * exp(x) = 1 + x + x^2/2 + x^3/(2*3) + x^4/(2*3*4) +...
122 			 *
123 			 * n is the current term number.
124 			 *
125 			 * The gamma_helper array contains a table of
126 			 * ln(x/256) * 256
127 			 * This is used because a^b = exp(b*ln(a))
128 			 *
129 			 * In this case:
130 			 * a is i / 256
131 			 * b is gamma.
132 			 *
133 			 * Note that everything is scaled by 256 for accuracy,
134 			 * plus another factor of 256 for the final result to
135 			 * be from 0-255.  Thus gamma_helper[] * gamma must be
136 			 * divided by 256*256 each iteration, to get back to
137 			 * the original power series.
138 			 */
139 			diff = (((diff / 256) * gamma_helper[i]) *
140 					(gamma - 256)) / (256 * n);
141 		}
142 
143 		/*
144 		 * Store the value in the table so that the
145 		 * floating point pow function isn't needed.
146 		 */
147 		gamma_table[i] = ((long)(value / 256) * i) / 256;
148 	}
149 }
150 
151 #endif /* SUPPORT_GAMMA */
152 
153 /*
154  * Get the name of the default font to use for the term.
155  */
get_default_font(int term_num)156 cptr get_default_font(int term_num)
157 {
158 	cptr font;
159 
160 	char buf[80];
161 
162 	/* Window specific font name */
163 	strnfmt(buf, 80, "ANGBAND_X11_FONT_%d", term_num);
164 
165 	/* Check environment for that font */
166 	font = getenv(buf);
167 
168 	/* Check environment for "base" font */
169 	if (!font) font = getenv("ANGBAND_X11_FONT");
170 
171 	/* No environment variables, use default font */
172 	if (!font)
173 	{
174 		switch (term_num)
175 		{
176 			case 0:
177 			{
178 				font = DEFAULT_X11_FONT_0;
179 				break;
180 			}
181 			case 1:
182 			{
183 				font = DEFAULT_X11_FONT_1;
184 				break;
185 			}
186 			case 2:
187 			{
188 				font = DEFAULT_X11_FONT_2;
189 				break;
190 			}
191 			case 3:
192 			{
193 				font = DEFAULT_X11_FONT_3;
194 				break;
195 			}
196 			case 4:
197 			{
198 				font = DEFAULT_X11_FONT_4;
199 				break;
200 			}
201 			case 5:
202 			{
203 				font = DEFAULT_X11_FONT_5;
204 				break;
205 			}
206 			case 6:
207 			{
208 				font = DEFAULT_X11_FONT_6;
209 				break;
210 			}
211 			case 7:
212 			{
213 				font = DEFAULT_X11_FONT_7;
214 				break;
215 			}
216 			default:
217 			{
218 				font = DEFAULT_X11_FONT;
219 			}
220 		}
221 	}
222 
223 	return (font);
224 }
225 
226 #ifdef USE_GRAPHICS
227 /*
228  * Make sure the graphical tiles we want are available.
229  *
230  * Note - we _must_ be passed an array 1024 in size for the filename.
231  */
pick_graphics(int graphics,int * xsize,int * ysize,char * filename)232 bool pick_graphics(int graphics, int *xsize, int *ysize, char *filename)
233 {
234 	int old_graphics = use_graphics;
235 
236 	use_graphics = GRAPHICS_NONE;
237 	use_transparency = FALSE;
238 
239 	if ((graphics == GRAPHICS_ANY) || (graphics == GRAPHICS_DAVID_GERVAIS))
240 	{
241 		/* Try the "32x32.bmp" file */
242 		path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/32x32.bmp");
243 
244 		/* Use the "32x32.bmp" file if it exists */
245 		if (0 == fd_close(fd_open(filename, O_RDONLY)))
246 		{
247 			use_transparency = TRUE;
248 
249 			*xsize = 32;
250 			*ysize = 32;
251 		}
252 
253 		use_graphics = GRAPHICS_DAVID_GERVAIS;
254 
255 		/* Did we change the graphics? */
256 		return (old_graphics != use_graphics);
257 	}
258 
259 	/* We failed, or we want 16x16 graphics */
260 	if ((graphics == GRAPHICS_ANY) || (graphics == GRAPHICS_ADAM_BOLT) ||
261 		 (graphics == GRAPHICS_HALF_3D))
262 	{
263 		/* Try the "16x16.bmp" file */
264 		path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/16x16.bmp");
265 
266 		/* Use the "16x16.bmp" file if it exists */
267 		if (0 == fd_close(fd_open(filename, O_RDONLY)))
268 		{
269 			use_transparency = TRUE;
270 
271 			*xsize = 16;
272 			*ysize = 16;
273 
274 			/* Use graphics */
275 			if (graphics == GRAPHICS_HALF_3D)
276 			{
277 				use_graphics = GRAPHICS_HALF_3D;
278 			}
279 			else
280 			{
281 				use_graphics = GRAPHICS_ADAM_BOLT;
282 			}
283 
284 			/* Did we change the graphics? */
285 			return (old_graphics != use_graphics);
286 		}
287 	}
288 
289 	/* We failed, or we want 8x8 graphics */
290 	if ((graphics == GRAPHICS_ANY) || (graphics == GRAPHICS_ORIGINAL))
291 	{
292 		/* Try the "8x8.bmp" file */
293 		path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/8x8.bmp");
294 
295 		/* Use the "8x8.bmp" file if it exists */
296 		if (0 == fd_close(fd_open(filename, O_RDONLY)))
297 		{
298 			/* Use graphics */
299 			use_graphics = GRAPHICS_ORIGINAL;
300 
301 			*xsize = 8;
302 			*ysize = 8;
303 		}
304 	}
305 
306 	/* Did we change the graphics? */
307 	return (old_graphics != use_graphics);
308 }
309 
310 /*
311  * Is a square in a bigtiled region?
312  */
is_bigtiled(int x,int y)313 bool is_bigtiled(int x, int y)
314 {
315 	if ((use_bigtile)
316 		&& (y >= Term->scr->big_y1)
317 		&& (y <= Term->scr->big_y2)
318 		&& (x >= Term->scr->big_x1))
319 	{
320 		return (TRUE);
321 	}
322 
323 	return (FALSE);
324 }
325 
toggle_bigtile(void)326 void toggle_bigtile(void)
327 {
328 	if (use_bigtile)
329 	{
330 		/* Hack - disable bigtile mode */
331 		Term_bigregion(-1, -1, -1);
332 
333 		use_bigtile = FALSE;
334 	}
335 	else
336 	{
337 		use_bigtile = TRUE;
338 	}
339 
340 	/* Hack - redraw everything + recalc bigtile regions */
341 	angband_term[0]->resize_hook();
342 }
343 
344 #endif /* USE_GRAPHICS */
345 
346 
347 /*
348  * The callbacks
349  */
350 static callback_list *callbacks[CALL_MAX];
351 
352 /*
353  * Initialise the callbacks
354  */
init_term_callbacks(void)355 void init_term_callbacks(void)
356 {
357 	/* Wipe the array */
358 	(void) C_WIPE(callbacks, CALL_MAX, callback_list *);
359 }
360 
361 /*
362  * Free the callbacks
363  */
free_term_callbacks(void)364 void free_term_callbacks(void)
365 {
366 	int i;
367 	callback_list *p, *p_next;
368 
369 	for (i = 0; i < CALL_MAX; i++)
370 	{
371 		p = callbacks[i];
372 
373 		while (p)
374 		{
375 			p_next = p->next;
376 			FREE(p);
377 			p = p_next;
378 		}
379 	}
380 }
381 
382 /*
383  * Register a callback
384  */
set_callback(callback_type call_func,int number,vptr data)385 void set_callback(callback_type call_func, int number, vptr data)
386 {
387 	/* Create a new callback */
388 	callback_list *node;
389 
390 	MAKE(node, callback_list);
391 
392 	/* Save information into node */
393 	node->next = callbacks[number];
394 	node->data = data;
395 	node->func = call_func;
396 
397 	/* Insert at the head of the list */
398 	callbacks[number] = node;
399 }
400 
del_callback(int number,vptr data)401 void del_callback(int number, vptr data)
402 {
403 	callback_list **p;
404 	callback_list *temp;
405 
406 	p = &callbacks[number];
407 
408 	/* Scan the list */
409 	while (*p)
410 	{
411 		/* A match? */
412 		if ((*p)->data == data)
413 		{
414 			/* Delete this node */
415 			temp = *p;
416 			*p = (*p)->next;
417 			FREE(temp);
418 
419 			return;
420 		}
421 
422 		/* Point to next node */
423 		p = &((*p)->next);
424 	}
425 
426 	quit("Callback does not exist");
427 }
428 
429 /*
430  * Code for the overhead mini-map
431  *
432  * This is used by the borg to store the map information.
433  * It is used by some ports to display a mini-map.  It
434  * is used by the tk port to display nearly everything.
435  *
436  * It is also used by the "overhead map" term type.
437  */
438 
439 
440 /* List of 16x16 blocks for the overhead map */
441 map_blk_ptr_ptr *map_cache;
442 
443 /* Refcount for map cache */
444 s16b *map_cache_refcount;
445 
446 /* Location of cache blocks */
447 int *map_cache_x;
448 int *map_cache_y;
449 
450 /* The map itself - grid of 16x16 blocks*/
451 int **map_grid;
452 
453 /* Player location */
454 static int player_x = 0;
455 static int player_y = 0;
456 
457 /*
458  * Access the player location
459  */
map_get_player(int * x,int * y)460 void map_get_player(int *x, int *y)
461 {
462 	*x = player_x;
463 	*y = player_y;
464 }
465 
466 /*
467  * Clear the map when changing a level.
468  */
clear_map(void)469 static void clear_map(void)
470 {
471 	int i, j;
472 
473 	/* Erase the map */
474 	for (i = 0; i < WILD_SIZE; i++)
475 	{
476 		for (j = 0; j < WILD_SIZE; j++)
477 		{
478 			/* Set unused */
479 			map_grid[i][j] = -1;
480 		}
481 	}
482 
483 	/* Erase the cache */
484 	for (i = 0; i < MAP_CACHE; i++)
485 	{
486 		map_cache_refcount[i] = 0;
487 
488 		/* Flag that the block isn't used */
489 		map_cache_x[i] = -1;
490 	}
491 }
492 
493 /*
494  * Create the map information
495  */
init_overhead_map(void)496 void init_overhead_map(void)
497 {
498 	int i, j;
499 
500 	/* Make the list of pointers to blocks */
501 	C_MAKE(map_cache, MAP_CACHE, map_blk_ptr_ptr);
502 
503 	/* Refcount for cache blocks */
504 	C_MAKE(map_cache_refcount, MAP_CACHE, s16b);
505 
506 	/* Cache block locations */
507 	C_MAKE(map_cache_x, MAP_CACHE, int);
508 	C_MAKE(map_cache_y, MAP_CACHE, int);
509 
510 	/* Allocate each block */
511 	for (i = 0; i < MAP_CACHE; i++)
512 	{
513 		/* Allocate block */
514 		C_MAKE(map_cache[i], WILD_BLOCK_SIZE, map_blk_ptr);
515 
516 		/* Allocate rows of a block */
517 		for (j = 0; j < WILD_BLOCK_SIZE; j++)
518 		{
519 			C_MAKE(map_cache[i][j], WILD_BLOCK_SIZE, map_block);
520 		}
521 	}
522 
523 	/* Allocate the overhead map itself */
524 	C_MAKE(map_grid, WILD_SIZE, int *);
525 
526 	for (i = 0; i < WILD_SIZE; i++)
527 	{
528 		/* Allocate one row of the wilderness */
529 		C_MAKE(map_grid[i], WILD_SIZE, int);
530 	}
531 
532 	/* Initialize */
533 	clear_map();
534 }
535 
536 /*
537  * Delete the overhead map
538  */
del_overhead_map(void)539 void del_overhead_map(void)
540 {
541 	int i, j;
542 
543 	/* Free refcount for cache blocks */
544 	FREE(map_cache_refcount);
545 
546 	/* Cache block locations */
547 	FREE(map_cache_x);
548 	FREE(map_cache_y);
549 
550 	/* Delete each block */
551 	for (i = 0; i < MAP_CACHE; i++)
552 	{
553 		/* Deallocate rows of a block */
554 		for (j = 0; j < WILD_BLOCK_SIZE; j++)
555 		{
556 			FREE(map_cache[i][j]);
557 		}
558 
559 		/* Free block */
560 		FREE(map_cache[i]);
561 	}
562 
563 	/* Free the list of pointers to blocks */
564 	FREE(map_cache);
565 
566 	for (i = 0; i < WILD_SIZE; i++)
567 	{
568 		/* Free one row of the wilderness */
569 		FREE(map_grid[i]);
570 	}
571 
572 	/* Free the overhead map itself */
573 	FREE(map_grid);
574 }
575 
576 
577 /*
578  * Erase a block
579  */
clear_block(int block)580 static void clear_block(int block)
581 {
582 	int i, j;
583 
584 	map_block *mb_ptr;
585 
586 	/* Wipe each square */
587 	for (i = 0; i < WILD_BLOCK_SIZE; i++)
588 	{
589 		for (j = 0; j < WILD_BLOCK_SIZE; j++)
590 		{
591 			mb_ptr = &map_cache[block][i][j];
592 
593 			(void)WIPE(mb_ptr, map_block);
594 		}
595 	}
596 
597 	/* Was this used? */
598 	if (map_cache_x[block] != -1)
599 	{
600 		/* Mark map block as unused */
601 		map_grid[map_cache_y[block]][map_cache_x[block]] = -1;
602 
603 		/* Set "unused block" flag */
604 		map_cache_x[block] = -1;
605 	}
606 }
607 
608 
609 /*
610  * Find an empty block to use
611  */
get_empty_block(void)612 static int get_empty_block(void)
613 {
614 	int i;
615 	int dist, best_dist = 0;
616 	int best_block = 0;
617 
618 	int px, py;
619 
620 	/* Get player block location */
621 	px = player_x / 16;
622 	py = player_y / 16;
623 
624 	/* Scan for a used but out of los block */
625 	for (i = 0; i < MAP_CACHE; i++)
626 	{
627 		/* Get block out of los */
628 		if (map_cache_refcount[i]) continue;
629 
630 		/* Check to see if unused */
631 		if (map_cache_x[i] < 0)
632 		{
633 			best_block = i;
634 			break;
635 		}
636 
637 		/* Get rough dist from player */
638 		dist = ABS(map_cache_x[i] - px) + ABS(map_cache_y[i] - py);
639 
640 		/* Save furthest block */
641 		if (dist > best_dist)
642 		{
643 			best_dist = dist;
644 			best_block = i;
645 		}
646 	}
647 
648 	/* Erase the block */
649 	clear_block(best_block);
650 
651 	/* Return the furthest unused block from the player */
652 	return (best_block);
653 }
654 
655 
656 /*
657  * Is the location in bounds on the map?
658  */
map_in_bounds(int x,int y)659 bool map_in_bounds(int x, int y)
660 {
661 	if (x < 0 || x >= WILD_BLOCK_SIZE * WILD_SIZE) return (FALSE);
662 	if (y < 0 || y >= WILD_BLOCK_SIZE * WILD_SIZE) return (FALSE);
663 	return (map_grid[y >> 4][x >> 4] != -1);
664 }
665 
666 
667 /*
668  * Save information into a block location
669  */
save_map_location(int x,int y,const term_map * map)670 static void save_map_location(int x, int y, const term_map *map)
671 {
672 	map_blk_ptr_ptr mbp_ptr;
673 	map_block *mb_ptr;
674 
675 	int x1 = x / WILD_BLOCK_SIZE;
676 	int y1 = y / WILD_BLOCK_SIZE;
677 
678 	int block_num;
679 
680 	callback_list *callback;
681 
682 	/* Does the location exist? */
683 	if (!map_in_bounds(x, y))
684 	{
685 		/* Create a new block there */
686 		block_num = get_empty_block();
687 
688 		/* Set this block up */
689 		mbp_ptr = map_cache[block_num];
690 
691 		/* Link to the map */
692 		map_grid[y1][x1] = block_num;
693 
694 		/* Save block coordinates */
695 		map_cache_x[block_num] = x1;
696 		map_cache_y[block_num] = y1;
697 	}
698 	else
699 	{
700 		block_num = map_grid[y1][x1];
701 		mbp_ptr = map_cache[block_num];
702 	}
703 
704 	mb_ptr = &mbp_ptr[y & 15][x & 15];
705 
706 	/* Increment refcount depending on visibility */
707 	if (map->flags & MAP_ONCE)
708 	{
709 		/* Wasn't seen, and now is */
710 		if (!(mb_ptr->flags & (MAP_ONCE)))
711 		{
712 			map_cache_refcount[block_num]++;
713 		}
714 	}
715 	else
716 	{
717 		/* Was seen, and now is not */
718 		if (mb_ptr->flags & MAP_ONCE)
719 		{
720 			/* Paranoia */
721 			if (!map_cache_refcount[block_num])
722 			{
723 				quit("Decrementing invalid overhead map loc");
724 			}
725 
726 			map_cache_refcount[block_num]--;
727 		}
728 	}
729 
730 	/* Save the tile data */
731 	mb_ptr->a = map->a;
732 	mb_ptr->c = map->c;
733 	mb_ptr->ta = map->ta;
734 	mb_ptr->tc = map->tc;
735 
736 	for (callback = callbacks[CALL_MAP_INFO]; callback; callback = callback->next)
737 	{
738 		/* Execute the callback */
739 		((map_info_hook_type)callback->func) (mb_ptr, map, callback->data);
740 	}
741 
742 	/* Save the flags */
743 	mb_ptr->flags = map->flags;
744 
745 	/* Save the priority */
746 	mb_ptr->priority = map->priority;
747 
748 #ifdef TERM_CAVE_MAP
749 
750 	/* Save the information */
751 	mb_ptr->terrain = map->terrain;
752 	mb_ptr->field = map->field;
753 
754 	mb_ptr->object = map->object;
755 	mb_ptr->unknown = map->unknown;
756 
757 	mb_ptr->monster = map->monster;
758 	mb_ptr->m_flags = map->m_flags;
759 	mb_ptr->m_hp = map->m_hp;
760 
761 #endif /* TERM_CAVE_MAP */
762 }
763 
764 /*
765  * Save the player location
766  */
set_player_location(int x,int y)767 static void set_player_location(int x, int y)
768 {
769 	callback_list *callback;
770 
771 	player_x = x;
772 	player_y = y;
773 
774 	/* Tell the port that the player has moved */
775 	for (callback = callbacks[CALL_PLAYER_MOVE]; callback; callback = callback->next)
776 	{
777 		/* Execute the callback */
778 		((player_move_hook_type)callback->func) (x, y, callback->data);
779 	}
780 }
781 
782 
783 /*
784  * Get the information in the map
785  */
map_loc(int x,int y)786 map_block *map_loc(int x, int y)
787 {
788 	return (&map_cache[map_grid[y / WILD_BLOCK_SIZE][x / WILD_BLOCK_SIZE]]
789 			[y & 15][x & 15]);
790 }
791 
792 
793 /* put the banners on the screen */
display_banner(wild_done_type * w_ptr)794 static void display_banner(wild_done_type *w_ptr)
795 {
796 	int wid, hgt;
797 
798 	place_type *pl_ptr;
799 
800 	/* Get size */
801 	Term_get_size(&wid, &hgt);
802 
803 	/* Do we have a place here? */
804 	pl_ptr = (w_ptr->place ? &place[w_ptr->place] : NULL);
805 
806 	/* Show the place name, if it is on the map */
807 	if (pl_ptr && (w_ptr->info & WILD_INFO_SEEN))
808 	{
809 		cptr banner;
810 		cptr place_dir;
811 		int i;
812 
813 		bool visited_town = FALSE;
814 		bool home_in_town = FALSE;
815 		bool castle_in_town = FALSE;
816 
817 		/* Is it a town */
818 		if (pl_ptr->numstores)
819 		{
820 			/* Upper banner */
821 			banner = pl_ptr->name;
822 
823 			/* Display town name */
824 			put_fstr(1 + (wid - strlen(banner)) / 2, 0, banner);
825 
826 			/* Find out if there are homes or castles here */
827 			for (i = 0; i < pl_ptr->numstores; i++)
828 			{
829 				store_type *st_ptr = &pl_ptr->store[i];
830 
831 				/* Is there a home? */
832 				if (st_ptr->type == BUILD_STORE_HOME) home_in_town = TRUE;
833 
834 				/* Is there a castle? */
835 				if (st_ptr->type == BUILD_CASTLE0 ||
836 					st_ptr->type == BUILD_CASTLE1) castle_in_town = TRUE;
837 
838 				/* Stores are not given coordinates until you visit a town */
839 				if (st_ptr->x != 0 && st_ptr->y != 0) visited_town = TRUE;
840 			}
841 
842 			/* Prevent knowledge from leaking out */
843 			home_in_town   &= visited_town;
844 			castle_in_town &= visited_town;
845 
846 			/* Find out the lower banner */
847 			if (home_in_town)
848 			{
849 				if (castle_in_town)
850 				{
851 					/* Town with home and castle */
852 					banner = "Move around, press * for town, h for home, c for castle or any key to exit.";
853 				}
854 				else
855 				{
856 					/* Town with home and no castle */
857 					banner = "Move around, press * for town, h for home or any key to exit.";
858 				}
859 			}
860 			/* Town with no home */
861 			else
862 			{
863 				if (castle_in_town)
864 				{
865 					/* Town with castle and no home */
866 					banner = "Move around, press * for town, c for castle or any key to exit.";
867 				}
868 				else
869 				{
870 					/* Town with no castle and no home */
871 					banner = "Move around, press * for town or any key to exit.";
872 				}
873 			}
874 
875 			/* Display lower banner */
876 			put_fstr(1 + (wid - strlen(banner)) / 2, hgt - 1, banner);
877 		}
878 		/* So it is in the wilderness */
879 		else
880 		{
881 			/* Display standard bottom line */
882 			put_fstr(wid / 2 - 23, hgt - 1,
883 					"Move around or hit any other key to continue.");
884 
885 			/* It is a wilderness dungeon */
886 			if (pl_ptr->dungeon)
887 			{
888 				/* Fetch closest known town and direction */
889 				banner = describe_quest_location(&place_dir,
890 								pl_ptr->x, pl_ptr->y, TRUE);
891 
892 				/* Did the player go into the dungeon? */
893 				if (pl_ptr->dungeon->recall_depth == 0)
894 				{
895 					/* It is still guarded by monsters */
896 					banner = format("Guarded dungeon %s of %s.", place_dir, banner);
897 				}
898 				else
899 				{
900 					/* No monsters to guard it */
901 					banner = format("Unguarded dungeon %s of %s.", place_dir, banner);
902 				}
903 			}
904 			/* It is a wilderness quest */
905 			else
906 			{
907 				/* Fetch wilderness quest name */
908 				banner = quest[pl_ptr->quest_num].name;
909 			}
910 
911 			/* Display wilderness place name */
912 			put_fstr((wid - strlen(banner)) / 2, 0, banner);
913 		}
914 	}
915 	else
916 	{
917 		/* Display standard bottom line */
918 		put_fstr(wid / 2 - 23, hgt - 1,
919 				"Move around or hit any other key to continue.");
920 	}
921 }
922 
923 
924 /* Display info about the home in one town */
dump_home_info(FILE * fff,int town)925 static bool dump_home_info(FILE *fff, int town)
926 {
927 	int i, k;
928 	bool visited_town = FALSE;
929 
930 	store_type *st_ptr;
931 	object_type *o_ptr;
932 
933 	for (i = 0; i < place[town].numstores; i++)
934 	{
935 		st_ptr = &place[town].store[i];
936 
937 		/* Stores are not given coordinates until you visit a town */
938 		if (st_ptr->x != 0 && st_ptr->y != 0) visited_town = TRUE;
939 
940 		/* The only interest is homes */
941 		if (st_ptr->type == BUILD_STORE_HOME)
942 		{
943 			/* Header with name of the town */
944 			froff(fff, "  [Home Inventory - %s]\n\n", place[i].name);
945 
946 			/* Home -- if anything there */
947 			if (st_ptr->stock)
948 			{
949 				char o_name[256];
950 
951 				/* Initialise counter */
952 				k = 0;
953 
954 				/* Dump all available items */
955 				OBJ_ITT_START (st_ptr->stock, o_ptr)
956 				{
957 					/* Describe object */
958 					object_desc(o_name, o_ptr, TRUE, 3, 256);
959 
960 					/* Clean formatting escape sequences */
961 					fmt_clean(o_name);
962 
963 					/* List the item, inlcuding its colour */
964 					froff(fff, " %s" CLR_SET_DEFAULT " %s\n",
965 						color_seq[tval_to_attr[o_ptr->tval]], o_name);
966 
967 					/* Increment counter */
968 					k++;
969 				}
970 				OBJ_ITT_END;
971 
972 				/* Add an empty line */
973 				froff(fff, "\n\n");
974 			}
975 			/* The home is empty */
976 			else
977 			{
978 				froff(fff, "  [Empty]\n\n");
979 			}
980 		}
981 	}
982 
983 	/* No home, no show */
984 	return (visited_town);
985 }
986 
987 
988 /* This function predicts whether keystroke c on a town has any effect */
dump_info_test(char c,int town)989 static bool dump_info_test(char c, int town)
990 {
991 	int i;
992 	bool visited_town = FALSE;
993 	bool build_found = FALSE;
994 
995 	store_type *st_ptr;
996 
997 	/* Paranoia */
998 	if (place[town].numstores == 0) return (FALSE);
999 
1000 	/* Find out if this command makes sense */
1001 	switch (c)
1002 	{
1003 		case '*':
1004 		{
1005 			/* Display the list of shops always works */
1006 			return (TRUE);
1007 		}
1008 
1009 		case 'h':
1010 		{
1011 			/* Display the items in the home needs a home */
1012 			for (i = 0; i < place[town].numstores; i++)
1013 			{
1014 				st_ptr = &place[town].store[i];
1015 
1016 				/* Stores are not given coordinates until you visit a town */
1017 				if (st_ptr->x != 0 && st_ptr->y != 0) visited_town = TRUE;
1018 
1019 				/* The only interest is homes */
1020 				if (st_ptr->type == BUILD_STORE_HOME) build_found = TRUE;
1021 			}
1022 
1023 			/* Return success */
1024 			return (build_found && visited_town);
1025 		}
1026 
1027 		case 'c':
1028 		{
1029 			/* Display the items in the home needs a home */
1030 			for (i = 0; i < place[town].numstores; i++)
1031 			{
1032 				st_ptr = &place[town].store[i];
1033 
1034 				/* Stores are not given coordinates until you visit a town */
1035 				if (st_ptr->x != 0 && st_ptr->y != 0) visited_town = TRUE;
1036 
1037 				/* The only interest is homes */
1038 				if (st_ptr->type == BUILD_CASTLE0 ||
1039 					st_ptr->type == BUILD_CASTLE1) build_found = TRUE;
1040 			}
1041 
1042 			/* Return success */
1043 			return (build_found && visited_town);
1044 		}
1045 	}
1046 
1047 	return (FALSE);
1048 }
1049 
1050 
1051 /* Show the knowledge the player has about a town */
do_cmd_view_map_aux(char c,int town)1052 static bool do_cmd_view_map_aux(char c, int town)
1053 {
1054 	FILE *fff;
1055 
1056 	char file_name[1024];
1057 
1058 	cptr title = NULL;
1059 
1060 	/* Call this proc with a place that is a town */
1061 	if (place[town].numstores == 0) return (FALSE);
1062 
1063 	/* go away if nothing will happen */
1064 	if (!dump_info_test(c, town)) return (FALSE);
1065 
1066 	/* Open temporary file */
1067 	fff = my_fopen_temp(file_name, 1024);
1068 
1069 	/* Failure */
1070 	if (!fff) return (FALSE);
1071 
1072 	/* Show what? */
1073 	switch (c)
1074 	{
1075 		case '*':
1076 		{
1077 			/* Display the list of shops */
1078 			dump_town_info(fff, town, FALSE);
1079 			title = "Town info";
1080 
1081 			break;
1082 		}
1083 
1084 		case 'h':
1085 		{
1086 			/* Display the items in the home */
1087 			(void)dump_home_info(fff, town);
1088 			title = "Home info";
1089 
1090 			break;
1091 		}
1092 
1093 		case 'c':
1094 		{
1095 			/* Display the quests taken */
1096 			dump_castle_info(fff, town);
1097 			title = "Castle info";
1098 
1099 			break;
1100 		}
1101 	}
1102 
1103 	/* Close the file */
1104 	my_fclose(fff);
1105 
1106 	/* Display the file contents */
1107 	(void)show_file(file_name, title, 0, 0);
1108 
1109 	/* Remove the file */
1110 	(void)fd_kill(file_name);
1111 
1112 	/* And curtain */
1113 	return (TRUE);
1114 }
1115 
1116 /* Keep the offset for the resize */
1117 static int map_cx = 0;
1118 static int map_cy = 0;
1119 
resize_big_map(void)1120 static void resize_big_map(void)
1121 {
1122 	int cx, cy;
1123 	wild_done_type *w_ptr;
1124 
1125 	cx = map_cx;
1126 	cy = map_cy;
1127 
1128 	/* Make a new map */
1129 	display_map(&cx, &cy);
1130 
1131 	/* Get wilderness square */
1132 	w_ptr = &wild[map_cy + p_ptr->py / WILD_BLOCK_SIZE]
1133 				 [map_cx + p_ptr->px / WILD_BLOCK_SIZE].done;
1134 
1135 	/* print the banners */
1136 	display_banner(w_ptr);
1137 
1138 	/* Show the cursor */
1139 	Term_gotoxy(cx, cy);
1140 }
1141 
1142 /*
1143  * Display a "small-scale" map of the dungeon for the player
1144  *
1145  * Currently, the "player" is displayed on the map.  XXX XXX XXX
1146  */
do_cmd_view_map(void)1147 void do_cmd_view_map(void)
1148 {
1149 	int py = p_ptr->py;
1150 	int px = p_ptr->px;
1151 
1152 	int cy, cx;
1153 	int wid, hgt;
1154 
1155 	void (*hook) (void);
1156 
1157 	/* No overhead map in vanilla town mode. */
1158 	if (!p_ptr->depth && vanilla_town) return;
1159 
1160 	/* Remember what the resize hook was */
1161 	hook = angband_term[0]->resize_hook;
1162 
1163 	/* Hack - change the redraw hook so bigscreen works */
1164 	angband_term[0]->resize_hook = resize_big_map;
1165 
1166 	/* Note */
1167 	prtf(0, 0, "Please wait...");
1168 
1169 	/* Flush */
1170 	Term_fresh();
1171 
1172 	/* Clear the screen */
1173 	Term_clear();
1174 
1175 	if (p_ptr->depth)
1176 	{
1177 		/* In the dungeon - All we have to do is display the map */
1178 
1179 		/* Get size */
1180 		Term_get_size(&wid, &hgt);
1181 
1182 		/* No offset from player */
1183 		cx = 0;
1184 		cy = 0;
1185 
1186 		/* Match offset for the resize */
1187 		map_cx = cx;
1188 		map_cy = cy;
1189 
1190 		/* Display the map */
1191 		display_map(&cx, &cy);
1192 
1193 		/* Wait for it */
1194 		put_fstr((wid - COL_MAP) / 2, hgt - 1, "Hit any key to continue");
1195 
1196 		/* Hilite the player */
1197 		Term_gotoxy(cx, cy);
1198 
1199 		/* Get any key */
1200 		(void)inkey();
1201 	}
1202 	else
1203 	{
1204 		/* Offset from player */
1205 		int x, y;
1206 
1207 		/* Direction */
1208 		int d;
1209 
1210 		/* Input character */
1211 		char c;
1212 
1213 		wild_done_type *w_ptr;
1214 
1215 		/* No offset yet */
1216 		x = 0;
1217 		y = 0;
1218 
1219 		/* In the wilderness - Display the map + move it around */
1220 
1221 		while (TRUE)
1222 		{
1223 			/* Reset offset of map */
1224 			cx = x;
1225 			cy = y;
1226 
1227 			/* Match offset for the resize */
1228 			map_cx = cx;
1229 			map_cy = cy;
1230 
1231 			display_map(&cx, &cy);
1232 
1233 			/* Get wilderness square */
1234 			w_ptr = &wild[y + py / WILD_BLOCK_SIZE][x + px / WILD_BLOCK_SIZE].done;
1235 
1236 			/* Get the banners on the screen */
1237 			display_banner(w_ptr);
1238 
1239 			/* Show the cursor */
1240 			Term_gotoxy(cx, cy);
1241 
1242 			/* Draw it */
1243 			Term_fresh();
1244 
1245 			/* Get a response */
1246 			c = inkey();
1247 
1248 			/* Allow a redraw */
1249 			if (c == KTRL('R'))
1250 			{
1251 				/* Do the redraw */
1252 				do_cmd_redraw();
1253 
1254 				continue;
1255 			}
1256 
1257 			/* On a town?  -- MT */
1258 			if (w_ptr->place)
1259 			{
1260 				/* Check if this is an info command */
1261 				if (do_cmd_view_map_aux(c, w_ptr->place)) continue;
1262 			}
1263 
1264 			/* Done if not a direction */
1265 			d = get_keymap_dir(c);
1266 
1267 			if (!d) break;
1268 
1269 			x += ddx[d];
1270 			y += ddy[d];
1271 
1272 			/* Bounds checking */
1273 			if (x + px / WILD_BLOCK_SIZE < 0)
1274 			{
1275 				x = -px / WILD_BLOCK_SIZE;
1276 			}
1277 			if (y + py / WILD_BLOCK_SIZE < 0)
1278 			{
1279 				y = -py / WILD_BLOCK_SIZE;
1280 			}
1281 			if (x + px / WILD_BLOCK_SIZE > max_wild - 2)
1282 			{
1283 				x = max_wild - px / WILD_BLOCK_SIZE - 2;
1284 			}
1285 			if (y + py / WILD_BLOCK_SIZE > max_wild - 2)
1286 			{
1287 				y = max_wild - py / WILD_BLOCK_SIZE - 2;
1288 			}
1289 		}
1290 	}
1291 
1292 	/* Hack - change the redraw hook so bigscreen works */
1293 	angband_term[0]->resize_hook = hook;
1294 
1295 	/* The size may have changed during the scores display */
1296 	angband_term[0]->resize_hook();
1297 
1298 	/* Hack - Flush it */
1299 	Term_fresh();
1300 }
1301 
1302 
1303 
1304 /*
1305  * Two arrays listing the effects of "brightness"
1306  * and "darkness" on various "base" colours.
1307  *
1308  * This is used to do dynamic lighting effects in ascii :-)
1309  */
1310 
1311 static const byte lighting_colours[16] =
1312 {
1313 	/* TERM_DARK */
1314 	TERM_L_DARK,
1315 
1316 	/* TERM_WHITE */
1317 	TERM_YELLOW,
1318 
1319 	/* TERM_SLATE */
1320 	TERM_WHITE,
1321 
1322 	/* TERM_ORANGE */
1323 	TERM_YELLOW,
1324 
1325 	/* TERM_RED */
1326 	TERM_RED,
1327 
1328 	/* TERM_GREEN */
1329 	TERM_L_GREEN,
1330 
1331 	/* TERM_BLUE */
1332 	TERM_BLUE,
1333 
1334 	/* TERM_UMBER */
1335 	TERM_L_UMBER,
1336 
1337 	/* TERM_L_DARK */
1338 	TERM_SLATE,
1339 
1340 	/* TERM_L_WHITE */
1341 	TERM_WHITE,
1342 
1343 	/* TERM_VIOLET */
1344 	TERM_L_RED,
1345 
1346 	/* TERM_YELLOW */
1347 	TERM_YELLOW,
1348 
1349 	/* TERM_L_RED */
1350 	TERM_L_RED,
1351 
1352 	/* TERM_L_GREEN */
1353 	TERM_YELLOW,
1354 
1355 	/* TERM_L_BLUE */
1356 	TERM_L_BLUE,
1357 
1358 	/* TERM_L_UMBER */
1359 	TERM_L_UMBER,
1360 };
1361 
1362 static const byte darking_colours[16] =
1363 {
1364 	/* TERM_DARK */
1365 	TERM_DARK,
1366 
1367 	/* TERM_WHITE */
1368 	TERM_SLATE,
1369 
1370 	/* TERM_SLATE */
1371 	TERM_L_DARK,
1372 
1373 	/* TERM_ORANGE */
1374 	TERM_UMBER,
1375 
1376 	/* TERM_RED */
1377 	TERM_RED,
1378 
1379 	/* TERM_GREEN */
1380 	TERM_GREEN,
1381 
1382 	/* TERM_BLUE */
1383 	TERM_BLUE,
1384 
1385 	/* TERM_UMBER */
1386 	TERM_RED,
1387 
1388 	/* TERM_L_DARK */
1389 	TERM_L_DARK,
1390 
1391 	/* TERM_L_WHITE */
1392 	TERM_SLATE,
1393 
1394 	/* TERM_VIOLET */
1395 	TERM_BLUE,
1396 
1397 	/* TERM_YELLOW */
1398 	TERM_ORANGE,
1399 
1400 	/* TERM_L_RED */
1401 	TERM_L_RED,
1402 
1403 	/* TERM_L_GREEN */
1404 	TERM_GREEN,
1405 
1406 	/* TERM_L_BLUE */
1407 	TERM_L_BLUE,
1408 
1409 	/* TERM_L_UMBER */
1410 	TERM_UMBER
1411 };
1412 
1413 
1414 
1415 #ifdef VARIABLE_PLAYER_GRAPH
1416 
1417 /* Magic numbers */
1418 #define BMP_FIRST_PC_CLASS		164
1419 #define BMP_FIRST_PC_RACE		128
1420 
variable_player_graph(byte * a,char * c)1421 static void variable_player_graph(byte *a, char *c)
1422 {
1423 	if (use_graphics != GRAPHICS_ADAM_BOLT)
1424 	{
1425 		if (!streq(ANGBAND_SYS, "ibm"))
1426 		{
1427 			if (use_graphics)
1428 			{
1429 				*a = BMP_FIRST_PC_CLASS + p_ptr->pclass;
1430 				*c = BMP_FIRST_PC_RACE + p_ptr->prace;
1431 			}
1432 		}
1433 		else
1434 		{
1435 			if (use_graphics)
1436 			{
1437 				if (p_ptr->psex == SEX_FEMALE) *c = (char)242;
1438 				switch (p_ptr->pclass)
1439 				{
1440 					case CLASS_PALADIN:
1441 					{
1442 						if (p_ptr->lev < 20)
1443 							*a = TERM_L_WHITE;
1444 						else
1445 							*a = TERM_WHITE;
1446 						*c = 253;
1447 						break;
1448 					}
1449 					case CLASS_WARRIOR_MAGE:
1450 					{
1451 						if (p_ptr->lev < 20)
1452 							*a = TERM_L_RED;
1453 						else
1454 							*a = TERM_VIOLET;
1455 						break;
1456 					}
1457 					case CLASS_CHAOS_WARRIOR:
1458 					{
1459 						*a = randint1(14);
1460 						break;
1461 					}
1462 					case CLASS_MAGE:
1463 					case CLASS_HIGH_MAGE:
1464 					{
1465 						if (p_ptr->lev < 20)
1466 							*a = TERM_L_RED;
1467 						else
1468 							*a = TERM_RED;
1469 						*c = 248;
1470 						break;
1471 					}
1472 					case CLASS_PRIEST:
1473 					{
1474 						if (p_ptr->lev < 20)
1475 							*a = TERM_L_BLUE;
1476 						else
1477 							*a = TERM_BLUE;
1478 						*c = 248;
1479 						break;
1480 					}
1481 					case CLASS_RANGER:
1482 					{
1483 						if (p_ptr->lev < 20)
1484 							*a = TERM_L_GREEN;
1485 						else
1486 							*a = TERM_GREEN;
1487 						break;
1488 					}
1489 					case CLASS_ROGUE:
1490 					{
1491 						if (p_ptr->lev < 20)
1492 							*a = TERM_SLATE;
1493 						else
1494 							*a = TERM_L_DARK;
1495 						break;
1496 					}
1497 					case CLASS_WARRIOR:
1498 					{
1499 						if (p_ptr->lev < 20)
1500 							*a = TERM_L_UMBER;
1501 						else
1502 							*a = TERM_UMBER;
1503 						break;
1504 					}
1505 					case CLASS_MONK:
1506 					case CLASS_MINDCRAFTER:
1507 					{
1508 						if (p_ptr->lev < 20)
1509 							*a = TERM_L_UMBER;
1510 						else
1511 							*a = TERM_UMBER;
1512 						*c = 248;
1513 						break;
1514 					}
1515 					default:
1516 					{
1517 						/* Unknown */
1518 						*a = TERM_WHITE;
1519 					}
1520 				}
1521 
1522 				switch (p_ptr->prace)
1523 				{
1524 					case RACE_GNOME:
1525 					case RACE_HOBBIT:
1526 					{
1527 						*c = 144;
1528 						break;
1529 					}
1530 					case RACE_DWARF:
1531 					{
1532 						*c = 236;
1533 						break;
1534 					}
1535 					case RACE_HALF_ORC:
1536 					{
1537 						*c = 243;
1538 						break;
1539 					}
1540 					case RACE_HALF_TROLL:
1541 					{
1542 						*c = 184;
1543 						break;
1544 					}
1545 					case RACE_ELF:
1546 					case RACE_HALF_ELF:
1547 					case RACE_HIGH_ELF:
1548 					{
1549 						*c = 223;
1550 						break;
1551 					}
1552 					case RACE_HALF_OGRE:
1553 					{
1554 						*c = 168;
1555 						break;
1556 					}
1557 					case RACE_HALF_GIANT:
1558 					case RACE_HALF_TITAN:
1559 					case RACE_CYCLOPS:
1560 					{
1561 						*c = 145;
1562 						break;
1563 					}
1564 					case RACE_YEEK:
1565 					{
1566 						*c = 209;
1567 						break;
1568 					}
1569 					case RACE_KLACKON:
1570 					{
1571 						*c = 229;
1572 						break;
1573 					}
1574 					case RACE_KOBOLD:
1575 					{
1576 						*c = 204;
1577 						break;
1578 					}
1579 					case RACE_NIBELUNG:
1580 					{
1581 						*c = 144;
1582 						break;
1583 					}
1584 					case RACE_DARK_ELF:
1585 					{
1586 						*c = 223;
1587 						break;
1588 					}
1589 					case RACE_DRACONIAN:
1590 					{
1591 						if (p_ptr->lev < 20)
1592 							*c = 240;
1593 						else if (p_ptr->lev < 40)
1594 							*c = 22;
1595 						else
1596 							*c = 137;
1597 						break;
1598 					}
1599 					case RACE_MIND_FLAYER:
1600 					{
1601 						*c = 236;
1602 						break;
1603 					}
1604 					case RACE_IMP:
1605 					{
1606 						*c = 142;
1607 						break;
1608 					}
1609 					case RACE_GOLEM:
1610 					{
1611 						*c = 6;
1612 						break;
1613 					}
1614 					case RACE_SKELETON:
1615 					{
1616 						if (p_ptr->pclass == CLASS_MAGE ||
1617 							p_ptr->pclass == CLASS_PRIEST ||
1618 							p_ptr->pclass == CLASS_HIGH_MAGE ||
1619 							p_ptr->pclass == CLASS_MONK ||
1620 							p_ptr->pclass == CLASS_MINDCRAFTER)
1621 							*c = 159;
1622 						else
1623 							*c = 181;
1624 						break;
1625 					}
1626 					case RACE_ZOMBIE:
1627 					case RACE_GHOUL:
1628 					{
1629 						*c = 221;
1630 						break;
1631 					}
1632 					case RACE_VAMPIRE:
1633 					{
1634 						*c = 217;
1635 						break;
1636 					}
1637 					case RACE_SPECTRE:
1638 					{
1639 						*c = 241;
1640 						break;
1641 					}
1642 					case RACE_SPRITE:
1643 					{
1644 						*c = 244;
1645 						break;
1646 					}
1647 					case RACE_BEASTMAN:
1648 					{
1649 						*c = 154;
1650 						break;
1651 					}
1652 				}
1653 			}
1654 		}
1655 	}
1656 }
1657 #endif /* VARIABLE_PLAYER_GRAPH */
1658 
1659 
1660 /*
1661  * Hack -- Legal monster codes
1662  */
1663 static cptr image_monster_hack =
1664 	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1665 
1666 
1667 /*
1668  * Mega-Hack -- Hallucinatory monster
1669  */
image_monster(byte * ap,char * cp)1670 static void image_monster(byte *ap, char *cp)
1671 {
1672 	int n = strlen(image_monster_hack);
1673 
1674 	/* Random symbol from set above */
1675 	if (use_graphics)
1676 	{
1677 		(*cp) = r_info[randint1(z_info->r_max - 1)].x_char;
1678 		(*ap) = r_info[randint1(z_info->r_max - 1)].x_attr;
1679 	}
1680 	else
1681 		/* Text mode */
1682 	{
1683 		(*cp) = (image_monster_hack[randint0(n)]);
1684 
1685 		/* Random color */
1686 		(*ap) = randint1(15);
1687 	}
1688 }
1689 
1690 
1691 /*
1692  * Hack -- Legal object codes
1693  */
1694 static cptr image_object_hack = "?/|\\\"!$()_-=[]{},~";
1695 
1696 
1697 /*
1698  * Mega-Hack -- Hallucinatory object
1699  */
image_object(byte * ap,char * cp)1700 static void image_object(byte *ap, char *cp)
1701 {
1702 	int n = strlen(image_object_hack);
1703 
1704 	if (use_graphics)
1705 	{
1706 		(*cp) = k_info[randint1(z_info->k_max - 1)].x_char;
1707 		(*ap) = k_info[randint1(z_info->k_max - 1)].x_attr;
1708 	}
1709 	else
1710 	{
1711 		(*cp) = (image_object_hack[randint0(n)]);
1712 
1713 		/* Random color */
1714 		(*ap) = randint1(15);
1715 	}
1716 }
1717 
1718 
1719 /*
1720  * Hack -- Random hallucination
1721  */
image_random(byte * ap,char * cp)1722 static void image_random(byte *ap, char *cp)
1723 {
1724 	/* Normally, assume monsters */
1725 	if (randint0(100) < 75)
1726 	{
1727 		image_monster(ap, cp);
1728 	}
1729 
1730 	/* Otherwise, assume objects */
1731 	else
1732 	{
1733 		image_object(ap, cp);
1734 	}
1735 }
1736 
1737 /*
1738  * Table of the GF type for each breath
1739  */
1740 static int breath_gf[32] =
1741 {
1742 	GF_NONE,	/* RF3_SHRIEK */
1743 	GF_NONE,	/* RF3_ELDRITCH_HORROR */
1744 	GF_NONE,	/* RF3_XXX3 */
1745 	GF_NONE,	/* RF3_ROCKET */
1746 	GF_NONE,	/* RF3_ARROW */
1747 	GF_NONE,	/* RF3_XXX6 */
1748 	GF_NONE,	/* RF3_XXX7 */
1749 	GF_NONE,	/* RF3_XXX8 */
1750 	GF_ACID,	/* RF3_BR_ACID */
1751 	GF_ELEC,	/* RF3_BR_ELEC */
1752 	GF_FIRE,	/* RF3_BR_FIRE */
1753 	GF_COLD,	/* RF3_BR_COLD */
1754 	GF_POIS,	/* RF3_BR_POIS */
1755 	GF_NETHER,	/* RF3_BR_NETH */
1756 	GF_LITE,	/* RF3_BR_LITE */
1757 	GF_DARK,	/* RF3_BR_DARK */
1758 	GF_CONFUSION,	/* RF3_BR_CONF */
1759 	GF_SOUND,	/* RF3_BR_SOUN */
1760 	GF_CHAOS,	/* RF3_BR_CHAO */
1761 	GF_DISENCHANT,	/* RF3_BR_DISE */
1762 	GF_NEXUS,	/* RF3_BR_NEXU */
1763 	GF_TIME,	/* RF3_BR_TIME */
1764 	GF_INERTIA,	/* RF3_BR_INER */
1765 	GF_GRAVITY,	/* RF3_BR_GRAV */
1766 	GF_SHARDS,	/* RF3_BR_SHAR */
1767 	GF_PLASMA,	/* RF3_BR_PLAS */
1768 	GF_FORCE,	/* RF3_BR_WALL */
1769 	GF_MANA,	/* RF3_BR_MANA */
1770 	GF_NONE,	/* RF3_BA_NUKE */
1771 	GF_NUKE,	/* RF3_BR_NUKE */
1772 	GF_NONE,	/* RF3_BA_CHAO */
1773 	GF_DISINTEGRATE	/* RF3_BR_DISI */
1774 };
1775 
1776 
1777 /*
1778  * Hack -- Get colour based on breaths of monster
1779  *
1780  * (This may be a little slow....
1781  */
breath_attr(const monster_race * r_ptr)1782 static byte breath_attr(const monster_race *r_ptr)
1783 {
1784 	/* Mask out the breath flags */
1785 	u32b flags = r_ptr->flags[3] & RF3_BREATHS;
1786 	u32b mask;
1787 
1788 	/* See if we breathe anything at all */
1789 	if (flags)
1790 	{
1791 		byte a;
1792 		char c;
1793 
1794 		cptr s;
1795 
1796 		int i;
1797 		int prob = 1;
1798 		int choice = 0;
1799 
1800 		/* Pick breath */
1801 		for (i = 8, mask = 256; i < 32; i++, mask += mask)
1802 		{
1803 			if (flags & mask)
1804 			{
1805 				/* See if we choose this spell */
1806 				if (one_in_(prob)) choice = i;
1807 
1808 				/* Decrease probability of picking next 'spell' */
1809 				prob++;
1810 			}
1811 		}
1812 
1813 		/* Paranoia */
1814 		if (choice)
1815 		{
1816 			/* Lookup the default colors for this type */
1817 			s = gf_color[breath_gf[choice]];
1818 
1819 			/* Oops */
1820 			if (!s) return (TERM_WHITE);
1821 
1822 			/* Pick a random color */
1823 			c = s[randint0(strlen(s))];
1824 
1825 			/* Lookup this color */
1826 			a = strchr(color_char, c) - color_char;
1827 
1828 			/*
1829 			 * Invalid color (note check for < 0 removed, gave a silly
1830 			 * warning because bytes are always >= 0 -- RG)
1831 			 */
1832 			if (a > 15) return (TERM_WHITE);
1833 
1834 			/* Use this color */
1835 			return (a);
1836 		}
1837 	}
1838 
1839 	/* Just do any of 7 colours */
1840 	switch (randint1(7))
1841 	{
1842 		case 1: return (TERM_RED);
1843 		case 2: return (TERM_L_RED);
1844 		case 3: return (TERM_WHITE);
1845 		case 4: return (TERM_L_GREEN);
1846 		case 5: return (TERM_BLUE);
1847 		case 6: return (TERM_L_DARK);
1848 		case 7: return (TERM_GREEN);
1849 	}
1850 
1851 	/* For the compilers... */
1852 	return (TERM_WHITE);
1853 }
1854 
1855 
1856 /*
1857  * Extract tile info for monster.
1858  *
1859  * Note how we manually alter the tile type to simulate effects
1860  * in ascii mode.  We must make sure not to break the images
1861  * when in (semi) graphics mode, where either the monster
1862  * or the floor it is standing on is non-ascii.
1863  */
map_mon_info(monster_type * m_ptr,monster_race * r_ptr,byte * a,char * c,term_map * map)1864 static void map_mon_info(monster_type *m_ptr, monster_race *r_ptr, byte *a, char *c,
1865 						term_map *map)
1866 {
1867 	byte feat_not_ascii;
1868 
1869 	byte ma = *a;
1870 	char mc = *c;
1871 
1872 	/* Visible monster */
1873 	if (m_ptr->ml)
1874 	{
1875 		/* Visible monster */
1876 		map->monster = m_ptr->r_idx;
1877 
1878 		/* Keep this grid */
1879 		map->flags |= MAP_ONCE;
1880 
1881 		/* Get monster information */
1882 		if (m_ptr->csleep) map->m_flags |= MONST_ASLEEP;
1883 		if (is_friendly(m_ptr)) map->m_flags |= MONST_FRIEND;
1884 		if (is_pet(m_ptr)) map->m_flags |= MONST_PET;
1885 		if (m_ptr->confused) map->m_flags |= MONST_CONFUSED;
1886 		if (m_ptr->monfear) map->m_flags |= MONST_FEAR;
1887 		if (m_ptr->stunned) map->m_flags |= MONST_STUN;
1888 		if (m_ptr->invulner) map->m_flags |= MONST_INVULN;
1889 
1890 		/* Get scaled monster hp */
1891 		map->m_hp = m_ptr->hp * 10 / m_ptr->maxhp;
1892 
1893 		/* Hack -- hallucination */
1894 		if (p_ptr->tim.image)
1895 		{
1896 			/* Hallucinatory monster */
1897 			image_monster(a, c);
1898 			return;
1899 		}
1900 		else
1901 		{
1902 			feat_not_ascii = ((*a) & 0x80);
1903 
1904 			/* Desired attr */
1905 			if (!FLAG(r_ptr, RF_ATTR_CLEAR) || feat_not_ascii)
1906 			{
1907 				ma = r_ptr->x_attr;
1908 			}
1909 
1910 			/* Desired char */
1911 			if (!FLAG(r_ptr, RF_CHAR_CLEAR) || feat_not_ascii)
1912 			{
1913 				mc = r_ptr->x_char;
1914 			}
1915 
1916 			/* Ignore weird codes + graphics */
1917 			if (!(ma & 0x80))
1918 			{
1919 				/* Multi-hued monster */
1920 				if (FLAG(r_ptr, RF_ATTR_MULTI))
1921 				{
1922 					/* Is it a shapechanger? */
1923 					if (FLAG(r_ptr, RF_SHAPECHANGER))
1924 					{
1925 						if (use_graphics)
1926 						{
1927 							mc = r_info[randint1(z_info->r_max - 1)].x_char;
1928 							ma = r_info[randint1(z_info->r_max - 1)].x_attr;
1929 						}
1930 						else
1931 						{
1932 							mc = (one_in_(25) ?
1933 								 image_object_hack[randint0
1934 											   (strlen(image_object_hack))] :
1935 								 image_monster_hack[randint0
1936 												(strlen(image_monster_hack))]);
1937 						}
1938 					}
1939 
1940 					/* Multi-hued attr */
1941 					if (FLAG(r_ptr, RF_ATTR_ANY))
1942 						ma = randint1(15);
1943 					else
1944 					{
1945 						/* Pick colour based on breaths */
1946 						ma = breath_attr(r_ptr);
1947 					}
1948 				}
1949 				/* Mimics' colors vary */
1950 				else if (((mc == '\"') || (mc == '!') || (mc == '='))
1951 						 && !FLAG(r_ptr, RF_UNIQUE))
1952 				{
1953 					/* Use char */ ;
1954 
1955 					/* Use semi-random attr */
1956 					ma = GET_ARRAY_INDEX(m_list, m_ptr) % 15 + 1;
1957 				}
1958 			}
1959 		}
1960 	}
1961 
1962 	/* Save results */
1963 	*a = ma;
1964 	*c = mc;
1965 }
1966 
1967 
1968 /*
1969  * Extract the attr/char to display at the given (legal) map location
1970  *
1971  * Basically, we "paint" the chosen attr/char in several passes, starting
1972  * with any known "terrain features" (defaulting to darkness), then adding
1973  * any known "objects", and finally, adding any known "monsters".  This
1974  * is not the fastest method but since most of the calls to this function
1975  * are made for grids with no monsters or objects, it is fast enough.
1976  *
1977  * Note that the "zero" entry in the feature/object/monster arrays are
1978  * used to provide "special" attr/char codes, with "monster zero" being
1979  * used for the player attr/char, "object zero" being used for the "stack"
1980  * attr/char, and "feature zero" being used for the "nothing" attr/char,
1981  * though this function makes use of only "feature zero".
1982  *
1983  * Note that monsters can have some "special" flags, including "ATTR_MULTI",
1984  * which means their color changes, and "ATTR_CLEAR", which means they take
1985  * the color of whatever is under them, and "CHAR_CLEAR", which means that
1986  * they take the symbol of whatever is under them.  Technically, the flag
1987  * "CHAR_MIMIC" is supposed to indicate that a monster looks strange when
1988  * examined, but this flag is currently ignored.
1989  *
1990  * Note the effects of hallucination.  Objects always appear as random
1991  * "objects", monsters as random "monsters", and normal grids occasionally
1992  * appear as random "monsters" or "objects", but note that these random
1993  * "monsters" and "objects" are really just "colored ascii symbols".
1994  *
1995  * Note the use of the new "terrain feature" information.  Note that the
1996  * assumption that all interesting "objects" and "terrain features" are
1997  * memorized allows extremely optimized processing below.  Note the use
1998  * of separate flags on objects to mark them as memorized allows a grid
1999  * to have memorized "terrain" without granting knowledge of any object
2000  * which may appear in that grid.
2001  *
2002  * We use the players memorised information to pick the terrain feature
2003  * to use.  This allows massive simplification - getting rid of all the
2004  * checks to tha old CAVE_MARK flag, and allowing the player is blind case
2005  * to be merged into the main line code.  The section picking the terrain
2006  * attr/feat is now less than a page long - which is important because
2007  * this routine is a major bottleneck.
2008  *
2009  * Note the "special lighting effects" which can be activated for floor
2010  * grids using the "view_special_lite" option causing certain grids to be
2011  * displayed using special colors.
2012  *
2013  * Note the "special lighting effects" which can be activated for wall
2014  * grids using the "view_granite_lite" option causing certain grids to be
2015  * displayed using special colors.
2016  *
2017  * The lighting and darkening of colours is handled by two arrays.  We can
2018  * also lighten and darken some terrains in the 16x16 tileset.
2019  *
2020  * Note that bizarre things must be done when the "attr" and/or "char"
2021  * codes have the "high-bit" set, since these values are used to encode
2022  * various "special" pictures in some versions, and certain situations,
2023  * such as "multi-hued" or "clear" monsters, cause the attr/char codes
2024  * to be "scrambled" in various ways.
2025  *
2026  *
2027  * Save data into the term_map struct so we can pass it to the ports
2028  * hooking the overhead map code.  The status of the square (x, y) has
2029  * probably changed.  This allows the main-???.c files to not access
2030  * internal game data, which may or may not be accessable.
2031  */
2032 
map_info(int x,int y,byte * ap,char * cp,byte * tap,char * tcp)2033 static void map_info(int x, int y, byte *ap, char *cp, byte *tap, char *tcp)
2034 {
2035 	feature_type *f_ptr;
2036 
2037 	object_type *o_ptr;
2038 	object_kind *k_ptr;
2039 
2040 	monster_type *m_ptr;
2041 	monster_race *r_ptr;
2042 
2043 	field_type *fld_ptr;
2044 
2045 	/* Get location */
2046 	cave_type *c_ptr = area(x, y);
2047 	pcave_type *pc_ptr = parea(x, y);
2048 
2049 	/* Get the memorized feature */
2050 	byte feat = pc_ptr->feat;
2051 
2052 	/* Info flags */
2053 	byte player = pc_ptr->player;
2054 
2055 	byte a;
2056 	char c;
2057 
2058 	s16b halluc = p_ptr->tim.image;
2059 	bool visible = player & GRID_SEEN;
2060 	bool glow = c_ptr->info & CAVE_GLOW;
2061 	bool lite = (c_ptr->info & CAVE_MNLT) || (player & GRID_LITE);
2062 
2063 	bool float_field = FALSE;
2064 
2065 	term_map map;
2066 
2067 	/* Clear map info */
2068 	(void)WIPE(&map, term_map);
2069 
2070 	/* Save known data */
2071 	map.terrain = feat;
2072 
2073 	/* Save location */
2074 	map.x = x;
2075 	map.y = y;
2076 
2077 	/* Default priority */
2078 	map.priority = 0;
2079 
2080 	/* Pointer to the feature */
2081 	f_ptr = &f_info[feat];
2082 
2083 	/* Hack -- rare random hallucination, except on outer dungeon walls */
2084 	if (halluc && !p_ptr->tim.blind && (feat != FEAT_PERM_SOLID) && one_in_(256))
2085 	{
2086 		/* Hallucinate */
2087 		image_random(&a, &c);
2088 
2089 		if (glow)
2090 		{
2091 			map.flags = MAP_GLOW;
2092 		}
2093 
2094 		(*tap) = a;
2095 		(*tcp) = c;
2096 	}
2097 	else
2098 	{
2099 		/* Visible */
2100 		if (visible)
2101 		{
2102 			map.flags = MAP_SEEN | MAP_ONCE;
2103 
2104 			if (glow) map.flags |= MAP_GLOW;
2105 			if (lite) map.flags |= MAP_LITE;
2106 		}
2107 
2108 		/* The feats attr */
2109 		a = f_ptr->x_attr;
2110 
2111 		/* The feats char */
2112 		c = f_ptr->x_char;
2113 
2114 		/*
2115 		 * Look for lighting effects.
2116 		 *
2117 		 * Need to have lighting on and the player is not blind.
2118 		 * We then need to have a grid that is allowed to be lit.
2119 		 */
2120 		if (view_bright_lite && !p_ptr->tim.blind
2121 			&& (!(f_ptr->flags & FF_BLOCK)
2122 				|| (view_granite_lite && !view_torch_grids)))
2123 		{
2124 			/* It's not in view or no lighting effects? */
2125 			if (((!(player & (GRID_VIEW))) && view_special_lite)
2126 				|| !visible)
2127 			{
2128 				/* If is ascii graphics */
2129 				if (a < 16)
2130 				{
2131 					/* Use darkened colour */
2132 					a = darking_colours[a];
2133 				}
2134 				else if ((use_graphics == GRAPHICS_ADAM_BOLT)
2135 						 && (f_ptr->flags & FF_USE_TRANS))
2136 				{
2137 					/* Use a dark tile */
2138 					c++;
2139 				}
2140 			}
2141 			else if (lite && view_yellow_lite)
2142 			{
2143 				/* Use the torch effect */
2144 				if (a < 16)
2145 				{
2146 					/* Use bright colour */
2147 					a = lighting_colours[a];
2148 				}
2149 				else if ((use_graphics == GRAPHICS_ADAM_BOLT)
2150 						 && (f_ptr->flags & FF_USE_TRANS))
2151 				{
2152 					/* Use a light tile */
2153 					c += 2;
2154 				}
2155 			}
2156 		}
2157 
2158 		/* Save the terrain info for the transparency effects */
2159 
2160 		/* Does the feature have "extended terrain" information? */
2161 		if (f_ptr->w_attr)
2162 		{
2163 			/*
2164 			 * Store extended terrain information.
2165 			 * Note hack to get lighting right.
2166 			 */
2167 			(*tap) = f_ptr->w_attr + a - f_ptr->x_attr;
2168 			(*tcp) = f_ptr->w_char + c - f_ptr->x_char;
2169 		}
2170 		else
2171 		{
2172 			(*tap) = a;
2173 			(*tcp) = c;
2174 		}
2175 	}
2176 
2177 
2178 	/* Fields */
2179 	FLD_ITT_START (c_ptr->fld_idx, fld_ptr)
2180 	{
2181 		/* Memorized, visible fields */
2182 		if ((fld_ptr->info & (FIELD_INFO_MARK | FIELD_INFO_VIS)) ==
2183 			(FIELD_INFO_MARK | FIELD_INFO_VIS))
2184 		{
2185 			/* Remember field type */
2186 			map.field = fld_ptr->t_idx;
2187 
2188 			/* Keep this grid */
2189 			map.flags |= MAP_ONCE;
2190 
2191 			/* High priority tile */
2192 			map.priority = 20;
2193 
2194 			/* Which display level to use? */
2195 			if (fld_ptr->info & FIELD_INFO_FEAT)
2196 			{
2197 				/* Terrain level */
2198 				if ((use_graphics == GRAPHICS_ADAM_BOLT)
2199 					&& (fld_ptr->info & (FIELD_INFO_TRANS)))
2200 				{
2201 					/* Take into account dynamic lighting. */
2202 					c += fld_ptr->f_char - f_ptr->x_char;
2203 				}
2204 				else
2205 				{
2206 					/* Normal char */
2207 					c = fld_ptr->f_char;
2208 				}
2209 
2210 				/* Normal attr */
2211 				a = fld_ptr->f_attr;
2212 
2213 				/* Save the terrain info for the transparency effects */
2214 				(*tap) = a;
2215 				(*tcp) = c;
2216 			}
2217 			else
2218 			{
2219 				/* Tile */
2220 				c = fld_ptr->f_char;
2221 				a = fld_ptr->f_attr;
2222 
2223 				/* Do we need to look at objects? */
2224 				if (!(fld_ptr->info & (FIELD_INFO_IGNORE)))
2225 				{
2226 					/* Above objects */
2227 					float_field = TRUE;
2228 				}
2229 			}
2230 
2231 			/* Done */
2232 			break;
2233 		}
2234 	}
2235 	FLD_ITT_END;
2236 
2237 	/* Objects */
2238 	OBJ_ITT_START (c_ptr->o_idx, o_ptr)
2239 	{
2240 		/* Memorized objects */
2241 		if (o_ptr->info & (OB_SEEN))
2242 		{
2243 			k_ptr = &k_info[o_ptr->k_idx];
2244 
2245 			/* Flavoured object */
2246 			if (k_ptr->flavor)
2247 			{
2248 				/* Save flavor character */
2249 				map.unknown = k_ptr->d_char;
2250 			}
2251 			else
2252 			{
2253 				/* Save object */
2254 				map.object = o_ptr->k_idx;
2255 			}
2256 
2257 			/* Keep this grid */
2258 			map.flags |= MAP_ONCE;
2259 
2260 			/* High priority tile */
2261 			map.priority = 20;
2262 
2263 			/* A field is obscuring the view to the object */
2264 			if (float_field) break;
2265 
2266 			/* Hack -- hallucination */
2267 			if (halluc)
2268 			{
2269 				image_object(&a, &c);
2270 			}
2271 			else
2272 			{
2273 				/* Normal char */
2274 				c = object_char(o_ptr);
2275 
2276 				/* Normal attr */
2277 				a = object_attr(o_ptr);
2278 			}
2279 
2280 			/* Done */
2281 			break;
2282 		}
2283 	}
2284 	OBJ_ITT_END;
2285 
2286 
2287 	/* Handle monsters */
2288 	if (c_ptr->m_idx)
2289 	{
2290 		m_ptr = &m_list[c_ptr->m_idx];
2291 		r_ptr = &r_info[m_ptr->r_idx];
2292 
2293 		/* Get monster tile info */
2294 		map_mon_info(m_ptr, r_ptr, &a, &c, &map);
2295 
2296 		/* Not hallucinating and Mimic in los? */
2297 		if (!halluc && visible && !m_ptr->ml && FLAG(r_ptr, RF_CHAR_MIMIC))
2298 		{
2299 			/* Keep this grid */
2300 			map.flags |= MAP_ONCE;
2301 
2302 			/* Save mimic character */
2303 			map.unknown = r_ptr->d_char;
2304 		}
2305 
2306 		/* High priority tile */
2307 		map.priority = 24;
2308 	}
2309 
2310 	/* Hack -- fake monochrome */
2311 	if (fake_monochrome)
2312 	{
2313 		if (p_ptr->tim.invuln || !use_color) a = TERM_WHITE;
2314 		else if (p_ptr->tim.wraith_form) a = TERM_L_DARK;
2315 	}
2316 
2317 	/* Handle "player" */
2318 	if ((x == p_ptr->px) && (y == p_ptr->py))
2319 	{
2320 		monster_race *r_ptr = &r_info[0];
2321 
2322 		/* Get the "player" attr */
2323 		a = r_ptr->x_attr;
2324 
2325 		/* Get the "player" char */
2326 		c = r_ptr->x_char;
2327 #ifdef VARIABLE_PLAYER_GRAPH
2328 
2329 		variable_player_graph(&a, &c)
2330 #endif /* VARIABLE_PLAYER_GRAPH */
2331 
2332 		/* High priority tile */
2333 		map.priority = 50;
2334 	}
2335 
2336 	/* Save the info */
2337 	(*ap) = a;
2338 	(*cp) = c;
2339 
2340 	/* Save tile information */
2341 	map.a = a;
2342 	map.c = c;
2343 	map.ta = (*tap);
2344 	map.tc = (*tcp);
2345 
2346 	/* Save information in map */
2347 	save_map_location(x, y, &map);
2348 }
2349 
2350 
2351 /*
2352  * Update the overhead map (used when the visuals change)
2353  */
update_overhead_map(void)2354 void update_overhead_map(void)
2355 {
2356 	map_block *mb_ptr;
2357 
2358 	byte a, ta;
2359 	char c, tc;
2360 
2361 	int x, y;
2362 
2363 	MAP_ITT_START (mb_ptr)
2364 	{
2365 		MAP_GET_LOC(x, y);
2366 
2367 		if (in_boundsp(x, y))
2368 		{
2369 			/* Update the known tile at the location */
2370 			map_info(x, y, &a, &c, &ta, &tc);
2371 		}
2372 	}
2373 	MAP_ITT_END;
2374 }
2375 
2376 
2377 /*
2378  * Erase the map
2379  */
Term_erase_map(void)2380 void Term_erase_map(void)
2381 {
2382 	callback_list *callback;
2383 
2384 	/* Notify erasure of the map */
2385 	for (callback = callbacks[CALL_MAP_ERASE]; callback; callback = callback->next)
2386 	{
2387 		/* Execute the callback */
2388 		((map_erase_hook_type)callback->func) (callback->data);
2389 	}
2390 
2391 	/* Actually clear the map */
2392 	clear_map();
2393 }
2394 
2395 
2396 /*
2397  * Prints the map of the dungeon
2398  *
2399  * Note that, for efficiency, we contain an "optimized" version
2400  * of both "lite_spot()" and "print_rel()", and that we use the
2401  * "lite_spot()" function to display the player grid, if needed.
2402  *
2403  * This function may be called when the cache is wrong.
2404  */
prt_map(void)2405 void prt_map(void)
2406 {
2407 	int x, y;
2408 	int v;
2409 
2410 	/* map bounds */
2411 	s16b xmin, xmax, ymin, ymax;
2412 
2413 	int wid, hgt;
2414 
2415 	byte *pa;
2416 	char *pc;
2417 
2418 	byte *pta;
2419 	char *ptc;
2420 
2421 	/* Get size */
2422 	get_map_size(&wid, &hgt);
2423 
2424 	/* Access the cursor state */
2425 	(void)Term_get_cursor(&v);
2426 
2427 	/* Hide the cursor */
2428 	(void)Term_set_cursor(0);
2429 
2430 	/* Get bounds */
2431 	xmin = p_ptr->panel_x1;
2432 	xmax = p_ptr->panel_x2 - 1;
2433 	ymin = p_ptr->panel_y1;
2434 	ymax = p_ptr->panel_y2 - 1;
2435 
2436 	/* Pointers to current position in the string */
2437 	pa = mp_a;
2438 	pc = mp_c;
2439 
2440 	pta = mp_ta;
2441 	ptc = mp_tc;
2442 
2443 	/* Dump the map */
2444 	for (y = ymin; y <= ymax; y++)
2445 	{
2446 		/* Clear the arrays in case panel doesn't fill screen */
2447 		for (x = 0; x < wid; x++)
2448 		{
2449 			mp_a[x] = 0;
2450 			mp_c[x] = 0;
2451 			mp_ta[x] = 0;
2452 			mp_tc[x] = 0;
2453 		}
2454 
2455 		/* Scan the columns of row "y" */
2456 		for (x = xmin; x <= xmax; x++)
2457 		{
2458 			if (in_bounds2(x, y))
2459 			{
2460 				/* Get map info */
2461 				map_info(x, y, pa, pc, pta, ptc);
2462 			}
2463 
2464 			/* Advance */
2465 			pa++;
2466 			pc++;
2467 			pta++;
2468 			ptc++;
2469 		}
2470 
2471 
2472 		/* Point to start of line */
2473 		pa = mp_a;
2474 		pc = mp_c;
2475 		pta = mp_ta;
2476 		ptc = mp_tc;
2477 
2478 		/* Efficiency -- Redraw that row of the map */
2479 		Term_queue_line(COL_MAP, y - p_ptr->panel_y1 + ROW_MAP,
2480 						wid, pa, pc, pta, ptc);
2481 	}
2482 
2483 	/* Restore the cursor */
2484 	(void)Term_set_cursor(v);
2485 }
2486 
2487 
display_dungeon(void)2488 void display_dungeon(void)
2489 {
2490 	int px = p_ptr->px;
2491 	int py = p_ptr->py;
2492 
2493 	int x, y;
2494 	byte a;
2495 	char c;
2496 
2497 	int wid = Term->wid / 2, hgt = Term->hgt / 2;
2498 
2499 	byte ta;
2500 	char tc;
2501 
2502 	for (x = px - wid + 1; x <= px + wid; x++)
2503 	{
2504 		for (y = py - hgt + 1; y <= py + hgt; y++)
2505 		{
2506 			if (in_boundsp(x, y))
2507 			{
2508 				/* Update this square */
2509 				map_info(x, y, &a, &c, &ta, &tc);
2510 
2511 				/* Hack -- Queue it */
2512 				Term_queue_char(x - px + wid - 1, y - py + hgt - 1, a, c, ta,
2513 								tc);
2514 			}
2515 			else
2516 			{
2517 				/* Clear out-of-bound tiles */
2518 
2519 				/* Access darkness */
2520 				feature_type *f_ptr = &f_info[FEAT_NONE];
2521 
2522 				/* Normal attr */
2523 				a = f_ptr->x_attr;
2524 
2525 				/* Normal char */
2526 				c = f_ptr->x_char;
2527 
2528 				/* Hack -- Queue it */
2529 				Term_queue_char(x - px + wid - 1, y - py + hgt - 1, a, c, a, c);
2530 			}
2531 		}
2532 	}
2533 }
2534 
2535 
2536 /*
2537  * Hack -- priority array (see below)
2538  *
2539  * Note that all "walls" always look like "secret doors" (see "map_info()").
2540  *
2541  * This really needs to be done a better way.
2542  */
2543 static const byte priority_table[][2] =
2544 {
2545 	/* Dark */
2546 	{FEAT_NONE, 2},
2547 
2548 	/* Floors */
2549 	{FEAT_FLOOR, 5},
2550 
2551 	/* Walls */
2552 	{FEAT_SECRET, 10},
2553 	{FEAT_WALL_EXTRA, 10},
2554 	{FEAT_WALL_INNER, 10},
2555 	{FEAT_WALL_OUTER, 10},
2556 	{FEAT_WALL_SOLID, 10},
2557 
2558 
2559 	/* Perm Walls */
2560 	{FEAT_PERM_EXTRA, 10},
2561 	{FEAT_PERM_INNER, 10},
2562 	{FEAT_PERM_OUTER, 10},
2563 	{FEAT_PERM_SOLID, 10},
2564 
2565 	/* Quartz */
2566 	{FEAT_QUARTZ, 11},
2567 
2568 	/* Magma */
2569 	{FEAT_MAGMA, 12},
2570 
2571 	/* Rubble */
2572 	{FEAT_RUBBLE, 13},
2573 
2574 	/* Open doors */
2575 	{FEAT_OPEN, 15},
2576 	{FEAT_BROKEN, 15},
2577 
2578 	/* Closed doors */
2579 	{FEAT_CLOSED, 17},
2580 
2581 	/* Hidden gold */
2582 	{FEAT_QUARTZ_K, 19},
2583 	{FEAT_MAGMA_K, 19},
2584 
2585 	/* water, lava, & trees */
2586 	{FEAT_DEEP_WATER, 20},
2587 	{FEAT_SHAL_WATER, 20},
2588 	{FEAT_DEEP_LAVA, 20},
2589 	{FEAT_SHAL_LAVA, 20},
2590 	{FEAT_DIRT, 6},
2591 	{FEAT_GRASS, 6},
2592 	{FEAT_TREES, 6},
2593 	{FEAT_MOUNTAIN, 20},
2594 
2595 	/* Stairs */
2596 	{FEAT_LESS, 25},
2597 	{FEAT_MORE, 25},
2598 
2599 	/* End */
2600 	{0, 0}
2601 };
2602 
2603 
2604 /*
2605  * Hack -- a priority function (see below)
2606  */
priority(byte feat)2607 static byte priority(byte feat)
2608 {
2609 	int i = 0;
2610 
2611 	/* Scan the table */
2612 	while (priority_table[i][1])
2613 	{
2614 		/* Does the feature match? */
2615 		if (priority_table[i][0] == feat)
2616 		{
2617 			return (priority_table[i][1]);
2618 		}
2619 
2620 		/* Next entry */
2621 		i++;
2622 	}
2623 
2624 	/* Default - assume floor */
2625 	return (5);
2626 }
2627 
2628 
2629 /*
2630  * Equivalent function to map_info, but for displaying
2631  * the reduced-size dungeon map.
2632  *
2633  * We need to calculate priority as well as the symbols to display.
2634  *
2635  * We cheat by getting the symbol recorded previously.
2636  */
display_map_info(int x,int y,char * c,byte * a,char * tc,byte * ta)2637 static int display_map_info(int x, int y, char *c, byte *a, char *tc, byte *ta)
2638 {
2639 	int tp;
2640 
2641 	byte feat;
2642 
2643 	map_block *mb_ptr;
2644 
2645 	if (!map_in_bounds(x, y))
2646 	{
2647 		/*
2648 		 * Out of bounds
2649 		 * XXX Hack try anyway.
2650 		 *
2651 		 * map_info() should bring the square in bounds.
2652 		 */
2653 		map_info(x, y, a, c, ta, tc);
2654 	}
2655 
2656 
2657 	/* Get overhead map square */
2658 	mb_ptr = map_loc(x, y);
2659 
2660 	/* Default to precalculated priority */
2661 	tp = mb_ptr->priority;
2662 
2663 	if (!tp)
2664 	{
2665 		/* Get terrain feature */
2666 		feat = parea(x, y)->feat;
2667 
2668 		/* Extract the priority of that attr/char */
2669 		tp = priority(feat);
2670 	}
2671 
2672 	/* Get tile */
2673 	if (mb_ptr->a)
2674 	{
2675 		/* Get attributes from overhead map */
2676 		*a = mb_ptr->a;
2677 		*c = mb_ptr->c;
2678 		*ta = mb_ptr->ta;
2679 		*tc = mb_ptr->tc;
2680 	}
2681 	else
2682 	{
2683 		map_info(x, y, a, c, ta, tc);
2684 	}
2685 
2686 	/* Return priority */
2687 	return (tp);
2688 }
2689 
2690 
2691 /*
2692  * Display a "small-scale" map of the dungeon in the active Term
2693  *
2694  * Note that the "map_info()" function must return fully colorized
2695  * data or this function will not work correctly.
2696  *
2697  * Note that this function must "disable" the special lighting
2698  * effects so that the "priority" function will work.
2699  *
2700  * Note the use of a specialized "priority" function to allow this
2701  * function to work with any graphic attr/char mappings, and the
2702  * attempts to optimize this function where possible.
2703  *
2704  * cx and cy are offsets from the position of the player.  This
2705  * allows the map to be shifted around - but only works in the
2706  * wilderness.  cx and cy return the position of the player on the
2707  * possibly shifted map.
2708  */
display_map(int * cx,int * cy)2709 void display_map(int *cx, int *cy)
2710 {
2711 	int py = p_ptr->py;
2712 	int px = p_ptr->px;
2713 
2714 	int i, j, x, y;
2715 
2716 	byte feat;
2717 
2718 	byte ta;
2719 	char tc;
2720 
2721 	byte tta;
2722 	char ttc;
2723 
2724 	byte tp;
2725 
2726 	bool road;
2727 
2728 	u16b w_type, w_info, twn;
2729 
2730 	byte **ma;
2731 	char **mc;
2732 
2733 	byte **mp;
2734 
2735 	byte **mta;
2736 	char **mtc;
2737 
2738 	int hgt, wid, yrat, xrat, xfactor, yfactor;
2739 
2740 	place_type *pl_ptr;
2741 
2742 
2743 	/* Hack - disable bigtile mode */
2744 	if (use_bigtile)
2745 	{
2746 		Term_bigregion(-1, -1, -1);
2747 	}
2748 
2749 	/* Get size */
2750 	Term_get_size(&wid, &hgt);
2751 	hgt -= 2;
2752 	wid -= 2;
2753 
2754 	/* Paranoia */
2755 	if ((hgt < 3) || (wid < 3))
2756 	{
2757 		/*
2758 		 * Need to place the player...
2759 		 * This is wrong, but the map is too small anyway.
2760 		 */
2761 		(*cy) = ROW_MAP;
2762 		(*cx) = COL_MAP;
2763 		return;
2764 	}
2765 
2766 	/* Allocate the maps */
2767 	C_MAKE(ma, (hgt + 2), byte *);
2768 	C_MAKE(mc, (hgt + 2), char *);
2769 	C_MAKE(mp, (hgt + 2), byte *);
2770 
2771 	C_MAKE(mta, (hgt + 2), byte *);
2772 	C_MAKE(mtc, (hgt + 2), char *);
2773 
2774 	/* Allocate and wipe each line map */
2775 	for (i = 0; i < (hgt + 2); i++)
2776 	{
2777 		/* Allocate one row each array */
2778 		C_MAKE(ma[i], (wid + 2), byte);
2779 		C_MAKE(mc[i], (wid + 2), char);
2780 		C_MAKE(mp[i], (wid + 2), byte);
2781 
2782 		C_MAKE(mta[i], (wid + 2), byte);
2783 		C_MAKE(mtc[i], (wid + 2), char);
2784 	}
2785 
2786 	/* Clear the chars and attributes */
2787 	for (y = 0; y < hgt + 2; ++y)
2788 	{
2789 		for (x = 0; x < wid + 2; ++x)
2790 		{
2791 			/* Nothing here */
2792 			ma[y][x] = TERM_WHITE;
2793 			mc[y][x] = ' ';
2794 
2795 			mta[y][x] = TERM_WHITE;
2796 			mtc[y][x] = ' ';
2797 
2798 			/* No priority */
2799 			mp[y][x] = 0;
2800 		}
2801 	}
2802 
2803 	if (!p_ptr->depth)
2804 	{
2805 		/* Plot wilderness */
2806 
2807 		/* work out coords of player in wilderness */
2808 		x = px / 16 + *cx;
2809 		y = py / 16 + *cy;
2810 
2811 		/* recenter */
2812 		x = x - wid / 2;
2813 		if (x + wid >= max_wild) x = max_wild - wid - 1;
2814 		if (x < 0) x = 0;
2815 
2816 		y = y - hgt / 2;
2817 		if (y + hgt >= max_wild) y = max_wild - hgt - 1;
2818 		if (y < 0) y = 0;
2819 
2820 		/* Player location in wilderness */
2821 		(*cy) += py / 16 - y + ROW_MAP;
2822 		(*cx) += px / 16 - x + 1;
2823 
2824 		/* Fill in the map */
2825 		for (i = 0; i < wid; ++i)
2826 		{
2827 			for (j = 0; j < hgt; ++j)
2828 			{
2829 				/* Only draw blocks inside map */
2830 				if (((x + i + 1) >= max_wild)
2831 					|| ((y + j + 1) >= max_wild)) continue;
2832 
2833 				/* Only draw blocks that have been seen */
2834 				if (!(wild[j + y][i + x].done.info & WILD_INFO_SEEN)) continue;
2835 
2836 				w_type = wild[j + y][i + x].done.wild;
2837 				w_info = wild[j + y][i + x].done.info;
2838 
2839 				if (w_type < WILD_SEA)
2840 				{
2841 					/* Normal terrain */
2842 					feat = wild_gen_data[w_type].feat;
2843 
2844 					/* Allow roads to be drawn */
2845 					road = TRUE;
2846 				}
2847 				else
2848 				{
2849 					feat = FEAT_DEEP_WATER;
2850 
2851 					/* No roads please */
2852 					road = FALSE;
2853 				}
2854 
2855 				/* Add in effect of other specials */
2856 				if (w_info & (WILD_INFO_WATER))
2857 				{
2858 					feat = FEAT_DEEP_WATER;
2859 				}
2860 				else if (w_info & (WILD_INFO_ACID))
2861 				{
2862 					feat = FEAT_DEEP_ACID;
2863 				}
2864 				else if (w_info & (WILD_INFO_LAVA))
2865 				{
2866 					feat = FEAT_DEEP_LAVA;
2867 				}
2868 
2869 				/* This is a nasty hack */
2870 
2871 				/* Add in effects of roads */
2872 				if ((w_info & (WILD_INFO_ROAD)) && road)
2873 				{
2874 					ma[j + 1][i + 1] = TERM_UMBER;
2875 					mc[j + 1][i + 1] = '+';
2876 					feat = FEAT_NONE;
2877 				}
2878 				else if ((w_info & (WILD_INFO_TRACK)) && road)
2879 				{
2880 					ma[j + 1][i + 1] = TERM_L_UMBER;
2881 					mc[j + 1][i + 1] = '+';
2882 					feat = FEAT_NONE;
2883 				}
2884 
2885 				/* Hack - draw places */
2886 				/* Eventually will get attr,char from place data structure. */
2887 
2888 				twn = wild[j + y][i + x].done.place;
2889 
2890 				/* If there is a place... */
2891 				if (twn)
2892 				{
2893 					pl_ptr = &place[twn];
2894 
2895 					switch (place[twn].type)
2896 					{
2897 						case TOWN_QUEST:
2898 						{
2899 							/* Hack make a char / attr from depth */
2900 							wild_type *w_ptr = &wild[pl_ptr->y][pl_ptr->x];
2901 
2902 							int depth = (w_ptr->done.mon_gen + 9) / 10;
2903 
2904 							if (depth > 9) depth = 9;
2905 
2906 							/* Quests are red */
2907 							ma[j + 1][i + 1] = TERM_RED;
2908 							mc[j + 1][i + 1] = '0' + depth;
2909 							feat = FEAT_NONE;
2910 
2911 							break;
2912 						}
2913 
2914 						case TOWN_DUNGEON:
2915 						{
2916 							/* Hack make a char / attr from depth */
2917 							int depth = (pl_ptr->dungeon->min_level + 9) / 10;
2918 
2919 							if (depth > 9) depth = 9;
2920 
2921 							/* Dungeons are blue */
2922 							ma[j + 1][i + 1] = TERM_L_BLUE;
2923 							mc[j + 1][i + 1] = '0' + depth;
2924 							feat = FEAT_NONE;
2925 
2926 							break;
2927 						}
2928 
2929 						default:
2930 						{
2931 							/* Towns are white */
2932 							ma[j + 1][i + 1] = TERM_WHITE;
2933 							mc[j + 1][i + 1] = pl_ptr->name[0];
2934 							feat = FEAT_NONE;
2935 
2936 							break;
2937 						}
2938 					}
2939 				}
2940 
2941 				/* Finally show position of player */
2942 				if ((i + x == px / 16) && (j + y == py / 16))
2943 				{
2944 					ma[j + 1][i + 1] = TERM_WHITE;
2945 					mc[j + 1][i + 1] = '@';
2946 					feat = FEAT_NONE;
2947 				}
2948 
2949 				if (feat)
2950 				{
2951 					/* Get attr / char pair for wilderness block type */
2952 					ma[j + 1][i + 1] = f_info[feat].x_attr;
2953 					mc[j + 1][i + 1] = f_info[feat].x_char;
2954 
2955 					if (f_info[feat].w_attr)
2956 					{
2957 						mta[j + 1][i + 1] = f_info[feat].w_attr;
2958 						mtc[j + 1][i + 1] = f_info[feat].w_char;
2959 					}
2960 					else
2961 					{
2962 						mta[j + 1][i + 1] = ma[j + 1][i + 1];
2963 						mtc[j + 1][i + 1] = mc[j + 1][i + 1];
2964 					}
2965 				}
2966 			}
2967 		}
2968 	}
2969 	else
2970 	{
2971 		yrat = p_ptr->max_hgt - p_ptr->min_hgt;
2972 		xrat = p_ptr->max_wid - p_ptr->min_wid;
2973 
2974 		/* Get scaling factors */
2975 		yfactor = ((yrat / hgt < 4) && (yrat > hgt)) ? 10 : 1;
2976 		xfactor = ((xrat / wid < 4) && (xrat > wid)) ? 10 : 1;
2977 
2978 		yrat = (yrat * yfactor + hgt - 1) / hgt;
2979 		xrat = (xrat * xfactor + wid - 1) / wid;
2980 
2981 		/* Player location in dungeon */
2982 		(*cy) = py * yfactor / yrat + ROW_MAP;
2983 		(*cx) = px * xfactor / xrat + 1;
2984 
2985 		/* Fill in the map of dungeon */
2986 		for (i = p_ptr->min_wid; i < p_ptr->max_wid; ++i)
2987 		{
2988 			for (j = p_ptr->min_hgt; j < p_ptr->max_hgt; ++j)
2989 			{
2990 				/* Location */
2991 				x = i * xfactor / xrat + 1;
2992 				y = j * yfactor / yrat + 1;
2993 
2994 				/* Get priority and symbol */
2995 				tp = display_map_info(i, j, &tc, &ta, &ttc, &tta);
2996 
2997 				/* Save "best" */
2998 				if (mp[y][x] < tp)
2999 				{
3000 					/* Save the char */
3001 					mc[y][x] = tc;
3002 
3003 					/* Save the attr */
3004 					ma[y][x] = ta;
3005 
3006 					/* Save the transparency graphic */
3007 					mtc[y][x] = ttc;
3008 					mta[y][x] = tta;
3009 
3010 					/* Save priority */
3011 					mp[y][x] = tp;
3012 				}
3013 			}
3014 		}
3015 	}
3016 
3017 	/* Corners */
3018 	i = wid + 1;
3019 	j = hgt + 1;
3020 
3021 	/* Draw the corners */
3022 	mc[0][0] = '+';
3023 	mc[0][i] = '+';
3024 	mc[j][0] = '+';
3025 	mc[j][i] = '+';
3026 
3027 	/* Draw the horizontal edges */
3028 	for (i = 1; i <= wid; i++)
3029 	{
3030 		mc[0][i] = '-';
3031 		mc[j][i] = '-';
3032 	}
3033 
3034 	/* Draw the vertical edges */
3035 	for (j = 1; j <= hgt; j++)
3036 	{
3037 		mc[j][0] = '|';
3038 		mc[j][i] = '|';
3039 	}
3040 
3041 	/* Display each map line in order */
3042 	for (j = 0; j < hgt + 2; ++j)
3043 	{
3044 		/* Display the line */
3045 		for (i = 0; i < wid + 2; ++i)
3046 		{
3047 			ta = ma[j][i];
3048 			tc = mc[j][i];
3049 
3050 			tta = mta[j][i];
3051 			ttc = mtc[j][i];
3052 
3053 			/* Hack -- Queue it */
3054 			Term_queue_char(i, j, ta, tc, tta, ttc);
3055 		}
3056 	}
3057 
3058 	/* Free each line map */
3059 	for (i = 0; i < (hgt + 2); i++)
3060 	{
3061 		/* Free one row each array */
3062 		FREE(ma[i]);
3063 		FREE(mc[i]);
3064 		FREE(mta[i]);
3065 		FREE(mtc[i]);
3066 		FREE(mp[i]);
3067 	}
3068 
3069 	/* Free the maps */
3070 	FREE(ma);
3071 	FREE(mc);
3072 	FREE(mta);
3073 	FREE(mtc);
3074 	FREE(mp);
3075 }
3076 
3077 
3078 /*
3079  * Redraw (on the screen) a given MAP location
3080  *
3081  * This function should only be called on "legal" grids
3082  */
lite_spot(int x,int y)3083 void lite_spot(int x, int y)
3084 {
3085 	byte a;
3086 	char c;
3087 
3088 	byte ta;
3089 	char tc;
3090 
3091 	/* Paranoia */
3092 	if (!character_dungeon) return;
3093 
3094 	if (in_boundsp(x, y))
3095 	{
3096 		/* Update this square */
3097 		map_info(x, y, &a, &c, &ta, &tc);
3098 
3099 		/* Redraw if on screen */
3100 		if (panel_contains(x, y))
3101 		{
3102 			/* Real coordinates convert to screen positions */
3103 			x -= p_ptr->panel_x1 - COL_MAP;
3104 			y -= p_ptr->panel_y1 - ROW_MAP;
3105 
3106 			/* Hack -- Queue it */
3107 			Term_queue_char(x, y, a, c, ta, tc);
3108 		}
3109 	}
3110 }
3111 
3112 /*
3113  * Moves the cursor to a given MAP (x, y) location
3114  */
move_cursor_relative(int x,int y)3115 void move_cursor_relative(int x, int y)
3116 {
3117 	/* Real coordinates convert to screen positions */
3118 	x -= p_ptr->panel_x1 - COL_MAP;
3119 	y -= p_ptr->panel_y1 - ROW_MAP;
3120 
3121 	/* Go there */
3122 	Term_gotoxy(x, y);
3123 }
3124 
3125 
3126 /*
3127  * Place an attr/char pair at the given map coordinate, if legal.
3128  */
print_rel(char c,byte a,int x,int y)3129 void print_rel(char c, byte a, int x, int y)
3130 {
3131 	/* Only do "legal" locations */
3132 	if (panel_contains(x, y))
3133 	{
3134 		/* Hack -- fake monochrome */
3135 		if (fake_monochrome)
3136 		{
3137 			if (p_ptr->tim.invuln || !use_color) a = TERM_WHITE;
3138 			else if (p_ptr->tim.wraith_form) a = TERM_L_DARK;
3139 		}
3140 
3141 		/* Real coordinates convert to screen positions */
3142 		x -= p_ptr->panel_x1 - COL_MAP;
3143 		y -= p_ptr->panel_y1 - ROW_MAP;
3144 
3145 		/* Draw the char using the attr */
3146 		Term_queue_char(x, y, a, c, a, c);
3147 	}
3148 }
3149 
3150 /*
3151  * The player has moved
3152  */
Term_move_player(void)3153 void Term_move_player(void)
3154 {
3155 	set_player_location(p_ptr->px, p_ptr->py);
3156 }
3157 
3158 
3159 
3160 #ifdef TERM_USE_LIST
3161 
3162 /* Lists of objects on the player */
3163 list_item *equipment;
3164 int equip_num;
3165 
3166 list_item *inventory;
3167 int inven_num;
3168 
3169 
3170 /* Current list (Usually used for stores) */
3171 list_item *cur_list;
3172 int cur_num;
3173 
3174 
3175 /*
3176  * Delete the object list
3177  */
delete_list(list_item ** l_ptr_ptr,int * num)3178 static void delete_list(list_item **l_ptr_ptr, int *num)
3179 {
3180 	int i;
3181 
3182 	list_item *l_ptr;
3183 
3184 	for (i = 0; i < *num; i++)
3185 	{
3186 		/* Get item */
3187 		l_ptr = &((*l_ptr_ptr)[i]);
3188 
3189 		/* Delete strings */
3190 		string_free(l_ptr->o_name);
3191 		string_free(l_ptr->xtra_name);
3192 	}
3193 
3194 	/* No more items */
3195 	*num = 0;
3196 
3197 	/* Kill list */
3198 	KILL(*l_ptr_ptr);
3199 }
3200 
3201 /*
3202  * Copy a list from t_ptr to l_ptr_ptr
3203  *
3204  * The first list comes from the game, the second is
3205  * stored here for later use by the ports / borg.
3206  *
3207  * We assume l_ptr_ptr points to a NULL pointer.
3208  */
copy_list(term_list * t_ptr,int num1,list_item ** l_ptr_ptr,int * num2)3209 static void copy_list(term_list *t_ptr, int num1, list_item **l_ptr_ptr,
3210                       int *num2)
3211 {
3212 	list_item *l_ptr;
3213 	term_list *tl_ptr;
3214 
3215 	int i;
3216 
3217 	/* Paranoia */
3218 	if (*l_ptr_ptr) quit("Trying to copy over an allocated list.");
3219 
3220 	/* We don't need to make an empty list */
3221 	if (!num1) return;
3222 
3223 	/* Save number of items in list */
3224 	*num2 = num1;
3225 
3226 	/* Create the list */
3227 	C_MAKE(*l_ptr_ptr, num1, list_item);
3228 
3229 	for (i = 0; i < num1; i++)
3230 	{
3231 		l_ptr = &((*l_ptr_ptr)[i]);
3232 		tl_ptr = &t_ptr[i];
3233 
3234 		/* Duplicate flags */
3235 		l_ptr->kn_flags[0] = tl_ptr->kn_flags[0];
3236 		l_ptr->kn_flags[1] = tl_ptr->kn_flags[1];
3237 		l_ptr->kn_flags[2] = tl_ptr->kn_flags[2];
3238 		l_ptr->kn_flags[3] = tl_ptr->kn_flags[3];
3239 
3240 		/* Duplicate cost */
3241 		l_ptr->cost = tl_ptr->cost;
3242 
3243 		/* Duplicate item type and weight */
3244 		l_ptr->k_idx = tl_ptr->k_idx;
3245 		l_ptr->weight = tl_ptr->weight;
3246 		l_ptr->number = tl_ptr->number;
3247 
3248 		/* Duplicate info */
3249 		l_ptr->info = tl_ptr->info;
3250 
3251 		/* Duplicate pval /tval */
3252 		l_ptr->pval = tl_ptr->pval;
3253 		l_ptr->tval = tl_ptr->tval;
3254 
3255 		/* Duplicate timeout */
3256 		l_ptr->timeout = tl_ptr->timeout;
3257 
3258 		/* Duplicate bonuses */
3259 		l_ptr->to_h = tl_ptr->to_h;
3260 		l_ptr->to_d = tl_ptr->to_d;
3261 		l_ptr->to_a = tl_ptr->to_a;
3262 
3263 		/* Duplicate AC */
3264 		l_ptr->ac = tl_ptr->ac;
3265 
3266 		/* Duplicate Dice */
3267 		l_ptr->dd = tl_ptr->dd;
3268 		l_ptr->ds = tl_ptr->ds;
3269 
3270 		/* Duplicate strings */
3271 		l_ptr->o_name = string_make(tl_ptr->o_name);
3272 		l_ptr->xtra_name = string_make(tl_ptr->xtra_name);
3273 	}
3274 }
3275 
3276 /*
3277  * Save the object list so that the port can access it.
3278  */
save_object_list(term_list * l_ptr,int num,byte list_type)3279 static void save_object_list(term_list *l_ptr, int num, byte list_type)
3280 {
3281 	callback_list *callback;
3282 
3283 	if (list_type == LIST_INVEN)
3284 	{
3285 		/* Delete old inventory list */
3286 		delete_list(&inventory, &inven_num);
3287 
3288 		/* Copy over with the new list */
3289 		copy_list(l_ptr, num, &inventory, &inven_num);
3290 	}
3291 
3292 	if (list_type == LIST_EQUIP)
3293 	{
3294 		/* Delete old equipment list */
3295 		delete_list(&equipment, &equip_num);
3296 
3297 		/* Copy over with the new list */
3298 		copy_list(l_ptr, num, &equipment, &equip_num);
3299 	}
3300 
3301 	if ((list_type == LIST_STORE) || (list_type == LIST_HOME))
3302 	{
3303 		/* Delete the old current list */
3304 		delete_list(&cur_list, &cur_num);
3305 
3306 		/* Copy over with the new list */
3307 		copy_list(l_ptr, num, &cur_list, &cur_num);
3308 	}
3309 
3310 	/* Notify port */
3311 	for (callback = callbacks[CALL_OBJECT_LIST]; callback; callback = callback->next)
3312 	{
3313 		/* Execute the callback */
3314 		((list_notice_hook_type)callback->func) (list_type, callback->data);
3315 	}
3316 }
3317 
3318 /*
3319  * Set the basic object flags to send to the port
3320  */
set_basic_flags(term_list * l_ptr,object_type * o_ptr,bool in_store)3321 static void set_basic_flags(term_list *l_ptr, object_type *o_ptr, bool in_store)
3322 {
3323 	object_flags oflags;
3324 
3325 	/* Known flags */
3326 	object_flags_known(o_ptr, &oflags);
3327 
3328 	l_ptr->kn_flags[0] = oflags.flags[0];
3329 	l_ptr->kn_flags[1] = oflags.flags[1];
3330 	l_ptr->kn_flags[2] = oflags.flags[2];
3331 	l_ptr->kn_flags[3] = oflags.flags[3];
3332 
3333 	/* Type of object */
3334 	if (object_aware_p(o_ptr) || in_store)
3335 	{
3336 		l_ptr->k_idx = o_ptr->k_idx;
3337 	}
3338 
3339 	/* Weight and number */
3340 	l_ptr->weight = o_ptr->weight;
3341 	l_ptr->number = o_ptr->number;
3342 
3343 	/* Save information */
3344 	l_ptr->info = o_ptr->info;
3345 
3346 	/* Hack - Save cost (If not in a store, this will be inaccurate) */
3347 	l_ptr->cost = o_ptr->temp_cost;
3348 
3349 	/* Do we have extra name information? */
3350 	if (object_known_p(o_ptr) && (o_ptr->xtra_name))
3351 	{
3352 		l_ptr->xtra_name = string_make(quark_str(o_ptr->xtra_name));
3353 	}
3354 	else
3355 	{
3356 		l_ptr->xtra_name = NULL;
3357 	}
3358 
3359 	/* Damage dice */
3360 	l_ptr->dd = o_ptr->dd;
3361 	l_ptr->ds = o_ptr->ds;
3362 
3363 	/* Hack - only send AC information if isn't a wand */
3364 	if (o_ptr->tval != TV_WAND)
3365 	{
3366 		l_ptr->ac = o_ptr->ac;
3367 	}
3368 
3369 	/* Identified items yield extra information */
3370 	if (object_known_p(o_ptr))
3371 	{
3372 		/* Bonuses */
3373 		l_ptr->to_h = o_ptr->to_h;
3374 		l_ptr->to_d = o_ptr->to_d;
3375 		l_ptr->to_a = o_ptr->to_a;
3376 
3377 		/* Pval */
3378 		if ((o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_STAFF))
3379 		{
3380 			/* Wand and staff charges */
3381 			l_ptr->pval = o_ptr->pval;
3382 		}
3383 	}
3384 
3385 	/* Pval */
3386 	if (KN_FLAG(o_ptr, TR_PVAL_MASK))
3387 	{
3388 		/* Normal items with noticable pval */
3389 		l_ptr->pval = o_ptr->pval;
3390 	}
3391 
3392 	/* Tval */
3393 	l_ptr->tval = o_ptr->tval;
3394 
3395 	/* Timeout */
3396 	if (o_ptr->tval == TV_LITE)
3397 	{
3398 		/* Lights have "obvious" timeouts */
3399 		l_ptr->timeout = o_ptr->timeout;
3400 	}
3401 	else
3402 	{
3403 		/* Rods can charge in piles */
3404 		if ((o_ptr->number > 1) && (o_ptr->tval == TV_ROD))
3405 		{
3406 			int power;
3407 			object_kind *k_ptr = &k_info[o_ptr->k_idx];
3408 
3409 			/*
3410 			 * Find out how many rods are charging.
3411 			 */
3412 			power = (o_ptr->timeout + (k_ptr->pval - 1)) / k_ptr->pval;
3413 			if (power > o_ptr->number) power = o_ptr->number;
3414 
3415 			/* Hack - Set timeout to number of charging items */
3416 			l_ptr->timeout = power;
3417 		}
3418 		else
3419 		{
3420 			/* Are we charging? */
3421 			l_ptr->timeout = o_ptr->timeout ? 1 : 0;
3422 		}
3423 	}
3424 }
3425 
3426 /*
3427  * Write out the equipment so that the ports can access it.
3428  *
3429  * This is equivalent to Term_write_list() below, except with
3430  * a static array of objects rather than a list.
3431  */
Term_write_equipment(void)3432 void Term_write_equipment(void)
3433 {
3434 	term_list *list, *l_ptr;
3435 
3436 	int i;
3437 	object_type *o_ptr;
3438 	char o_name[256];
3439 
3440 	/* Create the list */
3441 	C_MAKE(list, EQUIP_MAX, term_list);
3442 
3443 	/* Fill with information */
3444 	for (i = 0; i < EQUIP_MAX; i++)
3445 	{
3446 		/* Get object */
3447 		o_ptr = &p_ptr->equipment[i];
3448 
3449 		if (!o_ptr->k_idx) continue;
3450 
3451 		/* Get object list element */
3452 		l_ptr = &list[i];
3453 
3454 		/* Set object flags */
3455 		set_basic_flags(l_ptr, o_ptr, FALSE);
3456 
3457 		/* Describe the object */
3458 		object_desc(o_name, o_ptr, TRUE, 3, 256);
3459 
3460 		l_ptr->o_name = string_make(o_name);
3461 	}
3462 
3463 	/* Save for later */
3464 	save_object_list(list, EQUIP_MAX, LIST_EQUIP);
3465 
3466 	for (i = 0; i < EQUIP_MAX; i++)
3467 	{
3468 		l_ptr = &list[i];
3469 
3470 		/* Free the strings */
3471 		string_free(l_ptr->o_name);
3472 		string_free(l_ptr->xtra_name);
3473 	}
3474 
3475 	/* Free the list */
3476 	FREE(list);
3477 }
3478 
3479 
3480 /*
3481  * Angband-specific code used to send a list of objects to the port.
3482  * This allows in-game data to be read.
3483  *
3484  * Hack - we assume every object in the list is 'visible'
3485  */
Term_write_list(s16b o_idx,byte list_type)3486 void Term_write_list(s16b o_idx, byte list_type)
3487 {
3488 	term_list *list, *l_ptr;
3489 
3490 	int i = 0;
3491 	object_type *o_ptr;
3492 	char o_name[256];
3493 
3494 	/* Get list length */
3495 	int num = get_list_length(o_idx);
3496 
3497 	/* Empty? */
3498 	if (!num)
3499 	{
3500 		/* We have an empty list */
3501 		save_object_list(NULL, 0, list_type);
3502 
3503 		return;
3504 	}
3505 
3506 	/* Create the list */
3507 	C_MAKE(list, num, term_list);
3508 
3509 	/* Fill with information */
3510 	OBJ_ITT_START (o_idx, o_ptr)
3511 	{
3512 		/* Get object list element */
3513 		l_ptr = &list[i];
3514 
3515 		/* Stores are special */
3516 		if (list_type == LIST_STORE)
3517 		{
3518 			/* Set object flags */
3519 			set_basic_flags(l_ptr, o_ptr, TRUE);
3520 
3521 			/* Describe the object */
3522 			object_desc_store(o_name, o_ptr, TRUE, 3, 256);
3523 		}
3524 		else
3525 		{
3526 			/* Set object flags */
3527 			set_basic_flags(l_ptr, o_ptr, FALSE);
3528 
3529 			/* Describe the object */
3530 			object_desc(o_name, o_ptr, TRUE, 3, 256);
3531 		}
3532 
3533 		l_ptr->o_name = string_make(o_name);
3534 
3535 		/* Increment counter */
3536 		i++;
3537 	}
3538 	OBJ_ITT_END;
3539 
3540 	/* Save for later */
3541 	save_object_list(list, num, list_type);
3542 
3543 	for (i = 0; i < num; i++)
3544 	{
3545 		l_ptr = &list[i];
3546 
3547 		/* Free the strings */
3548 		string_free(l_ptr->o_name);
3549 		string_free(l_ptr->xtra_name);
3550 	}
3551 
3552 	/* Free the list */
3553 	FREE(list);
3554 }
3555 
3556 #else  /* TERM_USE_LIST */
3557 
3558 /*** Make generic do-nothing functions ***/
3559 
Term_write_equipment(void)3560 void Term_write_equipment(void)
3561 {
3562 	/* Do nothing */
3563 }
3564 
Term_write_list(s16b o_idx,byte list_type)3565 void Term_write_list(s16b o_idx, byte list_type)
3566 {
3567 	/* Ignore parameters */
3568 	(void)o_idx;
3569 	(void)list_type;
3570 
3571 	/* Do nothing */
3572 }
3573 
3574 #endif /* TERM_USE_LIST */
3575 
3576