1 /* NetHack 3.7 symbols.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.123 $ */
2 /* Copyright (c) NetHack Development Team 2020. */
3 /* NetHack may be freely redistributed. See license for details. */
8 staticfn
void savedsym_add(const char *, const char *, int);
9 staticfn
struct _savedsym
*savedsym_find(const char *, int);
11 extern const uchar def_r_oc_syms
[MAXOCLASSES
]; /* drawing.c */
13 #if defined(TERMLIB) || defined(CURSES_GRAPHICS)
14 void (*decgraphics_mode_callback
)(void) = 0; /* set in term_start_screen() */
15 #endif /* TERMLIB || CURSES */
18 void (*ibmgraphics_mode_callback
)(void) = 0; /* set in term_start_screen() */
19 void (*ascgraphics_mode_callback
)(void) = 0; /* set in term_start_screen() */
21 #ifdef CURSES_GRAPHICS
22 void (*cursesgraphics_mode_callback
)(void) = 0;
24 #if defined(TTY_GRAPHICS) && defined(WIN32)
25 void (*ibmgraphics_mode_callback
)(void) = 0;
27 #ifdef ENHANCED_SYMBOLS
28 void (*utf8graphics_mode_callback
)(void) = 0; /* set in term_start_screen and
29 * found in unixtty,windtty,&c */
33 * Explanations of the functions found below:
36 * Sets the current display symbols, the
37 * loadable symbols to the default NetHack
38 * symbols, including the rogue_syms rogue level
39 * symbols. This would typically be done
40 * immediately after execution begins. Any
41 * previously loaded external symbol sets are
45 * Called to swap in new current display symbols
46 * (showsyms) from either the default symbols,
47 * or from the loaded symbols.
49 * If (arg == 0) then showsyms are taken from
50 * defsyms, def_oc_syms, and def_monsyms.
52 * If (arg != 0), which is the normal expected
53 * usage, then showsyms are taken from the
54 * adjustable display symbols found in gp.primary_syms.
55 * gp.primary_syms may have been loaded from an external
56 * symbol file by config file options or interactively
57 * in the Options menu.
59 * assign_graphics(arg)
61 * This is used in the game core to toggle in and
62 * out of other {rogue} level display modes.
64 * If arg is ROGUESET, this places the rogue level
65 * symbols from gr.rogue_syms into gs.showsyms.
67 * If arg is PRIMARYSET, this places the symbols
68 * from gp.primary_syms into gs.showsyms.
70 * update_primary_symset()
71 * Update a member of the primary(primary_*) symbol set.
73 * update_rogue_symset()
74 * Update a member of the rogue (rogue_*) symbol set.
76 * update_ov_primary_symset()
77 * Update a member of the overrides for primary symbol set.
79 * update_ov_rogue_symset()
80 * Update a member of the overrides for rogue symbol set.
87 init_ov_primary_symbols();
88 init_ov_rogue_symbols();
89 init_primary_symbols();
99 for (i
= 0; i
< MAXPCHARS
; i
++)
100 gs
.showsyms
[i
+ SYM_OFF_P
] = defsyms
[i
].sym
;
101 for (i
= 0; i
< MAXOCLASSES
; i
++)
102 gs
.showsyms
[i
+ SYM_OFF_O
] = def_oc_syms
[i
].sym
;
103 for (i
= 0; i
< MAXMCLASSES
; i
++)
104 gs
.showsyms
[i
+ SYM_OFF_M
] = def_monsyms
[i
].sym
;
105 for (i
= 0; i
< WARNCOUNT
; i
++)
106 gs
.showsyms
[i
+ SYM_OFF_W
] = def_warnsyms
[i
].sym
;
107 for (i
= 0; i
< MAXOTHER
; i
++)
108 gs
.showsyms
[i
+ SYM_OFF_X
] = get_othersym(i
, PRIMARYSET
);
111 /* initialize defaults for the overrides to the rogue symset */
113 init_ov_rogue_symbols(void)
117 for (i
= 0; i
< SYM_MAX
; i
++)
118 go
.ov_rogue_syms
[i
] = (nhsym
) 0;
120 /* initialize defaults for the overrides to the primary symset */
122 init_ov_primary_symbols(void)
126 for (i
= 0; i
< SYM_MAX
; i
++)
127 go
.ov_primary_syms
[i
] = (nhsym
) 0;
131 get_othersym(int idx
, int which_set
)
133 nhsym sym
= (nhsym
) 0;
134 int oidx
= idx
+ SYM_OFF_X
;
136 if (which_set
== ROGUESET
)
137 sym
= go
.ov_rogue_syms
[oidx
] ? go
.ov_rogue_syms
[oidx
]
138 : gr
.rogue_syms
[oidx
];
140 sym
= go
.ov_primary_syms
[oidx
] ? go
.ov_primary_syms
[oidx
]
141 : gp
.primary_syms
[oidx
];
149 sym
= def_oc_syms
[ROCK_CLASS
].sym
;
155 /* these intentionally have no defaults */
156 case SYM_PET_OVERRIDE
:
157 case SYM_HERO_OVERRIDE
:
165 /* initialize defaults for the primary symset */
167 init_primary_symbols(void)
171 for (i
= 0; i
< MAXPCHARS
; i
++)
172 gp
.primary_syms
[i
+ SYM_OFF_P
] = defsyms
[i
].sym
;
173 for (i
= 0; i
< MAXOCLASSES
; i
++)
174 gp
.primary_syms
[i
+ SYM_OFF_O
] = def_oc_syms
[i
].sym
;
175 for (i
= 0; i
< MAXMCLASSES
; i
++)
176 gp
.primary_syms
[i
+ SYM_OFF_M
] = def_monsyms
[i
].sym
;
177 for (i
= 0; i
< WARNCOUNT
; i
++)
178 gp
.primary_syms
[i
+ SYM_OFF_W
] = def_warnsyms
[i
].sym
;
179 for (i
= 0; i
< MAXOTHER
; i
++)
180 gp
.primary_syms
[i
+ SYM_OFF_X
] = get_othersym(i
, PRIMARYSET
);
182 clear_symsetentry(PRIMARYSET
, FALSE
);
185 /* initialize defaults for the rogue symset */
187 init_rogue_symbols(void)
191 /* These are defaults that can get overwritten
192 later by the roguesymbols option */
194 for (i
= 0; i
< MAXPCHARS
; i
++)
195 gr
.rogue_syms
[i
+ SYM_OFF_P
] = defsyms
[i
].sym
;
196 gr
.rogue_syms
[S_vodoor
] = gr
.rogue_syms
[S_hodoor
]
197 = gr
.rogue_syms
[S_ndoor
] = '+';
198 gr
.rogue_syms
[S_upstair
] = gr
.rogue_syms
[S_dnstair
] = '%';
200 for (i
= 0; i
< MAXOCLASSES
; i
++)
201 gr
.rogue_syms
[i
+ SYM_OFF_O
] = def_r_oc_syms
[i
];
202 for (i
= 0; i
< MAXMCLASSES
; i
++)
203 gr
.rogue_syms
[i
+ SYM_OFF_M
] = def_monsyms
[i
].sym
;
204 for (i
= 0; i
< WARNCOUNT
; i
++)
205 gr
.rogue_syms
[i
+ SYM_OFF_W
] = def_warnsyms
[i
].sym
;
206 for (i
= 0; i
< MAXOTHER
; i
++)
207 gr
.rogue_syms
[i
+ SYM_OFF_X
] = get_othersym(i
, ROGUESET
);
209 clear_symsetentry(ROGUESET
, FALSE
);
210 /* default on Rogue level is no color
211 * but some symbol sets can override that
213 gs
.symset
[ROGUESET
].nocolor
= 1;
217 assign_graphics(int whichset
)
223 /* Adjust graphics display characters on Rogue levels */
225 for (i
= 0; i
< SYM_MAX
; i
++)
226 gs
.showsyms
[i
] = go
.ov_rogue_syms
[i
] ? go
.ov_rogue_syms
[i
]
229 #if defined(MSDOS) && defined(TILES_IN_GLYPHMAP)
233 gc
.currentgraphics
= ROGUESET
;
238 for (i
= 0; i
< SYM_MAX
; i
++)
239 gs
.showsyms
[i
] = go
.ov_primary_syms
[i
] ? go
.ov_primary_syms
[i
]
240 : gp
.primary_syms
[i
];
242 #if defined(MSDOS) && defined(TILES_IN_GLYPHMAP)
246 gc
.currentgraphics
= PRIMARYSET
;
249 reset_glyphmap(gm_symchange
);
253 switch_symbols(int nondefault
)
258 for (i
= 0; i
< SYM_MAX
; i
++)
259 gs
.showsyms
[i
] = go
.ov_primary_syms
[i
] ? go
.ov_primary_syms
[i
]
260 : gp
.primary_syms
[i
];
262 if (SYMHANDLING(H_IBM
) && ibmgraphics_mode_callback
)
263 (*ibmgraphics_mode_callback
)();
264 else if (SYMHANDLING(H_UNK
) && ascgraphics_mode_callback
)
265 (*ascgraphics_mode_callback
)();
267 #if defined(TERMLIB) || defined(CURSES_GRAPHICS)
268 /* curses doesn't assign any routine to dec..._callback but
269 probably does the expected initialization under the hood
270 for terminals capable of rendering DECgraphics */
271 if (SYMHANDLING(H_DEC
) && decgraphics_mode_callback
)
272 (*decgraphics_mode_callback
)();
273 # ifdef CURSES_GRAPHICS
274 /* there aren't any symbol sets with CURS handling, and the
275 curses interface never assigns a routine to curses..._callback */
276 if (SYMHANDLING(H_CURS
) && cursesgraphics_mode_callback
)
277 (*cursesgraphics_mode_callback
)();
280 #if defined(TTY_GRAPHICS) && defined(WIN32)
281 if (SYMHANDLING(H_IBM
) && ibmgraphics_mode_callback
)
282 (*ibmgraphics_mode_callback
)();
284 #ifdef ENHANCED_SYMBOLS
285 if (SYMHANDLING(H_UTF8
) && utf8graphics_mode_callback
)
286 (*utf8graphics_mode_callback
)();
289 init_primary_symbols();
295 update_ov_primary_symset(const struct symparse
*symp
, int val
)
297 go
.ov_primary_syms
[symp
->idx
] = val
;
301 update_ov_rogue_symset(const struct symparse
*symp
, int val
)
303 go
.ov_rogue_syms
[symp
->idx
] = val
;
307 update_primary_symset(const struct symparse
*symp
, int val
)
309 gp
.primary_syms
[symp
->idx
] = val
;
313 update_rogue_symset(const struct symparse
*symp
, int val
)
315 gr
.rogue_syms
[symp
->idx
] = val
;
319 clear_symsetentry(int which_set
, boolean name_too
)
321 #ifdef ENHANCED_SYMBOLS
322 int other_set
= (which_set
== PRIMARYSET
) ? ROGUESET
: PRIMARYSET
;
323 enum symset_handling_types old_handling
= gs
.symset
[which_set
].handling
;
326 if (gs
.symset
[which_set
].desc
)
327 free((genericptr_t
) gs
.symset
[which_set
].desc
);
328 gs
.symset
[which_set
].desc
= (char *) 0;
330 gs
.symset
[which_set
].handling
= H_UNK
;
331 gs
.symset
[which_set
].nocolor
= 0;
332 /* initialize restriction bits */
333 gs
.symset
[which_set
].primary
= 0;
334 gs
.symset
[which_set
].rogue
= 0;
337 if (gs
.symset
[which_set
].name
)
338 free((genericptr_t
) gs
.symset
[which_set
].name
);
339 gs
.symset
[which_set
].name
= (char *) 0;
341 #ifdef ENHANCED_SYMBOLS
342 /* if 'which_set' was using UTF8, it isn't anymore; if the other set
343 isn't using UTF8, discard the data for that */
344 if (old_handling
== H_UTF8
&& gs
.symset
[other_set
].handling
!= H_UTF8
)
345 free_all_glyphmap_u();
347 purge_custom_entries(which_set
);
348 clear_all_glyphmap_colors();
351 /* called from windmain.c */
353 symset_is_compatible(
354 enum symset_handling_types handling
,
355 unsigned long wincap2
)
357 #ifdef ENHANCED_SYMBOLS
358 #define WC2_utf8_bits (WC2_U_UTF8STR)
359 if (handling
== H_UTF8
&& ((wincap2
& WC2_utf8_bits
) != WC2_utf8_bits
))
370 * If you are adding code somewhere to be able to recognize
371 * particular types of symset "handling", define a
372 * H_XXX macro in include/sym.h and add the name
373 * to this array at the matching offset.
374 * Externally referenced from files.c, options.c, utf8map.c.
376 const char *const known_handling
[] = {
377 "UNKNOWN", /* H_UNK */
381 "MAC", /* H_MAC -- pre-OSX MACgraphics */
387 * Accepted keywords for symset restrictions.
388 * These can be virtually anything that you want to
389 * be able to test in the code someplace.
391 * - add a corresponding Bitfield to the symsetentry struct in sym.h
392 * - initialize the field to zero in parse_sym_line in the SYM_CONTROL
393 * case 0 section of the idx switch. The location is prefaced with
394 * with a comment stating "initialize restriction bits".
395 * - set the value appropriately based on the index of your keyword
396 * under the case 5 sections of the same SYM_CONTROL idx switches.
397 * - add the field to clear_symsetentry()
399 const char *const known_restrictions
[] = {
400 "primary", "rogue", (const char *) 0,
403 const struct symparse loadsyms
[] = {
404 { SYM_CONTROL
, 0, "start" },
405 { SYM_CONTROL
, 0, "begin" },
406 { SYM_CONTROL
, 1, "finish" },
407 { SYM_CONTROL
, 2, "handling" },
408 { SYM_CONTROL
, 3, "description" },
409 { SYM_CONTROL
, 4, "color" },
410 { SYM_CONTROL
, 4, "colour" },
411 { SYM_CONTROL
, 5, "restrictions" },
415 #define OBJCLASS_PARSE
417 #undef OBJCLASS_PARSE
418 #define MONSYMS_PARSE
421 { SYM_OTH
, SYM_NOTHING
+ SYM_OFF_X
, "S_nothing" },
422 { SYM_OTH
, SYM_UNEXPLORED
+ SYM_OFF_X
, "S_unexplored" },
423 { SYM_OTH
, SYM_BOULDER
+ SYM_OFF_X
, "S_boulder" },
424 { SYM_OTH
, SYM_INVISIBLE
+ SYM_OFF_X
, "S_invisible" },
425 { SYM_OTH
, SYM_PET_OVERRIDE
+ SYM_OFF_X
, "S_pet_override" },
426 { SYM_OTH
, SYM_HERO_OVERRIDE
+ SYM_OFF_X
, "S_hero_override" },
427 { SYM_INVALID
, 0, (const char *) 0 } /* fence post */
431 proc_symset_line(char *buf
)
433 return !((boolean
) parse_sym_line(buf
, gs
.symset_which_set
));
436 /* returns 0 on error */
438 parse_sym_line(char *buf
, int which_set
)
441 const struct symparse
*symp
= (struct symparse
*) 0;
442 char *bufp
, *commentp
, *altp
;
443 int glyph
= NO_GLYPH
;
444 boolean enhanced_unavailable
= FALSE
, is_glyph
= FALSE
;
446 if (strlen(buf
) >= BUFSZ
)
447 buf
[BUFSZ
- 1] = '\0';
448 /* convert each instance of whitespace (tabs, consecutive spaces)
449 into a single space; leading and trailing spaces are stripped */
452 /* remove trailing comment, if any (this isn't strictly needed for
453 individual symbols, and it won't matter if "X#comment" without
454 separating space slips through; for handling or set description,
455 symbol set creator is responsible for preceding '#' with a space
456 and that comment itself doesn't contain " #") */
457 if ((commentp
= strrchr(buf
, '#')) != 0 && commentp
[-1] == ' ')
460 /* find the '=' or ':' */
461 bufp
= strchr(buf
, '=');
462 altp
= strchr(buf
, ':');
464 if (!bufp
|| (altp
&& altp
< bufp
))
468 if (strncmpi(buf
, "finish", 6) == 0) {
469 /* end current graphics set */
470 if (gc
.chosen_symset_start
)
471 gc
.chosen_symset_end
= TRUE
;
472 gc
.chosen_symset_start
= FALSE
;
475 config_error_add("No \"finish\"");
478 /* skip '=' and space which follows, if any */
483 symp
= match_sym(buf
);
484 if (!symp
&& buf
[0] == 'G' && buf
[1] == '_') {
485 if (gc
.chosen_symset_start
) {
486 is_glyph
= match_glyph(buf
);
488 is_glyph
= TRUE
; /* report error only once */
490 #ifdef ENHANCED_SYMBOLS
491 enhanced_unavailable
= FALSE
;
493 enhanced_unavailable
= TRUE
;
496 if (!symp
&& !is_glyph
&& !enhanced_unavailable
) {
497 config_error_add("Unknown sym keyword");
501 if (!gs
.symset
[which_set
].name
) {
502 /* A null symset name indicates that we're just
503 building a pick-list of possible symset
504 values from the file, so only do that */
505 if (symp
->range
== SYM_CONTROL
) {
506 struct symsetentry
*tmpsp
, *lastsp
;
508 for (lastsp
= gs
.symset_list
; lastsp
; lastsp
= lastsp
->next
)
513 tmpsp
= (struct symsetentry
*) alloc(sizeof *tmpsp
);
514 tmpsp
->next
= (struct symsetentry
*) 0;
516 gs
.symset_list
= tmpsp
;
518 lastsp
->next
= tmpsp
;
519 tmpsp
->idx
= gs
.symset_count
++;
520 tmpsp
->name
= dupstr(bufp
);
521 tmpsp
->desc
= (char *) 0;
522 tmpsp
->handling
= H_UNK
;
523 /* initialize restriction bits */
529 /* handler type identified */
530 tmpsp
= lastsp
; /* most recent symset */
531 for (i
= 0; known_handling
[i
]; ++i
)
532 if (!strcmpi(known_handling
[i
], bufp
)) {
535 break; /* for loop */
539 /* description:something */
540 tmpsp
= lastsp
; /* most recent symset */
541 if (tmpsp
&& !tmpsp
->desc
)
542 tmpsp
->desc
= dupstr(bufp
);
545 /* restrictions: xxxx*/
546 tmpsp
= lastsp
; /* most recent symset */
547 for (i
= 0; known_restrictions
[i
]; ++i
) {
548 if (!strcmpi(known_restrictions
[i
], bufp
)) {
559 break; /* while loop */
567 if (symp
->range
&& symp
->range
== SYM_CONTROL
) {
570 /* start of symset */
571 if (!strcmpi(bufp
, gs
.symset
[which_set
].name
)) {
572 /* matches desired one */
573 gc
.chosen_symset_start
= TRUE
;
574 /* these init_*() functions clear symset fields too */
575 if (which_set
== ROGUESET
)
576 init_rogue_symbols();
577 else if (which_set
== PRIMARYSET
)
578 init_primary_symbols();
583 if (gc
.chosen_symset_start
)
584 gc
.chosen_symset_end
= TRUE
;
585 gc
.chosen_symset_start
= FALSE
;
588 /* handler type identified */
589 if (gc
.chosen_symset_start
)
590 set_symhandling(bufp
, which_set
);
592 /* case 3: (description) is ignored here */
593 case 4: /* color:off */
594 if (gc
.chosen_symset_start
) {
596 if (!strcmpi(bufp
, "true") || !strcmpi(bufp
, "yes")
597 || !strcmpi(bufp
, "on"))
598 gs
.symset
[which_set
].nocolor
= 0;
599 else if (!strcmpi(bufp
, "false")
600 || !strcmpi(bufp
, "no")
601 || !strcmpi(bufp
, "off"))
602 gs
.symset
[which_set
].nocolor
= 1;
606 case 5: /* restrictions: xxxx*/
607 if (gc
.chosen_symset_start
) {
610 while (known_restrictions
[n
]) {
611 if (!strcmpi(known_restrictions
[n
], bufp
)) {
614 gs
.symset
[which_set
].primary
= 1;
617 gs
.symset
[which_set
].rogue
= 1;
620 break; /* while loop */
628 /* Not SYM_CONTROL */
629 if (gs
.symset
[which_set
].handling
!= H_UTF8
) {
630 if (gc
.chosen_symset_start
) {
632 if (which_set
== PRIMARYSET
) {
633 update_primary_symset(symp
, val
);
634 } else if (which_set
== ROGUESET
) {
635 update_rogue_symset(symp
, val
);
638 #ifdef ENHANCED_SYMBOLS
640 if (gc
.chosen_symset_start
) {
641 glyphrep_to_custom_map_entries(buf
, &glyph
);
646 } else if (gc
.chosen_symset_start
) {
647 /* glyph, not symbol */
648 glyphrep_to_custom_map_entries(buf
, &glyph
);
650 #ifndef ENHANCED_SYMBOLS
657 set_symhandling(char *handling
, int which_set
)
661 gs
.symset
[which_set
].handling
= H_UNK
;
662 while (known_handling
[i
]) {
663 if (!strcmpi(known_handling
[i
], handling
)) {
664 gs
.symset
[which_set
].handling
= i
;
671 /* bundle some common usage into one easy-to-use routine */
673 load_symset(const char *s
, int which_set
)
675 clear_symsetentry(which_set
, TRUE
);
677 if (gs
.symset
[which_set
].name
)
678 free((genericptr_t
) gs
.symset
[which_set
].name
);
679 gs
.symset
[which_set
].name
= dupstr(s
);
681 if (read_sym_file(which_set
)) {
682 switch_symbols(TRUE
);
683 apply_customizations(gc
.currentgraphics
,
684 do_custom_symbols
| do_custom_colors
);
686 clear_symsetentry(which_set
, TRUE
);
695 clear_symsetentry(PRIMARYSET
, TRUE
);
696 clear_symsetentry(ROGUESET
, TRUE
);
698 /* symset_list is cleaned up as soon as it's used, so we shouldn't
699 have to anything about it here */
700 /* assert( symset_list == NULL ); */
707 struct _savedsym
*next
;
709 struct _savedsym
*saved_symbols
= NULL
;
714 struct _savedsym
*tmp
= saved_symbols
, *tmp2
;
725 staticfn
struct _savedsym
*
726 savedsym_find(const char *name
, int which_set
)
728 struct _savedsym
*tmp
= saved_symbols
;
731 if (which_set
== tmp
->which_set
&& !strcmp(name
, tmp
->name
))
739 savedsym_add(const char *name
, const char *val
, int which_set
)
741 struct _savedsym
*tmp
= NULL
;
743 if ((tmp
= savedsym_find(name
, which_set
)) != 0) {
745 tmp
->val
= dupstr(val
);
747 tmp
= (struct _savedsym
*) alloc(sizeof *tmp
);
748 tmp
->name
= dupstr(name
);
749 tmp
->val
= dupstr(val
);
750 tmp
->which_set
= which_set
;
751 tmp
->next
= saved_symbols
;
757 savedsym_strbuf(strbuf_t
*sbuf
)
759 struct _savedsym
*tmp
= saved_symbols
;
763 Sprintf(buf
, "%sSYMBOLS=%s:%s\n",
764 (tmp
->which_set
== ROGUESET
) ? "ROGUE" : "",
765 tmp
->name
, tmp
->val
);
766 strbuf_append(sbuf
, buf
);
771 /* Parse the value of a SYMBOLS line from a config file */
773 parsesymbols(char *opts
, int which_set
)
776 char *symname
, *strval
, *ch
,
777 *first_unquoted_comma
= 0, *first_unquoted_colon
= 0;
778 const struct symparse
*symp
;
779 boolean is_glyph
= FALSE
;
781 /* are there any commas or colons that aren't quoted? */
782 for (ch
= opts
+ 1; *ch
; ++ch
) {
783 char *prech
, *postch
;
790 if (*prech
== '\'' && *postch
== '\'')
796 if (*prech
== '\'' && *postch
== '\'')
799 if (*ch
== ',' && !first_unquoted_comma
)
800 first_unquoted_comma
= ch
;
801 if (*ch
== ':' && !first_unquoted_colon
)
802 first_unquoted_colon
= ch
;
804 if (first_unquoted_comma
!= 0) {
805 *first_unquoted_comma
++ = '\0';
806 if (!parsesymbols(first_unquoted_comma
, which_set
))
810 /* S_sample:string */
812 strval
= first_unquoted_colon
;
814 strval
= strchr(opts
, '=');
819 /* strip leading and trailing white space from symname and strval */
823 symp
= match_sym(symname
);
824 if (!symp
&& symname
[0] == 'G' && symname
[1] == '_') {
825 is_glyph
= match_glyph(symname
);
827 if (!symp
&& !is_glyph
)
830 if (symp
->range
&& symp
->range
!= SYM_CONTROL
) {
831 if (gs
.symset
[which_set
].handling
== H_UTF8
832 || (lowc(strval
[0]) == 'u' && strval
[1] == '+')) {
836 Snprintf(buf
, sizeof buf
, "%s:%s", opts
, strval
);
837 glyphrep_to_custom_map_entries(buf
, &glyph
);
839 val
= sym_val(strval
);
840 if (which_set
== ROGUESET
)
841 update_ov_rogue_symset(symp
, val
);
843 update_ov_primary_symset(symp
, val
);
847 savedsym_add(opts
, strval
, which_set
);
851 const struct symparse
*
854 static struct alternate_parse
{
858 { "S_armour", "S_armor" },
859 /* alt explosion names are numbered in phone key/button layout */
860 { "S_explode1", "S_expl_tl" },
861 { "S_explode2", "S_expl_tc" }, { "S_explode3", "S_expl_tr" },
862 { "S_explode4", "S_expl_ml" }, { "S_explode5", "S_expl_mc" },
863 { "S_explode6", "S_expl_mr" }, { "S_explode7", "S_expl_bl" },
864 { "S_explode8", "S_expl_bc" }, { "S_explode9", "S_expl_br" },
867 size_t len
= strlen(buf
);
868 const char *p
= strchr(buf
, ':'), *q
= strchr(buf
, '=');
869 const struct symparse
*sp
= loadsyms
;
871 /* G_ lines will never match here */
872 if ((buf
[0] == 'G' || buf
[0] == 'g') && buf
[1] == '_')
873 return (struct symparse
*) 0;
875 if (!p
|| (q
&& q
< p
))
878 /* note: there will be at most one space before the '='
879 because caller has condensed buf[] with mungspaces() */
880 if (p
> buf
&& p
[-1] == ' ')
882 len
= (int) (p
- buf
);
885 if ((len
>= strlen(sp
->name
)) && !strncmpi(buf
, sp
->name
, len
))
889 for (i
= 0; i
< SIZE(alternates
); ++i
) {
890 if ((len
>= strlen(alternates
[i
].altnm
))
891 && !strncmpi(buf
, alternates
[i
].altnm
, len
)) {
894 if (!strcmp(alternates
[i
].nm
, sp
->name
))
900 return (struct symparse
*) 0;
903 DISABLE_WARNING_FORMAT_NONLITERAL
906 * this is called from options.c to do the symset work.
909 do_symset(boolean rogueflag
)
915 menu_item
*symset_pick
= (menu_item
*) 0;
916 boolean ready_to_switch
= FALSE
,
917 nothing_to_do
= FALSE
;
918 char *symset_name
, fmtstr
[20];
919 struct symsetentry
*sl
;
920 int res
, which_set
, setcount
= 0, chosen
= -2, defindx
= 0;
923 which_set
= rogueflag
? ROGUESET
: PRIMARYSET
;
924 gs
.symset_list
= (struct symsetentry
*) 0;
925 /* clear symset[].name as a flag to read_sym_file() to build list */
926 symset_name
= gs
.symset
[which_set
].name
;
927 gs
.symset
[which_set
].name
= (char *) 0;
929 res
= read_sym_file(which_set
);
930 /* put symset name back */
931 gs
.symset
[which_set
].name
= symset_name
;
933 if (res
&& gs
.symset_list
) {
935 biggest
= (int) (sizeof "Default Symbols" - sizeof ""),
938 for (sl
= gs
.symset_list
; sl
; sl
= sl
->next
) {
939 /* check restrictions */
940 if (rogueflag
? sl
->primary
: sl
->rogue
)
942 #ifndef MAC_GRAPHICS_ENV
943 if (sl
->handling
== H_MAC
)
946 #ifndef ENHANCED_SYMBOLS
947 if (sl
->handling
== H_UTF8
)
951 /* find biggest name */
952 thissize
= sl
->name
? (int) strlen(sl
->name
) : 0;
953 if (thissize
> biggest
)
955 thissize
= sl
->desc
? (int) strlen(sl
->desc
) : 0;
956 if (thissize
> big_desc
)
960 There("are no appropriate %s symbol sets available.",
961 rogueflag
? "rogue level" : "primary");
965 Sprintf(fmtstr
, "%%-%ds %%s", biggest
+ 2);
966 tmpwin
= create_nhwindow(NHW_MENU
);
967 start_menu(tmpwin
, MENU_BEHAVE_STANDARD
);
969 any
.a_int
= 1; /* -1 + 2 [see 'if (sl->name) {' below]*/
972 add_menu(tmpwin
, &nul_glyphinfo
, &any
, 0, 0, ATR_NONE
,
973 clr
, "Default Symbols",
974 (any
.a_int
== defindx
) ? MENU_ITEMFLAGS_SELECTED
975 : MENU_ITEMFLAGS_NONE
);
977 for (sl
= gs
.symset_list
; sl
; sl
= sl
->next
) {
978 /* check restrictions */
979 if (rogueflag
? sl
->primary
: sl
->rogue
)
981 #ifndef MAC_GRAPHICS_ENV
982 if (sl
->handling
== H_MAC
)
985 #ifndef ENHANCED_SYMBOLS
986 if (sl
->handling
== H_UTF8
)
990 /* +2: sl->idx runs from 0 to N-1 for N symsets;
991 +1 because Defaults are implicitly in slot [0];
992 +1 again so that valid data is never 0 */
993 any
.a_int
= sl
->idx
+ 2;
994 if (symset_name
&& !strcmpi(sl
->name
, symset_name
))
996 Sprintf(buf
, fmtstr
, sl
->name
, sl
->desc
? sl
->desc
: "");
997 add_menu(tmpwin
, &nul_glyphinfo
, &any
, 0, 0,
999 (any
.a_int
== defindx
) ? MENU_ITEMFLAGS_SELECTED
1000 : MENU_ITEMFLAGS_NONE
);
1003 Sprintf(buf
, "Select %ssymbol set:",
1004 rogueflag
? "rogue level " : "");
1005 end_menu(tmpwin
, buf
);
1006 n
= select_menu(tmpwin
, PICK_ONE
, &symset_pick
);
1008 chosen
= symset_pick
[0].item
.a_int
;
1009 /* if picking non-preselected entry yields 2, make sure
1010 that we're going with the non-preselected one */
1011 if (n
== 2 && chosen
== defindx
)
1012 chosen
= symset_pick
[1].item
.a_int
;
1013 chosen
-= 2; /* convert menu index to symset index;
1014 * "Default symbols" have index -1 */
1015 free((genericptr_t
) symset_pick
);
1016 } else if (n
== 0 && defindx
> 0) {
1017 chosen
= defindx
- 2;
1019 destroy_nhwindow(tmpwin
);
1022 /* chose an actual symset name from file */
1023 for (sl
= gs
.symset_list
; sl
; sl
= sl
->next
)
1024 if (sl
->idx
== chosen
)
1027 /* free the now stale attributes */
1028 clear_symsetentry(which_set
, TRUE
);
1030 /* transfer only the name of the symbol set */
1031 gs
.symset
[which_set
].name
= dupstr(sl
->name
);
1032 ready_to_switch
= TRUE
;
1034 } else if (chosen
== -1) {
1035 /* explicit selection of defaults */
1036 /* free the now stale symset attributes */
1037 clear_symsetentry(which_set
, TRUE
);
1039 nothing_to_do
= TRUE
;
1041 /* The symbols file could not be accessed */
1042 pline("Unable to access \"%s\" file.", SYMBOLS
);
1044 } else if (!gs
.symset_list
) {
1045 /* The symbols file was empty */
1046 There("were no symbol sets found in \"%s\".", SYMBOLS
);
1051 while ((sl
= gs
.symset_list
) != 0) {
1052 gs
.symset_list
= sl
->next
;
1054 free((genericptr_t
) sl
->name
), sl
->name
= (char *) 0;
1056 free((genericptr_t
) sl
->desc
), sl
->desc
= (char *) 0;
1057 free((genericptr_t
) sl
);
1063 /* Set default symbols and clear the handling value */
1065 init_rogue_symbols();
1067 init_primary_symbols();
1069 if (gs
.symset
[which_set
].name
) {
1070 /* non-default symbols */
1072 if (!glyphid_cache_status()) {
1073 fill_glyphid_cache();
1075 ok
= read_sym_file(which_set
);
1076 if (glyphid_cache_status()) {
1077 free_glyphid_cache();
1080 ready_to_switch
= TRUE
;
1082 clear_symsetentry(which_set
, TRUE
);
1087 if (ready_to_switch
)
1088 switch_symbols(TRUE
);
1090 if (Is_rogue_level(&u
.uz
)) {
1092 assign_graphics(ROGUESET
);
1093 } else if (!rogueflag
)
1094 assign_graphics(PRIMARYSET
);
1095 apply_customizations(rogueflag
? ROGUESET
: PRIMARYSET
,
1096 (do_custom_symbols
| do_custom_colors
));
1097 preference_update("symset");
1101 RESTORE_WARNING_FORMAT_NONLITERAL