1 | /* SCCS Id: @(#)display.h 3.3 1999/11/30 */
2 | /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
3 | /* and Dave Cohrs, 1990. */
4 | /* NetHack may be freely redistributed. See license for details. */
5 |
6 | #ifndef DISPLAY_H
7 | #define DISPLAY_H
8 |
9 | #ifndef VISION_H
10 | #include "vision.h"
11 | #endif
12 |
13 | #ifndef MONDATA_H
14 | #include "mondata.h" /* for mindless() */
15 | #endif
16 |
17 | #ifndef INVISIBLE_OBJECTS
18 | #define vobj_at(x,y) (level.objects[x][y])
19 | #endif
20 |
21 | /*
22 | * sensemon()
23 | *
24 | * Returns true if the hero can sense the given monster. This includes
25 | * monsters that are hiding or mimicing other monsters.
26 | */
27 | #define tp_sensemon(mon) ( /* The hero can always sense a monster IF: */\
28 | (!mindless(mon->data)) && /* 1. the monster has a brain to sense AND */\
29 | ((Blind && Blind_telepat) || /* 2a. hero is blind and telepathic OR */\
30 | /* 2b. hero is using a telepathy inducing */\
31 | /* object and in range */\
32 | (Unblind_telepat && \
33 | (distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM)))) \
34 | )
35 |
36 | #define sensemon(mon) (tp_sensemon(mon) || Detect_monsters || MATCH_WARN_OF_MON(mon))
37 |
38 | /*
39 | * mon_warning() is used to warn of any dangerous monsters in your
40 | * vicinity, and a glyph representing the warning level is displayed.
41 | */
42 |
43 | #define mon_warning(mon) (Warning && !(mon)->mpeaceful && \
44 | (distu((mon)->mx, (mon)->my) < 100) && \
45 | (((int) ((mon)->m_lev / 4)) >= flags.warnlevel))
46 |
47 | /*
48 | * mon_visible()
49 | *
50 | * Returns true if the hero can see the monster. It is assumed that the
51 | * hero can physically see the location of the monster. The function
52 | * vobj_at() returns a pointer to an object that the hero can see there.
53 | * Infravision is not taken into account.
54 | */
55 | #define mon_visible(mon) ( /* The hero can see the monster */\
56 | /* IF the monster */\
57 | (!mon->minvis || See_invisible) && /* 1. is not invisible AND */\
58 | (!mon->mundetected) && /* 2. not an undetected hider */\
59 | (!(mon->mburied || u.uburied)) /* 3. neither you or it is buried */\
60 | )
61 |
62 | /*
63 | * see_with_infrared()
64 | *
65 | * This function is true if the player can see a monster using infravision.
66 | * The caller must check for invisibility (invisible monsters are also
67 | * invisible to infravision), because this is usually called from within
68 | * canseemon() or canspotmon() which already check that.
69 | */
70 | #define see_with_infrared(mon) (!Blind && Infravision && infravisible(mon->data) && couldsee(mon->mx, mon->my))
71 |
72 |
73 | /*
74 | * canseemon()
75 | *
76 | * This is the globally used canseemon(). It is not called within the display
77 | * routines. Like mon_visible(), but it checks to see if the hero sees the
78 | * location instead of assuming it. (And also considers worms.)
79 | */
80 | #define canseemon(mon) ((mon->wormno ? worm_known(mon) : \
81 | (cansee(mon->mx, mon->my) || see_with_infrared(mon))) \
82 | && mon_visible(mon))
83 |
84 |
85 | /*
86 | * canspotmon(mon)
87 | *
88 | * This function checks whether you can either see a monster or sense it by
89 | * telepathy, and is what you usually call for monsters about which nothing is
90 | * known.
91 | */
92 | #define canspotmon(mon) \
93 | (canseemon(mon) || sensemon(mon))
94 |
95 | /* knowninvisible(mon)
96 | * This one checks to see if you know a monster is both there and invisible.
97 | * 1) If you can see the monster and have see invisible, it is assumed the
98 | * monster is transparent, but visible in some manner. (Earlier versions of
99 | * Nethack were really inconsistent on this.)
100 | * 2) If you can't see the monster, but can see its location and you have
101 | * telepathy that works when you can see, you can tell that there is a
102 | * creature in an apparently empty spot.
103 | * Infravision is not relevant; we assume that invisible monsters are also
104 | * invisible to infravision.
105 | */
106 | #define knowninvisible(mon) \
107 | (mtmp->minvis && \
108 | ((cansee(mon->mx, mon->my) && (See_invisible || Detect_monsters)) || \
109 | (!Blind && (HTelepat & ~INTRINSIC) && \
110 | distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM) \
111 | ) \
112 | ) \
113 | )
114 |
115 | /*
116 | * is_safepet(mon)
117 | *
118 | * A special case check used in attack() and domove(). Placing the
119 | * definition here is convenient.
120 | */
121 | #define is_safepet(mon) \
122 | (mon && mon->mtame && canspotmon(mon) && flags.safe_dog \
123 | && !Confusion && !Hallucination && !Stunned)
124 |
125 |
126 | /*
127 | * canseeself()
128 | *
129 | * This returns true if the hero can see her/himself.
130 | *
131 | * The u.uswallow check assumes that you can see yourself even if you are
132 | * invisible. If not, then we don't need the check.
133 | */
134 | #define canseeself() (Blind || u.uswallow || (!Invisible && !u.uundetected))
135 |
136 |
137 | /*
138 | * random_monster()
139 | * random_object()
140 | * random_trap()
141 | *
142 | * Respectively return a random monster, object, or trap number.
143 | */
144 | #define random_monster() rn2(NUMMONS)
145 | #define random_object() rn1(NUM_OBJECTS-1,1)
146 | #define random_trap() rn1(TRAPNUM-1,1)
147 |
148 | /*
149 | * what_obj()
150 | * what_mon()
151 | * what_trap()
152 | *
153 | * If hallucinating, choose a random object/monster, otherwise, use the one
154 | * given.
155 | */
156 | #define what_obj(obj) (Hallucination ? random_object() : obj)
157 | #define what_mon(mon) (Hallucination ? random_monster() : mon)
158 | #define what_trap(trp) (Hallucination ? random_trap() : trp)
159 |
160 | /*
161 | * covers_objects()
162 | * covers_traps()
163 | *
164 | * These routines are true if what is really at the given location will
165 | * "cover" any objects or traps that might be there.
166 | */
167 | #define covers_objects(xx,yy) \
168 | ((is_pool(xx,yy) && !Underwater) || (levl[xx][yy].typ == LAVAPOOL))
169 |
170 | #define covers_traps(xx,yy) covers_objects(xx,yy)
171 |
172 |
173 | /*
174 | * tmp_at() control calls.
175 | */
176 | #define DISP_BEAM (-1) /* Keep all glyphs showing & clean up at end. */
177 | #define DISP_FLASH (-2) /* Clean up each glyph before displaying new one. */
178 | #define DISP_ALWAYS (-3) /* Like flash, but still displayed if not visible. */
179 | #define DISP_CHANGE (-4) /* Change glyph. */
180 | #define DISP_END (-5) /* Clean up. */
181 | #define DISP_FREEMEM (-6) /* Free all memory during exit only. */
182 |
183 |
184 | /* Total number of cmap indices in the sheild_static[] array. */
185 | #define SHIELD_COUNT 21
186 |
187 |
188 | /*
189 | * display_self()
190 | *
191 | * Display the hero. It is assumed that all checks necessary to determine
192 | * _if_ the hero can be seen have already been done.
193 | */
194 | #ifdef STEED
195 | #define display_self() \
196 | show_glyph(u.ux, u.uy, \
197 | (u.usteed && mon_visible(u.usteed)) ? \
198 | ridden_mon_to_glyph(u.usteed) : \
199 | youmonst.m_ap_type == M_AP_NOTHING ? \
200 | hero_glyph : \
201 | youmonst.m_ap_type == M_AP_FURNITURE ? \
202 | cmap_to_glyph(youmonst.mappearance) : \
203 | youmonst.m_ap_type == M_AP_OBJECT ? \
204 | objnum_to_glyph(youmonst.mappearance) : \
205 | /* else M_AP_MONSTER */ monnum_to_glyph(youmonst.mappearance))
206 | #else
207 | #define display_self() \
208 | show_glyph(u.ux, u.uy, \
209 | youmonst.m_ap_type == M_AP_NOTHING ? \
210 | hero_glyph : \
211 | youmonst.m_ap_type == M_AP_FURNITURE ? \
212 | cmap_to_glyph(youmonst.mappearance) : \
213 | youmonst.m_ap_type == M_AP_OBJECT ? \
214 | objnum_to_glyph(youmonst.mappearance) : \
215 | /* else M_AP_MONSTER */ monnum_to_glyph(youmonst.mappearance))
216 | #endif
217 |
218 | /*
219 | * A glyph is an abstraction that represents a _unique_ monster, object,
220 | * dungeon part, or effect. The uniqueness is important. For example,
221 | * It is not enough to have four (one for each "direction") zap beam glyphs,
222 | * we need a set of four for each beam type. Why go to so much trouble?
223 | * Because it is possible that any given window dependent display driver
224 | * [print_glyph()] can produce something different for each type of glyph.
225 | * That is, a beam of cold and a beam of fire would not only be different
226 | * colors, but would also be represented by different symbols.
227 | *
228 | * Glyphs are grouped for easy accessibility:
229 | *
230 | * monster Represents all the wild (not tame) monsters. Count: NUMMONS.
231 | *
232 | * pet Represents all of the tame monsters. Count: NUMMONS
233 | *
234 | * invisible Invisible monster placeholder. Count: 1
235 | *
236 | * detect Represents all detected monsters. Count: NUMMONS
237 | *
238 | * corpse One for each monster. Count: NUMMONS
239 | *
240 | * ridden Represents all monsters being ridden. Count: NUMMONS
241 | *
242 | * object One for each object. Count: NUM_OBJECTS
243 | *
244 | * cmap One for each entry in the character map. The character map
245 | * is the dungeon features and other miscellaneous things.
246 | * Count: MAXPCHARS
247 | *
248 | * zap beam A set of four (there are four directions) for each beam type.
249 | * The beam type is shifted over 2 positions and the direction
250 | * is stored in the lower 2 bits. Count: NUM_ZAP << 2
251 | *
252 | * swallow A set of eight for each monster. The eight positions rep-
253 | * resent those surrounding the hero. The monster number is
254 | * shifted over 3 positions and the swallow position is stored
255 | * in the lower three bits. Count: NUMMONS << 3
256 | *
257 | * warning A set of six representing the different warning levels.
258 | *
259 | * The following are offsets used to convert to and from a glyph.
260 | */
261 | #define NUM_ZAP 8 /* number of zap beam types */
262 |
263 | #define GLYPH_MON_OFF 0
264 | #define GLYPH_PET_OFF (NUMMONS + GLYPH_MON_OFF)
265 | #define GLYPH_INVIS_OFF (NUMMONS + GLYPH_PET_OFF)
266 | #define GLYPH_DETECT_OFF (1 + GLYPH_INVIS_OFF)
267 | #define GLYPH_BODY_OFF (NUMMONS + GLYPH_DETECT_OFF)
268 | #define GLYPH_RIDDEN_OFF (NUMMONS + GLYPH_BODY_OFF)
269 | #define GLYPH_OBJ_OFF (NUMMONS + GLYPH_RIDDEN_OFF)
270 | #define GLYPH_CMAP_OFF (NUM_OBJECTS + GLYPH_OBJ_OFF)
271 | #define GLYPH_ZAP_OFF (MAXPCHARS + GLYPH_CMAP_OFF)
272 | #define GLYPH_SWALLOW_OFF ((NUM_ZAP << 2) + GLYPH_ZAP_OFF)
273 | #define GLYPH_WARNING_OFF ((NUMMONS << 3) + GLYPH_SWALLOW_OFF)
274 | #define MAX_GLYPH (WARNCOUNT + GLYPH_WARNING_OFF)
275 |
276 | #define NO_GLYPH MAX_GLYPH
277 |
278 | #define GLYPH_INVISIBLE GLYPH_INVIS_OFF
279 |
280 | #define warning_to_glyph(mwarnlev) ((mwarnlev)+GLYPH_WARNING_OFF)
281 | #define mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_MON_OFF)
282 | #define detected_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_DETECT_OFF)
283 | #define ridden_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_RIDDEN_OFF)
284 | #define pet_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_PET_OFF)
285 |
286 | /* This has the unfortunate side effect of needing a global variable */
287 | /* to store a result. 'otg_temp' is defined and declared in decl.{ch}. */
288 | #define obj_to_glyph(obj) \
289 | (Hallucination ? \
290 | ((otg_temp = random_object()) == CORPSE ? \
291 | random_monster() + GLYPH_BODY_OFF : \
292 | otg_temp + GLYPH_OBJ_OFF) : \
293 | ((obj)->otyp == CORPSE ? \
294 | (int) (obj)->corpsenm + GLYPH_BODY_OFF : \
295 | (int) (obj)->otyp + GLYPH_OBJ_OFF))
296 |
297 | #define cmap_to_glyph(cmap_idx) ((int) (cmap_idx) + GLYPH_CMAP_OFF)
298 | #define trap_to_glyph(trap) \
299 | cmap_to_glyph(trap_to_defsym(what_trap((trap)->ttyp)))
300 |
301 | /* Not affected by hallucination. Gives a generic body for CORPSE */
302 | #define objnum_to_glyph(onum) ((int) (onum) + GLYPH_OBJ_OFF)
303 | #define monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_MON_OFF)
304 | #define detected_monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_DETECT_OFF)
305 | #define ridden_monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_RIDDEN_OFF)
306 | #define petnum_to_glyph(mnum) ((int) (mnum) + GLYPH_PET_OFF)
307 |
308 | /* The hero's glyph when seen as a monster. Could also be...
309 | * mon_to_glyph(Upolyd || Race_if(PM_HUMAN) ? u.umonnum : urace.malenum)
310 | */
311 | #define hero_glyph monnum_to_glyph(u.umonnum)
312 |
313 |
314 | /*
315 | * Change the given glyph into it's given type. Note:
316 | * 1) Pets, detected, and ridden monsters are animals and are converted
317 | * to the proper monster number.
318 | * 2) Bodies are all mapped into the generic CORPSE object
319 | * 3) If handed a glyph out of range for the type, these functions
320 | * will return NO_GLYPH (see exception below)
321 | * 4) glyph_to_swallow() does not return a showsyms[] index, but an
322 | * offset from the first swallow symbol. If handed something
323 | * out of range, it will return zero (for lack of anything better
324 | * to return).
325 | */
326 | #define glyph_to_mon(glyph) \
327 | (glyph_is_normal_monster(glyph) ? ((glyph)-GLYPH_MON_OFF) : \
328 | glyph_is_pet(glyph) ? ((glyph)-GLYPH_PET_OFF) : \
329 | glyph_is_detected_monster(glyph) ? ((glyph)-GLYPH_DETECT_OFF) : \
330 | glyph_is_ridden_monster(glyph) ? ((glyph)-GLYPH_RIDDEN_OFF) : \
331 | NO_GLYPH)
332 | #define glyph_to_obj(glyph) \
333 | (glyph_is_body(glyph) ? CORPSE : \
334 | glyph_is_normal_object(glyph) ? ((glyph)-GLYPH_OBJ_OFF) : \
335 | NO_GLYPH)
336 | #define glyph_to_trap(glyph) \
337 | (glyph_is_trap(glyph) ? \
338 | ((int) defsym_to_trap((glyph) - GLYPH_CMAP_OFF)) : \
339 | NO_GLYPH)
340 | #define glyph_to_cmap(glyph) \
341 | (glyph_is_cmap(glyph) ? ((glyph) - GLYPH_CMAP_OFF) : \
342 | NO_GLYPH)
343 | #define glyph_to_swallow(glyph) \
344 | (glyph_is_swallow(glyph) ? (((glyph) - GLYPH_SWALLOW_OFF) & 0x7) : \
345 | 0)
346 | #define glyph_to_warning(glyph) \
347 | (glyph_is_warning(glyph) ? ((glyph) - GLYPH_WARNING_OFF) : \
348 | NO_GLYPH);
349 |
350 | /*
351 | * Return true if the given glyph is what we want. Note that bodies are
352 | * considered objects.
353 | */
354 | #define glyph_is_monster(glyph) \
355 | (glyph_is_normal_monster(glyph) \
356 | || glyph_is_pet(glyph) \
357 | || glyph_is_ridden_monster(glyph) \
358 | || glyph_is_detected_monster(glyph))
359 | #define glyph_is_normal_monster(glyph) \
360 | ((glyph) >= GLYPH_MON_OFF && (glyph) < (GLYPH_MON_OFF+NUMMONS))
361 | #define glyph_is_pet(glyph) \
362 | ((glyph) >= GLYPH_PET_OFF && (glyph) < (GLYPH_PET_OFF+NUMMONS))
363 | #define glyph_is_body(glyph) \
364 | ((glyph) >= GLYPH_BODY_OFF && (glyph) < (GLYPH_BODY_OFF+NUMMONS))
365 | #define glyph_is_ridden_monster(glyph) \
366 | ((glyph) >= GLYPH_RIDDEN_OFF && (glyph) < (GLYPH_RIDDEN_OFF+NUMMONS))
367 | #define glyph_is_detected_monster(glyph) \
368 | ((glyph) >= GLYPH_DETECT_OFF && (glyph) < (GLYPH_DETECT_OFF+NUMMONS))
369 | #define glyph_is_invisible(glyph) ((glyph) == GLYPH_INVISIBLE)
370 | #define glyph_is_normal_object(glyph) \
371 | ((glyph) >= GLYPH_OBJ_OFF && (glyph) < (GLYPH_OBJ_OFF+NUM_OBJECTS))
372 | #define glyph_is_object(glyph) \
373 | (glyph_is_normal_object(glyph) \
374 | || glyph_is_body(glyph))
375 | #define glyph_is_trap(glyph) \
376 | ((glyph) >= (GLYPH_CMAP_OFF+trap_to_defsym(1)) && \
377 | (glyph) < (GLYPH_CMAP_OFF+trap_to_defsym(1)+TRAPNUM))
378 | #define glyph_is_cmap(glyph) \
379 | ((glyph) >= GLYPH_CMAP_OFF && (glyph) < (GLYPH_CMAP_OFF+MAXPCHARS))
380 | #define glyph_is_swallow(glyph) \
381 | ((glyph) >= GLYPH_SWALLOW_OFF && (glyph) < (GLYPH_SWALLOW_OFF+(NUMMONS << 3)))
382 | #define glyph_is_warning(glyph) \
383 | ((glyph) >= GLYPH_WARNING_OFF && (glyph) < (GLYPH_WARNING_OFF + WARNCOUNT))
384 | #endif /* DISPLAY_H */