Fandom

Wikihack

Source:NetHack 3.1.0/display.c

2,034pages on
this wiki
Add New Page
Talk0

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

Below is the full text to display.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/display.c#line123]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.
1.    /*	SCCS Id: @(#)display.c	3.1	92/10/25	*/
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.    /*
7.     *			THE NEW DISPLAY CODE
8.     *
9.     * The old display code has been broken up into three parts: vision, display,
10.    * and drawing.  Vision decides what locations can and cannot be physically
11.    * seen by the hero.  Display decides _what_ is displayed at a given location.
12.    * Drawing decides _how_ to draw a monster, fountain, sword, etc.
13.    *
14.    * The display system uses information from the vision system to decide
15.    * what to draw at a given location.  The routines for the vision system
16.    * can be found in vision.c and vision.h.  The routines for display can
17.    * be found in this file (display.c) and display.h.  The drawing routines
18.    * are part of the window port.  See doc/window.doc for the drawing
19.    * interface.
20.    *
21.    * The display system deals with an abstraction called a glyph.  Anything
22.    * that could possibly be displayed has a unique glyph identifier.
23.    *
24.    * What is seen on the screen is a combination of what the hero remembers
25.    * and what the hero currently sees.  Objects and dungeon features (walls
26.    * doors, etc) are remembered when out of sight.  Monsters and temporary
27.    * effects are not remembered.  Each location on the level has an
28.    * associated glyph.  This is the hero's _memory_ of what he or she has
29.    * seen there before.
30.    *
31.    * Display rules:
32.    *
33.    *	If the location is in sight, display in order:
34.    *		visible monsters
35.    *		visible objects
36.    *		known traps
37.    *		background
38.    *
39.    *	If the location is out of sight, display in order:
40.    *		sensed monsters (telepathy)
41.    *		memory
42.    *
43.    *
44.    *
45.    * Here is a list of the major routines in this file to be used externally:
46.    *
47.    * newsym
48.    *
49.    * Possibly update the screen location (x,y).  This is the workhorse routine.
50.    * It is always correct --- where correct means following the in-sight/out-
51.    * of-sight rules.  **Most of the code should use this routine.**  This
52.    * routine updates the map and displays monsters.
53.    *
54.    *
55.    * map_background
56.    * map_object
57.    * map_trap
58.    * unmap_object
59.    *
60.    * If you absolutely must override the in-sight/out-of-sight rules, there
61.    * are two possibilities.  First, you can mess with vision to force the
62.    * location in sight then use newsym(), or you can  use the map_* routines.
63.    * The first has not been tried [no need] and the second is used in the
64.    * detect routines --- detect object, magic mapping, etc.  The map_*
65.    * routines *change* what the hero remembers.  All changes made by these
66.    * routines will be sticky --- they will survive screen redraws.  Do *not*
67.    * use these for things that only temporarily change the screen.  These
68.    * routines are also used directly by newsym().  unmap_object is used to
69.    * clear a remembered object when/if detection reveals it isn't there.
70.    *
71.    *
72.    * show_glyph
73.    *
74.    * This is direct (no processing in between) buffered access to the screen.
75.    * Temporary screen effects are run through this and its companion,
76.    * flush_screen().  There is yet a lower level routine, print_glyph(),
77.    * but this is unbuffered and graphic dependent (i.e. it must be surrounded
78.    * by graphic set-up and tear-down routines).  Do not use print_glyph().
79.    *
80.    *
81.    * see_monsters
82.    * see_objects
83.    *
84.    * These are only used when something affects all of the monsters or
85.    * objects.  For objects, the only thing is hallucination.  For monsters,
86.    * there are hallucination and changing from/to blindness, etc.
87.    *
88.    *
89.    * tmp_at
90.    *
91.    * This is a useful interface for displaying temporary items on the screen.
92.    * Its interface is different than previously, so look at it carefully.
93.    *
94.    *
95.    *
96.    * Parts of the rm structure that are used:
97.    *
98.    *	typ	- What is really there.
99.    *	glyph	- What the hero remembers.  This will never be a monster.
100.   *		  Monsters "float" above this.
101.   *	lit	- True if the position is lit.  An optimization for
102.   *		  lit/unlit rooms.
103.   *	waslit	- True if the position was *remembered* as lit.
104.   *	seen	- Set to true when the location is seen or felt as it really
105.   *		  is.  This is used primarily for walls, which look like stone
106.   *		  if seen from the outside of a room.  However, this is
107.   *		  also used as a guide for blind heros.  If the hero has
108.   *		  seen or felt a room feature underneath a boulder, when the
109.   *		  boulder is moved, the hero should see it again.  This is
110.   *		  also used as an indicator for unmapping detected objects.
111.   *
112.   *	doormask   - Additional information for the typ field.
113.   *	horizontal - Indicates whether the wall or door is horizontal or
114.   *		     vertical.
115.   */
116.  #include "hack.h"
117.  
118.  static void FDECL(display_monster,(XCHAR_P,XCHAR_P,struct monst *,int,XCHAR_P));
119.  static int FDECL(swallow_to_glyph, (int, int));
120.  
121.  #ifdef INVISIBLE_OBJECTS
122.  /*
123.   * vobj_at()
124.   *
125.   * Returns a pointer to an object if the hero can see an object at the
126.   * given location.  This takes care of invisible objects.  NOTE, this
127.   * assumes that the hero is not blind and on top of the object pile.
128.   * It does NOT take into account that the location is out of sight, or,
129.   * say, one can see blessed, etc.
130.   */
131.  struct obj *
132.  vobj_at(x,y)
133.      xchar x,y;
134.  {
135.      register struct obj *obj = level.objects[x][y];
136.  
137.      while (obj) {
138.  	if (!obj->oinvis || See_invisible) return obj;
139.  	obj = obj->nexthere;
140.      }
141.      return ((struct obj *) 0);
142.  }
143.  #endif	/* else vobj_at() is defined in display.h */
144.  
145.  /*
146.   * The routines map_background(), map_object(), and map_trap() could just
147.   * as easily be:
148.   *
149.   *	map_glyph(x,y,glyph,show)
150.   *
151.   * Which is called with the xx_to_glyph() in the call.  Then I can get
152.   * rid of 3 routines that don't do very much anyway.  And then stop
153.   * having to create fake objects and traps.  However, I am reluctant to
154.   * make this change.
155.   */
156.  
157.  /*
158.   * map_background()
159.   *
160.   * Make the real background part of our map.  This routine assumes that
161.   * the hero can physically see the location.  Update the screen if directed.
162.   */
163.  void
164.  map_background(x, y, show)
165.      register xchar x,y;
166.      register int  show;
167.  {
168.      register int glyph = back_to_glyph(x,y);
169.  
170.      if (level.flags.hero_memory)
171.  	levl[x][y].glyph = glyph;
172.      if (show) show_glyph(x,y, glyph);
173.  }
174.  
175.  /*
176.   * map_trap()
177.   *
178.   * Map the trap and print it out if directed.  This routine assumes that the
179.   * hero can physically see the location.
180.   */
181.  void
182.  map_trap(trap, show)
183.      register struct trap *trap;
184.      register int	 show;
185.  {
186.      register int x = trap->tx, y = trap->ty;
187.      register int glyph = trap_to_glyph(trap);
188.  
189.      if (level.flags.hero_memory)
190.  	levl[x][y].glyph = glyph;
191.      if (show) show_glyph(x, y, glyph);
192.  }
193.  
194.  /*
195.   * map_object()
196.   *
197.   * Map the given object.  This routine assumes that the hero can physically
198.   * see the location of the object.  Update the screen if directed.
199.   */
200.  void
201.  map_object(obj, show)
202.      register struct obj *obj;
203.      register int	show;
204.  {
205.      register int x = obj->ox, y = obj->oy;
206.      register int glyph = obj_to_glyph(obj);
207.  
208.      if (level.flags.hero_memory)
209.  	levl[x][y].glyph = glyph;
210.      if (show) show_glyph(x, y, glyph);
211.  }
212.  
213.  /*
214.   * unmap_object()
215.   *
216.   * Remove something from the map when detection reveals that it isn't
217.   * there any more.  Replace it with background or known trap, but not
218.   * with any other remembered object.  No need to update the display;
219.   * a full update is imminent.
220.   *
221.   * This isn't quite correct due to overloading of the seen bit.  But
222.   * it works well enough for now.
223.   */
224.  void
225.  unmap_object(x, y)
226.      register int x, y;
227.  {
228.      register struct trap *trap;
229.  
230.      if (!level.flags.hero_memory) return;
231.  
232.      if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y))
233.  	map_trap(trap, 0);
234.      else if (levl[x][y].seen) {
235.  	struct rm *lev = &levl[x][y];
236.  
237.  	map_background(x, y, 0);
238.  
239.  	/* turn remembered dark room squares dark */
240.  	if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) &&
241.  							    lev->typ == ROOM)
242.  	    lev->glyph = cmap_to_glyph(S_stone);
243.      } else 
244.  	levl[x][y].glyph = cmap_to_glyph(S_stone);	/* default val */
245.  }
246.  
247.  
248.  /*
249.   * map_location()
250.   *
251.   * Make whatever at this location show up.  This is only for non-living
252.   * things.  This will not handle feeling invisible objects correctly.
253.   */
254.  #define map_location(x,y,show)						\
255.  {									\
256.      register struct obj   *obj;						\
257.      register struct trap  *trap;					\
258.  									\
259.      if ((obj = vobj_at(x,y)) && !covers_objects(x,y))			\
260.  	map_object(obj,show);						\
261.      else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y))	\
262.  	map_trap(trap,show);						\
263.      else								\
264.  	map_background(x,y,show);					\
265.  }
266.  
267.  
268.  /*
269.   * display_monster()
270.   *
271.   * Note that this is *not* a map_XXXX() function!  Monsters sort of float
272.   * above everything.
273.   *
274.   * Yuck.  Display body parts by recognizing that the display position is
275.   * not the same as the monster position.  Currently the only body part is
276.   * a worm tail.
277.   *  
278.   */
279.  static void
280.  display_monster(x, y, mon, in_sight, worm_tail)
281.      register xchar x, y;	/* display position */
282.      register struct monst *mon;	/* monster to display */
283.      int in_sight;		/* TRUE if the monster is physically seen */
284.      register xchar worm_tail;	/* mon is actually a worm tail */
285.  {
286.      register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING);
287.      register int sensed = mon_mimic &&
288.  	(Protection_from_shape_changers || sensemon(mon));
289.  
290.      /*
291.       * We must do the mimic check first.  If the mimic is mimicing something,
292.       * and the location is in sight, we have to change the hero's memory
293.       * so that when the position is out of sight, the hero remembers what
294.       * the mimic was mimicing.
295.       */
296.  
297.      if (mon_mimic && in_sight) {
298.  	switch (mon->m_ap_type) {
299.  	    default:
300.  		impossible("display_monster:  bad m_ap_type value [ = %d ]",
301.  							(int) mon->m_ap_type);
302.  	    case M_AP_NOTHING:
303.  		show_glyph(x, y, mon_to_glyph(mon));
304.  		break;
305.  
306.  	    case M_AP_FURNITURE: {
307.  		/*
308.  		 * This is a poor man's version of map_background().  I can't
309.  		 * use map_background() because we are overriding what is in
310.  		 * the 'typ' field.  Maybe have map_background()'s parameters
311.  		 * be (x,y,glyph) instead of just (x,y).
312.  		 *
313.  		 * mappearance is currently set to an S_ index value in
314.  		 * makemon.c.
315.  		 */
316.  		register int glyph = cmap_to_glyph(mon->mappearance);
317.  		levl[x][y].glyph = glyph;
318.  		if (!sensed) show_glyph(x,y, glyph);
319.  		break;
320.  	    }
321.  
322.  	    case M_AP_OBJECT: {
323.  		struct obj obj;	/* Make a fake object to send	*/
324.  				/* to map_object().		*/
325.  		obj.ox = x;
326.  		obj.oy = y;
327.  		obj.otyp = mon->mappearance;
328.  		obj.corpsenm = PM_TENGU;	/* if mimicing a corpse */
329.  		map_object(&obj,!sensed);
330.  		break;
331.  	    }
332.  
333.  	    case M_AP_MONSTER:
334.  		show_glyph(x,y, monnum_to_glyph(what_mon(mon->mappearance)));
335.  		break;
336.  	}
337.  	
338.      }
339.  
340.      /* If the mimic is unsucessfully mimicing something, display the monster */
341.      if (!mon_mimic || sensed) {
342.  	if (mon->mtame) {
343.  	    if (worm_tail)
344.  		show_glyph(x,y, petnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)));
345.  	    else    
346.  		show_glyph(x,y, pet_to_glyph(mon));
347.  	} else {
348.  	    if (worm_tail)
349.  		show_glyph(x,y, monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)));
350.  	    else    
351.  		show_glyph(x,y, mon_to_glyph(mon));
352.  	}
353.      }
354.  }
355.  
356.  /*
357.   * feel_location()
358.   *
359.   * Feel the given location.  This assumes that the hero is blind and that
360.   * the given position is either the hero's or one of the eight squares
361.   * adjacent to the hero (except for a boulder push).
362.   */
363.  void
364.  feel_location(x, y)
365.      xchar x, y;
366.  {
367.      struct rm *lev = &(levl[x][y]);
368.      struct obj *boulder;
369.      register struct monst *mon;
370.  
371.      /* The hero can't feel non pool locations while under water. */
372.      if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y))
373.  	return;
374.  
375.      /* If the hero is not in a corridor, then she will feel the wall as a */
376.      /* wall.  It doesn't matter if the hero is levitating or not.	  */
377.      if ((IS_WALL(lev->typ) || lev->typ == SDOOR) &&
378.  						levl[u.ux][u.uy].typ != CORR)
379.  	lev->seen = 1;
380.  
381.      if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
382.  	/*
383.  	 * Levitation Rules.  It is assumed that the hero can feel the state
384.  	 * of the walls around herself and can tell if she is in a corridor,
385.  	 * room, or doorway.  Boulders are felt because they are large enough.
386.  	 * Anything else is unknown because the hero can't reach the ground.
387.  	 * This makes things difficult.
388.  	 *
389.  	 * Check (and display) in order:
390.  	 *
391.  	 *	+ Stone, walls, and closed doors.
392.  	 *	+ Boulders.  [see a boulder before a doorway]
393.  	 *	+ Doors.
394.  	 *	+ Room/water positions
395.  	 *	+ Everything else (hallways!)
396.  	 */
397.  	if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) &&
398.  				(lev->doormask & (D_LOCKED | D_CLOSED)))) {
399.  	    map_background(x, y, 1);
400.  	} else if (boulder = sobj_at(BOULDER,x,y)) {
401.  	    map_object(boulder, 1);
402.  	} else if (IS_DOOR(lev->typ)) {
403.  	    map_background(x, y, 1);
404.  	} else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) {
405.  	    /*
406.  	     * An open room or water location.  Normally we wouldn't touch
407.  	     * this, but we have to get rid of remembered boulder symbols.
408.  	     * This will only occur in rare occations when the hero goes
409.  	     * blind and doesn't find a boulder where expected (something
410.  	     * came along and picked it up).  We know that there is not a
411.  	     * boulder at this location.  Show fountains, pools, etc.
412.  	     * underneath if already seen.  Otherwise, show the appropriate
413.  	     * floor symbol.
414.  	     *
415.  	     * This isn't quite correct.  If the boulder was on top of some
416.  	     * other objects they should be seen once the boulder is removed.
417.  	     * However, we have no way of knowing that what is there now
418.  	     * was there then.  So we let the hero have a lapse of memory.
419.  	     * We could also just display what is currently on the top of the
420.  	     * object stack (if anything).
421.  	     */
422.  	    if (lev->glyph == objnum_to_glyph(BOULDER)) {
423.  		if (lev->typ != ROOM && lev->seen) {
424.  		    map_background(x, y, 1);
425.  		} else {
426.  		    lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
427.  					       cmap_to_glyph(S_stone);
428.  		    show_glyph(x,y,lev->glyph);
429.  		}
430.  	    }
431.  	} else {
432.  	    /* We feel it (I think hallways are the only things left). */
433.  	    map_background(x, y, 1);
434.  	    /* Corridors are never felt as lit (unless remembered that way) */
435.  	    /* (lit_corridor only).					    */
436.  	    if (lev->typ == CORR &&
437.  		    lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
438.  		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
439.  	}
440.      } else {
441.  	map_location(x, y, 1);
442.  
443.  	if (Punished) {
444.  	    /*
445.  	     * A ball or chain is only felt if it is first on the object
446.  	     * location list.  Otherwise, we need to clear the felt bit ---
447.  	     * something has been dropped on the ball/chain.  If the bit is
448.  	     * not cleared, then when the ball/chain is moved it will drop
449.  	     * the wrong glyph.
450.  	     */
451.  	    if (uchain->ox == x && uchain->oy == y) {
452.  		if (level.objects[x][y] == uchain)
453.  		    u.bc_felt |= BC_CHAIN;
454.  		else
455.  		    u.bc_felt &= ~BC_CHAIN;	/* do not feel the chain */
456.  	    }
457.  	    if (!carried(uball) && uball->ox == x && uball->oy == y) {
458.  		if (level.objects[x][y] == uball)
459.  		    u.bc_felt |= BC_BALL;
460.  		else
461.  		    u.bc_felt &= ~BC_BALL;	/* do not feel the ball */
462.  	    }
463.  	}
464.  
465.  	/* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
466.  	if (lev->typ == ROOM &&
467.  		    lev->glyph == cmap_to_glyph(S_room) && !lev->waslit)
468.  	    show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone));
469.  	else if (lev->typ == CORR &&
470.  		    lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
471.  	    show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr));
472.      }
473.      /* draw monster on top if we can sense it */
474.      if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon))
475.  	display_monster(x,y,mon,1,((x != mon->mx)  || (y != mon->my)));
476.  }
477.  
478.  /*
479.   * newsym()
480.   *
481.   * Possibly put a new glyph at the given location.
482.   */
483.  void
484.  newsym(x,y)
485.      register xchar x,y;
486.  {
487.      register struct monst *mon;
488.      register struct rm *lev = &(levl[x][y]);
489.      register int see_it;
490.      register xchar worm_tail;
491.  
492.      /* only permit updating the hero when swallowed */
493.      if (u.uswallow) {
494.  	if (x == u.ux && y == u.uy) display_self();
495.  	return;
496.      }
497.      if (Underwater && !Is_waterlevel(&u.uz)) {
498.  	/* don't do anything unless (x,y) is an adjacent underwater position */
499.  	int dx, dy;
500.  	if (!is_pool(x,y)) return;
501.  	dx = x - u.ux;	if (dx < 0) dx = -dx;
502.  	dy = y - u.uy;	if (dy < 0) dy = -dy;
503.  	if (dx > 1 || dy > 1) return;
504.      }
505.  
506.      /* Can physically see the location. */
507.      if (cansee(x,y)) {
508.  	lev->waslit = (lev->lit!=0);	/* remember lit condition */
509.  
510.  	if (x == u.ux && y == u.uy) {
511.  	    if (canseeself()) {
512.  		map_location(x,y,0);	/* map *under* self */
513.  		display_self();
514.  	    } else
515.  		/* we can see what is there */
516.  		map_location(x,y,1);
517.  	}
518.  	else if ((mon = m_at(x,y)) &&
519.  		 ((see_it = mon_visible(mon)) || sensemon(mon))) {
520.  	    map_location(x,y,0); 	/* map under the monster */
521.      	    worm_tail = ((x != mon->mx)  || (y != mon->my));
522.  	    display_monster(x,y,mon,see_it,worm_tail);
523.  	}
524.  	else
525.  	    map_location(x,y,1);	/* map the location */
526.      }
527.  
528.      /* Can't see the location. */
529.      else {
530.  	if (x == u.ux && y == u.uy) {
531.  	    feel_location(u.ux, u.uy);		/* forces an update */
532.  
533.  	    if (canseeself()) display_self();
534.  	}
535.  	else if ((mon = m_at(x,y)) && sensemon(mon) &&
536.      		 		!((x != mon->mx)  || (y != mon->my))) {
537.  	    /* Monsters are printed every time. */
538.  	    display_monster(x,y,mon,0,0);
539.  	}
540.  	/*
541.  	 * If the location is remembered as being both dark (waslit is false)
542.  	 * and lit (glyph is a lit room or lit corridor) then it was either:
543.  	 *
544.  	 *	(1) A dark location that the hero could see through night
545.  	 *	    vision.
546.  	 *
547.  	 *	(2) Darkened while out of the hero's sight.  This can happen
548.  	 *	    when cursed scroll of light is read.
549.  	 *
550.  	 * In either case, we have to manually correct the hero's memory to
551.  	 * match waslit.  Deciding when to change waslit is non-trivial.
552.  	 *
553.  	 *  Note:  If flags.lit_corridor is set, then corridors act like room
554.  	 *	   squares.  That is, they light up if in night vision range.
555.  	 *	   If flags.lit_corridor is not set, then corridors will
556.  	 *	   remain dark unless lit by a light spell.
557.  	 *
558.  	 * These checks and changes must be here and not in back_to_glyph().
559.  	 * They are dependent on the position being out of sight.
560.  	 */
561.  	else if (!lev->waslit) {
562.  	    if (flags.lit_corridor && lev->glyph == cmap_to_glyph(S_litcorr) &&
563.  							    lev->typ == CORR)
564.  		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
565.  	    else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM)
566.  		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone));
567.  	    else
568.  		goto show_mem;
569.  	} else {
570.  show_mem:
571.  	    show_glyph(x, y, lev->glyph);
572.  	}
573.      }
574.  }
575.  
576.  
577.  /*
578.   * shieldeff()
579.   *
580.   * Put magic shield pyrotechnics at the given location.  This *could* be
581.   * pulled into a platform dependent routine for fancier graphics if desired.
582.   */
583.  void
584.  shieldeff(x,y)
585.      xchar x,y;
586.  {
587.      register int i;
588.  
589.      if (cansee(x,y)) {	/* Don't see anything if can't see the location */
590.  	for (i = 0; i < SHIELD_COUNT; i++) {
591.  	    show_glyph(x, y, cmap_to_glyph(shield_static[i]));
592.  	    flush_screen(1);	/* make sure the glyph shows up */
593.  	    delay_output();
594.  	}
595.  	newsym(x,y);		/* restore the old information */
596.      }
597.  }
598.  
599.  
600.  /*
601.   * tmp_at()
602.   *
603.   * Temporarily place glyphs on the screen.  Do not call delay_output().  It
604.   * is up to the caller to decide if it wants to wait [presently, everyone
605.   * but explode() wants to delay].
606.   *
607.   * Call:
608.   *	(DISP_BEAM,   glyph)	open, initialize glyph
609.   *	(DISP_FLASH,  glyph)	open, initialize glyph
610.   *	(DISP_CHANGE, glyph)	change glyph
611.   *	(DISP_END,    0)	close & clean up (second argument doesn't
612.   *				matter)
613.   *	(x, y)			display the glyph at the location
614.   *
615.   * DISP_BEAM  - Display the given glyph at each location, but do not erase
616.   *		any until the close call.
617.   * DISP_FLASH - Display the given glyph at each location, but erase the
618.   *		previous location's glyph.
619.   */
620.  void
621.  tmp_at(x, y)
622.      int x, y;
623.  {
624.      static coord saved[COLNO];	/* prev positions, only for DISP_BEAM */
625.      static int sidx = 0;	/* index of saved previous positions */
626.      static int sx = -1, sy;	/* previous position, only for DISP_FLASH */
627.      static int status;		/* either DISP_BEAM or DISP_FLASH */
628.      static int glyph;		/* glyph to use when printing */
629.  
630.      switch (x) {
631.  	case DISP_BEAM:
632.  	case DISP_FLASH:
633.  	    status = x;
634.  	    glyph  = y;
635.  	    flush_screen(0);	/* flush buffered glyphs */
636.  	    break;
637.  
638.  	case DISP_CHANGE:
639.  	    glyph = y;
640.  	    break;
641.  
642.  	case DISP_END:
643.  	    if (status == DISP_BEAM) {
644.  		register int i;
645.  
646.  		/* Erase (reset) from source to end */
647.  		for (i = 0; i < sidx; i++)
648.  		    newsym(saved[i].x,saved[i].y);
649.  		sidx = 0;
650.  		
651.  	    } else if (sx >= 0) {	/* DISP_FLASH (called at least once) */
652.  		newsym(sx,sy);	/* reset the location */
653.  		sx = -1;	/* reset sx to an illegal pos for next time */
654.  	    }
655.  	    break;
656.  
657.  	default:	/* do it */
658.  	    if (!cansee(x,y)) break;
659.  
660.  	    if (status == DISP_BEAM) {
661.  		saved[sidx  ].x = x;	/* save pos for later erasing */
662.  		saved[sidx++].y = y;
663.  	    }
664.  
665.  	    else {	/* DISP_FLASH */
666.  		if (sx >= 0)		/* not first call */
667.  		    newsym(sx,sy);	/* update the old position */
668.  
669.  		sx = x;		/* save previous pos for next call */
670.  		sy = y;
671.  	    }
672.  
673.  	    show_glyph(x,y,glyph);	/* show it */
674.  	    flush_screen(0);		/* make sure it shows up */
675.  	    break;
676.      } /* end case */
677.  }
678.  
679.  
680.  /*
681.   * swallowed()
682.   *
683.   * The hero is swallowed.  Show a special graphics sequence for this.  This
684.   * bypasses all of the display routines and messes with buffered screen
685.   * directly.  This method works because both vision and display check for
686.   * being swallowed.
687.   */
688.  void
689.  swallowed(first)
690.      int first;
691.  {
692.      static xchar lastx, lasty;	/* last swallowed position */
693.      int swallower;
694.  
695.      if (first)
696.  	cls();
697.      else {
698.  	register int x, y;
699.  
700.  	/* Clear old location */
701.  	for (y = lasty-1; y <= lasty+1; y++)
702.  	    if(isok(lastx,y)) {
703.  		for (x = lastx-1; x <= lastx+1; x++)
704.  		    show_glyph(x,y,cmap_to_glyph(S_stone));
705.  	    }
706.      }
707.  
708.      swallower = monsndx(u.ustuck->data);
709.      /*
710.       *  Display the hero surrounded by the monster's stomach.
711.       */
712.      if(isok(u.ux, u.uy-1)) {
713.  	show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl));
714.  	show_glyph(u.ux  , u.uy-1, swallow_to_glyph(swallower, S_sw_tc));
715.  	show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr));
716.      }
717.  
718.      show_glyph(u.ux-1, u.uy  , swallow_to_glyph(swallower, S_sw_ml));
719.      display_self();
720.      show_glyph(u.ux+1, u.uy  , swallow_to_glyph(swallower, S_sw_mr));
721.  
722.      if(isok(u.ux, u.uy+1)) {
723.  	show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl));
724.  	show_glyph(u.ux  , u.uy+1, swallow_to_glyph(swallower, S_sw_bc));
725.  	show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br));
726.      }
727.  
728.      /* Update the swallowed position. */
729.      lastx = u.ux;
730.      lasty = u.uy;
731.  }
732.  
733.  /*
734.   * under_water()
735.   *
736.   * Similar to swallowed() in operation.  Shows hero when underwater
737.   * except when in water level.  Special routines exist for that.
738.   */
739.  void
740.  under_water(mode)
741.      int mode;
742.  {
743.      static xchar lastx, lasty;
744.      static boolean dela;
745.      register int x, y;
746.  
747.      /* swallowing has a higher precedence than under water */
748.      if (Is_waterlevel(&u.uz) || u.uswallow) return;
749.  
750.      /* full update */
751.      if (mode == 1 || dela) {
752.  	cls();
753.  	dela = FALSE;
754.      }   
755.      /* delayed full update */
756.      else if (mode == 2) {
757.  	dela = TRUE;
758.  	return;
759.      }
760.      /* limited update */
761.      else {
762.  	for (y = lasty-1; y <= lasty+1; y++)
763.  	    for (x = lastx-1; x <= lastx+1; x++)
764.  		if (isok(x,y)) 
765.  		    show_glyph(x,y,cmap_to_glyph(S_stone));
766.      }
767.      for (x = u.ux-1; x <= u.ux+1; x++)
768.  	for (y = u.uy-1; y <= u.uy+1; y++)
769.  	    if (isok(x,y) && is_pool(x,y)) {
770.  		if (Blind && !(x == u.ux && y == u.uy))
771.  		    show_glyph(x,y,cmap_to_glyph(S_stone));
772.  		else	
773.  		    newsym(x,y);
774.  	    }
775.      lastx = u.ux;
776.      lasty = u.uy;
777.  }
778.  
779.  
780.  /* ========================================================================= */
781.  
782.  /*
783.   * Loop through all of the monsters and update them.  Called when:
784.   *	+ going blind & telepathic
785.   *	+ regaining sight & telepathic
786.   *	+ hallucinating
787.   *	+ doing a full screen redraw
788.   *	+ see invisible times out or a ring of see invisible is taken off
789.   *	+ when a potion of see invisible is quaffed or a ring of see
790.   *	  invisible is put on
791.   *	+ gaining telepathy when blind [givit() in eat.c, pleased() in pray.c]
792.   *	+ losing telepathy while blind [xkilled() in mon.c, attrcurse() in
793.   *	  sit.c]
794.   */
795.  void
796.  see_monsters()
797.  {
798.      register struct monst *mon;
799.      for (mon = fmon; mon; mon = mon->nmon) {
800.  	newsym(mon->mx,mon->my);
801.  	if (mon->wormno) see_wsegs(mon);
802.      }
803.  }
804.  
805.  /*
806.   * Block/unblock light depending on what a mimic is mimicing and if it's
807.   * invisible or not.  Should be called only when the state of See_invisible
808.   * changes.
809.   */
810.  void
811.  set_mimic_blocking()
812.  {
813.      register struct monst *mon;
814.      for (mon = fmon; mon; mon = mon->nmon)
815.  	if(mon->minvis &&
816.  	   ((mon->m_ap_type == M_AP_FURNITURE &&
817.  	      (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))||
818.  	    (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) {
819.  	    if(See_invisible)
820.  		block_point(mon->mx, mon->my);
821.  	    else
822.  		unblock_point(mon->mx, mon->my);
823.  	}
824.  }
825.  
826.  /*
827.   * Loop through all of the object *locations* and update them.  Called when
828.   *	+ hallucinating.
829.   */
830.  void
831.  see_objects()
832.  {
833.      register struct obj *obj;
834.      for(obj = fobj; obj; obj = obj->nobj)
835.  	if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy);
836.  }
837.  
838.  /*
839.   * Put the cursor on the hero.  Flush all accumulated glyphs before doing it.
840.   */
841.  void
842.  curs_on_u()
843.  {
844.      flush_screen(1);	/* Flush waiting glyphs & put cursor on hero */
845.  }
846.  
847.  int
848.  doredraw()
849.  {
850.      docrt();
851.      return 0;
852.  }
853.  
854.  void
855.  docrt()
856.  {
857.      register int x,y;
858.      register struct rm *lev;
859.  
860.      if (!u.ux) return; /* display isn't ready yet */
861.  
862.      if (u.uswallow) {
863.  	swallowed(1);
864.  	return;
865.      }
866.      if (Underwater && !Is_waterlevel(&u.uz)) {
867.  	under_water(1);
868.  	return;
869.      }
870.  
871.      /* shut down vision */
872.      vision_recalc(2);
873.  
874.      /*
875.       * This routine assumes that cls() does the following:
876.       *      + fills the physical screen with the symbol for rock
877.       *      + clears the glyph buffer
878.       */
879.      cls();
880.  
881.      /* display memory */
882.      for (x = 1; x < COLNO; x++) {
883.  	lev = &levl[x][0];
884.  	for (y = 0; y < ROWNO; y++, lev++)
885.  	    if (lev->glyph != cmap_to_glyph(S_stone))
886.  		show_glyph(x,y,lev->glyph);
887.      }
888.  
889.      /* see what is to be seen */
890.      vision_recalc(0);
891.  
892.      /* overlay with monsters */
893.      see_monsters();
894.  
895.      flags.botlx = 1;	/* force a redraw of the bottom line */
896.  }
897.  
898.  
899.  /* ========================================================================= */
900.  /* Glyph Buffering (3rd screen) ============================================ */
901.  
902.  typedef struct {
903.      xchar new;		/* perhaps move this bit into the rm strucure. */
904.      int   glyph;
905.  } gbuf_entry;
906.  
907.  static gbuf_entry gbuf[ROWNO][COLNO];
908.  static char gbuf_start[ROWNO];
909.  static char gbuf_stop[ROWNO];
910.  
911.  /*
912.   * Store the glyph in the 3rd screen for later flushing.
913.   */
914.  void
915.  show_glyph(x,y,glyph)
916.      xchar x,y;
917.      int   glyph;
918.  {
919.      /*
920.       * Check for bad positions and glyphs.
921.       */
922.      if (x <= 0 || x >= COLNO || y < 0 || y >= ROWNO) {
923.  	const char *text;
924.  	int  offset;
925.  
926.  	/* column 0 is invalid, but it's often used as a flag, so ignore it */
927.  	if (x == 0) return;
928.  
929.  	/*
930.  	 *  This assumes an ordering of the offsets.  See display.h for
931.  	 *  the definition.
932.  	 */
933.  	if (glyph >= GLYPH_SWALLOW_OFF) {		/* swallow border */
934.  	    text = "swallow border";	offset = glyph - GLYPH_SWALLOW_OFF;
935.  	}else if (glyph >= GLYPH_ZAP_OFF) {		/* zap beam */
936.  	    text = "zap beam";		offset = glyph - GLYPH_ZAP_OFF;
937.  	} else if (glyph >= GLYPH_CMAP_OFF) {		/* cmap */
938.  	    text = "cmap_index";	offset = glyph - GLYPH_CMAP_OFF;
939.  	} else if (glyph >= GLYPH_TRAP_OFF) {		/* trap */
940.  	    text = "trap";		offset = glyph - GLYPH_TRAP_OFF;
941.  	} else if (glyph >= GLYPH_OBJ_OFF) {		/* object */
942.  	    text = "object";		offset = glyph - GLYPH_OBJ_OFF;
943.  	} else if (glyph >= GLYPH_BODY_OFF) {		/* a corpse */
944.  	    text = "corpse";		offset = glyph - GLYPH_BODY_OFF;
945.  	} else {					/* a monster */
946.  	    text = "monster";		offset = glyph;
947.  	}
948.  
949.  	impossible("show_glyph:  bad pos %d %d with glyph %d [%s %d].",
950.  						x, y, glyph, text, offset);
951.  	return;
952.      }
953.  
954.      if (glyph >= MAX_GLYPH) {
955.  	impossible("show_glyph:  bad glyph %d [max %d] at (%d,%d).",
956.  					glyph, MAX_GLYPH, x, y);
957.  	return;
958.      }
959.  
960.      if (gbuf[y][x].glyph != glyph) {
961.  	gbuf[y][x].glyph = glyph;
962.  	gbuf[y][x].new   = 1;
963.  	if (gbuf_start[y] > x) gbuf_start[y] = x;
964.  	if (gbuf_stop[y]  < x) gbuf_stop[y]  = x;
965.      }
966.  }
967.  
968.  
969.  /*
970.   * Reset the changed glyph borders so that none of the 3rd screen has
971.   * changed.
972.   */
973.  #define reset_glyph_bbox()			\
974.      {						\
975.  	int i;					\
976.  						\
977.  	for (i = 0; i < ROWNO; i++) {		\
978.  	    gbuf_start[i] = COLNO-1;		\
979.  	    gbuf_stop[i]  = 0;			\
980.  	}					\
981.      }
982.  
983.  
984.  static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) };
985.  /*
986.   * Turn the 3rd screen into stone.
987.   */
988.  void
989.  clear_glyph_buffer()
990.  {
991.      register int x, y;
992.      register gbuf_entry *gptr;
993.  
994.      for (y = 0; y < ROWNO; y++) {
995.  	gptr = &gbuf[y][0];
996.  	for (x = COLNO; x; x--) {
997.  	    *gptr++ = nul_gbuf;
998.  	}
999.      }
1000.     reset_glyph_bbox();
1001. }
1002. 
1003. /*
1004.  * Assumes that the indicated positions are filled with S_stone glyphs.
1005.  */
1006. void
1007. row_refresh(start,stop,y)
1008.     int start,stop,y;
1009. {
1010.     register int x;
1011. 
1012.     for (x = start; x <= stop; x++)
1013. 	if (gbuf[y][x].glyph != cmap_to_glyph(S_stone))
1014. 	    print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph);
1015. }
1016. 
1017. void
1018. cls()
1019. {
1020.     display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
1021.     flags.botlx = 1;		/* force update of botl window */
1022.     clear_nhwindow(WIN_MAP);	/* clear physical screen */
1023. 
1024.     clear_glyph_buffer();	/* this is sort of an extra effort, but OK */
1025. }
1026. 
1027. /*
1028.  * Synch the third screen with the display.
1029.  */
1030. void
1031. flush_screen(cursor_on_u)
1032.     int cursor_on_u;
1033. {
1034.     /* Prevent infinite loops on errors:
1035.      *	    flush_screen->print_glyph->impossible->pline->flush_screen
1036.      */
1037.     static   boolean flushing = 0;
1038.     register int x,y;
1039. 
1040.     if (flushing) return;	/* if already flushing then return */
1041.     flushing = 1;
1042. 
1043.     for (y = 0; y < ROWNO; y++) {
1044. 	register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]];
1045. 	for (; x <= gbuf_stop[y]; gptr++, x++)
1046. 	    if (gptr->new) {
1047. 		print_glyph(WIN_MAP,x,y,gptr->glyph);
1048. 		gptr->new = 0;
1049. 	    }
1050.     }
1051. 
1052.     if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */
1053.     display_nhwindow(WIN_MAP, FALSE);
1054.     reset_glyph_bbox();
1055.     flushing = 0;
1056.     if(flags.botl || flags.botlx) bot();
1057. }
1058. 
1059. /* ========================================================================= */
1060. 
1061. /*
1062.  * back_to_glyph()
1063.  *
1064.  * Use the information in the rm structure at the given position to create
1065.  * a glyph of a background.
1066.  *
1067.  * I had to add a field in the rm structure (horizontal) so that we knew
1068.  * if open doors and secret doors were horizontal or vertical.  Previously,
1069.  * the screen symbol had the horizontal/vertical information set at
1070.  * level generation time.
1071.  *
1072.  * I used the 'ladder' field (really doormask) for deciding if stairwells
1073.  * were up or down.  I didn't want to check the upstairs and dnstairs
1074.  * variables.
1075.  */
1076. int
1077. back_to_glyph(x,y)
1078.     xchar x,y;
1079. {
1080.     int idx;
1081.     struct rm *ptr = &(levl[x][y]);
1082. 
1083.     switch (ptr->typ) {
1084. 	case SCORR:
1085. 	case STONE:		idx = S_stone;	  break;
1086. 	case ROOM:		idx = S_room;	  break;
1087. 	case CORR:
1088. 	    idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr;
1089. 	    break;
1090. 	case HWALL:	idx = ptr->seen ? S_hwall  : S_stone;   break;
1091. 	case VWALL:	idx = ptr->seen ? S_vwall  : S_stone;   break;
1092. 	case TLCORNER:	idx = ptr->seen ? S_tlcorn : S_stone;	break;
1093. 	case TRCORNER:	idx = ptr->seen ? S_trcorn : S_stone;	break;
1094. 	case BLCORNER:	idx = ptr->seen ? S_blcorn : S_stone;	break;
1095. 	case BRCORNER:	idx = ptr->seen ? S_brcorn : S_stone;	break;
1096. 	case CROSSWALL:	idx = ptr->seen ? S_crwall : S_stone;	break;
1097. 	case TUWALL:	idx = ptr->seen ? S_tuwall : S_stone;	break;
1098. 	case TDWALL:	idx = ptr->seen ? S_tdwall : S_stone;	break;
1099. 	case TLWALL:	idx = ptr->seen ? S_tlwall : S_stone;	break;
1100. 	case TRWALL:	idx = ptr->seen ? S_trwall : S_stone;	break;
1101. 	case SDOOR:
1102. 	    if (ptr->seen)
1103. 		idx = (ptr->horizontal) ? S_hwall : S_vwall;
1104. 	    else
1105. 		idx = S_stone;
1106. 	    break;
1107. 	case DOOR:
1108. 	    if (ptr->doormask) {
1109. 		if (ptr->doormask & D_BROKEN)
1110. 		    idx = S_ndoor;
1111. 		else if (ptr->doormask & D_ISOPEN)
1112. 		    idx = (ptr->horizontal) ? S_hodoor : S_vodoor;
1113. 		else			/* else is closed */
1114. 		    idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor;
1115. 	    } else
1116. 		idx = S_ndoor;
1117. 	    break;
1118. 	case POOL:
1119. 	case MOAT:		idx = S_pool;	  break;
1120. 	case STAIRS:
1121. 	    idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair;
1122. 	    break;
1123. 	case LADDER:
1124. 	    idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder;
1125. 	    break;
1126. 	case FOUNTAIN:		idx = S_fountain; break;
1127. 	case SINK:		idx = S_sink;     break;
1128. 	case ALTAR:		idx = S_altar;    break;
1129. 	case THRONE:		idx = S_throne;   break;
1130. 	case LAVAPOOL:		idx = S_lava;	  break;
1131. 	case ICE:		idx = S_ice;      break;
1132. 	case AIR:		idx = S_air;	  break;
1133. 	case CLOUD:		idx = S_cloud;	  break;
1134. 	case WATER:		idx = S_water;	  break;
1135. 	case DBWALL:
1136. 	    idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge;
1137. 	    break;
1138. 	case DRAWBRIDGE_UP:
1139. 	    switch(ptr->drawbridgemask & DB_UNDER) {
1140. 	    case DB_MOAT:  idx = S_pool; break;
1141. 	    case DB_LAVA:  idx = S_lava; break;
1142. 	    case DB_ICE:   idx = S_ice;  break;
1143. 	    case DB_FLOOR: idx = S_room; break;
1144. 	    default:
1145. 		impossible("Strange db-under: %d",
1146. 			   ptr->drawbridgemask & DB_UNDER);
1147. 		idx = S_room; /* something is better than nothing */
1148. 		break;
1149. 	    }
1150. 	    break;
1151. 	case DRAWBRIDGE_DOWN:
1152. 	    idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge;
1153. 	    break;
1154. 	default:
1155. 	    impossible("back_to_glyph:  unknown level type [ = %d ]",ptr->typ);
1156. 	    idx = S_room;
1157. 	    break;
1158.     }
1159. 
1160.     return cmap_to_glyph(idx);
1161. }
1162. 
1163. 
1164. /*
1165.  * swallow_to_glyph()
1166.  *
1167.  * Convert a monster number and a swallow location into the correct glyph.
1168.  * If you don't want a patchwork monster while hallucinating, decide on
1169.  * a random monster in swallowed() and don't use what_mon() here.
1170.  */
1171. static int
1172. swallow_to_glyph(mnum, loc)
1173.     int mnum;
1174.     int loc;
1175. {
1176.     if (loc < S_sw_tl || S_sw_br < loc) {
1177. 	impossible("swallow_to_glyph: bad swallow location");
1178. 	loc = S_sw_br;
1179.     }
1180.     return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF;
1181. }
1182. 
1183. 
1184. 
1185. /*
1186.  * zapdir_to_glyph()
1187.  *
1188.  * Change the given zap direction and beam type into a glyph.  Each beam
1189.  * type has four glyphs, one for each of the symbols below.  The order of
1190.  * the zap symbols [0-3] as defined in rm.h are:
1191.  *
1192.  *	|  S_vbeam	( 0, 1) or ( 0,-1)
1193.  *	-  S_hbeam	( 1, 0) or (-1,	0)
1194.  *	\  S_lslant	( 1, 1) or (-1,-1)
1195.  *	/  S_rslant	(-1, 1) or ( 1,-1)
1196.  */
1197. int
1198. zapdir_to_glyph(dx, dy, beam_type)
1199.     register int dx, dy;
1200.     int beam_type;
1201. {
1202.     if (beam_type >= NUM_ZAP) {
1203. 	impossible("zapdir_to_glyph:  illegal beam type");
1204. 	beam_type = 0;
1205.     }
1206.     dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0;
1207. 
1208.     return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF;
1209. }
1210. 
1211. 
1212. /*
1213.  * Utility routine for dowhatis() used to find out the glyph displayed at
1214.  * the location.  This isn't necessarily the same as the glyph in the levl
1215.  * structure, so we must check the "third screen".
1216.  */
1217. int
1218. glyph_at(x, y)
1219.     xchar x,y;
1220. {
1221.     if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
1222. 	return cmap_to_glyph(S_room);			/* XXX */
1223.     return gbuf[y][x].glyph;
1224. }
1225. 
1226. /*display.c*/

Also on Fandom

Random Wiki