Source:NetHack 3.1.0/display.c

Below is the full text to display.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.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.1	92/10/25	*/ 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.  *	seen	- Set to true when the location is seen or felt as it really 105.  *		  is. This is used primarily for walls, which look like stone 106.  *		  if seen from the outside of a room. However, this is 107. *		 also used as a guide for blind heros. If the hero has 108.  *		  seen or felt a room feature underneath a boulder, when the 109.  *		  boulder is moved, the hero should see it again. This is 110. *		 also used as an indicator for unmapping detected objects. 111.  *  112.   *	doormask   - Additional information for the typ field. 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.  #ifdef INVISIBLE_OBJECTS 122. /*  123.   * vobj_at 124.  *  125.   * Returns a pointer to an object if the hero can see an object at the 126.  * given location. This takes care of invisible objects. NOTE, this 127.  * assumes that the hero is not blind and on top of the object pile. 128.  * It does NOT take into account that the location is out of sight, or, 129.  * say, one can see blessed, etc. 130.  */  131.  struct obj * 132. vobj_at(x,y) 133.     xchar x,y; 134. {  135.      register struct obj *obj = level.objects[x][y]; 136.  137.      while (obj) { 138. 	if (!obj->oinvis || See_invisible) return obj; 139. 	obj = obj->nexthere; 140.     }  141.      return ((struct obj *) 0); 142. }  143.  #endif	/* else vobj_at is defined in display.h */ 144.  145.  /*  146.   * The routines map_background, map_object, and map_trap could just 147.  * as easily be: 148.  *  149.   *	map_glyph(x,y,glyph,show) 150.  *  151.   * Which is called with the xx_to_glyph in the call. Then I can get 152.  * rid of 3 routines that don't do very much anyway. And then stop 153.  * having to create fake objects and traps. However, I am reluctant to 154. * make this change. 155.  */  156.   157.  /*  158.   * map_background 159.  *  160.   * Make the real background part of our map. This routine assumes that 161.  * the hero can physically see the location. Update the screen if directed. 162.  */  163.  void 164. map_background(x, y, show) 165.     register xchar x,y; 166.     register int  show; 167. {  168.      register int glyph = back_to_glyph(x,y); 169.  170.      if (level.flags.hero_memory) 171. 	levl[x][y].glyph = glyph; 172.     if (show) show_glyph(x,y, glyph); 173. }  174.   175.  /*  176.   * map_trap 177.  *  178.   * Map the trap and print it out if directed. This routine assumes that the 179.  * hero can physically see the location. 180.  */  181.  void 182. map_trap(trap, show) 183.     register struct trap *trap; 184.     register int	 show; 185. {  186.      register int x = trap->tx, y = trap->ty; 187.     register int glyph = trap_to_glyph(trap); 188.  189.      if (level.flags.hero_memory) 190. 	levl[x][y].glyph = glyph; 191.     if (show) show_glyph(x, y, glyph); 192. }  193.   194.  /*  195.   * map_object 196.  *  197.   * Map the given object. This routine assumes that the hero can physically 198.  * see the location of the object. Update the screen if directed. 199.  */  200.  void 201. map_object(obj, show) 202.     register struct obj *obj; 203.     register int	show; 204. {  205.      register int x = obj->ox, y = obj->oy; 206.     register int glyph = obj_to_glyph(obj); 207.  208.      if (level.flags.hero_memory) 209. 	levl[x][y].glyph = glyph; 210.     if (show) show_glyph(x, y, glyph); 211. }  212.   213.  /*  214.   * unmap_object 215.  *  216.   * Remove something from the map when detection reveals that it isn't  217. * there any more. Replace it with background or known trap, but not 218.  * with any other remembered object. No need to update the display; 219.  * a full update is imminent. 220.  *  221.   * This isn't quite correct due to overloading of the seen bit. But 222.  * it works well enough for now. 223.  */  224.  void 225. unmap_object(x, y)  226. register int x, y; 227. { 228.      register struct trap *trap; 229.  230.      if (!level.flags.hero_memory) return; 231.  232.      if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y)) 233. 	map_trap(trap, 0); 234.     else if (levl[x][y].seen) { 235. 	struct rm *lev = &levl[x][y]; 236.  237.  	map_background(x, y, 0); 238.  239.  	/* turn remembered dark room squares dark */ 240. 	if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) &&  241.  							    lev->typ == ROOM) 242. 	    lev->glyph = cmap_to_glyph(S_stone); 243.     } else 244. 	levl[x][y].glyph = cmap_to_glyph(S_stone);	/* default val */ 245. }  246.   247.   248.  /*  249.   * map_location 250.  *  251.   * Make whatever at this location show up. This is only for non-living 252.  * things. This will not handle feeling invisible objects correctly. 253.  */  254.  #define map_location(x,y,show)						\ 255. {									\  256.      register struct obj   *obj;						\ 257.     register struct trap  *trap;					\ 258. 									\  259.      if ((obj = vobj_at(x,y)) && !covers_objects(x,y))			\ 260. 	map_object(obj,show);						\ 261.     else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y))	\ 262. 	map_trap(trap,show);						\ 263.     else								\ 264. 	map_background(x,y,show);					\ 265. }  266.   267.   268.  /*  269.   * display_monster 270.  *  271.   * Note that this is *not* a map_XXXX function! Monsters sort of float 272.  * above everything. 273.  *  274.   * Yuck. Display body parts by recognizing that the display position is 275. * not the same as the monster position. Currently the only body part is 276. * a worm tail. 277.  *   278.   */  279.  static void 280. display_monster(x, y, mon, in_sight, worm_tail) 281.     register xchar x, y;	/* display position */ 282.     register struct monst *mon;	/* monster to display */ 283.     int in_sight;		/* TRUE if the monster is physically seen */ 284.     register xchar worm_tail;	/* mon is actually a worm tail */ 285. {  286.      register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING); 287.     register int sensed = mon_mimic && 288. 	(Protection_from_shape_changers || sensemon(mon)); 289.  290.      /*  291.       * We must do the mimic check first. If the mimic is mimicing something, 292.      * and the location is in sight, we have to change the hero's memory 293.      * so that when the position is out of sight, the hero remembers what 294.      * the mimic was mimicing. 295.      */  296.   297.      if (mon_mimic && in_sight) { 298. 	switch (mon->m_ap_type) { 299. 	    default: 300. 		impossible("display_monster:  bad m_ap_type value [ = %d ]",  301.  							(int) mon->m_ap_type); 302. 	    case M_AP_NOTHING: 303. 		show_glyph(x, y, mon_to_glyph(mon)); 304. 		break; 305.  306.  	    case M_AP_FURNITURE: { 307. 		/*  308.  		 * This is a poor man's version of map_background. I can't 309. * use map_background because we are overriding what is in 310. * the 'typ' field. Maybe have map_background's parameters 311. 		 * be (x,y,glyph) instead of just (x,y). 312. 		 *  313.  		 * mappearance is currently set to an S_ index value in  314. * makemon.c. 315. */ 316.  		register int glyph = cmap_to_glyph(mon->mappearance); 317. 		levl[x][y].glyph = glyph; 318. 		if (!sensed) show_glyph(x,y, glyph); 319. 		break; 320. 	    }  321.   322.  	    case M_AP_OBJECT: { 323. 		struct obj obj;	/* Make a fake object to send	*/ 324. 				/* to map_object. */ 325.  		obj.ox = x;  326. obj.oy = y; 327. obj.otyp = mon->mappearance; 328. 		obj.corpsenm = PM_TENGU;	/* if mimicing a corpse */ 329. 		map_object(&obj,!sensed); 330. 		break; 331. 	    }  332.   333.  	    case M_AP_MONSTER: 334. 		show_glyph(x,y, monnum_to_glyph(what_mon(mon->mappearance))); 335. 		break; 336. 	}  337.  	  338.      }  339.   340.      /* If the mimic is unsucessfully mimicing something, display the monster */ 341.     if (!mon_mimic || sensed) { 342. 	if (mon->mtame) { 343. 	    if (worm_tail) 344. 		show_glyph(x,y, petnum_to_glyph(what_mon(PM_LONG_WORM_TAIL))); 345. 	    else 346. 		show_glyph(x,y, pet_to_glyph(mon)); 347. 	} else { 348. 	    if (worm_tail) 349. 		show_glyph(x,y, monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL))); 350. 	    else 351. 		show_glyph(x,y, mon_to_glyph(mon)); 352. 	}  353.      }  354.  }  355.   356.  /*  357.   * feel_location 358.  *  359.   * Feel the given location. This assumes that the hero is blind and that 360.  * the given position is either the hero's or one of the eight squares 361.  * adjacent to the hero (except for a boulder push). 362.  */  363.  void 364. feel_location(x, y)  365. xchar x, y; 366. { 367.      struct rm *lev = &(levl[x][y]); 368.     struct obj *boulder; 369.     register struct monst *mon; 370.  371.      /* The hero can't feel non pool locations while under water. */ 372.      if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y)) 373. 	return; 374.  375.      /* If the hero is not in a corridor, then she will feel the wall as a */ 376.     /* wall. It doesn't matter if the hero is levitating or not. */ 377.      if ((IS_WALL(lev->typ) || lev->typ == SDOOR) &&  378.  						levl[u.ux][u.uy].typ != CORR) 379. 	lev->seen = 1; 380.  381.      if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) { 382. 	/*  383.  	 * Levitation Rules. It is assumed that the hero can feel the state 384. 	 * of the walls around herself and can tell if she is in a corridor, 385. 	 * room, or doorway. Boulders are felt because they are large enough. 386. 	 * Anything else is unknown because the hero can't reach the ground. 387. 	 * This makes things difficult. 388. 	 *  389.  	 * Check (and display) in order: 390. 	 *  391.  	 *	+ Stone, walls, and closed doors. 392. 	 *	+ Boulders. [see a boulder before a doorway] 393. 	 *	+ Doors. 394. 	 *	+ Room/water positions 395. 	 *	+ Everything else (hallways!) 396. 	 */  397.  	if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) && 398. 				(lev->doormask & (D_LOCKED | D_CLOSED)))) { 399. 	    map_background(x, y, 1); 400. 	} else if (boulder = sobj_at(BOULDER,x,y)) { 401. 	    map_object(boulder, 1); 402. 	} else if (IS_DOOR(lev->typ)) { 403. 	    map_background(x, y, 1); 404. 	} else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) { 405. 	    /*  406.  	     * An open room or water location. Normally we wouldn't touch 407. 	     * this, but we have to get rid of remembered boulder symbols. 408. 	     * This will only occur in rare occations when the hero goes 409. 	     * blind and doesn't find a boulder where expected (something  410.  	     * came along and picked it up). We know that there is not a 411. * boulder at this location. Show fountains, pools, etc. 412. 	     * underneath if already seen. Otherwise, show the appropriate 413. 	     * floor symbol. 414. 	     *  415.  	     * This isn't quite correct. If the boulder was on top of some 416. 	     * other objects they should be seen once the boulder is removed. 417. 	     * However, we have no way of knowing that what is there now 418. 	     * was there then. So we let the hero have a lapse of memory. 419. 	     * We could also just display what is currently on the top of the 420. 	     * object stack (if anything). 421. 	     */  422.  	    if (lev->glyph == objnum_to_glyph(BOULDER)) { 423. 		if (lev->typ != ROOM && lev->seen) { 424. 		    map_background(x, y, 1); 425. 		} else { 426. 		    lev->glyph = lev->waslit ? cmap_to_glyph(S_room) : 427. 					       cmap_to_glyph(S_stone); 428. 		    show_glyph(x,y,lev->glyph); 429. 		}  430.  	    }  431.  	} else { 432. 	    /* We feel it (I think hallways are the only things left). */ 433.  	    map_background(x, y, 1); 434. 	    /* Corridors are never felt as lit (unless remembered that way) */ 435. 	    /* (lit_corridor only). */ 436.  	    if (lev->typ == CORR &&  437.  		    lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) 438. 		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); 439. 	}  440.      } else { 441. 	map_location(x, y, 1); 442.  443.  	if (Punished) { 444. 	    /*  445.  	     * A ball or chain is only felt if it is first on the object 446. 	     * location list. Otherwise, we need to clear the felt bit --- 447. 	     * something has been dropped on the ball/chain. If the bit is 448. * not cleared, then when the ball/chain is moved it will drop 449. 	     * the wrong glyph. 450. 	     */  451.  	    if (uchain->ox == x && uchain->oy == y) { 452. 		if (level.objects[x][y] == uchain) 453. 		    u.bc_felt |= BC_CHAIN; 454. 		else 455. 		    u.bc_felt &= ~BC_CHAIN;	/* do not feel the chain */ 456. 	    }  457.  	    if (!carried(uball) && uball->ox == x && uball->oy == y) { 458. 		if (level.objects[x][y] == uball) 459. 		    u.bc_felt |= BC_BALL; 460. 		else 461. 		    u.bc_felt &= ~BC_BALL;	/* do not feel the ball */ 462. 	    }  463.  	}  464.   465.  	/* Floor spaces are dark if unlit. Corridors are dark if unlit. */ 466.  	if (lev->typ == ROOM &&  467.  		    lev->glyph == cmap_to_glyph(S_room) && !lev->waslit) 468. 	    show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone)); 469. 	else if (lev->typ == CORR &&  470.  		    lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) 471. 	    show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr)); 472.     }  473.      /* draw monster on top if we can sense it */ 474.     if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon)) 475. 	display_monster(x,y,mon,1,((x != mon->mx)  || (y != mon->my))); 476. }  477.   478.  /*  479.   * newsym 480.  *  481.   * Possibly put a new glyph at the given location. 482.  */  483.  void 484. newsym(x,y) 485.     register xchar x,y; 486. {  487.      register struct monst *mon; 488.     register struct rm *lev = &(levl[x][y]); 489.     register int see_it; 490.     register xchar worm_tail; 491.  492.      /* only permit updating the hero when swallowed */ 493.     if (u.uswallow) { 494. 	if (x == u.ux && y == u.uy) display_self; 495. 	return; 496.     }  497.      if (Underwater && !Is_waterlevel(&u.uz)) { 498. 	/* don't do anything unless (x,y) is an adjacent underwater position */ 499. 	int dx, dy; 500. 	if (!is_pool(x,y)) return; 501. 	dx = x - u.ux;	if (dx < 0) dx = -dx; 502. 	dy = y - u.uy;	if (dy < 0) dy = -dy; 503. 	if (dx > 1 || dy > 1) return; 504.     }  505.   506.      /* Can physically see the location. */ 507.      if (cansee(x,y)) { 508. 	lev->waslit = (lev->lit!=0);	/* remember lit condition */ 509.  510.  	if (x == u.ux && y == u.uy) { 511. 	    if (canseeself) { 512. 		map_location(x,y,0);	/* map *under* self */ 513. 		display_self; 514. 	    } else 515. 		/* we can see what is there */ 516. 		map_location(x,y,1); 517. 	}  518.  	else if ((mon = m_at(x,y)) &&  519.  		 ((see_it = mon_visible(mon)) || sensemon(mon))) { 520. 	    map_location(x,y,0); 	/* map under the monster */ 521.     	    worm_tail = ((x != mon->mx)  || (y != mon->my)); 522. 	    display_monster(x,y,mon,see_it,worm_tail); 523. 	}  524.  	else 525. 	    map_location(x,y,1);	/* map the location */ 526.     }  527.   528.      /* Can't see the location. */ 529.      else { 530. 	if (x == u.ux && y == u.uy) { 531. 	    feel_location(u.ux, u.uy);		/* forces an update */ 532.  533.  	    if (canseeself) display_self; 534. 	}  535.  	else if ((mon = m_at(x,y)) && sensemon(mon) &&  536.      		 		!((x != mon->mx)  || (y != mon->my))) { 537. 	    /* Monsters are printed every time. */ 538.  	    display_monster(x,y,mon,0,0); 539. 	}  540.  	/*  541.  	 * If the location is remembered as being both dark (waslit is false) 542. 	 * and lit (glyph is a lit room or lit corridor) then it was either: 543. 	 *  544.  	 *	(1) A dark location that the hero could see through night 545. 	 *	    vision. 546. 	 *  547.  	 *	(2) Darkened while out of the hero's sight. This can happen 548. 	 *	    when cursed scroll of light is read. 549. 	 *  550.  	 * In either case, we have to manually correct the hero's memory to  551. * match waslit. Deciding when to change waslit is non-trivial. 552. 	 *  553.  	 *  Note:  If flags.lit_corridor is set, then corridors act like room 554. 	 *	   squares. That is, they light up if in night vision range. 555. 	 *	   If flags.lit_corridor is not set, then corridors will 556. 	 *	   remain dark unless lit by a light spell. 557. 	 *  558.  	 * These checks and changes must be here and not in back_to_glyph. 559. 	 * They are dependent on the position being out of sight. 560. 	 */  561.  	else if (!lev->waslit) { 562. 	    if (flags.lit_corridor && lev->glyph == cmap_to_glyph(S_litcorr) &&  563.  							    lev->typ == CORR) 564. 		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); 565. 	    else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM) 566. 		show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone)); 567. 	    else 568. 		goto show_mem; 569. 	} else { 570. show_mem: 571. 	    show_glyph(x, y, lev->glyph); 572. 	}  573.      }  574.  }  575.   576.   577.  /*  578.   * shieldeff 579.  *  580.   * Put magic shield pyrotechnics at the given location. This *could* be 581. * pulled into a platform dependent routine for fancier graphics if desired. 582.  */  583.  void 584. shieldeff(x,y) 585.     xchar x,y; 586. {  587.      register int i;  588. 589.     if (cansee(x,y)) {	/* Don't see anything if can't see the location */ 590. 	for (i = 0; i < SHIELD_COUNT; i++) { 591. 	    show_glyph(x, y, cmap_to_glyph(shield_static[i])); 592. 	    flush_screen(1);	/* make sure the glyph shows up */ 593. 	    delay_output; 594. 	}  595.  	newsym(x,y);		/* restore the old information */ 596.     }  597.  }  598.   599.   600.  /*  601.   * tmp_at 602.  *  603.   * Temporarily place glyphs on the screen. Do not call delay_output. It 604. * is up to the caller to decide if it wants to wait [presently, everyone 605.  * but explode wants to delay]. 606.  *  607.   * Call: 608.  *	(DISP_BEAM,   glyph)	open, initialize glyph 609.  *	(DISP_FLASH,  glyph)	open, initialize glyph 610.  *	(DISP_CHANGE, glyph)	change glyph 611.  *	(DISP_END,    0)	close & clean up (second argument doesn't  612.   *				matter) 613.  *	(x, y)			display the glyph at the location 614.  *  615.   * DISP_BEAM  - Display the given glyph at each location, but do not erase 616.  *		any until the close call. 617.  * DISP_FLASH - Display the given glyph at each location, but erase the 618.  *		previous location's glyph. 619.  */  620.  void 621. tmp_at(x, y)  622. int x, y; 623. { 624.      static coord saved[COLNO];	/* prev positions, only for DISP_BEAM */ 625.     static int sidx = 0;	/* index of saved previous positions */ 626.     static int sx = -1, sy;	/* previous position, only for DISP_FLASH */ 627.     static int status;		/* either DISP_BEAM or DISP_FLASH */ 628.     static int glyph;		/* glyph to use when printing */ 629.  630.      switch (x) { 631. 	case DISP_BEAM: 632. 	case DISP_FLASH: 633. 	    status = x;  634. glyph = y;  635. flush_screen(0);	/* flush buffered glyphs */ 636. 	    break; 637.  638.  	case DISP_CHANGE: 639. 	    glyph = y;  640. break; 641.  642.  	case DISP_END: 643. 	    if (status == DISP_BEAM) { 644. 		register int i;  645. 646. 		/* Erase (reset) from source to end */ 647. 		for (i = 0; i < sidx; i++) 648. 		    newsym(saved[i].x,saved[i].y); 649. 		sidx = 0; 650. 		  651.  	    } else if (sx >= 0) {	/* DISP_FLASH (called at least once) */ 652. 		newsym(sx,sy);	/* reset the location */ 653. 		sx = -1;	/* reset sx to an illegal pos for next time */ 654. 	    }  655.  	    break; 656.  657.  	default:	/* do it */ 658. 	    if (!cansee(x,y)) break; 659.  660.  	    if (status == DISP_BEAM) { 661. 		saved[sidx  ].x = x;	/* save pos for later erasing */ 662. 		saved[sidx++].y = y;  663. } 664.   665.  	    else {	/* DISP_FLASH */ 666. 		if (sx >= 0)		/* not first call */ 667. 		    newsym(sx,sy);	/* update the old position */ 668.  669.  		sx = x;		/* save previous pos for next call */ 670. 		sy = y;  671. } 672.   673.  	    show_glyph(x,y,glyph);	/* show it */ 674. 	    flush_screen(0);		/* make sure it shows up */ 675. 	    break; 676.     } /* end case */ 677. }  678.   679.   680.  /*  681.   * swallowed 682.  *  683.   * The hero is swallowed. Show a special graphics sequence for this. This 684.  * bypasses all of the display routines and messes with buffered screen 685.  * directly. This method works because both vision and display check for 686.  * being swallowed. 687.  */  688.  void 689. swallowed(first) 690.     int first; 691. {  692.      static xchar lastx, lasty;	/* last swallowed position */ 693.     int swallower; 694.  695.      if (first) 696. 	cls; 697.     else { 698. 	register int x, y;  699. 700. 	/* Clear old location */ 701. 	for (y = lasty-1; y <= lasty+1; y++) 702. 	    if(isok(lastx,y)) { 703. 		for (x = lastx-1; x <= lastx+1; x++) 704. 		    show_glyph(x,y,cmap_to_glyph(S_stone)); 705. 	    }  706.      }  707.   708.      swallower = monsndx(u.ustuck->data); 709.     /*  710.       *  Display the hero surrounded by the monster's stomach. 711.      */  712.      if(isok(u.ux, u.uy-1)) { 713. 	show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl)); 714. 	show_glyph(u.ux , u.uy-1, swallow_to_glyph(swallower, S_sw_tc)); 715. 	show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr)); 716.     }  717.   718.      show_glyph(u.ux-1, u.uy , swallow_to_glyph(swallower, S_sw_ml)); 719.     display_self; 720.     show_glyph(u.ux+1, u.uy , swallow_to_glyph(swallower, S_sw_mr)); 721.  722.      if(isok(u.ux, u.uy+1)) { 723. 	show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl)); 724. 	show_glyph(u.ux , u.uy+1, swallow_to_glyph(swallower, S_sw_bc)); 725. 	show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br)); 726.     }  727.   728.      /* Update the swallowed position. */ 729.      lastx = u.ux; 730.     lasty = u.uy; 731. }  732.   733.  /*  734.   * under_water 735.  *  736.   * Similar to swallowed in operation. Shows hero when underwater 737.  * except when in water level. Special routines exist for that. 738.  */  739.  void 740. under_water(mode) 741.     int mode; 742. {  743.      static xchar lastx, lasty; 744.     static boolean dela; 745.     register int x, y;  746. 747.     /* swallowing has a higher precedence than under water */ 748.     if (Is_waterlevel(&u.uz) || u.uswallow) return; 749.  750.      /* full update */ 751.     if (mode == 1 || dela) { 752. 	cls; 753. 	dela = FALSE; 754.     }    755.      /* delayed full update */ 756.     else if (mode == 2) { 757. 	dela = TRUE; 758. 	return; 759.     }  760.      /* limited update */ 761.     else { 762. 	for (y = lasty-1; y <= lasty+1; y++) 763. 	    for (x = lastx-1; x <= lastx+1; x++) 764. 		if (isok(x,y)) 765. 		    show_glyph(x,y,cmap_to_glyph(S_stone)); 766.     }  767.      for (x = u.ux-1; x <= u.ux+1; x++) 768. 	for (y = u.uy-1; y <= u.uy+1; y++) 769. 	    if (isok(x,y) && is_pool(x,y)) { 770. 		if (Blind && !(x == u.ux && y == u.uy)) 771. 		    show_glyph(x,y,cmap_to_glyph(S_stone)); 772. 		else 773. 		    newsym(x,y); 774. 	    }  775.      lastx = u.ux; 776.     lasty = u.uy; 777. }  778.   779.   780.  /* ========================================================================= */  781.   782.  /*  783.   * Loop through all of the monsters and update them. Called when: 784.  *	+ going blind & telepathic 785.  *	+ regaining sight & telepathic 786.  *	+ hallucinating 787.  *	+ doing a full screen redraw 788.  *	+ see invisible times out or a ring of see invisible is taken off 789.  *	+ when a potion of see invisible is quaffed or a ring of see 790.  *	  invisible is put on  791. *	+ gaining telepathy when blind [givit in eat.c, pleased in pray.c] 792. *	+ losing telepathy while blind [xkilled in mon.c, attrcurse in 793. *	 sit.c]  794. */ 795.  void 796. see_monsters 797. {  798.      register struct monst *mon; 799.     for (mon = fmon; mon; mon = mon->nmon) { 800. 	newsym(mon->mx,mon->my); 801. 	if (mon->wormno) see_wsegs(mon); 802.     }  803.  }  804.   805.  /*  806.   * Block/unblock light depending on what a mimic is mimicing and if it's  807. * invisible or not. Should be called only when the state of See_invisible 808.  * changes. 809.  */  810.  void 811. set_mimic_blocking 812. {  813.      register struct monst *mon; 814.     for (mon = fmon; mon; mon = mon->nmon) 815. 	if(mon->minvis &&  816.  	   ((mon->m_ap_type == M_AP_FURNITURE &&  817.  	      (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))|| 818. 	    (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) { 819. 	    if(See_invisible) 820. 		block_point(mon->mx, mon->my); 821. 	    else 822. 		unblock_point(mon->mx, mon->my); 823. 	}  824.  }  825.   826.  /*  827.   * Loop through all of the object *locations* and update them. Called when 828.  *	+ hallucinating. 829.  */  830.  void 831. see_objects 832. {  833.      register struct obj *obj; 834.     for(obj = fobj; obj; obj = obj->nobj) 835. 	if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy); 836. }  837.   838.  /*  839.   * Put the cursor on the hero. Flush all accumulated glyphs before doing it. 840.  */  841.  void 842. curs_on_u 843. {  844.      flush_screen(1);	/* Flush waiting glyphs & put cursor on hero */ 845. }  846.   847.  int 848. doredraw 849. {  850.      docrt; 851.     return 0; 852. }  853.   854.  void 855. docrt 856. {  857.      register int x,y; 858.     register struct rm *lev; 859.  860.      if (!u.ux) return; /* display isn't ready yet */ 861.  862.      if (u.uswallow) { 863. 	swallowed(1); 864. 	return; 865.     }  866.      if (Underwater && !Is_waterlevel(&u.uz)) { 867. 	under_water(1); 868. 	return; 869.     }  870.   871.      /* shut down vision */ 872.     vision_recalc(2); 873.  874.      /*  875.       * This routine assumes that cls does the following: 876.      *      + fills the physical screen with the symbol for rock 877.      *      + clears the glyph buffer 878.      */  879.      cls; 880.  881.      /* display memory */ 882.     for (x = 1; x < COLNO; x++) { 883. 	lev = &levl[x][0]; 884. 	for (y = 0; y < ROWNO; y++, lev++) 885. 	    if (lev->glyph != cmap_to_glyph(S_stone)) 886. 		show_glyph(x,y,lev->glyph); 887.     }  888.   889.      /* see what is to be seen */ 890.     vision_recalc(0); 891.  892.      /* overlay with monsters */ 893.     see_monsters; 894.  895.      flags.botlx = 1;	/* force a redraw of the bottom line */ 896. }  897.   898.   899.  /* ========================================================================= */  900.  /* Glyph Buffering (3rd screen) ============================================ */ 901.  902.  typedef struct { 903.     xchar new;		/* perhaps move this bit into the rm strucure. */ 904.      int   glyph; 905. } gbuf_entry; 906.  907.  static gbuf_entry gbuf[ROWNO][COLNO]; 908. static char gbuf_start[ROWNO]; 909. static char gbuf_stop[ROWNO]; 910.  911.  /*  912.   * Store the glyph in the 3rd screen for later flushing. 913.  */  914.  void 915. show_glyph(x,y,glyph) 916.     xchar x,y; 917.     int   glyph; 918. {  919.      /*  920.       * Check for bad positions and glyphs. 921.      */  922.      if (x <= 0 || x >= COLNO || y < 0 || y >= ROWNO) { 923. 	const char *text; 924. 	int  offset; 925.  926.  	/* column 0 is invalid, but it's often used as a flag, so ignore it */ 927. 	if (x == 0) return; 928.  929.  	/*  930.  	 *  This assumes an ordering of the offsets. See display.h for 931. 	 *  the definition. 932. 	 */  933.  	if (glyph >= GLYPH_SWALLOW_OFF) {		/* swallow border */ 934. 	    text = "swallow border";	offset = glyph - GLYPH_SWALLOW_OFF; 935. 	}else if (glyph >= GLYPH_ZAP_OFF) {		/* zap beam */ 936. 	    text = "zap beam";		offset = glyph - GLYPH_ZAP_OFF; 937. 	} else if (glyph >= GLYPH_CMAP_OFF) {		/* cmap */ 938. 	    text = "cmap_index";	offset = glyph - GLYPH_CMAP_OFF; 939. 	} else if (glyph >= GLYPH_TRAP_OFF) {		/* trap */ 940. 	    text = "trap";		offset = glyph - GLYPH_TRAP_OFF; 941. 	} else if (glyph >= GLYPH_OBJ_OFF) {		/* object */ 942. 	    text = "object";		offset = glyph - GLYPH_OBJ_OFF; 943. 	} else if (glyph >= GLYPH_BODY_OFF) {		/* a corpse */ 944. 	    text = "corpse";		offset = glyph - GLYPH_BODY_OFF; 945. 	} else {					/* a monster */ 946. 	    text = "monster";		offset = glyph; 947. 	}  948.   949.  	impossible("show_glyph:  bad pos %d %d with glyph %d [%s %d].",  950.  						x, y, glyph, text, offset); 951. 	return; 952.     }  953.   954.      if (glyph >= MAX_GLYPH) { 955. 	impossible("show_glyph:  bad glyph %d [max %d] at (%d,%d).",  956.  					glyph, MAX_GLYPH, x, y); 957. 	return; 958.     }  959.   960.      if (gbuf[y][x].glyph != glyph) { 961. 	gbuf[y][x].glyph = glyph; 962. 	gbuf[y][x].new   = 1; 963. 	if (gbuf_start[y] > x) gbuf_start[y] = x;  964. if (gbuf_stop[y] < x) gbuf_stop[y]  = x;  965. } 966.  }  967.   968.   969.  /*  970.   * Reset the changed glyph borders so that none of the 3rd screen has 971.  * changed. 972.  */  973.  #define reset_glyph_bbox			\ 974.     {						\  975.  	int i;					\ 976. 						\  977.  	for (i = 0; i < ROWNO; i++) {		\ 978. 	    gbuf_start[i] = COLNO-1;		\ 979. 	    gbuf_stop[i]  = 0;			\ 980. 	}					\  981.      }  982.   983.   984.  static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) }; 985. /*  986.   * Turn the 3rd screen into stone. 987.  */  988.  void 989. clear_glyph_buffer 990. {  991.      register int x, y;  992. register gbuf_entry *gptr; 993.  994.      for (y = 0; y < ROWNO; y++) { 995. 	gptr = &gbuf[y][0]; 996. 	for (x = COLNO; x; x--) { 997. 	    *gptr++ = nul_gbuf; 998. 	}  999.      }  1000.     reset_glyph_bbox; 1001. } 1002.  1003. /*  1004.  * Assumes that the indicated positions are filled with S_stone glyphs. 1005. */  1006. void 1007. row_refresh(start,stop,y) 1008.    int start,stop,y; 1009. { 1010.     register int x;  1011. 1012.    for (x = start; x <= stop; x++) 1013. 	if (gbuf[y][x].glyph != cmap_to_glyph(S_stone)) 1014. 	   print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph); 1015. } 1016.  1017. void 1018. cls 1019. { 1020.     display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */ 1021.    flags.botlx = 1;		/* force update of botl window */ 1022.    clear_nhwindow(WIN_MAP);	/* clear physical screen */ 1023. 1024.     clear_glyph_buffer;	/* this is sort of an extra effort, but OK */ 1025. } 1026.  1027. /*  1028.  * Synch the third screen with the display. 1029. */  1030. void 1031. flush_screen(cursor_on_u) 1032.    int cursor_on_u; 1033. { 1034.     /* Prevent infinite loops on errors: 1035.     *	    flush_screen->print_glyph->impossible->pline->flush_screen 1036.     */  1037.     static   boolean flushing = 0; 1038.    register int x,y; 1039. 1040.     if (flushing) return;	/* if already flushing then return */ 1041.    flushing = 1; 1042. 1043.     for (y = 0; y < ROWNO; y++) { 1044. 	register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]]; 1045. 	for (x <= gbuf_stop[y]; gptr++, x++) 1046. 	   if (gptr->new) { 1047. 		print_glyph(WIN_MAP,x,y,gptr->glyph); 1048. 		gptr->new = 0; 1049. 	   }  1050.     }  1051.  1052.     if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */ 1053.    display_nhwindow(WIN_MAP, FALSE); 1054.    reset_glyph_bbox; 1055.    flushing = 0; 1056.    if(flags.botl || flags.botlx) bot; 1057. } 1058.  1059. /* ========================================================================= */  1060.  1061. /*  1062.  * back_to_glyph 1063. *  1064.  * Use the information in the rm structure at the given position to create 1065. * a glyph of a background. 1066. *  1067.  * I had to add a field in the rm structure (horizontal) so that we knew 1068. * if open doors and secret doors were horizontal or vertical. Previously, 1069. * the screen symbol had the horizontal/vertical information set at  1070. * level generation time. 1071. *  1072.  * I used the 'ladder' field (really doormask) for deciding if stairwells 1073. * were up or down. I didn't want to check the upstairs and dnstairs 1074. * variables. 1075. */  1076. int 1077. back_to_glyph(x,y) 1078.    xchar x,y; 1079. { 1080.     int idx; 1081.    struct rm *ptr = &(levl[x][y]); 1082. 1083.     switch (ptr->typ) { 1084. 	case SCORR: 1085. 	case STONE:		idx = S_stone;	 break; 1086. 	case ROOM:		idx = S_room;	 break; 1087. 	case CORR: 1088. 	   idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr; 1089. 	   break; 1090. 	case HWALL:	idx = ptr->seen ? S_hwall : S_stone;   break; 1091. 	case VWALL:	idx = ptr->seen ? S_vwall : S_stone;   break; 1092. 	case TLCORNER:	idx = ptr->seen ? S_tlcorn : S_stone;	break; 1093. 	case TRCORNER:	idx = ptr->seen ? S_trcorn : S_stone;	break; 1094. 	case BLCORNER:	idx = ptr->seen ? S_blcorn : S_stone;	break; 1095. 	case BRCORNER:	idx = ptr->seen ? S_brcorn : S_stone;	break; 1096. 	case CROSSWALL:	idx = ptr->seen ? S_crwall : S_stone;	break; 1097. 	case TUWALL:	idx = ptr->seen ? S_tuwall : S_stone;	break; 1098. 	case TDWALL:	idx = ptr->seen ? S_tdwall : S_stone;	break; 1099. 	case TLWALL:	idx = ptr->seen ? S_tlwall : S_stone;	break; 1100. 	case TRWALL:	idx = ptr->seen ? S_trwall : S_stone;	break; 1101. 	case SDOOR: 1102. 	   if (ptr->seen) 1103. 		idx = (ptr->horizontal) ? S_hwall : S_vwall; 1104. 	   else 1105. 		idx = S_stone; 1106. 	   break; 1107. 	case DOOR: 1108. 	   if (ptr->doormask) { 1109. 		if (ptr->doormask & D_BROKEN) 1110. 		   idx = S_ndoor; 1111. 		else if (ptr->doormask & D_ISOPEN) 1112. 		   idx = (ptr->horizontal) ? S_hodoor : S_vodoor; 1113. 		else			/* else is closed */ 1114. 		   idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor; 1115. 	   } else 1116. 		idx = S_ndoor; 1117. 	   break; 1118. 	case POOL: 1119. 	case MOAT:		idx = S_pool;	 break; 1120. 	case STAIRS: 1121. 	   idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair; 1122. 	   break; 1123. 	case LADDER: 1124. 	   idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder; 1125. 	   break; 1126. 	case FOUNTAIN:		idx = S_fountain; break; 1127. 	case SINK:		idx = S_sink;    break; 1128. 	case ALTAR:		idx = S_altar;   break; 1129. 	case THRONE:		idx = S_throne;  break; 1130. 	case LAVAPOOL:		idx = S_lava;	 break; 1131. 	case ICE:		idx = S_ice;     break; 1132. 	case AIR:		idx = S_air;	 break; 1133. 	case CLOUD:		idx = S_cloud;	 break; 1134. 	case WATER:		idx = S_water;	 break; 1135. 	case DBWALL: 1136. 	   idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge; 1137. 	   break; 1138. 	case DRAWBRIDGE_UP: 1139. 	   switch(ptr->drawbridgemask & DB_UNDER) { 1140. 	   case DB_MOAT:  idx = S_pool; break; 1141. 	   case DB_LAVA:  idx = S_lava; break; 1142. 	   case DB_ICE:   idx = S_ice;  break; 1143. 	   case DB_FLOOR: idx = S_room; break; 1144. 	   default: 1145. 		impossible("Strange db-under: %d", 1146. 			   ptr->drawbridgemask & DB_UNDER); 1147. 		idx = S_room; /* something is better than nothing */ 1148. 		break; 1149. 	   }  1150. 	    break; 1151. 	case DRAWBRIDGE_DOWN: 1152. 	   idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge; 1153. 	   break; 1154. 	default: 1155. 	   impossible("back_to_glyph:  unknown level type [ = %d ]",ptr->typ); 1156. 	   idx = S_room; 1157. 	   break; 1158.    }  1159.  1160.     return cmap_to_glyph(idx); 1161. } 1162.  1163.  1164. /*  1165.  * swallow_to_glyph 1166. *  1167.  * Convert a monster number and a swallow location into the correct glyph. 1168. * If you don't want a patchwork monster while hallucinating, decide on  1169. * a random monster in swallowed and don't use what_mon here. 1170. */  1171. static int 1172. swallow_to_glyph(mnum, loc) 1173.    int mnum; 1174.    int loc; 1175. { 1176.     if (loc < S_sw_tl || S_sw_br < loc) { 1177. 	impossible("swallow_to_glyph: bad swallow location"); 1178. 	loc = S_sw_br; 1179.    }  1180.     return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF; 1181. } 1182.  1183.  1184.  1185. /*  1186.  * zapdir_to_glyph 1187. *  1188.  * Change the given zap direction and beam type into a glyph. Each beam 1189. * type has four glyphs, one for each of the symbols below. The order of 1190. * the zap symbols [0-3] as defined in rm.h are: 1191. *  1192.  *	|  S_vbeam	( 0, 1) or ( 0,-1) 1193. *	-  S_hbeam	( 1, 0) or (-1,	0) 1194. *	\  S_lslant	( 1, 1) or (-1,-1) 1195. *	/  S_rslant	(-1, 1) or ( 1,-1) 1196. */  1197. int 1198. zapdir_to_glyph(dx, dy, beam_type) 1199.    register int dx, dy; 1200.    int beam_type; 1201. { 1202.     if (beam_type >= NUM_ZAP) { 1203. 	impossible("zapdir_to_glyph: illegal beam type"); 1204. 	beam_type = 0; 1205.    }  1206.     dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0; 1207.  1208.     return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF; 1209. } 1210.  1211.  1212. /*  1213.  * Utility routine for dowhatis used to find out the glyph displayed at  1214. * the location. This isn't necessarily the same as the glyph in the levl 1215. * structure, so we must check the "third screen". 1216. */  1217. int 1218. glyph_at(x, y) 1219. xchar x,y; 1220. { 1221.     if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO) 1222. 	return cmap_to_glyph(S_room);			/* XXX */ 1223.    return gbuf[y][x].glyph; 1224. } 1225.  1226. /*display.c*/