make rank() static again
[NetHack.git] / src / glyphs.c
blob8b6a77854d243421429bde8c29a81028f37b2309
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. */
5 #include "hack.h"
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 };
16 struct find_struct {
17 enum things_to_find findtype;
18 int val;
19 int loadsyms_offset;
20 int loadsyms_count;
21 int *extraval;
22 uint32 color;
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 {
30 int glyphnum;
31 char *id;
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); */
52 staticfn void
53 to_custom_symset_entry_callback(
54 int glyph,
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 };
60 int uval = 0;
61 #endif
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.
74 * FIXME:
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);
83 } else {
84 static int glyphnag = 0;
86 if (!glyphnag++)
87 config_error_add("Unimplemented customization feature,"
88 " ignoring for now");
91 #endif
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);
96 } else {
97 static int colornag = 0;
99 if (!colornag++)
100 config_error_add("Unimplemented customization feature,"
101 " ignoring for now");
107 * Return value:
108 * 1 = success
109 * 0 = failure
112 glyphrep_to_custom_map_entries(
113 const char *op,
114 int *glyphptr)
116 to_custom_symbol_find = zero_find;
117 char buf[BUFSZ], *c_glyphid, *c_unicode, *c_colorval, *cp;
118 int reslt = 0;
119 long rgb = 0L;
120 boolean slash = FALSE, colon = FALSE;
122 if (!glyphid_cache)
123 reslt = 1; /* for debugger use only; no cache available */
124 nhUse(reslt);
126 Snprintf(buf, sizeof buf, "%s", op);
127 c_unicode = c_colorval = (char *) 0;
128 c_glyphid = cp = buf;
129 while (*cp) {
130 if (*cp == ':' || *cp == '/') {
131 if (*cp == ':') {
132 colon = TRUE;
133 *cp = '\0';
135 if (*cp == '/') {
136 slash = TRUE;
137 *cp = '\0';
140 cp++;
141 if (colon) {
142 c_unicode = cp;
143 colon = FALSE;
145 if (slash) {
146 c_colorval = cp;
147 slash = FALSE;
150 /* some sanity checks */
151 if (c_glyphid && *c_glyphid == ' ')
152 c_glyphid++;
153 if (c_colorval && *c_colorval == ' ')
154 c_colorval++;
155 if (c_unicode && *c_unicode == ' ') {
156 while (*c_unicode == ' ') {
157 c_unicode++;
160 if (c_unicode && !*c_unicode)
161 c_unicode = 0;
163 if ((c_colorval && (rgb = rgbstr_to_int32(c_colorval)) != -1L)
164 || !c_colorval) {
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
173 : rgb;
175 if (c_unicode)
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);
180 return reslt;
183 staticfn char *
184 fix_glyphname(char *str)
186 char *c;
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')
194 *c = '_';
196 return str;
200 glyph_to_cmap(int glyph)
202 if (glyph == GLYPH_CMAP_STONE_OFF)
203 return S_stone;
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))
217 return S_altar;
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;
228 else
229 return MAXPCHARS; /* MAXPCHARS is legal array index because
230 * of trailing fencepost entry */
233 staticfn int
234 glyph_find_core(
235 const char *id,
236 struct find_struct *findwhat)
238 int glyph;
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);
244 } else {
245 for (glyph = 0; glyph < MAX_GLYPH; ++glyph) {
246 do_callback = FALSE;
247 switch (findwhat->findtype) {
248 case find_cmap:
249 if (glyph_to_cmap(glyph) == findwhat->val)
250 do_callback = TRUE;
251 break;
252 case find_pm:
253 if (glyph_is_monster(glyph)
254 && monsym(&mons[glyph_to_mon(glyph)])
255 == findwhat->val)
256 do_callback = TRUE;
257 break;
258 case find_oc:
259 if (glyph_is_object(glyph)
260 && glyph_to_obj(glyph) == findwhat->val)
261 do_callback = TRUE;
262 break;
263 case find_glyph:
264 if (glyph == findwhat->val) {
265 do_callback = TRUE;
266 end_find = TRUE;
268 break;
269 case find_nothing:
270 default:
271 end_find = TRUE;
272 break;
274 if (do_callback)
275 (findwhat->callback)(glyph, findwhat);
276 if (end_find)
277 break;
280 return 1;
282 return 0;
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
298 over with.
302 void fill_glyphid_cache(void)
304 int reslt = 0;
306 if (!glyphid_cache) {
307 init_glyph_cache();
309 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);
315 if (!reslt) {
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.
332 staticfn void
333 init_glyph_cache(void)
335 size_t glyph;
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)
355 size_t idx;
357 if (!glyphid_cache)
358 return;
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;
365 free(glyphid_cache);
366 glyphid_cache = (struct glyphid_cache_t *) 0;
369 staticfn void
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);
376 size_t i = hash1;
378 do {
379 if (glyphid_cache[i].id == NULL) {
380 /* Empty bucket found */
381 glyphid_cache[i].id = dupstr(id);
382 glyphid_cache[i].glyphnum = glyphnum;
383 return;
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");
392 staticfn int
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);
399 size_t i = hash1;
401 do {
402 if (glyphid_cache[i].id == NULL) {
403 /* Empty bucket found */
404 return -1;
406 if (strcmpi(id, glyphid_cache[i].id) == 0) {
407 /* Match found */
408 return glyphid_cache[i].glyphnum;
410 i = (i + hash2) & (glyphid_cache_size - 1);
411 } while (i != hash1);
412 return -1;
415 staticfn char *
416 find_glyphid_in_cache_by_glyphnum(int glyphnum)
418 size_t idx;
420 if (!glyphid_cache)
421 return (char *) 0;
422 for (idx = 0; idx < glyphid_cache_size; ++idx) {
423 if (glyphid_cache[idx].glyphnum == glyphnum
424 && glyphid_cache[idx].id != 0) {
425 /* Match found */
426 return glyphid_cache[idx].id;
429 return (char *) 0;
432 staticfn uint32
433 glyph_hash(const char *id)
435 uint32 hash = 0;
436 size_t i;
438 for (i = 0; id[i] != '\0'; ++i) {
439 char ch = id[i];
440 if ('A' <= ch && ch <= 'Z') {
441 ch += 'a' - 'A';
443 hash = (hash << 1) | (hash >> 31);
444 hash ^= ch;
446 return hash;
449 boolean
450 glyphid_cache_status(void)
452 return (glyphid_cache != 0);
456 match_glyph(char *buf)
458 char workbuf[BUFSZ];
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;
472 if (!glyphid_cache)
473 reslt = 1; /* for debugger use only; no cache available */
474 nhUse(reslt);
475 reslt = glyphrep_to_custom_map_entries(op, &glyph);
476 if (reslt)
477 return 1;
478 return 0;
482 add_custom_nhcolor_entry(
483 const char *customization_name,
484 int glyphidx,
485 uint32 nhcolor,
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;
491 #if 0
492 static uint32 closecolor = 0;
493 static int clridx = 0;
494 #endif
496 if (!gdc->details) {
497 gdc->customization_name = dupstr(customization_name);
498 gdc->custtype = custom_nhcolor;
499 gdc->details = 0;
500 gdc->details_end = 0;
502 details = find_matching_customization(customization_name,
503 custom_nhcolor, which_set);
504 if (details) {
505 while (details) {
506 if (details->content.ccolor.glyphidx == glyphidx) {
507 details->content.ccolor.nhcolor = nhcolor;
508 return 1;
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;
520 } else {
521 gdc->details_end->next = newdetails;
523 gdc->details_end = newdetails;
524 gdc->count++;
525 return 1;
528 void
529 apply_customizations(
530 enum graphics_sets which_set,
531 enum do_customizations docustomize)
533 glyph_map *gmap;
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);
539 int custs;
541 for (custs = 0; custs < (int) custom_count; ++custs) {
542 sc = &gs.sym_customizations[which_set][custs];
543 if (sc->count && sc->details) {
544 at_least_one = TRUE;
545 /* These glyph customizations get applied to the glyphmap array,
546 not to symset entries */
547 details = sc->details;
548 while (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);
559 #endif
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;
571 if (at_least_one) {
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.
580 #if 0
581 staticfn void
582 shuffle_customizations(void)
584 static const int offsets[2] = { GLYPH_OBJ_OFF, GLYPH_OBJ_PILETOP_OFF };
585 int j;
587 for (j = 0; j < SIZE(offsets); j++) {
588 glyph_map *obj_glyphs = glyphmap + offsets[j];
589 int i;
590 struct unicode_representation *tmp_u[NUM_OBJECTS];
591 int duplicate[NUM_OBJECTS];
593 for (i = 0; i < NUM_OBJECTS; i++) {
594 duplicate[i] = -1;
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]);
611 *tmp_u[i] = *other;
612 if (other->utf8str != NULL) {
613 tmp_u[i]->utf8str = (uint8 *)
614 dupstr((const char *) other->utf8str);
616 } else {
617 tmp_u[i] = obj_glyphs[idx].u;
618 if (obj_glyphs[idx].u != NULL) {
619 duplicate[idx] = i;
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];
635 #else
636 staticfn void
637 shuffle_customizations(void)
639 static const int offsets[2] = { GLYPH_OBJ_OFF, GLYPH_OBJ_PILETOP_OFF };
640 int j;
642 for (j = 0; j < SIZE(offsets); j++) {
643 glyph_map *obj_glyphs = glyphmap + offsets[j];
644 int i;
645 #ifdef ENHANCED_SYMBOLS
646 struct unicode_representation *tmp_u[NUM_OBJECTS];
647 #endif
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++) {
654 duplicate[i] = -1;
655 #ifdef ENHANCED_SYMBOLS
656 tmp_u[i] = (struct unicode_representation *) 0;
657 #endif
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]];
673 #endif
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
680 if (other) {
681 tmp_u[i] = (struct unicode_representation *) alloc(
682 sizeof *tmp_u[i]);
683 *tmp_u[i] = *other;
684 if (other->utf8str != NULL) {
685 tmp_u[i]->utf8str =
686 (uint8 *) dupstr((const char *) other->utf8str);
689 #endif
690 } else {
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;
695 #endif
696 if (
697 #ifdef ENHANCED_SYMBOLS
698 obj_glyphs[idx].u != NULL ||
699 #endif
700 obj_glyphs[idx].customcolor != 0) {
701 duplicate[idx] = i;
702 #ifdef ENHANCED_SYMBOLS
703 obj_glyphs[idx].u = NULL;
704 #endif
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];
718 #endif
719 obj_glyphs[i].customcolor = tmp_customcolor[i];
720 obj_glyphs[i].color256idx = tmp_color256idx[i];
724 #endif
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))
737 return gdc->details;
738 return (struct customization_detail *) 0;
741 void
742 purge_all_custom_entries(void)
744 int i;
746 for (i = 0; i < NUM_GRAPHICS + 1; ++i) {
747 purge_custom_entries(i);
751 void
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;
761 while (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;
774 free(details);
775 details = next;
777 gdc->details = 0;
778 gdc->details_end = 0;
779 if (gdc->customization_name) {
780 free((genericptr_t) gdc->customization_name);
781 gdc->customization_name = 0;
783 gdc->count = 0;
786 void
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);
797 void
798 wizcustom_glyphids(winid win)
800 int glyphnum;
801 char *id;
803 if (!glyphid_cache)
804 return;
805 for (glyphnum = 0; glyphnum < MAX_GLYPH; ++glyphnum) {
806 id = find_glyphid_in_cache_by_glyphnum(glyphnum);
807 if (id) {
808 wizcustom_callback(win, glyphnum, id);
813 staticfn int
814 parse_id(
815 const char *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;
824 char buf[4][QBUFSZ];
826 if (findwhat->findtype == find_nothing && findwhat->restype) {
827 if (findwhat->restype == res_dump_glyphids) {
828 if (findwhat->reserved) {
829 fp = (FILE *) findwhat->reserved;
830 dump_ids = TRUE;
831 } else {
832 return 0;
835 if (findwhat->restype == res_fill_cache) {
836 if (findwhat->reserved
837 && findwhat->reserved == (genericptr_t) glyphid_cache) {
838 filling_cache = TRUE;
839 } else {
840 return 0;
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)
851 pm_offset = i;
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)
855 oc_offset = i;
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)
859 cmap_offset = i;
860 if (!cmap_count && cmap_offset && loadsyms[i].range != SYM_PCHAR)
861 cmap_count = i - cmap_offset;
862 i++;
865 if (is_G || filling_cache || dump_ids) {
866 if (!filling_cache && id && glyphid_cache) {
867 int val = find_glyph_in_cache(id);
868 if (val >= 0) {
869 findwhat->findtype = find_glyph;
870 findwhat->val = val;
871 findwhat->loadsyms_offset = 0;
872 return 1;
873 } else {
874 return 0;
876 } else {
877 const char *buf2, *buf3, *buf4;
879 /* individual matching glyph entries */
880 for (glyph = 0; glyph < MAX_GLYPH; ++glyph) {
881 skip_base = FALSE;
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 */
887 buf2 = "";
888 buf3 = monsdump[glyph_to_mon(glyph)].nm;
890 if (glyph_is_normal_male_monster(glyph)) {
891 buf2 = "male_";
892 } else if (glyph_is_normal_female_monster(glyph)) {
893 buf2 = "female_";
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)) {
903 buf2 = "pet_male_";
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)
914 ? "piletop_body_"
915 : "body_";
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)
930 ? "statue_of_male_"
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))
945 buf2 = "wand of ";
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))
950 buf2 = "scroll of ";
951 else if ((i >= POT_GAIN_ABILITY) && (i <= POT_WATER))
952 buf2 = (i == POT_WATER) ? "flask of n"
953 : "potion of ";
954 else if ((i >= RIN_ADORNMENT)
955 && (i <= RIN_PROTECTION_FROM_SHAPE_CHAN))
956 buf2 = "ring of ";
957 else if (i == LAND_MINE)
958 buf2 = "unset ";
959 else
960 buf2 = "";
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)) {
976 int cmap = -1;
978 /* buf2 will hold the distinguishing prefix */
979 /* buf3 will hold the base name */
980 /* buf4 will hold the distinguishing suffix */
981 buf2 = "";
982 buf3 = "";
983 buf4 = "";
984 if (glyph == GLYPH_CMAP_OFF) {
985 cmap = S_stone;
986 buf3 = "stone substrate";
987 skip_base = TRUE;
988 } else if (glyph_is_cmap_gehennom(glyph)) {
989 cmap = (glyph - GLYPH_CMAP_GEH_OFF) + S_vwall;
990 buf4 = "_gehennom";
991 } else if (glyph_is_cmap_knox(glyph)) {
992 cmap = (glyph - GLYPH_CMAP_KNOX_OFF) + S_vwall;
993 buf4 = "_knox";
994 } else if (glyph_is_cmap_main(glyph)) {
995 cmap = (glyph - GLYPH_CMAP_MAIN_OFF) + S_vwall;
996 buf4 = "_main";
997 } else if (glyph_is_cmap_mines(glyph)) {
998 cmap = (glyph - GLYPH_CMAP_MINES_OFF) + S_vwall;
999 buf4 = "_mines";
1000 } else if (glyph_is_cmap_sokoban(glyph)) {
1001 cmap = (glyph - GLYPH_CMAP_SOKO_OFF) + S_vwall;
1002 buf4 = "_sokoban";
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",
1008 "lawful", "other",
1011 j = (glyph - GLYPH_ALTAR_OFF);
1012 cmap = S_altar;
1013 if (j != altar_other) {
1014 Snprintf(buf[2], sizeof buf[2], "%s_",
1015 altar_text[j]);
1016 buf2 = buf[2];
1017 } else {
1018 buf3 = "altar other";
1019 skip_base = TRUE;
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]));
1035 buf3 = buf[3];
1036 buf2 = "";
1037 skip_base = TRUE;
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]);
1054 buf3 = buf[3];
1055 skip_base = TRUE;
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",
1065 int expl;
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]);
1073 buf2 = buf[2];
1074 Snprintf(buf[3], sizeof buf[3], "%s%s", "expl_",
1075 expl_texts[i]);
1076 buf3 = buf[3];
1077 skip_base = TRUE;
1079 if (!skip_base) {
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);
1102 if (dump_ids) {
1103 Fprintf(fp, "(%04d) %s\n", glyph, buf[0]);
1104 } else if (filling_cache) {
1105 add_glyph_to_cache(glyph, buf[0]);
1106 } else if (id) {
1107 if (!strcmpi(id, buf[0])) {
1108 findwhat->findtype = find_glyph;
1109 findwhat->val = glyph;
1110 findwhat->loadsyms_offset = 0;
1111 return 1;
1116 } /* not glyphid_cache */
1117 } else if (is_S) {
1118 /* cmap entries */
1119 for (i = 0; i < cmap_count; ++i) {
1120 if (!strcmpi(loadsyms[i + cmap_offset].name + 2, id + 2)) {
1121 findwhat->findtype = find_cmap;
1122 findwhat->val = i;
1123 findwhat->loadsyms_offset = i + cmap_offset;
1124 return 1;
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;
1131 findwhat->val = i;
1132 findwhat->loadsyms_offset = i + oc_offset;
1133 return 1;
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;
1142 return 1;
1146 if (dump_ids || filling_cache)
1147 return 1;
1148 findwhat->findtype = find_nothing;
1149 findwhat->val = 0;
1150 findwhat->loadsyms_offset = 0;
1151 return 0;
1154 /* extern glyph_map glyphmap[MAX_GLYPH]; */
1156 void
1157 clear_all_glyphmap_colors(void)
1159 int glyph;
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);
1174 /* not used yet */
1176 #if 0
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)
1199 return symdetails;
1200 symdetails = symdetails->next;
1203 return (struct customization_detail *) 0;
1206 struct customization_detail *
1207 find_display_urep_customization(
1208 const char *customization_name,
1209 int glyphidx,
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)
1220 return urepdetails;
1221 urepdetails = urepdetails->next;
1224 return (struct customization_detail *) 0;
1226 #endif /* 0 not used yet */
1228 #ifdef TEST_GLYPHNAMES
1230 static struct {
1231 int idx;
1232 const char *nm1;
1233 const char *nm2;
1234 } cmapname[MAXPCHARS] = {
1235 #define PCHAR_TILES
1236 #include "defsym.h"
1237 #undef PCHAR_TILES
1240 void
1241 test_glyphnames(void)
1243 int reslt;
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);
1253 staticfn void
1254 just_find_callback(int glyph UNUSED, struct find_struct *findwhat UNUSED)
1256 return;
1259 staticfn int
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);
1269 staticfn void
1270 to_unicode_callback(int glyph UNUSED, struct find_struct *findwhat)
1272 int uval;
1273 #ifdef NO_PARSING_SYMSET
1274 glyph_map *gm = &glyphmap[glyph];
1275 #endif
1276 uint8 utf8str[6];
1278 if (!findwhat->unicode_val)
1279 return;
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);
1285 #else
1287 #endif
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 */
1310 /* glyphs.c */