/* source/misc1.c: misc utility and initialization code, magic objects code

Copyright (c) 1989-91 James E. Wilson, Robert A. Koeneke

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 "config.h"
#include "constant.h"
#include "types.h"
#include "externs.h"

#ifdef __TURBOC__
#include	<stdlib.h>
#endif

#ifdef Pyramid
#include <sys/time.h>
#else
#include <time.h>
#endif
#if !defined(GEMDOS) && !defined(MAC) && !defined(AMIGA)
#ifndef VMS
#include <sys/types.h>
#else
#include <types.h>
#endif
#endif

#if !defined(ATARIST_MWC) && !defined(MAC) && !defined(VMS) && !defined(AMIGA)
long time();

#endif
struct tm *localtime();

#if defined(LINT_ARGS)
static void compact_objects(void);

#endif


/* gets a new random seed for the random number generator */
void 
init_seeds(seed)
	int32u seed;
{
	register int32u clock_var;

	if (seed == 0)
#ifdef MAC
		clock_var = time((time_t *) 0);
#else
		clock_var = time((long *) 0);
#endif
	else
		clock_var = seed;
	randes_seed = (int32) clock_var;

	clock_var += 8762;
	town_seed = (int32) clock_var;

	clock_var += 113452L;
	set_rnd_seed(clock_var);
	/* make it a little more random */
	for (clock_var = randint(100); clock_var != 0; clock_var--)
		(void) rnd();
}

/* holds the previous rnd state */
static int32u old_seed;

/* change to different random number generator state */
void 
set_seed(seed)
	int32u seed;
{
	old_seed = get_rnd_seed();

	/* want reproducible state here */
	set_rnd_seed(seed);
}


/* restore the normal random generator state */
void 
reset_seed()
{
	set_rnd_seed(old_seed);
}


/* Check the day-time strings to see if open		-RAK-	 */
int 
check_time()
{
#ifdef MORIA_HOU
	long clock_var;
	register struct tm *tp;

#ifdef MAC
	clock_var = time((time_t *) 0);
#else
	clock_var = time((long *) 0);
#endif
	tp = localtime(&clock_var);
	if (days[tp->tm_wday][tp->tm_hour + 4] == 'X')
		return TRUE;
	else
		return FALSE;
#else
	  return TRUE;
#endif
}


/* Generates a random integer x where 1<=X<=MAXVAL	-RAK-	 */
int 
randint(maxval)
	int maxval;
{
	register long randval;

	randval = rnd();
	return ((int) (randval % maxval) + 1);
}

/* Generates a random integer number of NORMAL distribution -RAK- */
int 
randnor(mean, stand)
	int mean, stand;
{
	register int tmp, offset, low, iindex, high;

#if 0
	/* alternate randnor code, slower but much smaller since no table */
	/* 2 per 1,000,000 will be > 4*SD, max is 5*SD */
	tmp = damroll(8, 99);		/* mean 400, SD 81 */
	tmp = (tmp - 400) * stand / 81;
	return tmp + mean;
#endif

	tmp = randint(MAX_SHORT);

	/* off scale, assign random value between 4 and 5 times SD */
	if (tmp == MAX_SHORT) {
		offset = 4 * stand + randint(stand);

		/* one half are negative */
		if (randint(2) == 1)
			offset = -offset;

		return mean + offset;
	}
	/* binary search normal normal_table to get index that matches tmp */
	/* this takes up to 8 iterations */
	low = 0;
	iindex = NORMAL_TABLE_SIZE >> 1;
	high = NORMAL_TABLE_SIZE;
	while (TRUE) {
		if ((normal_table[iindex] == tmp) || (high == (low + 1)))
			break;
		if (normal_table[iindex] > tmp) {
			high = iindex;
			iindex = low + ((iindex - low) >> 1);
		} else {
			low = iindex;
			iindex = iindex + ((high - iindex) >> 1);
		}
	}

	/* might end up one below target, check that here */
	if (normal_table[iindex] < tmp)
		iindex = iindex + 1;

	/* normal_table is based on SD of 64, so adjust the index value here, round
	   the half way case up */
	offset = ((stand * iindex) + (NORMAL_TABLE_SD >> 1)) / NORMAL_TABLE_SD;

	/* one half should be negative */
	if (randint(2) == 1)
		offset = -offset;

	return mean + offset;
}


/* Returns position of first set bit			-RAK-	 */
/* and clears that bit */
int 
bit_pos(test)
	int32u *test;
{
	register int i;
	register int32u mask = 0x1;

	for (i = 0; i < sizeof(*test) * 8; i++) {
		if (*test & mask) {
			*test &= ~mask;
			return (i);
		}
		mask <<= 1;
	}

	/* no one bits found */
	return (-1);
}

/* Checks a co-ordinate for in bounds status		-RAK-	 */
int 
in_bounds(y, x)
	int y, x;
{
	if ((y > 0) && (y < cur_height - 1) && (x > 0) && (x < cur_width - 1))
		return (TRUE);
	else
		return (FALSE);
}


/* Calculates current boundaries				-RAK-	 */
void 
panel_bounds()
{
	panel_row_min = panel_row * (SCREEN_HEIGHT / 2);
	panel_row_max = panel_row_min + SCREEN_HEIGHT - 1;
	panel_row_prt = panel_row_min - 1;
	panel_col_min = panel_col * (SCREEN_WIDTH / 2);
	panel_col_max = panel_col_min + SCREEN_WIDTH - 1;
	panel_col_prt = panel_col_min - 13;
}


/* Given an row (y) and col (x), this routine detects  -RAK-	 */
/* when a move off the screen has occurred and figures new borders. Force
   forcses the panel bounds to be recalculated, useful for 'W'here. */
int 
get_panel(y, x, force)
	int y, x, force;
{
	register int prow, pcol;
	register int panel;

	prow = panel_row;
	pcol = panel_col;
	if (force || (y < panel_row_min + 2) || (y > panel_row_max - 2)) {
		prow = ((y - SCREEN_HEIGHT / 4) / (SCREEN_HEIGHT / 2));
		if (prow > max_panel_rows)
			prow = max_panel_rows;
		else if (prow < 0)
			prow = 0;
	}
	if (force || (x < panel_col_min + 3) || (x > panel_col_max - 3)) {
		pcol = ((x - SCREEN_WIDTH / 4) / (SCREEN_WIDTH / 2));
		if (pcol > max_panel_cols)
			pcol = max_panel_cols;
		else if (pcol < 0)
			pcol = 0;
	}
	if ((prow != panel_row) || (pcol != panel_col)) {
		panel_row = prow;
		panel_col = pcol;
		panel_bounds();
		panel = TRUE;
		/* stop movement if any */
		if (find_bound)
			end_find();
	} else
		panel = FALSE;
	return (panel);
}


/* Tests a given point to see if it is within the screen -RAK-	 */
/* boundaries.							  */
int 
panel_contains(y, x)
	register int y, x;
{
	if ((y >= panel_row_min) && (y <= panel_row_max) &&
		(x >= panel_col_min) && (x <= panel_col_max))
		return (TRUE);
	else
		return (FALSE);
}


/* Distance between two points				-RAK-	 */
int 
distance(y1, x1, y2, x2)
	int y1, x1, y2, x2;
{
	register int dy, dx;

	dy = y1 - y2;
	if (dy < 0)
		dy = -dy;
	dx = x1 - x2;
	if (dx < 0)
		dx = -dx;

	return ((((dy + dx) << 1) - (dy > dx ? dx : dy)) >> 1);
}

/* Checks points north, south, east, and west for a wall -RAK-	 */
/* note that y,x is always in_bounds(), i.e. 0 < y < cur_height-1, and 0 < x <
   cur_width-1	 */
int 
next_to_walls(y, x)
	register int y, x;
{
	register int i;
	register cave_type *c_ptr;

	i = 0;
	c_ptr = &cave[y - 1][x];
	if (c_ptr->fval >= MIN_CAVE_WALL)
		i++;
	c_ptr = &cave[y + 1][x];
	if (c_ptr->fval >= MIN_CAVE_WALL)
		i++;
	c_ptr = &cave[y][x - 1];
	if (c_ptr->fval >= MIN_CAVE_WALL)
		i++;
	c_ptr = &cave[y][x + 1];
	if (c_ptr->fval >= MIN_CAVE_WALL)
		i++;

	return (i);
}


/* Checks all adjacent spots for corridors		-RAK-	 */
/* note that y, x is always in_bounds(), hence no need to check that j, k are
   in_bounds(), even if they are 0 or cur_x-1 is still works */
int 
next_to_corr(y, x)
	register int y, x;
{
	register int k, j, i;
	register cave_type *c_ptr;

	i = 0;
	for (j = y - 1; j <= (y + 1); j++)
		for (k = x - 1; k <= (x + 1); k++) {
			c_ptr = &cave[j][k];
			/* should fail if there is already a door present */
			if (c_ptr->fval == CORR_FLOOR
			 && (c_ptr->tptr == 0 || t_list[c_ptr->tptr].tval < TV_MIN_DOORS))
				i++;
		}
	return (i);
}


/* generates damage for 2d6 style dice rolls */
int 
damroll(num, sides)
	int num, sides;
{
	register int i, sum = 0;

	for (i = 0; i < num; i++)
		sum += randint(sides);
	return (sum);
}

int 
pdamroll(array)
	int8u *array;
{
	return damroll((int) array[0], (int) array[1]);
}


/* A simple, fast, integer-based line-of-sight algorithm.  By Joseph Hall, 4116
   Brewster Drive, Raleigh NC 27606.  Email to jnh@ecemwl.ncsu.edu.

Returns TRUE if a line of sight can be traced from x0, y0 to x1, y1.

The LOS begins at the center of the tile [x0, y0] and ends at the center of the
   tile [x1, y1].  If los() is to return TRUE, all of the tiles this line
   passes through must be transparent, WITH THE EXCEPTIONS of the starting and
   ending tiles.

We don't consider the line to be "passing through" a tile if it only passes
   across one corner of that tile. */

/* Because this function uses (short) ints for all calculations, overflow may
   occur if deltaX and deltaY exceed 90. */

int 
los(fromY, fromX, toY, toX)
	int fromY, fromX, toY, toX;
{
	register int tmp, deltaX, deltaY;

	deltaX = toX - fromX;
	deltaY = toY - fromY;

	/* Adjacent? */
	if ((deltaX < 2) && (deltaX > -2) && (deltaY < 2) && (deltaY > -2))
		return TRUE;

	/* Handle the cases where deltaX or deltaY == 0. */
	if (deltaX == 0) {
		register int p_y;		/* y position -- loop variable	 */

		if (deltaY < 0) {
			tmp = fromY;
			fromY = toY;
			toY = tmp;
		}
		for (p_y = fromY + 1; p_y < toY; p_y++)
			if (cave[p_y][fromX].fval >= MIN_CLOSED_SPACE)
				return FALSE;
		return TRUE;
	} else if (deltaY == 0) {
		register int px;		/* x position -- loop variable	 */

		if (deltaX < 0) {
			tmp = fromX;
			fromX = toX;
			toX = tmp;
		}
		for (px = fromX + 1; px < toX; px++)
			if (cave[fromY][px].fval >= MIN_CLOSED_SPACE)
				return FALSE;
		return TRUE;
	}
	/* Now, we've eliminated all the degenerate cases. In the computations
	   below, dy (or dx) and m are multiplied by a scale factor, scale =
	   abs(deltaX * deltaY * 2), so that we can use integer arithmetic. */

	{
		register int px,		/* x position				 */
		  p_y,					/* y position				 */
		  scale2;				/* above scale factor / 2		 */
		int scale,				/* above scale factor			 */
		  xSign,				/* sign of deltaX			 */
		  ySign,				/* sign of deltaY			 */
		  m;					/* slope or 1/slope of LOS		 */

		scale2 = abs(deltaX * deltaY);
		scale = scale2 << 1;
		xSign = (deltaX < 0) ? -1 : 1;
		ySign = (deltaY < 0) ? -1 : 1;

		/* Travel from one end of the line to the other, oriented along the
		   longer axis. */

		if (abs(deltaX) >= abs(deltaY)) {
			register int dy;	/* "fractional" y position	 */

			/* We start at the border between the first and second tiles, where
			   the y offset = .5 * slope.  Remember the scale factor.  We have:
			
			m = deltaY / deltaX * 2 * (deltaY * deltaX) = 2 * deltaY * deltaY. */

			dy = deltaY * deltaY;
			m = dy << 1;
			px = fromX + xSign;

			/* Consider the special case where slope == 1. */
			if (dy == scale2) {
				p_y = fromY + ySign;
				dy -= scale;
			} else
				p_y = fromY;

			while (toX - px) {
				if (cave[p_y][px].fval >= MIN_CLOSED_SPACE)
					return FALSE;

				dy += m;
				if (dy < scale2)
					px += xSign;
				else if (dy > scale2) {
					p_y += ySign;
					if (cave[p_y][px].fval >= MIN_CLOSED_SPACE)
						return FALSE;
					px += xSign;
					dy -= scale;
				} else {
					/* This is the case, dy == scale2, where the LOS exactly
					   meets the corner of a tile. */
					px += xSign;
					p_y += ySign;
					dy -= scale;
				}
			}
			return TRUE;
		} else {
			register int dx;	/* "fractional" x position	 */

			dx = deltaX * deltaX;
			m = dx << 1;

			p_y = fromY + ySign;
			if (dx == scale2) {
				px = fromX + xSign;
				dx -= scale;
			} else
				px = fromX;

			while (toY - p_y) {
				if (cave[p_y][px].fval >= MIN_CLOSED_SPACE)
					return FALSE;
				dx += m;
				if (dx < scale2)
					p_y += ySign;
				else if (dx > scale2) {
					px += xSign;
					if (cave[p_y][px].fval >= MIN_CLOSED_SPACE)
						return FALSE;
					p_y += ySign;
					dx -= scale;
				} else {
					px += xSign;
					p_y += ySign;
					dx -= scale;
				}
			}
			return TRUE;
		}
	}
}


/* Returns symbol for given row, column			-RAK-	 */
unsigned char 
loc_symbol(y, x)
	int y, x;
{
	register cave_type *cave_ptr;
	register struct flags *f_ptr;

	cave_ptr = &cave[y][x];
	f_ptr = &py.flags;

	if ((cave_ptr->cptr == 1) && (!find_flag || find_prself))
		return '@';
	else if (f_ptr->status & PY_BLIND)
		return ' ';
	else if ((f_ptr->image > 0) && (randint(12) == 1))
		return randint(95) + 31;
	else if ((cave_ptr->cptr > 1) && (m_list[cave_ptr->cptr].ml))
		return c_list[m_list[cave_ptr->cptr].mptr].cchar;
	else if (!cave_ptr->pl && !cave_ptr->tl && !cave_ptr->fm)
		return ' ';
	else if ((cave_ptr->tptr != 0)
			 && (t_list[cave_ptr->tptr].tval != TV_INVIS_TRAP))
		return t_list[cave_ptr->tptr].tchar;
	else if (cave_ptr->fval <= MAX_CAVE_FLOOR)
		return '.';
	else if (cave_ptr->fval == 16) // SHOP ROOF
		return 216;
	else if (cave_ptr->fval == 17) 
		return 217;
	else if (cave_ptr->fval == 18) 
		return 218;
	else if (cave_ptr->fval == 19) 
		return 219;
	else if (cave_ptr->fval == GRANITE_WALL || cave_ptr->fval == BOUNDARY_WALL
			   || highlight_seams == FALSE) 
		return '#';
	else 					/* Originally set highlight bit, but that is
								   not portable, now use the percent sign
								   instead. */
		return '%';
	
}


/* Tests a spot for light or field mark status		-RAK-	 */
int 
test_light(y, x)
	int y, x;
{
	register cave_type *cave_ptr;

	cave_ptr = &cave[y][x];
	if (cave_ptr->pl || cave_ptr->tl || cave_ptr->fm)
		return (TRUE);
	else
		return (FALSE);
}


/* Prints the map of the dungeon			-RAK-	 */
void 
prt_map()
{
	register int i, j, k;
	register unsigned char tmp_char;

	zap_map();

	k = 0;
	for (i = panel_row_min; i <= panel_row_max; i++) {	/* Top to bottom */
		k++;
		clear_line_fast(k);
		for (j = panel_col_min; j <= panel_col_max; j++) {		/* Left to right */
			tmp_char = loc_symbol(i, j);
			if (tmp_char != ' ')
				printg(tmp_char, i, j);
		}
	}
}


/* Compact monsters					-RAK-	 */
/* Return TRUE if any monsters were deleted, FALSE if could not delete any
   monsters.  */
int 
compact_monsters()
{
	register int i;
	int cur_dis, delete_any;
	register monster_type *mon_ptr;

#ifdef ATARIST_MWC
	int32 holder;

#endif

	msg_print("Compacting monsters...");

	cur_dis = 66;
	delete_any = FALSE;
	do {
		for (i = mfptr - 1; i >= MIN_MONIX; i--) {
			mon_ptr = &m_list[i];
			if ((cur_dis < mon_ptr->cdis) && (randint(3) == 1)) {
				/* Never compact away the Balrog!! */
#ifdef ATARIST_MWC
				if (c_list[mon_ptr->mptr].cmove & (holder = CM_WIN))
#else
				if (c_list[mon_ptr->mptr].cmove & CM_WIN)
#endif
					/* Do nothing */
					;
				/* in case this is called from within creatures(), this is a
				   horrible hack, the m_list/creatures() code needs to be
				   rewritten */
				else if (hack_monptr < i) {
					delete_monster(i);
					delete_any = TRUE;
				} else
					/* fix1_delete_monster() does not decrement mfptr, so don't
					   set delete_any if this was called */
					fix1_delete_monster(i);
			}
		}
		if (!delete_any) {
			cur_dis -= 6;
			/* Can't delete any monsters, return failure.  */
			if (cur_dis < 0)
				return FALSE;
		}
	}
	while (!delete_any);
	return TRUE;
}


/* Add to the players food time				-RAK-	 */
void 
add_food(num)
	int num;
{
	register struct flags *p_ptr;
	register int extra, penalty;

	p_ptr = &py.flags;
	if (p_ptr->food < 0)
		p_ptr->food = 0;
	p_ptr->food += num;
	if (p_ptr->food > PLAYER_FOOD_MAX) {
		msg_printc("You are bloated from overeating.",15);

		/* Calculate how much of num is responsible for the bloating. Give the
		   player food credit for 1/50, and slow him for that many turns also.  */
		extra = p_ptr->food - PLAYER_FOOD_MAX;
		if (extra > num)
			extra = num;
		penalty = extra / 50;

		p_ptr->slow += penalty;
		if (extra == num)
			p_ptr->food = p_ptr->food - num + penalty;
		else
			p_ptr->food = PLAYER_FOOD_MAX + penalty;
	} else if (p_ptr->food > PLAYER_FOOD_FULL)
		msg_print("You are full.");
}


/* Returns a pointer to next free space			-RAK-	 */
/* Returns -1 if could not allocate a monster.  */
int 
popm()
{
	if (mfptr == MAX_MALLOC) {
		if (!compact_monsters())
			return -1;
	}
	return (mfptr++);
}


/* Gives Max hit points					-RAK-	 */
int 
max_hp(array)
	int8u *array;
{
	return (array[0] * array[1]);
}


/* Places a monster at given location			-RAK-	 */
int 
place_monster(y, x, z, slp)
	register int y, x, z;
	int slp;
{
	register int cur_pos;
	register monster_type *mon_ptr;

	cur_pos = popm();
	if (cur_pos == -1)
		return FALSE;
	mon_ptr = &m_list[cur_pos];
	mon_ptr->fy = y;
	mon_ptr->fx = x;
	mon_ptr->mptr = z;
	if (c_list[z].cdefense & CD_MAX_HP)
		mon_ptr->hp = max_hp(c_list[z].hd);
	else
		mon_ptr->hp = pdamroll(c_list[z].hd);
	/* the c_list speed value is 10 greater, so that it can be a int8u */
	mon_ptr->cspeed = c_list[z].speed - 10 + py.flags.speed;
	mon_ptr->stunned = 0;
	mon_ptr->cdis = distance(char_row, char_col, y, x);
	mon_ptr->ml = FALSE;
	cave[y][x].cptr = cur_pos;
	if (slp) {
		if (c_list[z].sleep == 0)
			mon_ptr->csleep = 0;
		else
			mon_ptr->csleep = (c_list[z].sleep * 2) +
				randint((int) c_list[z].sleep * 10);
	} else
		mon_ptr->csleep = 0;
	return TRUE;
}


/* Places a monster at given location			-RAK-	 */
void 
place_win_monster()
{
	register int y, x, cur_pos;
	register monster_type *mon_ptr;

	if (!total_winner) {
		cur_pos = popm();
		/* Check for case where could not allocate space for the win monster,
		   this should never happen.  */
		if (cur_pos == -1)
			abort();
		mon_ptr = &m_list[cur_pos];
		do {
			y = randint(cur_height - 2);
			x = randint(cur_width - 2);
		}
		while ((cave[y][x].fval >= MIN_CLOSED_SPACE) || (cave[y][x].cptr != 0)
			   || (cave[y][x].tptr != 0) ||
			   (distance(y, x, char_row, char_col) <= MAX_SIGHT));
		mon_ptr->fy = y;
		mon_ptr->fx = x;
		mon_ptr->mptr = randint(WIN_MON_TOT) - 1 + m_level[MAX_MONS_LEVEL];
		if (c_list[mon_ptr->mptr].cdefense & CD_MAX_HP)
			mon_ptr->hp = max_hp(c_list[mon_ptr->mptr].hd);
		else
			mon_ptr->hp = pdamroll(c_list[mon_ptr->mptr].hd);
		/* the c_list speed value is 10 greater, so that it can be a int8u */
		mon_ptr->cspeed = c_list[mon_ptr->mptr].speed - 10 + py.flags.speed;
		mon_ptr->stunned = 0;
		mon_ptr->cdis = distance(char_row, char_col, y, x);
		cave[y][x].cptr = cur_pos;
		mon_ptr->csleep = 0;
	}
}


/* Return a monster suitable to be placed at a given level.  This makes high
   level monsters (up to the given level) slightly more common than low level
   monsters at any given level.   -CJS- */
int 
get_mons_num(level)
	int level;
{
	register int i, j, num;

	if (level == 0)
		i = randint(m_level[0]) - 1;
	else {
		if (level > MAX_MONS_LEVEL)
			level = MAX_MONS_LEVEL;
		if (randint(MON_NASTY) == 1) {
			i = randnor(0, 4);
			level = level + abs(i) + 1;
			if (level > MAX_MONS_LEVEL)
				level = MAX_MONS_LEVEL;
		} else {
			/* This code has been added to make it slightly more likely to get
			   the higher level monsters. Originally a uniform distribution
			   over all monsters of level less than or equal to the dungeon
			   level. This distribution makes a level n monster occur approx
			   2/n% of the time on level n, and 1/n*n% are 1st level. */

			num = m_level[level] - m_level[0];
			i = randint(num) - 1;
			j = randint(num) - 1;
			if (j > i)
				i = j;
			level = c_list[i + m_level[0]].level;
		}
		i = randint(m_level[level] - m_level[level - 1]) - 1 + m_level[level - 1];
	}
	return i;
}


/* Allocates a random monster				-RAK-	 */
void 
alloc_monster(num, dis, slp)
	int num, dis;
	int slp;
{
	register int y, x, i;
	int l;

	for (i = 0; i < num; i++) {
		do {
			y = randint(cur_height - 2);
			x = randint(cur_width - 2);
		}
		while (cave[y][x].fval >= MIN_CLOSED_SPACE || (cave[y][x].cptr != 0) ||
			   (distance(y, x, char_row, char_col) <= dis));

		l = get_mons_num(dun_level);
		/* Dragons are always created sleeping here, so as to give the player a
		   sporting chance.  */
		if (c_list[l].cchar == 'd' || c_list[l].cchar == 'D')
			slp = TRUE;
		/* Place_monster() should always return TRUE here.  It does not matter
		   if it fails though.  */
		(void) place_monster(y, x, l, slp);
	}
}


/* Places creature adjacent to given location		-RAK-	 */
int 
summon_monster(y, x, slp)
	int *y, *x;
	int slp;
{
	register int i, j, k;
	int l, summon;
	register cave_type *cave_ptr;

	i = 0;
	summon = FALSE;
	l = get_mons_num(dun_level + MON_SUMMON_ADJ);
	do {
		j = *y - 2 + randint(3);
		k = *x - 2 + randint(3);
		if (in_bounds(j, k)) {
			cave_ptr = &cave[j][k];
			if (cave_ptr->fval <= MAX_OPEN_SPACE && (cave_ptr->cptr == 0)) {
				/* Place_monster() should always return TRUE here.  */
				if (!place_monster(j, k, l, slp))
					return FALSE;
				summon = TRUE;
				i = 9;
				*y = j;
				*x = k;
			}
		}
		i++;
	}
	while (i <= 9);
	return (summon);
}


/* Places undead adjacent to given location		-RAK-	 */
int 
summon_undead(y, x)
	int *y, *x;
{
	register int i, j, k;
	int l, m, ctr, summon;
	register cave_type *cave_ptr;

	i = 0;
	summon = FALSE;
	l = m_level[MAX_MONS_LEVEL];
	do {
		m = randint(l) - 1;
		ctr = 0;
		do {
			if (c_list[m].cdefense & CD_UNDEAD) {
				ctr = 20;
				l = 0;
			} else {
				m++;
				if (m > l)
					ctr = 20;
				else
					ctr++;
			}
		}
		while (ctr <= 19);
	}
	while (l != 0);
	do {
		j = *y - 2 + randint(3);
		k = *x - 2 + randint(3);
		if (in_bounds(j, k)) {
			cave_ptr = &cave[j][k];
			if (cave_ptr->fval <= MAX_OPEN_SPACE && (cave_ptr->cptr == 0)) {
				/* Place_monster() should always return TRUE here.  */
				if (!place_monster(j, k, m, FALSE))
					return FALSE;
				summon = TRUE;
				i = 9;
				*y = j;
				*x = k;
			}
		}
		i++;
	}
	while (i <= 9);
	return (summon);
}


/* If too many objects on floor level, delete some of them-RAK-	 */
static void 
compact_objects()
{
	register int i, j;
	int ctr, cur_dis, chance;
	register cave_type *cave_ptr;

	msg_print("Compacting objects...");

	ctr = 0;
	cur_dis = 66;
	do {
		for (i = 0; i < cur_height; i++)
			for (j = 0; j < cur_width; j++) {
				cave_ptr = &cave[i][j];
				if ((cave_ptr->tptr != 0)
					&& (distance(i, j, char_row, char_col) > cur_dis)) {
					switch (t_list[cave_ptr->tptr].tval) {
						case TV_VIS_TRAP:
							chance = 15;
							break;
						case TV_INVIS_TRAP:
						case TV_RUBBLE:
						case TV_OPEN_DOOR:
						case TV_CLOSED_DOOR:
							chance = 5;
							break;
						case TV_UP_STAIR:
						case TV_DOWN_STAIR:
						case TV_STORE_DOOR:
							/* stairs, don't delete them */
							/* shop doors, don't delete them */
							chance = 0;
							break;
						case TV_SECRET_DOOR:	/* secret doors */
							chance = 3;
							break;
						default:
							chance = 10;
					}
					if (randint(100) <= chance) {
						(void) delete_object(i, j);
						ctr++;
					}
				}
			}
		if (ctr == 0)
			cur_dis -= 6;
	}
	while (ctr <= 0);
	if (cur_dis < 66)
		prt_map();
}

/* Gives pointer to next free space			-RAK-	 */
int 
popt()
{
	if (tcptr == MAX_TALLOC)
		compact_objects();
	return (tcptr++);
}


/* Pushs a record back onto free space list		-RAK-	 */
/* Delete_object() should always be called instead, unless the object in
   question is not in the dungeon, e.g. in store1.c and files.c */
void 
pusht(x)
	register int8u x;
{
	register int i, j;

	if (x != tcptr - 1) {
		t_list[x] = t_list[tcptr - 1];

		/* must change the tptr in the cave of the object just moved */
		for (i = 0; i < cur_height; i++)
			for (j = 0; j < cur_width; j++)
				if (cave[i][j].tptr == tcptr - 1)
					cave[i][j].tptr = x;
	}
	tcptr--;
	invcopy(&t_list[tcptr], OBJ_NOTHING);
}


/* Boolean : is object enchanted	  -RAK- */
int 
magik(chance)
	int chance;
{
	if (randint(100) <= chance)
		return (TRUE);
	else
		return (FALSE);
}


/* Enchant a bonus based on degree desired -RAK- */
int 
m_bonus(base, max_std, level)
	int base, max_std, level;
{
	register int x, stand_dev, tmp;

	stand_dev = (OBJ_STD_ADJ * level / 100) + OBJ_STD_MIN;
	/* Check for level > max_std since that may have generated an overflow.  */
	if (stand_dev > max_std || level > max_std)
		stand_dev = max_std;
	/* abs may be a macro, don't call it with randnor as a parameter */
	tmp = randnor(0, stand_dev);
	x = (abs(tmp) / 10) + base;
	if (x < base)
		return (base);
	else
		return (x);
}
