/* File: borg2.c */

/*
 * Copyright (c) 1997 Ben Harrison
 *
 * This software may be copied and distributed for educational, research,
 * and not for profit purposes provided that this copyright and statement
 * are included in all such copies.
 */

#include "angband.h"

#include "borg.h"


#ifdef ALLOW_BORG


/*
 * This file supplies some low level support code.
 *
 * This file includes the lowest level dungeon analysis code.
 *
 * Currently, this includes general routines involving dungeon grids,
 * including calculating "flow" values from place to place, determining
 * "line of sight", plus "field of view" and "torch-lit grids", setting
 * the target to a given location, and extracting the optimal direction
 * for "movement" from place to place.
 *
 * Note that the dungeon is assumed to be smaller than 256 by 256.
 */



/*
 * Make a note for later
 */
bool borg_make_note(cptr what)
{
	cptr s;

	/* Hack -- self note */
	borg_keypress(':');
	for (s = what; *s; s++) borg_keypress(*s);
	borg_keypress('\n');

	/* Success */
	return (TRUE);
}



/*
 * Attempt to change the borg's name
 */
bool borg_change_name(cptr str)
{
	cptr s;

	/* Cancel everything */
	borg_keypress(ESCAPE);
	borg_keypress(ESCAPE);

	/* Character description */
	borg_keypress('C');

	/* Change the name */
	borg_keypress('c');

	/* Enter the new name */
	for (s = str; *s; s++) borg_keypress(*s);

	/* End the name */
	borg_keypress('\r');

	/* Cancel everything */
	borg_keypress(ESCAPE);
	borg_keypress(ESCAPE);

	/* Success */
	return (TRUE);
}


/*
 * Attempt to dump a character description file
 */
bool borg_dump_character(cptr str)
{
	cptr s;

	/* Cancel everything */
	borg_keypress(ESCAPE);
	borg_keypress(ESCAPE);

	/* Character description */
	borg_keypress('C');

	/* Dump character file */
	borg_keypress('f');

	/* Enter the new name */
	for (s = str; *s; s++) borg_keypress(*s);

	/* End the file name */
	borg_keypress('\r');

	/* Cancel everything */
	borg_keypress(ESCAPE);
	borg_keypress(ESCAPE);

	/* Success */
	return (TRUE);
}




/*
 * Attempt to save the game
 */
bool borg_save_game(void)
{
	/* Cancel everything */
	borg_keypress(ESCAPE);
	borg_keypress(ESCAPE);

	/* Save the game */
	borg_keypress('^');
	borg_keypress('S');

	/* Cancel everything */
	borg_keypress(ESCAPE);
	borg_keypress(ESCAPE);

	/* Success */
	return (TRUE);
}




/*
 * Update the Borg based on the current "frame"
 *
 * Assumes the Borg is actually in the dungeon.
 */
void borg_update_frame(void)
{
	int i;

	byte t_a;

	char buf[160];


	/* Check for "   Town" or "  Lev 8" or " Lev 13" */
	if (0 == borg_what_text(COL_DEPTH, ROW_DEPTH, -7, &t_a, buf))
	{
		cptr s;

		/* Skip the non-digits */
		for (s = buf; *s && !isdigit(*s); s++) /* loop */;

		/* Extract the current level */
		b_ptr->depth = borg_base_depth = atoi(s);
	}


	/* Title (ignore) XXX XXX XXX */


	/* Info (monster health) XXX XXX XXX */


	/* Assume level is fine */
	borg_base_fix_lev = FALSE;

	/* Check for drained level */
	if (0 == borg_what_text(COL_LEVEL, ROW_LEVEL, -3, &t_a, buf))
	{
		/* Note "Lev" vs "LEV" */
		if (islower(buf[2])) borg_base_fix_lev = TRUE;
	}

	/* Extract current level */
	if (0 == borg_what_text(COL_LEVEL + 6, ROW_LEVEL, -6, &t_a, buf))
	{
		/* Extract "LEVEL xxxxxx" */
		b_ptr->lev = borg_base_level = atoi(buf);
	}


	/* Assume experience is fine */
	borg_base_fix_exp = FALSE;

	/* Check for drained experience */
	if (0 == borg_what_text(COL_EXP, ROW_EXP, -3, &t_a, buf))
	{
		/* Note "Exp" vs "EXP" */
		if (islower(buf[2])) borg_base_fix_exp = TRUE;
	}

	/* Extract current experience */
	if (0 == borg_what_text(COL_EXP + 4, ROW_EXP, -8, &t_a, buf))
	{
		/* Extract "EXP xxxxxxxx" */
		b_ptr->exp = borg_base_exp = atol(buf);
	}


	/* Extract current gold */
	if (0 == borg_what_text(COL_GOLD + 3, ROW_GOLD, -9, &t_a, buf))
	{
		/* Extract "AU xxxxxxxxx" */
		b_ptr->au = borg_base_au = atol(buf);
	}


	/* Extract speed */
	if (0 == borg_what_text(COL_SPEED, ROW_SPEED, -14, &t_a, buf))
	{
		/* Extract "Fast (+x)" or "Slow (-x)" */
		b_ptr->pspeed = borg_base_pspeed = 110 + atoi(buf + 6);
	}

	/* Extract armor class */
	if (0 == borg_what_text(COL_AC + 7, ROW_AC, -5, &t_a, buf))
	{
		/* Extract "Cur AC xxxxx" */
		b_ptr->ac = borg_base_ac = atoi(buf);
	}


	/* Extract maximum hitpoints */
	if (0 == borg_what_text(COL_MAXHP + 7, ROW_MAXHP, -5, &t_a, buf))
	{
		/* Extract "Max HP xxxxx" */
		b_ptr->mhp = borg_base_mhp = atoi(buf);
	}

	/* Extract current hitpoints */
	if (0 == borg_what_text(COL_CURHP + 7, ROW_CURHP, -5, &t_a, buf))
	{
		/* Extract "Cur HP xxxxx" */
		b_ptr->chp = borg_base_chp = atoi(buf);
	}


	/* Extract maximum spell points */
	if (0 == borg_what_text(COL_MAXSP + 7, ROW_MAXSP, -5, &t_a, buf))
	{
		/* Extract "Max SP xxxxx" (or zero) */
		b_ptr->msp = borg_base_msp = atoi(buf);
	}

	/* Extract current spell points */
	if (0 == borg_what_text(COL_CURSP + 7, ROW_CURSP, -5, &t_a, buf))
	{
		/* Extract "Cur SP xxxxx" (or zero) */
		b_ptr->csp = borg_base_csp = atoi(buf);
	}



	/* Clear all the "state flags" */
	borg_base_is_weak = borg_base_is_hungry = borg_base_is_full = borg_base_is_gorged = FALSE;
	borg_base_is_blind = borg_base_is_confused = borg_base_is_afraid = borg_base_is_poisoned = FALSE;
	borg_base_is_cut = borg_base_is_stun = borg_base_is_image = borg_base_is_study = FALSE;

	/* Check for hunger */
	if (0 == borg_what_text(COL_HUNGRY, ROW_HUNGRY, -1, &t_a, buf))
	{
		/* Check for "Hungry" */
		if (buf[0] == 'H') borg_base_is_hungry = TRUE;

		/* Check for "Weak" */
		if (buf[0] == 'W') borg_base_is_weak = borg_base_is_hungry = TRUE;

		/* Check for "Full" */
		if (buf[0] == 'F') borg_base_is_full = TRUE;

		/* Check for "Gorged" */
		if (buf[0] == 'G') borg_base_is_gorged = borg_base_is_full = TRUE;
	}

	/* Check for blind */
	if (0 == borg_what_text(COL_BLIND, ROW_BLIND, -1, &t_a, buf))
	{
		/* Check for "Blind" */
		if (buf[0] == 'B') borg_base_is_blind = TRUE;
	}

	/* Check for confused */
	if (0 == borg_what_text(COL_CONFUSED, ROW_CONFUSED, -1, &t_a, buf))
	{
		/* Check for "Confused" */
		if (buf[0] == 'C') borg_base_is_confused = TRUE;
	}

	/* Check for afraid */
	if (0 == borg_what_text(COL_AFRAID, ROW_AFRAID, -1, &t_a, buf))
	{
		/* Check for "Afraid" */
		if (buf[0] == 'A') borg_base_is_afraid = TRUE;
	}

	/* Check for poisoned */
	if (0 == borg_what_text(COL_POISONED, ROW_POISONED, -1, &t_a, buf))
	{
		/* Check for "Poisoned" */
		if (buf[0] == 'P') borg_base_is_poisoned = TRUE;
	}


	/* Check for cut XXX XXX */
	if (0 == borg_what_text(COL_CUT, ROW_CUT, -1, &t_a, buf))
	{
		/* Check for any text */
		if (isalpha(buf[0])) borg_base_is_cut = TRUE;
	}

	/* Check for stun XXX XXX */
	if (0 == borg_what_text(COL_STUN, ROW_STUN, -1, &t_a, buf))
	{
		/* Check for any text */
		if (isalpha(buf[0])) borg_base_is_stun = TRUE;
	}


	/* Parse "State" XXX XXX XXX */


	/* Check for study */
	if (0 == borg_what_text(COL_STUDY, ROW_STUDY, -1, &t_a, buf))
	{
		/* Check for "Study" */
		if (buf[0] == 'S') borg_base_is_study = TRUE;
	}


	/* Parse stats */
	for (i = 0; i < 6; i++)
	{
		/* Check "NNN   xxxxxx" */
		if (0 == borg_what_text(COL_STAT, ROW_STAT+i, -3, &t_a, buf))
		{
			/* Note "Nnn" vs "NNN" */
			borg_base_fix_stat[i] = (islower(buf[2]));
		}

		/* Check "NNN   xxxxxx" */
		if (0 == borg_what_text(COL_STAT+6, ROW_STAT+i, -6, &t_a, buf))
		{
			/* Parse "18/NNN" */
			if (buf[2] == '/') borg_base_stat[i] = 18 + atoi(buf+3);

			/* Parse " 18/NN" */
			else if (buf[3] == '/') borg_base_stat[i] = 18 + atoi(buf+4);

			/* Parse "    NN" */
			else borg_base_stat[i] = atoi(buf+4);
		}
	}
}



/*
 * A simple, fast, integer-based line-of-sight algorithm.
 *
 * See "los()" in "cave.c" for complete documentation
 */
bool borg_los(int y1, int x1, int y2, int x2)
{
	/* Delta */
	int dx, dy;

	/* Absolute */
	int ax, ay;

	/* Signs */
	int sx, sy;

	/* Fractions */
	int qx, qy;

	/* Scanners */
	int tx, ty;

	/* Scale factors */
	int f1, f2;

	/* Slope, or 1/Slope, of LOS */
	int m;


	/* Extract the offset */
	dy = y2 - y1;
	dx = x2 - x1;

	/* Extract the absolute offset */
	ay = ABS(dy);
	ax = ABS(dx);


	/* Handle adjacent (or identical) grids */
	if ((ax < 2) && (ay < 2)) return (TRUE);


	/* Paranoia -- require "safe" origin */
	/* if (!in_bounds(y1, x1)) return (FALSE); */


	/* Directly South/North */
	if (!dx)
	{
		/* South -- check for walls */
		if (dy > 0)
		{
			for (ty = y1 + 1; ty < y2; ty++)
			{
				if (!borg_cave_floor_bold(ty, x1)) return (FALSE);
			}
		}

		/* North -- check for walls */
		else
		{
			for (ty = y1 - 1; ty > y2; ty--)
			{
				if (!borg_cave_floor_bold(ty, x1)) return (FALSE);
			}
		}

		/* Assume los */
		return (TRUE);
	}

	/* Directly East/West */
	if (!dy)
	{
		/* East -- check for walls */
		if (dx > 0)
		{
			for (tx = x1 + 1; tx < x2; tx++)
			{
				if (!borg_cave_floor_bold(y1, tx)) return (FALSE);
			}
		}

		/* West -- check for walls */
		else
		{
			for (tx = x1 - 1; tx > x2; tx--)
			{
				if (!borg_cave_floor_bold(y1, tx)) return (FALSE);
			}
		}

		/* Assume los */
		return (TRUE);
	}


	/* Extract some signs */
	sx = (dx < 0) ? -1 : 1;
	sy = (dy < 0) ? -1 : 1;


	/* Vertical "knights" */
	if (ax == 1)
	{
		if (ay == 2)
		{
			if (borg_cave_floor_bold(y1 + sy, x1)) return (TRUE);
		}
	}

	/* Horizontal "knights" */
	else if (ay == 1)
	{
		if (ax == 2)
		{
			if (borg_cave_floor_bold(y1, x1 + sx)) return (TRUE);
		}
	}


	/* Calculate scale factor div 2 */
	f2 = (ax * ay);

	/* Calculate scale factor */
	f1 = f2 << 1;


	/* Travel horizontally */
	if (ax >= ay)
	{
		/* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */
		qy = ay * ay;
		m = qy << 1;

		tx = x1 + sx;

		/* Consider the special case where slope == 1. */
		if (qy == f2)
		{
			ty = y1 + sy;
			qy -= f1;
		}
		else
		{
			ty = y1;
		}

		/* Note (below) the case (qy == f2), where */
		/* the LOS exactly meets the corner of a tile. */
		while (x2 - tx)
		{
			if (!borg_cave_floor_bold(ty, tx)) return (FALSE);

			qy += m;

			if (qy < f2)
			{
				tx += sx;
			}
			else if (qy > f2)
			{
				ty += sy;
				if (!borg_cave_floor_bold(ty, tx)) return (FALSE);
				qy -= f1;
				tx += sx;
			}
			else
			{
				ty += sy;
				qy -= f1;
				tx += sx;
			}
		}
	}

	/* Travel vertically */
	else
	{
		/* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */
		qx = ax * ax;
		m = qx << 1;

		ty = y1 + sy;

		if (qx == f2)
		{
			tx = x1 + sx;
			qx -= f1;
		}
		else
		{
			tx = x1;
		}

		/* Note (below) the case (qx == f2), where */
		/* the LOS exactly meets the corner of a tile. */
		while (y2 - ty)
		{
			if (!borg_cave_floor_bold(ty, tx)) return (FALSE);

			qx += m;

			if (qx < f2)
			{
				ty += sy;
			}
			else if (qx > f2)
			{
				tx += sx;
				if (!borg_cave_floor_bold(ty, tx)) return (FALSE);
				qx -= f1;
				ty += sy;
			}
			else
			{
				tx += sx;
				qx -= f1;
				ty += sy;
			}
		}
	}

	/* Assume los */
	return (TRUE);
}




/*
 * Check the projection from (x1,y1) to (x2,y2).
 *
 * This function is used to help determine if a ranged attack
 * by a monster might reach us, if all unknown grids are floors
 * and no monsters are blocking the projection.
 *
 * Adapted from "projectable()" in "spells1.c".
 */
bool borg_projectable(int y1, int x1, int y2, int x2)
{
	int dist, y, x;

	/* Start at the initial location */
	y = y1; x = x1;

	/* Simulate the spell/missile path */
	for (dist = 0; dist <= MAX_RANGE; dist++)
	{
		/* Hack -- assume unknown grids are walls */
		/* if (dist && (db_ptr->cave_feat[y][x] == FEAT_NONE)) break; */

		/* Never pass through walls/doors */
		if (dist && (!borg_cave_floor_bold(y, x))) break;

		/* Check for arrival at "final target" */
		if ((x == x2) && (y == y2)) return (TRUE);

		/* Calculate the new location */
		mmove2(&y, &x, y1, x1, y2, x2);
	}

	/* Assume obstruction */
	return (FALSE);
}



/*
 * The following functions are taken from "cave.c", and then modified for
 * the use of the Borg.  See "cave.c" for more complete documentation.
 *
 * First, some of the code is not needed by the Borg and must be removed.
 * This includes and code dealing with the variables "temp_n", "temp_y",
 * or "temp_x", the constants "CAVE_TEMP" or "CAVE_GLOW", or the functions
 * "lite_spot()" or "note_spot()".  Note that almost all of the "complete
 * the algorithm" code is thus removed (except for the code to clear the
 * "CAVE_XTRA" flags).
 *
 * Then, make the following substitutions (in order).  XXX XXX XXX
 *
 *   CAVE_ -> BORG_
 *
 *   p_ptr -> b_ptr
 *
 *   cave_ -> db_ptr->cave_
 *
 *   lite_ -> borg_lite_
 *   view_ -> borg_view_
 *
 *   forget_ -> borg_forget_
 *   update_ -> borg_update_
 *
 *   update_borg_aux -> update_aux
 *
 *   borg_view_reduce_view -> view_reduce_view
 *
 *   db_ptr->cave_lite_hack -> borg_cave_lite_hack
 *   db_ptr->cave_view_hack -> borg_cave_view_hack
 *
 *   db_ptr->cave_floor_bold -> borg_cave_floor_bold
 *
 *   los -> borg_los
 *
 *
 * Last adaptation: 1997-05-04
 */



/*
 * Forget the "BORG_LITE" grids, redrawing as needed.
 */
void borg_forget_lite(void)
{
	int i, x, y;

	/* None to forget */
	if (!borg_lite_n) return;

	/* Clear them all */
	for (i = 0; i < borg_lite_n; i++)
	{
		y = borg_lite_y[i];
		x = borg_lite_x[i];

		/* Forget "LITE" flag */
		db_ptr->cave_info[y][x] &= ~(BORG_LITE);
	}

	/* None left */
	borg_lite_n = 0;
}


/*
 * Simplify the "borg_update_lite()" function XXX XXX XXX
 *
 * This macro allows us to efficiently add a grid to the "lite" array,
 * note that we are never called for illegal grids, or for grids which
 * have already been placed into the "lite" array, and we are never
 * called when the "lite" array is full.
 */
#define borg_cave_lite_hack(Y,X) \
	do { \
		db_ptr->cave_info[Y][X] |= (BORG_LITE); \
		borg_lite_y[borg_lite_n] = (Y); \
		borg_lite_x[borg_lite_n] = (X); \
		borg_lite_n++; \
	} while (0)


/*
 * Update the "BORG_LITE" grids, redrawing as needed.
 */
void borg_update_lite(void)
{
	int py = b_ptr->py;
	int px = b_ptr->px;

	int r = b_ptr->cur_lite;

	int i, y, x;


	/*** Special case ***/

	/* Hack -- Player has no lite */
	if (r <= 0)
	{
		/* Forget the old lite */
		borg_forget_lite();

		/* All done */
		return;
	}


	/*** Save the old "lite" grids for later ***/

	/* Clear them all */
	for (i = 0; i < borg_lite_n; i++)
	{
		y = borg_lite_y[i];
		x = borg_lite_x[i];

		/* Mark the grid as not "lite" */
		db_ptr->cave_info[y][x] &= ~(BORG_LITE);
	}

	/* None left */
	borg_lite_n = 0;


	/*** Collect the new "lite" grids ***/

	/* Player grid */
	borg_cave_lite_hack(py, px);

	/* Radius 1 -- torch radius */
	if (r >= 1)
	{
		/* Adjacent grid */
		borg_cave_lite_hack(py+1, px);
		borg_cave_lite_hack(py-1, px);
		borg_cave_lite_hack(py, px+1);
		borg_cave_lite_hack(py, px-1);

		/* Diagonal grids */
		borg_cave_lite_hack(py+1, px+1);
		borg_cave_lite_hack(py+1, px-1);
		borg_cave_lite_hack(py-1, px+1);
		borg_cave_lite_hack(py-1, px-1);
	}

	/* Radius 2 -- lantern radius */
	if (r >= 2)
	{
		/* South of the player */
		if (borg_cave_floor_bold(py+1, px))
		{
			borg_cave_lite_hack(py+2, px);
			borg_cave_lite_hack(py+2, px+1);
			borg_cave_lite_hack(py+2, px-1);
		}

		/* North of the player */
		if (borg_cave_floor_bold(py-1, px))
		{
			borg_cave_lite_hack(py-2, px);
			borg_cave_lite_hack(py-2, px+1);
			borg_cave_lite_hack(py-2, px-1);
		}

		/* East of the player */
		if (borg_cave_floor_bold(py, px+1))
		{
			borg_cave_lite_hack(py, px+2);
			borg_cave_lite_hack(py+1, px+2);
			borg_cave_lite_hack(py-1, px+2);
		}

		/* West of the player */
		if (borg_cave_floor_bold(py, px-1))
		{
			borg_cave_lite_hack(py, px-2);
			borg_cave_lite_hack(py+1, px-2);
			borg_cave_lite_hack(py-1, px-2);
		}
	}

	/* Radius 3+ -- artifact radius */
	if (r >= 3)
	{
		int y1, y2, x1, x2;

		/* Paranoia */
		if (r > 5) r = 5;

		/* South-East of the player */
		if (borg_cave_floor_bold(py+1, px+1))
		{
			borg_cave_lite_hack(py+2, px+2);
		}

		/* South-West of the player */
		if (borg_cave_floor_bold(py+1, px-1))
		{
			borg_cave_lite_hack(py+2, px-2);
		}

		/* North-East of the player */
		if (borg_cave_floor_bold(py-1, px+1))
		{
			borg_cave_lite_hack(py-2, px+2);
		}

		/* North-West of the player */
		if (borg_cave_floor_bold(py-1, px-1))
		{
			borg_cave_lite_hack(py-2, px-2);
		}

		/* Maximal north */
		y1 = py - r;
		if (y1 < 0) y1 = 0;

		/* Maximal south */
		y2 = py + r;
		if (y2 > DUNGEON_HGT-1) y2 = DUNGEON_HGT-1;

		/* Maximal west */
		x1 = px - r;
		if (x1 < 0) x1 = 0;

		/* Maximal east */
		x2 = px + r;
		if (x2 > DUNGEON_WID-1) x2 = DUNGEON_WID-1;

		/* Scan the maximal box */
		for (y = y1; y <= y2; y++)
		{
			for (x = x1; x <= x2; x++)
			{
				int d;

				int dy = (py > y) ? (py - y) : (y - py);
				int dx = (px > x) ? (px - x) : (x - px);

				/* Skip the "central" grids (above) */
				if ((dy <= 2) && (dx <= 2)) continue;

				/* Hack -- approximate the distance */
				d = (dy > dx) ? (dy + (dx>>1)) : (dx + (dy>>1));

				/* Skip distant grids */
				if (d > r) continue;

				/* Viewable grids get "torch lit" */
				if (db_ptr->cave_info[y][x] & (BORG_VIEW))
				{
					/* This grid is "torch lit" */
					borg_cave_lite_hack(y, x);
				}
			}
		}
	}
}




/*
 * Forget the "BORG_VIEW" grids, redrawing as needed
 */
void borg_forget_view(void)
{
	int i;

	/* None to forget */
	if (!borg_view_n) return;

	/* Clear them all */
	for (i = 0; i < borg_view_n; i++)
	{
		int y = borg_view_y[i];
		int x = borg_view_x[i];

		/* Forget that the grid is viewable */
		db_ptr->cave_info[y][x] &= ~(BORG_VIEW);
	}

	/* None left */
	borg_view_n = 0;
}


/*
 * Simplify the "borg_update_view()" function XXX XXX XXX
 *
 * This macro allows us to efficiently add a grid to the "view" array,
 * note that we are never called for illegal grids, or for grids which
 * have already been placed into the "view" array, and we are never
 * called when the "view" array is full.
 */
#define borg_cave_view_hack(Y,X) \
	do { \
		db_ptr->cave_info[Y][X] |= (BORG_VIEW); \
		borg_view_y[borg_view_n] = (Y); \
		borg_view_x[borg_view_n] = (X); \
		borg_view_n++; \
	} while (0)


/*
 * Helper function for "borg_update_view()" below
 *
 * This function processes the "viewability" of the grid (y,x).
 *
 * Grid (y1,x1) is on the "diagonal" between (py,px) and (y,x)
 * Grid (y2,x2) is "adjacent", also between (py,px) and (y,x).
 *
 * This function returns "TRUE" if vision is "blocked" by grid (y,x).
 */
static bool borg_update_view_aux(int y, int x, int y1, int x1, int y2, int x2)
{
	bool f1, f2, v1, v2, z1, z2, wall;


	/* Check for walls */
	f1 = (borg_cave_floor_bold(y1, x1));
	f2 = (borg_cave_floor_bold(y2, x2));

	/* Totally blocked by physical walls */
	if (!f1 && !f2) return (TRUE);


	/* Check for visibility */
	v1 = (f1 && (db_ptr->cave_info[y1][x1] & (BORG_VIEW)));
	v2 = (f2 && (db_ptr->cave_info[y2][x2] & (BORG_VIEW)));

	/* Totally blocked by "unviewable neighbors" */
	if (!v1 && !v2) return (TRUE);


	/* Check for walls */
	wall = (!borg_cave_floor_bold(y, x));


	/* Check the "ease" of visibility */
	z1 = (v1 && (db_ptr->cave_info[y1][x1] & (BORG_XTRA)));
	z2 = (v2 && (db_ptr->cave_info[y2][x2] & (BORG_XTRA)));

	/* Hack -- "easy" plus "easy" yields "easy" */
	if (z1 && z2)
	{
		db_ptr->cave_info[y][x] |= (BORG_XTRA);

		borg_cave_view_hack(y, x);

		return (wall);
	}

	/* Hack -- primary "easy" yields "viewed" */
	if (z1)
	{
		borg_cave_view_hack(y, x);

		return (wall);
	}


	/* Hack -- "view" plus "view" yields "view" */
	if (v1 && v2)
	{
		/* db_ptr->cave_info[y][x] |= (BORG_XTRA); */

		borg_cave_view_hack(y, x);

		return (wall);
	}


	/* Mega-Hack -- the "borg_los()" function works poorly on walls */
	if (wall)
	{
		borg_cave_view_hack(y, x);

		return (wall);
	}


	/* Actual line of sight test */
	if (TRUE)
	{
		int py = b_ptr->py;
		int px = b_ptr->px;

		/* Hack -- check line of sight */
		if (borg_los(py, px, y, x))
		{
			borg_cave_view_hack(y, x);

			return (wall);
		}
	}


	/* Assume no line of sight. */
	return (TRUE);
}


/*
 * Hack -- keep the code below simple
 */
#define DY1 0
#define DY2 (DUNGEON_HGT-1)
#define DX1 0
#define DX2 (DUNGEON_WID-1)


/*
 * Update the "BORG_VIEW" grids, redrawing as needed
 */
void borg_update_view(void)
{
	int py = b_ptr->py;
	int px = b_ptr->px;

	int n, m, d, k, y, x, z;

	int se, sw, ne, nw, es, en, ws, wn;

	int full, over;


	/*** Initialize ***/

	/* Optimize */
	if (view_reduce_view && !b_ptr->depth)
	{
		/* Full radius (10) */
		full = MAX_SIGHT / 2;

		/* Octagon factor (15) */
		over = MAX_SIGHT * 3 / 4;
	}

	/* Normal */
	else
	{
		/* Full radius (20) */
		full = MAX_SIGHT;

		/* Octagon factor (30) */
		over = MAX_SIGHT * 3 / 2;
	}


	/*** Step 0 -- Begin ***/

	/* Save the old "view" grids for later */
	for (n = 0; n < borg_view_n; n++)
	{
		y = borg_view_y[n];
		x = borg_view_x[n];

		/* Mark the grid as not in "view" */
		db_ptr->cave_info[y][x] &= ~(BORG_VIEW);
	}

	/* Start over with the "view" array */
	borg_view_n = 0;


	/*** Step 1 -- adjacent grids ***/

	/* Now start on the player */
	y = py;
	x = px;

	/* Assume the player grid is easily viewable */
	db_ptr->cave_info[y][x] |= (BORG_XTRA);

	/* Assume the player grid is viewable */
	borg_cave_view_hack(y, x);


	/*** Step 2 -- Major Diagonals ***/

	/* Hack -- Limit */
	z = full * 2 / 3;

	/* Scan south-east */
	for (d = 1; d <= z; d++)
	{
		db_ptr->cave_info[y+d][x+d] |= (BORG_XTRA);
		borg_cave_view_hack(y+d, x+d);
		if (!borg_cave_floor_bold(y+d, x+d)) break;
	}

	/* Scan south-west */
	for (d = 1; d <= z; d++)
	{
		db_ptr->cave_info[y+d][x-d] |= (BORG_XTRA);
		borg_cave_view_hack(y+d, x-d);
		if (!borg_cave_floor_bold(y+d, x-d)) break;
	}

	/* Scan north-east */
	for (d = 1; d <= z; d++)
	{
		db_ptr->cave_info[y-d][x+d] |= (BORG_XTRA);
		borg_cave_view_hack(y-d, x+d);
		if (!borg_cave_floor_bold(y-d, x+d)) break;
	}

	/* Scan north-west */
	for (d = 1; d <= z; d++)
	{
		db_ptr->cave_info[y-d][x-d] |= (BORG_XTRA);
		borg_cave_view_hack(y-d, x-d);
		if (!borg_cave_floor_bold(y-d, x-d)) break;
	}


	/*** Step 3 -- major axes ***/

	/* Scan south */
	for (d = 1; d <= full; d++)
	{
		db_ptr->cave_info[y+d][x] |= (BORG_XTRA);
		borg_cave_view_hack(y+d, x);
		if (!borg_cave_floor_bold(y+d, x)) break;
	}

	/* Initialize the "south strips" */
	se = sw = d;

	/* Scan north */
	for (d = 1; d <= full; d++)
	{
		db_ptr->cave_info[y-d][x] |= (BORG_XTRA);
		borg_cave_view_hack(y-d, x);
		if (!borg_cave_floor_bold(y-d, x)) break;
	}

	/* Initialize the "north strips" */
	ne = nw = d;

	/* Scan east */
	for (d = 1; d <= full; d++)
	{
		db_ptr->cave_info[y][x+d] |= (BORG_XTRA);
		borg_cave_view_hack(y, x+d);
		if (!borg_cave_floor_bold(y, x+d)) break;
	}

	/* Initialize the "east strips" */
	es = en = d;

	/* Scan west */
	for (d = 1; d <= full; d++)
	{
		db_ptr->cave_info[y][x-d] |= (BORG_XTRA);
		borg_cave_view_hack(y, x-d);
		if (!borg_cave_floor_bold(y, x-d)) break;
	}

	/* Initialize the "west strips" */
	ws = wn = d;


	/*** Step 4 -- Divide each "octant" into "strips" ***/

	/* Now check each "strip" */
	for (n = 1; n <= over / 2; n++)
	{
		int ypn, ymn, ypnpd, ymnmd;
		int xpn, xmn, xpnpd, xmnmd;


		/* Acquire the "bounds" of the maximal circle */
		z = over - n - n;
		if (z > full - n) z = full - n;
		while ((z + n + (n>>1)) > full) z--;


		/* Access the four diagonal grids */
		ypn = y + n;
		ymn = y - n;
		xpn = x + n;
		xmn = x - n;


		/* South strip */
		if (ypn < DY2)
		{
			/* Maximum distance */
			m = MIN(z, DY2 - ypn);

			/* East side */
			if (n < se)
			{
				/* Scan */
				for (k = n, ypnpd = ypn+1, d = 1; d <= m; d++, ypnpd++)
				{
					/* Check grid "d" in strip "n", notice "blockage" */
					if (borg_update_view_aux(ypnpd, xpn, ypnpd-1, xpn-1, ypnpd-1, xpn))
					{
						if (n + d >= se) break;
					}

					/* Track most distant "non-blockage" */
					else
					{
						k = n + d;
					}
				}

				/* Limit the next strip */
				se = k + 1;
			}

			/* West side */
			if (n < sw)
			{
				/* Scan */
				for (k = n, ypnpd = ypn+1, d = 1; d <= m; d++, ypnpd++)
				{
					/* Check grid "d" in strip "n", notice "blockage" */
					if (borg_update_view_aux(ypnpd, xmn, ypnpd-1, xmn+1, ypnpd-1, xmn))
					{
						if (n + d >= sw) break;
					}

					/* Track most distant "non-blockage" */
					else
					{
						k = n + d;
					}
				}

				/* Limit the next strip */
				sw = k + 1;
			}
		}


		/* North strip */
		if (ymn > DY1)
		{
			/* Maximum distance */
			m = MIN(z, ymn - DY1);

			/* East side */
			if (n < ne)
			{
				/* Scan */
				for (k = n, ymnmd = ymn-1, d = 1; d <= m; d++, ymnmd--)
				{
					/* Check grid "d" in strip "n", notice "blockage" */
					if (borg_update_view_aux(ymnmd, xpn, ymnmd+1, xpn-1, ymnmd+1, xpn))
					{
						if (n + d >= ne) break;
					}

					/* Track most distant "non-blockage" */
					else
					{
						k = n + d;
					}
				}

				/* Limit the next strip */
				ne = k + 1;
			}

			/* West side */
			if (n < nw)
			{
				/* Scan */
				for (k = n, ymnmd = ymn-1, d = 1; d <= m; d++, ymnmd--)
				{
					/* Check grid "d" in strip "n", notice "blockage" */
					if (borg_update_view_aux(ymnmd, xmn, ymnmd+1, xmn+1, ymnmd+1, xmn))
					{
						if (n + d >= nw) break;
					}

					/* Track most distant "non-blockage" */
					else
					{
						k = n + d;
					}
				}

				/* Limit the next strip */
				nw = k + 1;
			}
		}


		/* East strip */
		if (xpn < DX2)
		{
			/* Maximum distance */
			m = MIN(z, DX2 - xpn);

			/* South side */
			if (n < es)
			{
				/* Scan */
				for (k = n, xpnpd = xpn+1, d = 1; d <= m; d++, xpnpd++)
				{
					/* Check grid "d" in strip "n", notice "blockage" */
					if (borg_update_view_aux(ypn, xpnpd, ypn-1, xpnpd-1, ypn, xpnpd-1))
					{
						if (n + d >= es) break;
					}

					/* Track most distant "non-blockage" */
					else
					{
						k = n + d;
					}
				}

				/* Limit the next strip */
				es = k + 1;
			}

			/* North side */
			if (n < en)
			{
				/* Scan */
				for (k = n, xpnpd = xpn+1, d = 1; d <= m; d++, xpnpd++)
				{
					/* Check grid "d" in strip "n", notice "blockage" */
					if (borg_update_view_aux(ymn, xpnpd, ymn+1, xpnpd-1, ymn, xpnpd-1))
					{
						if (n + d >= en) break;
					}

					/* Track most distant "non-blockage" */
					else
					{
						k = n + d;
					}
				}

				/* Limit the next strip */
				en = k + 1;
			}
		}


		/* West strip */
		if (xmn > DX1)
		{
			/* Maximum distance */
			m = MIN(z, xmn - DX1);

			/* South side */
			if (n < ws)
			{
				/* Scan */
				for (k = n, xmnmd = xmn-1, d = 1; d <= m; d++, xmnmd--)
				{
					/* Check grid "d" in strip "n", notice "blockage" */
					if (borg_update_view_aux(ypn, xmnmd, ypn-1, xmnmd+1, ypn, xmnmd+1))
					{
						if (n + d >= ws) break;
					}

					/* Track most distant "non-blockage" */
					else
					{
						k = n + d;
					}
				}

				/* Limit the next strip */
				ws = k + 1;
			}

			/* North side */
			if (n < wn)
			{
				/* Scan */
				for (k = n, xmnmd = xmn-1, d = 1; d <= m; d++, xmnmd--)
				{
					/* Check grid "d" in strip "n", notice "blockage" */
					if (borg_update_view_aux(ymn, xmnmd, ymn+1, xmnmd+1, ymn, xmnmd+1))
					{
						if (n + d >= wn) break;
					}

					/* Track most distant "non-blockage" */
					else
					{
						k = n + d;
					}
				}

				/* Limit the next strip */
				wn = k + 1;
			}
		}
	}


	/*** Step 5 -- Complete the algorithm ***/

	/* Process "new" grids */
	for (n = 0; n < borg_view_n; n++)
	{
		y = borg_view_y[n];
		x = borg_view_x[n];

		/* Clear the "BORG_XTRA" flag */
		db_ptr->cave_info[y][x] &= ~(BORG_XTRA);
	}
}



/*
 * Hack -- keep the code above simple
 */
#undef DY1
#undef DY2
#undef DX1
#undef DX2




#else

#ifdef MACINTOSH
static int HACK = 0;
#endif /* MACINTOSH */

#endif /* ALLOW_BORG */
