Source:NetHack 3.3.0/display.c

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