OSDN Git Service

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