OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / src / mapglyph.c
1 /* NetHack 3.6  mapglyph.c      $NHDT-Date: 1448175698 2015/11/22 07:01:38 $  $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */
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-2016            */
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 static int explcolors[] = {
18     CLR_BLACK,   /* dark    */
19     CLR_GREEN,   /* noxious */
20     CLR_BROWN,   /* muddy   */
21     CLR_BLUE,    /* wet     */
22     CLR_MAGENTA, /* magical */
23     CLR_ORANGE,  /* fiery   */
24     CLR_WHITE,   /* frosty  */
25 };
26
27 #if !defined(TTY_GRAPHICS)
28 #define has_color(n) TRUE
29 #endif
30
31 #ifdef TEXTCOLOR
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)
68 int glyph, *ocolor, x, y;
69 int *ochar;
70 unsigned *ospecial;
71 {
72     register int offset, idx;
73     int color = NO_COLOR;
74     nhsym ch;
75     unsigned special = 0;
76     /* condense multiple tests in macro version down to single */
77     boolean has_rogue_ibm_graphics = HAS_ROGUE_IBM_GRAPHICS;
78     boolean has_rogue_color = (has_rogue_ibm_graphics
79                                && symset[currentgraphics].nocolor == 0);
80
81     /*
82      *  Map the glyph back to a character and color.
83      *
84      *  Warning:  For speed, this makes an assumption on the order of
85      *            offsets.  The order is set in display.h.
86      */
87     if ((offset = (glyph - GLYPH_STATUE_OFF)) >= 0) { /* a statue */
88         idx = mons[offset].mlet + SYM_OFF_M;
89         if (has_rogue_color)
90             color = CLR_RED;
91         else
92             obj_color(STATUE);
93         special |= MG_STATUE;
94         if (is_objpile(x,y))
95             special |= MG_OBJPILE;
96     } else if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* warn flash */
97         idx = offset + SYM_OFF_W;
98         if (has_rogue_color)
99             color = NO_COLOR;
100         else
101             warn_color(offset);
102     } else if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */
103         /* see swallow_to_glyph() in display.c */
104         idx = (S_sw_tl + (offset & 0x7)) + SYM_OFF_P;
105         if (has_rogue_color && iflags.use_color)
106             color = NO_COLOR;
107         else
108             mon_color(offset >> 3);
109     } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */
110         /* see zapdir_to_glyph() in display.c */
111         idx = (S_vbeam + (offset & 0x3)) + SYM_OFF_P;
112         if (has_rogue_color && iflags.use_color)
113             color = NO_COLOR;
114         else
115             zap_color((offset >> 2));
116     } else if ((offset = (glyph - GLYPH_EXPLODE_OFF)) >= 0) { /* explosion */
117         idx = ((offset % MAXEXPCHARS) + S_explode1) + SYM_OFF_P;
118         explode_color(offset / MAXEXPCHARS);
119     } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) { /* cmap */
120         idx = offset + SYM_OFF_P;
121         if (has_rogue_color && iflags.use_color) {
122             if (offset >= S_vwall && offset <= S_hcdoor)
123                 color = CLR_BROWN;
124             else if (offset >= S_arrow_trap && offset <= S_polymorph_trap)
125                 color = CLR_MAGENTA;
126             else if (offset == S_corr || offset == S_litcorr)
127                 color = CLR_GRAY;
128             else if (offset >= S_room && offset <= S_water
129                      && offset != S_darkroom)
130                 color = CLR_GREEN;
131             else
132                 color = NO_COLOR;
133 #ifdef TEXTCOLOR
134         /* provide a visible difference if normal and lit corridor
135            use the same symbol */
136         } else if (iflags.use_color && offset == S_litcorr
137                    && showsyms[idx] == showsyms[S_corr + SYM_OFF_P]) {
138             color = CLR_WHITE;
139 #endif
140         /* try to provide a visible difference between water and lava
141            if they use the same symbol and color is disabled */
142         } else if (!iflags.use_color && offset == S_lava
143                    && (showsyms[idx] == showsyms[S_pool + SYM_OFF_P]
144                        || showsyms[idx] == showsyms[S_water + SYM_OFF_P])) {
145             special |= MG_BW_LAVA;
146         } else {
147             cmap_color(offset);
148         }
149     } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) { /* object */
150         idx = objects[offset].oc_class + SYM_OFF_O;
151         if (offset == BOULDER)
152             idx = SYM_BOULDER + SYM_OFF_X;
153         if (has_rogue_color && iflags.use_color) {
154             switch (objects[offset].oc_class) {
155             case COIN_CLASS:
156                 color = CLR_YELLOW;
157                 break;
158             case FOOD_CLASS:
159                 color = CLR_RED;
160                 break;
161             default:
162                 color = CLR_BRIGHT_BLUE;
163                 break;
164             }
165         } else
166             obj_color(offset);
167         if (offset != BOULDER && is_objpile(x,y))
168             special |= MG_OBJPILE;
169     } else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) { /* mon ridden */
170         idx = mons[offset].mlet + SYM_OFF_M;
171         if (has_rogue_color)
172             /* This currently implies that the hero is here -- monsters */
173             /* don't ride (yet...).  Should we set it to yellow like in */
174             /* the monster case below?  There is no equivalent in rogue. */
175             color = NO_COLOR; /* no need to check iflags.use_color */
176         else
177             mon_color(offset);
178         special |= MG_RIDDEN;
179     } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) { /* a corpse */
180         idx = objects[CORPSE].oc_class + SYM_OFF_O;
181         if (has_rogue_color && iflags.use_color)
182             color = CLR_RED;
183         else
184             mon_color(offset);
185         special |= MG_CORPSE;
186         if (is_objpile(x,y))
187             special |= MG_OBJPILE;
188     } else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* mon detect */
189         idx = mons[offset].mlet + SYM_OFF_M;
190         if (has_rogue_color)
191             color = NO_COLOR; /* no need to check iflags.use_color */
192         else
193             mon_color(offset);
194         /* Disabled for now; anyone want to get reverse video to work? */
195         /* is_reverse = TRUE; */
196         special |= MG_DETECT;
197     } else if ((offset = (glyph - GLYPH_INVIS_OFF)) >= 0) { /* invisible */
198         idx = SYM_INVISIBLE + SYM_OFF_X;
199         if (has_rogue_color)
200             color = NO_COLOR; /* no need to check iflags.use_color */
201         else
202             invis_color(offset);
203         special |= MG_INVIS;
204     } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) { /* a pet */
205         idx = mons[offset].mlet + SYM_OFF_M;
206         if (has_rogue_color)
207             color = NO_COLOR; /* no need to check iflags.use_color */
208         else
209             pet_color(offset);
210         special |= MG_PET;
211     } else { /* a monster */
212         idx = mons[glyph].mlet + SYM_OFF_M;
213         if (has_rogue_color && iflags.use_color) {
214             if (x == u.ux && y == u.uy)
215                 /* actually player should be yellow-on-gray if in corridor */
216                 color = CLR_YELLOW;
217             else
218                 color = NO_COLOR;
219         } else {
220             mon_color(glyph);
221 #ifdef TEXTCOLOR
222             /* special case the hero for `showrace' option */
223             if (iflags.use_color && x == u.ux && y == u.uy
224                 && flags.showrace && !Upolyd)
225                 color = HI_DOMESTIC;
226 #endif
227         }
228     }
229
230     ch = showsyms[idx];
231 #ifdef TEXTCOLOR
232     /* Turn off color if no color defined, or rogue level w/o PC graphics. */
233     if (!has_color(color) || (Is_rogue_level(&u.uz) && !has_rogue_color))
234         color = NO_COLOR;
235 #endif
236
237     *ochar = (int) ch;
238     *ospecial = special;
239 #ifdef TEXTCOLOR
240     *ocolor = color;
241 #endif
242     return idx;
243 }
244
245 char *
246 encglyph(glyph)
247 int glyph;
248 {
249     static char encbuf[20];
250
251     Sprintf(encbuf, "\\G%04X%04X", context.rndencode, glyph);
252     return encbuf;
253 }
254
255 /*
256  * This differs from putstr() because the str parameter can
257  * contain a sequence of characters representing:
258  *        \GXXXXNNNN    a glyph value, encoded by encglyph().
259  *
260  * For window ports that haven't yet written their own
261  * XXX_putmixed() routine, this general one can be used.
262  * It replaces the encoded glyph sequence with a single
263  * showsyms[] char, then just passes that string onto
264  * putstr().
265  */
266
267 void
268 genl_putmixed(window, attr, str)
269 winid window;
270 int attr;
271 const char *str;
272 {
273     static const char hex[] = "00112233445566778899aAbBcCdDeEfF";
274     char buf[BUFSZ];
275     const char *cp = str;
276     char *put = buf;
277
278     while (*cp) {
279         if (*cp == '\\') {
280             int rndchk, dcount, so, gv, ch = 0, oc = 0;
281             unsigned os = 0;
282             const char *dp, *save_cp;
283
284             save_cp = cp++;
285             switch (*cp) {
286             case 'G': /* glyph value \GXXXXNNNN*/
287                 rndchk = dcount = 0;
288                 for (++cp; *cp && ++dcount <= 4; ++cp)
289                     if ((dp = index(hex, *cp)) != 0)
290                         rndchk = (rndchk * 16) + ((int) (dp - hex) / 2);
291                     else
292                         break;
293                 if (rndchk == context.rndencode) {
294                     gv = dcount = 0;
295                     for (; *cp && ++dcount <= 4; ++cp)
296                         if ((dp = index(hex, *cp)) != 0)
297                             gv = (gv * 16) + ((int) (dp - hex) / 2);
298                         else
299                             break;
300                     so = mapglyph(gv, &ch, &oc, &os, 0, 0);
301                     *put++ = showsyms[so];
302                     /* 'cp' is ready for the next loop iteration and '*cp'
303                        should not be copied at the end of this iteration */
304                     continue;
305                 } else {
306                     /* possible forgery - leave it the way it is */
307                     cp = save_cp;
308                 }
309                 break;
310 #if 0
311             case 'S': /* symbol offset */
312                 so = rndchk = dcount = 0;
313                 for (++cp; *cp && ++dcount <= 4; ++cp)
314                     if ((dp = index(hex, *cp)) != 0)
315                         rndchk = (rndchk * 16) + ((int) (dp - hex) / 2);
316                     else
317                         break;
318                 if (rndchk == context.rndencode) {
319                     dcount = 0;
320                     for (; *cp && ++dcount <= 2; ++cp)
321                         if ((dp = index(hex, *cp)) != 0)
322                             so = (so * 16) + ((int) (dp - hex) / 2);
323                         else
324                             break;
325                 }
326                 *put++ = showsyms[so];
327                 break;
328 #endif
329             case '\\':
330                 break;
331             }
332         }
333 #if 1 /*JP*/
334         if (is_kanji(*(unsigned char *)cp)) {
335             *put++ = *cp++;
336         }
337 #endif
338         *put++ = *cp++;
339     }
340     *put = '\0';
341     /* now send it to the normal putstr */
342     putstr(window, attr, buf);
343 }
344
345 /*mapglyph.c*/