Source:Display.c

Below is the full text to src/display.c from NetHack 3.4.3. To link to a particular line, write [[display.c#line123 ]], for example. 1.   /*	SCCS Id: @(#)display.c	3.4	2003/02/19	*/ 2.   /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ 3.   /* and Dave Cohrs, 1990. */ 4.    /* NetHack may be freely redistributed. See license for details. */

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