OSDN Git Service

update year to 2020
[jnethack/source.git] / src / mapglyph.c
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. */
4
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020            */
8 /* JNetHack may be freely redistributed.  See license for details. */
9
10 #include "hack.h"
11 #if defined(TTY_GRAPHICS)
12 #include "wintty.h" /* for prototype of has_color() only */
13 #endif
14 #include "color.h"
15 #define HI_DOMESTIC CLR_WHITE /* monst.c */
16
17 #if !defined(TTY_GRAPHICS)
18 #define has_color(n) TRUE
19 #endif
20
21 #ifdef TEXTCOLOR
22 static const int explcolors[] = {
23     CLR_BLACK,   /* dark    */
24     CLR_GREEN,   /* noxious */
25     CLR_BROWN,   /* muddy   */
26     CLR_BLUE,    /* wet     */
27     CLR_MAGENTA, /* magical */
28     CLR_ORANGE,  /* fiery   */
29     CLR_WHITE,   /* frosty  */
30 };
31
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
41
42 #else /* no text color */
43
44 #define zap_color(n)
45 #define cmap_color(n)
46 #define obj_color(n)
47 #define mon_color(n)
48 #define invis_color(n)
49 #define pet_color(c)
50 #define warn_color(n)
51 #define explode_color(n)
52 #endif
53
54 #if defined(USE_TILES) && defined(MSDOS)
55 #define HAS_ROGUE_IBM_GRAPHICS \
56     (currentgraphics == ROGUESET && SYMHANDLING(H_IBM) && !iflags.grmode)
57 #else
58 #define HAS_ROGUE_IBM_GRAPHICS \
59     (currentgraphics == ROGUESET && SYMHANDLING(H_IBM))
60 #endif
61
62 #define is_objpile(x,y) (!Hallucination && level.objects[(x)][(y)] \
63                          && level.objects[(x)][(y)]->nexthere)
64
65 /*ARGSUSED*/
66 int
67 mapglyph(glyph, ochar, ocolor, ospecial, x, y, mgflags)
68 int glyph, *ocolor, x, y;
69 int *ochar;
70 unsigned *ospecial;
71 unsigned mgflags;
72 {
73     register int offset, idx;
74     int color = NO_COLOR;
75     nhsym ch;
76     unsigned special = 0;
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);
82
83     /*
84      *  Map the glyph back to a character and color.
85      *
86      *  Warning:  For speed, this makes an assumption on the order of
87      *            offsets.  The order is set in display.h.
88      */
89     if ((offset = (glyph - GLYPH_STATUE_OFF)) >= 0) { /* a statue */
90         idx = mons[offset].mlet + SYM_OFF_M;
91         if (has_rogue_color)
92             color = CLR_RED;
93         else
94             obj_color(STATUE);
95         special |= MG_STATUE;
96         if (is_objpile(x,y))
97             special |= MG_OBJPILE;
98     } else if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* warn flash */
99         idx = offset + SYM_OFF_W;
100         if (has_rogue_color)
101             color = NO_COLOR;
102         else
103             warn_color(offset);
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)
108             color = NO_COLOR;
109         else
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)
115             color = NO_COLOR;
116         else
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)
125                 color = CLR_BROWN;
126             else if (offset >= S_arrow_trap && offset <= S_polymorph_trap)
127                 color = CLR_MAGENTA;
128             else if (offset == S_corr || offset == S_litcorr)
129                 color = CLR_GRAY;
130             else if (offset >= S_room && offset <= S_water
131                      && offset != S_darkroom)
132                 color = CLR_GREEN;
133             else
134                 color = NO_COLOR;
135 #ifdef TEXTCOLOR
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]) {
140             color = CLR_WHITE;
141 #endif
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;
148         } else {
149             cmap_color(offset);
150         }
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) {
157             case COIN_CLASS:
158                 color = CLR_YELLOW;
159                 break;
160             case FOOD_CLASS:
161                 color = CLR_RED;
162                 break;
163             default:
164                 color = CLR_BRIGHT_BLUE;
165                 break;
166             }
167         } else
168             obj_color(offset);
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;
173         if (has_rogue_color)
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 */
178         else
179             mon_color(offset);
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)
184             color = CLR_RED;
185         else
186             mon_color(offset);
187         special |= MG_CORPSE;
188         if (is_objpile(x,y))
189             special |= MG_OBJPILE;
190     } else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* mon detect */
191         idx = mons[offset].mlet + SYM_OFF_M;
192         if (has_rogue_color)
193             color = NO_COLOR; /* no need to check iflags.use_color */
194         else
195             mon_color(offset);
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;
201         if (has_rogue_color)
202             color = NO_COLOR; /* no need to check iflags.use_color */
203         else
204             invis_color(offset);
205         special |= MG_INVIS;
206     } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) { /* a pet */
207         idx = mons[offset].mlet + SYM_OFF_M;
208         if (has_rogue_color)
209             color = NO_COLOR; /* no need to check iflags.use_color */
210         else
211             pet_color(offset);
212         special |= MG_PET;
213     } else { /* a monster */
214         idx = mons[glyph].mlet + SYM_OFF_M;
215         if (has_rogue_color && iflags.use_color) {
216             if (is_you)
217                 /* actually player should be yellow-on-gray if in corridor */
218                 color = CLR_YELLOW;
219             else
220                 color = NO_COLOR;
221         } else {
222             mon_color(glyph);
223 #ifdef TEXTCOLOR
224             /* special case the hero for `showrace' option */
225             if (iflags.use_color && is_you && flags.showrace && !Upolyd)
226                 color = HI_DOMESTIC;
227 #endif
228         }
229     }
230
231     /* These were requested by a blind player to enhance screen reader use */
232     if (sysopt.accessibility == 1 && !(mgflags & MG_FLAG_NOOVERRIDE)) {
233         int ovidx;
234
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])
239                 idx = ovidx;
240         }
241         if (is_you) {
242             ovidx = SYM_HERO_OVERRIDE + SYM_OFF_X;
243             if (Is_rogue_level(&u.uz) ? ov_rogue_syms[ovidx]
244                                       : ov_primary_syms[ovidx])
245                 idx = ovidx;
246         }
247     }
248
249     ch = showsyms[idx];
250 #ifdef TEXTCOLOR
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))
253 #endif
254         color = NO_COLOR;
255     *ochar = (int) ch;
256     *ospecial = special;
257     *ocolor = color;
258     return idx;
259 }
260
261 char *
262 encglyph(glyph)
263 int glyph;
264 {
265     static char encbuf[20]; /* 10+1 would suffice */
266
267     Sprintf(encbuf, "\\G%04X%04X", context.rndencode, glyph);
268     return encbuf;
269 }
270
271 char *
272 decode_mixed(buf, str)
273 char *buf;
274 const char *str;
275 {
276     static const char hex[] = "00112233445566778899aAbBcCdDeEfF";
277     char *put = buf;
278
279     if (!str)
280         return strcpy(buf, "");
281
282     while (*str) {
283         if (*str == '\\') {
284             int rndchk, dcount, so, gv, ch = 0, oc = 0;
285             unsigned os = 0;
286             const char *dp, *save_str;
287
288             save_str = str++;
289             switch (*str) {
290             case 'G': /* glyph value \GXXXXNNNN*/
291                 rndchk = dcount = 0;
292                 for (++str; *str && ++dcount <= 4; ++str)
293                     if ((dp = index(hex, *str)) != 0)
294                         rndchk = (rndchk * 16) + ((int) (dp - hex) / 2);
295                     else
296                         break;
297                 if (rndchk == context.rndencode) {
298                     gv = dcount = 0;
299                     for (; *str && ++dcount <= 4; ++str)
300                         if ((dp = index(hex, *str)) != 0)
301                             gv = (gv * 16) + ((int) (dp - hex) / 2);
302                         else
303                             break;
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 */
308                     continue;
309                 } else {
310                     /* possible forgery - leave it the way it is */
311                     str = save_str;
312                 }
313                 break;
314 #if 0
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);
320                     else
321                         break;
322                 if (rndchk == context.rndencode) {
323                     dcount = 0;
324                     for (; *str && ++dcount <= 2; ++str)
325                         if ((dp = index(hex, *str)) != 0)
326                             so = (so * 16) + ((int) (dp - hex) / 2);
327                         else
328                             break;
329                 }
330                 *put++ = showsyms[so];
331                 break;
332 #endif
333             case '\\':
334                 break;
335             case '\0':
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
339                    nearby objects. */
340                 /* brh - should we perhaps not allow things to have names
341                    that contain '\\' */
342                 str = save_str;
343                 break;
344             }
345         }
346 #if 1 /*JP*/
347         if (is_kanji(*(unsigned char *)str)) {
348             *put++ = *str++;
349         }
350 #endif
351         *put++ = *str++;
352     }
353     *put = '\0';
354     return buf;
355 }
356
357 /*
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().
361  *
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
366  * putstr().
367  */
368
369 void
370 genl_putmixed(window, attr, str)
371 winid window;
372 int attr;
373 const char *str;
374 {
375     char buf[BUFSZ];
376
377     /* now send it to the normal putstr */
378     putstr(window, attr, decode_mixed(buf, str));
379 }
380
381 /*mapglyph.c*/