OSDN Git Service

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