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