1 /* NetHack 3.7 glyphs.c TODO: add NHDT branch/date/revision tags */
2 /* Copyright (c) Michael Allison, 2021. */
3 /* NetHack may be freely redistributed. See license for details. */
7 extern const struct symparse loadsyms
[];
8 extern glyph_map glyphmap
[MAX_GLYPH
];
9 extern struct enum_dump monsdump
[];
10 extern struct enum_dump objdump
[];
12 #define Fprintf (void) fprintf
14 enum reserved_activities
{ res_nothing
, res_dump_glyphids
, res_fill_cache
};
15 enum things_to_find
{ find_nothing
, find_pm
, find_oc
, find_cmap
, find_glyph
};
17 enum things_to_find findtype
;
23 const char *unicode_val
; /* U+NNNN format */
24 void (*callback
)(int glyph
, struct find_struct
*);
25 enum reserved_activities restype
;
26 genericptr_t reserved
;
28 static const struct find_struct zero_find
= { 0 };
29 struct glyphid_cache_t
{
33 static struct glyphid_cache_t
*glyphid_cache
;
34 static unsigned glyphid_cache_lsize
;
35 static size_t glyphid_cache_size
;
36 static struct find_struct glyphcache_find
, to_custom_symbol_find
;
37 static const long nonzero_black
= CLR_BLACK
| NH_BASIC_COLOR
;
39 staticfn
void init_glyph_cache(void);
40 staticfn
void add_glyph_to_cache(int glyphnum
, const char *id
);
41 staticfn
int find_glyph_in_cache(const char *id
);
42 staticfn
char *find_glyphid_in_cache_by_glyphnum(int glyphnum
);
43 staticfn uint32
glyph_hash(const char *id
);
44 staticfn
void to_custom_symset_entry_callback(int glyph
,
45 struct find_struct
*findwhat
);
46 staticfn
int parse_id(const char *id
, struct find_struct
*findwhat
);
47 staticfn
int glyph_find_core(const char *id
, struct find_struct
*findwhat
);
48 staticfn
char *fix_glyphname(char *str
);
49 staticfn
void shuffle_customizations(void);
50 /* staticfn void purge_custom_entries(enum graphics_sets which_set); */
53 to_custom_symset_entry_callback(
55 struct find_struct
*findwhat
)
57 int idx
= gs
.symset_which_set
;
58 #ifdef ENHANCED_SYMBOLS
59 uint8 utf8str
[6] = { 0, 0, 0, 0, 0, 0 };
63 if (findwhat
->extraval
)
64 *findwhat
->extraval
= glyph
;
66 assert(idx
>= 0 && idx
< NUM_GRAPHICS
);
67 #ifdef ENHANCED_SYMBOLS
68 if (findwhat
->unicode_val
)
69 uval
= unicode_val(findwhat
->unicode_val
);
70 if (uval
&& unicodeval_to_utf8str(uval
, utf8str
, sizeof utf8str
)) {
71 /* presently the customizations are affiliated with a particular
72 * symset but if we don't have any symset context, ignore it for now
73 * in order to avoid a segfault.
75 * One future idea might be to store the U+ entries under "UTF8"
76 * and apply those customizations to any current symset if it has
77 * a UTF8 handler. Similar approach for unaffiliated glyph/symbols
78 * non-UTF color customizations
80 if (gs
.symset
[idx
].name
) {
81 add_custom_urep_entry(gs
.symset
[idx
].name
, glyph
, uval
,
82 utf8str
, gs
.symset_which_set
);
84 static int glyphnag
= 0;
87 config_error_add("Unimplemented customization feature,"
92 if (findwhat
->color
) {
93 if (gs
.symset
[idx
].name
) {
94 add_custom_nhcolor_entry(gs
.symset
[idx
].name
, glyph
,
95 findwhat
->color
, gs
.symset_which_set
);
97 static int colornag
= 0;
100 config_error_add("Unimplemented customization feature,"
101 " ignoring for now");
112 glyphrep_to_custom_map_entries(
116 to_custom_symbol_find
= zero_find
;
117 char buf
[BUFSZ
], *c_glyphid
, *c_unicode
, *c_colorval
, *cp
;
120 boolean slash
= FALSE
, colon
= FALSE
;
123 reslt
= 1; /* for debugger use only; no cache available */
126 Snprintf(buf
, sizeof buf
, "%s", op
);
127 c_unicode
= c_colorval
= (char *) 0;
128 c_glyphid
= cp
= buf
;
130 if (*cp
== ':' || *cp
== '/') {
150 /* some sanity checks */
151 if (c_glyphid
&& *c_glyphid
== ' ')
153 if (c_colorval
&& *c_colorval
== ' ')
155 if (c_unicode
&& *c_unicode
== ' ') {
156 while (*c_unicode
== ' ') {
160 if (c_unicode
&& !*c_unicode
)
163 if ((c_colorval
&& (rgb
= rgbstr_to_int32(c_colorval
)) != -1L)
165 /* if the color 0 is an actual color, as opposed to just "not set"
166 we set a marker bit outside the 24-bit range to indicate a
167 valid color value 0. That allows valid color 0, but allows a
168 simple checking for 0 to detect "not set". The window port that
169 implements the color switch, needs to either check that bit
170 or appropriately mask colors with 0xFFFFFF. */
171 to_custom_symbol_find
.color
= (rgb
== -1 || !c_colorval
) ? 0L
172 : (rgb
== 0L) ? nonzero_black
176 to_custom_symbol_find
.unicode_val
= c_unicode
;
177 to_custom_symbol_find
.extraval
= glyphptr
;
178 to_custom_symbol_find
.callback
= to_custom_symset_entry_callback
;
179 reslt
= glyph_find_core(c_glyphid
, &to_custom_symbol_find
);
184 fix_glyphname(char *str
)
188 for (c
= str
; *c
; c
++) {
189 if (*c
>= 'A' && *c
<= 'Z')
190 *c
+= (char) ('a' - 'A');
191 else if (*c
>= '0' && *c
<= '9')
193 else if (*c
< 'a' || *c
> 'z')
200 glyph_to_cmap(int glyph
)
202 if (glyph
== GLYPH_CMAP_STONE_OFF
)
204 else if (glyph_is_cmap_main(glyph
))
205 return (glyph
- GLYPH_CMAP_MAIN_OFF
) + S_vwall
;
206 else if (glyph_is_cmap_mines(glyph
))
207 return (glyph
- GLYPH_CMAP_MINES_OFF
) + S_vwall
;
208 else if (glyph_is_cmap_gehennom(glyph
))
209 return (glyph
- GLYPH_CMAP_GEH_OFF
) + S_vwall
;
210 else if (glyph_is_cmap_knox(glyph
))
211 return (glyph
- GLYPH_CMAP_KNOX_OFF
) + S_vwall
;
212 else if (glyph_is_cmap_sokoban(glyph
))
213 return (glyph
- GLYPH_CMAP_SOKO_OFF
) + S_vwall
;
214 else if (glyph_is_cmap_a(glyph
))
215 return (glyph
- GLYPH_CMAP_A_OFF
) + S_ndoor
;
216 else if (glyph_is_cmap_altar(glyph
))
218 else if (glyph_is_cmap_b(glyph
))
219 return (glyph
- GLYPH_CMAP_B_OFF
) + S_grave
;
220 else if (glyph_is_cmap_c(glyph
))
221 return (glyph
- GLYPH_CMAP_C_OFF
) + S_digbeam
;
222 else if (glyph_is_cmap_zap(glyph
))
223 return ((glyph
- GLYPH_ZAP_OFF
) % 4) + S_vbeam
;
224 else if (glyph_is_swallow(glyph
))
225 return glyph_to_swallow(glyph
) + S_sw_tl
;
226 else if (glyph_is_explosion(glyph
))
227 return glyph_to_explosion(glyph
) + S_expl_tl
;
229 return MAXPCHARS
; /* MAXPCHARS is legal array index because
230 * of trailing fencepost entry */
236 struct find_struct
*findwhat
)
239 boolean do_callback
, end_find
= FALSE
;
241 if (parse_id(id
, findwhat
)) {
242 if (findwhat
->findtype
== find_glyph
) {
243 (*findwhat
->callback
)(findwhat
->val
, findwhat
);
245 for (glyph
= 0; glyph
< MAX_GLYPH
; ++glyph
) {
247 switch (findwhat
->findtype
) {
249 if (glyph_to_cmap(glyph
) == findwhat
->val
)
253 if (glyph_is_monster(glyph
)
254 && monsym(&mons
[glyph_to_mon(glyph
)])
259 if (glyph_is_object(glyph
)
260 && glyph_to_obj(glyph
) == findwhat
->val
)
264 if (glyph
== findwhat
->val
) {
275 (findwhat
->callback
)(glyph
, findwhat
);
286 When we start to process a config file or a symbol file,
287 that might have G_ entries, generating all 9000+ glyphid
288 for comparison repeatedly each time we encounter a G_
289 entry to decipher, then comparing against them, is obviously
290 extremely performance-poor.
292 Setting aside the "comparison" part for now (that has to be
293 done in some manner), we can likely do something about the
294 repeated "generation" of the names for parsing prior to the
295 actual comparison part by generating them once, ahead of the
296 bulk of the potential parsings. We can later free up
297 all the memory those names consumed once the bulk parsing is
302 void fill_glyphid_cache(void)
306 if (!glyphid_cache
) {
310 glyphcache_find
= zero_find
;
311 glyphcache_find
.findtype
= find_nothing
;
312 glyphcache_find
.reserved
= (genericptr_t
) glyphid_cache
;
313 glyphcache_find
.restype
= res_fill_cache
;
314 reslt
= parse_id((char *) 0, &glyphcache_find
);
316 free_glyphid_cache();
317 glyphid_cache
= (struct glyphid_cache_t
*) 0;
323 * The glyph ID cache is a simple double-hash table.
324 * The cache size is a power of two, and two hashes are derived from the
325 * cache ID. The first is a location in the table, and the second is an
326 * offset. On any collision, the second hash is added to the first until
327 * a match or an empty bucket is found.
328 * The second hash is an odd number, which is necessary and sufficient
329 * to traverse the entire table.
333 init_glyph_cache(void)
337 /* Cache size of power of 2 not less than 2*MAX_GLYPH */
338 glyphid_cache_lsize
= 0;
339 glyphid_cache_size
= 1;
340 while (glyphid_cache_size
< 2*MAX_GLYPH
) {
341 ++glyphid_cache_lsize
;
342 glyphid_cache_size
<<= 1;
345 glyphid_cache
= (struct glyphid_cache_t
*) alloc(
346 glyphid_cache_size
* sizeof (struct glyphid_cache_t
));
347 for (glyph
= 0; glyph
< glyphid_cache_size
; ++glyph
) {
348 glyphid_cache
[glyph
].glyphnum
= 0;
349 glyphid_cache
[glyph
].id
= (char *) 0;
353 void free_glyphid_cache(void)
359 for (idx
= 0; idx
< glyphid_cache_size
; ++idx
) {
360 if (glyphid_cache
[idx
].id
) {
361 free(glyphid_cache
[idx
].id
);
362 glyphid_cache
[idx
].id
= (char *) 0;
366 glyphid_cache
= (struct glyphid_cache_t
*) 0;
370 add_glyph_to_cache(int glyphnum
, const char *id
)
372 uint32 hash
= glyph_hash(id
);
373 size_t hash1
= (size_t) (hash
& (glyphid_cache_size
- 1));
374 size_t hash2
= (size_t)
375 (((hash
>> glyphid_cache_lsize
) & (glyphid_cache_size
- 1)) | 1);
379 if (glyphid_cache
[i
].id
== NULL
) {
380 /* Empty bucket found */
381 glyphid_cache
[i
].id
= dupstr(id
);
382 glyphid_cache
[i
].glyphnum
= glyphnum
;
385 /* For speed, assume that no ID occurs twice */
386 i
= (i
+ hash2
) & (glyphid_cache_size
- 1);
387 } while (i
!= hash1
);
388 /* This should never happen */
389 panic("glyphid_cache full");
393 find_glyph_in_cache(const char *id
)
395 uint32 hash
= glyph_hash(id
);
396 size_t hash1
= (size_t) (hash
& (glyphid_cache_size
- 1));
397 size_t hash2
= (size_t)
398 (((hash
>> glyphid_cache_lsize
) & (glyphid_cache_size
- 1)) | 1);
402 if (glyphid_cache
[i
].id
== NULL
) {
403 /* Empty bucket found */
406 if (strcmpi(id
, glyphid_cache
[i
].id
) == 0) {
408 return glyphid_cache
[i
].glyphnum
;
410 i
= (i
+ hash2
) & (glyphid_cache_size
- 1);
411 } while (i
!= hash1
);
416 find_glyphid_in_cache_by_glyphnum(int glyphnum
)
422 for (idx
= 0; idx
< glyphid_cache_size
; ++idx
) {
423 if (glyphid_cache
[idx
].glyphnum
== glyphnum
424 && glyphid_cache
[idx
].id
!= 0) {
426 return glyphid_cache
[idx
].id
;
433 glyph_hash(const char *id
)
438 for (i
= 0; id
[i
] != '\0'; ++i
) {
440 if ('A' <= ch
&& ch
<= 'Z') {
443 hash
= (hash
<< 1) | (hash
>> 31);
450 glyphid_cache_status(void)
452 return (glyphid_cache
!= 0);
456 match_glyph(char *buf
)
460 /* buf contains a G_ glyph reference, not an S_ symbol.
461 There could be an R-G-B color attached too.
462 Let's get a copy to work with. */
463 Snprintf(workbuf
, sizeof workbuf
, "%s", buf
); /* get a copy */
464 return glyphrep(workbuf
);
468 glyphrep(const char *op
)
470 int reslt
= 0, glyph
= NO_GLYPH
;
473 reslt
= 1; /* for debugger use only; no cache available */
475 reslt
= glyphrep_to_custom_map_entries(op
, &glyph
);
482 add_custom_nhcolor_entry(
483 const char *customization_name
,
486 enum graphics_sets which_set
)
488 struct symset_customization
*gdc
489 = &gs
.sym_customizations
[which_set
][custom_nhcolor
];
490 struct customization_detail
*details
, *newdetails
= 0;
492 static uint32 closecolor
= 0;
493 static int clridx
= 0;
497 gdc
->customization_name
= dupstr(customization_name
);
498 gdc
->custtype
= custom_nhcolor
;
500 gdc
->details_end
= 0;
502 details
= find_matching_customization(customization_name
,
503 custom_nhcolor
, which_set
);
506 if (details
->content
.ccolor
.glyphidx
== glyphidx
) {
507 details
->content
.ccolor
.nhcolor
= nhcolor
;
510 details
= details
->next
;
513 /* create new details entry */
514 newdetails
= (struct customization_detail
*) alloc(sizeof *newdetails
);
515 newdetails
->content
.urep
.glyphidx
= glyphidx
;
516 newdetails
->content
.ccolor
.nhcolor
= nhcolor
;
517 newdetails
->next
= (struct customization_detail
*) 0;
518 if (gdc
->details
== NULL
) {
519 gdc
->details
= newdetails
;
521 gdc
->details_end
->next
= newdetails
;
523 gdc
->details_end
= newdetails
;
529 apply_customizations(
530 enum graphics_sets which_set
,
531 enum do_customizations docustomize
)
534 struct customization_detail
*details
;
535 struct symset_customization
*sc
;
536 boolean at_least_one
= FALSE
,
537 do_colors
= ((docustomize
& do_custom_colors
) != 0),
538 do_symbols
= ((docustomize
& do_custom_symbols
) != 0);
541 for (custs
= 0; custs
< (int) custom_count
; ++custs
) {
542 sc
= &gs
.sym_customizations
[which_set
][custs
];
543 if (sc
->count
&& sc
->details
) {
545 /* These glyph customizations get applied to the glyphmap array,
546 not to symset entries */
547 details
= sc
->details
;
549 #ifdef ENHANCED_SYMBOLS
550 if (iflags
.customsymbols
&& do_symbols
) {
551 if (sc
->custtype
== custom_ureps
) {
552 gmap
= &glyphmap
[details
->content
.urep
.glyphidx
];
553 if (gs
.symset
[which_set
].handling
== H_UTF8
)
554 (void) set_map_u(gmap
,
555 details
->content
.urep
.u
.utf32ch
,
556 details
->content
.urep
.u
.utf8str
);
560 if (iflags
.customcolors
&& do_colors
) {
561 if (sc
->custtype
== custom_nhcolor
) {
562 gmap
= &glyphmap
[details
->content
.ccolor
.glyphidx
];
563 (void) set_map_customcolor(gmap
,
564 details
->content
.ccolor
.nhcolor
);
567 details
= details
->next
;
572 shuffle_customizations();
576 /* Shuffle the customizations to match shuffled object descriptions,
577 * so a red potion isn't displayed with a blue customization, and so on.
582 shuffle_customizations(void)
584 static const int offsets
[2] = { GLYPH_OBJ_OFF
, GLYPH_OBJ_PILETOP_OFF
};
587 for (j
= 0; j
< SIZE(offsets
); j
++) {
588 glyph_map
*obj_glyphs
= glyphmap
+ offsets
[j
];
590 struct unicode_representation
*tmp_u
[NUM_OBJECTS
];
591 int duplicate
[NUM_OBJECTS
];
593 for (i
= 0; i
< NUM_OBJECTS
; i
++) {
595 tmp_u
[i
] = (struct unicode_representation
*) 0;
597 for (i
= 0; i
< NUM_OBJECTS
; i
++) {
598 int idx
= objects
[i
].oc_descr_idx
;
601 * Shuffling gem appearances can cause the same oc_descr_idx to
602 * appear more than once. Detect this condition and ensure that
603 * each pointer points to a unique allocation.
605 if (duplicate
[idx
] >= 0) {
606 /* Current structure already appears in tmp_u */
607 struct unicode_representation
*other
= tmp_u
[duplicate
[idx
]];
609 tmp_u
[i
] = (struct unicode_representation
*)
610 alloc(sizeof *tmp_u
[i
]);
612 if (other
->utf8str
!= NULL
) {
613 tmp_u
[i
]->utf8str
= (uint8
*)
614 dupstr((const char *) other
->utf8str
);
617 tmp_u
[i
] = obj_glyphs
[idx
].u
;
618 if (obj_glyphs
[idx
].u
!= NULL
) {
620 obj_glyphs
[idx
].u
= NULL
;
624 for (i
= 0; i
< NUM_OBJECTS
; i
++) {
625 /* Some glyphmaps may not have been transferred */
626 if (obj_glyphs
[i
].u
!= NULL
) {
627 free(obj_glyphs
[i
].u
->utf8str
);
628 free(obj_glyphs
[i
].u
);
630 obj_glyphs
[i
].u
= tmp_u
[i
];
637 shuffle_customizations(void)
639 static const int offsets
[2] = { GLYPH_OBJ_OFF
, GLYPH_OBJ_PILETOP_OFF
};
642 for (j
= 0; j
< SIZE(offsets
); j
++) {
643 glyph_map
*obj_glyphs
= glyphmap
+ offsets
[j
];
645 #ifdef ENHANCED_SYMBOLS
646 struct unicode_representation
*tmp_u
[NUM_OBJECTS
];
648 uint32 tmp_customcolor
[NUM_OBJECTS
];
649 uint16 tmp_color256idx
[NUM_OBJECTS
];
651 int duplicate
[NUM_OBJECTS
];
653 for (i
= 0; i
< NUM_OBJECTS
; i
++) {
655 #ifdef ENHANCED_SYMBOLS
656 tmp_u
[i
] = (struct unicode_representation
*) 0;
658 tmp_customcolor
[i
] = 0;
659 tmp_color256idx
[i
] = 0;
661 for (i
= 0; i
< NUM_OBJECTS
; i
++) {
662 int idx
= objects
[i
].oc_descr_idx
;
665 * Shuffling gem appearances can cause the same oc_descr_idx to
666 * appear more than once. Detect this condition and ensure that
667 * each pointer points to a unique allocation.
669 if (duplicate
[idx
] >= 0) {
670 #ifdef ENHANCED_SYMBOLS
671 /* Current structure already appears in tmp_u */
672 struct unicode_representation
*other
= tmp_u
[duplicate
[idx
]];
674 uint32 other_customcolor
= tmp_customcolor
[duplicate
[idx
]];
675 uint16 other_color256idx
= tmp_color256idx
[duplicate
[idx
]];
677 tmp_customcolor
[i
] = other_customcolor
;
678 tmp_color256idx
[i
] = other_color256idx
;
679 #ifdef ENHANCED_SYMBOLS
681 tmp_u
[i
] = (struct unicode_representation
*) alloc(
684 if (other
->utf8str
!= NULL
) {
686 (uint8
*) dupstr((const char *) other
->utf8str
);
691 tmp_customcolor
[i
] = obj_glyphs
[idx
].customcolor
;
692 tmp_color256idx
[i
] = obj_glyphs
[idx
].color256idx
;
693 #ifdef ENHANCED_SYMBOLS
694 tmp_u
[i
] = obj_glyphs
[idx
].u
;
697 #ifdef ENHANCED_SYMBOLS
698 obj_glyphs
[idx
].u
!= NULL
||
700 obj_glyphs
[idx
].customcolor
!= 0) {
702 #ifdef ENHANCED_SYMBOLS
703 obj_glyphs
[idx
].u
= NULL
;
705 obj_glyphs
[idx
].customcolor
= 0;
706 obj_glyphs
[idx
].color256idx
= 0;
710 for (i
= 0; i
< NUM_OBJECTS
; i
++) {
711 /* Some glyphmaps may not have been transferred */
712 #ifdef ENHANCED_SYMBOLS
713 if (obj_glyphs
[i
].u
!= NULL
) {
714 free(obj_glyphs
[i
].u
->utf8str
);
715 free(obj_glyphs
[i
].u
);
717 obj_glyphs
[i
].u
= tmp_u
[i
];
719 obj_glyphs
[i
].customcolor
= tmp_customcolor
[i
];
720 obj_glyphs
[i
].color256idx
= tmp_color256idx
[i
];
726 struct customization_detail
*
727 find_matching_customization(
728 const char *customization_name
,
729 enum customization_types custtype
,
730 enum graphics_sets which_set
)
732 struct symset_customization
*gdc
733 = &gs
.sym_customizations
[which_set
][custtype
];
735 if ((gdc
->custtype
== custtype
) && gdc
->customization_name
736 && (strcmp(customization_name
, gdc
->customization_name
) == 0))
738 return (struct customization_detail
*) 0;
742 purge_all_custom_entries(void)
746 for (i
= 0; i
< NUM_GRAPHICS
+ 1; ++i
) {
747 purge_custom_entries(i
);
752 purge_custom_entries(enum graphics_sets which_set
)
754 enum customization_types custtype
;
755 struct symset_customization
*gdc
;
756 struct customization_detail
*details
, *next
;
758 for (custtype
= custom_none
; custtype
< custom_count
; ++custtype
) {
759 gdc
= &gs
.sym_customizations
[which_set
][custtype
];
760 details
= gdc
->details
;
762 next
= details
->next
;
763 if (gdc
->custtype
== custom_ureps
) {
764 if (details
->content
.urep
.u
.utf8str
)
765 free(details
->content
.urep
.u
.utf8str
);
766 details
->content
.urep
.u
.utf8str
= (uint8
*) 0;
767 } else if (gdc
->custtype
== custom_symbols
) {
768 details
->content
.sym
.symparse
= (struct symparse
*) 0;
769 details
->content
.sym
.val
= 0;
770 } else if (gdc
->custtype
== custom_nhcolor
) {
771 details
->content
.ccolor
.nhcolor
= 0;
772 details
->content
.ccolor
.glyphidx
= 0;
778 gdc
->details_end
= 0;
779 if (gdc
->customization_name
) {
780 free((genericptr_t
) gdc
->customization_name
);
781 gdc
->customization_name
= 0;
787 dump_all_glyphids(FILE *fp
)
789 struct find_struct dump_glyphid_find
= zero_find
;
791 dump_glyphid_find
.findtype
= find_nothing
;
792 dump_glyphid_find
.reserved
= (genericptr_t
) fp
;
793 dump_glyphid_find
.restype
= res_dump_glyphids
;
794 (void) parse_id((char *) 0, &dump_glyphid_find
);
798 wizcustom_glyphids(winid win
)
805 for (glyphnum
= 0; glyphnum
< MAX_GLYPH
; ++glyphnum
) {
806 id
= find_glyphid_in_cache_by_glyphnum(glyphnum
);
808 wizcustom_callback(win
, glyphnum
, id
);
816 struct find_struct
*findwhat
)
818 FILE *fp
= (FILE *) 0;
819 int i
= 0, j
, mnum
, glyph
,
820 pm_offset
= 0, oc_offset
= 0, cmap_offset
= 0,
821 pm_count
= 0, oc_count
= 0, cmap_count
= 0;
822 boolean skip_base
= FALSE
, skip_this_one
, dump_ids
= FALSE
,
823 filling_cache
= FALSE
, is_S
= FALSE
, is_G
= FALSE
;
826 if (findwhat
->findtype
== find_nothing
&& findwhat
->restype
) {
827 if (findwhat
->restype
== res_dump_glyphids
) {
828 if (findwhat
->reserved
) {
829 fp
= (FILE *) findwhat
->reserved
;
835 if (findwhat
->restype
== res_fill_cache
) {
836 if (findwhat
->reserved
837 && findwhat
->reserved
== (genericptr_t
) glyphid_cache
) {
838 filling_cache
= TRUE
;
845 is_G
= (id
&& id
[0] == 'G' && id
[1] == '_');
846 is_S
= (id
&& id
[0] == 'S' && id
[1] == '_');
848 if ((is_G
&& !glyphid_cache
) || filling_cache
|| dump_ids
|| is_S
) {
849 while (loadsyms
[i
].range
) {
850 if (!pm_offset
&& loadsyms
[i
].range
== SYM_MON
)
852 if (!pm_count
&& pm_offset
&& loadsyms
[i
].range
!= SYM_MON
)
853 pm_count
= i
- pm_offset
;
854 if (!oc_offset
&& loadsyms
[i
].range
== SYM_OC
)
856 if (!oc_count
&& oc_offset
&& loadsyms
[i
].range
!= SYM_OC
)
857 oc_count
= i
- oc_offset
;
858 if (!cmap_offset
&& loadsyms
[i
].range
== SYM_PCHAR
)
860 if (!cmap_count
&& cmap_offset
&& loadsyms
[i
].range
!= SYM_PCHAR
)
861 cmap_count
= i
- cmap_offset
;
865 if (is_G
|| filling_cache
|| dump_ids
) {
866 if (!filling_cache
&& id
&& glyphid_cache
) {
867 int val
= find_glyph_in_cache(id
);
869 findwhat
->findtype
= find_glyph
;
871 findwhat
->loadsyms_offset
= 0;
877 const char *buf2
, *buf3
, *buf4
;
879 /* individual matching glyph entries */
880 for (glyph
= 0; glyph
< MAX_GLYPH
; ++glyph
) {
882 skip_this_one
= FALSE
;
883 buf
[0][0] = buf
[1][0] = buf
[2][0] = buf
[3][0] = '\0';
884 if (glyph_is_monster(glyph
)) {
885 /* buf2 will hold the distinguishing prefix */
886 /* buf3 will hold the base name */
888 buf3
= monsdump
[glyph_to_mon(glyph
)].nm
;
890 if (glyph_is_normal_male_monster(glyph
)) {
892 } else if (glyph_is_normal_female_monster(glyph
)) {
894 } else if (glyph_is_ridden_male_monster(glyph
)) {
895 buf2
= "ridden_male_";
896 } else if (glyph_is_ridden_female_monster(glyph
)) {
897 buf2
= "ridden_female_";
898 } else if (glyph_is_detected_male_monster(glyph
)) {
899 buf2
= "detected_male_";
900 } else if (glyph_is_detected_female_monster(glyph
)) {
901 buf2
= "detected_female_";
902 } else if (glyph_is_male_pet(glyph
)) {
904 } else if (glyph_is_female_pet(glyph
)) {
905 buf2
= "pet_female_";
907 Strcpy(buf
[0], "G_");
908 Strcat(buf
[0], buf2
);
909 Strcat(buf
[0], buf3
);
910 } else if (glyph_is_body(glyph
)) {
911 /* buf2 will hold the distinguishing prefix */
912 /* buf3 will hold the base name */
913 buf2
= glyph_is_body_piletop(glyph
)
916 buf3
= monsdump
[glyph_to_body_corpsenm(glyph
)].nm
;
917 Strcpy(buf
[0], "G_");
918 Strcat(buf
[0], buf2
);
919 Strcat(buf
[0], buf3
);
920 } else if (glyph_is_statue(glyph
)) {
921 /* buf2 will hold the distinguishing prefix */
922 /* buf3 will hold the base name */
923 buf2
= glyph_is_fem_statue_piletop(glyph
)
924 ? "piletop_statue_of_female_"
925 : glyph_is_fem_statue(glyph
)
926 ? "statue_of_female_"
927 : glyph_is_male_statue_piletop(glyph
)
928 ? "piletop_statue_of_male_"
929 : glyph_is_male_statue(glyph
)
931 : ""; /* shouldn't happen */
932 buf3
= monsdump
[glyph_to_statue_corpsenm(glyph
)].nm
;
933 Strcpy(buf
[0], "G_");
934 Strcat(buf
[0], buf2
);
935 Strcat(buf
[0], buf3
);
936 } else if (glyph_is_object(glyph
)) {
937 i
= glyph_to_obj(glyph
);
938 /* buf2 will hold the distinguishing prefix */
939 /* buf3 will hold the base name */
940 if (((i
> SCR_STINKING_CLOUD
) && (i
< SCR_MAIL
))
941 || ((i
> WAN_LIGHTNING
) && (i
< GOLD_PIECE
)))
942 skip_this_one
= TRUE
;
943 if (!skip_this_one
) {
944 if ((i
>= WAN_LIGHT
) && (i
<= WAN_LIGHTNING
))
946 else if ((i
>= SPE_DIG
) && (i
< SPE_BLANK_PAPER
))
947 buf2
= "spellbook of ";
948 else if ((i
>= SCR_ENCHANT_ARMOR
)
949 && (i
<= SCR_STINKING_CLOUD
))
951 else if ((i
>= POT_GAIN_ABILITY
) && (i
<= POT_WATER
))
952 buf2
= (i
== POT_WATER
) ? "flask of n"
954 else if ((i
>= RIN_ADORNMENT
)
955 && (i
<= RIN_PROTECTION_FROM_SHAPE_CHAN
))
957 else if (i
== LAND_MINE
)
961 buf3
= (i
== SCR_BLANK_PAPER
) ? "blank scroll"
962 : (i
== SPE_BLANK_PAPER
) ? "blank spellbook"
963 : (i
== SLIME_MOLD
) ? "slime mold"
964 : obj_descr
[i
].oc_name
965 ? obj_descr
[i
].oc_name
966 : obj_descr
[i
].oc_descr
;
967 Strcpy(buf
[0], "G_");
968 if (glyph_is_normal_piletop_obj(glyph
))
969 Strcat(buf
[0], "piletop_");
970 Strcat(buf
[0], buf2
);
971 Strcat(buf
[0], buf3
);
973 } else if (glyph_is_cmap(glyph
) || glyph_is_cmap_zap(glyph
)
974 || glyph_is_swallow(glyph
)
975 || glyph_is_explosion(glyph
)) {
978 /* buf2 will hold the distinguishing prefix */
979 /* buf3 will hold the base name */
980 /* buf4 will hold the distinguishing suffix */
984 if (glyph
== GLYPH_CMAP_OFF
) {
986 buf3
= "stone substrate";
988 } else if (glyph_is_cmap_gehennom(glyph
)) {
989 cmap
= (glyph
- GLYPH_CMAP_GEH_OFF
) + S_vwall
;
991 } else if (glyph_is_cmap_knox(glyph
)) {
992 cmap
= (glyph
- GLYPH_CMAP_KNOX_OFF
) + S_vwall
;
994 } else if (glyph_is_cmap_main(glyph
)) {
995 cmap
= (glyph
- GLYPH_CMAP_MAIN_OFF
) + S_vwall
;
997 } else if (glyph_is_cmap_mines(glyph
)) {
998 cmap
= (glyph
- GLYPH_CMAP_MINES_OFF
) + S_vwall
;
1000 } else if (glyph_is_cmap_sokoban(glyph
)) {
1001 cmap
= (glyph
- GLYPH_CMAP_SOKO_OFF
) + S_vwall
;
1003 } else if (glyph_is_cmap_a(glyph
)) {
1004 cmap
= (glyph
- GLYPH_CMAP_A_OFF
) + S_ndoor
;
1005 } else if (glyph_is_cmap_altar(glyph
)) {
1006 static const char *const altar_text
[] = {
1007 "unaligned", "chaotic", "neutral",
1011 j
= (glyph
- GLYPH_ALTAR_OFF
);
1013 if (j
!= altar_other
) {
1014 Snprintf(buf
[2], sizeof buf
[2], "%s_",
1018 buf3
= "altar other";
1021 } else if (glyph_is_cmap_b(glyph
)) {
1022 cmap
= (glyph
- GLYPH_CMAP_B_OFF
) + S_grave
;
1023 } else if (glyph_is_cmap_zap(glyph
)) {
1024 static const char *const zap_texts
[] = {
1025 "missile", "fire", "frost", "sleep",
1026 "death", "lightning", "poison gas", "acid"
1029 j
= (glyph
- GLYPH_ZAP_OFF
);
1030 cmap
= (j
% 4) + S_vbeam
;
1031 Snprintf(buf
[2], sizeof buf
[2], "%s",
1032 loadsyms
[cmap
+ cmap_offset
].name
+ 2);
1033 Snprintf(buf
[3], sizeof buf
[3], "%s zap %s",
1034 zap_texts
[j
/ 4], fix_glyphname(buf
[2]));
1038 } else if (glyph_is_cmap_c(glyph
)) {
1039 cmap
= (glyph
- GLYPH_CMAP_C_OFF
) + S_digbeam
;
1040 } else if (glyph_is_swallow(glyph
)) {
1041 static const char *const swallow_texts
[] = {
1042 "top left", "top center", "top right",
1043 "middle left", "middle right", "bottom left",
1044 "bottom center", "bottom right",
1047 j
= glyph
- GLYPH_SWALLOW_OFF
;
1048 cmap
= glyph_to_swallow(glyph
);
1049 mnum
= j
/ ((S_sw_br
- S_sw_tl
) + 1);
1050 Strcpy(buf
[3], "swallow ");
1051 Strcat(buf
[3], monsdump
[mnum
].nm
);
1052 Strcat(buf
[3], " ");
1053 Strcat(buf
[3], swallow_texts
[cmap
]);
1056 } else if (glyph_is_explosion(glyph
)) {
1057 static const char *const expl_type_texts
[] = {
1058 "dark", "noxious", "muddy", "wet",
1059 "magical", "fiery", "frosty",
1061 static const char *const expl_texts
[] = {
1062 "tl", "tc", "tr", "ml", "mc",
1063 "mr", "bl", "bc", "br",
1067 j
= glyph
- GLYPH_EXPLODE_OFF
;
1068 expl
= j
/ ((S_expl_br
- S_expl_tl
) + 1);
1069 cmap
= glyph_to_explosion(glyph
) + S_expl_tl
;
1070 i
= cmap
- S_expl_tl
;
1071 Snprintf(buf
[2], sizeof buf
[2], "%s ",
1072 expl_type_texts
[expl
]);
1074 Snprintf(buf
[3], sizeof buf
[3], "%s%s", "expl_",
1080 if (cmap
>= 0 && cmap
< MAXPCHARS
) {
1081 buf3
= loadsyms
[cmap
+ cmap_offset
].name
+ 2;
1084 Strcpy(buf
[0], "G_");
1085 Strcat(buf
[0], buf2
);
1086 Strcat(buf
[0], buf3
);
1087 Strcat(buf
[0], buf4
);
1088 } else if (glyph_is_invisible(glyph
)) {
1089 Strcpy(buf
[0], "G_invisible");
1090 } else if (glyph_is_nothing(glyph
)) {
1091 Strcpy(buf
[0], "G_nothing");
1092 } else if (glyph_is_unexplored(glyph
)) {
1093 Strcpy(buf
[0], "G_unexplored");
1094 } else if (glyph_is_warning(glyph
)) {
1095 j
= glyph
- GLYPH_WARNING_OFF
;
1096 Snprintf(buf
[0], sizeof buf
[0], "G_%s%d", "warning", j
);
1098 if (memchr(buf
[0], '\0', sizeof buf
[0]) == NULL
)
1099 panic("parse_id: buf[0] overflowed");
1100 if (!skip_this_one
) {
1101 fix_glyphname(buf
[0]+2);
1103 Fprintf(fp
, "(%04d) %s\n", glyph
, buf
[0]);
1104 } else if (filling_cache
) {
1105 add_glyph_to_cache(glyph
, buf
[0]);
1107 if (!strcmpi(id
, buf
[0])) {
1108 findwhat
->findtype
= find_glyph
;
1109 findwhat
->val
= glyph
;
1110 findwhat
->loadsyms_offset
= 0;
1116 } /* not glyphid_cache */
1119 for (i
= 0; i
< cmap_count
; ++i
) {
1120 if (!strcmpi(loadsyms
[i
+ cmap_offset
].name
+ 2, id
+ 2)) {
1121 findwhat
->findtype
= find_cmap
;
1123 findwhat
->loadsyms_offset
= i
+ cmap_offset
;
1127 /* objclass entries */
1128 for (i
= 0; i
< oc_count
; ++i
) {
1129 if (!strcmpi(loadsyms
[i
+ oc_offset
].name
+ 2, id
+ 2)) {
1130 findwhat
->findtype
= find_oc
;
1132 findwhat
->loadsyms_offset
= i
+ oc_offset
;
1136 /* permonst entries */
1137 for (i
= 0; i
<= pm_count
; ++i
) {
1138 if (!strcmpi(loadsyms
[i
+ pm_offset
].name
+ 2, id
+ 2)) {
1139 findwhat
->findtype
= find_pm
;
1140 findwhat
->val
= i
+ 1; /* starts at 1 */
1141 findwhat
->loadsyms_offset
= i
+ pm_offset
;
1146 if (dump_ids
|| filling_cache
)
1148 findwhat
->findtype
= find_nothing
;
1150 findwhat
->loadsyms_offset
= 0;
1154 /* extern glyph_map glyphmap[MAX_GLYPH]; */
1157 clear_all_glyphmap_colors(void)
1161 for (glyph
= 0; glyph
< MAX_GLYPH
; ++glyph
) {
1162 if (glyphmap
[glyph
].customcolor
)
1163 glyphmap
[glyph
].customcolor
= 0;
1164 glyphmap
[glyph
].color256idx
= 0;
1168 void reset_customcolors(void)
1170 clear_all_glyphmap_colors();
1171 apply_customizations(gc
.currentgraphics
, do_custom_colors
);
1177 staticfn
struct customization_detail
*find_display_sym_customization(
1178 const char *customization_name
, const struct symparse
*symparse
,
1179 enum graphics_sets which_set
);
1180 staticfn
struct customization_detail
*find_display_urep_customization(
1181 const char *customization_name
, int glyphidx
,
1182 enum graphics_sets which_set
);
1184 struct customization_detail
*
1185 find_display_sym_customization(
1186 const char *customization_name
,
1187 const struct symparse
*symparse
,
1188 enum graphics_sets which_set
)
1190 struct symset_customization
*gdc
;
1191 struct customization_detail
*symdetails
;
1193 gdc
= &gs
.sym_customizations
[which_set
][custom_symbols
];
1194 if ((gdc
->custtype
== custom_symbols
)
1195 && (strcmp(customization_name
, gdc
->customization_name
) == 0)) {
1196 symdetails
= gdc
->details
;
1197 while (symdetails
) {
1198 if (symdetails
->content
.sym
.symparse
== symparse
)
1200 symdetails
= symdetails
->next
;
1203 return (struct customization_detail
*) 0;
1206 struct customization_detail
*
1207 find_display_urep_customization(
1208 const char *customization_name
,
1210 enum graphics_sets which_set
)
1212 struct symset_customization
*gdc
= &gs
.sym_customizations
[which_set
];
1213 struct customization_detail
*urepdetails
;
1215 if ((gdc
->custtype
== custom_reps
)
1216 || (strcmp(customization_name
, gdc
->customization_name
) == 0)) {
1217 urepdetails
= gdc
->details
;
1218 while (urepdetails
) {
1219 if (urepdetails
->content
.urep
.glyphidx
== glyphidx
)
1221 urepdetails
= urepdetails
->next
;
1224 return (struct customization_detail
*) 0;
1226 #endif /* 0 not used yet */
1228 #ifdef TEST_GLYPHNAMES
1234 } cmapname
[MAXPCHARS
] = {
1241 test_glyphnames(void)
1245 reslt
= find_glyphs("G_potion_of_monster_detection");
1246 reslt
= find_glyphs("G_piletop_body_chickatrice");
1247 reslt
= find_glyphs("G_detected_male_homunculus");
1248 reslt
= find_glyphs("S_pool");
1249 reslt
= find_glyphs("S_dog");
1250 reslt
= glyphs_to_unicode("S_dog", "U+130E6", 0L);
1254 just_find_callback(int glyph UNUSED
, struct find_struct
*findwhat UNUSED
)
1260 find_glyphs(const char *id
)
1262 struct find_struct find_only
= zero_find
;
1264 find_only
.unicode_val
= 0;
1265 find_only
.callback
= just_find_callback
;
1266 return glyph_find_core(id
, &find_only
);
1270 to_unicode_callback(int glyph UNUSED
, struct find_struct
*findwhat
)
1273 #ifdef NO_PARSING_SYMSET
1274 glyph_map
*gm
= &glyphmap
[glyph
];
1278 if (!findwhat
->unicode_val
)
1280 uval
= unicode_val(findwhat
->unicode_val
);
1281 if (unicodeval_to_utf8str(uval
, utf8str
, sizeof utf8str
)) {
1282 #ifdef NO_PARSING_SYMSET
1283 set_map_u(gm
, uval
, utf8str
,
1284 (findwhat
->color
!= 0L) ? findwhat
->color
: 0L);
1292 glyphs_to_unicode(const char *id
, const char *unicode_val
, long clr
)
1294 struct find_struct to_unicode
= zero_find
;
1296 to_unicode
.unicode_val
= unicode_val
;
1297 to_unicode
.callback
= to_unicode_callback
;
1298 /* if the color 0 is an actual color, as opposed to just "not set"
1299 we set a marker bit outside the 24-bit range to indicate a
1300 valid color value 0. That allows valid color 0, but allows a
1301 simple checking for 0 to detect "not set". The window port that
1302 implements the color switch, needs to either check that bit
1303 or appropriately mask colors with 0xFFFFFF. */
1304 to_unicode
.color
= (clr
== -1) ? 0L : (clr
== 0L) ? nonzero_black
: clr
;
1305 return glyph_find_core(id
, &to_unicode
);
1308 #endif /* SOME TEST STUFF */