Source:SLASH'EM 0.0.7E7F2/vision.c

Below is the full text to vision.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/vision.c#line123 ]], for example.

The latest source code for vanilla NetHack is at Source code.

1.   /*	SCCS Id: @(#)vision.c	3.4	1999/02/18	*/ 2.   /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6. 7.   /* Circles ==================================================================*/ 8.    9.    /*  10.    * These numbers are limit offsets for one quadrant of a circle of a given 11.   * radius (the first number of each line) from the source. The number in 12. * the comment is the element number (so pointers can be set up). Each 13.   * "circle" has as many elements as its radius+1. The radius is the number 14.   * of points away from the source that the limit exists. The radius of the 15.   * offset on the same row as the source *is* included so we don't have to  16. * make an extra check. For example, a circle of radius 4 has offsets: 17.   *  18.    *				XXX	+2 19.   *				...X	+3 20.   *				....X	+4 21.   *				....X	+4 22.   *				@...X   +4 23.   *  24.    */  25.   char circle_data[] = { 26.  /*  0*/	 1, 1,  27.   /*  2*/	 2, 2, 1,  28.   /*  5*/	 3, 3, 2, 1,  29.   /*  9*/	 4, 4, 4, 3, 2,  30.   /* 14*/	 5, 5, 5, 4, 3, 2,  31.   /* 20*/	 6, 6, 6, 5, 5, 4, 2,  32.   /* 27*/	 7, 7, 7, 6, 6, 5, 4, 2,  33.   /* 35*/	 8, 8, 8, 7, 7, 6, 6, 4, 2,  34.   /* 44*/	 9, 9, 9, 9, 8, 8, 7, 6, 5, 3,  35.   /* 54*/	10,10,10,10, 9, 9, 8, 7, 6, 5, 3,  36.   /* 65*/	11,11,11,11,10,10, 9, 9, 8, 7, 5, 3,  37.   /* 77*/	12,12,12,12,11,11,10,10, 9, 8, 7, 5, 3,  38.   /* 90*/	13,13,13,13,12,12,12,11,10,10, 9, 7, 6, 3,  39.   /*104*/	14,14,14,14,13,13,13,12,12,11,10, 9, 8, 6, 3,  40.   /*119*/	15,15,15,15,14,14,14,13,13,12,11,10, 9, 8, 6, 3,  41.   /*135*/ 16 /* should be MAX_RADIUS+1; used to terminate range loops -dlc */ 42.  };  43.    44.   /*  45.    * These are the starting indexes into the circle_data[] array for a  46. * circle of a given radius. 47.   */  48.   char circle_start[] = { 49.  /*  */	  0,	/* circles of radius zero are not used */ 50.  /* 1*/    0,  51.   /* 2*/	  2,  52.   /* 3*/	  5,  53.   /* 4*/	  9,  54.   /* 5*/	 14,  55.   /* 6*/	 20,  56.   /* 7*/	 27,  57.   /* 8*/	 35,  58.   /* 9*/	 44,  59.   /*10*/	 54,  60.   /*11*/	 65,  61.   /*12*/	 77,  62.   /*13*/	 90,  63.   /*14*/	104,  64.   /*15*/	119,  65.   };  66.    67.    68.   /*===========================================================================*/  69.   /* Vision (arbitrary line of sight) =========================================*/ 70.   71.   /*-- global variables --*/ 72.   73.   #if 0	/* (moved to decl.c) */ 74.  /* True if we need to run a full vision recalculation. */ 75.   boolean	vision_full_recalc = 0; 76.   77.   /* Pointers to the current vision array. */ 78.   char	**viz_array; 79.  #endif 80.  char	*viz_rmin, *viz_rmax;		/* current vision cs bounds */ 81.   82.    83.   /*-- local variables --*/ 84.   85.    86.   static char could_see[2][ROWNO][COLNO];		/* vision work space */ 87.  static char *cs_rows0[ROWNO], *cs_rows1[ROWNO]; 88.  static char  cs_rmin0[ROWNO],  cs_rmax0[ROWNO]; 89.  static char  cs_rmin1[ROWNO],  cs_rmax1[ROWNO]; 90.   91.   static char  viz_clear[ROWNO][COLNO];		/* vision clear/blocked map */ 92.  static char *viz_clear_rows[ROWNO]; 93.   94.   static char  left_ptrs[ROWNO][COLNO];		/* LOS algorithm helpers */ 95.  static char right_ptrs[ROWNO][COLNO]; 96.   97.   /* Forward declarations. */ 98.   STATIC_DCL void FDECL(fill_point, (int,int)); 99.  STATIC_DCL void FDECL(dig_point, (int,int)); 100. STATIC_DCL void NDECL(view_init); 101. STATIC_DCL void FDECL(view_from,(int,int,char **,char *,char *,int, 102. 			     void (*)(int,int,genericptr_t),genericptr_t)); 103. STATIC_DCL void FDECL(get_unused_cs, (char ***,char **,char **)); 104. #ifdef REINCARNATION 105. STATIC_DCL void FDECL(rogue_vision, (char **,char *,char *)); 106. #endif 107.  108.  /* Macro definitions that I can't find anywhere. */ 109.  #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0 )) 110.  #define v_abs(z)  ((z) < 0 ? -(z) : (z))	/* don't use abs -- it may exist */ 111.  112.  /*  113.   * vision_init 114.  *  115.   * The one-time vision initialization routine. 116.  *  117.   * This must be called before mklev is called in newgame [allmain.c], 118.  * or before a game restore. Else we die a horrible death. 119.  */  120.  void 121. vision_init 122. {  123.      int i;  124. 125.     /* Set up the pointers. */ 126.      for (i = 0; i < ROWNO; i++) { 127. 	cs_rows0[i] = could_see[0][i]; 128. 	cs_rows1[i] = could_see[1][i]; 129. 	viz_clear_rows[i] = viz_clear[i]; 130.     }  131.   132.      /* Start out with cs0 as our current array */ 133.     viz_array = cs_rows0; 134.     viz_rmin  = cs_rmin0; 135.     viz_rmax  = cs_rmax0; 136.  137.      vision_full_recalc = 0; 138.     (void) memset((genericptr_t) could_see, 0, sizeof(could_see)); 139.  140.      /* Initialize the vision algorithm (currently C or D). */ 141.      view_init; 142.  143.  #ifdef VISION_TABLES 144.     /* Note:  this initializer doesn't do anything except guarantee that 145. 	      we're linked properly. 146.     */  147.      vis_tab_init; 148. #endif 149. }  150.   151.  /*  152.   * does_block 153.  *  154.   * Returns true if the level feature, object, or monster at (x,y) blocks 155.  * sight. 156.  */  157.  int 158. does_block(x,y,lev) 159.     int x, y;  160. register struct rm   *lev; 161. {  162.      struct obj   *obj; 163.     struct monst *mon; 164.  165.      /* Features that block. . */ 166.      /* KMH -- added trees */ 167.     if (IS_ROCK(lev->typ) || lev->typ == TREE || (IS_DOOR(lev->typ) && 168. 			    (lev->doormask & (D_CLOSED|D_LOCKED|D_TRAPPED) ))) 169. 	return 1; 170.  171.      if (lev->typ == CLOUD || lev->typ == WATER ||  172.  			(lev->typ == MOAT && Underwater)) 173. 	return 1; 174.  175.      /* Boulders block light. */ 176.      for (obj = level.objects[x][y]; obj; obj = obj->nexthere) 177. 	if (obj->otyp == BOULDER) return 1; 178.  179.      /* Mimics mimicing a door or boulder block light. */ 180.      if ((mon = m_at(x,y)) && (!mon->minvis || See_invisible) &&  181.  	  ((mon->m_ap_type == M_AP_FURNITURE &&  182.  	  (mon->mappearance == S_hcdoor || mon->mappearance == S_vcdoor)) || 183. 	  (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) 184. 	return 1; 185.  186.      return 0; 187. }  188.   189.  /*  190.   * vision_reset 191.  *  192.   * This must be called *after* the levl[][] structure is set with the new 193.  * level and the level monsters and objects are in place. 194.  */  195.  void 196. vision_reset 197. {  198.      int y;  199. register int x, i, dig_left, block; 200.     register struct rm    *lev; 201.  202.      /* Start out with cs0 as our current array */ 203.     viz_array = cs_rows0; 204.     viz_rmin  = cs_rmin0; 205.     viz_rmax  = cs_rmax0; 206.  207.      (void) memset((genericptr_t) could_see, 0, sizeof(could_see)); 208.  209.      /* Reset the pointers and clear so that we have a "full" dungeon. */ 210.      (void) memset((genericptr_t) viz_clear,        0, sizeof(viz_clear)); 211.  212.      /* Dig the level */ 213.     for (y = 0; y < ROWNO; y++) { 214. 	dig_left = 0; 215. 	block = TRUE;	/* location (0,y) is always stone; it's !isok */ 216. 	lev = &levl[1][y]; 217. 	for (x = 1; x < COLNO; x++, lev += ROWNO) 218. 	    if (block != (IS_ROCK(lev->typ) || does_block(x,y,lev))) { 219. 		if(block) { 220. 		    for(i=dig_left; i<x; i++) { 221. 			left_ptrs [y][i] = dig_left; 222. 			right_ptrs[y][i] = x-1; 223. 		    }  224.  		} else { 225. 		    i = dig_left; 226. 		    if(dig_left) dig_left--; /* point at first blocked point */ 227. 		    for(i<x; i++) { 228. 			left_ptrs [y][i] = dig_left; 229. 			right_ptrs[y][i] = x;  230. viz_clear[y][i] = 1; 231. 		    }  232.  		}  233.  		dig_left = x;  234. block = !block; 235. 	    }  236.  	/* handle right boundary; almost identical for blocked/unblocked */ 237. 	i = dig_left; 238. 	if(!block && dig_left) dig_left--; /* point at first blocked point */ 239. 	for(i<COLNO; i++) { 240. 	    left_ptrs [y][i] = dig_left; 241. 	    right_ptrs[y][i] = (COLNO-1); 242. 	    viz_clear[y][i] = !block; 243. 	}  244.      }  245.   246.      iflags.vision_inited = 1;	/* vision is ready */ 247.     vision_full_recalc = 1;	/* we want to run vision_recalc */ 248. }  249.   250.   251.  /*  252.   * get_unused_cs 253.  *  254.   * Called from vision_recalc and at least one light routine. Get pointers 255.  * to the unused vision work area. 256.  */  257.  STATIC_OVL void 258. get_unused_cs(rows, rmin, rmax) 259.     char ***rows; 260.     char **rmin, **rmax; 261. {  262.      register int  row; 263.     register char *nrmin, *nrmax; 264.  265.      if (viz_array == cs_rows0) { 266. 	*rows = cs_rows1; 267. 	*rmin = cs_rmin1; 268. 	*rmax = cs_rmax1; 269.     } else { 270. 	*rows = cs_rows0; 271. 	*rmin = cs_rmin0; 272. 	*rmax = cs_rmax0; 273.     }  274.   275.      /* return an initialized, unused work area */ 276.     nrmin = *rmin; 277.     nrmax = *rmax; 278.  279.      (void) memset((genericptr_t)**rows, 0, ROWNO*COLNO);  /* we see nothing */ 280.     for (row = 0; row < ROWNO; row++) {		/* set row min & max */ 281. 	*nrmin++ = COLNO-1; 282. 	*nrmax++ = 0; 283.     }  284.  }  285.   286.   287.  #ifdef REINCARNATION 288. /*  289.   * rogue_vision 290.  *  291.   * Set the "could see" and in sight bits so vision acts just like the old 292.  * rogue game: 293.  *  294.   *	+ If in a room, the hero can see to the room boundaries. 295.  *	+ The hero can always see adjacent squares. 296.  *  297.   * We set the in_sight bit here as well to escape a bug that shows up  298. * due to the one-sided lit wall hack. 299.  */  300.  STATIC_OVL void 301. rogue_vision(next, rmin, rmax) 302.     char **next;	/* could_see array pointers */ 303.     char *rmin, *rmax; 304. {  305.      int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; /* no SHARED... */ 306.      int start, stop, in_door, xhi, xlo, yhi, ylo; 307.     register int zx, zy; 308.  309.      /* If in a lit room, we are able to see to its boundaries. */ 310.      /* If dark, set COULD_SEE so various spells work -dlc */ 311.     if (rnum >= 0) { 312. 	for (zy = rooms[rnum].ly-1; zy <= rooms[rnum].hy+1; zy++) { 313. 	    rmin[zy] = start = rooms[rnum].lx-1; 314. 	    rmax[zy] = stop  = rooms[rnum].hx+1; 315.  316.  	    for (zx = start; zx <= stop; zx++) { 317. 		if (rooms[rnum].rlit) { 318. 		    next[zy][zx] = COULD_SEE | IN_SIGHT; 319. 		    levl[zx][zy].seenv = SVALL;	/* see the walls */ 320. 		} else 321. 		    next[zy][zx] = COULD_SEE; 322. 	    }  323.  	}  324.      }  325.   326.      in_door = levl[u.ux][u.uy].typ == DOOR; 327.  328.      /* Can always see adjacent. */ 329.      ylo = max(u.uy - 1, 0); 330.     yhi = min(u.uy + 1, ROWNO - 1); 331.     xlo = max(u.ux - 1, 1); 332.     xhi = min(u.ux + 1, COLNO - 1); 333.     for (zy = ylo; zy <= yhi; zy++) { 334. 	if (xlo < rmin[zy]) rmin[zy] = xlo; 335. 	if (xhi > rmax[zy]) rmax[zy] = xhi; 336.  337.  	for (zx = xlo; zx <= xhi; zx++) { 338. 	    next[zy][zx] = COULD_SEE | IN_SIGHT; 339. 	    /*  340.  	     * Yuck, update adjacent non-diagonal positions when in a doorway. 341. 	     * We need to do this to catch the case when we first step into 342. 	     * a room. The room's walls were not seen from the outside, but 343. 	     * now are seen (the seen bits are set just above). However, the 344. 	     * positions are not updated because they were already in sight. 345. 	     * So, we have to do it here. 346. 	     */  347.  	    if (in_door && (zx == u.ux || zy == u.uy)) newsym(zx,zy); 348. 	}  349.      }  350.  }  351.  #endif /* REINCARNATION */ 352.  353.  /*#define EXTEND_SPINE*/	/* possibly better looking wall-angle */ 354.  355.  #ifdef EXTEND_SPINE 356.  357.  STATIC_DCL int FDECL(new_angle, (struct rm *, unsigned char *, int, int)); 358. /*  359.   * new_angle 360.  *  361.   * Return the new angle seen by the hero for this location. The angle 362.  * bit is given in the value pointed at by sv. 363.  *  364.   * For T walls and crosswall, just setting the angle bit, even though 365.  * it is technically correct, doesn't look good. If we can see the 366.  * next position beyond the current one and it is a wall that we can 367.  * see, then we want to extend a spine of the T to connect with the wall 368.  * that is beyond. Example: 369.  *  370.   *	 Correct, but ugly			   Extend T spine 371.  *  372.   *		| ...					| ...  373.   *		| ...	<-- wall beyond & floor -->	| ...  374. *		| ...					| ... 375.   * Unseen   -->   ... | ... 376.   * spine	+-... <-- trwall & doorway	-->	+-... 377. *		| ...					| ... 378.   *  379.   *  380.   *		   @	<-- hero		-->	   @ 381.  *  382.   *  383.   * We fake the above check by only checking if the horizontal & 384.  * vertical positions adjacent to the crosswall and T wall are 385.  * unblocked. Then, _in general_ we can see beyond. Generally, 386.  * this is good enough. 387.  *  388.   *	+ When this function is called we don't have all of the seen 389.  *	  information (we're doing a top down scan in vision_recalc). 390.  *	  We would need to scan once to set all IN_SIGHT and COULD_SEE 391.  *	  bits, then again to correctly set the seenv bits. 392.  *	+ I'm trying to make this as cheap as possible. The display & 393.  *	  vision eat up too much CPU time. 394.  *	  395.   *  396.   * Note:  Even as I write this, I'm still not convinced. There are too 397.  *	  many exceptions. I may have to bite the bullet and do more 398.  *	  checks. - Dean 2/11/93 399.  */  400.  STATIC_OVL int 401. new_angle(lev, sv, row, col) 402.     struct rm *lev; 403.     unsigned char *sv; 404.     int row, col; 405. {  406.      register int res = *sv; 407.  408.      /*  409.       * Do extra checks for crosswalls and T walls if we see them from 410.      * an angle. 411.      */  412.      if (lev->typ >= CROSSWALL && lev->typ <= TRWALL) { 413. 	switch (res) { 414. 	    case SV0: 415. 		if (col > 0	  && viz_clear[row][col-1]) res |= SV7; 416. 		if (row > 0	  && viz_clear[row-1][col]) res |= SV1; 417. 		break; 418. 	    case SV2: 419. 		if (row > 0	  && viz_clear[row-1][col]) res |= SV1; 420. 		if (col < COLNO-1 && viz_clear[row][col+1]) res |= SV3; 421. 		break; 422. 	    case SV4: 423. 		if (col < COLNO-1 && viz_clear[row][col+1]) res |= SV3; 424. 		if (row < ROWNO-1 && viz_clear[row+1][col]) res |= SV5; 425. 		break; 426. 	    case SV6: 427. 		if (row < ROWNO-1 && viz_clear[row+1][col]) res |= SV5; 428. 		if (col > 0	  && viz_clear[row][col-1]) res |= SV7; 429. 		break; 430. 	}  431.      }  432.      return res; 433. }  434.  #else 435. /*  436.   * new_angle 437.  *  438.   * Return the new angle seen by the hero for this location. The angle 439.  * bit is given in the value pointed at by sv. 440.  *  441.   * The other parameters are not used. 442.  */  443.  #define new_angle(lev, sv, row, col) (*sv) 444.  445.  #endif 446.  447.   448.  /*  449.   * vision_recalc 450.  *  451.   * Do all of the heavy vision work. Recalculate all locations that could 452.  * possibly be seen by the hero --- if the location were lit, etc.  Note 453.  * which locations are actually seen because of lighting. Then add to 454. * this all locations that be seen by hero due to night vision and x-ray 455.  * vision. Finally, compare with what the hero was able to see previously. 456.  * Update the difference. 457.  *  458.   * This function is usually called only when the variable 'vision_full_recalc' 459.  * is set. The following is a list of places where this function is called, 460.  * with three valid values for the control flag parameter: 461.  *  462.   * Control flag = 0. A complete vision recalculation. Generate the vision 463.  * tables from scratch. This is necessary to correctly set what the hero 464.  * can see. (1) and (2) call this routine for synchronization purposes, (3) 465.  * calls this routine so it can operate correctly. 466.  *  467.   *	+ After the monster move, before input from the player. [moveloop] 468.  *	+ At end of moveloop. [moveloop ??? not sure why this is here] 469.  *	+ Right before something is printed. [pline] 470.  *	+ Right before we do a vision based operation. [do_clear_area] 471.  *	+ screen redraw, so we can renew all positions in sight. [docrt] 472.  *WAC   + when firing wand of fire [buzz] #define LIGHT_SRC_SPELL 473.  *WAC   + fire explosions [explode] #define LIGHT_SRC_SPELL 474.  *  475.   * Control flag = 1. An adjacent vision recalculation. The hero has moved 476.  * one square. Knowing this, it might be possible to optimize the vision 477.  * recalculation using the current knowledge. This is presently unimplemented 478.  * and is treated as a control = 0 call. 479.  *  480.   *	+ Right after the hero moves. [domove] 481.  *  482.   * Control flag = 2. Turn off the vision system. Nothing new will be 483. * displayed, since nothing is seen. This is usually done when you need 484.  * a newsym run on all locations in sight, or on some locations but you 485.  * don't know which ones. 486.  *  487.   *	+ Before a screen redraw, so all positions are renewed. [docrt] 488.  *	+ Right before the hero arrives on a new level. [goto_level] 489.  *	+ Right after a scroll of light is read. [litroom] 490.  *	+ After an option has changed that affects vision [parseoptions] 491.  *	+ Right after the hero is swallowed. [gulpmu] 492.  *	+ Just before bubbles are moved. [movebubbles] 493.  */  494.  void 495. vision_recalc(control) 496.     int control; 497. {  498.      char **temp_array;	/* points to the old vision array */ 499.     char **next_array;	/* points to the new vision array */ 500.     char *next_row;	/* row pointer for the new array */ 501.     char *old_row;	/* row pointer for the old array */ 502.     char *next_rmin;	/* min pointer for the new array */ 503.     char *next_rmax;	/* max pointer for the new array */ 504.     char *ranges;	/* circle ranges -- used for xray & night vision */ 505.     int row;		/* row counter (outer loop)  */ 506.     int start, stop;	/* inner loop starting/stopping index */ 507.     int dx, dy;		/* one step from a lit door or lit wall (see below) */ 508.     register int col;	/* inner loop counter */ 509.     register struct rm *lev;	/* pointer to current pos */ 510.     struct rm *flev;	/* pointer to position in "front" of current pos */ 511.     extern unsigned char seenv_matrix[3][3];	/* from display.c */ 512.     static unsigned char colbump[COLNO+1];	/* cols to bump sv */ 513.     unsigned char *sv;				/* ptr to seen angle bits */ 514.     int oldseenv;				/* previous seenv value */ 515.  516.      vision_full_recalc = 0;			/* reset flag */ 517.     if (in_mklev || !iflags.vision_inited) return; 518.  519.  #ifdef GCC_WARN 520.     row = 0; 521. #endif 522.  523.      /*  524.       * Either the light sources have been taken care of, or we must 525.      * recalculate them here. 526.      */  527.   528.      /* Get the unused could see, row min, and row max arrays. */ 529.      get_unused_cs(&next_array, &next_rmin, &next_rmax); 530.  531.      /* You see nothing, nothing can see you --- if swallowed or refreshing. */ 532.      if (u.uswallow || control == 2) { 533. 	/* do nothing -- get_unused_cs nulls out the new work area */ 534.  535.      } else if (Blind) { 536. 	/*  537.  	 * Calculate the could_see array even when blind so that monsters 538. 	 * can see you, even if you can't see them. Note that the current 539. 	 * setup allows: 540. 	 *  541.  	 *	+ Monsters to see with the "new" vision, even on the rogue 542. 	 *	  level. 543. 	 *  544.  	 *	+ Monsters can see you even when you're in a pit. 545. 	 */  546.  	view_from(u.uy, u.ux, next_array, next_rmin, next_rmax,  547.  		0, (void FDECL((*),(int,int,genericptr_t)))0, (genericptr_t)0); 548.  549.  	/*  550.  	 * Our own version of the update loop below. We know we can't see 551. 	 * anything, so we only need update positions we used to be able 552. 	 * to see. 553. 	 */  554.  	temp_array = viz_array;	/* set viz_array so newsym will work */ 555. 	viz_array = next_array; 556.  557.  	for (row = 0; row < ROWNO; row++) { 558. 	    old_row = temp_array[row]; 559.  560.  	    /* Find the min and max positions on the row. */ 561.  	    start = min(viz_rmin[row], next_rmin[row]); 562. 	    stop  = max(viz_rmax[row], next_rmax[row]); 563.  564.  	    for (col = start; col <= stop; col++) 565. 		if (old_row[col] & IN_SIGHT) newsym(col,row); 566. 	}  567.   568.  	/* skip the normal update loop */ 569. 	goto skip; 570.     }  571.  #ifdef REINCARNATION 572.     else if (Is_rogue_level(&u.uz)) { 573. 	rogue_vision(next_array,next_rmin,next_rmax); 574.     }  575.  #endif 576.     else { 577. 	int has_night_vision = 1;	/* hero has night vision */ 578.  579.  	if (Underwater && !Is_waterlevel(&u.uz)) { 580. 	    /*  581.  	     * The hero is under water. Only see surrounding locations if 582. * they are also underwater. This overrides night vision but 583. 	     * does not override x-ray vision. 584. 	     */  585.  	    has_night_vision = 0; 586.  587.  	    for (row = u.uy-1; row <= u.uy+1; row++) 588. 		for (col = u.ux-1; col <= u.ux+1; col++) { 589. 		    if (!isok(col,row) || !is_pool(col,row)) continue; 590.  591.  		    next_rmin[row] = min(next_rmin[row], col); 592. 		    next_rmax[row] = max(next_rmax[row], col); 593. 		    next_array[row][col] = IN_SIGHT | COULD_SEE; 594. 		}  595.  	}  596.   597.  	/* if in a pit, just update for immediate locations */ 598. 	else if (u.utrap && u.utraptype == TT_PIT) { 599. 	    for (row = u.uy-1; row <= u.uy+1; row++) { 600. 		if (row < 0) continue;	if (row >= ROWNO) break; 601.  602.  		next_rmin[row] = max(      0, u.ux - 1); 603. 		next_rmax[row] = min(COLNO-1, u.ux + 1); 604. 		next_row = next_array[row]; 605.  606.  		for(col=next_rmin[row]; col <= next_rmax[row]; col++) 607. 		    next_row[col] = IN_SIGHT | COULD_SEE; 608. 	    }  609.  	} else 610. 	    view_from(u.uy, u.ux, next_array, next_rmin, next_rmax,  611.                                          0,(void(*)(int, int, genericptr_t))0, (genericptr_t)0); 612.  613.  	/*  614.  	 * Set the IN_SIGHT bit for xray and night vision. 615. 	 */  616.  	if (u.xray_range >= 0) { 617. 	    if (u.xray_range) { 618. 		ranges = circle_ptr(u.xray_range); 619.  620.  		for (row = u.uy-u.xray_range; row <= u.uy+u.xray_range; row++) { 621. 		    if (row < 0) continue;	if (row >= ROWNO) break; 622. 		    dy = v_abs(u.uy-row);	next_row = next_array[row]; 623.  624.  		    start = max(      0, u.ux - ranges[dy]); 625. 		    stop  = min(COLNO-1, u.ux + ranges[dy]); 626.  627.  		    for (col = start; col <= stop; col++) { 628. 			char old_row_val = next_row[col]; 629. 			next_row[col] |= IN_SIGHT; 630. 			oldseenv = levl[col][row].seenv; 631. 			levl[col][row].seenv = SVALL;	/* see all! */ 632.  			/* Update if previously not in sight or new angle. */ 633.  			if (!(old_row_val & IN_SIGHT) || oldseenv != SVALL) 634. 			    newsym(col,row); 635. 		    }  636.   637.  		    next_rmin[row] = min(start, next_rmin[row]); 638. 		    next_rmax[row] = max(stop, next_rmax[row]); 639. 		}  640.   641.  	    } else {	/* range is 0 */ 642. 		next_array[u.uy][u.ux] |= IN_SIGHT; 643. 		levl[u.ux][u.uy].seenv = SVALL; 644. 		next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]); 645. 		next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]); 646. 	    }  647.  	}  648.   649.  	if (has_night_vision && u.xray_range < u.nv_range) { 650. 	    if (!u.nv_range) {	/* range is 0 */ 651. 		next_array[u.uy][u.ux] |= IN_SIGHT; 652. 		levl[u.ux][u.uy].seenv = SVALL; 653. 		next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]); 654. 		next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]); 655. 	    } else if (u.nv_range > 0) { 656. 		ranges = circle_ptr(u.nv_range); 657.  658.  		for (row = u.uy-u.nv_range; row <= u.uy+u.nv_range; row++) { 659. 		    if (row < 0) continue;	if (row >= ROWNO) break; 660. 		    dy = v_abs(u.uy-row);	next_row = next_array[row]; 661.  662.  		    start = max(      0, u.ux - ranges[dy]); 663. 		    stop  = min(COLNO-1, u.ux + ranges[dy]); 664.  665.  		    for (col = start; col <= stop; col++) 666. 			if (next_row[col]) next_row[col] |= IN_SIGHT; 667.  668.  		    next_rmin[row] = min(start, next_rmin[row]); 669. 		    next_rmax[row] = max(stop, next_rmax[row]); 670. 		}  671.  	    }  672.  	}  673.      }  674.   675.      /* Set the correct bits for all light sources. */ 676.      do_light_sources(next_array); 677.  678.   679.      /*  680.       * Make the viz_array the new array so that cansee will work correctly. 681.      */  682.      temp_array = viz_array; 683.     viz_array = next_array; 684.  685.      /*  686.       * The main update loop. Here we do two things: 687.      *  688.       *	    + Set the IN_SIGHT bit for places that we could see and are lit. 689.      *	    + Reset changed places. 690.      *  691.       * There is one thing that make deciding what the hero can see 692.      * difficult: 693.      *  694.       *  1.  Directional lighting. Items that block light create problems. 695.      *      The worst offenders are doors. Suppose a door to a lit room 696.      *      is closed. It is lit on one side, but not on the other. How 697.      *      do you know? You have to check the closest adjacent position. 698.      *	    Even so, that is not entirely correct. But it seems close 699.      *	    enough for now. 700.      */  701.      colbump[u.ux] = colbump[u.ux+1] = 1; 702.     for (row = 0; row < ROWNO; row++) { 703. 	dy = u.uy - row;                dy = sign(dy); 704. 	next_row = next_array[row];     old_row = temp_array[row]; 705.  706.  	/* Find the min and max positions on the row. */ 707.  	start = min(viz_rmin[row], next_rmin[row]); 708. 	stop  = max(viz_rmax[row], next_rmax[row]); 709. 	lev = &levl[start][row]; 710.  711.  	sv = &seenv_matrix[dy+1][start < u.ux ? 0 : (start > u.ux ? 2:1)]; 712.  713.  	for (col = start; col <= stop;  714.  				lev += ROWNO, sv += (int) colbump[++col]) { 715. 	    if (next_row[col] & IN_SIGHT) { 716. 		/*  717.  		 * We see this position because of night- or xray-vision. 718. 		 */  719.  		oldseenv = lev->seenv; 720. 		lev->seenv |= new_angle(lev,sv,row,col); /* update seen angle */ 721.  722.  		/* Update pos if previously not in sight or new angle. */ 723.  		if ( !(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv) 724. 		    newsym(col,row); 725. 	    }  726.   727.  	    else if ((next_row[col] & COULD_SEE)  728.  				&& (lev->lit || (next_row[col] & TEMP_LIT))) { 729. 		/*  730.  		 * We see this position because it is lit. 731. 		 */  732.  		if ((IS_DOOR(lev->typ) || lev->typ == SDOOR || 733. 		     IS_WALL(lev->typ)) && !viz_clear[row][col]) { 734. 		    /*  735.  		     * Make sure doors, walls, boulders or mimics don't show up  736. * at the end of dark hallways. We do this by checking 737. 		     * the adjacent position. If it is lit, then we can see 738. 		     * the door or wall, otherwise we can't.  739. */ 740.  		    dx = u.ux - col;	dx = sign(dx); 741. 		    flev = &(levl[col+dx][row+dy]); 742. 		    if (flev->lit || next_array[row+dy][col+dx] & TEMP_LIT) { 743. 			next_row[col] |= IN_SIGHT;	/* we see it */ 744.  745.  			oldseenv = lev->seenv; 746. 			lev->seenv |= new_angle(lev,sv,row,col); 747.  748.  			/* Update pos if previously not in sight or new angle.*/ 749. 			if (!(old_row[col] & IN_SIGHT) || oldseenv!=lev->seenv) 750. 			    newsym(col,row); 751. 		    } else 752. 			goto not_in_sight;	/* we don't see it */ 753.  754.  		} else { 755. 		    next_row[col] |= IN_SIGHT;	/* we see it */ 756.  757.  		    oldseenv = lev->seenv; 758. 		    lev->seenv |= new_angle(lev,sv,row,col); 759.  760.  		    /* Update pos if previously not in sight or new angle. */ 761.  		    if ( !(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv) 762. 			newsym(col,row); 763. 		}  764.  	    } else if ((next_row[col] & COULD_SEE) && lev->waslit) { 765. 		/*  766.  		 * If we make it here, the hero _could see_ the location, 767. 		 * but doesn't see it (location is not lit). 768. 		 * However, the hero _remembers_ it as lit (waslit is true). 769. 		 * The hero can now see that it is not lit, so change waslit 770. 		 * and update the location. 771. 		 */  772.  		lev->waslit = 0; /* remember lit condition */ 773. 		newsym(col,row); 774. 	    }  775.  	    /*  776.  	     * At this point we know that the row position is *not* in normal 777. 	     * sight. That is, the position is could be seen, but is dark 778. 	     * or LOS is just plain blocked. 779. 	     *  780.  	     * Update the position if: 781. 	     * o If the old one *was* in sight. We may need to clean up 782. *  the glyph -- E.g. darken room spot, etc. 783. 	     * o If we now could see the location (yet the location is not  784.  	     *   lit), but previously we couldn't see the location, or vice 785. 	     *   versa. Update the spot because there there may be an infared 786. 	     *   monster there. 787. 	     */  788.  	    else { 789. not_in_sight: 790. 		if ((old_row[col] & IN_SIGHT)  791.  			|| ((next_row[col] & COULD_SEE) 792. 				^ (old_row[col] & COULD_SEE))) 793. 		    newsym(col,row); 794. 	    }  795.   796.  	} /* end for col. . */ 797.      }	/* end for row. . */  798.      colbump[u.ux] = colbump[u.ux+1] = 0; 799.  800.  skip: 801.     /* This newsym caused a crash delivering msg about failure to open 802.      * dungeon file init_dungeons -> panic -> done(11) -> 803.      * vision_recalc(2) -> newsym -> crash! u.ux and u.uy are 0 and 804.      * program_state.panicking == 1 under those circumstances 805.      */  806.      if (!program_state.panicking) 807. 	newsym(u.ux, u.uy);		/* Make sure the hero shows up! */ 808.   809.      /* Set the new min and max pointers. */ 810.      viz_rmin  = next_rmin; 811.     viz_rmax = next_rmax; 812. }  813.   814.   815.  /*  816.   * block_point 817.  *  818.   * Make the location opaque to light. 819.  */  820.  void 821. block_point(x,y) 822.     int x, y;  823. { 824.      fill_point(y,x); 825.  826.      /* recalc light sources here? */ 827.   828.      /*  829.       * We have to do a full vision recalculation if we "could see" the 830.      * location. Why? Suppose some monster opened a way so that the 831.      * hero could see a lit room. However, the position of the opening 832.      * was out of night-vision range of the hero. Suddenly the hero should 833.      * see the lit room. 834.      */  835.      if (viz_array[y][x]) vision_full_recalc = 1; 836. }  837.   838.  /*  839.   * unblock_point 840.  *  841.   * Make the location transparent to light. 842.  */  843.  void 844. unblock_point(x,y) 845.     int x, y;  846. { 847.      dig_point(y,x); 848.  849.      /* recalc light sources here? */ 850.   851.      if (viz_array[y][x]) vision_full_recalc = 1; 852. }  853.   854.   855.  /*===========================================================================*\  856.   |									     |  857.   |	Everything below this line uses (y,x) instead of (x,y) --- the	     | 858.  |	algorithms are faster if they are less recursive and can scan	     | 859.  |	on a row longer. | 860.   |									     |  861.  \*===========================================================================*/  862.   863.   864.  /* ========================================================================= *\  865.  			Left and Right Pointer Updates 866. \* ========================================================================= */  867.   868.  /*  869.   *			LEFT and RIGHT pointer rules 870.  *  871.   *  872.   * **NOTE**  The rules changed on 4/4/90. This comment reflects the 873.  * new rules. The change was so that the stone-wall optimization 874.  * would work. 875.  *  876.   * OK, now the tough stuff. We must maintain our left and right 877.  * row pointers. The rules are as follows: 878.  *  879.   * Left Pointers: 880.  * ______________  881.   *  882.   * + If you are a clear spot, your left will point to the first 883.  *   stone to your left. If there is none, then point the first 884.  *   legal position in the row (0). 885.  *  886.   * + If you are a blocked spot, then your left will point to the 887.  *   left-most blocked spot to your left that is connected to you. 888.  *   This means that a left-edge (a blocked spot that has an open  889.   *   spot on its left) will point to itself. 890.  *  891.   *  892.   * Right Pointers: 893.  * ---  894.   * + If you are a clear spot, your right will point to the first 895.  *   stone to your right. If there is none, then point the last 896.  *   legal position in the row (COLNO-1). 897.  *  898.   * + If you are a blocked spot, then your right will point to the 899.  *   right-most blocked spot to your right that is connected to you. 900.  *   This means that a right-edge (a blocked spot that has an open  901.   *    spot on its right) will point to itself. 902.  */  903.  STATIC_OVL void 904. dig_point(row,col) 905.     int row,col; 906. {  907.      int i;  908. 909.     if (viz_clear[row][col]) return;		/* already done */ 910.  911.      viz_clear[row][col] = 1; 912.  913.      /*  914.       * Boundary cases first. 915.      */  916.      if (col == 0) {				/* left edge */ 917. 	if (viz_clear[row][1]) { 918. 	    right_ptrs[row][0] = right_ptrs[row][1]; 919. 	} else { 920. 	    right_ptrs[row][0] = 1; 921. 	    for (i = 1; i <= right_ptrs[row][1]; i++) 922. 		left_ptrs[row][i] = 1; 923. 	}  924.      } else if (col == (COLNO-1)) {		/* right edge */ 925.  926.  	if (viz_clear[row][COLNO-2]) { 927. 	    left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2]; 928. 	} else { 929. 	    left_ptrs[row][COLNO-1] = COLNO-2; 930. 	    for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++) 931. 		right_ptrs[row][i] = COLNO-2; 932. 	}  933.      }  934.   935.      /*  936.       * At this point, we know we aren't on the boundaries. 937.      */  938.      else if (viz_clear[row][col-1] && viz_clear[row][col+1]) { 939. 	/* Both sides clear */ 940. 	for (i = left_ptrs[row][col-1]; i <= col; i++) { 941. 	    if (!viz_clear[row][i]) continue;	/* catch non-end case */ 942. 	    right_ptrs[row][i] = right_ptrs[row][col+1]; 943. 	}  944.  	for (i = col; i <= right_ptrs[row][col+1]; i++) { 945. 	    if (!viz_clear[row][i]) continue;	/* catch non-end case */ 946. 	    left_ptrs[row][i] = left_ptrs[row][col-1]; 947. 	}  948.   949.      } else if (viz_clear[row][col-1]) { 950. 	/* Left side clear, right side blocked. */ 951.  	for (i = col+1; i <= right_ptrs[row][col+1]; i++) 952. 	    left_ptrs[row][i] = col+1; 953.  954.  	for (i = left_ptrs[row][col-1]; i <= col; i++) { 955. 	    if (!viz_clear[row][i]) continue;	/* catch non-end case */ 956. 	    right_ptrs[row][i] = col+1; 957. 	}  958.  	left_ptrs[row][col] = left_ptrs[row][col-1]; 959.  960.      } else if (viz_clear[row][col+1]) { 961. 	/* Right side clear, left side blocked. */ 962.  	for (i = left_ptrs[row][col-1]; i < col; i++) 963. 	    right_ptrs[row][i] = col-1; 964.  965.  	for (i = col; i <= right_ptrs[row][col+1]; i++) { 966. 	    if (!viz_clear[row][i]) continue;	/* catch non-end case */ 967. 	    left_ptrs[row][i] = col-1; 968. 	}  969.  	right_ptrs[row][col] = right_ptrs[row][col+1]; 970.  971.      } else { 972. 	/* Both sides blocked */ 973. 	for (i = left_ptrs[row][col-1]; i < col; i++) 974. 	    right_ptrs[row][i] = col-1; 975.  976.  	for (i = col+1; i <= right_ptrs[row][col+1]; i++) 977. 	    left_ptrs[row][i] = col+1; 978.  979.  	left_ptrs[row][col]  = col-1; 980. 	right_ptrs[row][col] = col+1; 981.     }  982.  }  983.   984.  STATIC_OVL void 985. fill_point(row,col) 986.     int row, col; 987. {  988.      int i;  989. 990.     if (!viz_clear[row][col]) return; 991.  992.      viz_clear[row][col] = 0; 993.  994.      if (col == 0) { 995. 	if (viz_clear[row][1]) {			/* adjacent is clear */ 996. 	    right_ptrs[row][0] = 0; 997. 	} else { 998. 	    right_ptrs[row][0] = right_ptrs[row][1]; 999. 	    for (i = 1; i <= right_ptrs[row][1]; i++) 1000. 		left_ptrs[row][i] = 0; 1001. 	} 1002.     } else if (col == COLNO-1) { 1003. 	if (viz_clear[row][COLNO-2]) {		/* adjacent is clear */ 1004. 	   left_ptrs[row][COLNO-1] = COLNO-1; 1005. 	} else { 1006. 	   left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2]; 1007. 	   for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++) 1008. 		right_ptrs[row][i] = COLNO-1; 1009. 	} 1010.     }  1011.  1012.     /*  1013.      * Else we know that we are not on an edge. 1014.     */  1015.     else if (viz_clear[row][col-1] && viz_clear[row][col+1]) { 1016. 	/* Both sides clear */ 1017. 	for (i = left_ptrs[row][col-1]+1; i <= col; i++) 1018. 	   right_ptrs[row][i] = col; 1019. 1020. 	if (!left_ptrs[row][col-1])		/* catch the end case */ 1021. 	   right_ptrs[row][0] = col; 1022. 1023. 	for (i = col; i < right_ptrs[row][col+1]; i++) 1024. 	   left_ptrs[row][i] = col; 1025. 1026. 	if (right_ptrs[row][col+1] == COLNO-1)	/* catch the end case */ 1027. 	   left_ptrs[row][COLNO-1] = col; 1028. 1029.     } else if (viz_clear[row][col-1]) { 1030. 	/* Left side clear, right side blocked. */ 1031. 	for (i = col; i <= right_ptrs[row][col+1]; i++) 1032. 	   left_ptrs[row][i] = col; 1033. 1034. 	for (i = left_ptrs[row][col-1]+1; i < col; i++) 1035. 	   right_ptrs[row][i] = col; 1036. 1037. 	if (!left_ptrs[row][col-1])		/* catch the end case */ 1038. 	   right_ptrs[row][i] = col; 1039. 1040. 	right_ptrs[row][col] = right_ptrs[row][col+1]; 1041. 1042.     } else if (viz_clear[row][col+1]) { 1043. 	/* Right side clear, left side blocked. */ 1044. 	for (i = left_ptrs[row][col-1]; i <= col; i++) 1045. 	   right_ptrs[row][i] = col; 1046. 1047. 	for (i = col+1; i < right_ptrs[row][col+1]; i++) 1048. 	   left_ptrs[row][i] = col; 1049. 1050. 	if (right_ptrs[row][col+1] == COLNO-1)	/* catch the end case */ 1051. 	   left_ptrs[row][i] = col; 1052. 1053. 	left_ptrs[row][col] = left_ptrs[row][col-1]; 1054. 1055.     } else { 1056. 	/* Both sides blocked */ 1057. 	for (i = left_ptrs[row][col-1]; i <= col; i++) 1058. 	   right_ptrs[row][i] = right_ptrs[row][col+1]; 1059. 1060. 	for (i = col; i <= right_ptrs[row][col+1]; i++) 1061. 	   left_ptrs[row][i] = left_ptrs[row][col-1]; 1062.    }  1063. }  1064.  1065.  1066. /*===========================================================================*/  1067. /*===========================================================================*/  1068. /* Use either algorithm C or D.  See the config.h for more details. =========*/ 1069.  1070. /*  1071.  * Variables local to both Algorithms C and D.  1072. */ 1073. static int  start_row; 1074. static int start_col; 1075. static int step; 1076. static char **cs_rows; 1077. static char *cs_left; 1078. static char *cs_right; 1079. 1080. static void FDECL((*vis_func), (int,int,genericptr_t)); 1081. static genericptr_t varg; 1082. 1083. /*  1084.  * Both Algorithms C and D use the following macros. 1085. *  1086.  *      good_row(z)	  - Return TRUE if the argument is a legal row. 1087. *      set_cs(rowp,col)  - Set the local could see array. 1088. *      set_min(z)	  - Save the min value of the argument and the current 1089. *			      row minimum. 1090. *      set_max(z)	  - Save the max value of the argument and the current 1091. *			      row maximum. 1092. *  1093.  * The last three macros depend on having local pointers row_min, row_max, 1094. * and rowp being set correctly. 1095. */  1096. #define set_cs(rowp,col) (rowp[col] = COULD_SEE) 1097. #define good_row(z) ((z) >= 0 && (z) < ROWNO) 1098. #define set_min(z) if (*row_min > (z)) *row_min = (z) 1099. #define set_max(z) if (*row_max < (z)) *row_max = (z) 1100. #define is_clear(row,col) viz_clear_rows[row][col] 1101. 1102. /*  1103.  * clear_path		expanded into 4 macros/functions: 1104. *  1105.  *	q1_path 1106. *	q2_path 1107. *	q3_path 1108. *	q4_path 1109. *  1110.  * "Draw" a line from the start to the given location. Stop if we hit 1111. * something that blocks light. The start and finish points themselves are 1112. * not checked, just the points between them. These routines do _not_ 1113. * expect to be called with the same starting and stopping point. 1114. *  1115.  * These routines use the generalized integer Bresenham's algorithm (fast  1116.  * line drawing) for all quadrants. The algorithm was taken from _Procedural 1117. * Elements for Computer Graphics_, by David F. Rogers. McGraw-Hill, 1985. 1118. */  1119. #ifdef MACRO_CPATH	/* quadrant calls are macros */ 1120. 1121. /*  1122.  * When called, the result is in "result". 1123. * The first two arguments (srow,scol) are one end of the path. The next 1124. * two arguments (row,col) are the destination. The last argument is 1125. * used as a C language label. This means that it must be different 1126. * in each pair of calls. 1127. */  1128.  1129. /*  1130.  *  Quadrant I (step < 0). 1131. */  1132. #define q1_path(srow,scol,y2,x2,label)			\ 1133. {							\ 1134.     int dx, dy;						\ 1135.    register int k, err, x, y, dxs, dys;		\ 1136. 							\ 1137.     x  = (scol);	y  = (srow);			\ 1138.    dx = (x2) - x;	dy = y - (y2);			\ 1139. 							\ 1140.     result = 0;		 /* default to a blocked path */\ 1141. 							\ 1142.     dxs = dx << 1;	   /* save the shifted values */\ 1143.    dys = dy << 1;					\ 1144.    if (dy > dx) {					\ 1145. 	err = dxs - dy;					\ 1146. 							\ 1147. 	for (k = dy-1; k; k--) {			\ 1148. 	   if (err >= 0) {				\ 1149. 		x++;					\ 1150. 		err -= dys;				\ 1151. 	   }						\  1152. 	    y--;					\ 1153. 	   err += dxs;					\ 1154. 	   if (!is_clear(y,x)) goto label;/* blocked */\ 1155. 	}						\ 1156.     } else {						\ 1157. 	err = dys - dx;					\ 1158. 							\ 1159. 	for (k = dx-1; k; k--) {			\ 1160. 	   if (err >= 0) {				\ 1161. 		y--;					\ 1162. 		err -= dxs;				\ 1163. 	   }						\  1164. 	    x++;					\ 1165. 	   err += dys;					\ 1166. 	   if (!is_clear(y,x)) goto label;/* blocked */\ 1167. 	}						\ 1168.     }							\  1169. 							\  1170.     result = 1;						\ 1171. } 1172.  1173. /*  1174.  * Quadrant IV (step > 0). 1175. */  1176. #define q4_path(srow,scol,y2,x2,label)			\ 1177. {							\ 1178.     int dx, dy;						\ 1179.    register int k, err, x, y, dxs, dys;		\ 1180. 							\ 1181.     x  = (scol);	y  = (srow);			\ 1182.    dx = (x2) - x;	dy = (y2) - y;			\ 1183. 							\ 1184.     result = 0;		 /* default to a blocked path */\ 1185. 							\ 1186.     dxs = dx << 1;	   /* save the shifted values */\ 1187.    dys = dy << 1;					\ 1188.    if (dy > dx) {					\ 1189. 	err = dxs - dy;					\ 1190. 							\ 1191. 	for (k = dy-1; k; k--) {			\ 1192. 	   if (err >= 0) {				\ 1193. 		x++;					\ 1194. 		err -= dys;				\ 1195. 	   }						\  1196. 	    y++;					\ 1197. 	   err += dxs;					\ 1198. 	   if (!is_clear(y,x)) goto label;/* blocked */\ 1199. 	}						\ 1200. 							\  1201.     } else {						\ 1202. 	err = dys - dx;					\ 1203. 							\ 1204. 	for (k = dx-1; k; k--) {			\ 1205. 	   if (err >= 0) {				\ 1206. 		y++;					\ 1207. 		err -= dxs;				\ 1208. 	   }						\  1209. 	    x++;					\ 1210. 	   err += dys;					\ 1211. 	   if (!is_clear(y,x)) goto label;/* blocked */\ 1212. 	}						\ 1213.     }							\  1214. 							\  1215.     result = 1;						\ 1216. } 1217.  1218. /*  1219.  * Quadrant II (step < 0). 1220. */  1221. #define q2_path(srow,scol,y2,x2,label)			\ 1222. {							\ 1223.     int dx, dy;						\ 1224.    register int k, err, x, y, dxs, dys;		\ 1225. 							\ 1226.     x  = (scol);	y  = (srow);			\ 1227.    dx = x - (x2);	dy = y - (y2);			\ 1228. 							\ 1229.     result = 0;		 /* default to a blocked path */\ 1230. 							\ 1231.     dxs = dx << 1;	   /* save the shifted values */\ 1232.    dys = dy << 1;					\ 1233.    if (dy > dx) {					\ 1234. 	err = dxs - dy;					\ 1235. 							\ 1236. 	for (k = dy-1; k; k--) {			\ 1237. 	   if (err >= 0) {				\ 1238. 		x--;					\ 1239. 		err -= dys;				\ 1240. 	   }						\  1241. 	    y--;					\ 1242. 	   err += dxs;					\ 1243. 	   if (!is_clear(y,x)) goto label;/* blocked */\ 1244. 	}						\ 1245.     } else {						\ 1246. 	err = dys - dx;					\ 1247. 							\ 1248. 	for (k = dx-1; k; k--) {			\ 1249. 	   if (err >= 0) {				\ 1250. 		y--;					\ 1251. 		err -= dxs;				\ 1252. 	   }						\  1253. 	    x--;					\ 1254. 	   err += dys;					\ 1255. 	   if (!is_clear(y,x)) goto label;/* blocked */\ 1256. 	}						\ 1257.     }							\  1258. 							\  1259.     result = 1;						\ 1260. } 1261.  1262. /*  1263.  * Quadrant III (step > 0). 1264. */  1265. #define q3_path(srow,scol,y2,x2,label)			\ 1266. {							\ 1267.     int dx, dy;						\ 1268.    register int k, err, x, y, dxs, dys;		\ 1269. 							\ 1270.     x  = (scol);	y  = (srow);			\ 1271.    dx = x - (x2);	dy = (y2) - y;			\ 1272. 							\ 1273.     result = 0;		 /* default to a blocked path */\ 1274. 							\ 1275.     dxs = dx << 1;	   /* save the shifted values */\ 1276.    dys = dy << 1;					\ 1277.    if (dy > dx) {					\ 1278. 	err = dxs - dy;					\ 1279. 							\ 1280. 	for (k = dy-1; k; k--) {			\ 1281. 	   if (err >= 0) {				\ 1282. 		x--;					\ 1283. 		err -= dys;				\ 1284. 	   }						\  1285. 	    y++;					\ 1286. 	   err += dxs;					\ 1287. 	   if (!is_clear(y,x)) goto label;/* blocked */\ 1288. 	}						\ 1289. 							\  1290.     } else {						\ 1291. 	err = dys - dx;					\ 1292. 							\ 1293. 	for (k = dx-1; k; k--) {			\ 1294. 	   if (err >= 0) {				\ 1295. 		y++;					\ 1296. 		err -= dxs;				\ 1297. 	   }						\  1298. 	    x--;					\ 1299. 	   err += dys;					\ 1300. 	   if (!is_clear(y,x)) goto label;/* blocked */\ 1301. 	}						\ 1302.     }							\  1303. 							\  1304.     result = 1;						\ 1305. } 1306.  1307. #else   /* quadrants are really functions */ 1308. 1309. STATIC_DCL int FDECL(_q1_path, (int,int,int,int)); 1310. STATIC_DCL int FDECL(_q2_path, (int,int,int,int)); 1311. STATIC_DCL int FDECL(_q3_path, (int,int,int,int)); 1312. STATIC_DCL int FDECL(_q4_path, (int,int,int,int)); 1313. 1314. #define q1_path(sy,sx,y,x,dummy) result = _q1_path(sy,sx,y,x) 1315. #define q2_path(sy,sx,y,x,dummy) result = _q2_path(sy,sx,y,x) 1316. #define q3_path(sy,sx,y,x,dummy) result = _q3_path(sy,sx,y,x) 1317. #define q4_path(sy,sx,y,x,dummy) result = _q4_path(sy,sx,y,x) 1318. 1319. /*  1320.  * Quadrant I (step < 0). 1321. */  1322. STATIC_OVL int 1323. _q1_path(srow,scol,y2,x2) 1324.    int scol, srow, y2, x2; 1325. { 1326.     int dx, dy; 1327.    register int k, err, x, y, dxs, dys; 1328. 1329.     x  = scol;		y  = srow; 1330.    dx = x2 - x;	dy = y - y2; 1331. 1332.     dxs = dx << 1;	   /* save the shifted values */ 1333.    dys = dy << 1; 1334.    if (dy > dx) { 1335. 	err = dxs - dy; 1336. 1337. 	for (k = dy-1; k; k--) { 1338. 	   if (err >= 0) { 1339. 		x++; 1340. 		err -= dys; 1341. 	   }  1342. 	    y--; 1343. 	   err += dxs; 1344. 	   if (!is_clear(y,x)) return 0; /* blocked */ 1345. 	} 1346.     } else { 1347. 	err = dys - dx; 1348. 1349. 	for (k = dx-1; k; k--) { 1350. 	   if (err >= 0) { 1351. 		y--; 1352. 		err -= dxs; 1353. 	   }  1354. 	    x++; 1355. 	   err += dys; 1356. 	   if (!is_clear(y,x)) return 0;/* blocked */ 1357. 	} 1358.     }  1359.  1360.     return 1; 1361. } 1362.  1363. /*  1364.  * Quadrant IV (step > 0). 1365. */  1366. STATIC_OVL int 1367. _q4_path(srow,scol,y2,x2) 1368.    int scol, srow, y2, x2; 1369. { 1370.     int dx, dy; 1371.    register int k, err, x, y, dxs, dys; 1372. 1373.     x  = scol;		y  = srow; 1374.    dx = x2 - x;	dy = y2 - y;  1375. 1376.    dxs = dx << 1;	   /* save the shifted values */ 1377.    dys = dy << 1; 1378.    if (dy > dx) { 1379. 	err = dxs - dy; 1380. 1381. 	for (k = dy-1; k; k--) { 1382. 	   if (err >= 0) { 1383. 		x++; 1384. 		err -= dys; 1385. 	   }  1386. 	    y++; 1387. 	   err += dxs; 1388. 	   if (!is_clear(y,x)) return 0; /* blocked */ 1389. 	} 1390.     } else { 1391. 	err = dys - dx; 1392. 1393. 	for (k = dx-1; k; k--) { 1394. 	   if (err >= 0) { 1395. 		y++; 1396. 		err -= dxs; 1397. 	   }  1398. 	    x++; 1399. 	   err += dys; 1400. 	   if (!is_clear(y,x)) return 0;/* blocked */ 1401. 	} 1402.     }  1403.  1404.     return 1; 1405. } 1406.  1407. /*  1408.  * Quadrant II (step < 0). 1409. */  1410. STATIC_OVL int 1411. _q2_path(srow,scol,y2,x2) 1412.    int scol, srow, y2, x2; 1413. { 1414.     int dx, dy; 1415.    register int k, err, x, y, dxs, dys; 1416. 1417.     x  = scol;		y  = srow; 1418.    dx = x - x2;	dy = y - y2; 1419. 1420.     dxs = dx << 1;	   /* save the shifted values */ 1421.    dys = dy << 1; 1422.    if (dy > dx) { 1423. 	err = dxs - dy; 1424. 1425. 	for (k = dy-1; k; k--) { 1426. 	   if (err >= 0) { 1427. 		x--; 1428. 		err -= dys; 1429. 	   }  1430. 	    y--; 1431. 	   err += dxs; 1432. 	   if (!is_clear(y,x)) return 0; /* blocked */ 1433. 	} 1434.     } else { 1435. 	err = dys - dx; 1436. 1437. 	for (k = dx-1; k; k--) { 1438. 	   if (err >= 0) { 1439. 		y--; 1440. 		err -= dxs; 1441. 	   }  1442. 	    x--; 1443. 	   err += dys; 1444. 	   if (!is_clear(y,x)) return 0;/* blocked */ 1445. 	} 1446.     }  1447.  1448.     return 1; 1449. } 1450.  1451. /*  1452.  * Quadrant III (step > 0). 1453. */  1454. STATIC_OVL int 1455. _q3_path(srow,scol,y2,x2) 1456.    int scol, srow, y2, x2; 1457. { 1458.     int dx, dy; 1459.    register int k, err, x, y, dxs, dys; 1460. 1461.     x  = scol;		y  = srow; 1462.    dx = x - x2;	dy = y2 - y;  1463. 1464.    dxs = dx << 1;	   /* save the shifted values */ 1465.    dys = dy << 1; 1466.    if (dy > dx) { 1467. 	err = dxs - dy; 1468. 1469. 	for (k = dy-1; k; k--) { 1470. 	   if (err >= 0) { 1471. 		x--; 1472. 		err -= dys; 1473. 	   }  1474. 	    y++; 1475. 	   err += dxs; 1476. 	   if (!is_clear(y,x)) return 0; /* blocked */ 1477. 	} 1478.     } else { 1479. 	err = dys - dx; 1480. 1481. 	for (k = dx-1; k; k--) { 1482. 	   if (err >= 0) { 1483. 		y++; 1484. 		err -= dxs; 1485. 	   }  1486. 	    x--; 1487. 	   err += dys; 1488. 	   if (!is_clear(y,x)) return 0;/* blocked */ 1489. 	} 1490.     }  1491.  1492.     return 1; 1493. } 1494.  1495. #endif	/* quadrants are functions */ 1496. 1497. /*  1498.  * Use vision tables to determine if there is a clear path from 1499. * (col1,row1) to (col2,row2). This is used by: 1500. *		m_cansee 1501. *		m_canseeu 1502. *		do_light_sources 1503. */  1504. boolean 1505. clear_path(col1,row1,col2,row2) 1506.    int col1, row1, col2, row2; 1507. { 1508.     int result; 1509. 1510.     if(col1 < col2) { 1511. 	if(row1 > row2) { 1512. 	   q1_path(row1,col1,row2,col2,cleardone); 1513. 	} else { 1514. 	   q4_path(row1,col1,row2,col2,cleardone); 1515. 	} 1516.     } else { 1517. 	if(row1 > row2) { 1518. 	   q2_path(row1,col1,row2,col2,cleardone); 1519. 	} else if(row1 == row2 && col1 == col2) { 1520. 	   result = 1; 1521. 	} else { 1522. 	   q3_path(row1,col1,row2,col2,cleardone); 1523. 	} 1524.     }  1525. #ifdef MACRO_CPATH 1526. cleardone: 1527. #endif 1528.    return((boolean)result); 1529. } 1530.  1531. #ifdef VISION_TABLES 1532. /*===========================================================================*\ 1533. 			    GENERAL LINE OF SIGHT 1534. 				Algorithm D 1535. \*===========================================================================*/ 1536.  1537.  1538. /*  1539.  * Indicate caller for the shadow routines. 1540. */  1541. #define FROM_RIGHT 0 1542. #define FROM_LEFT 1 1543. 1544.  1545. /*  1546.  * Include the table definitions. 1547. */  1548. #include "vis_tab.h"  1549. 1550. 1551. /* 3D table pointers. */ 1552. static close2d *close_dy[CLOSE_MAX_BC_DY]; 1553. static far2d  *far_dy[FAR_MAX_BC_DY]; 1554. 1555. STATIC_DCL void FDECL(right_side, (int,int,int,int,int,int,int,char*)); 1556. STATIC_DCL void FDECL(left_side, (int,int,int,int,int,int,int,char*)); 1557. STATIC_DCL int FDECL(close_shadow, (int,int,int,int)); 1558. STATIC_DCL int FDECL(far_shadow, (int,int,int,int)); 1559. 1560. /*  1561.  * Initialize algorithm D's table pointers. If we don't have these, 1562. * then we do 3D table lookups. Verrrry slow. 1563. */  1564. STATIC_OVL void 1565. view_init 1566. { 1567.     int i;  1568. 1569.    for (i = 0; i < CLOSE_MAX_BC_DY; i++) 1570. 	close_dy[i] = &close_table[i]; 1571. 1572.     for (i = 0; i < FAR_MAX_BC_DY; i++) 1573. 	far_dy[i] = &far_table[i]; 1574. } 1575.  1576.  1577. /*  1578.  * If the far table has an entry of OFF_TABLE, then the far block prevents 1579. * us from seeing the location just above/below it. I.e. the first visible 1580. * location is one *before* the block. 1581. */  1582. #define OFF_TABLE 0xff 1583. 1584. STATIC_OVL int 1585. close_shadow(side,this_row,block_row,block_col) 1586.    int side,this_row,block_row,block_col; 1587. { 1588.     register int sdy, sdx, pdy, offset; 1589. 1590.     /*  1591.      * If on the same column (block_row = -1), then we can see it. 1592.     */  1593.     if (block_row < 0) return block_col; 1594. 1595.     /* Take explicit absolute values. Adjust. */ 1596.     if ((sdy = (start_row-block_row)) < 0) sdy = -sdy; --sdy;	/* src   dy */ 1597.    if ((sdx = (start_col-block_col)) < 0) sdx = -sdx;		/* src   dx */ 1598.    if ((pdy = (block_row-this_row))  < 0) pdy = -pdy;		/* point dy */ 1599. 1600.     if (sdy < 0 || sdy >= CLOSE_MAX_SB_DY || sdx >= CLOSE_MAX_SB_DX ||  1601. 						    pdy >= CLOSE_MAX_BC_DY) { 1602. 	impossible("close_shadow: bad value"); 1603. 	return block_col; 1604.    }  1605.     offset = close_dy[sdy]->close[sdx][pdy]; 1606.    if (side == FROM_RIGHT) 1607. 	return block_col + offset; 1608. 1609.     return block_col - offset; 1610. } 1611.  1612.  1613. STATIC_OVL int 1614. far_shadow(side,this_row,block_row,block_col) 1615.    int side,this_row,block_row,block_col; 1616. { 1617.     register int sdy, sdx, pdy, offset; 1618. 1619.     /*  1620.      * Take care of a bug that shows up only on the borders. 1621.     *  1622.      * If the block is beyond the border, then the row is negative. Return 1623.     * the block's column number (should be 0 or COLNO-1). 1624.     *  1625.      * Could easily have the column be -1, but then wouldn't know if it was 1626.     * the left or right border. 1627.     */  1628.     if (block_row < 0) return block_col; 1629. 1630.     /* Take explicit absolute values. Adjust. */ 1631.     if ((sdy = (start_row-block_row)) < 0) sdy = -sdy;		/* src   dy */ 1632.    if ((sdx = (start_col-block_col)) < 0) sdx = -sdx; --sdx;	/* src   dx */ 1633.    if ((pdy = (block_row-this_row))  < 0) pdy = -pdy; --pdy;	/* point dy */ 1634. 1635.     if (sdy >= FAR_MAX_SB_DY || sdx < 0 || sdx >= FAR_MAX_SB_DX ||  1636. 					    pdy < 0 || pdy >= FAR_MAX_BC_DY) { 1637. 	impossible("far_shadow: bad value"); 1638. 	return block_col; 1639.    }  1640.     if ((offset = far_dy[sdy]->far_q[sdx][pdy]) == OFF_TABLE) offset = -1; 1641.    if (side == FROM_RIGHT) 1642. 	return block_col + offset; 1643. 1644.     return block_col - offset; 1645. } 1646.  1647.  1648. /*  1649.  * right_side 1650. *  1651.  * Figure out what could be seen on the right side of the source. 1652. */  1653. STATIC_OVL void 1654. right_side(row, cb_row, cb_col, fb_row, fb_col, left, right_mark, limits) 1655.    int row;		/* current row */ 1656.    int	cb_row, cb_col;	/* close block row and col */ 1657.    int	fb_row, fb_col;	/* far block row and col */ 1658.    int left;		/* left mark of the previous row */ 1659.    int	right_mark;	/* right mark of previous row */ 1660.    char *limits;	/* points at range limit for current row, or NULL */ 1661. { 1662.     register int  i;  1663. register char *rowp; 1664.    int  hit_stone = 0; 1665.    int  left_shadow, right_shadow, loc_right; 1666.    int  lblock_col;		/* local block column (current row) */ 1667.    int  nrow, deeper; 1668.    char *row_min;		/* left most */ 1669.    char *row_max;		/* right most */ 1670.    int		  lim_max;	/* right most limit of circle */ 1671. 1672. #ifdef GCC_WARN 1673.    rowp = 0; 1674. #endif 1675.    nrow    = row + step; 1676. #ifdef GCC_WARN 1677.    rowp = row_min = row_max = NULL; 1678.    lblock_col = 0; 1679. #endif 1680.    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1))); 1681.    if(!vis_func) { 1682. 	rowp   = cs_rows[row]; 1683. 	row_min = &cs_left[row]; 1684. 	row_max = &cs_right[row]; 1685.    }  1686.     if(limits) { 1687. 	lim_max = start_col + *limits; 1688. 	if(lim_max > COLNO-1) lim_max = COLNO-1; 1689. 	if(right_mark > lim_max) right_mark = lim_max; 1690. 	limits++; /* prepare for next row */ 1691.    } else 1692. 	lim_max = COLNO-1; 1693. 1694.     /*  1695.      * Get the left shadow from the close block. This value could be 1696. * illegal. 1697.     */  1698.     left_shadow = close_shadow(FROM_RIGHT,row,cb_row,cb_col); 1699. 1700.     /*  1701.      * Mark all stone walls as seen before the left shadow. All this work 1702.     * for a special case. 1703.     *  1704.      * NOTE. With the addition of this code in here, it is now *required* 1705.     * for the algorithm to work correctly. If this is commented out, 1706.     * change the above assignment so that left and not left_shadow is the 1707.     * variable that gets the shadow. 1708.     */  1709.     while (left <= right_mark) { 1710. 	loc_right = right_ptrs[row][left]; 1711. 	if(loc_right > lim_max) loc_right = lim_max; 1712. 	if (viz_clear_rows[row][left]) { 1713. 	   if (loc_right >= left_shadow) { 1714. 		left = left_shadow;	/* opening ends beyond shadow */ 1715. 		break; 1716. 	   }  1717. 	    left = loc_right; 1718. 	   loc_right = right_ptrs[row][left]; 1719. 	   if(loc_right > lim_max) loc_right = lim_max; 1720. 	   if (left == loc_right) return;	/* boundary */ 1721. 1722. 	    /* Shadow covers opening, beyond right mark */ 1723. 	   if (left == right_mark && left_shadow > right_mark) return; 1724. 	} 1725.  1726. 	if (loc_right > right_mark)	/* can't see stone beyond the mark */ 1727. 	   loc_right = right_mark; 1728. 1729. 	if(vis_func) { 1730. 	   for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); 1731. 	} else { 1732. 	   for (i = left; i <= loc_right; i++) set_cs(rowp,i); 1733. 	   set_min(left);	set_max(loc_right); 1734. 	} 1735.  1736. 	if (loc_right == right_mark) return;	/* all stone */ 1737. 	if (loc_right >= left_shadow) hit_stone = 1; 1738. 	left = loc_right + 1; 1739.    }  1740.  1741.     /*  1742.      * At this point we are at the first visible clear spot on or beyond 1743.     * the left shadow, unless the left shadow is an illegal value. If we 1744. * have "hit stone" then we have a stone wall just to our left. 1745.     */  1746.  1747.     /*  1748.      * Get the right shadow. Make sure that it is a legal value. 1749.     */  1750.     if ((right_shadow = far_shadow(FROM_RIGHT,row,fb_row,fb_col)) >= COLNO) 1751. 	right_shadow = COLNO-1; 1752.    /*  1753.      * Make vertical walls work the way we want them. In this case, we 1754. * note when the close block blocks the column just above/beneath 1755.     * it (right_shadow < fb_col [actually right_shadow == fb_col-1]). If 1756. * the location is filled, then we want to see it, so we put the 1757.     * right shadow back (same as fb_col). 1758.     */  1759.     if (right_shadow < fb_col && !viz_clear_rows[row][fb_col]) 1760. 	right_shadow = fb_col; 1761.    if(right_shadow > lim_max) right_shadow = lim_max; 1762. 1763.     /*  1764.      * Main loop. Within the range of sight of the previous row, mark all 1765.     * stone walls as seen. Follow open areas recursively. 1766.     */  1767.     while (left <= right_mark) { 1768. 	/* Get the far right of the opening or wall */ 1769. 	loc_right = right_ptrs[row][left]; 1770. 	if(loc_right > lim_max) loc_right = lim_max; 1771. 1772. 	if (!viz_clear_rows[row][left]) { 1773. 	   hit_stone = 1;	/* use stone on this row as close block */ 1774. 	   /*  1775. 	     * We can see all of the wall until the next open spot or the 1776. 	    * start of the shadow caused by the far block (right). 1777. 	    *  1778. 	     * Can't see stone beyond the right mark. 1779. 	    */  1780. 	    if (loc_right > right_mark) loc_right = right_mark; 1781. 1782. 	    if(vis_func) { 1783. 		for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); 1784. 	   } else { 1785. 		for (i = left; i <= loc_right; i++) set_cs(rowp,i); 1786. 		set_min(left);	set_max(loc_right); 1787. 	   }  1788.  1789. 	    if (loc_right == right_mark) return;	/* hit the end */ 1790. 	   left = loc_right + 1; 1791. 	   loc_right = right_ptrs[row][left]; 1792. 	   if(loc_right > lim_max) loc_right = lim_max; 1793. 	   /* fall through... we know at least one position is visible */ 1794. 	} 1795.  1796. 	/*  1797. 	 * We are in an opening. 1798. 	 * 1799. 	 * If this is the first open spot since the could see area  (this is  1800. 	 * true if we have hit stone), get the shadow generated by the wall 1801. 	 * just to our left. 1802. 	 */ 1803. 	if (hit_stone) { 1804. 	   lblock_col = left-1;	/* local block column */ 1805. 	   left = close_shadow(FROM_RIGHT,row,row,lblock_col); 1806. 	   if (left > lim_max) break;		/* off the end */ 1807. 	} 1808.  1809. 	/*  1810. 	 * Check if the shadow covers the opening. If it does, then 1811. 	 * move to end of the opening. A shadow generated on from a 1812. * wall on this row does *not* cover the wall on the right 1813. 	 * of the opening. 1814. 	 */ 1815. 	if (left >= loc_right) { 1816. 	   if (loc_right == lim_max) {		/* boundary */ 1817. 		if (left == lim_max) { 1818. 		   if(vis_func) (*vis_func)(lim_max, row, varg); 1819. 		   else { 1820. 			set_cs(rowp,lim_max);	/* last pos */ 1821. 			set_max(lim_max); 1822. 		   }  1823. 		}  1824. 		return;					/* done */ 1825. 	   }  1826. 	    left = loc_right; 1827. 	   continue; 1828. 	} 1829.  1830. 	/*  1831. 	 * If the far wall of the opening (loc_right) is closer than the 1832. 	 * shadow limit imposed by the far block (right) then use the far 1833. 	 * wall as our new far block when we recurse. 1834. 	 * 1835. 	 * If the limits are the the same, and the far block really exists 1836. 	 * (fb_row >= 0) then do the same as above. 1837. 	 * 1838. 	 * Normally, the check would be for the far wall being closer OR EQUAL 1839. 	 * to the shadow limit. However, there is a bug that arises from the 1840. 	 * fact that the clear area pointers end in an open space (if it 1841. 	 * exists) on a boundary. This then makes a far block exist where it 1842. * shouldn't --- on a boundary. To get around that, I had to 1843. * introduce the concept of a non-existent far block (when the 1844. 	 * row < 0). Next I have to check for it. Here is where that check 1845. 	 * exists. 1846. 	 */ 1847. 	if ((loc_right < right_shadow) ||  1848. 				(fb_row >= 0 && loc_right == right_shadow)) { 1849. 	   if(vis_func) { 1850. 		for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); 1851. 	   } else { 1852. 		for (i = left; i <= loc_right; i++) set_cs(rowp,i); 1853. 		set_min(left);	set_max(loc_right); 1854. 	   }  1855.  1856. 	    if (deeper) { 1857. 		if (hit_stone) 1858. 		   right_side(nrow,row,lblock_col,row,loc_right,  1859. 							left,loc_right,limits); 1860. 		else 1861. 		   right_side(nrow,cb_row,cb_col,row,loc_right,  1862. 							left,loc_right,limits); 1863. 	   }  1864.  1865. 	    /*  1866. 	     * The following line, setting hit_stone, is needed for those 1867. 	    * walls that are only 1 wide. If hit stone is *not* set and 1868. 	    * the stone is only one wide, then the close block is the old 1869. 	    * one instead one on the current row. A way around having to 1870. * set it here is to make left = loc_right (not loc_right+1) and 1871. 	    * let the outer loop take care of it. However, if we do that 1872. 	    * then we then have to check for boundary conditions here as  1873. * well. 1874. 	    */  1875. 	    hit_stone = 1; 1876. 1877. 	    left = loc_right+1; 1878. 	} 1879. 	/*  1880. 	 * The opening extends beyond the right mark. This means that 1881. 	 * the next far block is the current far block. 1882. 	 */ 1883. 	else { 1884. 	   if(vis_func) { 1885. 		for (i=left; i <= right_shadow; i++) (*vis_func)(i, row, varg); 1886. 	   } else { 1887. 		for (i = left; i <= right_shadow; i++) set_cs(rowp,i); 1888. 		set_min(left);	set_max(right_shadow); 1889. 	   }  1890.  1891. 	    if (deeper) { 1892. 		if (hit_stone) 1893. 		   right_side(nrow,   row,lblock_col,fb_row,fb_col,  1894. 						     left,right_shadow,limits); 1895. 		else 1896. 		   right_side(nrow,cb_row,    cb_col,fb_row,fb_col,  1897. 						     left,right_shadow,limits); 1898. 	   }  1899.  1900. 	    return;	/* we're outta here */ 1901. 	} 1902.     }  1903. }  1904.  1905.  1906. /*  1907.  * left_side 1908. *  1909.  * This routine is the mirror image of right_side. Please see right_side 1910. * for blow by blow comments. 1911. */  1912. STATIC_OVL void 1913. left_side(row, cb_row, cb_col, fb_row, fb_col, left_mark, right, limits) 1914.    int row;		/* the current row */ 1915.    int	cb_row, cb_col;	/* close block row and col */ 1916.    int	fb_row, fb_col;	/* far block row and col */ 1917.    int	left_mark;	/* left mark of previous row */ 1918.    int right;		/* right mark of the previous row */ 1919.    char *limits; 1920. { 1921.     register int  i;  1922. register char *rowp; 1923.    int  hit_stone = 0; 1924.    int  left_shadow, right_shadow, loc_left; 1925.    int  lblock_col;		/* local block column (current row) */ 1926.    int  nrow, deeper; 1927.    char *row_min;		/* left most */ 1928.    char *row_max;		/* right most */ 1929.    int		  lim_min; 1930. 1931. #ifdef GCC_WARN 1932.    rowp = row_min = row_max = NULL; 1933.    lblock_col = 0; 1934. #endif 1935.    nrow    = row + step; 1936.    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1))); 1937.    if(!vis_func) { 1938. 	rowp   = cs_rows[row]; 1939. 	row_min = &cs_left[row]; 1940. 	row_max = &cs_right[row]; 1941.    }  1942.     if(limits) { 1943. 	lim_min = start_col - *limits; 1944. 	if(lim_min < 0) lim_min = 0; 1945. 	if(left_mark < lim_min) left_mark = lim_min; 1946. 	limits++; /* prepare for next row */ 1947.    } else 1948. 	lim_min = 0; 1949. 1950.     /* This value could be illegal. */ 1951.     right_shadow = close_shadow(FROM_LEFT,row,cb_row,cb_col); 1952. 1953.     while ( right >= left_mark ) { 1954. 	loc_left = left_ptrs[row][right]; 1955. 	if(loc_left < lim_min) loc_left = lim_min; 1956. 	if (viz_clear_rows[row][right]) { 1957. 	   if (loc_left <= right_shadow) { 1958. 		right = right_shadow;	/* opening ends beyond shadow */ 1959. 		break; 1960. 	   }  1961. 	    right = loc_left; 1962. 	   loc_left = left_ptrs[row][right]; 1963. 	   if(loc_left < lim_min) loc_left = lim_min; 1964. 	   if (right == loc_left) return;	/* boundary */ 1965. 	} 1966.  1967. 	if (loc_left < left_mark)	/* can't see beyond the left mark */ 1968. 	   loc_left = left_mark; 1969. 1970. 	if(vis_func) { 1971. 	   for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); 1972. 	} else { 1973. 	   for (i = loc_left; i <= right; i++) set_cs(rowp,i); 1974. 	   set_min(loc_left);	set_max(right); 1975. 	} 1976.  1977. 	if (loc_left == left_mark) return;	/* all stone */ 1978. 	if (loc_left <= right_shadow) hit_stone = 1; 1979. 	right = loc_left - 1; 1980.    }  1981.  1982.     /* At first visible clear spot on or beyond the right shadow. */ 1983.  1984.     if ((left_shadow = far_shadow(FROM_LEFT,row,fb_row,fb_col)) < 0) 1985. 	left_shadow = 0; 1986. 1987.     /* Do vertical walls as we want. */ 1988.     if (left_shadow > fb_col && !viz_clear_rows[row][fb_col]) 1989. 	left_shadow = fb_col; 1990.    if(left_shadow < lim_min) left_shadow = lim_min; 1991. 1992.     while (right >= left_mark) { 1993. 	loc_left = left_ptrs[row][right]; 1994. 1995. 	if (!viz_clear_rows[row][right]) { 1996. 	   hit_stone = 1;	/* use stone on this row as close block */ 1997. 1998. 	    /* We can only see walls until the left mark */ 1999. 	   if (loc_left < left_mark) loc_left = left_mark; 2000. 2001. 	    if(vis_func) { 2002. 		for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); 2003. 	   } else { 2004. 		for (i = loc_left; i <= right; i++) set_cs(rowp,i); 2005. 		set_min(loc_left);	set_max(right); 2006. 	   }  2007.  2008. 	    if (loc_left == left_mark) return;	/* hit end */ 2009. 	   right = loc_left - 1; 2010. 	   loc_left = left_ptrs[row][right]; 2011. 	   if (loc_left < lim_min) loc_left = lim_min; 2012. 	   /* fall through...*/ 2013. 	} 2014.  2015. 	/* We are in an opening. */ 2016. 	if (hit_stone) { 2017. 	   lblock_col = right+1;	/* stone block (local) */ 2018. 	   right = close_shadow(FROM_LEFT,row,row,lblock_col); 2019. 	   if (right < lim_min) return;	/* off the end */ 2020. 	} 2021.  2022. 	/*  Check if the shadow covers the opening. */ 2023. 	if (right <= loc_left) { 2024. 	   /*  Make a boundary condition work. */ 2025. 	    if (loc_left == lim_min) {	/* at boundary */ 2026. 		if (right == lim_min) { 2027. 		   if(vis_func) (*vis_func)(lim_min, row, varg); 2028. 		   else { 2029. 			set_cs(rowp,lim_min);	/* caught the last pos */ 2030. 			set_min(lim_min); 2031. 		   }  2032. 		}  2033. 		return;			/* and break out the loop */ 2034. 	   }  2035.  2036. 	    right = loc_left; 2037. 	   continue; 2038. 	} 2039.  2040. 	/* If the far wall of the opening is closer than the shadow limit. */ 2041. 	if ((loc_left > left_shadow) ||  2042. 				    (fb_row >= 0 && loc_left == left_shadow)) { 2043. 	   if(vis_func) { 2044. 		for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); 2045. 	   } else { 2046. 		for (i = loc_left; i <= right; i++) set_cs(rowp,i); 2047. 		set_min(loc_left);	set_max(right); 2048. 	   }  2049.  2050. 	    if (deeper) { 2051. 		if (hit_stone) 2052. 		   left_side(nrow,row,lblock_col,row,loc_left,  2053. 							loc_left,right,limits); 2054. 		else 2055. 		   left_side(nrow,cb_row,cb_col,row,loc_left,  2056. 							loc_left,right,limits); 2057. 	   }  2058.  2059. 	    hit_stone = 1;	/* needed for walls of width 1 */ 2060. 	   right = loc_left-1; 2061. 	} 2062. 	/*  The opening extends beyond the left mark. */ 2063. 	else { 2064. 	   if(vis_func) { 2065. 		for (i=left_shadow; i <= right; i++) (*vis_func)(i, row, varg); 2066. 	   } else { 2067. 		for (i = left_shadow; i <= right; i++) set_cs(rowp,i); 2068. 		set_min(left_shadow);	set_max(right); 2069. 	   }  2070.  2071. 	    if (deeper) { 2072. 		if (hit_stone) 2073. 		   left_side(nrow,row,lblock_col,fb_row,fb_col,  2074. 						     left_shadow,right,limits); 2075. 		else 2076. 		   left_side(nrow,cb_row,cb_col,fb_row,fb_col,  2077. 						     left_shadow,right,limits); 2078. 	   }  2079.  2080. 	    return;	/* we're outta here */ 2081. 	} 2082.  2083.     }  2084. }  2085.  2086. /*  2087.  * view_from 2088. *  2089.  * Calculate a view from the given location. Initialize and fill a 2090. * ROWNOxCOLNO array (could_see) with all the locations that could be 2091. * seen from the source location. Initialize and fill the left most 2092. * and right most boundaries of what could be seen. 2093. */  2094. STATIC_OVL void 2095. view_from(srow,scol,loc_cs_rows,left_most,right_most, range, func, arg) 2096.    int  srow, scol;			/* source row and column */ 2097.    char **loc_cs_rows;			/* could_see array (row pointers) */ 2098.    char *left_most, *right_most;	/* limits of what could be seen */ 2099.    int range;		/* 0 if unlimited */ 2100.    void FDECL((*func), (int,int,genericptr_t)); 2101.    genericptr_t arg; 2102. { 2103.     register int i;  2104. char	 *rowp; 2105.    int		 nrow, left, right, left_row, right_row; 2106.    char	 *limits; 2107. 2108.     /* Set globals for near_shadow, far_shadow, etc. to use. */ 2109.     start_col = scol; 2110.    start_row = srow; 2111.    cs_rows   = loc_cs_rows; 2112.    cs_left   = left_most; 2113.    cs_right  = right_most; 2114.    vis_func = func; 2115.    varg = arg; 2116. 2117.     /*  Find the left and right limits of sight on the starting row. */ 2118.     if (viz_clear_rows[srow][scol]) { 2119. 	left = left_ptrs[srow][scol]; 2120. 	right = right_ptrs[srow][scol]; 2121.    } else { 2122. 	left = (!scol) ? 0 : 2123. 	    (viz_clear_rows[srow][scol-1] ?  left_ptrs[srow][scol-1] : scol-1); 2124. 	right = (scol == COLNO-1) ? COLNO-1 : 2125. 	   (viz_clear_rows[srow][scol+1] ? right_ptrs[srow][scol+1] : scol+1); 2126.    }  2127.  2128.     if(range) { 2129. 	if(range > MAX_RADIUS || range < 1) 2130. 	   panic("view_from called with range %d", range); 2131. 	limits = circle_ptr(range) + 1; /* start at next row */ 2132. 	if(left < scol - range) left = scol - range; 2133. 	if(right > scol + range) right = scol + range; 2134.    } else 2135. 	limits = (char*) 0; 2136. 2137.     if(func) { 2138. 	for (i = left; i <= right; i++) (*func)(i, srow, arg); 2139.    } else { 2140. 	/* Row optimization */ 2141. 	rowp = cs_rows[srow]; 2142. 2143. 	/* We know that we can see our row. */ 2144. 	for (i = left; i <= right; i++) set_cs(rowp,i); 2145. 	cs_left[srow] = left; 2146. 	cs_right[srow] = right; 2147.    }  2148.  2149.     /* The far block has a row number of -1 if we are on an edge. */ 2150.     right_row = (right == COLNO-1) ? -1 : srow; 2151.    left_row  = (!left)		   ? -1 : srow; 2152. 2153.     /*  2154.      *  Check what could be seen in quadrants. 2155.     */  2156.     if ( (nrow = srow+1) < ROWNO ) { 2157. 	step = 1;	/* move down */ 2158. 	if (scol= 0 ) { 2165. 	step = -1;	/* move up */ 2166. 	if (scol<COLNO-1) 2167. 	   right_side(nrow,-1,scol,right_row,right,scol,right,limits); 2168. 	if (scol) 2169. 	   left_side(nrow,-1,scol,left_row, left, left, scol,limits); 2170.    }  2171. }  2172.  2173.  2174. #else	/*===== End of algorithm D =====*/ 2175. 2176.  2177. /*===========================================================================*\  2178. 			    GENERAL LINE OF SIGHT 2179. 				Algorithm C 2180. \*===========================================================================*/ 2181.  2182. /*  2183.  * Defines local to Algorithm C.  2184. */ 2185. STATIC_DCL void FDECL(right_side, (int,int,int,char*)); 2186. STATIC_DCL void FDECL(left_side, (int,int,int,char*)); 2187. 2188. /* Initialize algorithm C (nothing). */ 2189. STATIC_OVL void 2190. view_init 2191. { 2192. }  2193.  2194. /*  2195.  * Mark positions as visible on one quadrant of the right side. The 2196. * quadrant is determined by the value of the global variable step. 2197. */  2198. STATIC_OVL void 2199. right_side(row, left, right_mark, limits) 2200.    int row;		/* current row */ 2201.    int left;		/* first (left side) visible spot on prev row */ 2202.    int right_mark;	/* last (right side) visible spot on prev row */ 2203.    char *limits;	/* points at range limit for current row, or NULL */ 2204. { 2205.     int		  right;	/* right limit of "could see" */ 2206.    int		  right_edge;	/* right edge of an opening */ 2207.    int		  nrow;		/* new row (calculate once) */ 2208.    int		  deeper;	/* if TRUE, call self as needed */ 2209.    int		  result;	/* set by q?_path */ 2210.    register int  i;		/* loop counter */ 2211.    register char *rowp;	/* row optimization */ 2212.    char	  *row_min;	/* left most  [used by macro set_min] */ 2213.    char	  *row_max;	/* right most [used by macro set_max] */ 2214.    int		  lim_max;	/* right most limit of circle */ 2215. 2216. #ifdef GCC_WARN 2217.    rowp = row_min = row_max = 0; 2218. #endif 2219.    nrow    = row + step; 2220.    /*  2221.      * Can go deeper if the row is in bounds and the next row is within 2222.     * the circle's limit. We tell the latter by checking to see if the next 2223.     * limit value is the start of a new circle radius (meaning we depend  2224.      * on the structure of circle_data[]). 2225.     */  2226.     deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1))); 2227.    if(!vis_func) { 2228. 	rowp   = cs_rows[row];	/* optimization */ 2229. 	row_min = &cs_left[row]; 2230. 	row_max = &cs_right[row]; 2231.    }  2232.     if(limits) { 2233. 	lim_max = start_col + *limits; 2234. 	if(lim_max > COLNO-1) lim_max = COLNO-1; 2235. 	if(right_mark > lim_max) right_mark = lim_max; 2236. 	limits++; /* prepare for next row */ 2237.    } else 2238. 	lim_max = COLNO-1; 2239. 2240.     while (left <= right_mark) { 2241. 	right_edge = right_ptrs[row][left]; 2242. 	if(right_edge > lim_max) right_edge = lim_max; 2243. 2244. 	if (!is_clear(row,left)) { 2245. 	   /*  2246. 	     * Jump to the far side of a stone wall. We can set all 2247. 	    * the points in between as seen. 2248. 	    *  2249. 	     * If the right edge goes beyond the right mark, check to see 2250. 	    * how much we can see. 2251. 	    */  2252. 	    if (right_edge > right_mark) { 2253. 		/* 2254. 		 * If the mark on the previous row was a clear position, 2255. 		 * the odds are that we can actually see part of the wall 2256. 		 * beyond the mark on this row. If so, then see one beyond 2257. 		 * the mark. Otherwise don't. This is a kludge so corners 2258. 		 * with an adjacent doorway show up in nethack. 2259. 		 */ 2260. 		right_edge = is_clear(row-step,right_mark) ? 2261. 						   right_mark+1 : right_mark; 2262. 	   }  2263. 	    if(vis_func) { 2264. 		for (i = left; i <= right_edge; i++) (*vis_func)(i, row, varg); 2265. 	   } else { 2266. 		for (i = left; i <= right_edge; i++) set_cs(rowp,i); 2267. 		set_min(left);     set_max(right_edge); 2268. 	   }  2269. 	    left = right_edge + 1; /* no limit check necessary */ 2270. 	   continue; 2271. 	} 2272.  2273. 	/* No checking needed if our left side is the start column. */ 2274. 	if (left != start_col) { 2275. 	   /*  2276. 	     * Find the left side. Move right until we can see it or we run 2277. 	    * into a wall. 2278. 	    */  2279. 	    for (left <= right_edge; left++) { 2280. 		if (step < 0) { 2281. 		   q1_path(start_row,start_col,row,left,rside1); 2282. 		} else { 2283. 		   q4_path(start_row,start_col,row,left,rside1); 2284. 		} 2285. rside1:					/* used if q?_path is a macro */ 2286. 		if (result) break; 2287. 	   }  2288.  2289. 	    /*  2290. 	     * Check for boundary conditions. We *need* check (2) to break 2291. 	    * an infinite loop where: 2292. 	    *  2293. 	     *		left == right_edge == right_mark == lim_max. 2294. 	    *  2295. 	     */  2296. 	    if (left > lim_max) return;	/* check (1) */ 2297. 	   if (left == lim_max) {	/* check (2) */ 2298. 		if(vis_func) (*vis_func)(lim_max, row, varg); 2299. 		else { 2300. 		   set_cs(rowp,lim_max); 2301. 		   set_max(lim_max); 2302. 		} 2303. 		return; 2304. 	   }  2305. 	    /*  2306. 	     * Check if we can see any spots in the opening. We might 2307. 	    * (left == right_edge) or might not (left == right_edge+1) have 2308. 	    * been able to see the far wall. Make sure we *can* see the 2309. 	    * wall (remember, we can see the spot above/below this one) 2310. 	    * by backing up. 2311. 	    */  2312. 	    if (left >= right_edge) { 2313. 		left = right_edge;	/* for the case left == right_edge+1 */ 2314. 		continue; 2315. 	   }  2316. 	}  2317.  2318. 	/*  2319. 	 * Find the right side. If the marker from the previous row is 2320. * closer than the edge on this row, then we have to check 2321. 	 * how far we can see around the corner (under the overhang). Stop 2322. 	 * at the first non-visible spot or we actually hit the far wall. 2323. 	 * 2324. 	 * Otherwise, we know we can see the right edge of the current row. 2325. 	 * 2326. 	 * This must be a strict less than so that we can always see a  2327. * horizontal wall, even if it is adjacent to us. 2328. 	 */ 2329. 	if (right_mark < right_edge) { 2330. 	   for (right = right_mark; right <= right_edge; right++) { 2331. 		if (step < 0) { 2332. 		   q1_path(start_row,start_col,row,right,rside2); 2333. 		} else { 2334. 		   q4_path(start_row,start_col,row,right,rside2); 2335. 		} 2336. rside2:					/* used if q?_path is a macro */ 2337. 		if (!result) break; 2338. 	   }  2339. 	    --right;	/* get rid of the last increment */ 2340. 	} 2341. 	else 2342. 	   right = right_edge; 2343. 2344. 	/*  2345. 	 * We have the range that we want. Set the bits. Note that 2346. 	 * there is no else --- we no longer handle splinters. 2347. 	 */ 2348. 	if (left <= right) { 2349. 	   /*  2350. 	     * An ugly special case. If you are adjacent to a vertical wall 2351. 	    * and it has a break in it, then the right mark is set to be  2352. * start_col. We *want* to be able to see adjacent vertical 2353. 	    * walls, so we have to set it back. 2354. 	    */  2355. 	    if (left == right && left == start_col &&  2356. 			start_col < (COLNO-1) && !is_clear(row,start_col+1)) 2357. 		right = start_col+1; 2358. 2359. 	    if(right > lim_max) right = lim_max; 2360. 	   /* set the bits */ 2361. 	   if(vis_func) 2362. 		for (i = left; i <= right; i++) (*vis_func)(i, row, varg); 2363. 	   else { 2364. 		for (i = left; i <= right; i++) set_cs(rowp,i); 2365. 		set_min(left);     set_max(right); 2366. 	   }  2367.  2368. 	    /* recursive call for next finger of light */ 2369. 	   if (deeper) right_side(nrow,left,right,limits); 2370. 	   left = right + 1; /* no limit check necessary */ 2371. 	} 2372.     }  2373. }  2374.  2375.  2376. /*  2377.  * This routine is the mirror image of right_side. See right_side for 2378. * extensive comments. 2379. */  2380. STATIC_OVL void 2381. left_side(row, left_mark, right, limits) 2382.    int row, left_mark, right; 2383.    char *limits; 2384. { 2385.     int		  left, left_edge, nrow, deeper, result; 2386.    register int  i;  2387. register char *rowp; 2388.    char	  *row_min, *row_max; 2389.    int		  lim_min; 2390. 2391. #ifdef GCC_WARN 2392.    rowp = row_min = row_max = 0; 2393. #endif 2394.    nrow    = row+step; 2395.    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1))); 2396.    if(!vis_func) { 2397. 	rowp   = cs_rows[row]; 2398. 	row_min = &cs_left[row]; 2399. 	row_max = &cs_right[row]; 2400.    }  2401.     if(limits) { 2402. 	lim_min = start_col - *limits; 2403. 	if(lim_min < 0) lim_min = 0; 2404. 	if(left_mark < lim_min) left_mark = lim_min; 2405. 	limits++; /* prepare for next row */ 2406.    } else 2407. 	lim_min = 0; 2408. 2409.     while (right >= left_mark) { 2410. 	left_edge = left_ptrs[row][right]; 2411. 	if(left_edge < lim_min) left_edge = lim_min; 2412. 2413. 	if (!is_clear(row,right)) { 2414. 	   /* Jump to the far side of a stone wall. */ 2415. 	    if (left_edge < left_mark) { 2416. 		/* Maybe see more (kludge). */ 2417. 		left_edge = is_clear(row-step,left_mark) ? 2418. 						   left_mark-1 : left_mark; 2419. 	   }  2420. 	    if(vis_func) { 2421. 		for (i = left_edge; i <= right; i++) (*vis_func)(i, row, varg); 2422. 	   } else { 2423. 		for (i = left_edge; i <= right; i++) set_cs(rowp,i); 2424. 		set_min(left_edge); set_max(right); 2425. 	   }  2426. 	    right = left_edge - 1; /* no limit check necessary */ 2427. 	   continue; 2428. 	} 2429.  2430. 	if (right != start_col) { 2431. 	   /* Find the right side. */ 2432. 	    for (right >= left_edge; right--) { 2433. 		if (step < 0) { 2434. 		   q2_path(start_row,start_col,row,right,lside1); 2435. 		} else { 2436. 		   q3_path(start_row,start_col,row,right,lside1); 2437. 		} 2438. lside1:					/* used if q?_path is a macro */ 2439. 		if (result) break; 2440. 	   }  2441.  2442. 	    /* Check for boundary conditions. */ 2443. 	    if (right < lim_min) return; 2444. 	   if (right == lim_min) { 2445. 		if(vis_func) (*vis_func)(lim_min, row, varg); 2446. 		else { 2447. 		   set_cs(rowp,lim_min); 2448. 		   set_min(lim_min); 2449. 		} 2450. 		return; 2451. 	   }  2452. 	    /* Check if we can see any spots in the opening. */ 2453. 	    if (right <= left_edge) { 2454. 		right = left_edge; 2455. 		continue; 2456. 	   }  2457. 	}  2458.  2459. 	/* Find the left side. */ 2460. 	if (left_mark > left_edge) { 2461. 	   for (left = left_mark; left >= left_edge; --left) { 2462. 		if (step < 0) { 2463. 		   q2_path(start_row,start_col,row,left,lside2); 2464. 		} else { 2465. 		   q3_path(start_row,start_col,row,left,lside2); 2466. 		} 2467. lside2:					/* used if q?_path is a macro */ 2468. 		if (!result) break; 2469. 	   }  2470. 	    left++;	/* get rid of the last decrement */ 2471. 	} 2472. 	else 2473. 	   left = left_edge; 2474. 2475. 	if (left <= right) { 2476. 	   /* An ugly special case. */ 2477. 	    if (left == right && right == start_col &&  2478. 			    start_col > 0 && !is_clear(row,start_col-1)) 2479. 		left = start_col-1; 2480. 2481. 	    if(left < lim_min) left = lim_min; 2482. 	   if(vis_func) 2483. 		for (i = left; i <= right; i++) (*vis_func)(i, row, varg); 2484. 	   else { 2485. 		for (i = left; i <= right; i++) set_cs(rowp,i); 2486. 		set_min(left);     set_max(right); 2487. 	   }  2488.  2489. 	    /* Recurse */ 2490. 	   if (deeper) left_side(nrow,left,right,limits); 2491. 	   right = left - 1; /* no limit check necessary */ 2492. 	} 2493.     }  2494. }  2495.  2496.  2497. /*  2498.  * Calculate all possible visible locations from the given location 2499. * (srow,scol). NOTE this is (y,x)! Mark the visible locations in the 2500. * array provided. 2501. */  2502. STATIC_OVL void 2503. view_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg) 2504.    int  srow, scol;	/* starting row and column */ 2505.    char **loc_cs_rows;	/* pointers to the rows of the could_see array */ 2506.    char *left_most;	/* min mark on each row */ 2507.    char *right_most;	/* max mark on each row */ 2508.    int range;		/* 0 if unlimited */ 2509.    void FDECL((*func), (int,int,genericptr_t)); 2510.    genericptr_t arg; 2511. { 2512.     register int i;		/* loop counter */ 2513.    char         *rowp;		/* optimization for setting could_see */ 2514.    int		 nrow;		/* the next row */ 2515.    int		 left;		/* the left-most visible column */ 2516.    int		 right;		/* the right-most visible column */ 2517.    char	 *limits;	/* range limit for next row */ 2518. 2519.     /* Set globals for q?_path, left_side, and right_side to use. */ 2520.     start_col = scol; 2521.    start_row = srow; 2522.    cs_rows   = loc_cs_rows;	/* 'could see' rows */ 2523.    cs_left   = left_most; 2524.    cs_right  = right_most; 2525.    vis_func = func; 2526.    varg = arg; 2527. 2528.     /*  2529.      * Determine extent of sight on the starting row. 2530.     */  2531.     if (is_clear(srow,scol)) { 2532. 	left = left_ptrs[srow][scol]; 2533. 	right = right_ptrs[srow][scol]; 2534.    } else { 2535. 	/* 2536. 	 * When in stone, you can only see your adjacent squares, unless 2537. 	 * you are on an array boundary or a stone/clear boundary. 2538. 	 */ 2539. 	left  = (!scol) ? 0 : 2540. 		(is_clear(srow,scol-1) ? left_ptrs[srow][scol-1] : scol-1); 2541. 	right = (scol == COLNO-1) ? COLNO-1 : 2542. 		(is_clear(srow,scol+1) ? right_ptrs[srow][scol+1] : scol+1); 2543.    }  2544.  2545.     if(range) { 2546. 	if(range > MAX_RADIUS || range < 1) 2547. 	   panic("view_from called with range %d", range); 2548. 	limits = circle_ptr(range) + 1; /* start at next row */ 2549. 	if(left < scol - range) left = scol - range; 2550. 	if(right > scol + range) right = scol + range; 2551.    } else 2552. 	limits = (char*) 0; 2553. 2554.     if(func) { 2555. 	for (i = left; i <= right; i++) (*func)(i, srow, arg); 2556.    } else { 2557. 	/* Row pointer optimization. */ 2558. 	rowp = cs_rows[srow]; 2559. 2560. 	/* We know that we can see our row. */ 2561. 	for (i = left; i <= right; i++) set_cs(rowp,i); 2562. 	cs_left[srow] = left; 2563. 	cs_right[srow] = right; 2564.    }  2565.  2566.     /*  2567.      * Check what could be seen in quadrants. We need to check for valid 2568.     * rows here, since we don't do it in the routines right_side and 2569.     * left_side [ugliness to remove extra routine calls]. 2570.     */  2571.     if ( (nrow = srow+1) < ROWNO ) {	/* move down */ 2572. 	step = 1; 2573. 	if (scol < COLNO-1) right_side(nrow, scol, right, limits); 2574. 	if (scol)	   left_side (nrow, left,  scol, limits); 2575.    }  2576.  2577.     if ( (nrow = srow-1) >= 0 ) {	/* move up */ 2578. 	step = -1; 2579. 	if (scol < COLNO-1) right_side(nrow, scol, right, limits); 2580. 	if (scol)	   left_side (nrow, left,  scol, limits); 2581.    }  2582. }  2583.  2584. #endif	/*===== End of algorithm C =====*/ 2585. 2586. /*  2587.  * AREA OF EFFECT "ENGINE" 2588. *  2589.  * Calculate all possible visible locations as viewed from the given location 2590. * (srow,scol) within the range specified. Perform "func" with (x, y) args and 2591. * additional argument "arg" for each square. 2592. *  2593.  * If not centered on the hero, just forward arguments to view_from; it  2594. * will call "func" when necessary. If the hero is the center, use the 2595. * vision matrix and reduce extra work. 2596. */  2597. void 2598. do_clear_area(scol,srow,range,func,arg) 2599.    int scol, srow, range; 2600.    void FDECL((*func), (int,int,genericptr_t)); 2601.    genericptr_t arg; 2602. { 2603. 	/* If not centered on hero, do the hard work of figuring the area */ 2604. 	if (scol != u.ux || srow != u.uy) 2605. 	   view_from(srow, scol, (char **)0, (char *)0, (char *)0,  2606. 							range, func, arg); 2607. 	else { 2608. 	   register int x;  2609. int y, min_x, max_x, max_y, offset; 2610. 	   char *limits; 2611. 2612. 	    if (range > MAX_RADIUS || range < 1) 2613. 		panic("do_clear_area: illegal range %d", range); 2614. 	   if(vision_full_recalc) 2615. 		vision_recalc(0);	/* recalc vision if dirty */ 2616. 	   limits = circle_ptr(range); 2617. 	   if ((max_y = (srow + range)) >= ROWNO) max_y = ROWNO-1; 2618. 	   if ((y = (srow - range)) < 0) y = 0; 2619. 	   for (y <= max_y; y++) { 2620. 		offset = limits[v_abs(y-srow)]; 2621. 		if((min_x = (scol - offset)) < 0) min_x = 0; 2622. 		if((max_x = (scol + offset)) >= COLNO) max_x = COLNO-1; 2623. 		for (x = min_x; x <= max_x; x++) 2624. 		   if (couldsee(x, y)) 2625. 			(*func)(x, y, arg); 2626. 	   }  2627. 	}  2628. }  2629.  2630. /*vision.c*/