Wikia

Wikihack

Source:Display.c

2,032pages on
this wiki
Talk0

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

Top of file Edit

1.    /*	SCCS Id: @(#)display.c	3.4	2003/02/19	*/
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.    
The NetHack General Public License applies to screenshots, source code and other content from NetHack.

The New Display Code Edit

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 (or sensed) 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.    * map_invisible
59.    * unmap_object
60.    *
61.    * If you absolutely must override the in-sight/out-of-sight rules, there
62.    * are two possibilities.  First, you can mess with vision to force the
63.    * location in sight then use newsym(), or you can  use the map_* routines.
64.    * The first has not been tried [no need] and the second is used in the
65.    * detect routines --- detect object, magic mapping, etc.  The map_*
66.    * routines *change* what the hero remembers.  All changes made by these
67.    * routines will be sticky --- they will survive screen redraws.  Do *not*
68.    * use these for things that only temporarily change the screen.  These
69.    * routines are also used directly by newsym().  unmap_object is used to
70.    * clear a remembered object when/if detection reveals it isn't there.
71.    *
72.    *
73.    * show_glyph
74.    *
75.    * This is direct (no processing in between) buffered access to the screen.
76.    * Temporary screen effects are run through this and its companion,
77.    * flush_screen().  There is yet a lower level routine, print_glyph(),
78.    * but this is unbuffered and graphic dependent (i.e. it must be surrounded
79.    * by graphic set-up and tear-down routines).  Do not use print_glyph().
80.    *
81.    *
82.    * see_monsters
83.    * see_objects
84.    * see_traps
85.    *
86.    * These are only used when something affects all of the monsters or
87.    * objects or traps.  For objects and traps, the only thing is hallucination.
88.    * For monsters, there are hallucination and changing from/to blindness, etc.
89.    *
90.    *
91.    * tmp_at
92.    *
93.    * This is a useful interface for displaying temporary items on the screen.
94.    * Its interface is different than previously, so look at it carefully.
95.    *
96.    *
97.    *
98.    * Parts of the rm structure that are used:
99.    *
100.   *	typ	- What is really there.
101.   *	glyph	- What the hero remembers.  This will never be a monster.
102.   *		  Monsters "float" above this.
103.   *	lit	- True if the position is lit.  An optimization for
104.   *		  lit/unlit rooms.
105.   *	waslit	- True if the position was *remembered* as lit.
106.   *	seenv	- A vector of bits representing the directions from which the
107.   *		  hero has seen this position.  The vector's primary use is
108.   *		  determining how walls are seen.  E.g. a wall sometimes looks
109.   *		  like stone on one side, but is seen as a wall from the other.
110.   *		  Other uses are for unmapping detected objects and felt
111.   *		  locations, where we need to know if the hero has ever
112.   *		  seen the location.
113.   *	flags   - Additional information for the typ field.  Different for
114.   *		  each typ.
115.   *	horizontal - Indicates whether the wall or door is horizontal or
116.   *		     vertical.
117.   */
118.  #include "hack.h"
119.  #include "region.h"
120.  
121.  STATIC_DCL void FDECL(display_monster,(XCHAR_P,XCHAR_P,struct monst *,int,XCHAR_P));
122.  STATIC_DCL int FDECL(swallow_to_glyph, (int, int));
123.  STATIC_DCL void FDECL(display_warning,(struct monst *));
124.  
125.  STATIC_DCL int FDECL(check_pos, (int, int, int));
126.  #ifdef WA_VERBOSE
127.  STATIC_DCL boolean FDECL(more_than_one, (int, int, int, int, int));
128.  #endif
129.  STATIC_DCL int FDECL(set_twall, (int,int, int,int, int,int, int,int));
130.  STATIC_DCL int FDECL(set_wall, (int, int, int));
131.  STATIC_DCL int FDECL(set_corn, (int,int, int,int, int,int, int,int));
132.  STATIC_DCL int FDECL(set_crosswall, (int, int));
133.  STATIC_DCL void FDECL(set_seenv, (struct rm *, int, int, int, int));
134.  STATIC_DCL void FDECL(t_warn, (struct rm *));
135.  STATIC_DCL int FDECL(wall_angle, (struct rm *));
136.  

vobj_at Edit

137.  #ifdef INVISIBLE_OBJECTS
138.  /*
139.   * vobj_at()
140.   *
141.   * Returns a pointer to an object if the hero can see an object at the
142.   * given location.  This takes care of invisible objects.  NOTE, this
143.   * assumes that the hero is not blind and on top of the object pile.
144.   * It does NOT take into account that the location is out of sight, or,
145.   * say, one can see blessed, etc.
146.   */
147.  struct obj *
148.  vobj_at(x,y)
149.      xchar x,y;
150.  {
151.      register struct obj *obj = level.objects[x][y];
152.  
153.      while (obj) {
154.  	if (!obj->oinvis || See_invisible) return obj;
155.  	obj = obj->nexthere;
156.      }
157.      return ((struct obj *) 0);
158.  }
159.  #endif	/* else vobj_at() is defined in display.h */
160.  

magic_map_background Edit

161.  /*
162.   * magic_map_background()
163.   *
164.   * This function is similar to map_background (see below) except we pay
165.   * attention to and correct unexplored, lit ROOM and CORR spots.
166.   */
167.  void
168.  magic_map_background(x, y, show)
169.      xchar x,y;
170.      int  show;
171.  {
172.      int glyph = back_to_glyph(x,y);	/* assumes hero can see x,y */
173.      struct rm *lev = &levl[x][y];
174.  
175.      /*
176.       * Correct for out of sight lit corridors and rooms that the hero
177.       * doesn't remember as lit.
178.       */
179.      if (!cansee(x,y) && !lev->waslit) {
180.  	/* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
181.  	if (lev->typ == ROOM && glyph == cmap_to_glyph(S_room))
182.  	    glyph = cmap_to_glyph(S_stone);
183.  	else if (lev->typ == CORR && glyph == cmap_to_glyph(S_litcorr))
184.  	    glyph = cmap_to_glyph(S_corr);
185.      }
186.      if (level.flags.hero_memory)
187.  	lev->glyph = glyph;
188.      if (show) show_glyph(x,y, glyph);
189.  }
190.  

map_background Edit

191.  /*
192.   * The routines map_background(), map_object(), and map_trap() could just
193.   * as easily be:
194.   *
195.   *	map_glyph(x,y,glyph,show)
196.   *
197.   * Which is called with the xx_to_glyph() in the call.  Then I can get
198.   * rid of 3 routines that don't do very much anyway.  And then stop
199.   * having to create fake objects and traps.  However, I am reluctant to
200.   * make this change.
201.   */
202.  /* FIXME: some of these use xchars for x and y, and some use ints.  Make
203.   * this consistent.
204.   */
205.  
206.  /*
207.   * map_background()
208.   *
209.   * Make the real background part of our map.  This routine assumes that
210.   * the hero can physically see the location.  Update the screen if directed.
211.   */
212.  void
213.  map_background(x, y, show)
214.      register xchar x,y;
215.      register int  show;
216.  {
217.      register int glyph = back_to_glyph(x,y);
218.  
219.      if (level.flags.hero_memory)
220.  	levl[x][y].glyph = glyph;
221.      if (show) show_glyph(x,y, glyph);
222.  }
223.  

map_trap Edit

224.  /*
225.   * map_trap()
226.   *
227.   * Map the trap and print it out if directed.  This routine assumes that the
228.   * hero can physically see the location.
229.   */
230.  void
231.  map_trap(trap, show)
232.      register struct trap *trap;
233.      register int	 show;
234.  {
235.      register int x = trap->tx, y = trap->ty;
236.      register int glyph = trap_to_glyph(trap);
237.  
238.      if (level.flags.hero_memory)
239.  	levl[x][y].glyph = glyph;
240.      if (show) show_glyph(x, y, glyph);
241.  }
242.  

map_object Edit

243.  /*
244.   * map_object()
245.   *
246.   * Map the given object.  This routine assumes that the hero can physically
247.   * see the location of the object.  Update the screen if directed.
248.   */
249.  void
250.  map_object(obj, show)
251.      register struct obj *obj;
252.      register int	show;
253.  {
254.      register int x = obj->ox, y = obj->oy;
255.      register int glyph = obj_to_glyph(obj);
256.  
257.      if (level.flags.hero_memory)
258.  	levl[x][y].glyph = glyph;
259.      if (show) show_glyph(x, y, glyph);
260.  }
261.  

map_invisible Edit

262.  /*
263.   * map_invisible()
264.   *
265.   * Make the hero remember that a square contains an invisible monster.
266.   * This is a special case in that the square will continue to be displayed
267.   * this way even when the hero is close enough to see it.  To get rid of
268.   * this and display the square's actual contents, use unmap_object() followed
269.   * by newsym() if necessary.
270.   */
271.  void
272.  map_invisible(x, y)
273.  register xchar x, y;
274.  {
275.      if (x != u.ux || y != u.uy) { /* don't display I at hero's location */
276.  	if (level.flags.hero_memory)
277.  	    levl[x][y].glyph = GLYPH_INVISIBLE;
278.  	show_glyph(x, y, GLYPH_INVISIBLE);
279.      }
280.  }
281.  

unmap_object Edit

282.  /*
283.   * unmap_object()
284.   *
285.   * Remove something from the map when the hero realizes it's not there any
286.   * more.  Replace it with background or known trap, but not with any other
287.   * If this is used for detection, a full screen update is imminent anyway;
288.   * if this is used to get rid of an invisible monster notation, we might have
289.   * to call newsym().
290.   */
291.  void
292.  unmap_object(x, y)
293.      register int x, y;
294.  {
295.      register struct trap *trap;
296.  
297.      if (!level.flags.hero_memory) return;
298.  
299.      if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y))
300.  	map_trap(trap, 0);
301.      else if (levl[x][y].seenv) {
302.  	struct rm *lev = &levl[x][y];
303.  
304.  	map_background(x, y, 0);
305.  
306.  	/* turn remembered dark room squares dark */
307.  	if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) &&
308.  							    lev->typ == ROOM)
309.  	    lev->glyph = cmap_to_glyph(S_stone);
310.      } else
311.  	levl[x][y].glyph = cmap_to_glyph(S_stone);	/* default val */
312.  }
313.  
314.  

map_location Edit

315.  /*
316.   * map_location()
317.   *
318.   * Make whatever at this location show up.  This is only for non-living
319.   * things.  This will not handle feeling invisible objects correctly.
320.   *
321.   * Internal to display.c, this is a #define for speed.
322.   */
323.  #define _map_location(x,y,show)						\
324.  {									\
325.      register struct obj   *obj;						\
326.      register struct trap  *trap;					\
327.  									\
328.      if ((obj = vobj_at(x,y)) && !covers_objects(x,y))			\
329.  	map_object(obj,show);						\
330.      else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y))	\
331.  	map_trap(trap,show);						\
332.      else								\
333.  	map_background(x,y,show);					\
334.  }
335.  
336.  void
337.  map_location(x,y,show)
338.      int x, y, show;
339.  {
340.      _map_location(x,y,show);
341.  }
342.  
343.  #define DETECTED 	2
344.  #define PHYSICALLY_SEEN 1
345.  #define is_worm_tail(mon)	((mon) && ((x != (mon)->mx)  || (y != (mon)->my)))
346.  

display_monster Edit

347.  /*
348.   * display_monster()
349.   *
350.   * Note that this is *not* a map_XXXX() function!  Monsters sort of float
351.   * above everything.
352.   *
353.   * Yuck.  Display body parts by recognizing that the display position is
354.   * not the same as the monster position.  Currently the only body part is
355.   * a worm tail.
356.   *
357.   */
358.  STATIC_OVL void
359.  display_monster(x, y, mon, sightflags, worm_tail)
360.      register xchar x, y;	/* display position */
361.      register struct monst *mon;	/* monster to display */
362.      int sightflags;		/* 1 if the monster is physically seen */
363.      				/* 2 if detected using Detect_monsters */
364.      register xchar worm_tail;	/* mon is actually a worm tail */
365.  {
366.      register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING);
367.      register int sensed = mon_mimic &&
368.  	(Protection_from_shape_changers || sensemon(mon));
369.      /*
370.       * We must do the mimic check first.  If the mimic is mimicing something,
371.       * and the location is in sight, we have to change the hero's memory
372.       * so that when the position is out of sight, the hero remembers what
373.       * the mimic was mimicing.
374.       */
375.  
376.      if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) {
377.  	switch (mon->m_ap_type) {
378.  	    default:
379.  		impossible("display_monster:  bad m_ap_type value [ = %d ]",
380.  							(int) mon->m_ap_type);
381.  	    case M_AP_NOTHING:
382.  		show_glyph(x, y, mon_to_glyph(mon));
383.  		break;
384.  
385.  	    case M_AP_FURNITURE: {
386.  		/*
387.  		 * This is a poor man's version of map_background().  I can't
388.  		 * use map_background() because we are overriding what is in
389.  		 * the 'typ' field.  Maybe have map_background()'s parameters
390.  		 * be (x,y,glyph) instead of just (x,y).
391.  		 *
392.  		 * mappearance is currently set to an S_ index value in
393.  		 * makemon.c.
394.  		 */
395.  		register int glyph = cmap_to_glyph(mon->mappearance);
396.  		levl[x][y].glyph = glyph;
397.  		if (!sensed) show_glyph(x,y, glyph);
398.  		break;
399.  	    }
400.  
401.  	    case M_AP_OBJECT: {
402.  		struct obj obj;	/* Make a fake object to send	*/
403.  				/* to map_object().		*/
404.  		obj.ox = x;
405.  		obj.oy = y;
406.  		obj.otyp = mon->mappearance;
407.  		obj.corpsenm = PM_TENGU;	/* if mimicing a corpse */
408.  		map_object(&obj,!sensed);
409.  		break;
410.  	    }
411.  
412.  	    case M_AP_MONSTER:
413.  		show_glyph(x,y, monnum_to_glyph(what_mon((int)mon->mappearance)));
414.  		break;
415.  	}
416.  	
417.      }
418.  
419.      /* If the mimic is unsucessfully mimicing something, display the monster */
420.      if (!mon_mimic || sensed) {
421.  	int num;
422.  
423.  	/* [ALI] Only use detected glyphs when monster wouldn't be
424.  	 * visible by any other means.
425.  	 */
426.  	if (sightflags == DETECTED) {
427.  	    if (worm_tail)
428.  		num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
429.  	    else
430.  		num = detected_mon_to_glyph(mon);
431.  	} else if (mon->mtame && !Hallucination) {
432.  	    if (worm_tail)
433.  		num = petnum_to_glyph(PM_LONG_WORM_TAIL);
434.  	    else
435.  		num = pet_to_glyph(mon);
436.  	} else {
437.  	    if (worm_tail)
438.  		num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
439.  	    else
440.  		num = mon_to_glyph(mon);
441.  	}
442.  	show_glyph(x,y,num);
443.      }
444.  }
445.  

display_warning Edit

446.  /*
447.   * display_warning()
448.   *
449.   * This is also *not* a map_XXXX() function!  Monster warnings float
450.   * above everything just like monsters do, but only if the monster
451.   * is not showing.
452.   *
453.   * Do not call for worm tails.
454.   */
455.  STATIC_OVL void
456.  display_warning(mon)
457.      register struct monst *mon;
458.  {
459.      int x = mon->mx, y = mon->my;
460.      int wl = (int) (mon->m_lev / 4);
461.      int glyph;
462.  
463.      if (mon_warning(mon)) {
464.          if (wl > WARNCOUNT - 1) wl = WARNCOUNT - 1;
465.  	/* 3.4.1: this really ought to be rn2(WARNCOUNT), but value "0"
466.  	   isn't handled correctly by the what_is routine so avoid it */
467.  	if (Hallucination) wl = rn1(WARNCOUNT-1,1);
468.          glyph = warning_to_glyph(wl);
469.      } else if (MATCH_WARN_OF_MON(mon)) {
470.  	glyph = mon_to_glyph(mon);
471.      } else {
472.      	impossible("display_warning did not match warning type?");
473.          return;
474.      }
475.      show_glyph(x, y, glyph);
476.  }
477.  

feel_location Edit

478.  /*
479.   * feel_location()
480.   *
481.   * Feel the given location.  This assumes that the hero is blind and that
482.   * the given position is either the hero's or one of the eight squares
483.   * adjacent to the hero (except for a boulder push).
484.   * If an invisible monster has gone away, that will be discovered.  If an
485.   * invisible monster has appeared, this will _not_ be discovered since
486.   * searching only finds one monster per turn so we must check that separately.
487.   */
488.  void
489.  feel_location(x, y)
490.      xchar x, y;
491.  {
492.      struct rm *lev = &(levl[x][y]);
493.      struct obj *boulder;
494.      register struct monst *mon;
495.  
496.      /* If the hero's memory of an invisible monster is accurate, we want to keep
497.       * him from detecting the same monster over and over again on each turn.
498.       * We must return (so we don't erase the monster).  (We must also, in the
499.       * search function, be sure to skip over previously detected 'I's.)
500.       */
501.      if (glyph_is_invisible(levl[x][y].glyph) && m_at(x,y)) return;
502.  
503.      /* The hero can't feel non pool locations while under water. */
504.      if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y))
505.  	return;
506.  
507.      /* Set the seen vector as if the hero had seen it.  It doesn't matter */
508.      /* if the hero is levitating or not.				  */
509.      set_seenv(lev, u.ux, u.uy, x, y);
510.  
511.      if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
512.  	/*
513.  	 * Levitation Rules.  It is assumed that the hero can feel the state
514.  	 * of the walls around herself and can tell if she is in a corridor,
515.  	 * room, or doorway.  Boulders are felt because they are large enough.
516.  	 * Anything else is unknown because the hero can't reach the ground.
517.  	 * This makes things difficult.
518.  	 *
519.  	 * Check (and display) in order:
520.  	 *
521.  	 *	+ Stone, walls, and closed doors.
522.  	 *	+ Boulders.  [see a boulder before a doorway]
523.  	 *	+ Doors.
524.  	 *	+ Room/water positions
525.  	 *	+ Everything else (hallways!)
526.  	 */
527.  	if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) &&
528.  				(lev->doormask & (D_LOCKED | D_CLOSED)))) {
529.  	    map_background(x, y, 1);
530.  	} else if ((boulder = sobj_at(BOULDER,x,y)) != 0) {
531.  	    map_object(boulder, 1);
532.  	} else if (IS_DOOR(lev->typ)) {
533.  	    map_background(x, y, 1);
534.  	} else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) {
535.  	    /*
536.  	     * An open room or water location.  Normally we wouldn't touch
537.  	     * this, but we have to get rid of remembered boulder symbols.
538.  	     * This will only occur in rare occations when the hero goes
539.  	     * blind and doesn't find a boulder where expected (something
540.  	     * came along and picked it up).  We know that there is not a
541.  	     * boulder at this location.  Show fountains, pools, etc.
542.  	     * underneath if already seen.  Otherwise, show the appropriate
543.  	     * floor symbol.
544.  	     *
545.  	     * Similarly, if the hero digs a hole in a wall or feels a location
546.  	     * that used to contain an unseen monster.  In these cases,
547.  	     * there's no reason to assume anything was underneath, so
548.  	     * just show the appropriate floor symbol.  If something was
549.  	     * embedded in the wall, the glyph will probably already
550.  	     * reflect that.  Don't change the symbol in this case.
551.  	     *
552.  	     * This isn't quite correct.  If the boulder was on top of some
553.  	     * other objects they should be seen once the boulder is removed.
554.  	     * However, we have no way of knowing that what is there now
555.  	     * was there then.  So we let the hero have a lapse of memory.
556.  	     * We could also just display what is currently on the top of the
557.  	     * object stack (if anything).
558.  	     */
559.  	    if (lev->glyph == objnum_to_glyph(BOULDER)) {
560.  		if (lev->typ != ROOM && lev->seenv) {
561.  		    map_background(x, y, 1);
562.  		} else {
563.  		    lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
564.  					       cmap_to_glyph(S_stone);
565.  		    show_glyph(x,y,lev->glyph);
566.  		}
567.  	    } else if ((lev->glyph >= cmap_to_glyph(S_stone) &&
568.  			lev->glyph < cmap_to_glyph(S_room)) ||
569.  		       glyph_is_invisible(levl[x][y].glyph)) {
570.  		lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
571.  					   cmap_to_glyph(S_stone);
572.  		show_glyph(x,y,lev->glyph);
573.  	    }
574.  	} else {
575.  	    /* We feel it (I think hallways are the only things left). */
576.  	    map_background(x, y, 1);
577.  	    /* Corridors are never felt as lit (unless remembered that way) */
578.  	    /* (lit_corridor only).					    */
579.  	    if (lev->typ == CORR &&
580.  		    lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
581.  		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
582.  	}
583.      } else {
584.  	_map_location(x, y, 1);
585.  
586.  	if (Punished) {
587.  	    /*
588.  	     * A ball or chain is only felt if it is first on the object
589.  	     * location list.  Otherwise, we need to clear the felt bit ---
590.  	     * something has been dropped on the ball/chain.  If the bit is
591.  	     * not cleared, then when the ball/chain is moved it will drop
592.  	     * the wrong glyph.
593.  	     */
594.  	    if (uchain->ox == x && uchain->oy == y) {
595.  		if (level.objects[x][y] == uchain)
596.  		    u.bc_felt |= BC_CHAIN;
597.  		else
598.  		    u.bc_felt &= ~BC_CHAIN;	/* do not feel the chain */
599.  	    }
600.  	    if (!carried(uball) && uball->ox == x && uball->oy == y) {
601.  		if (level.objects[x][y] == uball)
602.  		    u.bc_felt |= BC_BALL;
603.  		else
604.  		    u.bc_felt &= ~BC_BALL;	/* do not feel the ball */
605.  	    }
606.  	}
607.  
608.  	/* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
609.  	if (lev->typ == ROOM &&
610.  		    lev->glyph == cmap_to_glyph(S_room) && !lev->waslit)
611.  	    show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone));
612.  	else if (lev->typ == CORR &&
613.  		    lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
614.  	    show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr));
615.      }
616.      /* draw monster on top if we can sense it */
617.      if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon))
618.  	display_monster(x, y, mon,
619.  		(tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)) ? PHYSICALLY_SEEN : DETECTED,
620.  		is_worm_tail(mon));
621.  }
622.  

newsym Edit

623.  /*
624.   * newsym()
625.   *
626.   * Possibly put a new glyph at the given location.
627.   */
628.  void
629.  newsym(x,y)
630.      register int x,y;
631.  {
632.      register struct monst *mon;
633.      register struct rm *lev = &(levl[x][y]);
634.      register int see_it;
635.      register xchar worm_tail;
636.  
637.      if (in_mklev) return;
638.  
639.      /* only permit updating the hero when swallowed */
640.      if (u.uswallow) {
641.  	if (x == u.ux && y == u.uy) display_self();
642.  	return;
643.      }
644.      if (Underwater && !Is_waterlevel(&u.uz)) {
645.  	/* don't do anything unless (x,y) is an adjacent underwater position */
646.  	int dx, dy;
647.  	if (!is_pool(x,y)) return;
648.  	dx = x - u.ux;	if (dx < 0) dx = -dx;
649.  	dy = y - u.uy;	if (dy < 0) dy = -dy;
650.  	if (dx > 1 || dy > 1) return;
651.      }
652.  
653.      /* Can physically see the location. */
654.      if (cansee(x,y)) {
655.          NhRegion* reg = visible_region_at(x,y);
656.  	/*
657.  	 * Don't use templit here:  E.g.
658.  	 *
659.  	 *	lev->waslit = !!(lev->lit || templit(x,y));
660.  	 *
661.  	 * Otherwise we have the "light pool" problem, where non-permanently
662.  	 * lit areas just out of sight stay remembered as lit.  They should
663.  	 * re-darken.
664.  	 *
665.  	 * Perhaps ALL areas should revert to their "unlit" look when
666.  	 * out of sight.
667.  	 */
668.  	lev->waslit = (lev->lit!=0);	/* remember lit condition */
669.  
670.  	if (reg != NULL && ACCESSIBLE(lev->typ)) {
671.  	    show_region(reg,x,y);
672.  	    return;
673.  	}
674.  	if (x == u.ux && y == u.uy) {
675.  	    if (senseself()) {
676.  		_map_location(x,y,0);	/* map *under* self */
677.  		display_self();
678.  	    } else
679.  		/* we can see what is there */
680.  		_map_location(x,y,1);
681.  	}
682.  	else {
683.  	    mon = m_at(x,y);
684.  	    worm_tail = is_worm_tail(mon);
685.  	    see_it = mon && (worm_tail
686.  		? (!mon->minvis || See_invisible)
687.  		: (mon_visible(mon)) || tp_sensemon(mon) || MATCH_WARN_OF_MON(mon));
688.  	    if (mon && (see_it || (!worm_tail && Detect_monsters))) {
689.  		if (mon->mtrapped) {
690.  		    struct trap *trap = t_at(x, y);
691.  		    int tt = trap ? trap->ttyp : NO_TRAP;
692.  
693.  		    /* if monster is in a physical trap, you see the trap too */
694.  		    if (tt == BEAR_TRAP || tt == PIT ||
695.  			tt == SPIKED_PIT ||tt == WEB) {
696.  			trap->tseen = TRUE;
697.  		    }
698.  		}
699.  		_map_location(x,y,0);	/* map under the monster */
700.  		/* also gets rid of any invisibility glyph */
701.  		display_monster(x, y, mon, see_it ? PHYSICALLY_SEEN : DETECTED, worm_tail);
702.  	    }
703.  	    else if (mon && mon_warning(mon) && !is_worm_tail(mon))
704.  	        display_warning(mon);
705.  	    else if (glyph_is_invisible(levl[x][y].glyph))
706.  		map_invisible(x, y);
707.  	    else
708.  		_map_location(x,y,1);	/* map the location */
709.  	}
710.      }
711.  
712.      /* Can't see the location. */
713.      else {
714.  	if (x == u.ux && y == u.uy) {
715.  	    feel_location(u.ux, u.uy);		/* forces an update */
716.  
717.  	    if (senseself()) display_self();
718.  	}
719.  	else if ((mon = m_at(x,y))
720.  		&& ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)
721.  		    		|| (see_with_infrared(mon) && mon_visible(mon))))
722.  		    || Detect_monsters)
723.  		&& !is_worm_tail(mon)) {
724.  	    /* Monsters are printed every time. */
725.  	    /* This also gets rid of any invisibility glyph */
726.  	    display_monster(x, y, mon, see_it ? 0 : DETECTED, 0);
727.  	}
728.  	else if ((mon = m_at(x,y)) && mon_warning(mon) &&
729.  		 !is_worm_tail(mon)) {
730.  	        display_warning(mon);
731.  	}		
732.  
733.  	/*
734.  	 * If the location is remembered as being both dark (waslit is false)
735.  	 * and lit (glyph is a lit room or lit corridor) then it was either:
736.  	 *
737.  	 *	(1) A dark location that the hero could see through night
738.  	 *	    vision.
739.  	 *
740.  	 *	(2) Darkened while out of the hero's sight.  This can happen
741.  	 *	    when cursed scroll of light is read.
742.  	 *
743.  	 * In either case, we have to manually correct the hero's memory to
744.  	 * match waslit.  Deciding when to change waslit is non-trivial.
745.  	 *
746.  	 *  Note:  If flags.lit_corridor is set, then corridors act like room
747.  	 *	   squares.  That is, they light up if in night vision range.
748.  	 *	   If flags.lit_corridor is not set, then corridors will
749.  	 *	   remain dark unless lit by a light spell and may darken
750.  	 *	   again, as discussed above.
751.  	 *
752.  	 * These checks and changes must be here and not in back_to_glyph().
753.  	 * They are dependent on the position being out of sight.
754.  	 */
755.  	else if (!lev->waslit) {
756.  	    if (lev->glyph == cmap_to_glyph(S_litcorr) && lev->typ == CORR)
757.  		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
758.  	    else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM)
759.  		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone));
760.  	    else
761.  		goto show_mem;
762.  	} else {
763.  show_mem:
764.  	    show_glyph(x, y, lev->glyph);
765.  	}
766.      }
767.  }
768.  
769.  #undef is_worm_tail
770.  

shieldeff Edit

771.  /*
772.   * shieldeff()
773.   *
774.   * Put magic shield pyrotechnics at the given location.  This *could* be
775.   * pulled into a platform dependent routine for fancier graphics if desired.
776.   */
777.  void
778.  shieldeff(x,y)
779.      xchar x,y;
780.  {
781.      register int i;
782.  
783.      if (!flags.sparkle) return;
784.      if (cansee(x,y)) {	/* Don't see anything if can't see the location */
785.  	for (i = 0; i < SHIELD_COUNT; i++) {
786.  	    show_glyph(x, y, cmap_to_glyph(shield_static[i]));
787.  	    flush_screen(1);	/* make sure the glyph shows up */
788.  	    delay_output();
789.  	}
790.  	newsym(x,y);		/* restore the old information */
791.      }
792.  }
793.  
794.  

tmp_at Edit

795.  /*
796.   * tmp_at()
797.   *
798.   * Temporarily place glyphs on the screen.  Do not call delay_output().  It
799.   * is up to the caller to decide if it wants to wait [presently, everyone
800.   * but explode() wants to delay].
801.   *
802.   * Call:
803.   *	(DISP_BEAM,   glyph)	open, initialize glyph
804.   *	(DISP_FLASH,  glyph)	open, initialize glyph
805.   *	(DISP_ALWAYS, glyph)	open, initialize glyph
806.   *	(DISP_CHANGE, glyph)	change glyph
807.   *	(DISP_END,    0)	close & clean up (second argument doesn't
808.   *				matter)
809.   *	(DISP_FREEMEM, 0)	only used to prevent memory leak during
810.   *				exit)
811.   *	(x, y)			display the glyph at the location
812.   *
813.   * DISP_BEAM  - Display the given glyph at each location, but do not erase
814.   *		any until the close call.
815.   * DISP_FLASH - Display the given glyph at each location, but erase the
816.   *		previous location's glyph.
817.   * DISP_ALWAYS- Like DISP_FLASH, but vision is not taken into account.
818.   */
819.  
820.  static struct tmp_glyph {
821.      coord saved[COLNO];	/* previously updated positions */
822.      int sidx;		/* index of next unused slot in saved[] */
823.      int style;		/* either DISP_BEAM or DISP_FLASH or DISP_ALWAYS */
824.      int glyph;		/* glyph to use when printing */
825.      struct tmp_glyph *prev;
826.  } tgfirst;
827.  
828.  void
829.  tmp_at(x, y)
830.      int x, y;
831.  {
832.      static struct tmp_glyph *tglyph = (struct tmp_glyph *)0;
833.      struct tmp_glyph *tmp;
834.  
835.      switch (x) {
836.  	case DISP_BEAM:
837.  	case DISP_FLASH:
838.  	case DISP_ALWAYS:
839.  	    if (!tglyph)
840.  		tmp = &tgfirst;
841.  	    else	/* nested effect; we need dynamic memory */
842.  		tmp = (struct tmp_glyph *)alloc(sizeof (struct tmp_glyph));
843.  	    tmp->prev = tglyph;
844.  	    tglyph = tmp;
845.  	    tglyph->sidx = 0;
846.  	    tglyph->style = x;
847.  	    tglyph->glyph = y;
848.  	    flush_screen(0);	/* flush buffered glyphs */
849.  	    return;
850.  
851.  	case DISP_FREEMEM:  /* in case game ends with tmp_at() in progress */
852.  	    while (tglyph) {
853.  		tmp = tglyph->prev;
854.  		if (tglyph != &tgfirst) free((genericptr_t)tglyph);
855.  		tglyph = tmp;
856.  	    }
857.  	    return;
858.  
859.  	default:
860.  	    break;
861.      }
862.  
863.      if (!tglyph) panic("tmp_at: tglyph not initialized");
864.  
865.      switch (x) {
866.  	case DISP_CHANGE:
867.  	    tglyph->glyph = y;
868.  	    break;
869.  
870.  	case DISP_END:
871.  	    if (tglyph->style == DISP_BEAM) {
872.  		register int i;
873.  
874.  		/* Erase (reset) from source to end */
875.  		for (i = 0; i < tglyph->sidx; i++)
876.  		    newsym(tglyph->saved[i].x, tglyph->saved[i].y);
877.  	    } else {		/* DISP_FLASH or DISP_ALWAYS */
878.  		if (tglyph->sidx)	/* been called at least once */
879.  		    newsym(tglyph->saved[0].x, tglyph->saved[0].y);
880.  	    }
881.  	 /* tglyph->sidx = 0; -- about to be freed, so not necessary */
882.  	    tmp = tglyph->prev;
883.  	    if (tglyph != &tgfirst) free((genericptr_t)tglyph);
884.  	    tglyph = tmp;
885.  	    break;
886.  
887.  	default:	/* do it */
888.  	    if (tglyph->style == DISP_BEAM) {
889.  		if (!cansee(x,y)) break;
890.  		/* save pos for later erasing */
891.  		tglyph->saved[tglyph->sidx].x = x;
892.  		tglyph->saved[tglyph->sidx].y = y;
893.  		tglyph->sidx += 1;
894.  	    } else {	/* DISP_FLASH/ALWAYS */
895.  		if (tglyph->sidx) { /* not first call, so reset previous pos */
896.  		    newsym(tglyph->saved[0].x, tglyph->saved[0].y);
897.  		    tglyph->sidx = 0;	/* display is presently up to date */
898.  		}
899.  		if (!cansee(x,y) && tglyph->style != DISP_ALWAYS) break;
900.  		tglyph->saved[0].x = x;
901.  		tglyph->saved[0].y = y;
902.  		tglyph->sidx = 1;
903.  	    }
904.  
905.  	    show_glyph(x, y, tglyph->glyph);	/* show it */
906.  	    flush_screen(0);			/* make sure it shows up */
907.  	    break;
908.      } /* end case */
909.  }
910.  
911.  

swallowed Edit

912.  /*
913.   * swallowed()
914.   *
915.   * The hero is swallowed.  Show a special graphics sequence for this.  This
916.   * bypasses all of the display routines and messes with buffered screen
917.   * directly.  This method works because both vision and display check for
918.   * being swallowed.
919.   */
920.  void
921.  swallowed(first)
922.      int first;
923.  {
924.      static xchar lastx, lasty;	/* last swallowed position */
925.      int swallower, left_ok, rght_ok;
926.  
927.      if (first)
928.  	cls();
929.      else {
930.  	register int x, y;
931.  
932.  	/* Clear old location */
933.  	for (y = lasty-1; y <= lasty+1; y++)
934.  	    for (x = lastx-1; x <= lastx+1; x++)
935.  		if (isok(x,y)) show_glyph(x,y,cmap_to_glyph(S_stone));
936.      }
937.  
938.      swallower = monsndx(u.ustuck->data);
939.      /* assume isok(u.ux,u.uy) */
940.      left_ok = isok(u.ux-1,u.uy);
941.      rght_ok = isok(u.ux+1,u.uy);
942.      /*
943.       *  Display the hero surrounded by the monster's stomach.
944.       */
945.      if(isok(u.ux, u.uy-1)) {
946.  	if (left_ok)
947.  	show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl));
948.  	show_glyph(u.ux  , u.uy-1, swallow_to_glyph(swallower, S_sw_tc));
949.  	if (rght_ok)
950.  	show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr));
951.      }
952.  
953.      if (left_ok)
954.      show_glyph(u.ux-1, u.uy  , swallow_to_glyph(swallower, S_sw_ml));
955.      display_self();
956.      if (rght_ok)
957.      show_glyph(u.ux+1, u.uy  , swallow_to_glyph(swallower, S_sw_mr));
958.  
959.      if(isok(u.ux, u.uy+1)) {
960.  	if (left_ok)
961.  	show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl));
962.  	show_glyph(u.ux  , u.uy+1, swallow_to_glyph(swallower, S_sw_bc));
963.  	if (rght_ok)
964.  	show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br));
965.      }
966.  
967.      /* Update the swallowed position. */
968.      lastx = u.ux;
969.      lasty = u.uy;
970.  }
971.  

under_water Edit

972.  /*
973.   * under_water()
974.   *
975.   * Similar to swallowed() in operation.  Shows hero when underwater
976.   * except when in water level.  Special routines exist for that.
977.   */
978.  void
979.  under_water(mode)
980.      int mode;
981.  {
982.      static xchar lastx, lasty;
983.      static boolean dela;
984.      register int x, y;
985.  
986.      /* swallowing has a higher precedence than under water */
987.      if (Is_waterlevel(&u.uz) || u.uswallow) return;
988.  
989.      /* full update */
990.      if (mode == 1 || dela) {
991.  	cls();
992.  	dela = FALSE;
993.      }
994.      /* delayed full update */
995.      else if (mode == 2) {
996.  	dela = TRUE;
997.  	return;
998.      }
999.      /* limited update */
1000.     else {
1001. 	for (y = lasty-1; y <= lasty+1; y++)
1002. 	    for (x = lastx-1; x <= lastx+1; x++)
1003. 		if (isok(x,y))
1004. 		    show_glyph(x,y,cmap_to_glyph(S_stone));
1005.     }
1006.     for (x = u.ux-1; x <= u.ux+1; x++)
1007. 	for (y = u.uy-1; y <= u.uy+1; y++)
1008. 	    if (isok(x,y) && is_pool(x,y)) {
1009. 		if (Blind && !(x == u.ux && y == u.uy))
1010. 		    show_glyph(x,y,cmap_to_glyph(S_stone));
1011. 		else	
1012. 		    newsym(x,y);
1013. 	    }
1014.     lastx = u.ux;
1015.     lasty = u.uy;
1016. }
1017. 

under_ground Edit

1018. /*
1019.  *	under_ground()
1020.  *
1021.  *	Very restricted display.  You can only see yourself.
1022.  */
1023. void
1024. under_ground(mode)
1025.     int mode;
1026. {
1027.     static boolean dela;
1028. 
1029.     /* swallowing has a higher precedence than under ground */
1030.     if (u.uswallow) return;
1031. 
1032.     /* full update */
1033.     if (mode == 1 || dela) {
1034. 	cls();
1035. 	dela = FALSE;
1036.     }
1037.     /* delayed full update */
1038.     else if (mode == 2) {
1039. 	dela = TRUE;
1040. 	return;
1041.     }
1042.     /* limited update */
1043.     else
1044. 	newsym(u.ux,u.uy);
1045. }
1046. 
1047. 
1048. /* ========================================================================= */
1049. 

see_monsters Edit

1050. /*
1051.  * Loop through all of the monsters and update them.  Called when:
1052.  *	+ going blind & telepathic
1053.  *	+ regaining sight & telepathic
1054.  *      + getting and losing infravision 
1055.  *	+ hallucinating
1056.  *	+ doing a full screen redraw
1057.  *	+ see invisible times out or a ring of see invisible is taken off
1058.  *	+ when a potion of see invisible is quaffed or a ring of see
1059.  *	  invisible is put on
1060.  *	+ gaining telepathy when blind [givit() in eat.c, pleased() in pray.c]
1061.  *	+ losing telepathy while blind [xkilled() in mon.c, attrcurse() in
1062.  *	  sit.c]
1063.  */
1064. void
1065. see_monsters()
1066. {
1067.     register struct monst *mon;
1068. 
1069.     for (mon = fmon; mon; mon = mon->nmon) {
1070. 	if (DEADMONSTER(mon)) continue;
1071. 	newsym(mon->mx,mon->my);
1072. 	if (mon->wormno) see_wsegs(mon);
1073.     }
1074. #ifdef STEED
1075.     /* when mounted, hero's location gets caught by monster loop */
1076.     if (!u.usteed)
1077. #endif
1078.     newsym(u.ux, u.uy);
1079. }
1080. 

set_mimic_blocking Edit

1081. /*
1082.  * Block/unblock light depending on what a mimic is mimicing and if it's
1083.  * invisible or not.  Should be called only when the state of See_invisible
1084.  * changes.
1085.  */
1086. void
1087. set_mimic_blocking()
1088. {
1089.     register struct monst *mon;
1090. 
1091.     for (mon = fmon; mon; mon = mon->nmon) {
1092. 	if (DEADMONSTER(mon)) continue;
1093. 	if (mon->minvis &&
1094. 	   ((mon->m_ap_type == M_AP_FURNITURE &&
1095. 	     (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor)) ||
1096. 	    (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) {
1097. 	    if(See_invisible)
1098. 		block_point(mon->mx, mon->my);
1099. 	    else
1100. 		unblock_point(mon->mx, mon->my);
1101. 	}
1102.     }
1103. }
1104. 

see_objects Edit

1105. /*
1106.  * Loop through all of the object *locations* and update them.  Called when
1107.  *	+ hallucinating.
1108.  */
1109. void
1110. see_objects()
1111. {
1112.     register struct obj *obj;
1113.     for(obj = fobj; obj; obj = obj->nobj)
1114. 	if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy);
1115. }
1116. 

see_traps Edit

1117. /*
1118.  * Update hallucinated traps.
1119.  */
1120. void
1121. see_traps()
1122. {
1123.     struct trap *trap;
1124.     int glyph;
1125. 
1126.     for (trap = ftrap; trap; trap = trap->ntrap) {
1127. 	glyph = glyph_at(trap->tx, trap->ty);
1128. 	if (glyph_is_trap(glyph))
1129. 	    newsym(trap->tx, trap->ty);
1130.     }
1131. }
1132. 

curs_on_u Edit

1133. /*
1134.  * Put the cursor on the hero.  Flush all accumulated glyphs before doing it.
1135.  */
1136. void
1137. curs_on_u()
1138. {
1139.     flush_screen(1);	/* Flush waiting glyphs & put cursor on hero */
1140. }
1141. 

doredraw Edit

1142. int
1143. doredraw()
1144. {
1145.     docrt();
1146.     return 0;
1147. }
1148. 

docrt Edit

1149. void
1150. docrt()
1151. {
1152.     register int x,y;
1153.     register struct rm *lev;
1154. 
1155.     if (!u.ux) return; /* display isn't ready yet */
1156. 
1157.     if (u.uswallow) {
1158. 	swallowed(1);
1159. 	return;
1160.     }
1161.     if (Underwater && !Is_waterlevel(&u.uz)) {
1162. 	under_water(1);
1163. 	return;
1164.     }
1165.     if (u.uburied) {
1166. 	under_ground(1);
1167. 	return;
1168.     }
1169. 
1170.     /* shut down vision */
1171.     vision_recalc(2);
1172. 
1173.     /*
1174.      * This routine assumes that cls() does the following:
1175.      *      + fills the physical screen with the symbol for rock
1176.      *      + clears the glyph buffer
1177.      */
1178.     cls();
1179. 
1180.     /* display memory */
1181.     for (x = 1; x < COLNO; x++) {
1182. 	lev = &levl[x][0];
1183. 	for (y = 0; y < ROWNO; y++, lev++)
1184. 	    if (lev->glyph != cmap_to_glyph(S_stone))
1185. 		show_glyph(x,y,lev->glyph);
1186.     }
1187. 
1188.     /* see what is to be seen */
1189.     vision_recalc(0);
1190. 
1191.     /* overlay with monsters */
1192.     see_monsters();
1193. 
1194.     flags.botlx = 1;	/* force a redraw of the bottom line */
1195. }
1196. 
1197. 
1198. /* ========================================================================= */

show_glyph Edit

1199. /* Glyph Buffering (3rd screen) ============================================ */
1200. 
1201. typedef struct {
1202.     xchar new;		/* perhaps move this bit into the rm strucure. */
1203.     int   glyph;
1204. } gbuf_entry;
1205. 
1206. static gbuf_entry gbuf[ROWNO][COLNO];
1207. static char gbuf_start[ROWNO];
1208. static char gbuf_stop[ROWNO];
1209. 
1210. /*
1211.  * Store the glyph in the 3rd screen for later flushing.
1212.  */
1213. void
1214. show_glyph(x,y,glyph)
1215.     int x, y, glyph;
1216. {
1217.     /*
1218.      * Check for bad positions and glyphs.
1219.      */
1220.     if (!isok(x, y)) {
1221. 	const char *text;
1222. 	int  offset;
1223. 
1224. 	/* column 0 is invalid, but it's often used as a flag, so ignore it */
1225. 	if (x == 0) return;
1226. 
1227. 	/*
1228. 	 *  This assumes an ordering of the offsets.  See display.h for
1229. 	 *  the definition.
1230. 	 */
1231. 
1232. 	if (glyph >= GLYPH_WARNING_OFF) {	/* a warning */
1233. 	    text = "warning";		offset = glyph - GLYPH_WARNING_OFF;
1234. 	} else if (glyph >= GLYPH_SWALLOW_OFF) {	/* swallow border */
1235. 	    text = "swallow border";	offset = glyph - GLYPH_SWALLOW_OFF;
1236. 	} else if (glyph >= GLYPH_ZAP_OFF) {		/* zap beam */
1237. 	    text = "zap beam";		offset = glyph - GLYPH_ZAP_OFF;
1238. 	} else if (glyph >= GLYPH_EXPLODE_OFF) {	/* explosion */
1239. 	    text = "explosion";		offset = glyph - GLYPH_EXPLODE_OFF;
1240. 	} else if (glyph >= GLYPH_CMAP_OFF) {		/* cmap */
1241. 	    text = "cmap_index";	offset = glyph - GLYPH_CMAP_OFF;
1242. 	} else if (glyph >= GLYPH_OBJ_OFF) {		/* object */
1243. 	    text = "object";		offset = glyph - GLYPH_OBJ_OFF;
1244. 	} else if (glyph >= GLYPH_RIDDEN_OFF) {		/* ridden mon */
1245. 	    text = "ridden mon";	offset = glyph - GLYPH_RIDDEN_OFF;
1246. 	} else if (glyph >= GLYPH_BODY_OFF) {		/* a corpse */
1247. 	    text = "corpse";		offset = glyph - GLYPH_BODY_OFF;
1248. 	} else if (glyph >= GLYPH_DETECT_OFF) {		/* detected mon */
1249. 	    text = "detected mon";	offset = glyph - GLYPH_DETECT_OFF;
1250. 	} else if (glyph >= GLYPH_INVIS_OFF) {		/* invisible mon */
1251. 	    text = "invisible mon";	offset = glyph - GLYPH_INVIS_OFF;
1252. 	} else if (glyph >= GLYPH_PET_OFF) {		/* a pet */
1253. 	    text = "pet";		offset = glyph - GLYPH_PET_OFF;
1254. 	} else {					/* a monster */
1255. 	    text = "monster";		offset = glyph;
1256. 	}
1257. 
1258. 	impossible("show_glyph:  bad pos %d %d with glyph %d [%s %d].",
1259. 						x, y, glyph, text, offset);
1260. 	return;
1261.     }
1262. 
1263.     if (glyph >= MAX_GLYPH) {
1264. 	impossible("show_glyph:  bad glyph %d [max %d] at (%d,%d).",
1265. 					glyph, MAX_GLYPH, x, y);
1266. 	return;
1267.     }
1268. 
1269.     if (gbuf[y][x].glyph != glyph) {
1270. 	gbuf[y][x].glyph = glyph;
1271. 	gbuf[y][x].new   = 1;
1272. 	if (gbuf_start[y] > x) gbuf_start[y] = x;
1273. 	if (gbuf_stop[y]  < x) gbuf_stop[y]  = x;
1274.     }
1275. }
1276. 
1277. 

clear_glyph_buffer Edit

1278. /*
1279.  * Reset the changed glyph borders so that none of the 3rd screen has
1280.  * changed.
1281.  */
1282. #define reset_glyph_bbox()			\
1283.     {						\
1284. 	int i;					\
1285. 						\
1286. 	for (i = 0; i < ROWNO; i++) {		\
1287. 	    gbuf_start[i] = COLNO-1;		\
1288. 	    gbuf_stop[i]  = 0;			\
1289. 	}					\
1290.     }
1291. 
1292. 
1293. static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) };
1294. /*
1295.  * Turn the 3rd screen into stone.
1296.  */
1297. void
1298. clear_glyph_buffer()
1299. {
1300.     register int x, y;
1301.     register gbuf_entry *gptr;
1302. 
1303.     for (y = 0; y < ROWNO; y++) {
1304. 	gptr = &gbuf[y][0];
1305. 	for (x = COLNO; x; x--) {
1306. 	    *gptr++ = nul_gbuf;
1307. 	}
1308.     }
1309.     reset_glyph_bbox();
1310. }
1311. 

row_refresh Edit

1312. /*
1313.  * Assumes that the indicated positions are filled with S_stone glyphs.
1314.  */
1315. void
1316. row_refresh(start,stop,y)
1317.     int start,stop,y;
1318. {
1319.     register int x;
1320. 
1321.     for (x = start; x <= stop; x++)
1322. 	if (gbuf[y][x].glyph != cmap_to_glyph(S_stone))
1323. 	    print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph);
1324. }
1325. 

cls Edit

1326. void
1327. cls()
1328. {
1329.     display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
1330.     flags.botlx = 1;		/* force update of botl window */
1331.     clear_nhwindow(WIN_MAP);	/* clear physical screen */
1332. 
1333.     clear_glyph_buffer();	/* this is sort of an extra effort, but OK */
1334. }
1335. 

flush_screen Edit

1336. /*
1337.  * Synch the third screen with the display.
1338.  */
1339. void
1340. flush_screen(cursor_on_u)
1341.     int cursor_on_u;
1342. {
1343.     /* Prevent infinite loops on errors:
1344.      *	    flush_screen->print_glyph->impossible->pline->flush_screen
1345.      */
1346.     static   boolean flushing = 0;
1347.     static   boolean delay_flushing = 0;
1348.     register int x,y;
1349. 
1350.     if (cursor_on_u == -1) delay_flushing = !delay_flushing;
1351.     if (delay_flushing) return;
1352.     if (flushing) return;	/* if already flushing then return */
1353.     flushing = 1;
1354. 
1355.     for (y = 0; y < ROWNO; y++) {
1356. 	register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]];
1357. 	for (; x <= gbuf_stop[y]; gptr++, x++)
1358. 	    if (gptr->new) {
1359. 		print_glyph(WIN_MAP,x,y,gptr->glyph);
1360. 		gptr->new = 0;
1361. 	    }
1362.     }
1363. 
1364.     if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */
1365.     display_nhwindow(WIN_MAP, FALSE);
1366.     reset_glyph_bbox();
1367.     flushing = 0;
1368.     if(flags.botl || flags.botlx) bot();
1369. }
1370. 
1371. /* ========================================================================= */
1372. 

back_to_glyph Edit

1373. /*
1374.  * back_to_glyph()
1375.  *
1376.  * Use the information in the rm structure at the given position to create
1377.  * a glyph of a background.
1378.  *
1379.  * I had to add a field in the rm structure (horizontal) so that we knew
1380.  * if open doors and secret doors were horizontal or vertical.  Previously,
1381.  * the screen symbol had the horizontal/vertical information set at
1382.  * level generation time.
1383.  *
1384.  * I used the 'ladder' field (really doormask) for deciding if stairwells
1385.  * were up or down.  I didn't want to check the upstairs and dnstairs
1386.  * variables.
1387.  */
1388. int
1389. back_to_glyph(x,y)
1390.     xchar x,y;
1391. {
1392.     int idx;
1393.     struct rm *ptr = &(levl[x][y]);
1394. 
1395.     switch (ptr->typ) {
1396. 	case SCORR:
1397. 	case STONE:
1398. 	    idx = level.flags.arboreal ? S_tree : S_stone;
1399. 	    break;
1400. 	case ROOM:		idx = S_room;	  break;
1401. 	case CORR:
1402. 	    idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr;
1403. 	    break;
1404. 	case HWALL:
1405. 	case VWALL:
1406. 	case TLCORNER:
1407. 	case TRCORNER:
1408. 	case BLCORNER:
1409. 	case BRCORNER:
1410. 	case CROSSWALL:
1411. 	case TUWALL:
1412. 	case TDWALL:
1413. 	case TLWALL:
1414. 	case TRWALL:
1415. 	case SDOOR:
1416. 	    idx = ptr->seenv ? wall_angle(ptr) : S_stone;
1417. 	    break;
1418. 	case DOOR:
1419. 	    if (ptr->doormask) {
1420. 		if (ptr->doormask & D_BROKEN)
1421. 		    idx = S_ndoor;
1422. 		else if (ptr->doormask & D_ISOPEN)
1423. 		    idx = (ptr->horizontal) ? S_hodoor : S_vodoor;
1424. 		else			/* else is closed */
1425. 		    idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor;
1426. 	    } else
1427. 		idx = S_ndoor;
1428. 	    break;
1429. 	case IRONBARS:	idx = S_bars;     break;
1430. 	case TREE:		idx = S_tree;     break;
1431. 	case POOL:
1432. 	case MOAT:		idx = S_pool;	  break;
1433. 	case STAIRS:
1434. 	    idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair;
1435. 	    break;
1436. 	case LADDER:
1437. 	    idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder;
1438. 	    break;
1439. 	case FOUNTAIN:		idx = S_fountain; break;
1440. 	case SINK:		idx = S_sink;     break;
1441. 	case ALTAR:		idx = S_altar;    break;
1442. 	case GRAVE:		idx = S_grave;    break;
1443. 	case THRONE:		idx = S_throne;   break;
1444. 	case LAVAPOOL:		idx = S_lava;	  break;
1445. 	case ICE:		idx = S_ice;      break;
1446. 	case AIR:		idx = S_air;	  break;
1447. 	case CLOUD:		idx = S_cloud;	  break;
1448. 	case WATER:		idx = S_water;	  break;
1449. 	case DBWALL:
1450. 	    idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge;
1451. 	    break;
1452. 	case DRAWBRIDGE_UP:
1453. 	    switch(ptr->drawbridgemask & DB_UNDER) {
1454. 	    case DB_MOAT:  idx = S_pool; break;
1455. 	    case DB_LAVA:  idx = S_lava; break;
1456. 	    case DB_ICE:   idx = S_ice;  break;
1457. 	    case DB_FLOOR: idx = S_room; break;
1458. 	    default:
1459. 		impossible("Strange db-under: %d",
1460. 			   ptr->drawbridgemask & DB_UNDER);
1461. 		idx = S_room; /* something is better than nothing */
1462. 		break;
1463. 	    }
1464. 	    break;
1465. 	case DRAWBRIDGE_DOWN:
1466. 	    idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge;
1467. 	    break;
1468. 	default:
1469. 	    impossible("back_to_glyph:  unknown level type [ = %d ]",ptr->typ);
1470. 	    idx = S_room;
1471. 	    break;
1472.     }
1473. 
1474.     return cmap_to_glyph(idx);
1475. }
1476. 
1477. 

swallow_to_glyph Edit

1478. /*
1479.  * swallow_to_glyph()
1480.  *
1481.  * Convert a monster number and a swallow location into the correct glyph.
1482.  * If you don't want a patchwork monster while hallucinating, decide on
1483.  * a random monster in swallowed() and don't use what_mon() here.
1484.  */
1485. STATIC_OVL int
1486. swallow_to_glyph(mnum, loc)
1487.     int mnum;
1488.     int loc;
1489. {
1490.     if (loc < S_sw_tl || S_sw_br < loc) {
1491. 	impossible("swallow_to_glyph: bad swallow location");
1492. 	loc = S_sw_br;
1493.     }
1494.     return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF;
1495. }
1496. 
1497. 
1498. 

zapdir_to_glyph Edit

1499. /*
1500.  * zapdir_to_glyph()
1501.  *
1502.  * Change the given zap direction and beam type into a glyph.  Each beam
1503.  * type has four glyphs, one for each of the symbols below.  The order of
1504.  * the zap symbols [0-3] as defined in rm.h are:
1505.  *
1506.  *	|  S_vbeam	( 0, 1) or ( 0,-1)
1507.  *	-  S_hbeam	( 1, 0) or (-1,	0)
1508.  *	\  S_lslant	( 1, 1) or (-1,-1)
1509.  *	/  S_rslant	(-1, 1) or ( 1,-1)
1510.  */
1511. int
1512. zapdir_to_glyph(dx, dy, beam_type)
1513.     register int dx, dy;
1514.     int beam_type;
1515. {
1516.     if (beam_type >= NUM_ZAP) {
1517. 	impossible("zapdir_to_glyph:  illegal beam type");
1518. 	beam_type = 0;
1519.     }
1520.     dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0;
1521. 
1522.     return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF;
1523. }
1524. 
1525. 

glyph_at Edit

1526. /*
1527.  * Utility routine for dowhatis() used to find out the glyph displayed at
1528.  * the location.  This isn't necessarily the same as the glyph in the levl
1529.  * structure, so we must check the "third screen".
1530.  */
1531. int
1532. glyph_at(x, y)
1533.     xchar x,y;
1534. {
1535.     if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
1536. 	return cmap_to_glyph(S_room);			/* XXX */
1537.     return gbuf[y][x].glyph;
1538. }
1539. 
1540. 
1541. /* ------------------------------------------------------------------------- */

type_to_name Edit

1542. /* Wall Angle -------------------------------------------------------------- */
1543. 
1544. /*#define WA_VERBOSE*/	/* give (x,y) locations for all "bad" spots */
1545. 
1546. #ifdef WA_VERBOSE
1547. 
1548. static const char *FDECL(type_to_name, (int));
1549. static void FDECL(error4, (int,int,int,int,int,int));
1550. 
1551. static int bad_count[MAX_TYPE]; /* count of positions flagged as bad */
1552. static const char *type_names[MAX_TYPE] = {
1553. 	"STONE",	"VWALL",	"HWALL",	"TLCORNER",
1554. 	"TRCORNER",	"BLCORNER",	"BRCORNER",	"CROSSWALL",
1555. 	"TUWALL",	"TDWALL",	"TLWALL",	"TRWALL",
1556. 	"DBWALL",	"SDOOR",	"SCORR",	"POOL",
1557. 	"MOAT",		"WATER",	"DRAWBRIDGE_UP","LAVAPOOL",
1558. 	"DOOR",		"CORR",		"ROOM",		"STAIRS",
1559. 	"LADDER",	"FOUNTAIN",	"THRONE",	"SINK",
1560. 	"ALTAR",	"ICE",		"DRAWBRIDGE_DOWN","AIR",
1561. 	"CLOUD"
1562. };
1563. 
1564. 
1565. static const char *
1566. type_to_name(type)
1567.     int type;
1568. {
1569.     return (type < 0 || type > MAX_TYPE) ? "unknown" : type_names[type];
1570. }
1571. 

error4 Edit

1572. static void
1573. error4(x, y, a, b, c, dd)
1574.     int x, y, a, b, c, dd;
1575. {
1576.     pline("set_wall_state: %s @ (%d,%d) %s%s%s%s",
1577. 	type_to_name(levl[x][y].typ), x, y,
1578. 	a ? "1":"", b ? "2":"", c ? "3":"", dd ? "4":"");
1579.     bad_count[levl[x][y].typ]++;
1580. }
1581. #endif /* WA_VERBOSE */
1582. 

check_pos Edit

1583. /*
1584.  * Return 'which' if position is implies an unfinshed exterior.  Return
1585.  * zero otherwise.  Unfinished implies outer area is rock or a corridor.
1586.  *
1587.  * Things that are ambigious: lava
1588.  */
1589. STATIC_OVL int
1590. check_pos(x, y, which)
1591.     int x, y, which;
1592. {
1593.     int type;
1594.     if (!isok(x,y)) return which;
1595.     type = levl[x][y].typ;
1596.     if (IS_ROCK(type) || type == CORR || type == SCORR) return which;
1597.     return 0;
1598. }
1599. 

more_than_one Edit

1600. /* Return TRUE if more than one is non-zero. */
1601. /*ARGSUSED*/
1602. #ifdef WA_VERBOSE
1603. STATIC_OVL boolean
1604. more_than_one(x, y, a, b, c)
1605.     int x, y, a, b, c;
1606. {
1607.     if ((a && (b|c)) || (b && (a|c)) || (c && (a|b))) {
1608. 	error4(x,y,a,b,c,0);
1609. 	return TRUE;
1610.     }
1611.     return FALSE;
1612. }
1613. #else
1614. #define more_than_one(x, y, a, b, c) (((a) && ((b)|(c))) || ((b) && ((a)|(c))) || ((c) && ((a)|(b))))
1615. #endif
1616. 

set_twall Edit

1617. /* Return the wall mode for a T wall. */
1618. STATIC_OVL int
1619. set_twall(x0,y0, x1,y1, x2,y2, x3,y3)
1620. int x0,y0, x1,y1, x2,y2, x3,y3;
1621. {
1622.     int wmode, is_1, is_2, is_3;
1623. 
1624.     is_1 = check_pos(x1, y1, WM_T_LONG);
1625.     is_2 = check_pos(x2, y2, WM_T_BL);
1626.     is_3 = check_pos(x3, y3, WM_T_BR);
1627.     if (more_than_one(x0, y0, is_1, is_2, is_3)) {
1628. 	wmode = 0;
1629.     } else {
1630. 	wmode = is_1 + is_2 + is_3;
1631.     }
1632.     return wmode;
1633. }
1634. 

set_wall Edit

1635. /* Return wall mode for a horizontal or vertical wall. */
1636. STATIC_OVL int
1637. set_wall(x, y, horiz)
1638.     int x, y, horiz;
1639. {
1640.     int wmode, is_1, is_2;
1641. 
1642.     if (horiz) {
1643. 	is_1 = check_pos(x,y-1, WM_W_TOP);
1644. 	is_2 = check_pos(x,y+1, WM_W_BOTTOM);
1645.     } else {
1646. 	is_1 = check_pos(x-1,y, WM_W_LEFT);
1647. 	is_2 = check_pos(x+1,y, WM_W_RIGHT);
1648.     }
1649.     if (more_than_one(x, y, is_1, is_2, 0)) {
1650. 	wmode = 0;
1651.     } else {
1652. 	wmode = is_1 + is_2;
1653.     }
1654.     return wmode;
1655. }
1656. 
1657. 

set_corn Edit

1658. /* Return a wall mode for a corner wall. (x4,y4) is the "inner" position. */
1659. STATIC_OVL int
1660. set_corn(x1,y1, x2,y2, x3,y3, x4,y4)
1661. 	int x1, y1, x2, y2, x3, y3, x4, y4;
1662. {
1663.     int wmode, is_1, is_2, is_3, is_4;
1664. 
1665.     is_1 = check_pos(x1, y1, 1);
1666.     is_2 = check_pos(x2, y2, 1);
1667.     is_3 = check_pos(x3, y3, 1);
1668.     is_4 = check_pos(x4, y4, 1);	/* inner location */
1669. 
1670.     /*
1671.      * All 4 should not be true.  So if the inner location is rock,
1672.      * use it.  If all of the outer 3 are true, use outer.  We currently
1673.      * can't cover the case where only part of the outer is rock, so
1674.      * we just say that all the walls are finished (if not overridden
1675.      * by the inner section).
1676.      */
1677.     if (is_4) {
1678. 	wmode = WM_C_INNER;
1679.     } else if (is_1 && is_2 && is_3)
1680. 	wmode = WM_C_OUTER;
1681.      else
1682. 	wmode = 0;	/* finished walls on all sides */
1683. 
1684.     return wmode;
1685. }
1686. 

set_crosswall Edit

1687. /* Return mode for a crosswall. */
1688. STATIC_OVL int
1689. set_crosswall(x, y)
1690.     int x, y;
1691. {
1692.     int wmode, is_1, is_2, is_3, is_4;
1693. 
1694.     is_1 = check_pos(x-1, y-1, 1);
1695.     is_2 = check_pos(x+1, y-1, 1);
1696.     is_3 = check_pos(x+1, y+1, 1);
1697.     is_4 = check_pos(x-1, y+1, 1);
1698. 
1699.     wmode = is_1+is_2+is_3+is_4;
1700.     if (wmode > 1) {
1701. 	if (is_1 && is_3 && (is_2+is_4 == 0)) {
1702. 	    wmode = WM_X_TLBR;
1703. 	} else if (is_2 && is_4 && (is_1+is_3 == 0)) {
1704. 	    wmode = WM_X_BLTR;
1705. 	} else {
1706. #ifdef WA_VERBOSE
1707. 	    error4(x,y,is_1,is_2,is_3,is_4);
1708. #endif
1709. 	    wmode = 0;
1710. 	}
1711.     } else if (is_1)
1712. 	wmode = WM_X_TL;
1713.     else if (is_2)
1714. 	wmode = WM_X_TR;
1715.     else if (is_3)
1716. 	wmode = WM_X_BR;
1717.     else if (is_4)
1718. 	wmode = WM_X_BL;
1719. 
1720.     return wmode;
1721. }
1722. 

set_wall_state Edit

1723. /* Called from mklev.  Scan the level and set the wall modes. */
1724. void
1725. set_wall_state()
1726. {
1727.     int x, y;
1728.     int wmode;
1729.     struct rm *lev;
1730. 
1731. #ifdef WA_VERBOSE
1732.     for (x = 0; x < MAX_TYPE; x++) bad_count[x] = 0;
1733. #endif
1734. 
1735.     for (x = 0; x < COLNO; x++)
1736. 	for (lev = &levl[x][0], y = 0; y < ROWNO; y++, lev++) {
1737. 	    switch (lev->typ) {
1738. 		case SDOOR:
1739. 		    wmode = set_wall(x, y, (int) lev->horizontal);
1740. 		    break;
1741. 		case VWALL:
1742. 		    wmode = set_wall(x, y, 0);
1743. 		    break;
1744. 		case HWALL:
1745. 		    wmode = set_wall(x, y, 1);
1746. 		    break;
1747. 		case TDWALL:
1748. 		    wmode = set_twall(x,y, x,y-1, x-1,y+1, x+1,y+1);
1749. 		    break;
1750. 		case TUWALL:
1751. 		    wmode = set_twall(x,y, x,y+1, x+1,y-1, x-1,y-1);
1752. 		    break;
1753. 		case TLWALL:
1754. 		    wmode = set_twall(x,y, x+1,y, x-1,y-1, x-1,y+1);
1755. 		    break;
1756. 		case TRWALL:
1757. 		    wmode = set_twall(x,y, x-1,y, x+1,y+1, x+1,y-1);
1758. 		    break;
1759. 		case TLCORNER:
1760. 		    wmode = set_corn(x-1,y-1, x,y-1, x-1,y, x+1,y+1);
1761. 		    break;
1762. 		case TRCORNER:
1763. 		    wmode = set_corn(x,y-1, x+1,y-1, x+1,y, x-1,y+1);
1764. 		    break;
1765. 		case BLCORNER:
1766. 		    wmode = set_corn(x,y+1, x-1,y+1, x-1,y, x+1,y-1);
1767. 		    break;
1768. 		case BRCORNER:
1769. 		    wmode = set_corn(x+1,y, x+1,y+1, x,y+1, x-1,y-1);
1770. 		    break;
1771. 		case CROSSWALL:
1772. 		    wmode = set_crosswall(x, y);
1773. 		    break;
1774. 
1775. 		default:
1776. 		    wmode = -1;	/* don't set wall info */
1777. 		    break;
1778. 	    }
1779. 
1780. 	if (wmode >= 0)
1781. 	    lev->wall_info = (lev->wall_info & ~WM_MASK) | wmode;
1782. 	}
1783. 
1784. #ifdef WA_VERBOSE
1785.     /* check if any bad positions found */
1786.     for (x = y = 0; x < MAX_TYPE; x++)
1787. 	if (bad_count[x]) {
1788. 	    if (y == 0) {
1789. 		y = 1;	/* only print once */
1790. 		pline("set_wall_type: wall mode problems with: ");
1791. 	    }
1792. 	    pline("%s %d;", type_names[x], bad_count[x]);
1793. 	}
1794. #endif /* WA_VERBOSE */
1795. }
1796. 
1797. /* ------------------------------------------------------------------------- */

set_seenv Edit

1798. /* This matrix is used here and in vision.c. */
1799. unsigned char seenv_matrix[3][3] = { {SV2,   SV1, SV0},
1800. 				     {SV3, SVALL, SV7},
1801. 				     {SV4,   SV5, SV6} };
1802. 
1803. #define sign(z) ((z) < 0 ? -1 : ((z) > 0 ? 1 : 0))
1804. 
1805. /* Set the seen vector of lev as if seen from (x0,y0) to (x,y). */
1806. STATIC_OVL void
1807. set_seenv(lev, x0, y0, x, y)
1808.     struct rm *lev;
1809.     int x0, y0, x, y;	/* from, to */
1810. {
1811.     int dx = x-x0, dy = y0-y;
1812.     lev->seenv |= seenv_matrix[sign(dy)+1][sign(dx)+1];
1813. }
1814. 
1815. /* ------------------------------------------------------------------------- */
1816. 

Wall types Edit

1817. /* T wall types, one for each row in wall_matrix[][]. */
1818. #define T_d 0
1819. #define T_l 1
1820. #define T_u 2
1821. #define T_r 3
1822. 
1823. /*
1824.  * These are the column names of wall_matrix[][].  They are the "results"
1825.  * of a tdwall pattern match.  All T walls are rotated so they become
1826.  * a tdwall.  Then we do a single pattern match, but return the
1827.  * correct result for the original wall by using different rows for
1828.  * each of the wall types.
1829.  */
1830. #define T_stone  0
1831. #define T_tlcorn 1
1832. #define T_trcorn 2
1833. #define T_hwall  3
1834. #define T_tdwall 4
1835. 
1836. static const int wall_matrix[4][5] = {
1837.     { S_stone, S_tlcorn, S_trcorn, S_hwall, S_tdwall },	/* tdwall */
1838.     { S_stone, S_trcorn, S_brcorn, S_vwall, S_tlwall },	/* tlwall */
1839.     { S_stone, S_brcorn, S_blcorn, S_hwall, S_tuwall },	/* tuwall */
1840.     { S_stone, S_blcorn, S_tlcorn, S_vwall, S_trwall },	/* trwall */
1841. };
1842. 
1843. 
1844. /* Cross wall types, one for each "solid" quarter.  Rows of cross_matrix[][]. */
1845. #define C_bl 0
1846. #define C_tl 1
1847. #define C_tr 2
1848. #define C_br 3
1849. 
1850. /*
1851.  * These are the column names for cross_matrix[][].  They express results
1852.  * in C_br (bottom right) terms.  All crosswalls with a single solid
1853.  * quarter are rotated so the solid section is at the bottom right.
1854.  * We pattern match on that, but return the correct result depending
1855.  * on which row we'ere looking at.
1856.  */
1857. #define C_trcorn 0
1858. #define C_brcorn 1
1859. #define C_blcorn 2
1860. #define C_tlwall 3
1861. #define C_tuwall 4
1862. #define C_crwall 5
1863. 
1864. static const int cross_matrix[4][6] = {
1865.     { S_brcorn, S_blcorn, S_tlcorn, S_tuwall, S_trwall, S_crwall },
1866.     { S_blcorn, S_tlcorn, S_trcorn, S_trwall, S_tdwall, S_crwall },
1867.     { S_tlcorn, S_trcorn, S_brcorn, S_tdwall, S_tlwall, S_crwall },
1868.     { S_trcorn, S_brcorn, S_blcorn, S_tlwall, S_tuwall, S_crwall },
1869. };
1870. 
1871. 

t_warn Edit

1872. /* Print out a T wall warning and all interesting info. */
1873. STATIC_OVL void
1874. t_warn(lev)
1875.     struct rm *lev;
1876. {
1877.     static const char warn_str[] = "wall_angle: %s: case %d: seenv = 0x%x";
1878.     const char *wname;
1879. 
1880.     if (lev->typ == TUWALL) wname = "tuwall";
1881.     else if (lev->typ == TLWALL) wname = "tlwall";
1882.     else if (lev->typ == TRWALL) wname = "trwall";
1883.     else if (lev->typ == TDWALL) wname = "tdwall";
1884.     else wname = "unknown";
1885.     impossible(warn_str, wname, lev->wall_info & WM_MASK,
1886. 	(unsigned int) lev->seenv);
1887. }
1888. 
1889. 

wall_angle Edit

1890. /*
1891.  * Return the correct graphics character index using wall type, wall mode,
1892.  * and the seen vector.  It is expected that seenv is non zero.
1893.  *
1894.  * All T-wall vectors are rotated to be TDWALL.  All single crosswall
1895.  * blocks are rotated to bottom right.  All double crosswall are rotated
1896.  * to W_X_BLTR.  All results are converted back.
1897.  *
1898.  * The only way to understand this is to take out pen and paper and
1899.  * draw diagrams.  See rm.h for more details on the wall modes and
1900.  * seen vector (SV).
1901.  */
1902. STATIC_OVL int
1903. wall_angle(lev)
1904.     struct rm *lev;
1905. {
1906.     register unsigned int seenv = lev->seenv & 0xff;
1907.     const int *row;
1908.     int col, idx;
1909. 
1910. #define only(sv, bits)	(((sv) & (bits)) && ! ((sv) & ~(bits)))
1911.     switch (lev->typ) {
1912. 	case TUWALL:
1913. 		row = wall_matrix[T_u];
1914. 		seenv = (seenv >> 4 | seenv << 4) & 0xff;/* rotate to tdwall */
1915. 		goto do_twall;
1916. 	case TLWALL:
1917. 		row = wall_matrix[T_l];
1918. 		seenv = (seenv >> 2 | seenv << 6) & 0xff;/* rotate to tdwall */
1919. 		goto do_twall;
1920. 	case TRWALL:
1921. 		row = wall_matrix[T_r];
1922. 		seenv = (seenv >> 6 | seenv << 2) & 0xff;/* rotate to tdwall */
1923. 		goto do_twall;
1924. 	case TDWALL:
1925. 		row = wall_matrix[T_d];
1926. do_twall:
1927. 		switch (lev->wall_info & WM_MASK) {
1928. 		    case 0:
1929. 			if (seenv == SV4) {
1930. 			    col = T_tlcorn;
1931. 			} else if (seenv == SV6) {
1932. 			    col = T_trcorn;
1933. 			} else if (seenv & (SV3|SV5|SV7) ||
1934. 					    ((seenv & SV4) && (seenv & SV6))) {
1935. 			    col = T_tdwall;
1936. 			} else if (seenv & (SV0|SV1|SV2)) {
1937. 			    col = (seenv & (SV4|SV6) ? T_tdwall : T_hwall);
1938. 			} else {
1939. 			    t_warn(lev);
1940. 			    col = T_stone;
1941. 			}
1942. 			break;
1943. 		    case WM_T_LONG:
1944. 			if (seenv & (SV3|SV4) && !(seenv & (SV5|SV6|SV7))) {
1945. 			    col = T_tlcorn;
1946. 			} else if (seenv&(SV6|SV7) && !(seenv&(SV3|SV4|SV5))) {
1947. 			    col = T_trcorn;
1948. 			} else if ((seenv & SV5) ||
1949. 				((seenv & (SV3|SV4)) && (seenv & (SV6|SV7)))) {
1950. 			    col = T_tdwall;
1951. 			} else {
1952. 			    /* only SV0|SV1|SV2 */
1953. 			    if (! only(seenv, SV0|SV1|SV2) )
1954. 				t_warn(lev);
1955. 			    col = T_stone;
1956. 			}
1957. 			break;
1958. 		    case WM_T_BL:
1959. #if 0	/* older method, fixed */
1960. 			if (only(seenv, SV4|SV5)) {
1961. 			    col = T_tlcorn;
1962. 			} else if ((seenv & (SV0|SV1|SV2)) &&
1963. 					only(seenv, SV0|SV1|SV2|SV6|SV7)) {
1964. 			    col = T_hwall;
1965. 			} else if (seenv & SV3 ||
1966. 			    ((seenv & (SV0|SV1|SV2)) && (seenv & (SV4|SV5)))) {
1967. 			    col = T_tdwall;
1968. 			} else {
1969. 			    if (seenv != SV6)
1970. 				t_warn(lev);
1971. 			    col = T_stone;
1972. 			}
1973. #endif	/* 0 */
1974. 			if (only(seenv, SV4|SV5))
1975. 			    col = T_tlcorn;
1976. 			else if ((seenv & (SV0|SV1|SV2|SV7)) &&
1977. 					!(seenv & (SV3|SV4|SV5)))
1978. 			    col = T_hwall;
1979. 			else if (only(seenv, SV6))
1980. 			    col = T_stone;
1981. 			else
1982. 			    col = T_tdwall;
1983. 			break;
1984. 		    case WM_T_BR:
1985. #if 0	/* older method, fixed */
1986. 			if (only(seenv, SV5|SV6)) {
1987. 			    col = T_trcorn;
1988. 			} else if ((seenv & (SV0|SV1|SV2)) &&
1989. 					    only(seenv, SV0|SV1|SV2|SV3|SV4)) {
1990. 			    col = T_hwall;
1991. 			} else if (seenv & SV7 ||
1992. 			    ((seenv & (SV0|SV1|SV2)) && (seenv & (SV5|SV6)))) {
1993. 			    col = T_tdwall;
1994. 			} else {
1995. 			    if (seenv != SV4)
1996. 				t_warn(lev);
1997. 			    col = T_stone;
1998. 			}
1999. #endif	/* 0 */
2000. 			if (only(seenv, SV5|SV6))
2001. 			    col = T_trcorn;
2002. 			else if ((seenv & (SV0|SV1|SV2|SV3)) &&
2003. 					!(seenv & (SV5|SV6|SV7)))
2004. 			    col = T_hwall;
2005. 			else if (only(seenv, SV4))
2006. 			    col = T_stone;
2007. 			else
2008. 			    col = T_tdwall;
2009. 
2010. 			break;
2011. 		    default:
2012. 			impossible("wall_angle: unknown T wall mode %d",
2013. 				lev->wall_info & WM_MASK);
2014. 			col = T_stone;
2015. 			break;
2016. 		}
2017. 		idx = row[col];
2018. 		break;
2019. 
2020. 	case SDOOR:
2021. 		if (lev->horizontal) goto horiz;
2022. 		/* fall through */
2023. 	case VWALL:
2024. 		switch (lev->wall_info & WM_MASK) {
2025. 		    case 0: idx = seenv ? S_vwall : S_stone; break;
2026. 		    case 1: idx = seenv & (SV1|SV2|SV3|SV4|SV5) ? S_vwall :
2027. 								  S_stone;
2028. 			    break;
2029. 		    case 2: idx = seenv & (SV0|SV1|SV5|SV6|SV7) ? S_vwall :
2030. 								  S_stone;
2031. 			    break;
2032. 		    default:
2033. 			impossible("wall_angle: unknown vwall mode %d",
2034. 				lev->wall_info & WM_MASK);
2035. 			idx = S_stone;
2036. 			break;
2037. 		}
2038. 		break;
2039. 
2040. 	case HWALL:
2041. horiz:
2042. 		switch (lev->wall_info & WM_MASK) {
2043. 		    case 0: idx = seenv ? S_hwall : S_stone; break;
2044. 		    case 1: idx = seenv & (SV3|SV4|SV5|SV6|SV7) ? S_hwall :
2045. 								  S_stone;
2046. 			    break;
2047. 		    case 2: idx = seenv & (SV0|SV1|SV2|SV3|SV7) ? S_hwall :
2048. 								  S_stone;
2049. 			    break;
2050. 		    default:
2051. 			impossible("wall_angle: unknown hwall mode %d",
2052. 				lev->wall_info & WM_MASK);
2053. 			idx = S_stone;
2054. 			break;
2055. 		}
2056. 		break;
2057. 
2058. #define set_corner(idx, lev, which, outer, inner, name)	\
2059.     switch ((lev)->wall_info & WM_MASK) {				    \
2060. 	case 0:		 idx = which; break;				    \
2061. 	case WM_C_OUTER: idx = seenv &  (outer) ? which : S_stone; break;   \
2062. 	case WM_C_INNER: idx = seenv & ~(inner) ? which : S_stone; break;   \
2063. 	default:							    \
2064. 	    impossible("wall_angle: unknown %s mode %d", name,		    \
2065. 		(lev)->wall_info & WM_MASK);				    \
2066. 	    idx = S_stone;						    \
2067. 	    break;							    \
2068.     }
2069. 
2070. 	case TLCORNER:
2071. 	    set_corner(idx, lev, S_tlcorn, (SV3|SV4|SV5), SV4, "tlcorn");
2072. 	    break;
2073. 	case TRCORNER:
2074. 	    set_corner(idx, lev, S_trcorn, (SV5|SV6|SV7), SV6, "trcorn");
2075. 	    break;
2076. 	case BLCORNER:
2077. 	    set_corner(idx, lev, S_blcorn, (SV1|SV2|SV3), SV2, "blcorn");
2078. 	    break;
2079. 	case BRCORNER:
2080. 	    set_corner(idx, lev, S_brcorn, (SV7|SV0|SV1), SV0, "brcorn");
2081. 	    break;
2082. 
2083. 
2084. 	case CROSSWALL:
2085. 		switch (lev->wall_info & WM_MASK) {
2086. 		    case 0:
2087. 			if (seenv == SV0)
2088. 			    idx = S_brcorn;
2089. 			else if (seenv == SV2)
2090. 			    idx = S_blcorn;
2091. 			else if (seenv == SV4)
2092. 			    idx = S_tlcorn;
2093. 			else if (seenv == SV6)
2094. 			    idx = S_trcorn;
2095. 			else if (!(seenv & ~(SV0|SV1|SV2)) &&
2096. 					(seenv & SV1 || seenv == (SV0|SV2)))
2097. 			    idx = S_tuwall;
2098. 			else if (!(seenv & ~(SV2|SV3|SV4)) &&
2099. 					(seenv & SV3 || seenv == (SV2|SV4)))
2100. 			    idx = S_trwall;
2101. 			else if (!(seenv & ~(SV4|SV5|SV6)) &&
2102. 					(seenv & SV5 || seenv == (SV4|SV6)))
2103. 			    idx = S_tdwall;
2104. 			else if (!(seenv & ~(SV0|SV6|SV7)) &&
2105. 					(seenv & SV7 || seenv == (SV0|SV6)))
2106. 			    idx = S_tlwall;
2107. 			else
2108. 			    idx = S_crwall;
2109. 			break;
2110. 
2111. 		    case WM_X_TL:
2112. 			row = cross_matrix[C_tl];
2113. 			seenv = (seenv >> 4 | seenv << 4) & 0xff;
2114. 			goto do_crwall;
2115. 		    case WM_X_TR:
2116. 			row = cross_matrix[C_tr];
2117. 			seenv = (seenv >> 6 | seenv << 2) & 0xff;
2118. 			goto do_crwall;
2119. 		    case WM_X_BL:
2120. 			row = cross_matrix[C_bl];
2121. 			seenv = (seenv >> 2 | seenv << 6) & 0xff;
2122. 			goto do_crwall;
2123. 		    case WM_X_BR:
2124. 			row = cross_matrix[C_br];
2125. do_crwall:
2126. 			if (seenv == SV4)
2127. 			    idx = S_stone;
2128. 			else {
2129. 			    seenv = seenv & ~SV4;	/* strip SV4 */
2130. 			    if (seenv == SV0) {
2131. 				col = C_brcorn;
2132. 			    } else if (seenv & (SV2|SV3)) {
2133. 				if (seenv & (SV5|SV6|SV7))
2134. 				    col = C_crwall;
2135. 				else if (seenv & (SV0|SV1))
2136. 				    col = C_tuwall;
2137. 				else
2138. 				    col = C_blcorn;
2139. 			    } else if (seenv & (SV5|SV6)) {
2140. 				if (seenv & (SV1|SV2|SV3))
2141. 				    col = C_crwall;
2142. 				else if (seenv & (SV0|SV7))
2143. 				    col = C_tlwall;
2144. 				else
2145. 				    col = C_trcorn;
2146. 			    } else if (seenv & SV1) {
2147. 				col = seenv & SV7 ? C_crwall : C_tuwall;
2148. 			    } else if (seenv & SV7) {
2149. 				col = seenv & SV1 ? C_crwall : C_tlwall;
2150. 			    } else {
2151. 				impossible(
2152. 				    "wall_angle: bottom of crwall check");
2153. 				col = C_crwall;
2154. 			    }
2155. 
2156. 			    idx = row[col];
2157. 			}
2158. 			break;
2159. 
2160. 		    case WM_X_TLBR:
2161. 			if ( only(seenv, SV1|SV2|SV3) )
2162. 			    idx = S_blcorn;
2163. 			else if ( only(seenv, SV5|SV6|SV7) )
2164. 			    idx = S_trcorn;
2165. 			else if ( only(seenv, SV0|SV4) )
2166. 			    idx = S_stone;
2167. 			else
2168. 			    idx = S_crwall;
2169. 			break;
2170. 
2171. 		    case WM_X_BLTR:
2172. 			if ( only(seenv, SV0|SV1|SV7) )
2173. 			    idx = S_brcorn;
2174. 			else if ( only(seenv, SV3|SV4|SV5) )
2175. 			    idx = S_tlcorn;
2176. 			else if ( only(seenv, SV2|SV6) )
2177. 			    idx = S_stone;
2178. 			else
2179. 			    idx = S_crwall;
2180. 			break;
2181. 
2182. 		    default:
2183. 			impossible("wall_angle: unknown crosswall mode");
2184. 			idx = S_stone;
2185. 			break;
2186. 		}
2187. 		break;
2188. 
2189. 	default:
2190. 	    impossible("wall_angle: unexpected wall type %d", lev->typ);
2191. 	    idx = S_stone;
2192.     }
2193.     return idx;
2194. }
2195. 
2196. /*display.c*/

Around Wikia's network

Random Wiki