1 /* NetHack 3.6 mapglyph.c $NHDT-Date: 1573943501 2019/11/16 22:31:41 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.51 $ */
2 /* Copyright (c) David Cohrs, 1991 */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
8 /* JNetHack may be freely redistributed. See license for details. */
11 #if defined(TTY_GRAPHICS)
12 #include "wintty.h" /* for prototype of has_color() only */
15 #define HI_DOMESTIC CLR_WHITE /* monst.c */
17 #if !defined(TTY_GRAPHICS)
18 #define has_color(n) TRUE
22 static const int explcolors[] = {
24 CLR_GREEN, /* noxious */
25 CLR_BROWN, /* muddy */
27 CLR_MAGENTA, /* magical */
28 CLR_ORANGE, /* fiery */
29 CLR_WHITE, /* frosty */
32 #define zap_color(n) color = iflags.use_color ? zapcolors[n] : NO_COLOR
33 #define cmap_color(n) color = iflags.use_color ? defsyms[n].color : NO_COLOR
34 #define obj_color(n) color = iflags.use_color ? objects[n].oc_color : NO_COLOR
35 #define mon_color(n) color = iflags.use_color ? mons[n].mcolor : NO_COLOR
36 #define invis_color(n) color = NO_COLOR
37 #define pet_color(n) color = iflags.use_color ? mons[n].mcolor : NO_COLOR
38 #define warn_color(n) \
39 color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
40 #define explode_color(n) color = iflags.use_color ? explcolors[n] : NO_COLOR
42 #else /* no text color */
48 #define invis_color(n)
51 #define explode_color(n)
54 #if defined(USE_TILES) && defined(MSDOS)
55 #define HAS_ROGUE_IBM_GRAPHICS \
56 (currentgraphics == ROGUESET && SYMHANDLING(H_IBM) && !iflags.grmode)
58 #define HAS_ROGUE_IBM_GRAPHICS \
59 (currentgraphics == ROGUESET && SYMHANDLING(H_IBM))
62 #define is_objpile(x,y) (!Hallucination && level.objects[(x)][(y)] \
63 && level.objects[(x)][(y)]->nexthere)
67 mapglyph(glyph, ochar, ocolor, ospecial, x, y, mgflags)
68 int glyph, *ocolor, x, y;
73 register int offset, idx;
77 /* condense multiple tests in macro version down to single */
78 boolean has_rogue_ibm_graphics = HAS_ROGUE_IBM_GRAPHICS,
79 is_you = (x == u.ux && y == u.uy),
80 has_rogue_color = (has_rogue_ibm_graphics
81 && symset[currentgraphics].nocolor == 0);
84 * Map the glyph back to a character and color.
86 * Warning: For speed, this makes an assumption on the order of
87 * offsets. The order is set in display.h.
89 if ((offset = (glyph - GLYPH_STATUE_OFF)) >= 0) { /* a statue */
90 idx = mons[offset].mlet + SYM_OFF_M;
97 special |= MG_OBJPILE;
98 } else if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* warn flash */
99 idx = offset + SYM_OFF_W;
104 } else if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */
105 /* see swallow_to_glyph() in display.c */
106 idx = (S_sw_tl + (offset & 0x7)) + SYM_OFF_P;
107 if (has_rogue_color && iflags.use_color)
110 mon_color(offset >> 3);
111 } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */
112 /* see zapdir_to_glyph() in display.c */
113 idx = (S_vbeam + (offset & 0x3)) + SYM_OFF_P;
114 if (has_rogue_color && iflags.use_color)
117 zap_color((offset >> 2));
118 } else if ((offset = (glyph - GLYPH_EXPLODE_OFF)) >= 0) { /* explosion */
119 idx = ((offset % MAXEXPCHARS) + S_explode1) + SYM_OFF_P;
120 explode_color(offset / MAXEXPCHARS);
121 } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) { /* cmap */
122 idx = offset + SYM_OFF_P;
123 if (has_rogue_color && iflags.use_color) {
124 if (offset >= S_vwall && offset <= S_hcdoor)
126 else if (offset >= S_arrow_trap && offset <= S_polymorph_trap)
128 else if (offset == S_corr || offset == S_litcorr)
130 else if (offset >= S_room && offset <= S_water
131 && offset != S_darkroom)
136 /* provide a visible difference if normal and lit corridor
137 use the same symbol */
138 } else if (iflags.use_color && offset == S_litcorr
139 && showsyms[idx] == showsyms[S_corr + SYM_OFF_P]) {
142 /* try to provide a visible difference between water and lava
143 if they use the same symbol and color is disabled */
144 } else if (!iflags.use_color && offset == S_lava
145 && (showsyms[idx] == showsyms[S_pool + SYM_OFF_P]
146 || showsyms[idx] == showsyms[S_water + SYM_OFF_P])) {
147 special |= MG_BW_LAVA;
151 } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) { /* object */
152 idx = objects[offset].oc_class + SYM_OFF_O;
153 if (offset == BOULDER)
154 idx = SYM_BOULDER + SYM_OFF_X;
155 if (has_rogue_color && iflags.use_color) {
156 switch (objects[offset].oc_class) {
164 color = CLR_BRIGHT_BLUE;
169 if (offset != BOULDER && is_objpile(x,y))
170 special |= MG_OBJPILE;
171 } else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) { /* mon ridden */
172 idx = mons[offset].mlet + SYM_OFF_M;
174 /* This currently implies that the hero is here -- monsters */
175 /* don't ride (yet...). Should we set it to yellow like in */
176 /* the monster case below? There is no equivalent in rogue. */
177 color = NO_COLOR; /* no need to check iflags.use_color */
180 special |= MG_RIDDEN;
181 } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) { /* a corpse */
182 idx = objects[CORPSE].oc_class + SYM_OFF_O;
183 if (has_rogue_color && iflags.use_color)
187 special |= MG_CORPSE;
189 special |= MG_OBJPILE;
190 } else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* mon detect */
191 idx = mons[offset].mlet + SYM_OFF_M;
193 color = NO_COLOR; /* no need to check iflags.use_color */
196 /* Disabled for now; anyone want to get reverse video to work? */
197 /* is_reverse = TRUE; */
198 special |= MG_DETECT;
199 } else if ((offset = (glyph - GLYPH_INVIS_OFF)) >= 0) { /* invisible */
200 idx = SYM_INVISIBLE + SYM_OFF_X;
202 color = NO_COLOR; /* no need to check iflags.use_color */
206 } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) { /* a pet */
207 idx = mons[offset].mlet + SYM_OFF_M;
209 color = NO_COLOR; /* no need to check iflags.use_color */
213 } else { /* a monster */
214 idx = mons[glyph].mlet + SYM_OFF_M;
215 if (has_rogue_color && iflags.use_color) {
217 /* actually player should be yellow-on-gray if in corridor */
224 /* special case the hero for `showrace' option */
225 if (iflags.use_color && is_you && flags.showrace && !Upolyd)
231 /* These were requested by a blind player to enhance screen reader use */
232 if (sysopt.accessibility == 1 && !(mgflags & MG_FLAG_NOOVERRIDE)) {
235 if ((special & MG_PET) != 0) {
236 ovidx = SYM_PET_OVERRIDE + SYM_OFF_X;
237 if (Is_rogue_level(&u.uz) ? ov_rogue_syms[ovidx]
238 : ov_primary_syms[ovidx])
242 ovidx = SYM_HERO_OVERRIDE + SYM_OFF_X;
243 if (Is_rogue_level(&u.uz) ? ov_rogue_syms[ovidx]
244 : ov_primary_syms[ovidx])
251 /* Turn off color if no color defined, or rogue level w/o PC graphics. */
252 if (!has_color(color) || (Is_rogue_level(&u.uz) && !has_rogue_color))
265 static char encbuf[20]; /* 10+1 would suffice */
267 Sprintf(encbuf, "\\G%04X%04X", context.rndencode, glyph);
272 decode_mixed(buf, str)
276 static const char hex[] = "00112233445566778899aAbBcCdDeEfF";
280 return strcpy(buf, "");
284 int rndchk, dcount, so, gv, ch = 0, oc = 0;
286 const char *dp, *save_str;
290 case 'G': /* glyph value \GXXXXNNNN*/
292 for (++str; *str && ++dcount <= 4; ++str)
293 if ((dp = index(hex, *str)) != 0)
294 rndchk = (rndchk * 16) + ((int) (dp - hex) / 2);
297 if (rndchk == context.rndencode) {
299 for (; *str && ++dcount <= 4; ++str)
300 if ((dp = index(hex, *str)) != 0)
301 gv = (gv * 16) + ((int) (dp - hex) / 2);
304 so = mapglyph(gv, &ch, &oc, &os, 0, 0, 0);
305 *put++ = showsyms[so];
306 /* 'str' is ready for the next loop iteration and '*str'
307 should not be copied at the end of this iteration */
310 /* possible forgery - leave it the way it is */
315 case 'S': /* symbol offset */
316 so = rndchk = dcount = 0;
317 for (++str; *str && ++dcount <= 4; ++str)
318 if ((dp = index(hex, *str)) != 0)
319 rndchk = (rndchk * 16) + ((int) (dp - hex) / 2);
322 if (rndchk == context.rndencode) {
324 for (; *str && ++dcount <= 2; ++str)
325 if ((dp = index(hex, *str)) != 0)
326 so = (so * 16) + ((int) (dp - hex) / 2);
330 *put++ = showsyms[so];
336 /* String ended with '\\'. This can happen when someone
337 names an object with a name ending with '\\', drops the
338 named object on the floor nearby and does a look at all
340 /* brh - should we perhaps not allow things to have names
347 if (is_kanji(*(unsigned char *)str)) {
358 * This differs from putstr() because the str parameter can
359 * contain a sequence of characters representing:
360 * \GXXXXNNNN a glyph value, encoded by encglyph().
362 * For window ports that haven't yet written their own
363 * XXX_putmixed() routine, this general one can be used.
364 * It replaces the encoded glyph sequence with a single
365 * showsyms[] char, then just passes that string onto
370 genl_putmixed(window, attr, str)
377 /* now send it to the normal putstr */
378 putstr(window, attr, decode_mixed(buf, str));