/*
 * generate.c: initialize/create a dungeon or town level 
 *
 * Copyright (c) 1989 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 "constant.h"
#include "config.h"
#include "types.h"
#include "externs.h"
#include "monster.h"

#ifdef USG
#if !defined(ATARIST_MWC)
#ifndef __TURBOC__
#include <memory.h>
#else
#include <mem.h>
#endif
#endif
#endif

#ifdef __MINT__
#include <string.h>
#endif

/* Lets do all prototypes correctly.... -CWS */
#ifndef NO_LINT_ARGS
#ifdef __STDC__
static void correct_dir(int *, int *, int, int, int, int);
static void rand_dir(int *, int *);
static void fill_cave(int);
static void place_streamer(int, int);
static void place_open_door(int, int);
static void place_broken_door(int, int);
static void place_closed_door(int, int);
static void place_locked_door(int, int);
static void place_stuck_door(int, int);
static void place_secret_door(int, int);
static void place_door(int, int);
static void place_up_stairs(int, int);
static void place_down_stairs(int, int);
static void place_stairs(int, int, int);
static void vault_trap(int, int, int, int, int);
static void vault_monster(int, int, int);
static void vault_jelly(int, int);
static void vault_orc(int, int, int);
static void vault_troll(int, int, int);
static void vault_undead(int, int);
static void vault_dragon(int, int, int, int);
static void vault_demon(int, int, int);
static void vault_giant(int, int, int);
static void build_room(int, int);
static void build_type1(int, int);
static void build_type5(int, int);
static void build_type2(int, int);
static void build_type3(int, int);
static void vault_nasty(int, int, int, int, int);
static void special_pit(int, int, int);
static void build_tunnel(int, int, int, int);
static int next_to(int, int);
static void try_door(int, int);
static void new_spot(int16 *, int16 *);
static void build_pit(int, int);
static void build_store(int, int, int);
#else
static void         correct_dir();
static void         rand_dir();
static void         fill_cave();
static void         place_streamer();
static void         place_open_door();
static void         place_broken_door();
static void         place_closed_door();
static void         place_locked_door();
static void         place_stuck_door();
static void         place_secret_door();
static void         place_door();
static void         place_up_stairs();
static void         place_down_stairs();
static void         place_stairs();
static void         vault_trap();
static void         vault_monster();
static void         vault_jelly();
static void         vault_orc();
static void         vault_troll();
static void         vault_undead();
static void         vault_dragon();
static void         vault_demon();
static void         vault_giant();
static void         build_room();
static void         build_type1();
static void         build_type5();
static void         build_type2();
static void         build_type3();
static void         vault_nasty();
static void         special_pit();
static int          next_to();
static void         try_door();
static void         new_spot();
static void         build_pit();
static void         build_store();
#endif

static void         place_boundary();
static void         place_destroyed();
static void         blank_cave();
static void         cave_gen();
static void         tlink();
static void         mlink();
static void         town_gen();
#endif

typedef struct coords {
    int                 x, y;
}                   coords;

static coords       doorstk[100];
static int          doorindex;

extern int          rating;
extern int          peek;

/* Always picks a correct direction		 */
static void 
correct_dir(rdir, cdir, y1, x1, y2, x2)
    int                *rdir, *cdir;
    register int        y1, x1, y2, x2;
{
    if (y1 < y2)
	*rdir = 1;
    else if (y1 == y2)
	*rdir = 0;
    else
	*rdir = (-1);
    if (x1 < x2)
	*cdir = 1;
    else if (x1 == x2)
	*cdir = 0;
    else
	*cdir = (-1);
    if ((*rdir != 0) && (*cdir != 0)) {
	if (randint(2) == 1)
	    *rdir = 0;
	else
	    *cdir = 0;
    }
}


/* Chance of wandering direction			 */
static void 
rand_dir(rdir, cdir)
    int                *rdir, *cdir;
{
    register int        tmp;

    tmp = randint(4);
    if (tmp < 3) {
	*cdir = 0;
	*rdir = (-3) + (tmp << 1);   /* tmp=1 -> *rdir=-1; tmp=2 -> *rdir=1 */
    } else {
	*rdir = 0;
	*cdir = (-7) + (tmp << 1);   /* tmp=3 -> *cdir=-1; tmp=4 -> *cdir=1 */
    }
}


/* Blanks out entire cave				-RAK-	 */
static void 
blank_cave()
{
#ifndef USG
    bzero((char *)&cave[0][0], sizeof(cave));
#else
#ifdef MAC
/* On the mac, cave is a pointer, so sizeof(cave) = 4! */
    (void)memset((char *)&cave[0][0], 0, sizeof(cave_type) * MAX_HEIGHT * MAX_WIDTH);
#else
    (void)memset((char *)&cave[0][0], 0, sizeof(cave));
#endif
#endif
}


/* Fills in empty spots with desired rock		-RAK-	 */
/* Note: 9 is a temporary value.				 */
static void 
fill_cave(fval)
    register int        fval;
{
    register int        i, j;
    register cave_type *c_ptr;

/* no need to check the border of the cave */

    for (i = cur_height - 2; i > 0; i--) {
	c_ptr = &cave[i][1];
	for (j = cur_width - 2; j > 0; j--) {
	    if ((c_ptr->fval == NULL_WALL) || (c_ptr->fval == TMP1_WALL) ||
		(c_ptr->fval == TMP2_WALL))
		c_ptr->fval = fval;
	    c_ptr++;
	}
    }
}

/* Places indestructible rock around edges of dungeon	-RAK-	 */
static void 
place_boundary()
{
    register int        i;
    register cave_type *top_ptr, *bottom_ptr;

    cave_type(*left_ptr)[MAX_WIDTH];
    cave_type(*right_ptr)[MAX_WIDTH];

/* put permanent wall on leftmost row and rightmost row */
    left_ptr = (cave_type(*)[MAX_WIDTH]) & cave[0][0];
    right_ptr = (cave_type(*)[MAX_WIDTH]) & cave[0][cur_width - 1];

    for (i = 0; i < cur_height; i++) {
	((cave_type *) left_ptr)->fval = BOUNDARY_WALL;
	left_ptr++;
	((cave_type *) right_ptr)->fval = BOUNDARY_WALL;
	right_ptr++;
    }

/* put permanent wall on top row and bottom row */
    top_ptr = &cave[0][0];
    bottom_ptr = &cave[cur_height - 1][0];

    for (i = 0; i < cur_width; i++) {
	top_ptr->fval = BOUNDARY_WALL;
	top_ptr++;
	bottom_ptr->fval = BOUNDARY_WALL;
	bottom_ptr++;
    }
}


/* Places "streamers" of rock through dungeon		-RAK-	 */
static void 
place_streamer(fval, treas_chance)
    int                 fval;
    int                 treas_chance;
{
    register int        i, tx, ty;
    int                 y, x, t1, t2, dir;
    register cave_type *c_ptr;

/* Choose starting point and direction		 */
    y = (cur_height / 2) + 11 - randint(23);
    x = (cur_width / 2) + 16 - randint(33);

    dir = randint(8);		   /* Number 1-4, 6-9	 */
    if (dir > 4)
	dir = dir + 1;

/* Place streamer into dungeon			 */
    t1 = 2 * DUN_STR_RNG + 1;	   /* Constants	 */
    t2 = DUN_STR_RNG + 1;
    do {
	for (i = 0; i < DUN_STR_DEN; i++) {
	    ty = y + randint(t1) - t2;
	    tx = x + randint(t1) - t2;
	    if (in_bounds(ty, tx)) {
		c_ptr = &cave[ty][tx];
		if (c_ptr->fval == GRANITE_WALL) {
		    c_ptr->fval = fval;
		    if (randint(treas_chance) == 1)
			place_gold(ty, tx);
		}
	    }
	}
    }
    while (mmove(dir, &y, &x));
}
void 
repl_spot(y, x, typ)		   /* copied verbatim from spells.c - damn
				    * thing won't find it. :( :( -DGK */
    int                 y, x, typ;
{
    register cave_type *c_ptr;

    c_ptr = &cave[y][x];
    switch (typ) {
      case 1:
      case 2:
      case 3:
	c_ptr->fval = CORR_FLOOR;
	break;
      case 4:
      case 7:
      case 10:
	c_ptr->fval = GRANITE_WALL;
	break;
      case 5:
      case 8:
      case 11:
	c_ptr->fval = MAGMA_WALL;
	break;
      case 6:
      case 9:
      case 12:
	c_ptr->fval = QUARTZ_WALL;
	break;
    }
    c_ptr->pl = FALSE;
    c_ptr->fm = FALSE;
    c_ptr->lr = FALSE;		   /* this is no longer part of a room */
    if (c_ptr->tptr != 0)
	(void)delete_object(y, x);
    if (c_ptr->cptr > 1)
	delete_monster((int)c_ptr->cptr);
}


static void 
place_destroyed()
{
    register int        y, x;
    register int        i, j, k;
    int                 n;

    for (n = 1; n <= randint(5); n++) {
	x = randint(cur_width - 32) + 15;
	y = randint(cur_height - 32) + 15;
	for (i = (y - 15); i <= (y + 15); i++)
	    for (j = (x - 15); j <= (x + 15); j++)
		if (in_bounds(i, j) && (cave[i][j].fval != BOUNDARY_WALL) &&
		    ((cave[i][j].tptr == 0) ||	/* DGK */
		     ((t_list[cave[i][j].tptr].tval != TV_UP_STAIR) &&
		      (t_list[cave[i][j].tptr].tval != TV_DOWN_STAIR) &&
		      (!(t_list[cave[i][j].tptr].flags2 & TR_ARTIFACT))))) {
		    k = distance(i, j, y, x);
		    if (i == char_row && j == char_col)
			repl_spot(i, j, 1);
		    else if (k < 13)
			repl_spot(i, j, (int)randint(6));
		    else if (k < 16)
			repl_spot(i, j, (int)randint(9));
		}
    }
}

static void 
place_open_door(y, x)
    int                 y, x;
{
    register int        cur_pos;
    register cave_type *c_ptr;

    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    c_ptr = &cave[y][x];
    if (c_ptr->tptr != 0)
	if (((t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
	     (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
	     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
	    (t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
	    return;		   /* abort! */
	else
	    delete_object(y, x);
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_OPEN_DOOR);
    c_ptr->fval = CORR_FLOOR;
}


static void 
place_broken_door(y, x)
    int                 y, x;
{
    register int        cur_pos;
    register cave_type *c_ptr;

    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    c_ptr = &cave[y][x];
    if (c_ptr->tptr != 0)
	if (((t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
	     (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
	     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
	    (t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
	    return;		   /* abort! */
	else
	    delete_object(y, x);
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_OPEN_DOOR);
    c_ptr->fval = CORR_FLOOR;
    t_list[cur_pos].p1 = 1;
}


static void 
place_closed_door(y, x)
    int                 y, x;
{
    register int        cur_pos;
    register cave_type *c_ptr;

    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    c_ptr = &cave[y][x];
    if (c_ptr->tptr != 0)
	if (((t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
	     (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
	     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
	    (t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
	    return;		   /* abort! */
	else
	    delete_object(y, x);
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_CLOSED_DOOR);
    c_ptr->fval = BLOCKED_FLOOR;
}


static void 
place_locked_door(y, x)
    int                 y, x;
{
    register int        cur_pos;
    register cave_type *c_ptr;

    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    c_ptr = &cave[y][x];
    if (c_ptr->tptr != 0)
	if (((t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
	     (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
	     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
	    (t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
	    return;		   /* abort! */
	else
	    delete_object(y, x);
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_CLOSED_DOOR);
    c_ptr->fval = BLOCKED_FLOOR;
    t_list[cur_pos].p1 = randint(10) + 10;
}


static void 
place_stuck_door(y, x)
    int                 y, x;
{
    register int        cur_pos;
    register cave_type *c_ptr;

    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    c_ptr = &cave[y][x];
    if (c_ptr->tptr != 0)
	if (((t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
	     (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
	     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
	    (t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
	    return;		   /* abort! */
	else
	    delete_object(y, x);
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_CLOSED_DOOR);
    c_ptr->fval = BLOCKED_FLOOR;
    t_list[cur_pos].p1 = (-randint(10) - 10);
}


static void 
place_secret_door(y, x)
    int                 y, x;
{
    register int        cur_pos;
    register cave_type *c_ptr;

    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    c_ptr = &cave[y][x];
    if (c_ptr->tptr != 0)
	if (((t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
	     (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
	     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
	    (t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
	    return;		   /* abort! */
	else
	    delete_object(y, x);
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_SECRET_DOOR);
    c_ptr->fval = BLOCKED_FLOOR;
}


static void 
place_door(y, x)
    int                 y, x;
{
    register int        tmp;

    tmp = randint(8);
    if (tmp < 4) {
	if (randint(4) == 1)
	    place_broken_door(y, x);
	else
	    place_open_door(y, x);
    } else if (tmp < 7) {
	tmp = randint(100);
	if (tmp > 25)
	    place_closed_door(y, x);
	else if (tmp == 3)
	    place_stuck_door(y, x);
	else
	    place_locked_door(y, x);
    } else
	place_secret_door(y, x);
}


/* Place an up staircase at given y, x			-RAK-	 */
static void 
place_up_stairs(y, x)
    int                 y, x;
{
    register int        cur_pos;
    register cave_type *c_ptr;

    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    c_ptr = &cave[y][x];
    if (c_ptr->tptr != 0)
	if (((t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
	     (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
	     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
	    (t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
	    return;		   /* abort! */
	else
	    delete_object(y, x);
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_UP_STAIR);

}


/* Place a down staircase at given y, x			-RAK-	 */
static void 
place_down_stairs(y, x)
    int                 y, x;
{
    register int        cur_pos;
    register cave_type *c_ptr;

    if (is_quest(dun_level)) {
	place_up_stairs(y, x);
	return;
    }
    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    c_ptr = &cave[y][x];
    if (c_ptr->tptr != 0)
	if (((t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
	     (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
	     (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
	    (t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
	    (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
	    return;		   /* abort! */
	else
	    delete_object(y, x);
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_DOWN_STAIR);
}


/* Places a staircase 1=up, 2=down			-RAK-	 */
static void 
place_stairs(typ, num, walls)
    int                 typ, num, walls;
{
    register cave_type *cave_ptr;
    int                 i, j, flag;
    register int        y1, x1, y2, x2;

    for (i = 0; i < num; i++) {
	flag = FALSE;
	do {
	    j = 0;
	    do {
	    /*
	     * Note: don't let y1/x1 be zero, and don't let y2/x2 be equal to
	     * cur_height-1/cur_width-1, these values are always
	     * BOUNDARY_ROCK. 
	     */
		y1 = randint(cur_height - 14);
		x1 = randint(cur_width - 14);
		y2 = y1 + 12;
		x2 = x1 + 12;
		do {
		    do {
			cave_ptr = &cave[y1][x1];
			if (cave_ptr->fval <= MAX_OPEN_SPACE
			    && (cave_ptr->tptr == 0)
			    && (next_to_walls(y1, x1) >= walls)) {
			    flag = TRUE;
			    if (typ == 1)
				place_up_stairs(y1, x1);
			    else
				place_down_stairs(y1, x1);
			}
			x1++;
		    }
		    while ((x1 != x2) && (!flag));
		    x1 = x2 - 12;
		    y1++;
		}
		while ((y1 != y2) && (!flag));
		j++;
	    }
	    while ((!flag) && (j <= 30));
	    walls--;
	}
	while (!flag);
    }
}


/* Place a trap with a given displacement of point	-RAK-	 */
static void 
vault_trap(y, x, yd, xd, num)
    int                 y, x, yd, xd, num;
{
    register int        count, y1, x1;
    int                 i, flag;
    register cave_type *c_ptr;

    for (i = 0; i < num; i++) {
	flag = FALSE;
	count = 0;
	do {
	    do {		   /* add another bounds check -CFT */
		y1 = y - yd - 1 + randint(2 * yd + 1);
		x1 = x - xd - 1 + randint(2 * xd + 1);
	    } while (!in_bounds(y1, x1));
	    c_ptr = &cave[y1][x1];
	    if ((c_ptr->fval != NULL_WALL) && (c_ptr->fval <= MAX_CAVE_FLOOR)
		&& (c_ptr->tptr == 0)) {
		place_trap(y1, x1, randint(MAX_TRAP) - 1);
		flag = TRUE;
	    }
	    count++;
	}
	while ((!flag) && (count <= 5));
    }
}


/* Place a monster with a given displacement of point	-RAK-	 */
static void 
vault_monster(y, x, num)
    int                 y, x, num;
{
    register int        i;
    int                 y1, x1;

    for (i = 0; i < num; i++) {
	y1 = y;
	x1 = x;
	(void)summon_monster(&y1, &x1, TRUE);
    }
}

static void 
vault_jelly(y, x)
    int                 y, x;
{
    int                 l, m, summon;

    summon = FALSE;
    l = m_level[MAX_MONS_LEVEL];
    do {
	m = randint(l) - 1;
	if (((c_list[m].cchar == 'j') || (c_list[m].cchar == ',')
	     || (c_list[m].cchar == 'i') || (c_list[m].cchar == 'm'))
	    && !(c_list[m].cdefense & EVIL)) {
	    summon = TRUE;
	    place_monster(y, x, m, TRUE);
	}
    } while (!summon);
}

static void 
vault_orc(y, x, rank)
    int                 y, x, rank;
{
    register int        i;

    i = 0;
    switch (rank) {
      case 1:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Snaga"))
		break;
	    i++;
	}
	break;
      case 2:
      case 3:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Black orc"))
		break;
	    i++;
	}
	break;
      case 4:
      case 5:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Uruk"))
		break;
	    i++;
	}
	break;
      case 6:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Orc captain"))
		break;
	    i++;
	}
	break;
    }
    if (i != MAX_CREATURES)
	place_monster(y, x, i, FALSE);
}

static void 
vault_troll(y, x, rank)
    int                 y, x, rank;
{
    register int        i;

    i = 0;
    switch (rank) {
      case 1:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Forest troll"))
		break;
	    i++;
	}
	break;
      case 2:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Stone troll"))
		break;
	    i++;
	}
	break;
      case 3:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Ice troll"))
		break;
	    i++;
	}
	break;
      case 4:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Cave troll"))
		break;
	    i++;
	}
	break;
      case 5:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Water troll"))
		break;
	    i++;
	}
	break;
      case 6:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Olog"))
		break;
	    i++;
	}
	break;
    }
    if (i != MAX_CREATURES)
	place_monster(y, x, i, FALSE);
}

static void 
vault_undead(y, x)
    int                 y, x;
{
    int                 l, m, summon;

    summon = FALSE;
    l = m_level[MAX_MONS_LEVEL];
    do {
	m = randint(l) - 1;
	if ((c_list[m].cdefense & UNDEAD) && !(c_list[m].cdefense & UNIQUE)) {
	    summon = TRUE;
	    place_monster(y, x, m, TRUE);
	}
    } while (!summon);
}


static void 
vault_dragon(y, x, rank, type)
    int                 y, x, rank, type;
{
    register int        i;

    i = 0;
    switch (rank) {
      case 1:
      case 2:
      case 3:
	switch (type) {
	  case 1:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Young blue dragon"))
		    break;
		i++;
	    }
	    break;
	  case 2:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Young white dragon"))
		    break;
		i++;
	    }
	    break;
	  case 3:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Young green dragon"))
		    break;
		i++;
	    }
	    break;
	  case 4:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Young black dragon"))
		    break;
		i++;
	    }
	    break;
	  case 5:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Young red dragon"))
		    break;
		i++;
	    }
	    break;
	  case 6:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Young Multi-Hued Dragon"))
		    break;
		i++;
	    }
	    break;
	}
	break;
      case 4:
      case 5:
	switch (type) {
	  case 1:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Mature blue Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 2:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Mature white Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 3:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Mature green Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 4:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Mature black Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 5:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Mature red Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 6:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Mature Multi-Hued Dragon"))
		    break;
		i++;
	    }
	    break;
	}
	break;
      case 6:
	switch (type) {
	  case 1:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Ancient blue Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 2:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Ancient white Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 3:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Ancient green Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 4:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Ancient black Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 5:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Ancient red Dragon"))
		    break;
		i++;
	    }
	    break;
	  case 6:
	    while (i < MAX_CREATURES) {
		if (!stricmp(c_list[i].name, "Ancient Multi-Hued Dragon"))
		    break;
		i++;
	    }
	    break;
	}
	break;
    }
    if (i != MAX_CREATURES)
	place_monster(y, x, i, FALSE);
}

static void 
vault_demon(y, x, rank)
    int                 y, x, rank;
{
    register int        i;

    i = 0;
    switch (rank) {
      case 1:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Vrock"))
		break;
	    i++;
	}
	break;
      case 2:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Hezrou"))
		break;
	    i++;
	}
	break;
      case 3:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Glabrezu"))
		break;
	    i++;
	}
	break;
      case 4:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Nalfeshnee"))
		break;
	    i++;
	}
	break;
      case 5:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Marilith"))
		break;
	    i++;
	}
	break;
      case 6:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Lesser balrog"))
		break;
	    i++;
	}
	break;
    }
    if (i != MAX_CREATURES)
	place_monster(y, x, i, FALSE);
}


static void 
vault_giant(y, x, rank)
    int                 y, x, rank;
{
    register int        i;

    i = 0;
    switch (rank) {
      case 1:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Hill giant"))
		break;
	    i++;
	}
	break;
      case 2:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Frost giant"))
		break;
	    i++;
	}
	break;
      case 3:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Fire giant"))
		break;
	    i++;
	}
	break;
      case 4:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Stone giant"))
		break;
	    i++;
	}
	break;
      case 5:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Cloud giant"))
		break;
	    i++;
	}
	break;
      case 6:
	while (i < MAX_CREATURES) {
	    if (!stricmp(c_list[i].name, "Storm giant"))
		break;
	    i++;
	}
	break;
    }
    if (i != MAX_CREATURES)
	place_monster(y, x, i, FALSE);
}


/* Builds a room at a row, column coordinate		-RAK-	 */
static void 
build_room(yval, xval)
    int                 yval, xval;
{
    register int        i, j, y_depth, x_right;
    int                 y_height, x_left;
    int8u               floor;
    register cave_type *c_ptr, *d_ptr;

    if (dun_level <= randint(25))
	floor = LIGHT_FLOOR;	   /* Floor with light	 */
    else
	floor = DARK_FLOOR;	   /* Dark floor		 */

    y_height = yval - randint(4);
    y_depth = yval + randint(3);
    x_left = xval - randint(11);
    x_right = xval + randint(11);

/*
 * for paranoia's sake: bounds-check!  Memory errors caused by accessing
 * cave[][] out-of-bounds are nearly impossible to spot!  -CFT 
 */
    if (y_height < 1)
	y_height = 1;
    if (y_depth >= (cur_height - 1))
	y_depth = cur_height - 2;
    if (x_left < 1)
	x_left = 1;
    if (x_right >= (cur_width - 1))
	x_right = cur_width - 2;

/*
 * the x dim of rooms tends to be much larger than the y dim, so don't bother
 * rewriting the y loop 
 */
    for (i = y_height; i <= y_depth; i++) {
	c_ptr = &cave[i][x_left];
	for (j = x_left; j <= x_right; j++) {
	    c_ptr->fval = floor;
	    c_ptr->lr = TRUE;
	    c_ptr++;
	}
    }

    for (i = (y_height - 1); i <= (y_depth + 1); i++) {
	c_ptr = &cave[i][x_left - 1];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
	c_ptr = &cave[i][x_right + 1];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
    }

    c_ptr = &cave[y_height - 1][x_left];
    d_ptr = &cave[y_depth + 1][x_left];
    for (i = x_left; i <= x_right; i++) {
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
	c_ptr++;
	d_ptr->fval = GRANITE_WALL;
	d_ptr->lr = TRUE;
	d_ptr++;
    }

/* Every so often fill a normal room with pillars - Decado */

    if (randint(20) == 2) {
	for (i = y_height; i <= y_depth; i += 2) {
	    for (j = x_left; j <= x_right; j += 2) {
		c_ptr = &cave[i][j];
		c_ptr->fval = TMP1_WALL;
		c_ptr->lr = TRUE;
	    }
	}
    }
}

/* Builds a room at a row, column coordinate		-RAK-	 */
/* Type 1 unusual rooms are several overlapping rectangular ones	 */
static void 
build_type1(yval, xval)
    int                 yval, xval;
{
    int                 y_height, y_depth;
    int                 x_left, x_right, limit;
    register int        i0, i, j;
    int8u               floor;
    register cave_type *c_ptr, *d_ptr;

    if (dun_level <= randint(25))
	floor = LIGHT_FLOOR;	   /* Floor with light	 */
    else
	floor = DARK_FLOOR;	   /* Dark floor		 */
    limit = 1 + randint(2);
    for (i0 = 0; i0 < limit; i0++) {
	y_height = yval - randint(4);
	y_depth = yval + randint(3);
	x_left = xval - randint(11);
	x_right = xval + randint(11);

    /*
     * for paranoia's sake: bounds-check!  Memory errors caused by accessing
     * cave[][] out-of-bounds are nearly impossible to spot!  -CFT 
     */
	if (y_height < 1)
	    y_height = 1;
	if (y_depth >= (cur_height - 1))
	    y_depth = cur_height - 2;
	if (x_left < 1)
	    x_left = 1;
	if (x_right >= (cur_width - 1))
	    x_right = cur_width - 2;

    /*
     * the x dim of rooms tends to be much larger than the y dim, so don't
     * bother rewriting the y loop 
     */

	for (i = y_height; i <= y_depth; i++) {
	    c_ptr = &cave[i][x_left];
	    for (j = x_left; j <= x_right; j++) {
		c_ptr->fval = floor;
		c_ptr->lr = TRUE;
		c_ptr++;
	    }
	}
	for (i = (y_height - 1); i <= (y_depth + 1); i++) {
	    c_ptr = &cave[i][x_left - 1];
	    if (c_ptr->fval != floor) {
		c_ptr->fval = GRANITE_WALL;
		c_ptr->lr = TRUE;
	    }
	    c_ptr = &cave[i][x_right + 1];
	    if (c_ptr->fval != floor) {
		c_ptr->fval = GRANITE_WALL;
		c_ptr->lr = TRUE;
	    }
	}
	c_ptr = &cave[y_height - 1][x_left];
	d_ptr = &cave[y_depth + 1][x_left];
	for (i = x_left; i <= x_right; i++) {
	    if (c_ptr->fval != floor) {
		c_ptr->fval = GRANITE_WALL;
		c_ptr->lr = TRUE;
	    }
	    c_ptr++;
	    if (d_ptr->fval != floor) {
		d_ptr->fval = GRANITE_WALL;
		d_ptr->lr = TRUE;
	    }
	    d_ptr++;
	}
    }
}

/* Wish me LUCK! - Decado */

static void 
build_type5(yval, xval)
    int                 yval, xval;
{
    register int        x, y, x1, y1, vault;
    int                 width = 0, height = 0;
    char               *template = NULL;
    char               *t;	   /* use t to avoid changing template in
				    * loop.  This should fix some memory
				    * troubles, because now we aren't
				    * free()ing with a bad pointer.  Thanks
				    * much to
				    * gehring@pib1.physik.uni-bonn.edu for
				    * pointing this bug out... -CFT */
    char                buf[50];
    int8u               floor;
    int8u               wall;
    register cave_type *c_ptr;

    if (dun_level <= randint(25))
	floor = LIGHT_FLOOR;	   /* Floor with light	 */
    else
	floor = DARK_FLOOR;	   /* Dark floor		 */


    vault = 0;
    switch (randint(8)) {
      case 1:
	width = 20;
	height = 12;
	template = (char *)malloc((size_t) width * height + 1);
	rating += 5;
	sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s",
		"       %%%%%%       ",
		"    %%%..##..%%%    ",
		"  %%....####....%%  ",
		" %......#**#......% ",
		"%...,.##+##+##.,...%",
		"%.,.,.#*#*&#*#.,.,.%",
		"%.,.,.#*#&*#*#.,.,.%",
		"%...,.##+##+##.,...%",
		" %......#**#......% ",
		"  %%....####....%%  ",
		"    %%%..##..%%%    ",
		"       %%%%%%       ");
	break;
      case 2:
	width = 20;
	height = 14;
	template = (char *)malloc((size_t) width * height + 1);
	rating += 5;
	sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
		"   %%%%%%%%%%%%%%   ",
		"  %%.##########.%%  ",
		" %%..#..,,,,..#..%% ",
		"%%,..#.,####,.#..,%%",
		"%....#.,#**#,.#....%",
		"%.###+,##&&##,+###.%",
		"%.#..,,#*&**#,,..#.%",
		"%.#..,,#**&*#,,..#.%",
		"%.###+,##&&##,+###.%",
		"%....#.,#**#,.#....%",
		"%%,..#.,####,.#..,%%",
		" %%..#..,,,,..#..%% ",
		"  %%.##########.%%  ",
		"   %%%%%%%%%%%%%%   ");
	break;
      case 3:
	width = 20;
	height = 12;
	template = (char *)malloc((size_t) width * height + 1);
	rating += 5;
	sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s",
		"    %%%%%%%%%%%%    ",
		" %%%%..........%%%% ",
		" %...###+##+###...% ",
		"%%...#,,#,,#,,#...%%",
		"%.###+##+##+##+###.%",
		"%.#,,#&&#**#&&#,,#.%",
		"%.#,,#&&#**#&&#,,#.%",
		"%.###+##+##+##+###.%",
		"%%...#,,#,,#,,#...%%",
		" %...###+##+###...% ",
		" %%%%..........%%%% ",
		"    %%%%%%%%%%%%    ");
	break;
      case 4:
	width = 20;
	height = 12;
	template = (char *)malloc((size_t) width * height + 1);
	rating += 5;
	sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s",
		"%%%%%%%%%%%%%%%%%%%%",
		"%*.......&........*%",
		"%.################.%",
		"%.#,.,.,.,.,.,.,.#.%",
		"%.#.############,#.%",
		"%.#,+,&&+**#&*,#.#&%",
		"%&#.#,*&#**+&&,+,#.%",
		"%.#,############.#.%",
		"%.#.,.,.,.,.,.,.,#.%",
		"%.################.%",
		"%*........&.......*%",
		"%%%%%%%%%%%%%%%%%%%%");
	break;
      case 5:
	width = 20;
	height = 12;
	template = (char *)malloc((size_t) width * height + 1);
	rating += 5;
	sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s",
		"%%%%%%%%%%%%%%%%%   ",
		"%,,,##,,,,##....%%  ",
		"%,,,,##,,,,##....%% ",
		"%#,,,,##,,,,##....%%",
		"%##,,,,##,,,,##....%",
		"%.##,,,,,,,,,,#+...%",
		"%..#+,,,,,,,,,,##..%",
		"%...##,,,,##,,,,##.%",
		"%%...##,,,,##,,,,##%",
		" %%...##,,,,##,,,,#%",
		"  %%...##,,,,##,,,,%",
		"   %%%%%%%%%%%%%%%%%");
	break;
      case 6:
	width = 20;
	height = 12;
	template = (char *)malloc((size_t) width * height + 1);
	rating += 5;
	sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s",
		"   %%%%%%%%%%%%%%%%%",
		"  %%....##,,,,##,,,%",
		" %%....##,,,,##,,,,%",
		"%%....##,,,,##,,,,#%",
		"%....##,,,,##,,,,##%",
		"%...+#,,,,,,,,,,##.%",
		"%..##,,,,,,,,,,+#..%",
		"%.##,,,,##,,,,##...%",
		"%##,,,,##,,,,##...%%",
		"%#,,,,##,,,,##...%% ",
		"%,,,,##,,,,##...%%  ",
		"%%%%%%%%%%%%%%%%%   ");
	break;
      case 7:
	width = 20;
	height = 12;
	template = (char *)malloc((size_t) width * height + 1);
	rating += 5;
	sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s",
		"%%%%%%%%%%%%%%%%%%%%",
		"%,################,%",
		"%^#.*...&..,....,#^%",
		"%^#...,......&...#^%",
		"%^#######++#######^%",
		"%^+.,..&+,*+*....+^%",
		"%^+..*.,+.&+.,.&.+^%",
		"%^#######++#######^%",
		"%^#....,.,.....,.#^%",
		"%^#..&......*....#^%",
		"%,################,%",
		"%%%%%%%%%%%%%%%%%%%%");
	break;
      case 8:
	vault = TRUE;
	switch (randint(4)) {
	  case 4:
	    width = 40;
	    height = 18;
	    template = (char *)malloc((size_t) width * height + 1);
	    rating += 25;
	    sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
		    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%",
		    "%######################################%",
		    "%#*8..&##***++^^^^^^^^^^^^++***##&..*8#%",
		    "%#8..&##,,,,,##^^^^^^^^^^##,,,,,X#&..*#%",
		    "%#..&X#.....,.##^^^^^^^^##..&....##&..#%",
		    "%#.&##..,.&....##^^^^^^##..,...&..##&.#%",
		    "%#&##..*...&.^..##^^^^##..*....,..,##&#%",
		    "%####+#############++#############+####%",
		    "%+....,.,.#&&&&***+88+***&&&&#,.,.,...+%",
		    "%+...,.,.,#&&&&***+88+***&&&&#.,.,....+%",
		    "%####+#############++#############+####%",
		    "%#&##..*....&...##^^^^##...*...&,..X#&#%",
		    "%#.&##..&.^....##^^^^^^##....&....##&.#%",
		    "%#..&##....&..##^^^^^^^^##..,..*.##&..#%",
		    "%#*..&X#,,,,,##^^^^^^^^^^##,,,,,##&..8#%",
		    "%#8*..&##***++^^^^^^^^^^^^++***##&..*8#%",
		    "%######################################%",
		    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
	    break;
	  case 3:
	    width = 39;
	    height = 17;
	    template = (char *)malloc((size_t) width * height + 1);
	    rating += 35;
	    sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
		    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%",
		    "%#####################################%",
		    "%+&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XO#%",
		    "%###################################X#%",
		    "%#OX&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XOX&#%",
		    "%#X###################################%",
		    "%#&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XO#%",
		    "%###################################X#%",
		    "%#OX&XOX&XOX&XOOOOOOOOOOOXOX&XOX&XOX&#%",
		    "%#X###################################%",
		    "%#&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XO#%",
		    "%###################################X#%",
		    "%#OX&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XOX&#%",
		    "%#X###################################%",
		    "%#&XOX&XOX&XOX&XOX&XOX&XOX&XOX&XOX&X&+%",
		    "%#####################################%",
		    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
	    break;
	  case 2:
	    width = 40;
	    height = 18;
	    template = (char *)malloc((size_t) width * height + 1);
	    rating += 30;
	    sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
		    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%",
		    "%######################################%",
		    "%#,X,X,X,X,X,X,X,X*@@*X,X,X,X,X,X,X,X,#%",
		    "%#+################XX################+#%",
		    "%#.,..,.#&.&.,*##******##*,.&.&#.,...,X%",
		    "%#..,.^^#....,##***@@***##,....#^^..,.X%",
		    "%######+#^&.&##***@XX@***##&.&^#+######%",
		    "%#,.&.^^#+####***@X##X@***####+#^^.,..#%",
		    "%#..,&,.#^^^@#**@X#OO#X@**X@^^^#.,..&,#%",
		    "%#.,....#^^^@X**@X#OO#X@**#@^^^#.&.,..#%",
		    "%#...,^^#+####***@X##X@***####+#^^..,.#%",
		    "%######+#^&.&##***@XX@***##&.&^#+######%",
		    "%X.,..^^#.....##***@@***##,....#^^.,..#%",
		    "%X...,..#&.&.,*##******##*,.&.&#..,..,#%",
		    "%#+################XX################+#%",
		    "%#,X,X,X,X,X,X,X,X*@@*X,X,X,X,X,X,X,X,#%",
		    "%######################################%",
		    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
	    break;
	  case 1:
	    width = 40;
	    height = 15;
	    template = (char *)malloc((size_t)width * height + 1);
	    rating += 25;
	    sprintf(template, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
		    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%",
		    "%&+.^..^..^..^..^..^..^..^..^..^..^..+&%",
		    "%+####################################+%",
		    "%.#.&.^,#&^&^#****+^*^@^#.*.&..#..*.,#.%",
		    "%^#.,.&^+^&^@#^^^^#@^*^*#....*^+.^...#^%",
		    "%.#*..,.###+####+####+###.&.^..#..&,.#.%",
		    "%^#..^.*#*..^&&@@*#,,,,,####+###,....#^%",
		    "%.##+##############,*O*,#,,,,,,###+###.%",
		    "%^#*&#.&,*.#,*&^*^#,,,,,#,,,,,,#....,#^%",
		    "%.#&,+....*+,*&^*^##########+###.,...+.%",
		    "%^#.,#.*.&.#,*&^*^+.,.&.^*.&^&^#.....#^%",
		    "%.#^*#.,..,#,*&^*^#*.^*.,..&&&^#,..,.#.%",
		    "%+####################################+%",
		    "%&+..^..^..^..^..^..^..^..^..^..^..^.+&%",
		    "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
	    break;
	}
	break;
    }

/* check these rooms will fit on the map! */

    wall = TMP1_WALL;
    if (vault) {
	xval += 4;		   /* neat kludge deccy... */
	yval += 4;
	wall = BOUNDARY_WALL;
	if (floor == LIGHT_FLOOR)
	    floor = NT_LIGHT_FLOOR;
	else
	    floor = NT_DARK_FLOOR;
    }
/* DO NOT CHANGE yval or xval after this check... */
    if (!(in_bounds(yval - (height / 2), xval - (width / 2)) &&
	  in_bounds(yval + (height / 2), xval + (width / 2)))) {
	free(template);
	build_type2(yval, xval);
	return;
    }

    good_item_flag = TRUE;	/* this is more like it.... -CWS */

    t = template;		/* this avoids memory troubles... see above -CFT */
    for (y = 0; y < height; y++) {
	for (x = 0; x < width; x++) {
	    x1 = xval - (width / 2) + x;
	    y1 = yval - (height / 2) + y;
	    c_ptr = &cave[y1][x1];
	    switch (*t++) {
	      case '#':	   /* lit up wall */
		c_ptr->fval = wall;
		c_ptr->lr = TRUE;
		break;
	      case 'X':
		c_ptr->fval = TMP1_WALL;
		c_ptr->lr = TRUE;
		break;
	      case '%':	   /* lit up wall */
		c_ptr->fval = GRANITE_WALL;	/* Not temp, since this may
						 * have doors in */
		c_ptr->lr = TRUE;
		break;
	      case '.':	   /* lit up/ not lit up floor */
		c_ptr->fval = floor;
		c_ptr->lr = TRUE;
		break;
	      case '*':	   /* treasure/trap */
		c_ptr->fval = floor;
		if (randint(20) > 7) {
		    object_level = dun_level;
		    place_object(y1, x1);
		}
		else if (randint(10) > 2)
		    place_trap(y1, x1, randint(MAX_TRAP) - 1);
		else if (randint(2) == 1 && !vault)
		    place_down_stairs(y1, x1);
		else if (!vault)
		    place_up_stairs(y1, x1);
		c_ptr->lr = TRUE;
		break;
	      case '+':	   /* secret doors */
		place_secret_door(y1, x1);
		c_ptr->lr = TRUE;
		break;
	      case '&':	   /* Monster */
		c_ptr->fval = floor;
		place_monster(y1, x1,
		get_mons_num(dun_level + MON_SUMMON_ADJ + 2 + vault), TRUE);
		c_ptr->lr = TRUE;
		break;
	      case '@':	   /* Meaner monster */
		c_ptr->fval = floor;
		place_monster(y1, x1,
			      get_nmons_num(dun_level + MON_SUMMON_ADJ + 7),
			      TRUE);
		c_ptr->lr = TRUE;
		break;
	      case '8':	   /* Meaner monster */
		c_ptr->fval = floor;
		place_monster(y1, x1,
			      get_nmons_num(dun_level + MON_SUMMON_ADJ + 7),
			      TRUE);
		place_special(y1, x1, 1);
		c_ptr->lr = TRUE;
		break;
	      case 'O':	   /* Nasty monster and treasure */
		c_ptr->fval = floor;
		place_monster(y1, x1,
			      get_nmons_num(dun_level + MON_SUMMON_ADJ + 40),
			      TRUE);
		place_special(y1, x1, 666);
		c_ptr->lr = TRUE;
		break;
	      case ',':	   /* Monster/object */
		c_ptr->fval = floor;
		if (randint(2) == 1)
		    place_monster(y1, x1,
		    get_mons_num(dun_level + MON_SUMMON_ADJ + vault), TRUE);
		if (randint(2) == 1) {
		    object_level = dun_level;
		    place_object(y1, x1);
		}
		c_ptr->lr = TRUE;
		break;
	      case '^':
		c_ptr->fval = floor;
		place_trap(y1, x1, randint(MAX_TRAP) - 1);
		c_ptr->lr = TRUE;
		break;
	      case ' ':
		break;
	      default:
		sprintf(buf, "Cockup='%c'", *t);
		msg_print(buf);
		break;
	    }
	}
    }
    free(template);
}

/* Builds an unusual room at a row, column coordinate	-RAK-	 */
/* Type 2 unusual rooms all have an inner room:			 */
/* 1 - Just an inner room with one door			 */
/* 2 - An inner room within an inner room			 */
/* 3 - An inner room with pillar(s)				 */
/* 4 - Inner room has a maze					 */
/* 5 - A set of four inner rooms				 */
static void 
build_type2(yval, xval)
    int                 yval, xval;
{
    register int        i, j, y_height, x_left;
    int                 y_depth, x_right, tmp;
    int8u               floor;
    register cave_type *c_ptr, *d_ptr;

    if (dun_level <= randint(25))
	floor = LIGHT_FLOOR;	   /* Floor with light	 */
    else
	floor = DARK_FLOOR;	   /* Dark floor		 */
    y_height = yval - 4;
    y_depth = yval + 4;
    x_left = xval - 11;
    x_right = xval + 11;

/*
 * paranoia bounds-check...   if the room can't fit in the cave, punt out and
 * build a simpler room type (type1 is already bounds-checked) This should
 * help solve MORE memory troubles! -CFT 
 */
    if (!in_bounds(y_height, x_left) || !in_bounds(y_depth, x_right)) {
	build_type1(yval, xval);
	return;
    }
/*
 * the x dim of rooms tends to be much larger than the y dim, so don't bother
 * rewriting the y loop 
 */

    for (i = y_height; i <= y_depth; i++) {
	c_ptr = &cave[i][x_left];
	for (j = x_left; j <= x_right; j++) {
	    c_ptr->fval = floor;
	    c_ptr->lr = TRUE;
	    c_ptr++;
	}
    }
    for (i = (y_height - 1); i <= (y_depth + 1); i++) {
	c_ptr = &cave[i][x_left - 1];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
	c_ptr = &cave[i][x_right + 1];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
    }
    c_ptr = &cave[y_height - 1][x_left];
    d_ptr = &cave[y_depth + 1][x_left];
    for (i = x_left; i <= x_right; i++) {
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
	c_ptr++;
	d_ptr->fval = GRANITE_WALL;
	d_ptr->lr = TRUE;
	d_ptr++;
    }
/* The inner room		 */
    y_height = y_height + 2;
    y_depth = y_depth - 2;
    x_left = x_left + 2;
    x_right = x_right - 2;
    for (i = (y_height - 1); i <= (y_depth + 1); i++) {
	cave[i][x_left - 1].fval = TMP1_WALL;
	cave[i][x_right + 1].fval = TMP1_WALL;
    }
    c_ptr = &cave[y_height - 1][x_left];
    d_ptr = &cave[y_depth + 1][x_left];
    for (i = x_left; i <= x_right; i++) {
	c_ptr->fval = TMP1_WALL;
	c_ptr++;
	d_ptr->fval = TMP1_WALL;
	d_ptr++;
    }
/* Inner room variations		 */
    switch (randint(5)) {
      case 1:			   /* Just an inner room.	 */
	tmp = randint(4);
	if (tmp < 3) {		   /* Place a door	 */
	    if (tmp == 1)
		place_secret_door(y_height - 1, xval);
	    else
		place_secret_door(y_depth + 1, xval);
	} else {
	    if (tmp == 3)
		place_secret_door(yval, x_left - 1);
	    else
		place_secret_door(yval, x_right + 1);
	}
	vault_monster(yval, xval, 1);
	break;

      case 2:			   /* Treasure Vault	 */
	tmp = randint(4);
	if (tmp < 3) {		   /* Place a door	 */
	    if (tmp == 1)
		place_secret_door(y_height - 1, xval);
	    else
		place_secret_door(y_depth + 1, xval);
	} else {
	    if (tmp == 3)
		place_secret_door(yval, x_left - 1);
	    else
		place_secret_door(yval, x_right + 1);
	}

	for (i = yval - 1; i <= yval + 1; i++) {
	    cave[i][xval - 1].fval = TMP1_WALL;
	    cave[i][xval + 1].fval = TMP1_WALL;
	}
	cave[yval - 1][xval].fval = TMP1_WALL;
	cave[yval + 1][xval].fval = TMP1_WALL;

	tmp = randint(4);	   /* Place a door	 */
	if (tmp < 3)
	    place_locked_door(yval - 3 + (tmp << 1), xval);	/* 1 -> yval-1; 2 ->
								 * yval+1 */
	else
	    place_locked_door(yval, xval - 7 + (tmp << 1));

    /* Place an object in the treasure vault	 */
	tmp = randint(10);
	if (tmp > 2) {
	    object_level = dun_level;
	    place_object(yval, xval);
	}
	else if (tmp == 2)
	    place_down_stairs(yval, xval);
	else
	    place_up_stairs(yval, xval);

    /* Guard the treasure well		 */
	vault_monster(yval, xval, 2 + randint(3));
    /* If the monsters don't get 'em.	 */
	vault_trap(yval, xval, 4, 10, 2 + randint(3));
	break;

      case 3:			   /* Inner pillar(s).	 */
	tmp = randint(4);
	if (tmp < 3) {		   /* Place a door	 */
	    if (tmp == 1)
		place_secret_door(y_height - 1, xval);
	    else
		place_secret_door(y_depth + 1, xval);
	} else {
	    if (tmp == 3)
		place_secret_door(yval, x_left - 1);
	    else
		place_secret_door(yval, x_right + 1);
	}

	for (i = yval - 1; i <= yval + 1; i++) {
	    c_ptr = &cave[i][xval - 1];
	    for (j = xval - 1; j <= xval + 1; j++) {
		c_ptr->fval = TMP1_WALL;
		c_ptr++;
	    }
	}
	if (randint(2) == 1) {
	    tmp = randint(2);
	    for (i = yval - 1; i <= yval + 1; i++) {
		c_ptr = &cave[i][xval - 5 - tmp];
		for (j = xval - 5 - tmp; j <= xval - 3 - tmp; j++) {
		    c_ptr->fval = TMP1_WALL;
		    c_ptr++;
		}
	    }
	    for (i = yval - 1; i <= yval + 1; i++) {
		c_ptr = &cave[i][xval + 3 + tmp];
		for (j = xval + 3 + tmp; j <= xval + 5 + tmp; j++) {
		    c_ptr->fval = TMP1_WALL;
		    c_ptr++;
		}
	    }
	}
	if (randint(3) == 1) {	   /* Inner rooms	 */
	    c_ptr = &cave[yval - 1][xval - 5];
	    d_ptr = &cave[yval + 1][xval - 5];
	    for (i = xval - 5; i <= xval + 5; i++) {
		c_ptr->fval = TMP1_WALL;
		c_ptr++;
		d_ptr->fval = TMP1_WALL;
		d_ptr++;
	    }
	    cave[yval][xval - 5].fval = TMP1_WALL;
	    cave[yval][xval + 5].fval = TMP1_WALL;
	    place_secret_door(yval - 3 + (randint(2) << 1), xval - 3);
	    place_secret_door(yval - 3 + (randint(2) << 1), xval + 3);
	    object_level = dun_level;
	    if (randint(3) == 1)
		place_object(yval, xval - 2);
	    if (randint(3) == 1)
		place_object(yval, xval + 2);
	    vault_monster(yval, xval - 2, randint(2));
	    vault_monster(yval, xval + 2, randint(2));
	}
	break;

      case 4:			   /* Maze inside.	 */
	tmp = randint(4);
	if (tmp < 3) {		   /* Place a door	 */
	    if (tmp == 1)
		place_secret_door(y_height - 1, xval);
	    else
		place_secret_door(y_depth + 1, xval);
	} else {
	    if (tmp == 3)
		place_secret_door(yval, x_left - 1);
	    else
		place_secret_door(yval, x_right + 1);
	}

	for (i = y_height; i <= y_depth; i++)
	    for (j = x_left; j <= x_right; j++)
		if (0x1 & (j + i))
		    cave[i][j].fval = TMP1_WALL;

    /* Monsters just love mazes.		 */
	vault_monster(yval, xval - 5, randint(3));
	vault_monster(yval, xval + 5, randint(3));
    /* Traps make them entertaining.	 */
	vault_trap(yval, xval - 3, 2, 8, randint(3));
	vault_trap(yval, xval + 3, 2, 8, randint(3));
    /* Mazes should have some treasure too..	 */
	for (i = 0; i < 3; i++)
	    random_object(yval, xval, 1);
	break;

      case 5:			   /* Four small rooms.	 */
	for (i = y_height; i <= y_depth; i++)
	    cave[i][xval].fval = TMP1_WALL;

	c_ptr = &cave[yval][x_left];
	for (i = x_left; i <= x_right; i++) {
	    c_ptr->fval = TMP1_WALL;
	    c_ptr++;
	}

	if (randint(2) == 1) {
	    i = randint(10);
	    place_secret_door(y_height - 1, xval - i);
	    place_secret_door(y_height - 1, xval + i);
	    place_secret_door(y_depth + 1, xval - i);
	    place_secret_door(y_depth + 1, xval + i);
	} else {
	    i = randint(3);
	    place_secret_door(yval + i, x_left - 1);
	    place_secret_door(yval - i, x_left - 1);
	    place_secret_door(yval + i, x_right + 1);
	    place_secret_door(yval - i, x_right + 1);
	}

    /* Treasure in each one.		 */
	random_object(yval, xval, 2 + randint(2));
    /* Gotta have some monsters.		 */
	vault_monster(yval + 2, xval - 4, randint(2));
	vault_monster(yval + 2, xval + 4, randint(2));
	vault_monster(yval - 2, xval - 4, randint(2));
	vault_monster(yval - 2, xval + 4, randint(2));
	break;
    }
}

/* Builds a room at a row, column coordinate		-RAK-	 */
/* Type 3 unusual rooms are cross shaped			 */
static void 
build_type3(yval, xval)
    int                 yval, xval;
{
    int                 y_height, y_depth;
    int                 x_left, x_right;
    register int        tmp, i, j;
    int8u               floor;
    register cave_type *c_ptr;

/*
 * quick, basic bounds-check... If too close, then this is better suited to a
 * simpler room type. -CFT 
 */
    if (!in_bounds(yval - 3, xval - 3) || !in_bounds(yval + 3, xval + 3)) {
	build_type1(yval, xval);
	return;
    }
    if (dun_level <= randint(25))
	floor = LIGHT_FLOOR;	   /* Floor with light	 */
    else
	floor = DARK_FLOOR;	   /* Dark floor	 */
    tmp = 2 + randint(2);
    y_height = yval - tmp;
    y_depth = yval + tmp;
    x_left = xval - 1;
    x_right = xval + 1;
/*
 * for paranoia's sake: bounds-check!  Memory errors caused by accessing
 * cave[][] out-of-bounds are nearly impossible to spot!  -CFT 
 */
    if (y_height < 1)
	y_height = 1;
    if (y_depth >= (cur_height - 1))
	y_depth = cur_height - 2;
    for (i = y_height; i <= y_depth; i++)
	for (j = x_left; j <= x_right; j++) {
	    c_ptr = &cave[i][j];
	    c_ptr->fval = floor;
	    c_ptr->lr = TRUE;
	}
    for (i = (y_height - 1); i <= (y_depth + 1); i++) {
	c_ptr = &cave[i][x_left - 1];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
	c_ptr = &cave[i][x_right + 1];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
    }
    for (i = x_left; i <= x_right; i++) {
	c_ptr = &cave[y_height - 1][i];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
	c_ptr = &cave[y_depth + 1][i];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
    }
    tmp = 2 + randint(9);
    y_height = yval - 1;
    y_depth = yval + 1;
    x_left = xval - tmp;
    x_right = xval + tmp;
/*
 * for paranoia's sake: bounds-check!  Memory errors caused by accessing
 * cave[][] out-of-bounds are nearly impossible to spot!  -CFT 
 */

    if (x_left < 1)
	x_left = 1;
    if (x_right >= (cur_width - 1))
	x_right = cur_width - 2;

    for (i = y_height; i <= y_depth; i++)
	for (j = x_left; j <= x_right; j++) {
	    c_ptr = &cave[i][j];
	    c_ptr->fval = floor;
	    c_ptr->lr = TRUE;
	}
    for (i = (y_height - 1); i <= (y_depth + 1); i++) {
	c_ptr = &cave[i][x_left - 1];
	if (c_ptr->fval != floor) {
	    c_ptr->fval = GRANITE_WALL;
	    c_ptr->lr = TRUE;
	}
	c_ptr = &cave[i][x_right + 1];
	if (c_ptr->fval != floor) {
	    c_ptr->fval = GRANITE_WALL;
	    c_ptr->lr = TRUE;
	}
    }
    for (i = x_left; i <= x_right; i++) {
	c_ptr = &cave[y_height - 1][i];
	if (c_ptr->fval != floor) {
	    c_ptr->fval = GRANITE_WALL;
	    c_ptr->lr = TRUE;
	}
	c_ptr = &cave[y_depth + 1][i];
	if (c_ptr->fval != floor) {
	    c_ptr->fval = GRANITE_WALL;
	    c_ptr->lr = TRUE;
	}
    }
/* Special features.			 */
    switch (randint(4)) {
      case 1:			   /* Large middle pillar		 */
	for (i = yval - 1; i <= yval + 1; i++) {
	    c_ptr = &cave[i][xval - 1];
	    for (j = xval - 1; j <= xval + 1; j++) {
		c_ptr->fval = TMP1_WALL;
		c_ptr++;
	    }
	}
	break;

      case 2:			   /* Inner treasure vault		 */
	for (i = yval - 1; i <= yval + 1; i++) {
	    cave[i][xval - 1].fval = TMP1_WALL;
	    cave[i][xval + 1].fval = TMP1_WALL;
	}
	cave[yval - 1][xval].fval = TMP1_WALL;
	cave[yval + 1][xval].fval = TMP1_WALL;

	tmp = randint(4);	   /* Place a door	 */
	if (tmp < 3)
	    place_secret_door(yval - 3 + (tmp << 1), xval);
	else
	    place_secret_door(yval, xval - 7 + (tmp << 1));

    /* Place a treasure in the vault		 */
	object_level = dun_level;
	place_object(yval, xval);
    /* Let's guard the treasure well.	 */
	vault_monster(yval, xval, 2 + randint(2));
    /* Traps naturally			 */
	vault_trap(yval, xval, 4, 4, 1 + randint(3));
	break;

      case 3:
	if (randint(3) == 1) {
	    cave[yval - 1][xval - 2].fval = TMP1_WALL;
	    cave[yval + 1][xval - 2].fval = TMP1_WALL;
	    cave[yval - 1][xval + 2].fval = TMP1_WALL;
	    cave[yval + 1][xval + 2].fval = TMP1_WALL;
	    cave[yval - 2][xval - 1].fval = TMP1_WALL;
	    cave[yval - 2][xval + 1].fval = TMP1_WALL;
	    cave[yval + 2][xval - 1].fval = TMP1_WALL;
	    cave[yval + 2][xval + 1].fval = TMP1_WALL;
	    if (randint(3) == 1) {
		place_secret_door(yval, xval - 2);
		place_secret_door(yval, xval + 2);
		place_secret_door(yval - 2, xval);
		place_secret_door(yval + 2, xval);
	    }
	} else if (randint(3) == 1) {
	    cave[yval][xval].fval = TMP1_WALL;
	    cave[yval - 1][xval].fval = TMP1_WALL;
	    cave[yval + 1][xval].fval = TMP1_WALL;
	    cave[yval][xval - 1].fval = TMP1_WALL;
	    cave[yval][xval + 1].fval = TMP1_WALL;
	} else if (randint(3) == 1)
	    cave[yval][xval].fval = TMP1_WALL;
	break;

      case 4:
	break;
    }
}

static void 
vault_nasty(j, i, type, rank, colour)
    int                 j, i, type, rank, colour;
{
    switch (type) {
      case 1:
	vault_jelly(j, i);
	break;
      case 2:
	vault_orc(j, i, rank);
	break;
      case 3:
	vault_troll(j, i, rank);
	break;
      case 4:
	vault_undead(j, i);
	break;
      case 5:
	vault_dragon(j, i, rank, colour);
	break;
      case 6:
	vault_demon(j, i, rank);
	break;
      case 7:
	vault_giant(j, i, rank);
	break;
    }
}

static void 
special_pit(yval, xval, type)
    int                 yval, xval, type;
{
    register int        i, j, y_height, x_left;
    int                 y_depth, x_right, colour;
    int8u               floor;
    register cave_type *c_ptr, *d_ptr;

    floor = DARK_FLOOR;
    y_height = yval - 4;
    y_depth = yval + 4;
    x_left = xval - 11;
    x_right = xval + 11;

/*
 * for paranoia's sake: bounds-check!  Memory errors caused by accessing
 * cave[][] out-of-bounds are nearly impossible to spot!  -CFT 
 */
    if (y_height < 1)
	y_height = 1;
    if (y_depth >= (cur_height - 1))
	y_depth = cur_height - 2;
    if (x_left < 1)
	x_left = 1;
    if (x_right >= (cur_width - 1))
	x_right = cur_width - 2;

/*
 * the x dim of rooms tends to be much larger than the y dim, so don't bother
 * rewriting the y loop 
 */

    for (i = y_height; i <= y_depth; i++) {
	c_ptr = &cave[i][x_left];
	for (j = x_left; j <= x_right; j++) {
	    c_ptr->fval = floor;
	    c_ptr->lr = TRUE;
	    c_ptr++;
	}
    }
    for (i = (y_height - 1); i <= (y_depth + 1); i++) {
	c_ptr = &cave[i][x_left - 1];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
	c_ptr = &cave[i][x_right + 1];
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
    }
    c_ptr = &cave[y_height - 1][x_left];
    d_ptr = &cave[y_depth + 1][x_left];
    for (i = x_left; i <= x_right; i++) {
	c_ptr->fval = GRANITE_WALL;
	c_ptr->lr = TRUE;
	c_ptr++;
	d_ptr->fval = GRANITE_WALL;
	d_ptr->lr = TRUE;
	d_ptr++;
    }
/* The inner room		 */
    y_height = y_height + 2;
    y_depth = y_depth - 2;
    x_left = x_left + 2;
    x_right = x_right - 2;
    for (i = (y_height - 1); i <= (y_depth + 1); i++) {
	cave[i][x_left - 1].fval = TMP1_WALL;
	cave[i][x_right + 1].fval = TMP1_WALL;
    }
    c_ptr = &cave[y_height - 1][x_left];
    d_ptr = &cave[y_depth + 1][x_left];
    for (i = x_left; i <= x_right; i++) {
	c_ptr->fval = TMP1_WALL;
	c_ptr++;
	d_ptr->fval = TMP1_WALL;
	d_ptr++;
    }
    switch (randint(4)) {
      case 1:
	place_secret_door(y_height - 1, xval);
	break;
      case 2:
	place_secret_door(y_depth + 1, xval);
	break;
      case 3:
	place_secret_door(yval, x_left - 1);
	break;
      case 4:
	place_secret_door(yval, x_right + 1);
	break;
    }
    colour = randint(6);
    if (wizard || peek) {
	switch (type) {
	  case 1:
	    msg_print("A Slime Pit");
	    break;
	  case 2:
	    msg_print("An Orc Pit");
	    break;
	  case 3:
	    msg_print("A Troll Pit");
	    break;
	  case 4:
	    msg_print("A Graveyard");
	    break;
	  case 5:
	    switch (colour) {
	      case 1:
		msg_print("A Blue Dragon Pit");
		break;
	      case 2:
		msg_print("A White Dragon Pit");
		break;
	      case 3:
		msg_print("A Green Dragon Pit");
		break;
	      case 4:
		msg_print("A Black Dragon Pit");
		break;
	      case 5:
		msg_print("A Red Dragon Pit");
		break;
	      case 6:
		msg_print("A Multi-Hued Dragon Pit");
		break;
	    }
	    break;
	  case 6:
	    msg_print("A Demon Pit");
	    break;
	  case 7:
	    msg_print("A Giant Pit");
	    break;
	}
    }
    j = y_height;
    for (i = x_left; i <= x_right; i++)
	vault_nasty(j, i, type, 1, colour);
    j = y_depth;
    for (i = x_left; i <= x_right; i++)
	vault_nasty(j, i, type, 1, colour);
    i = x_left;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 1, colour);
    i = x_right;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 1, colour);
    i = x_left + 1;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 2, colour);
    i = x_left + 2;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 2, colour);
    i = x_right - 1;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 2, colour);
    i = x_right - 2;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 2, colour);
    i = x_left + 3;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 3, colour);
    i = x_left + 4;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 3, colour);
    i = x_right - 3;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 3, colour);
    i = x_right - 4;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 3, colour);
    i = x_left + 5;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 4, colour);
    i = x_left + 6;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 4, colour);
    i = x_right - 5;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 4, colour);
    i = x_right - 6;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 4, colour);
    i = x_left + 7;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 5, colour);
    i = x_left + 8;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 5, colour);
    i = x_right - 7;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 5, colour);
    i = x_right - 8;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 5, colour);
    i = x_right - 9;
    for (j = (y_height + 1); j <= (y_depth - 1); j++)
	vault_nasty(j, i, type, 6, colour);
}

/* Constructs a tunnel between two points		 */
static void 
build_tunnel(row1, col1, row2, col2)
    int                 row1, col1, row2, col2;
{
    register int        tmp_row, tmp_col, i, j;
    register cave_type *c_ptr;
    cave_type          *d_ptr;
    coords              tunstk[1000], wallstk[1000];
    coords             *tun_ptr;
    int                 row_dir, col_dir, tunindex, wallindex;
    int                 stop_flag, door_flag, main_loop_count;
    int                 start_row, start_col;

/* Main procedure for Tunnel			 */
/* Note: 9 is a temporary value		 */
    stop_flag = FALSE;
    door_flag = FALSE;
    tunindex = 0;
    wallindex = 0;
    main_loop_count = 0;
    start_row = row1;
    start_col = col1;
    correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);

    do {
    /* prevent infinite loops, just in case */
	main_loop_count++;
	if (main_loop_count > 2000)
	    stop_flag = TRUE;

	if (randint(100) > DUN_TUN_CHG) {
	    if (randint(DUN_TUN_RND) == 1)
		rand_dir(&row_dir, &col_dir);
	    else
		correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
	}
	tmp_row = row1 + row_dir;
	tmp_col = col1 + col_dir;
	while (!in_bounds(tmp_row, tmp_col)) {
	    if (randint(DUN_TUN_RND) == 1)
		rand_dir(&row_dir, &col_dir);
	    else
		correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
	    tmp_row = row1 + row_dir;
	    tmp_col = col1 + col_dir;
	}
	c_ptr = &cave[tmp_row][tmp_col];
	if (c_ptr->fval == NULL_WALL) {
	    row1 = tmp_row;
	    col1 = tmp_col;
	    if (tunindex < 1000) {
		tunstk[tunindex].y = row1;
		tunstk[tunindex].x = col1;
		tunindex++;
	    }
	    door_flag = FALSE;
	} else if (c_ptr->fval == TMP2_WALL)
	/* do nothing */
	    ;
	else if (c_ptr->fval == GRANITE_WALL) {
	    d_ptr = &cave[tmp_row + row_dir][tmp_col + col_dir];
	    if ((d_ptr->fval == GRANITE_WALL) || (d_ptr->fval == TMP2_WALL))
		c_ptr->fval = TMP2_WALL;
	/*
	 * if can not pass completely through wall don't try... And mark as
	 * impassible for future -KOC 
	 */
	    else {
		row1 = tmp_row;
		col1 = tmp_col;
		if (wallindex < 1000) {
		    wallstk[wallindex].y = row1;
		    wallstk[wallindex].x = col1;
		    wallindex++;
		}
		for (i = row1 - 1; i <= row1 + 1; i++)
		    for (j = col1 - 1; j <= col1 + 1; j++)
			if (in_bounds(i, j)) {
			    d_ptr = &cave[i][j];
			/*
			 * values 11 and 12 are impossible here,
			 * place_streamer is never run before build_tunnel 
			 */
			    if (d_ptr->fval == GRANITE_WALL)
				d_ptr->fval = TMP2_WALL;
			}
	    }
	} else if (c_ptr->fval == CORR_FLOOR || c_ptr->fval == BLOCKED_FLOOR) {
	    row1 = tmp_row;
	    col1 = tmp_col;
	    if (!door_flag) {
		if (doorindex < 100) {
		    doorstk[doorindex].y = row1;
		    doorstk[doorindex].x = col1;
		    doorindex++;
		}
		door_flag = TRUE;
	    }
	    if (randint(100) > DUN_TUN_CON) {
	    /*
	     * make sure that tunnel has gone a reasonable distance before
	     * stopping it, this helps prevent isolated rooms 
	     */
		tmp_row = row1 - start_row;
		if (tmp_row < 0)
		    tmp_row = (-tmp_row);
		tmp_col = col1 - start_col;
		if (tmp_col < 0)
		    tmp_col = (-tmp_col);
		if (tmp_row > 10 || tmp_col > 10)
		    stop_flag = TRUE;
	    }
	} else {		   /* c_ptr->fval != NULL, TMP2, GRANITE,
				    * CORR */
	    row1 = tmp_row;
	    col1 = tmp_col;
	}
    }
    while (((row1 != row2) || (col1 != col2)) && (!stop_flag));

    tun_ptr = &tunstk[0];
    for (i = 0; i < tunindex; i++) {
	d_ptr = &cave[tun_ptr->y][tun_ptr->x];
	d_ptr->fval = CORR_FLOOR;
	tun_ptr++;
    }
    for (i = 0; i < wallindex; i++) {
	c_ptr = &cave[wallstk[i].y][wallstk[i].x];
	if (c_ptr->fval == TMP2_WALL) {
	    if (randint(100) < DUN_TUN_PEN)
		place_door(wallstk[i].y, wallstk[i].x);
	    else {
	    /* these have to be doorways to rooms */
		c_ptr->fval = CORR_FLOOR;
	    }
	}
    }
}


static int 
next_to(y, x)
    register int        y, x;
{
    register int        next;

    if (!in_bounds(y, x))
	return 0;		   /* abort! -CFT */
    if (next_to_corr(y, x) > 2)
	if ((cave[y - 1][x].fval >= MIN_CAVE_WALL)
	    && (cave[y + 1][x].fval >= MIN_CAVE_WALL))
	    next = TRUE;
	else if ((cave[y][x - 1].fval >= MIN_CAVE_WALL)
		 && (cave[y][x + 1].fval >= MIN_CAVE_WALL))
	    next = TRUE;
	else
	    next = FALSE;
    else
	next = FALSE;
    return (next);
}

/* Places door at y, x position if at least 2 walls found	 */
static void 
try_door(y, x)
    register int        y, x;
{
    if (!in_bounds(y, x))
	return;			   /* abort! -CFT */
    if ((cave[y][x].fval == CORR_FLOOR) && (randint(100) > DUN_TUN_JCT)
	&& next_to(y, x))
	place_door(y, x);
}


/* Returns random co-ordinates				-RAK-	 */
static void 
new_spot(y, x)
    int16              *y, *x;
{
    register int        i, j;
    register cave_type *c_ptr;

    do {
	i = randint(cur_height - 2);
	j = randint(cur_width - 2);
	c_ptr = &cave[i][j];
    }
    while (c_ptr->fval >= MIN_CLOSED_SPACE || (c_ptr->cptr != 0)
	   || (c_ptr->tptr != 0) || (c_ptr->fval == NT_LIGHT_FLOOR)
	   || (c_ptr->fval == NT_DARK_FLOOR));
    *y = i;
    *x = j;
}

static void 
build_pit(yval, xval)
    int                 yval, xval;
{
    int                 tmp;

/*    if (randint((dun_level * dun_level * dun_level) + 1) < 25000)
	good_item_flag = TRUE;                      pits aren't very special.... */
    tmp = randint(dun_level > 80 ? 80 : dun_level);
    rating += 10;
    if (tmp < 10)
	special_pit(yval, xval, 1);
    else if (tmp < 20)
	special_pit(yval, xval, 2);
    else if (tmp < 43)
	((randint(3) == 1)
	 ? special_pit(yval, xval, 7)
	 : special_pit(yval, xval, 3));
    else if (tmp < 57)
	special_pit(yval, xval, 4);
    else if (tmp < 73)
	special_pit(yval, xval, 5);
    else
	special_pit(yval, xval, 6);
}

/* Cave logic flow for generation of new dungeon		 */
static void 
cave_gen()
{
    struct spot_type {
	int                 endx;
	int                 endy;
    };
    int                 room_map[20][20];
    register int        i, j, k;
    int                 y1, x1, y2, x2, pick1, pick2, tmp;
    int                 row_rooms, col_rooms, alloc_level;
    int16               yloc[400], xloc[400];
    int                 pit_ok, spec_level;

    rating = 0;
    spec_level = 0;
    pit_ok = FALSE;
    if ((randint(DUN_DEST) == 1) && (dun_level > 10) && (!is_quest(dun_level))) {
	if (wizard)
	    msg_print("Destroyed Level");
	spec_level = SPEC_DEST;
    } else
	pit_ok = TRUE;

    row_rooms = 2 * (cur_height / SCREEN_HEIGHT);
    col_rooms = 2 * (cur_width / SCREEN_WIDTH);
    for (i = 0; i < row_rooms; i++)
	for (j = 0; j < col_rooms; j++)
	    room_map[i][j] = FALSE;
    k = randnor(DUN_ROO_MEA, 2);
    for (i = 0; i < k; i++)
	room_map[randint(row_rooms) - 1][randint(col_rooms) - 1] = TRUE;
    k = 0;
    for (i = 0; i < row_rooms; i++)
	for (j = 0; j < col_rooms; j++)
	    if (room_map[i][j] == TRUE) {
		yloc[k] = i * (SCREEN_HEIGHT >> 1) + QUART_HEIGHT;
		xloc[k] = j * (SCREEN_WIDTH >> 1) + QUART_WIDTH;
		if (dun_level > randint(DUN_UNUSUAL)) {
		    tmp = randint(5);
		    if ((tmp == 1) || (spec_level))
			build_type1(yloc[k], xloc[k]);
		    else if (tmp == 2)
			build_type2(yloc[k], xloc[k]);
		    else if (tmp == 3)
			build_type3(yloc[k], xloc[k]);
		    else if ((tmp == 4) && dun_level > randint(DUN_UNUSUAL)) {
			build_type5(yloc[k], xloc[k]);
			if (j + 1 < col_rooms)
			    room_map[i][j + 1] = FALSE;
			if (j + 1 < col_rooms && i + 1 < row_rooms)
			    room_map[i + 1][j + 1] = FALSE;
			if (j > 0 && i + 1 < row_rooms)
			    room_map[i + 1][j - 1] = FALSE;
			if (i + 1 < row_rooms)
			    room_map[i + 1][j] = FALSE;
		    } else if (dun_level > randint(DUN_UNUSUAL) && pit_ok) {
			build_pit(yloc[k], xloc[k]);
			pit_ok = FALSE;
		    } else {
			build_room(yloc[k], xloc[k]);
		    }
		} else
		    build_room(yloc[k], xloc[k]);
		k++;
	    }
    for (i = 0; i < k; i++) {
	pick1 = randint(k) - 1;
	pick2 = randint(k) - 1;
	y1 = yloc[pick1];
	x1 = xloc[pick1];
	yloc[pick1] = yloc[pick2];
	xloc[pick1] = xloc[pick2];
	yloc[pick2] = y1;
	xloc[pick2] = x1;
    }
    doorindex = 0;
/* move zero entry to k, so that can call build_tunnel all k times */
    yloc[k] = yloc[0];
    xloc[k] = xloc[0];
    for (i = 0; i < k; i++) {
	y1 = yloc[i];
	x1 = xloc[i];
	y2 = yloc[i + 1];
	x2 = xloc[i + 1];
	build_tunnel(y2, x2, y1, x1);
    }
    fill_cave(GRANITE_WALL);
    for (i = 0; i < DUN_STR_MAG; i++)
	place_streamer(MAGMA_WALL, DUN_STR_MC);
    for (i = 0; i < DUN_STR_QUA; i++)
	place_streamer(QUARTZ_WALL, DUN_STR_QC);
    place_boundary();
/* Place intersection doors	 */
    for (i = 0; i < doorindex; i++) {
	try_door(doorstk[i].y, doorstk[i].x - 1);
	try_door(doorstk[i].y, doorstk[i].x + 1);
	try_door(doorstk[i].y - 1, doorstk[i].x);
	try_door(doorstk[i].y + 1, doorstk[i].x);
    }
    if (spec_level == SPEC_DEST)
	place_destroyed();

    alloc_level = (dun_level / 3);
    if (alloc_level < 2)
	alloc_level = 2;
    else if (alloc_level > 10)
	alloc_level = 10;
    place_stairs(2, randint(2) + 2, 3);
    place_stairs(1, randint(2), 3);
/* Set up the character co-ords, used by alloc_monster, place_win_monster */
    new_spot(&char_row, &char_col);
    alloc_monster((randint(8) + MIN_MALLOC_LEVEL + alloc_level), 0, TRUE);
    alloc_object(set_corr, 3, randint(alloc_level));
    alloc_object(set_room, 5, randnor(TREAS_ROOM_ALLOC, 3));
    alloc_object(set_floor, 5, randnor(TREAS_ANY_ALLOC, 3));
    alloc_object(set_floor, 4, randnor(TREAS_GOLD_ALLOC, 3));
    alloc_object(set_floor, 1, randint(alloc_level));
    if (place_ghost())
	good_item_flag = TRUE;
    else if (spec_level == SPEC_DEST) {
	int                 flag, counter = 0;

	do {
	    flag = place_ghost();
	    counter++;
	} while (!flag && counter < 10);
    }
    if (randint(5) < 4 && dun_level >= WIN_MON_APPEAR)
	place_win_monster();
}


/* Builds a store at a row, column coordinate			 */
static void 
build_store(store_num, y, x)
    int                 store_num, y, x;
{
    int                 yval, y_height, y_depth;
    int                 xval, x_left, x_right;
    register int        i, j;
    int                 cur_pos, tmp;
    register cave_type *c_ptr;

    yval = y * 10 + 5;
    xval = x * 14 + 12;
    y_height = yval - randint(3);
    y_depth = yval + randint(4);
    x_left = xval - randint(4);
    x_right = xval + randint(4);
    for (i = y_height; i <= y_depth; i++)
	for (j = x_left; j <= x_right; j++)
	    cave[i][j].fval = BOUNDARY_WALL;
    tmp = randint(4);
    if (tmp < 3) {
	i = randint(y_depth - y_height) + y_height - 1;
	if (tmp == 1)
	    j = x_left;
	else
	    j = x_right;
    } else {
	j = randint(x_right - x_left) + x_left - 1;
	if (tmp == 3)
	    i = y_depth;
	else
	    i = y_height;
    }
    c_ptr = &cave[i][j];
    c_ptr->fval = CORR_FLOOR;
    cur_pos = popt();
    c_ptr->tptr = cur_pos;
    invcopy(&t_list[cur_pos], OBJ_STORE_DOOR + store_num);
}


/* Link all free space in treasure list together		 */
static void 
tlink()
{
    register int        i;

    for (i = 0; i < MAX_TALLOC; i++)
	invcopy(&t_list[i], OBJ_NOTHING);
    tcptr = MIN_TRIX;
}


/* Link all free space in monster list together			 */
static void 
mlink()
{
    register int        i;

    for (i = 0; i < MAX_MALLOC; i++)
	if (m_list[i].mptr)
	    delete_monster(i);
    for (i = 0; i < MAX_MALLOC; i++)
	m_list[i] = blank_monster;
    delete_unique();		   /* Kludgey Fix ~Ludwig */
    mfptr = MIN_MONIX;
}


/* Town logic flow for generation of new town		 */
static void 
town_gen()
{
    register int        i, j, l, m;
    register cave_type *c_ptr;
    int                 rooms[MAX_STORES], k;

    set_seed(town_seed);
    for (i = 0; i < MAX_STORES; i++)
	rooms[i] = i;
    l = MAX_STORES;
    for (i = 0; i < 2; i++)
	for (j = 0; j < 4; j++) {
	    k = randint(l) - 1;
	    build_store(rooms[k], i, j);
	    for (m = k; m < l - 1; m++)
		rooms[m] = rooms[m + 1];
	    l--;
	}
    fill_cave(DARK_FLOOR);
/* make stairs before reset_seed, so that they don't move around */
    place_boundary();
    place_stairs(2, 1, 0);
    reset_seed();
/* Set up the character co-ords, used by alloc_monster below */
    new_spot(&char_row, &char_col);
    if (0x1 & (turn / 5000)) {	   /* Night	 */
	for (i = 0; i < cur_height; i++) {
	    c_ptr = &cave[i][0];
	    for (j = 0; j < cur_width; j++) {
		if (c_ptr->fval != DARK_FLOOR)
		    c_ptr->pl = TRUE;
		c_ptr++;
	    }
	}
	alloc_monster(MIN_MALLOC_TN, 3, TRUE);
    } else {			   /* Day	 */
	for (i = 0; i < cur_height; i++) {
	    c_ptr = &cave[i][0];
	    for (j = 0; j < cur_width; j++) {
		c_ptr->pl = TRUE;
		c_ptr++;
	    }
	}
	alloc_monster(MIN_MALLOC_TD, 3, TRUE);
    }
    store_maint();
    place_ghost();
}


/* Generates a random dungeon level			-RAK-	 */
void 
generate_cave()
{
    panel_row_min = 0;
    panel_row_max = 0;
    panel_col_min = 0;
    panel_col_max = 0;
    char_row = (-1);
    char_col = (-1);

    tlink();
    mlink();
    blank_cave();

    if (dun_level == 0) {
	cur_height = SCREEN_HEIGHT;
	cur_width = SCREEN_WIDTH;
	max_panel_rows = (cur_height / SCREEN_HEIGHT) * 2 - 2;
	max_panel_cols = (cur_width / SCREEN_WIDTH) * 2 - 2;
	panel_row = max_panel_rows;
	panel_col = max_panel_cols;
	town_gen();
    } else {
	cur_height = MAX_HEIGHT;
	cur_width = MAX_WIDTH;
	max_panel_rows = (cur_height / SCREEN_HEIGHT) * 2 - 2;
	max_panel_cols = (cur_width / SCREEN_WIDTH) * 2 - 2;
	panel_row = max_panel_rows;
	panel_col = max_panel_cols;
	cave_gen();
    }

    unfelt = TRUE;
    feeling = 0;
    if (rating > 100)
	feeling = 2;
    else if (rating > 80)
	feeling = 3;
    else if (rating > 60)
	feeling = 4;
    else if (rating > 40)
	feeling = 5;
    else if (rating > 30)
	feeling = 6;
    else if (rating > 20)
	feeling = 7;
    else if (rating > 10)
	feeling = 8;
    else if (rating > 0)
	feeling = 9;
    else
	feeling = 10;

    if (good_item_flag)		/* do this last to explicitly set value -CWS */
	feeling = 1;
}
