Source:NetHack 3.4.0/display.c

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

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

1.   /*	SCCS Id: @(#)display.c	3.4	2000/07/27	*/ 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 (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.  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.  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.   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.   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.   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.   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 (level.flags.hero_memory) 276. 	levl[x][y].glyph = GLYPH_INVISIBLE; 277.     show_glyph(x, y, GLYPH_INVISIBLE); 278. }  279.   280.  /*  281.   * unmap_object 282.  *  283.   * Remove something from the map when the hero realizes it's not there any 284.  * more. Replace it with background or known trap, but not with any other 285.  * If this is used for detection, a full screen update is imminent anyway; 286.  * if this is used to get rid of an invisible monster notation, we might have 287.  * to call newsym. 288.  */  289.  void 290. unmap_object(x, y)  291. register int x, y; 292. { 293.      register struct trap *trap; 294.  295.      if (!level.flags.hero_memory) return; 296.  297.      if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y)) 298. 	map_trap(trap, 0); 299.     else if (levl[x][y].seenv) { 300. 	struct rm *lev = &levl[x][y]; 301.  302.  	map_background(x, y, 0); 303.  304.  	/* turn remembered dark room squares dark */ 305. 	if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) &&  306.  							    lev->typ == ROOM) 307. 	    lev->glyph = cmap_to_glyph(S_stone); 308.     } else 309. 	levl[x][y].glyph = cmap_to_glyph(S_stone);	/* default val */ 310. }  311.   312.   313.  /*  314.   * map_location 315.  *  316.   * Make whatever at this location show up. This is only for non-living 317.  * things. This will not handle feeling invisible objects correctly. 318.  *  319.   * Internal to display.c, this is a #define for speed. 320.  */  321.  #define _map_location(x,y,show)						\ 322. {									\  323.      register struct obj   *obj;						\ 324.     register struct trap  *trap;					\ 325. 									\  326.      if ((obj = vobj_at(x,y)) && !covers_objects(x,y))			\ 327. 	map_object(obj,show);						\ 328.     else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y))	\ 329. 	map_trap(trap,show);						\ 330.     else								\ 331. 	map_background(x,y,show);					\ 332. }  333.   334.  void map_location(x,y,show) 335.     int x, y, show; 336. {  337.      _map_location(x,y,show); 338. }  339.   340.  #define DETECTED 	2 341. #define PHYSICALLY_SEEN 1 342. #define is_worm_tail(mon)	((mon) && ((x != (mon)->mx)  || (y != (mon)->my))) 343.  344.  /*  345.   * display_monster 346.  *  347.   * Note that this is *not* a map_XXXX function! Monsters sort of float 348.  * above everything. 349.  *  350.   * Yuck. Display body parts by recognizing that the display position is 351. * not the same as the monster position. Currently the only body part is 352. * a worm tail. 353.  *  354.   */  355.  STATIC_OVL void 356. display_monster(x, y, mon, sightflags, worm_tail) 357.     register xchar x, y;	/* display position */ 358.     register struct monst *mon;	/* monster to display */ 359.     int sightflags;		/* 1 if the monster is physically seen */ 360.     				/* 2 if detected using Detect_monsters */ 361.     register xchar worm_tail;	/* mon is actually a worm tail */ 362. {  363.      register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING); 364.     register int sensed = mon_mimic && 365. 	(Protection_from_shape_changers || sensemon(mon)); 366.     /*  367.       * We must do the mimic check first. If the mimic is mimicing something, 368.      * and the location is in sight, we have to change the hero's memory 369.      * so that when the position is out of sight, the hero remembers what 370.      * the mimic was mimicing. 371.      */  372.   373.      if (mon_mimic && sightflags) { 374. 	switch (mon->m_ap_type) { 375. 	    default: 376. 		impossible("display_monster:  bad m_ap_type value [ = %d ]",  377.  							(int) mon->m_ap_type); 378. 	    case M_AP_NOTHING: 379. 		show_glyph(x, y, mon_to_glyph(mon)); 380. 		break; 381.  382.  	    case M_AP_FURNITURE: { 383. 		/*  384.  		 * This is a poor man's version of map_background. I can't 385. * use map_background because we are overriding what is in 386. * the 'typ' field. Maybe have map_background's parameters 387. 		 * be (x,y,glyph) instead of just (x,y). 388. 		 *  389.  		 * mappearance is currently set to an S_ index value in  390. * makemon.c. 391. */ 392.  		register int glyph = cmap_to_glyph(mon->mappearance); 393. 		levl[x][y].glyph = glyph; 394. 		if (!sensed) show_glyph(x,y, glyph); 395. 		break; 396. 	    }  397.   398.  	    case M_AP_OBJECT: { 399. 		struct obj obj;	/* Make a fake object to send	*/ 400. 				/* to map_object. */ 401.  		obj.ox = x;  402. obj.oy = y; 403. obj.otyp = mon->mappearance; 404. 		obj.corpsenm = PM_TENGU;	/* if mimicing a corpse */ 405. 		map_object(&obj,!sensed); 406. 		break; 407. 	    }  408.   409.  	    case M_AP_MONSTER: 410. 		show_glyph(x,y, monnum_to_glyph(what_mon((int)mon->mappearance))); 411. 		break; 412. 	}  413.  	  414.      }  415.   416.      /* If the mimic is unsucessfully mimicing something, display the monster */ 417.     if (!mon_mimic || sensed) { 418. 	int num; 419.  420.  	/* [ALI] Only use detected glyphs when monster wouldn't be  421. * visible by any other means. 422. 	 */  423.  	if (sightflags == DETECTED) { 424. 	    if (worm_tail) 425. 		num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); 426. 	    else 427. 		num = detected_mon_to_glyph(mon); 428. 	} else if (mon->mtame && !Hallucination) { 429. 	    if (worm_tail) 430. 		num = petnum_to_glyph(PM_LONG_WORM_TAIL); 431. 	    else 432. 		num = pet_to_glyph(mon); 433. 	} else { 434. 	    if (worm_tail) 435. 		num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); 436. 	    else 437. 		num = mon_to_glyph(mon); 438. 	}  439.  	show_glyph(x,y,num); 440.     }  441.  }  442.   443.  /*  444.   * display_warning 445.  *  446.   * This is also *not* a map_XXXX function! Monster warnings float 447.  * above everything just like monsters do, but only if the monster 448.  * is not showing. 449.  *  450.   * Do not call for worm tails. 451.  */  452.  STATIC_OVL void 453. display_warning(mon) 454.     register struct monst *mon; 455. {  456.      int x = mon->mx, y = mon->my; 457.     int wl = (int) (mon->m_lev / 4); 458.     int glyph; 459.  460.      if (mon_warning(mon)) { 461.         if (wl > WARNCOUNT - 1) wl = WARNCOUNT - 1; 462.         glyph = warning_to_glyph(wl); 463.     } else if (MATCH_WARN_OF_MON(mon)) { 464. 	glyph = mon_to_glyph(mon); 465.     } else { 466.     	impossible("display_warning did not match warning type?"); 467.         return; 468.     }  469.      show_glyph(x, y, glyph); 470. }  471.   472.  /*  473.   * feel_location 474.  *  475.   * Feel the given location. This assumes that the hero is blind and that 476.  * the given position is either the hero's or one of the eight squares 477.  * adjacent to the hero (except for a boulder push). 478.  * If an invisible monster has gone away, that will be discovered. If an 479. * invisible monster has appeared, this will _not_ be discovered since 480.  * searching only finds one monster per turn so we must check that separately. 481.  */  482.  void 483. feel_location(x, y)  484. xchar x, y; 485. { 486.      struct rm *lev = &(levl[x][y]); 487.     struct obj *boulder; 488.     register struct monst *mon; 489.  490.      /* If the hero's memory of an invisible monster is accurate, we want to keep 491.      * him from detecting the same monster over and over again on each turn. 492.      * We must return (so we don't erase the monster). (We must also, in the 493.       * search function, be sure to skip over previously detected 'I's.) 494.      */  495.      if (glyph_is_invisible(levl[x][y].glyph) && m_at(x,y)) return; 496.  497.      /* The hero can't feel non pool locations while under water. */ 498.      if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y)) 499. 	return; 500.  501.      /* Set the seen vector as if the hero had seen it. It doesn't matter */ 502.     /* if the hero is levitating or not. */ 503.      set_seenv(lev, u.ux, u.uy, x, y); 504.  505.      if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) { 506. 	/*  507.  	 * Levitation Rules. It is assumed that the hero can feel the state 508. 	 * of the walls around herself and can tell if she is in a corridor, 509. 	 * room, or doorway. Boulders are felt because they are large enough. 510. 	 * Anything else is unknown because the hero can't reach the ground. 511. 	 * This makes things difficult. 512. 	 *  513.  	 * Check (and display) in order: 514. 	 *  515.  	 *	+ Stone, walls, and closed doors. 516. 	 *	+ Boulders. [see a boulder before a doorway] 517. 	 *	+ Doors. 518. 	 *	+ Room/water positions 519. 	 *	+ Everything else (hallways!) 520. 	 */  521.  	if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) && 522. 				(lev->doormask & (D_LOCKED | D_CLOSED)))) { 523. 	    map_background(x, y, 1); 524. 	} else if ((boulder = sobj_at(BOULDER,x,y)) != 0) { 525. 	    map_object(boulder, 1); 526. 	} else if (IS_DOOR(lev->typ)) { 527. 	    map_background(x, y, 1); 528. 	} else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) { 529. 	    /*  530.  	     * An open room or water location. Normally we wouldn't touch 531. 	     * this, but we have to get rid of remembered boulder symbols. 532. 	     * This will only occur in rare occations when the hero goes 533. 	     * blind and doesn't find a boulder where expected (something  534.  	     * came along and picked it up). We know that there is not a 535. * boulder at this location. Show fountains, pools, etc. 536. 	     * underneath if already seen. Otherwise, show the appropriate 537. 	     * floor symbol. 538. 	     *  539.  	     * This isn't quite correct. If the boulder was on top of some 540. 	     * other objects they should be seen once the boulder is removed. 541. 	     * However, we have no way of knowing that what is there now 542. 	     * was there then. So we let the hero have a lapse of memory. 543. 	     * We could also just display what is currently on the top of the 544. 	     * object stack (if anything). 545. 	     */  546.  	    if (lev->glyph == objnum_to_glyph(BOULDER)) { 547. 		if (lev->typ != ROOM && lev->seenv) { 548. 		    map_background(x, y, 1); 549. 		} else { 550. 		    lev->glyph = lev->waslit ? cmap_to_glyph(S_room) : 551. 					       cmap_to_glyph(S_stone); 552. 		    show_glyph(x,y,lev->glyph); 553. 		}  554.  	    }  555.  	} else { 556. 	    /* We feel it (I think hallways are the only things left). */ 557.  	    map_background(x, y, 1); 558. 	    /* Corridors are never felt as lit (unless remembered that way) */ 559. 	    /* (lit_corridor only). */ 560.  	    if (lev->typ == CORR &&  561.  		    lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) 562. 		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); 563. 	}  564.      } else { 565. 	_map_location(x, y, 1); 566.  567.  	if (Punished) { 568. 	    /*  569.  	     * A ball or chain is only felt if it is first on the object 570. 	     * location list. Otherwise, we need to clear the felt bit --- 571. 	     * something has been dropped on the ball/chain. If the bit is 572. * not cleared, then when the ball/chain is moved it will drop 573. 	     * the wrong glyph. 574. 	     */  575.  	    if (uchain->ox == x && uchain->oy == y) { 576. 		if (level.objects[x][y] == uchain) 577. 		    u.bc_felt |= BC_CHAIN; 578. 		else 579. 		    u.bc_felt &= ~BC_CHAIN;	/* do not feel the chain */ 580. 	    }  581.  	    if (!carried(uball) && uball->ox == x && uball->oy == y) { 582. 		if (level.objects[x][y] == uball) 583. 		    u.bc_felt |= BC_BALL; 584. 		else 585. 		    u.bc_felt &= ~BC_BALL;	/* do not feel the ball */ 586. 	    }  587.  	}  588.   589.  	/* Floor spaces are dark if unlit. Corridors are dark if unlit. */ 590.  	if (lev->typ == ROOM &&  591.  		    lev->glyph == cmap_to_glyph(S_room) && !lev->waslit) 592. 	    show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone)); 593. 	else if (lev->typ == CORR &&  594.  		    lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) 595. 	    show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr)); 596.     }  597.      /* draw monster on top if we can sense it */ 598.     if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon)) 599. 	display_monster(x, y, mon,  600.  		(tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)) ? PHYSICALLY_SEEN : DETECTED,  601.  		is_worm_tail(mon)); 602. }  603.   604.  /*  605.   * newsym 606.  *  607.   * Possibly put a new glyph at the given location. 608.  */  609.  void 610. newsym(x,y) 611.     register int x,y; 612. {  613.      register struct monst *mon; 614.     register struct rm *lev = &(levl[x][y]); 615.     register int see_it; 616.     register xchar worm_tail; 617.  618.      if (in_mklev) return; 619.  620.      /* only permit updating the hero when swallowed */ 621.     if (u.uswallow) { 622. 	if (x == u.ux && y == u.uy) display_self; 623. 	return; 624.     }  625.      if (Underwater && !Is_waterlevel(&u.uz)) { 626. 	/* don't do anything unless (x,y) is an adjacent underwater position */ 627. 	int dx, dy; 628. 	if (!is_pool(x,y)) return; 629. 	dx = x - u.ux;	if (dx < 0) dx = -dx; 630. 	dy = y - u.uy;	if (dy < 0) dy = -dy; 631. 	if (dx > 1 || dy > 1) return; 632.     }  633.   634.      /* Can physically see the location. */ 635.      if (cansee(x,y)) { 636.         NhRegion* reg = visible_region_at(x,y); 637. 	/*  638.  	 * Don't use templit here:  E.g.  639. * 640.  	 *	lev->waslit = !!(lev->lit || templit(x,y)); 641. 	 *  642.  	 * Otherwise we have the "light pool" problem, where non-permanently 643. 	 * lit areas just out of sight stay remembered as lit.  They should 644. 	 * re-darken. 645. 	 *  646.  	 * Perhaps ALL areas should revert to their "unlit" look when 647. 	 * out of sight. 648. 	 */  649.  	lev->waslit = (lev->lit!=0);	/* remember lit condition */ 650.  651.  	if (reg != NULL && ACCESSIBLE(lev->typ)) { 652. 	    show_region(reg,x,y); 653. 	    return; 654. 	}  655.  	if (x == u.ux && y == u.uy) { 656. 	    if (canseeself) { 657. 		_map_location(x,y,0);	/* map *under* self */ 658. 		display_self; 659. 	    } else 660. 		/* we can see what is there */ 661. 		_map_location(x,y,1); 662. 	}  663.  	else { 664. 	    mon = m_at(x,y); 665. 	    worm_tail = is_worm_tail(mon); 666. 	    see_it = mon && (worm_tail  667.  		? (!mon->minvis || See_invisible)  668.  		: (mon_visible(mon)) || tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)); 669. 	    if (mon && (see_it || (!worm_tail && Detect_monsters))) { 670. 		if (mon->mtrapped) { 671. 		    struct trap *trap = t_at(x, y); 672. 		    int tt = trap ? trap->ttyp : NO_TRAP; 673.  674.  		    /* if monster is in a physical trap, you see the trap too */ 675. 		    if (tt == BEAR_TRAP || tt == PIT ||  676.  			tt == SPIKED_PIT ||tt == WEB) { 677. 			trap->tseen = TRUE; 678. 		    }  679.  		}  680.  		_map_location(x,y,0);	/* map under the monster */ 681. 		/* also gets rid of any invisibility glyph */ 682. 		display_monster(x, y, mon, see_it ? PHYSICALLY_SEEN : DETECTED, worm_tail); 683. 	    }  684.  	    else if (mon && mon_warning(mon) && !is_worm_tail(mon)) 685. 	        display_warning(mon); 686. 	    else if (glyph_is_invisible(levl[x][y].glyph)) 687. 		map_invisible(x, y); 688. 	    else 689. 		_map_location(x,y,1);	/* map the location */ 690. 	}  691.      }  692.   693.      /* Can't see the location. */ 694.      else { 695. 	if (x == u.ux && y == u.uy) { 696. 	    feel_location(u.ux, u.uy);		/* forces an update */ 697.  698.  	    if (canseeself) display_self; 699. 	}  700.  	else if ((mon = m_at(x,y))  701.  		&& ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon) 702. 		    		|| (see_with_infrared(mon) && mon_visible(mon)))) 703. 		    || Detect_monsters)  704.  		&& !is_worm_tail(mon)) { 705. 	    /* Monsters are printed every time. */ 706.  	    /* This also gets rid of any invisibility glyph */ 707. 	    display_monster(x, y, mon, see_it ? 0 : DETECTED, 0); 708. 	}  709.  	else if ((mon = m_at(x,y)) && mon_warning(mon) &&  710.  		 !is_worm_tail(mon)) { 711. 	        display_warning(mon); 712. 	}		  713.   714.  	/*  715.  	 * If the location is remembered as being both dark (waslit is false) 716. 	 * and lit (glyph is a lit room or lit corridor) then it was either: 717. 	 *  718.  	 *	(1) A dark location that the hero could see through night 719. 	 *	    vision. 720. 	 *  721.  	 *	(2) Darkened while out of the hero's sight. This can happen 722. 	 *	    when cursed scroll of light is read. 723. 	 *  724.  	 * In either case, we have to manually correct the hero's memory to  725. * match waslit. Deciding when to change waslit is non-trivial. 726. 	 *  727.  	 *  Note:  If flags.lit_corridor is set, then corridors act like room 728. 	 *	   squares. That is, they light up if in night vision range. 729. 	 *	   If flags.lit_corridor is not set, then corridors will 730. 	 *	   remain dark unless lit by a light spell. 731. 	 *  732.  	 * These checks and changes must be here and not in back_to_glyph. 733. 	 * They are dependent on the position being out of sight. 734. 	 */  735.  	else if (!lev->waslit) { 736. 	    if (flags.lit_corridor && lev->glyph == cmap_to_glyph(S_litcorr) &&  737.  							    lev->typ == CORR) 738. 		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); 739. 	    else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM) 740. 		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone)); 741. 	    else 742. 		goto show_mem; 743. 	} else { 744. show_mem: 745. 	    show_glyph(x, y, lev->glyph); 746. 	}  747.      }  748.  }  749.   750.  #undef is_worm_tail 751.  752.  /*  753.   * shieldeff 754.  *  755.   * Put magic shield pyrotechnics at the given location. This *could* be 756. * pulled into a platform dependent routine for fancier graphics if desired. 757.  */  758.  void 759. shieldeff(x,y) 760.     xchar x,y; 761. {  762.      register int i;  763. 764.     if (!flags.sparkle) return; 765.     if (cansee(x,y)) {	/* Don't see anything if can't see the location */ 766. 	for (i = 0; i < SHIELD_COUNT; i++) { 767. 	    show_glyph(x, y, cmap_to_glyph(shield_static[i])); 768. 	    flush_screen(1);	/* make sure the glyph shows up */ 769. 	    delay_output; 770. 	}  771.  	newsym(x,y);		/* restore the old information */ 772.     }  773.  }  774.   775.   776.  /*  777.   * tmp_at 778.  *  779.   * Temporarily place glyphs on the screen. Do not call delay_output. It 780. * is up to the caller to decide if it wants to wait [presently, everyone 781.  * but explode wants to delay]. 782.  *  783.   * Call: 784.  *	(DISP_BEAM,   glyph)	open, initialize glyph 785.  *	(DISP_FLASH,  glyph)	open, initialize glyph 786.  *	(DISP_ALWAYS, glyph)	open, initialize glyph 787.  *	(DISP_CHANGE, glyph)	change glyph 788.  *	(DISP_END,    0)	close & clean up (second argument doesn't  789.   *				matter) 790.  *	(DISP_FREEMEM, 0)	only used to prevent memory leak during 791.  *				exit)  792.   *	(x, y)			display the glyph at the location  793.   *  794.   * DISP_BEAM  - Display the given glyph at each location, but do not erase  795.   *		any until the close call.  796.   * DISP_FLASH - Display the given glyph at each location, but erase the  797.   *		previous location's glyph.  798.   * DISP_ALWAYS- Like DISP_FLASH, but vision is not taken into account.  799.   */  800.   801.  static struct tmp_glyph {  802.      coord saved[COLNO];	/* previously updated positions */  803.      int sidx;		/* index of next unused slot in saved[] */  804.      int style;		/* either DISP_BEAM or DISP_FLASH or DISP_ALWAYS */  805.      int glyph;		/* glyph to use when printing */  806.      struct tmp_glyph *prev;  807.  } tgfirst;  808.   809.  void  810.  tmp_at(x, y)  811.      int x, y;  812.  {  813.      static struct tmp_glyph *tglyph = (struct tmp_glyph *)0;  814. struct tmp_glyph *tmp; 815.  816.      switch (x) { 817. 	case DISP_BEAM: 818. 	case DISP_FLASH: 819. 	case DISP_ALWAYS: 820. 	    if (!tglyph) 821. 		tmp = &tgfirst; 822. 	    else	/* nested effect; we need dynamic memory */ 823. 		tmp = (struct tmp_glyph *)alloc(sizeof (struct tmp_glyph)); 824. 	    tmp->prev = tglyph; 825. 	    tglyph = tmp; 826. 	    tglyph->sidx = 0; 827. 	    tglyph->style = x;  828. tglyph->glyph = y; 829. flush_screen(0);	/* flush buffered glyphs */ 830. 	    return; 831.  832.  	case DISP_FREEMEM:  /* in case game ends with tmp_at in progress */ 833. 	    while (tglyph) { 834. 		tmp = tglyph->prev; 835. 		if (tglyph != &tgfirst) free((genericptr_t)tglyph); 836. 		tglyph = tmp; 837. 	    }  838.  	    return; 839.  840.  	default: 841. 	    break; 842.     }  843.   844.      if (!tglyph) panic("tmp_at: tglyph not initialized"); 845.  846.      switch (x) { 847. 	case DISP_CHANGE: 848. 	    tglyph->glyph = y;  849. break; 850.  851.  	case DISP_END: 852. 	    if (tglyph->style == DISP_BEAM) { 853. 		register int i;  854. 855. 		/* Erase (reset) from source to end */ 856. 		for (i = 0; i < tglyph->sidx; i++) 857. 		    newsym(tglyph->saved[i].x, tglyph->saved[i].y); 858. 	    } else {		/* DISP_FLASH or DISP_ALWAYS */ 859. 		if (tglyph->sidx)	/* been called at least once */ 860. 		    newsym(tglyph->saved[0].x, tglyph->saved[0].y); 861. 	    }  862.  	 /* tglyph->sidx = 0; -- about to be freed, so not necessary */ 863. 	    tmp = tglyph->prev; 864. 	    if (tglyph != &tgfirst) free((genericptr_t)tglyph); 865. 	    tglyph = tmp; 866. 	    break; 867.  868.  	default:	/* do it */ 869. 	    if (tglyph->style == DISP_BEAM) { 870. 		if (!cansee(x,y)) break; 871. 		/* save pos for later erasing */ 872. 		tglyph->saved[tglyph->sidx].x = x;  873. tglyph->saved[tglyph->sidx].y = y; 874. tglyph->sidx += 1; 875. 	    } else {	/* DISP_FLASH/ALWAYS */ 876. 		if (tglyph->sidx) { /* not first call, so reset previous pos */ 877. 		    newsym(tglyph->saved[0].x, tglyph->saved[0].y); 878. 		    tglyph->sidx = 0;	/* display is presently up to date */ 879. 		}  880.  		if (!cansee(x,y) && tglyph->style != DISP_ALWAYS) break; 881. 		tglyph->saved[0].x = x;  882. tglyph->saved[0].y = y; 883. tglyph->sidx = 1; 884. 	    }  885.   886.  	    show_glyph(x, y, tglyph->glyph);	/* show it */ 887. 	    flush_screen(0);			/* make sure it shows up */ 888. 	    break; 889.     } /* end case */ 890. }  891.   892.   893.  /*  894.   * swallowed 895.  *  896.   * The hero is swallowed. Show a special graphics sequence for this. This 897.  * bypasses all of the display routines and messes with buffered screen 898.  * directly. This method works because both vision and display check for 899.  * being swallowed. 900.  */  901.  void 902. swallowed(first) 903.     int first; 904. {  905.      static xchar lastx, lasty;	/* last swallowed position */ 906.     int swallower, left_ok, rght_ok; 907.  908.      if (first) 909. 	cls; 910.     else { 911. 	register int x, y;  912. 913. 	/* Clear old location */ 914. 	for (y = lasty-1; y <= lasty+1; y++) 915. 	    for (x = lastx-1; x <= lastx+1; x++) 916. 		if (isok(x,y)) show_glyph(x,y,cmap_to_glyph(S_stone)); 917.     }  918.   919.      swallower = monsndx(u.ustuck->data); 920.     /* assume isok(u.ux,u.uy) */ 921.     left_ok = isok(u.ux-1,u.uy); 922.     rght_ok = isok(u.ux+1,u.uy); 923.     /*  924.       *  Display the hero surrounded by the monster's stomach. 925.      */  926.      if(isok(u.ux, u.uy-1)) { 927. 	if (left_ok) 928. 	show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl)); 929. 	show_glyph(u.ux , u.uy-1, swallow_to_glyph(swallower, S_sw_tc)); 930. 	if (rght_ok) 931. 	show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr)); 932.     }  933.   934.      if (left_ok) 935.     show_glyph(u.ux-1, u.uy , swallow_to_glyph(swallower, S_sw_ml)); 936.     display_self; 937.     if (rght_ok) 938.     show_glyph(u.ux+1, u.uy , swallow_to_glyph(swallower, S_sw_mr)); 939.  940.      if(isok(u.ux, u.uy+1)) { 941. 	if (left_ok) 942. 	show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl)); 943. 	show_glyph(u.ux , u.uy+1, swallow_to_glyph(swallower, S_sw_bc)); 944. 	if (rght_ok) 945. 	show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br)); 946.     }  947.   948.      /* Update the swallowed position. */ 949.      lastx = u.ux; 950.     lasty = u.uy; 951. }  952.   953.  /*  954.   * under_water 955.  *  956.   * Similar to swallowed in operation. Shows hero when underwater 957.  * except when in water level. Special routines exist for that. 958.  */  959.  void 960. under_water(mode) 961.     int mode; 962. {  963.      static xchar lastx, lasty; 964.     static boolean dela; 965.     register int x, y;  966. 967.     /* swallowing has a higher precedence than under water */ 968.     if (Is_waterlevel(&u.uz) || u.uswallow) return; 969.  970.      /* full update */ 971.     if (mode == 1 || dela) { 972. 	cls; 973. 	dela = FALSE; 974.     }  975.      /* delayed full update */ 976.     else if (mode == 2) { 977. 	dela = TRUE; 978. 	return; 979.     }  980.      /* limited update */ 981.     else { 982. 	for (y = lasty-1; y <= lasty+1; y++) 983. 	    for (x = lastx-1; x <= lastx+1; x++) 984. 		if (isok(x,y)) 985. 		    show_glyph(x,y,cmap_to_glyph(S_stone)); 986.     }  987.      for (x = u.ux-1; x <= u.ux+1; x++) 988. 	for (y = u.uy-1; y <= u.uy+1; y++) 989. 	    if (isok(x,y) && is_pool(x,y)) { 990. 		if (Blind && !(x == u.ux && y == u.uy)) 991. 		    show_glyph(x,y,cmap_to_glyph(S_stone)); 992. 		else 993. 		    newsym(x,y); 994. 	    }  995.      lastx = u.ux; 996.     lasty = u.uy; 997. }  998.   999.  /*  1000.  *	under_ground 1001. *  1002.  *	Very restricted display. You can only see yourself. 1003. */  1004. void 1005. under_ground(mode) 1006.    int mode; 1007. { 1008.     static boolean dela; 1009. 1010.     /* swallowing has a higher precedence than under ground */ 1011.    if (u.uswallow) return; 1012. 1013.     /* full update */ 1014.    if (mode == 1 || dela) { 1015. 	cls; 1016. 	dela = FALSE; 1017.    }  1018.     /* delayed full update */ 1019.    else if (mode == 2) { 1020. 	dela = TRUE; 1021. 	return; 1022.    }  1023.     /* limited update */ 1024.    else 1025. 	newsym(u.ux,u.uy); 1026. } 1027.  1028.  1029. /* ========================================================================= */  1030.  1031. /*  1032.  * Loop through all of the monsters and update them. Called when: 1033. *	+ going blind & telepathic 1034. *	+ regaining sight & telepathic 1035. *      + getting and losing infravision 1036. *	+ hallucinating 1037. *	+ doing a full screen redraw 1038. *	+ see invisible times out or a ring of see invisible is taken off 1039. *	+ when a potion of see invisible is quaffed or a ring of see 1040. *	  invisible is put on  1041. *	+ gaining telepathy when blind [givit in eat.c, pleased in pray.c] 1042. *	+ losing telepathy while blind [xkilled in mon.c, attrcurse in 1043. *	 sit.c]  1044. */ 1045. void 1046. see_monsters 1047. { 1048.     register struct monst *mon; 1049.    for (mon = fmon; mon; mon = mon->nmon) { 1050. 	if (DEADMONSTER(mon)) continue; 1051. 	newsym(mon->mx,mon->my); 1052. 	if (mon->wormno) see_wsegs(mon); 1053.    }  1054. }  1055.  1056. /*  1057.  * Block/unblock light depending on what a mimic is mimicing and if it's  1058. * invisible or not. Should be called only when the state of See_invisible 1059. * changes. 1060. */  1061. void 1062. set_mimic_blocking 1063. { 1064.     register struct monst *mon; 1065.    for (mon = fmon; mon; mon = mon->nmon) 1066. 	if(!DEADMONSTER(mon) && mon->minvis && 1067. 	   ((mon->m_ap_type == M_AP_FURNITURE &&  1068. 	      (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))|| 1069. 	   (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) { 1070. 	   if(See_invisible) 1071. 		block_point(mon->mx, mon->my); 1072. 	   else 1073. 		unblock_point(mon->mx, mon->my); 1074. 	} 1075. }  1076.  1077. /*  1078.  * Loop through all of the object *locations* and update them. Called when 1079. *	+ hallucinating. 1080. */  1081. void 1082. see_objects 1083. { 1084.     register struct obj *obj; 1085.    for(obj = fobj; obj; obj = obj->nobj) 1086. 	if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy); 1087. } 1088.  1089. /*  1090.  * Update hallucinated traps. 1091. */  1092. void 1093. see_traps 1094. { 1095.     struct trap *trap; 1096.    int glyph; 1097. 1098.     for (trap = ftrap; trap; trap = trap->ntrap) { 1099. 	glyph = glyph_at(trap->tx, trap->ty); 1100. 	if (glyph_is_trap(glyph)) 1101. 	   newsym(trap->tx, trap->ty); 1102.    }  1103. }  1104.  1105. /*  1106.  * Put the cursor on the hero. Flush all accumulated glyphs before doing it. 1107. */  1108. void 1109. curs_on_u 1110. { 1111.     flush_screen(1);	/* Flush waiting glyphs & put cursor on hero */ 1112. } 1113.  1114. int 1115. doredraw 1116. { 1117.     docrt; 1118.    return 0; 1119. } 1120.  1121. void 1122. docrt 1123. { 1124.     register int x,y; 1125.    register struct rm *lev; 1126. 1127.     if (!u.ux) return; /* display isn't ready yet */ 1128. 1129.     if (u.uswallow) { 1130. 	swallowed(1); 1131. 	return; 1132.    }  1133.     if (Underwater && !Is_waterlevel(&u.uz)) { 1134. 	under_water(1); 1135. 	return; 1136.    }  1137.     if (u.uburied) { 1138. 	under_ground(1); 1139. 	return; 1140.    }  1141.  1142.     /* shut down vision */ 1143.    vision_recalc(2); 1144. 1145.     /*  1146.      * This routine assumes that cls does the following: 1147.     *      + fills the physical screen with the symbol for rock 1148.     *      + clears the glyph buffer 1149.     */  1150.     cls; 1151. 1152.     /* display memory */ 1153.    for (x = 1; x < COLNO; x++) { 1154. 	lev = &levl[x][0]; 1155. 	for (y = 0; y < ROWNO; y++, lev++) 1156. 	   if (lev->glyph != cmap_to_glyph(S_stone)) 1157. 		show_glyph(x,y,lev->glyph); 1158.    }  1159.  1160.     /* see what is to be seen */ 1161.    vision_recalc(0); 1162. 1163.     /* overlay with monsters */ 1164.    see_monsters; 1165. 1166.     flags.botlx = 1;	/* force a redraw of the bottom line */ 1167. } 1168.  1169.  1170. /* ========================================================================= */  1171. /* Glyph Buffering (3rd screen) ============================================ */ 1172. 1173. typedef struct { 1174.    xchar new;		/* perhaps move this bit into the rm strucure. */ 1175.     int   glyph; 1176. } gbuf_entry; 1177. 1178. static gbuf_entry gbuf[ROWNO][COLNO]; 1179. static char gbuf_start[ROWNO]; 1180. static char gbuf_stop[ROWNO]; 1181. 1182. /*  1183.  * Store the glyph in the 3rd screen for later flushing. 1184. */  1185. void 1186. show_glyph(x,y,glyph) 1187.    int x, y, glyph; 1188. { 1189.     /*  1190.      * Check for bad positions and glyphs. 1191.     */  1192.     if (!isok(x, y)) { 1193. 	const char *text; 1194. 	int offset; 1195. 1196. 	/* column 0 is invalid, but it's often used as a flag, so ignore it */ 1197. 	if (x == 0) return; 1198. 1199. 	/*  1200. 	 *  This assumes an ordering of the offsets. See display.h for 1201. 	 * the definition. 1202. 	 */ 1203.  1204. 	if (glyph >= GLYPH_WARNING_OFF) {	/* a warning */ 1205. 	   text = "warning";		offset = glyph - GLYPH_WARNING_OFF; 1206. 	} else if (glyph >= GLYPH_SWALLOW_OFF) {	/* swallow border */ 1207. 	   text = "swallow border";	offset = glyph - GLYPH_SWALLOW_OFF; 1208. 	} else if (glyph >= GLYPH_ZAP_OFF) {		/* zap beam */ 1209. 	   text = "zap beam";		offset = glyph - GLYPH_ZAP_OFF; 1210. 	} else if (glyph >= GLYPH_EXPLODE_OFF) {	/* explosion */ 1211. 	   text = "explosion";		offset = glyph - GLYPH_EXPLODE_OFF; 1212. 	} else if (glyph >= GLYPH_CMAP_OFF) {		/* cmap */ 1213. 	   text = "cmap_index";	offset = glyph - GLYPH_CMAP_OFF; 1214. 	} else if (glyph >= GLYPH_OBJ_OFF) {		/* object */ 1215. 	   text = "object";		offset = glyph - GLYPH_OBJ_OFF; 1216. 	} else if (glyph >= GLYPH_RIDDEN_OFF) {		/* ridden mon */ 1217. 	   text = "ridden mon";	offset = glyph - GLYPH_RIDDEN_OFF; 1218. 	} else if (glyph >= GLYPH_BODY_OFF) {		/* a corpse */ 1219. 	   text = "corpse";		offset = glyph - GLYPH_BODY_OFF; 1220. 	} else if (glyph >= GLYPH_DETECT_OFF) {		/* detected mon */ 1221. 	   text = "detected mon";	offset = glyph - GLYPH_DETECT_OFF; 1222. 	} else if (glyph >= GLYPH_INVIS_OFF) {		/* invisible mon */ 1223. 	   text = "invisible mon";	offset = glyph - GLYPH_INVIS_OFF; 1224. 	} else if (glyph >= GLYPH_PET_OFF) {		/* a pet */ 1225. 	   text = "pet";		offset = glyph - GLYPH_PET_OFF; 1226. 	} else {					/* a monster */ 1227. 	   text = "monster";		offset = glyph; 1228. 	} 1229.  1230. 	impossible("show_glyph:  bad pos %d %d with glyph %d [%s %d].",  1231. 						x, y, glyph, text, offset); 1232. 	return; 1233.    }  1234.  1235.     if (glyph >= MAX_GLYPH) { 1236. 	impossible("show_glyph: bad glyph %d [max %d] at (%d,%d).",  1237. 					glyph, MAX_GLYPH, x, y); 1238. 	return; 1239.    }  1240.  1241.     if (gbuf[y][x].glyph != glyph) { 1242. 	gbuf[y][x].glyph = glyph; 1243. 	gbuf[y][x].new  = 1; 1244. 	if (gbuf_start[y] > x) gbuf_start[y] = x; 1245. if (gbuf_stop[y] < x) gbuf_stop[y]  = x;  1246. } 1247. }  1248.  1249.  1250. /*  1251.  * Reset the changed glyph borders so that none of the 3rd screen has 1252. * changed. 1253. */  1254. #define reset_glyph_bbox			\ 1255.    {						\  1256. 	int i;					\ 1257. 						\ 1258. 	for (i = 0; i < ROWNO; i++) {		\ 1259. 	   gbuf_start[i] = COLNO-1;		\ 1260. 	   gbuf_stop[i]  = 0;			\ 1261. 	}					\ 1262.     }  1263.  1264.  1265. static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) }; 1266. /* 1267.  * Turn the 3rd screen into stone. 1268. */  1269. void 1270. clear_glyph_buffer 1271. { 1272.     register int x, y;  1273. register gbuf_entry *gptr; 1274. 1275.     for (y = 0; y < ROWNO; y++) { 1276. 	gptr = &gbuf[y][0]; 1277. 	for (x = COLNO; x; x--) { 1278. 	   *gptr++ = nul_gbuf; 1279. 	} 1280.     }  1281.     reset_glyph_bbox; 1282. } 1283.  1284. /*  1285.  * Assumes that the indicated positions are filled with S_stone glyphs. 1286. */  1287. void 1288. row_refresh(start,stop,y) 1289.    int start,stop,y; 1290. { 1291.     register int x;  1292. 1293.    for (x = start; x <= stop; x++) 1294. 	if (gbuf[y][x].glyph != cmap_to_glyph(S_stone)) 1295. 	   print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph); 1296. } 1297.  1298. void 1299. cls 1300. { 1301.     display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */ 1302.    flags.botlx = 1;		/* force update of botl window */ 1303.    clear_nhwindow(WIN_MAP);	/* clear physical screen */ 1304. 1305.     clear_glyph_buffer;	/* this is sort of an extra effort, but OK */ 1306. } 1307.  1308. /*  1309.  * Synch the third screen with the display. 1310. */  1311. void 1312. flush_screen(cursor_on_u) 1313.    int cursor_on_u; 1314. { 1315.     /* Prevent infinite loops on errors: 1316.     *	    flush_screen->print_glyph->impossible->pline->flush_screen 1317.     */  1318.     static   boolean flushing = 0; 1319.    register int x,y; 1320. 1321.     if (flushing) return;	/* if already flushing then return */ 1322.    flushing = 1; 1323. 1324.     for (y = 0; y < ROWNO; y++) { 1325. 	register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]]; 1326. 	for (x <= gbuf_stop[y]; gptr++, x++) 1327. 	   if (gptr->new) { 1328. 		print_glyph(WIN_MAP,x,y,gptr->glyph); 1329. 		gptr->new = 0; 1330. 	   }  1331.     }  1332.  1333.     if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */ 1334.    display_nhwindow(WIN_MAP, FALSE); 1335.    reset_glyph_bbox; 1336.    flushing = 0; 1337.    if(flags.botl || flags.botlx) bot; 1338. } 1339.  1340. /* ========================================================================= */  1341.  1342. /*  1343.  * back_to_glyph 1344. *  1345.  * Use the information in the rm structure at the given position to create 1346. * a glyph of a background. 1347. *  1348.  * I had to add a field in the rm structure (horizontal) so that we knew 1349. * if open doors and secret doors were horizontal or vertical. Previously, 1350. * the screen symbol had the horizontal/vertical information set at  1351. * level generation time. 1352. *  1353.  * I used the 'ladder' field (really doormask) for deciding if stairwells 1354. * were up or down. I didn't want to check the upstairs and dnstairs 1355. * variables. 1356. */  1357. int 1358. back_to_glyph(x,y) 1359.    xchar x,y; 1360. { 1361.     int idx; 1362.    struct rm *ptr = &(levl[x][y]); 1363. 1364.     switch (ptr->typ) { 1365. 	case SCORR: 1366. 	case STONE: 1367. 	   idx = level.flags.arboreal ? S_tree : S_stone; 1368. 	   break; 1369. 	case ROOM:		idx = S_room;	 break; 1370. 	case CORR: 1371. 	   idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr; 1372. 	   break; 1373. 	case HWALL: 1374. 	case VWALL: 1375. 	case TLCORNER: 1376. 	case TRCORNER: 1377. 	case BLCORNER: 1378. 	case BRCORNER: 1379. 	case CROSSWALL: 1380. 	case TUWALL: 1381. 	case TDWALL: 1382. 	case TLWALL: 1383. 	case TRWALL: 1384. 	case SDOOR: 1385. 	   idx = ptr->seenv ? wall_angle(ptr) : S_stone; 1386. 	   break; 1387. 	case DOOR: 1388. 	   if (ptr->doormask) { 1389. 		if (ptr->doormask & D_BROKEN) 1390. 		   idx = S_ndoor; 1391. 		else if (ptr->doormask & D_ISOPEN) 1392. 		   idx = (ptr->horizontal) ? S_hodoor : S_vodoor; 1393. 		else			/* else is closed */ 1394. 		   idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor; 1395. 	   } else 1396. 		idx = S_ndoor; 1397. 	   break; 1398. 	case IRONBARS:	idx = S_bars;    break; 1399. 	case TREE:		idx = S_tree;    break; 1400. 	case POOL: 1401. 	case MOAT:		idx = S_pool;	 break; 1402. 	case STAIRS: 1403. 	   idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair; 1404. 	   break; 1405. 	case LADDER: 1406. 	   idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder; 1407. 	   break; 1408. 	case FOUNTAIN:		idx = S_fountain; break; 1409. 	case SINK:		idx = S_sink;    break; 1410. 	case ALTAR:		idx = S_altar;   break; 1411. 	case GRAVE:		idx = S_grave;   break; 1412. 	case THRONE:		idx = S_throne;  break; 1413. 	case LAVAPOOL:		idx = S_lava;	 break; 1414. 	case ICE:		idx = S_ice;     break; 1415. 	case AIR:		idx = S_air;	 break; 1416. 	case CLOUD:		idx = S_cloud;	 break; 1417. 	case WATER:		idx = S_water;	 break; 1418. 	case DBWALL: 1419. 	   idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge; 1420. 	   break; 1421. 	case DRAWBRIDGE_UP: 1422. 	   switch(ptr->drawbridgemask & DB_UNDER) { 1423. 	   case DB_MOAT:  idx = S_pool; break; 1424. 	   case DB_LAVA:  idx = S_lava; break; 1425. 	   case DB_ICE:   idx = S_ice;  break; 1426. 	   case DB_FLOOR: idx = S_room; break; 1427. 	   default: 1428. 		impossible("Strange db-under: %d", 1429. 			   ptr->drawbridgemask & DB_UNDER); 1430. 		idx = S_room; /* something is better than nothing */ 1431. 		break; 1432. 	   }  1433. 	    break; 1434. 	case DRAWBRIDGE_DOWN: 1435. 	   idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge; 1436. 	   break; 1437. 	default: 1438. 	   impossible("back_to_glyph:  unknown level type [ = %d ]",ptr->typ); 1439. 	   idx = S_room; 1440. 	   break; 1441.    }  1442.  1443.     return cmap_to_glyph(idx); 1444. } 1445.  1446.  1447. /*  1448.  * swallow_to_glyph 1449. *  1450.  * Convert a monster number and a swallow location into the correct glyph. 1451. * If you don't want a patchwork monster while hallucinating, decide on  1452. * a random monster in swallowed and don't use what_mon here. 1453. */  1454. STATIC_OVL int 1455. swallow_to_glyph(mnum, loc) 1456.    int mnum; 1457.    int loc; 1458. { 1459.     if (loc < S_sw_tl || S_sw_br < loc) { 1460. 	impossible("swallow_to_glyph: bad swallow location"); 1461. 	loc = S_sw_br; 1462.    }  1463.     return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF; 1464. } 1465.  1466.  1467.  1468. /*  1469.  * zapdir_to_glyph 1470. *  1471.  * Change the given zap direction and beam type into a glyph. Each beam 1472. * type has four glyphs, one for each of the symbols below. The order of 1473. * the zap symbols [0-3] as defined in rm.h are: 1474. *  1475.  *	|  S_vbeam	( 0, 1) or ( 0,-1) 1476. *	-  S_hbeam	( 1, 0) or (-1,	0) 1477. *	\  S_lslant	( 1, 1) or (-1,-1) 1478. *	/  S_rslant	(-1, 1) or ( 1,-1) 1479. */  1480. int 1481. zapdir_to_glyph(dx, dy, beam_type) 1482.    register int dx, dy; 1483.    int beam_type; 1484. { 1485.     if (beam_type >= NUM_ZAP) { 1486. 	impossible("zapdir_to_glyph: illegal beam type"); 1487. 	beam_type = 0; 1488.    }  1489.     dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0; 1490.  1491.     return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF; 1492. } 1493.  1494.  1495. /*  1496.  * Utility routine for dowhatis used to find out the glyph displayed at  1497. * the location. This isn't necessarily the same as the glyph in the levl 1498. * structure, so we must check the "third screen". 1499. */  1500. int 1501. glyph_at(x, y) 1502. xchar x,y; 1503. { 1504.     if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO) 1505. 	return cmap_to_glyph(S_room);			/* XXX */ 1506.    return gbuf[y][x].glyph; 1507. } 1508.  1509.  1510. /* - */  1511. /* Wall Angle -- */ 1512. 1513. /*#define WA_VERBOSE*/	/* give (x,y) locations for all "bad" spots */ 1514. 1515. #ifdef WA_VERBOSE 1516. 1517. static const char *FDECL(type_to_name, (int)); 1518. static void FDECL(error4, (int,int,int,int,int,int)); 1519. 1520. static int bad_count[MAX_TYPE]; /* count of positions flagged as bad */ 1521. static const char *type_names[MAX_TYPE] = { 1522. 	"STONE",	"VWALL",	"HWALL",	"TLCORNER", 1523. 	"TRCORNER",	"BLCORNER",	"BRCORNER",	"CROSSWALL", 1524. 	"TUWALL",	"TDWALL",	"TLWALL",	"TRWALL", 1525. 	"DBWALL",	"SDOOR",	"SCORR",	"POOL", 1526. 	"MOAT",		"WATER",	"DRAWBRIDGE_UP","LAVAPOOL", 1527. 	"DOOR",		"CORR",		"ROOM",		"STAIRS", 1528. 	"LADDER",	"FOUNTAIN",	"THRONE",	"SINK", 1529. 	"ALTAR",	"ICE",		"DRAWBRIDGE_DOWN","AIR", 1530. 	"CLOUD" 1531. }; 1532.  1533.  1534. static const char * 1535. type_to_name(type) 1536.    int type; 1537. { 1538.     return (type < 0 || type > MAX_TYPE) ? "unknown" : type_names[type]; 1539. } 1540.  1541. static void 1542. error4(x, y, a, b, c, dd) 1543.    int x, y, a, b, c, dd; 1544. { 1545.     pline("set_wall_state: %s @ (%d,%d) %s%s%s%s",  1546. 	type_to_name(levl[x][y].typ), x, y,  1547. 	a ? "1":"", b ? "2":"", c ? "3":"", dd ? "4":""); 1548.    bad_count[levl[x][y].typ]++; 1549. } 1550. #endif /* WA_VERBOSE */ 1551. 1552. /*  1553.  * Return 'which' if position is implies an unfinshed exterior. Return 1554. * zero otherwise. Unfinished implies outer area is rock or a corridor. 1555. *  1556.  * Things that are ambigious: lava 1557. */  1558. STATIC_OVL int 1559. check_pos(x, y, which) 1560.    int x, y, which; 1561. { 1562.     int type; 1563.    if (!isok(x,y)) return which; 1564.    type = levl[x][y].typ; 1565.    if (IS_ROCK(type) || type == CORR || type == SCORR) return which; 1566.    return 0; 1567. } 1568.  1569. /* Return TRUE if more than one is non-zero. */ 1570. /*ARGSUSED*/ 1571. #ifdef WA_VERBOSE 1572. STATIC_OVL boolean 1573. more_than_one(x, y, a, b, c) 1574. int x, y, a, b, c; 1575. { 1576.     if ((a && (b|c)) || (b && (a|c)) || (c && (a|b))) { 1577. 	error4(x,y,a,b,c,0); 1578. 	return TRUE; 1579.    }  1580.     return FALSE; 1581. } 1582. #else 1583. #define more_than_one(x, y, a, b, c) (((a) && ((b)|(c))) || ((b) && ((a)|(c))) || ((c) && ((a)|(b)))) 1584. #endif 1585. 1586. /* Return the wall mode for a T wall. */ 1587. STATIC_OVL int 1588. set_twall(x0,y0, x1,y1, x2,y2, x3,y3) 1589. int x0,y0, x1,y1, x2,y2, x3,y3; 1590. { 1591.     int wmode, is_1, is_2, is_3; 1592. 1593.     is_1 = check_pos(x1, y1, WM_T_LONG); 1594.    is_2 = check_pos(x2, y2, WM_T_BL); 1595.    is_3 = check_pos(x3, y3, WM_T_BR); 1596.    if (more_than_one(x0, y0, is_1, is_2, is_3)) { 1597. 	wmode = 0; 1598.    } else { 1599. 	wmode = is_1 + is_2 + is_3; 1600.    }  1601.     return wmode; 1602. } 1603.  1604. /* Return wall mode for a horizontal or vertical wall. */ 1605. STATIC_OVL int 1606. set_wall(x, y, horiz) 1607.    int x, y, horiz; 1608. { 1609.     int wmode, is_1, is_2; 1610. 1611.     if (horiz) { 1612. 	is_1 = check_pos(x,y-1, WM_W_TOP); 1613. 	is_2 = check_pos(x,y+1, WM_W_BOTTOM); 1614.    } else { 1615. 	is_1 = check_pos(x-1,y, WM_W_LEFT); 1616. 	is_2 = check_pos(x+1,y, WM_W_RIGHT); 1617.    }  1618.     if (more_than_one(x, y, is_1, is_2, 0)) { 1619. 	wmode = 0; 1620.    } else { 1621. 	wmode = is_1 + is_2; 1622.    }  1623.     return wmode; 1624. } 1625.  1626.  1627. /* Return a wall mode for a corner wall. (x4,y4) is the "inner" position. */ 1628. STATIC_OVL int 1629. set_corn(x1,y1, x2,y2, x3,y3, x4,y4) 1630. 	int x1, y1, x2, y2, x3, y3, x4, y4; 1631. { 1632.     int wmode, is_1, is_2, is_3, is_4; 1633. 1634.     is_1 = check_pos(x1, y1, 1); 1635.    is_2 = check_pos(x2, y2, 1); 1636.    is_3 = check_pos(x3, y3, 1); 1637.    is_4 = check_pos(x4, y4, 1);	/* inner location */ 1638. 1639.     /*  1640.      * All 4 should not be true. So if the inner location is rock, 1641.     * use it. If all of the outer 3 are true, use outer. We currently 1642.     * can't cover the case where only part of the outer is rock, so  1643. * we just say that all the walls are finished (if not overridden 1644.      * by the inner section). 1645.     */  1646.     if (is_4) { 1647. 	wmode = WM_C_INNER; 1648.    } else if (is_1 && is_2 && is_3) 1649. 	wmode = WM_C_OUTER; 1650.     else 1651. 	wmode = 0;	/* finished walls on all sides */ 1652. 1653.     return wmode; 1654. } 1655.  1656. /* Return mode for a crosswall. */ 1657. STATIC_OVL int 1658. set_crosswall(x, y) 1659. int x, y; 1660. { 1661.     int wmode, is_1, is_2, is_3, is_4; 1662. 1663.     is_1 = check_pos(x-1, y-1, 1); 1664.    is_2 = check_pos(x+1, y-1, 1); 1665.    is_3 = check_pos(x+1, y+1, 1); 1666.    is_4 = check_pos(x-1, y+1, 1); 1667. 1668.     wmode = is_1+is_2+is_3+is_4; 1669.    if (wmode > 1) { 1670. 	if (is_1 && is_3 && (is_2+is_4 == 0)) { 1671. 	   wmode = WM_X_TLBR; 1672. 	} else if (is_2 && is_4 && (is_1+is_3 == 0)) { 1673. 	   wmode = WM_X_BLTR; 1674. 	} else { 1675. #ifdef WA_VERBOSE 1676. 	   error4(x,y,is_1,is_2,is_3,is_4); 1677. #endif 1678. 	   wmode = 0; 1679. 	} 1680.     } else if (is_1) 1681. 	wmode = WM_X_TL; 1682.    else if (is_2) 1683. 	wmode = WM_X_TR; 1684.    else if (is_3) 1685. 	wmode = WM_X_BR; 1686.    else if (is_4) 1687. 	wmode = WM_X_BL; 1688. 1689.     return wmode; 1690. } 1691.  1692. /* Called from mklev. Scan the level and set the wall modes. */ 1693. void 1694. set_wall_state 1695. { 1696.     int x, y;  1697. int wmode; 1698.    struct rm *lev; 1699. 1700. #ifdef WA_VERBOSE 1701.    for (x = 0; x < MAX_TYPE; x++) bad_count[x] = 0; 1702. #endif 1703. 1704.     for (x = 0; x < COLNO; x++) 1705. 	for (lev = &levl[x][0], y = 0; y < ROWNO; y++, lev++) { 1706. 	   switch (lev->typ) { 1707. 		case SDOOR: 1708. 		   wmode = set_wall(x, y, (int) lev->horizontal); 1709. 		   break; 1710. 		case VWALL: 1711. 		   wmode = set_wall(x, y, 0); 1712. 		   break; 1713. 		case HWALL: 1714. 		   wmode = set_wall(x, y, 1); 1715. 		   break; 1716. 		case TDWALL: 1717. 		   wmode = set_twall(x,y, x,y-1, x-1,y+1, x+1,y+1); 1718. 		   break; 1719. 		case TUWALL: 1720. 		   wmode = set_twall(x,y, x,y+1, x+1,y-1, x-1,y-1); 1721. 		   break; 1722. 		case TLWALL: 1723. 		   wmode = set_twall(x,y, x+1,y, x-1,y-1, x-1,y+1); 1724. 		   break; 1725. 		case TRWALL: 1726. 		   wmode = set_twall(x,y, x-1,y, x+1,y+1, x+1,y-1); 1727. 		   break; 1728. 		case TLCORNER: 1729. 		   wmode = set_corn(x-1,y-1, x,y-1, x-1,y, x+1,y+1); 1730. 		   break; 1731. 		case TRCORNER: 1732. 		   wmode = set_corn(x,y-1, x+1,y-1, x+1,y, x-1,y+1); 1733. 		   break; 1734. 		case BLCORNER: 1735. 		   wmode = set_corn(x,y+1, x-1,y+1, x-1,y, x+1,y-1); 1736. 		   break; 1737. 		case BRCORNER: 1738. 		   wmode = set_corn(x+1,y, x+1,y+1, x,y+1, x-1,y-1); 1739. 		   break; 1740. 		case CROSSWALL: 1741. 		   wmode = set_crosswall(x, y); 1742. 		   break; 1743. 1744. 		default: 1745. 		   wmode = -1;	/* don't set wall info */ 1746. 		   break; 1747. 	   }  1748.  1749. 	if (wmode >= 0) 1750. 	   lev->wall_info = (lev->wall_info & ~WM_MASK) | wmode; 1751. 	} 1752.  1753. #ifdef WA_VERBOSE 1754.    /* check if any bad positions found */ 1755.    for (x = y = 0; x < MAX_TYPE; x++) 1756. 	if (bad_count[x]) { 1757. 	   if (y == 0) { 1758. 		y = 1;	/* only print once */ 1759. 		pline("set_wall_type: wall mode problems with: "); 1760. 	   }  1761. 	    pline("%s %d;", type_names[x], bad_count[x]); 1762. 	} 1763. #endif /* WA_VERBOSE */ 1764. } 1765.  1766. /* - */  1767. /* This matrix is used here and in vision.c. */ 1768. unsigned char seenv_matrix[3][3] = { {SV2,  SV1, SV0}, 1769. 				    {SV3, SVALL, SV7}, 1770. 				    {SV4,   SV5, SV6} }; 1771. 1772. #define sign(z) ((z) < 0 ? -1 : ((z) > 0 ? 1 : 0)) 1773.  1774. /* Set the seen vector of lev as if seen from (x0,y0) to (x,y). */ 1775. STATIC_OVL void 1776. set_seenv(lev, x0, y0, x, y) 1777. struct rm *lev; 1778.    int x0, y0, x, y;	/* from, to */ 1779. { 1780.     int dx = x-x0, dy = y0-y; 1781.    lev->seenv |= seenv_matrix[sign(dy)+1][sign(dx)+1]; 1782. } 1783.  1784. /* - */  1785.  1786. /* T wall types, one for each row in wall_matrix[][]. */ 1787. #define T_d 0 1788. #define T_l 1 1789. #define T_u 2 1790. #define T_r 3 1791. 1792. /*  1793.  * These are the column names of wall_matrix[][]. They are the "results" 1794. * of a tdwall pattern match. All T walls are rotated so they become 1795. * a tdwall. Then we do a single pattern match, but return the 1796. * correct result for the original wall by using different rows for 1797. * each of the wall types. 1798. */  1799. #define T_stone  0 1800. #define T_tlcorn 1 1801. #define T_trcorn 2 1802. #define T_hwall 3 1803. #define T_tdwall 4 1804. 1805. static const int wall_matrix[4][5] = { 1806.    { S_stone, S_tlcorn, S_trcorn, S_hwall, S_tdwall },	/* tdwall */ 1807.    { S_stone, S_trcorn, S_brcorn, S_vwall, S_tlwall },	/* tlwall */ 1808.    { S_stone, S_brcorn, S_blcorn, S_hwall, S_tuwall },	/* tuwall */ 1809.    { S_stone, S_blcorn, S_tlcorn, S_vwall, S_trwall },	/* trwall */ 1810. }; 1811.  1812.  1813. /* Cross wall types, one for each "solid" quarter. Rows of cross_matrix[][]. */ 1814. #define C_bl 0 1815. #define C_tl 1 1816. #define C_tr 2 1817. #define C_br 3 1818. 1819. /*  1820.  * These are the column names for cross_matrix[][]. They express results 1821. * in C_br (bottom right) terms. All crosswalls with a single solid 1822. * quarter are rotated so the solid section is at the bottom right. 1823. * We pattern match on that, but return the correct result depending 1824. * on which row we'ere looking at. 1825. */  1826. #define C_trcorn 0 1827. #define C_brcorn 1 1828. #define C_blcorn 2 1829. #define C_tlwall 3 1830. #define C_tuwall 4 1831. #define C_crwall 5 1832. 1833. static const int cross_matrix[4][6] = { 1834.    { S_brcorn, S_blcorn, S_tlcorn, S_tuwall, S_trwall, S_crwall }, 1835.    { S_blcorn, S_tlcorn, S_trcorn, S_trwall, S_tdwall, S_crwall }, 1836.    { S_tlcorn, S_trcorn, S_brcorn, S_tdwall, S_tlwall, S_crwall }, 1837.    { S_trcorn, S_brcorn, S_blcorn, S_tlwall, S_tuwall, S_crwall }, 1838. }; 1839.  1840.  1841. /* Print out a T wall warning and all interesting info. */ 1842. STATIC_OVL void 1843. t_warn(lev) 1844.    struct rm *lev; 1845. { 1846.     static const char *warn_str = "wall_angle: %s: case %d: seenv = 0x%x"; 1847.    const char *wname; 1848. 1849.     if (lev->typ == TUWALL) wname = "tuwall"; 1850.    else if (lev->typ == TLWALL) wname = "tlwall"; 1851.    else if (lev->typ == TRWALL) wname = "trwall"; 1852.    else if (lev->typ == TDWALL) wname = "tdwall"; 1853.    else wname = "unknown"; 1854.    impossible(warn_str, wname, lev->wall_info & WM_MASK,  1855. 	(unsigned int) lev->seenv); 1856. } 1857.  1858.  1859. /*  1860.  * Return the correct graphics character index using wall type, wall mode, 1861. * and the seen vector. It is expected that seenv is non zero. 1862. *  1863.  * All T-wall vectors are rotated to be TDWALL. All single crosswall 1864. * blocks are rotated to bottom right. All double crosswall are rotated 1865. * to W_X_BLTR. All results are converted back. 1866. *  1867.  * The only way to understand this is to take out pen and paper and 1868. * draw diagrams. See rm.h for more details on the wall modes and 1869. * seen vector (SV). 1870. */  1871. STATIC_OVL int 1872. wall_angle(lev) 1873.    struct rm *lev; 1874. { 1875.     register unsigned int seenv = lev->seenv & 0xff; 1876.    const int *row; 1877.    int col, idx; 1878. 1879. #define only(sv, bits)	(((sv) & (bits)) && ! ((sv) & ~(bits))) 1880.    switch (lev->typ) { 1881. 	case TUWALL: 1882. 		row = wall_matrix[T_u]; 1883. 		seenv = (seenv >> 4 | seenv << 4) & 0xff;/* rotate to tdwall */ 1884. 		goto do_twall; 1885. 	case TLWALL: 1886. 		row = wall_matrix[T_l]; 1887. 		seenv = (seenv >> 2 | seenv << 6) & 0xff;/* rotate to tdwall */ 1888. 		goto do_twall; 1889. 	case TRWALL: 1890. 		row = wall_matrix[T_r]; 1891. 		seenv = (seenv >> 6 | seenv << 2) & 0xff;/* rotate to tdwall */ 1892. 		goto do_twall; 1893. 	case TDWALL: 1894. 		row = wall_matrix[T_d]; 1895. do_twall: 1896. 		switch (lev->wall_info & WM_MASK) { 1897. 		   case 0: 1898. 			if (seenv == SV4) { 1899. 			   col = T_tlcorn; 1900. 			} else if (seenv == SV6) { 1901. 			   col = T_trcorn; 1902. 			} else if (seenv & (SV3|SV5|SV7) || 1903. 					    ((seenv & SV4) && (seenv & SV6))) { 1904. 			   col = T_tdwall; 1905. 			} else if (seenv & (SV0|SV1|SV2)) { 1906. 			   col = (seenv & (SV4|SV6) ? T_tdwall : T_hwall); 1907. 			} else { 1908. 			   t_warn(lev); 1909. 			   col = T_stone; 1910. 			} 1911. 			break; 1912. 		   case WM_T_LONG: 1913. 			if (seenv & (SV3|SV4) && !(seenv & (SV5|SV6|SV7))) { 1914. 			   col = T_tlcorn; 1915. 			} else if (seenv&(SV6|SV7) && !(seenv&(SV3|SV4|SV5))) { 1916. 			   col = T_trcorn; 1917. 			} else if ((seenv & SV5) || 1918. 				((seenv & (SV3|SV4)) && (seenv & (SV6|SV7)))) { 1919. 			   col = T_tdwall; 1920. 			} else { 1921. 			   /* only SV0|SV1|SV2 */ 1922. 			   if (! only(seenv, SV0|SV1|SV2) ) 1923. 				t_warn(lev); 1924. 			   col = T_stone; 1925. 			} 1926. 			break; 1927. 		   case WM_T_BL: 1928. #if 0	/* older method, fixed */ 1929. 			if (only(seenv, SV4|SV5)) { 1930. 			   col = T_tlcorn; 1931. 			} else if ((seenv & (SV0|SV1|SV2)) && 1932. 					only(seenv, SV0|SV1|SV2|SV6|SV7)) { 1933. 			   col = T_hwall; 1934. 			} else if (seenv & SV3 || 1935. 			    ((seenv & (SV0|SV1|SV2)) && (seenv & (SV4|SV5)))) { 1936. 			   col = T_tdwall; 1937. 			} else { 1938. 			   if (seenv != SV6) 1939. 				t_warn(lev); 1940. 			   col = T_stone; 1941. 			} 1942. #endif	/* 0 */ 1943. 			if (only(seenv, SV4|SV5)) 1944. 			   col = T_tlcorn; 1945. 			else if ((seenv & (SV0|SV1|SV2|SV7)) && 1946. 					!(seenv & (SV3|SV4|SV5))) 1947. 			   col = T_hwall; 1948. 			else if (only(seenv, SV6)) 1949. 			   col = T_stone; 1950. 			else 1951. 			   col = T_tdwall; 1952. 			break; 1953. 		   case WM_T_BR: 1954. #if 0	/* older method, fixed */ 1955. 			if (only(seenv, SV5|SV6)) { 1956. 			   col = T_trcorn; 1957. 			} else if ((seenv & (SV0|SV1|SV2)) && 1958. 					    only(seenv, SV0|SV1|SV2|SV3|SV4)) { 1959. 			   col = T_hwall; 1960. 			} else if (seenv & SV7 || 1961. 			    ((seenv & (SV0|SV1|SV2)) && (seenv & (SV5|SV6)))) { 1962. 			   col = T_tdwall; 1963. 			} else { 1964. 			   if (seenv != SV4) 1965. 				t_warn(lev); 1966. 			   col = T_stone; 1967. 			} 1968. #endif	/* 0 */ 1969. 			if (only(seenv, SV5|SV6)) 1970. 			   col = T_trcorn; 1971. 			else if ((seenv & (SV0|SV1|SV2|SV3)) && 1972. 					!(seenv & (SV5|SV6|SV7))) 1973. 			   col = T_hwall; 1974. 			else if (only(seenv, SV4)) 1975. 			   col = T_stone; 1976. 			else 1977. 			   col = T_tdwall; 1978. 1979. 			break; 1980. 		   default: 1981. 			impossible("wall_angle: unknown T wall mode %d", 1982. 				lev->wall_info & WM_MASK); 1983. 			col = T_stone; 1984. 			break; 1985. 		} 1986. 		idx = row[col]; 1987. 		break; 1988. 1989. 	case SDOOR: 1990. 		if (lev->horizontal) goto horiz; 1991. 		/* fall through */ 1992. 	case VWALL: 1993. 		switch (lev->wall_info & WM_MASK) { 1994. 		   case 0: idx = seenv ? S_vwall : S_stone; break; 1995. 		   case 1: idx = seenv & (SV1|SV2|SV3|SV4|SV5) ? S_vwall : 1996. 								 S_stone; 1997. 			   break; 1998. 		   case 2: idx = seenv & (SV0|SV1|SV5|SV6|SV7) ? S_vwall : 1999. 								 S_stone; 2000. 			   break; 2001. 		   default: 2002. 			impossible("wall_angle: unknown vwall mode %d", 2003. 				lev->wall_info & WM_MASK); 2004. 			idx = S_stone; 2005. 			break; 2006. 		} 2007. 		break; 2008. 2009. 	case HWALL: 2010. horiz: 2011. 		switch (lev->wall_info & WM_MASK) { 2012. 		   case 0: idx = seenv ? S_hwall : S_stone; break; 2013. 		   case 1: idx = seenv & (SV3|SV4|SV5|SV6|SV7) ? S_hwall : 2014. 								 S_stone; 2015. 			   break; 2016. 		   case 2: idx = seenv & (SV0|SV1|SV2|SV3|SV7) ? S_hwall : 2017. 								 S_stone; 2018. 			   break; 2019. 		   default: 2020. 			impossible("wall_angle: unknown hwall mode %d", 2021. 				lev->wall_info & WM_MASK); 2022. 			idx = S_stone; 2023. 			break; 2024. 		} 2025. 		break; 2026. 2027. #define set_corner(idx, lev, which, outer, inner, name)	\ 2028.    switch ((lev)->wall_info & WM_MASK) {				    \ 2029. 	case 0:		 idx = which; break;				   \ 2030. 	case WM_C_OUTER: idx = seenv & (outer) ? which : S_stone; break;  \ 2031. 	case WM_C_INNER: idx = seenv & ~(inner) ? which : S_stone; break;  \ 2032. 	default:							   \ 2033. 	   impossible("wall_angle: unknown %s mode %d", name,		    \  2034. 		(lev)->wall_info & WM_MASK);				    \ 2035. 	   idx = S_stone;						    \ 2036. 	   break;							    \ 2037.    }  2038.  2039. 	case TLCORNER: 2040. 	   set_corner(idx, lev, S_tlcorn, (SV3|SV4|SV5), SV4, "tlcorn"); 2041. 	   break; 2042. 	case TRCORNER: 2043. 	   set_corner(idx, lev, S_trcorn, (SV5|SV6|SV7), SV6, "trcorn"); 2044. 	   break; 2045. 	case BLCORNER: 2046. 	   set_corner(idx, lev, S_blcorn, (SV1|SV2|SV3), SV2, "blcorn"); 2047. 	   break; 2048. 	case BRCORNER: 2049. 	   set_corner(idx, lev, S_brcorn, (SV7|SV0|SV1), SV0, "brcorn"); 2050. 	   break; 2051. 2052.  2053. 	case CROSSWALL: 2054. 		switch (lev->wall_info & WM_MASK) { 2055. 		   case 0: 2056. 			if (seenv == SV0) 2057. 			   idx = S_brcorn; 2058. 			else if (seenv == SV2) 2059. 			   idx = S_blcorn; 2060. 			else if (seenv == SV4) 2061. 			   idx = S_tlcorn; 2062. 			else if (seenv == SV6) 2063. 			   idx = S_trcorn; 2064. 			else if (!(seenv & ~(SV0|SV1|SV2)) && 2065. 					(seenv & SV1 || seenv == (SV0|SV2))) 2066. 			   idx = S_tuwall; 2067. 			else if (!(seenv & ~(SV2|SV3|SV4)) && 2068. 					(seenv & SV3 || seenv == (SV2|SV4))) 2069. 			   idx = S_trwall; 2070. 			else if (!(seenv & ~(SV4|SV5|SV6)) && 2071. 					(seenv & SV5 || seenv == (SV4|SV6))) 2072. 			   idx = S_tdwall; 2073. 			else if (!(seenv & ~(SV0|SV6|SV7)) && 2074. 					(seenv & SV7 || seenv == (SV0|SV6))) 2075. 			   idx = S_tlwall; 2076. 			else 2077. 			   idx = S_crwall; 2078. 			break; 2079. 2080. 		    case WM_X_TL: 2081. 			row = cross_matrix[C_tl]; 2082. 			seenv = (seenv >> 4 | seenv << 4) & 0xff; 2083. 			goto do_crwall; 2084. 		   case WM_X_TR: 2085. 			row = cross_matrix[C_tr]; 2086. 			seenv = (seenv >> 6 | seenv << 2) & 0xff; 2087. 			goto do_crwall; 2088. 		   case WM_X_BL: 2089. 			row = cross_matrix[C_bl]; 2090. 			seenv = (seenv >> 2 | seenv << 6) & 0xff; 2091. 			goto do_crwall; 2092. 		   case WM_X_BR: 2093. 			row = cross_matrix[C_br]; 2094. do_crwall: 2095. 			if (seenv == SV4) 2096. 			   idx = S_stone; 2097. 			else { 2098. 			   seenv = seenv & ~SV4;	/* strip SV4 */ 2099. 			   if (seenv == SV0) { 2100. 				col = C_brcorn; 2101. 			   } else if (seenv & (SV2|SV3)) { 2102. 				if (seenv & (SV5|SV6|SV7)) 2103. 				   col = C_crwall; 2104. 				else if (seenv & (SV0|SV1)) 2105. 				   col = C_tuwall; 2106. 				else 2107. 				   col = C_blcorn; 2108. 			   } else if (seenv & (SV5|SV6)) { 2109. 				if (seenv & (SV1|SV2|SV3)) 2110. 				   col = C_crwall; 2111. 				else if (seenv & (SV0|SV7)) 2112. 				   col = C_tlwall; 2113. 				else 2114. 				   col = C_trcorn; 2115. 			   } else if (seenv & SV1) { 2116. 				col = seenv & SV7 ? C_crwall : C_tuwall; 2117. 			   } else if (seenv & SV7) { 2118. 				col = seenv & SV1 ? C_crwall : C_tlwall; 2119. 			   } else { 2120. 				impossible( 2121. 				    "wall_angle: bottom of crwall check"); 2122. 				col = C_crwall; 2123. 			   }  2124.  2125. 			    idx = row[col]; 2126. 			} 2127. 			break; 2128. 2129. 		    case WM_X_TLBR: 2130. 			if ( only(seenv, SV1|SV2|SV3) ) 2131. 			   idx = S_blcorn; 2132. 			else if ( only(seenv, SV5|SV6|SV7) ) 2133. 			   idx = S_trcorn; 2134. 			else if ( only(seenv, SV0|SV4) ) 2135. 			   idx = S_stone; 2136. 			else 2137. 			   idx = S_crwall; 2138. 			break; 2139. 2140. 		    case WM_X_BLTR: 2141. 			if ( only(seenv, SV0|SV1|SV7) ) 2142. 			   idx = S_brcorn; 2143. 			else if ( only(seenv, SV3|SV4|SV5) ) 2144. 			   idx = S_tlcorn; 2145. 			else if ( only(seenv, SV2|SV6) ) 2146. 			   idx = S_stone; 2147. 			else 2148. 			   idx = S_crwall; 2149. 			break; 2150. 2151. 		    default: 2152. 			impossible("wall_angle: unknown crosswall mode"); 2153. 			idx = S_stone; 2154. 			break; 2155. 		} 2156. 		break; 2157. 2158. 	default: 2159. 	   impossible("wall_angle: unexpected wall type %d", lev->typ); 2160. 	   idx = S_stone; 2161.    }  2162.     return idx; 2163. } 2164.  2165. /*display.c*/