Source:NetHack 3.2.0/display.c

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