empiremud/cnf/
empiremud/doc/
empiremud/lib/boards/
empiremud/lib/etc/
empiremud/lib/misc/
empiremud/lib/plralias/F-J/
empiremud/lib/plralias/K-O/
empiremud/lib/plralias/P-T/
empiremud/lib/plralias/U-Z/
empiremud/lib/plrobjs/
empiremud/lib/plrobjs/F-J/
empiremud/lib/plrobjs/K-O/
empiremud/lib/plrobjs/P-T/
empiremud/lib/plrobjs/U-Z/
empiremud/lib/world/
empiremud/lib/world/mob/
empiremud/lib/world/obj/
empiremud/log/
/* ************************************************************************
*   File: building.c                                     EmpireMUD AD 1.0 *
*  Usage: Miscellaneous player-level commands                             *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Code base by Paul Clarke.  EmpireMUD Project, a tbgMUD Production.     *
*  Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson.        *
*                                                                         *
*  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

/*
 * Paul's Thoughts:
 *  - sector checks should be standardized so they can be done through one
 *    function.  this also cleans up adding new sect flags
 */

#include "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "empire.h"
#include "skills.h"
#include "vnums.h"

/* extern variables */
extern bool can_claim(Creature ch);
extern int last_action_rotation;
extern int rev_dir[];
extern const char *dirs[];


#define CLEAR_FIELD(r)		((SECT(r) == SECT_ROAD && world[r].type == 0 && world[r].type2 == 0) || SECT(r) == SECT_SEEDED || SECT(r) == SECT_FIELD)
#define CLEAR_BRIDGE(r)		((SECT(r) == SECT_ROAD && world[r].type == 1 && world[r].type2 == -1) && IS_COMPLETE(r))
#define CLEAR_DESERT(r)		((SECT(r) == SECT_ROAD && world[r].type == 0 && world[r].type2 == 1) || SECT(r) == SECT_DESERT)

/* Terrain flags */
#define BUILD_NONE			-1
#define BUILD_WATER			(1 << 0)
#define BUILD_FIELD			(1 << 1)
#define BUILD_MOUNTAIN		(1 << 2)
#define BUILD_FOREST		(1 << 3)
#define BUILD_DESERT		(1 << 4)
#define BUILD_RIVER			(1 << 5)
#define BUILD_TUNNEL		(1 << 6)
#define BUILD_BRIDGE		(1 << 7)

/* For find_building_list_entry */
#define FIND_BUILD_NORMAL		0
#define FIND_BUILD_UPGRADE		1

#define MAX_MONUMENT_SIZE		5

/* This prevents structures from trying to face the wrong way */
#define SINGLE_SPARE		{{-1}}
#define NORTH_ONLY_SPARE	SINGLE_SPARE, SINGLE_SPARE, SINGLE_SPARE
#define SIMPLE_MAP(sect)	{{{(sect)}}, NORTH_ONLY_SPARE}

#define HENGE_MAP	{	\
	{	/* North-facing */	\
		{	MONUMENT_O_HENGE_UL,	MONUMENT_O_HENGE_UR		},	\
		{	MONUMENT_O_HENGE_LL,	MONUMENT_O_HENGE_LR		}	\
		},	\
	NORTH_ONLY_SPARE	\
	}

#define TEMPLE_MAP	{	\
	{	/* North-facing */		\
		{ MONUMENT_C_TEMPLE_UL,		MONUMENT_C_TEMPLE_UR	},	\
		{ MONUMENT_C_TEMPLE_LL,		MONUMENT_C_TEMPLE_LR	}	\
		},	\
	NORTH_ONLY_SPARE	\
	}

#define HIGHTEMPLE_MAP {	\
	{	/* North-facing */	\
		{ MONUMENT_C_HIGHTEMPLE_UL,	MONUMENT_C_HIGHTEMPLE_UC,	MONUMENT_C_HIGHTEMPLE_UR	},	\
		{ MONUMENT_C_HIGHTEMPLE_CL,	MONUMENT_C_HIGHTEMPLE_CC,	MONUMENT_C_HIGHTEMPLE_CR	},	\
		{ MONUMENT_C_HIGHTEMPLE_LL,	MONUMENT_C_HIGHTEMPLE_LC,	MONUMENT_C_HIGHTEMPLE_LR	}	\
		},	\
	NORTH_ONLY_SPARE	\
	}

#define FORT_MAP {	\
	{	/* North-facing */	\
		{ MULTI_UL_DOOR,	MULTI_UR	},	\
		{ MULTI_LL,			MULTI_LR	}	\
		},	\
	/* East */	SINGLE_SPARE,	\
	{	/* South-facing */	\
		{ MULTI_UL,		MULTI_UR		},	\
		{ MULTI_LL,		MULTI_LR_DOOR	}	\
		},	\
	/* West */	SINGLE_SPARE	\
	}

#define CASTLE_MAP {	\
	{	/* North-facing */	\
		{ MULTI_UL,		MULTI_HORIZ_DOOR,	MULTI_UR		},	\
		{ MULTI_VERT_L,	MULTI_CENTER,		MULTI_VERT_R	},	\
		{ MULTI_LL,		MULTI_HORIZ,		MULTI_LR		}	\
		},	\
	{	/* East-facing */	\
		{ MULTI_UL,		MULTI_HORIZ,		MULTI_UR		},	\
		{ MULTI_VERT_L,	MULTI_CENTER,		MULTI_VERT_DOOR_R	},	\
		{ MULTI_LL,		MULTI_HORIZ,		MULTI_LR		}	\
		},	\
	{	/* South-facing */	\
		{ MULTI_UL,		MULTI_HORIZ,		MULTI_UR		},	\
		{ MULTI_VERT_L,	MULTI_CENTER,		MULTI_VERT_R	},	\
		{ MULTI_LL,		MULTI_HORIZ_DOOR,	MULTI_LR		}	\
		},	\
	{	/* West-facing */	\
		{ MULTI_UL,		MULTI_HORIZ,		MULTI_UR		},	\
		{ MULTI_VERT_DOOR_L,MULTI_CENTER,	MULTI_VERT_R	},	\
		{ MULTI_LL,		MULTI_HORIZ,		MULTI_LR		}	\
		}	\
	}

#define PYRAMID_MAP {	\
	{	/* North-facing */	\
		{ MONUMENT_C_PYRAMID_CORNER_L,	MONUMENT_C_PYRAMID_HORIZ_DOOR,	MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_CORNER_R	},	\
		{ MONUMENT_C_PYRAMID_VERT_L,	MONUMENT_C_PYRAMID_CENTER_UL,	MONUMENT_C_PYRAMID_CENTER_UR,	MONUMENT_C_PYRAMID_VERT_R	},	\
		{ MONUMENT_C_PYRAMID_VERT_L,	MONUMENT_C_PYRAMID_CENTER_LL,	MONUMENT_C_PYRAMID_CENTER_LR,	MONUMENT_C_PYRAMID_VERT_R	},	\
		{ MONUMENT_C_PYRAMID_CORNER_L,	MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_CORNER_R	}	\
		},	\
	{	/* East-facing */	\
		{ MONUMENT_C_PYRAMID_CORNER_L,	MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_CORNER_R	},	\
		{ MONUMENT_C_PYRAMID_VERT_L,	MONUMENT_C_PYRAMID_CENTER_UL,	MONUMENT_C_PYRAMID_CENTER_UR,	MONUMENT_C_PYRAMID_VERT_DOOR_R	},	\
		{ MONUMENT_C_PYRAMID_VERT_L,	MONUMENT_C_PYRAMID_CENTER_LL,	MONUMENT_C_PYRAMID_CENTER_LR,	MONUMENT_C_PYRAMID_VERT_R	},	\
		{ MONUMENT_C_PYRAMID_CORNER_L,	MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_CORNER_R	}	\
		},	\
	{	/* South-facing */	\
		{ MONUMENT_C_PYRAMID_CORNER_L,	MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_CORNER_R	},	\
		{ MONUMENT_C_PYRAMID_VERT_L,	MONUMENT_C_PYRAMID_CENTER_UL,	MONUMENT_C_PYRAMID_CENTER_UR,	MONUMENT_C_PYRAMID_VERT_R	},	\
		{ MONUMENT_C_PYRAMID_VERT_L,	MONUMENT_C_PYRAMID_CENTER_LL,	MONUMENT_C_PYRAMID_CENTER_LR,	MONUMENT_C_PYRAMID_VERT_R	},	\
		{ MONUMENT_C_PYRAMID_CORNER_L,	MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_HORIZ_DOOR,	MONUMENT_C_PYRAMID_CORNER_R	}	\
		},	\
	{	/* West-facing */	\
		{ MONUMENT_C_PYRAMID_CORNER_L,	MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_CORNER_R	},	\
		{ MONUMENT_C_PYRAMID_VERT_L,	MONUMENT_C_PYRAMID_CENTER_UL,	MONUMENT_C_PYRAMID_CENTER_UR,	MONUMENT_C_PYRAMID_VERT_R	},	\
		{ MONUMENT_C_PYRAMID_VERT_DOOR_L,MONUMENT_C_PYRAMID_CENTER_LL,	MONUMENT_C_PYRAMID_CENTER_LR,	MONUMENT_C_PYRAMID_VERT_R	},	\
		{ MONUMENT_C_PYRAMID_CORNER_L,	MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_HORIZ,		MONUMENT_C_PYRAMID_CORNER_R	}	\
		}	\
	}

/* Buildings with name "upgrade" won't trigger dismantle, and can't be built */
#define BUILD_UPGRADE		"Upgrade"
/* Buildings with the name "dismantle" can't be built */
#define BUILD_DISMANTLE		"Dismantle"
#define BUILD_LINE_BREAK	{ "\t", 0, 0, 0, 0, 0, 0, SIMPLE_MAP(-1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
#define BUILD_LAST_ENTRY	{ "\n", 0, 0, 0, 0, 0, 0, SIMPLE_MAP(-1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }


struct build_data_structure {
	char *name;
	int special;
	bool closed;
	int height, width;

	int sect, type2;
	int map[NUM_SIMPLE_DIRS][MAX_MONUMENT_SIZE][MAX_MONUMENT_SIZE];

	int built_on, facing, reverse;
	int science, leadership, intelligence;

	int sticks, logs, rocks, iron;
	int max_rooms, designate_flags, base_affects;
	} build[] = {

		/*
		 * "name", special processing #, closed?, height (tiles), width (tiles),
		 * map (see below), build sects,
		 * leadership, intelligence,
		 * sticks, logs, rocks, iron
		 *
		 * Special Processing:
		 *  -1: no special processing
		 *   0: required person to dedicate to
		 *   1: face a direction but don't change map
		 *   2: face a direction and use the direction map
		 *   3: it's a well
		 *
		 * Maps:
		 *  These are used to map out the tiles of any monument from 1x1 to
		 *  MAX_MONUMENT_SIZExMAX_MONUMENT_SIZE.
		 */

		/* Simple Field buildings */

		{ "hut",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_HUT),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			1, 0, 1,
			30,	0,	0,	0,
			0,	0,	0	},

		{ "cabin",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_CABIN),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			1, 0, 1,
			0,	12,	0,	0,
			0,	0,	0	},

		{ "house",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_HOUSE),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			1, 0, 1,
			0,	20,	0,	0,
			2,	0,	0	},

		{ "househaven",	1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_HAVEN_HOUSE),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			6,	0,	5,
			0,	20,	20,	0,
			3,	0,	0	},

		{ "well",		3,		0,		1,		1,
			SECT_WELL,	-1,	SIMPLE_MAP(0),
			BUILD_FIELD,	-1,	-1,
			2, 0, 1,
			5,	1,	20,	0,
			0,	0,	0	},

		{ "stonehouse",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_STONE_HOUSE),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			2, 0, 1,
			0,	20,	20,	0,
			3,	0,	0	},

		{ "largehouse",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_LARGE_HOUSE),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			2, 0, 2,
			0,	40,	40,	0,
			5,	0,	0	},

		{ "baths",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_BATHS),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			3, 0, 3,
			30,	8,	40,	0,
			0,	0,	0	},

		{ "fountain",		-1,		0,		1,		1,
			SECT_FOUNTAIN,	-1,	SIMPLE_MAP(0),
			BUILD_FIELD,	-1,	-1,
			4, 0, 3,
			30,	4,	40,	0,
			0,	0,	0	},

		{ "fort",		2,	1,	2,	2,
			SECT_MULTI,	0,	FORT_MAP,
			BUILD_FIELD,	BUILD_FIELD,	-1,
			4, 1, 4,
			0, 100, 100, 60,
			20,	DES_FORGE | DES_ARMORY,	0	},

		{ "castle",		2,	1,	3,	3,
			SECT_MULTI,	0,	CASTLE_MAP,
			BUILD_FIELD,	BUILD_FIELD,	-1,
			5, 2, 4,
			0, 150, 200, 135,
			40,	DES_FORGE | DES_ARMORY | DES_GREATHALL | DES_THRONE | DES_VAULT | DES_BATHS,	0	},

		BUILD_LINE_BREAK,


		/* Desert Buildings */

		{ "mudhut",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_MUD_HUT),
			BUILD_DESERT,	BUILD_DESERT,	-1,
			1, 0, 1,
			0,	1,	20,	0,
			0,	0,	0	},

		{ "pueblo",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_PUEBLO),
			BUILD_DESERT,	BUILD_DESERT,	-1,
			2, 0, 2,
			0,	12,	40,	0,
			2,	0,	0	},

		{ "pueblohaven",	1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_HAVEN_PUEBLO),
			BUILD_DESERT,	BUILD_DESERT,	-1,
			6,	0,	5,
			0,	12,	40,	0,
			3,	0,	0	},

		{ "undergroundcomplex",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_UNDERGROUND_COMPLEX),
			BUILD_DESERT,	BUILD_DESERT,	-1,
			4, 0, 3,
			40,	120,	0,	100,
			25,	DES_NO_HALL | DES_TUNNEL,	ROOM_AFF_CHAMELEON_DESERT },

		{ "greathouse",		2,	1,	2,	2,
			SECT_MULTI,	2,	FORT_MAP,
			BUILD_DESERT,	BUILD_DESERT,	-1,
			4, 1, 4,
			0, 40, 250, 60,
			20,	DES_FORGE | DES_ARMORY,	0	},

		{ "palace",		2,	1,	3,	3,
			SECT_MULTI,	2,	CASTLE_MAP,
			BUILD_DESERT,	BUILD_DESERT,	-1,
			5, 2, 5,
			0, 100, 250, 120,
			40,	DES_FORGE | DES_ARMORY | DES_GREATHALL | DES_THRONE | DES_VAULT | DES_BATHS,	0	},

		BUILD_LINE_BREAK,


		/* Tree Buildings */

		{ "treehouse",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_TREE_COMPLEX),
			BUILD_FOREST,	BUILD_FOREST,	-1,
			2, 0,	3,
			30,	3,	0,	0,
			0,	DES_SKYBRIDGE,	ROOM_AFF_CHAMELEON_FOREST	},

		/*{ "treecomplex",	1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_TREE_COMPLEX),
			BUILD_FOREST,	BUILD_FOREST,	-1,
			3, 0, 4,
			30,	40,	0,	5,
			3,	DES_SKYBRIDGE,	ROOM_AFF_CHAMELEON_FOREST	},*/

		{ "treefort",		2,	1,	2,	2,
			SECT_MULTI,	1,	FORT_MAP,
			BUILD_FOREST,	BUILD_FOREST,	-1,
			4, 1, 4,
			250, 30, 0, 40,
			20,	DES_FORGE | DES_ARMORY | DES_SKYBRIDGE,	ROOM_AFF_CHAMELEON_FOREST	},

		{ "burrowhaven",	1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_HAVEN_BURROW),
			BUILD_FOREST,	BUILD_FOREST,	-1,
			6,	0,	5,
			0,	20,	20,	0,
			3,	DES_NO_HALL | DES_TUNNEL,	0	},

		BUILD_LINE_BREAK,


		/* Mountain buildings */

		{ "mine",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_MINE),
			BUILD_MOUNTAIN,	BUILD_MOUNTAIN | BUILD_FIELD | BUILD_DESERT,	-1,
			1, 0, 2,
			0,	14,	0,	0,
			0,	0,	0	},

		{ "cliffdwelling",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_CLIFF_DWELLING),
			BUILD_MOUNTAIN,	BUILD_MOUNTAIN | BUILD_FIELD | BUILD_DESERT,	-1,
			2, 0, 2,
			5,	20,	30,	0,
			3,	0,	0	},

		{ "cavehaven",	1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_HAVEN_CAVE),
			BUILD_MOUNTAIN,	BUILD_MOUNTAIN,	-1,
			6,	0,	5,
			0,	20,	0,	0,
			3,	DES_TUNNEL | DES_NO_HALL,	ROOM_AFF_CHAMELEON_MOUNTAIN	},

		{ "tunnel",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_TUNNEL),
			BUILD_MOUNTAIN,	BUILD_FIELD | BUILD_DESERT | BUILD_TUNNEL,	BUILD_MOUNTAIN | BUILD_TUNNEL,
			2, 0, 3,
			0,	20,	0,	0,
			0,	0,	0	},

		/* tunnel upgrade */
		{ BUILD_UPGRADE,	1,	1,	1,	1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_TUNNEL2),
			SECT_BUILDING,	BUILDING_TUNNEL,	-1,
			4,	0,	3,
			0,	20,	0,	0,
			0,	0,	0	},

		/* tunnel2 dismantle */
		{ BUILD_DISMANTLE,	1,	1,	1,	1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_TUNNEL2),
			BUILD_MOUNTAIN,	BUILD_FIELD | BUILD_DESERT | BUILD_TUNNEL,	BUILD_MOUNTAIN | BUILD_TUNNEL,
			4,	0,	3,
			0,	40,	0,	0,
			0,	0,	0	},

		{ "mountainoutpost",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_MOUNTAIN_OUTPOST),
			BUILD_MOUNTAIN,	BUILD_MOUNTAIN,	-1,
			3, 0, 2,
			30,	4,	20,	0,
			0,	0,	0	},

		{ "minecomplex",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_MINE_COMPLEX),
			BUILD_MOUNTAIN,	BUILD_MOUNTAIN | BUILD_FIELD | BUILD_DESERT,	-1,
			4, 0, 4,
			30,	120,	0,	20,
			25,	DES_NO_HALL | DES_TUNNEL,	0	},

		BUILD_LINE_BREAK,


		/* Guard Towers */

		{ "guardtower",		1,		1,		1,		1,
			SECT_BUILDING,	0,	SIMPLE_MAP(BUILDING_GUARD_TOWER),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			3, 0, 3,
			30,	4,	0,	0,
			0,	0,	0	},

		/* guard tower upgrade 1 */
		{ BUILD_UPGRADE,	1,	1,	1,	1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_GUARD_TOWER2),
			SECT_BUILDING,	BUILDING_GUARD_TOWER,	-1,
			4,	0,	4,
			30,	4,	0,	20,
			0,	0,	0	},

		/* guard tower 2 dismantle */
		{ BUILD_DISMANTLE,	1,	1,	1,	1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_GUARD_TOWER2),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			4,	0,	4,
			60,	8,	0,	20,
			0,	0,	0	},

		/* guard tower upgrade 2 */
		{ BUILD_UPGRADE,	1,	1,	1,	1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_GUARD_TOWER3),
			SECT_BUILDING,	BUILDING_GUARD_TOWER2,	-1,
			5,	0,	5,
			30,	4,	0,	40,
			0,	0,	0	},

		/* guard tower 3 dismantle */
		{ BUILD_DISMANTLE,	1,	1,	1,	1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_GUARD_TOWER3),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			5,	0,	5,
			90,	12,	0,	60,
			0,	0,	0	},

		{ "sentry",		1,		1,		1,		1,
			SECT_BUILDING,	2,	SIMPLE_MAP(BUILDING_GUARD_TOWER),
			BUILD_DESERT,	BUILD_DESERT,	-1,
			3, 0, 3,
			30,	4,	0,	0,
			0,	0,	0 },

		{ "watchtower",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_WATCH_TOWER),
			BUILD_FOREST,	BUILD_FOREST,	-1,
			3, 0, 4,
			30,	4,	0,	20,
			0,	0,	ROOM_AFF_CHAMELEON_FOREST	},

		BUILD_LINE_BREAK,


		/* Barriers */

		{ "fence",		-1,		0,		1,		1,
			SECT_BARRIER,	0,	SIMPLE_MAP(0),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			1, 0, 1,
			20,	0,	0,	0,
			0,	0,	0	},

		{ "trellis",		-1,		0,		1,		1,
			SECT_BARRIER,	1,	SIMPLE_MAP(0),
			BUILD_FOREST,	BUILD_FOREST,	-1,
			2, 0, 1,
			20,	0,	0,	0,
			0,	0,	ROOM_AFF_CHAMELEON_FOREST	},

		{ "spikedbarrier",		-1,		0,		1,		1,
			SECT_BARRIER,	2,	SIMPLE_MAP(0),
			BUILD_DESERT,	BUILD_DESERT,	-1,
			1, 0, 1,
			20,	0,	0,	0,
			0,	0,	0	},

		{ "wall",		-1,		0,		1,		1,
			SECT_BARRIER,	0,	SIMPLE_MAP(1),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			3, 0, 1,
			0,	0,	20,	0,
			0,	0,	0	},

		{ "palisade",		-1,		0,		1,		1,
			SECT_BARRIER,	1,	SIMPLE_MAP(1),
			BUILD_FOREST,	BUILD_FOREST,	-1,
			4, 0, 1,
			0,	0,	20,	0,
			0,	0,	ROOM_AFF_CHAMELEON_FOREST	},

		{ "adobewall",		-1,		0,		1,		1,
			SECT_BARRIER,	2,	SIMPLE_MAP(1),
			BUILD_DESERT,	BUILD_DESERT,	-1,
			3, 0, 1,
			0,	0,	20,	0,
			0,	0,	0	},

		{ "gatehouse",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_GATEHOUSE),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,
			2, 0, 2,
			30,	4,	20,	0,
			0,	0,	0	},

		BUILD_LINE_BREAK,


		/* Specialized Buildings */

		{ "baker",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_BAKER),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			2, 0, 3,
			0,	25,	30,	8,
			0,	0,	0	},

		{ "carpenter",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_CARPENTER),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			3, 0, 3,
			20,	40,	10,	10,
			0,	0,	0	},

		{ "forge",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_FORGE),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			3, 0, 3,
			0,	20,	30,	50,
			0,	0,	0	},

		{ "glassworker",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_GLASS),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			3, 0, 3,
			0,	20,	30,	8,
			0,	0,	0	},

		{ "mill",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_MILL),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			2, 0, 3,
			0,	20,	60,	0,
			0,	0,	0	},

		{ "potter",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_POTTER),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			3, 0, 3,
			0,	20,	20,	10,
			0,	0,	0	},

		{ "stable",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_STABLE),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			2, 0, 3,
			0,	60,	0,	20,
			0,	0,	0	},

		BUILD_LINE_BREAK,


		/* Water Specialized Buildings */

		{ "bridge",		-1,		0,		1,		1,
			SECT_ROAD,	-1,	SIMPLE_MAP(1),
			BUILD_RIVER,	-1,	-1,
			3, 0, 3,
			30,	16,	20,	0,
			0,	0,	0	},

		{ "docks",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_DOCKS),
			BUILD_FIELD | BUILD_DESERT,	BUILD_WATER,	BUILD_FIELD | BUILD_DESERT,
			3, 0, 2,
			0,	40,	0,	0,
			0,	0,	0	},

		{ "shipyard",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_SHIPYARD),
			BUILD_FIELD | BUILD_DESERT,	BUILD_WATER,	BUILD_FIELD | BUILD_DESERT,
			3, 0, 3,
			0,	50,	30,	0,
			0,	0,	0	},

		/* shipyard upgrade */
		{ BUILD_UPGRADE,	1,	1,	1,	1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_SHIPYARD2),
			SECT_BUILDING,	BUILDING_SHIPYARD,	-1,
			4,	0,	3,
			0,	75,	0,	35,
			0,	0,	0	},

		/* shipyard2 dismantle */
		{ BUILD_DISMANTLE,	1,	1,	1,	1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_SHIPYARD2),
			BUILD_FIELD | BUILD_DESERT,	BUILD_WATER,	BUILD_FIELD | BUILD_DESERT,
			4,	0,	3,
			0,	125,	30,	35,
			0,	0,	0	},

		BUILD_LINE_BREAK,


		/* Storage Buildings */

		{ "apiary",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_APIARY),
			BUILD_FIELD,	BUILD_FIELD,	-1,
			2, 0, 2,
			0,	20,	0,	0,
			0,	0,	0	},

		{ "arsenal",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_ARSENAL),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			1, 0, 1,
			0,	20,	0,	0,
			0,	0,	0	},

		{ "cannery",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_CANNERY),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			1, 0, 1,
			0,	20,	0,	0,
			0,	0,	0	},

		{ "foundry",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_FOUNDRY),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			1, 0, 1,
			0,	20,	0,	0,
			0,	0,	0	},

		{ "granary",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_GRANARY),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			1, 0, 1,
			0,	20,	0,	0,
			0,	0,	0	},

		{ "gravelpit",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_GRAVEL_PIT),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			1, 0, 1,
			20,	0,	0,	0,
			0,	0,	0	},

		{ "lumberyard",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_LUMBER_YARD),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			1, 0, 1,
			20,	0,	0,	0,
			0,	0,	0	},

		{ "tannery",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_TANNERY),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			1, 0, 1,
			0,	20,	0,	0,
			0,	0,	0	},

		{ "utilityshed",		1,		1,		1,		1,
			SECT_BUILDING,	-1,	SIMPLE_MAP(BUILDING_TOOLS),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			2, 0, 2,
			0,	20,	0,	0,
			0,	0,	0	},

		BUILD_LINE_BREAK,


		/* Monuments: Open */

		{ "statue",		0,		0,		1,		1,
			SECT_MONUMENT_OPEN,	-1,	SIMPLE_MAP(MONUMENT_O_STATUE),
			BUILD_FIELD | BUILD_DESERT,	-1,	-1,
			0, 3, 1,
			0,	80,	100,	0,
			0,	0,	0	},

		/* henge dismantles */
		{ BUILD_DISMANTLE,	-1,	0,	1,	1,
			SECT_MONUMENT_OPEN,	-1,	SIMPLE_MAP(MONUMENT_O_HENGE_UL),
			BUILD_FIELD | BUILD_DESERT,	-1,	-1,
			0,	0,	3,
			0,	0,	100,	0,
			0,	0,	0	},

		{ BUILD_DISMANTLE,	-1,	0,	1,	1,
			SECT_MONUMENT_OPEN,	-1,	SIMPLE_MAP(MONUMENT_O_HENGE_UR),
			BUILD_FIELD | BUILD_DESERT,	-1,	-1,
			0,	0,	3,
			0,	0,	100,	0,
			0,	0,	0	},

		{ BUILD_DISMANTLE,	-1,	0,	1,	1,
			SECT_MONUMENT_OPEN,	-1,	SIMPLE_MAP(MONUMENT_O_HENGE_LL),
			BUILD_FIELD | BUILD_DESERT,	-1,	-1,
			0,	0,	3,
			0,	0,	100,	0,
			0,	0,	0	},

		{ BUILD_DISMANTLE,	-1,	0,	1,	1,
			SECT_MONUMENT_OPEN,	-1,	SIMPLE_MAP(MONUMENT_O_HENGE_LR),
			BUILD_FIELD | BUILD_DESERT,	-1,	-1,
			0,	0,	3,
			0,	0,	100,	0,
			0,	0,	0	},

		{ "henge",		-1,		0,		2,		2,
			SECT_MONUMENT_OPEN,	-1,	HENGE_MAP,
			BUILD_FIELD | BUILD_DESERT,	-1,	-1,
			0, 3, 3,
			0,	0,	100,	0,
			0,	0,	0	},

		{ "megalith",	-1,		0,		1,		1,
			SECT_MONUMENT_OPEN,	-1,	SIMPLE_MAP(MONUMENT_O_MEGALITH),
			BUILD_FIELD | BUILD_DESERT,	-1,	-1,
			0, 3, 2,
			0,	80,	250,	0,
			0,	0,	0	},

		{ "cemetary",	-1,		0,		1,		1,
			SECT_MONUMENT_OPEN,	-1,	SIMPLE_MAP(MONUMENT_O_CEMETARY),
			BUILD_FIELD,	-1,	-1,
			0, 3, 1,
			0,	0,	100,	0,
			0,	0,	0	},

		{ "park",		-1,		0,		1,		1,
			SECT_MONUMENT_OPEN,	-1,	SIMPLE_MAP(MONUMENT_O_PARK),
			BUILD_FIELD,	-1,	-1,
			0, 3, 2,
			25,	20,	0,	0,
			0,	0,	0	},

		BUILD_LINE_BREAK,


		/* Monuments: Closed */

		{ "tomb",		1,		1,		1,		1,
			SECT_MONUMENT_CLOSED,	-1,	SIMPLE_MAP(MONUMENT_C_TOMB),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			0, 4, 3,
			0,	20,	30,	0,
			0,	0,	0	},

		{ "shrine",		0,		1,		1,		1,
			SECT_MONUMENT_CLOSED,	-1,	SIMPLE_MAP(MONUMENT_C_SHRINE),
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			0, 3, 2,
			60,	4,	20,	0,
			0,	0,	0	},

		{ "temple",		0,		1,		2,		2,
			SECT_MONUMENT_CLOSED,	-1,	TEMPLE_MAP,
			BUILD_FIELD | BUILD_DESERT,	BUILD_FIELD | BUILD_DESERT,	-1,
			0, 4, 3,
			40,	40,	80,	0,
			0,	0,	0	},

		{ "hightemple",		0,	1,		3,		3,
			SECT_MONUMENT_CLOSED,	-1,	HIGHTEMPLE_MAP,
			BUILD_FIELD | BUILD_DESERT,		BUILD_FIELD | BUILD_DESERT,	-1,
			0, 5, 4,
			80,	80,	200,	0,
			0,	0,	0	},

		{ "pyramid",		2,	1,		4,		4,
			SECT_MONUMENT_CLOSED,	-1,	PYRAMID_MAP,
			BUILD_DESERT,	BUILD_DESERT,	-1,
			0, 5, 5,
			250,	250,	250,	250,
			0,	0,	0	},

		/* This must come last */
		BUILD_LAST_ENTRY

		};


int find_building_list_entry(room_rnum room, byte type) {
	int i, j, x, y;
	room_rnum r = HOME_ROOM(room), shift, point;
	bool ok, done = FALSE;

	/* find y */
	for (y = 0; ; y++) {
		shift = real_shift(r, y * shift_dir[NORTH][0], y * shift_dir[NORTH][1]);
		if (HOME_ROOM(shift) != r) {
			y--;
			break;
			}
		}

	/* find x */
	for (x = 0; ; x++) {
		shift = real_shift(r, x * shift_dir[WEST][0], x * shift_dir[WEST][1]);
		if (HOME_ROOM(shift) != r) {
			x--;
			break;
			}
		}

	/* We set up our north-west corner point.. */
	point = r;
	point = real_shift(point, x * shift_dir[WEST][0], x * shift_dir[WEST][1]);
	point = real_shift(point, y * shift_dir[NORTH][0], y * shift_dir[NORTH][1]);

	/* Error checking */
	if (HOME_ROOM(point) != r) {
		syslog(0, TRUE, "SYSERR: Point setup failed in find_building_list_entry!");
		return -1;
		}

	/* Check the building map:
	 *  - we will go through each direction that the map could face
	 *  - we will pan from the northwest corner, comparing each sect
	 *  - any time 'ok' was not cancelled, we will break
	 */

	/* Each building in the building tree */
	for (i = 0; str_cmp("\n", build[i].name); i++) {
		if (type == FIND_BUILD_UPGRADE && str_cmp(build[i].name, BUILD_UPGRADE))
			continue;
		else if (type == FIND_BUILD_NORMAL && !str_cmp(build[i].name, BUILD_UPGRADE))
			continue;

		/* Each possible direction */
		for (j = 0, ok = TRUE; j < NUM_SIMPLE_DIRS; j++, ok = TRUE) {

			/* Note: this WILL mess up if the building has no maps.. but why would it? */
			if (build[i].map[j][0][0] == -1)
				continue;

			/* Across the width */
			for (x = 0; x < build[i].width && ok; x++) {

				/* Down the height */
				for (y = 0; y < build[i].height && ok; y++) {
					shift = point;
					shift = real_shift(shift, x * shift_dir[EAST][0], x * shift_dir[EAST][1]);
					shift = real_shift(shift, y * shift_dir[SOUTH][0], y * shift_dir[SOUTH][1]);

					if (SECT(shift) != build[i].sect)
						ok = FALSE;
					if (build[i].type2 != -1 && world[shift].type2 != build[i].type2)
						ok = FALSE;
					if (world[shift].type != build[i].map[j][y][x])
						ok = FALSE;
					}

				}

			/* Was ok never false? */
			if (ok) {
				done = TRUE;
				break;
				}
			}

		/* Are we done? */
		if (done)
			break;
		}

	if (!str_cmp("\n", build[i].name))
		return -1;
	return i;
	}


bool is_entrance(int rnum) {
	int i, j;

	/* A few times I call this function with NOWHERE.. easier here */
	if (rnum == NOWHERE)
		return FALSE;

	for (i = 0; i < NUM_2D_DIRS; i++)
		if (SECT((j = real_shift(rnum, shift_dir[i][0], shift_dir[i][1]))) == SECT_BUILDING || SECT((j = real_shift(rnum, shift_dir[i][0], shift_dir[i][1]))) == SECT_MONUMENT_CLOSED || SECT((j = real_shift(rnum, shift_dir[i][0], shift_dir[i][1]))) == SECT_MULTI) {
			if (world[j].building_entrance == i)
				return TRUE;
			else if ((BUILDING_TYPE(j) == BUILDING_DOCKS || BUILDING_TYPE(j) == BUILDING_SHIPYARD || BUILDING_TYPE(j) == BUILDING_SHIPYARD2 || BUILDING_TYPE(j) == BUILDING_GATEHOUSE) && world[j].building_entrance == rev_dir[i])
				return TRUE;
			}
	return FALSE;
	}

bool build_monument_map(Creature ch, int type, int dir, room_rnum map[MAX_MONUMENT_SIZE][MAX_MONUMENT_SIZE]) {
	int i, j, k;
	int focus_column = ((build[type].width + 1) / 2) - 1;

	/*
	 * This shows us how to find the focus_column in row 0
	 * This is shift east, shift north for a given width/height
	 */
	int amount_to_shift[NUM_SIMPLE_DIRS][2][MAX_MONUMENT_SIZE + 1] = {
		/* North */	{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
		/* East */	{ { 0, 0, -1, -1, -2, -2 }, { 0, 0, 1, 1, 1, 2 } },
		/* South */	{ { 0, 0, -1, 0, -1, 0 }, { 0, 0, 1, 2, 3, 4 } },
		/* West */	{ { 0, 0, 0, 1, 1, 2 }, { 0, 0, 0, 1, 2, 2 } }
		};

	for (i = 0; i < MAX_MONUMENT_SIZE; i++)
		for (j = 0; j < MAX_MONUMENT_SIZE; j++)
			map[i][j] = NOWHERE;

	/*
	 * Set up the primary room
	 * This is always the top-center or left-of-center, depending upon width
	 *   X XO OXO OXOO OOXOO
	 *     OO OOO OOOO OOOOO
	 *        OOO OOOO OOOOO
	 *            OOOO OOOOO
	 *                 OOOOO
	 *
	 * If you don't understand what it's doing, have faith
	 */

	/* Shift east by the appropriate amount for this width */
	map[0][focus_column] = real_shift(ch->in_room, amount_to_shift[dir][0][build[type].width] * shift_dir[EAST][0], amount_to_shift[dir][0][build[type].width] * shift_dir[EAST][1]);

	/* Shift north by the appropriate amount for this height */
	map[0][focus_column] = real_shift(map[0][focus_column], amount_to_shift[dir][1][build[type].height] * shift_dir[NORTH][0], amount_to_shift[dir][1][build[type].height] * shift_dir[NORTH][1]);

	/* Now design the top row */
	for (k = 0; k < build[type].width; k++)
		map[0][k] = real_shift(map[0][focus_column], (k - focus_column) * shift_dir[EAST][0], (k - focus_column) * shift_dir[EAST][1]);

	/* Set up the bottom half of the map based upon the top */
	for (j = 1; j < build[type].height; j++)
		for (i = 0; i < build[type].width; i++)
			map[j][i] = real_shift(map[0][i], j * shift_dir[SOUTH][0], j * shift_dir[SOUTH][1]);


	/* Check sectors */
	for (j = 0; j < build[type].height; j++)
		for (i = 0; i < build[type].width; i++)
			if (!CAN_USE_ROOM(ch, map[j][i], 1)) {
				msg_to_char(ch, "You don't have permission to build at (%d, %d).\r\n", X_COORD(map[j][i]), Y_COORD(map[j][i]));
				return FALSE;
				}
			else if (!((IS_SET(build[type].built_on, BUILD_FIELD) && CLEAR_FIELD(map[j][i])) || (IS_SET(build[type].built_on, BUILD_MOUNTAIN) && SECT(map[j][i]) == SECT_MOUNTAIN) || (IS_SET(build[type].built_on, BUILD_DESERT) && CLEAR_DESERT(map[j][i])) || (IS_SET(build[type].built_on, BUILD_RIVER) && SECT(map[j][i]) == SECT_RIVER) || (IS_SET(build[type].built_on, BUILD_FOREST) && SECT(map[j][i]) == SECT_FOREST_4) || (IS_SET(build[type].built_on, BUILD_WATER) && (SECT(map[j][i]) == SECT_OCEAN || SECT(map[j][i]) == SECT_RIVER)))) {
				msg_to_char(ch, "You need to build on: ");

				*buf = '\0';

				if (IS_SET(build[type].built_on, BUILD_FIELD))
					sprintf(buf + strlen(buf), "%sfield", *buf ? ", " : "");
				if (IS_SET(build[type].built_on, BUILD_WATER | BUILD_RIVER))
					sprintf(buf + strlen(buf), "%swater", *buf ? ", " : "");
				if (IS_SET(build[type].built_on, BUILD_MOUNTAIN))
					sprintf(buf + strlen(buf), "%smountain", *buf ? ", " : "");
				if (IS_SET(build[type].built_on, BUILD_DESERT))
					sprintf(buf + strlen(buf), "%sdesert", *buf ? ", " : "");
				if (IS_SET(build[type].built_on, BUILD_FOREST))
					sprintf(buf + strlen(buf), "%sforest", *buf ? ", " : "");

				msg_to_char(ch, "%s (%d, %d)\r\n", buf, X_COORD(map[j][i]), Y_COORD(map[j][i]));

				return FALSE;
				}
			else if (is_entrance(map[j][i])) {
				msg_to_char(ch, "You can't build in front of the entrance at (%d, %d).\r\n", X_COORD(map[j][i]), Y_COORD(map[j][i]));
				return FALSE;
				}

	/* The sectors are good, permission is good, it all looks good. */

	return TRUE;
	}


void setup_monument_resources(room_rnum room, int type) {
	world[room].res.logs = build[type].logs;
	world[room].res.rocks = build[type].rocks;
	world[room].res.iron = build[type].iron;
	world[room].res.sticks = build[type].sticks;
	}


ACMD(do_build) {
	room_rnum to_room = NOWHERE, to_rev = NOWHERE;
	room_rnum map[MAX_MONUMENT_SIZE][MAX_MONUMENT_SIZE];
	int e = -1, type = 0, map_dir = NORTH, dir = NORTH;
	bool found = 0;
	int i, j, c = 0;
	long id = 0;

	two_arguments(argument, arg, buf);

	if (*arg)
		for (type = 0; str_cmp(build[type].name, "\n") && (!is_abbrev(arg, build[type].name) || !str_cmp(build[type].name, BUILD_UPGRADE) || !str_cmp(build[type].name, BUILD_DISMANTLE)); type++);

	if (!*arg || !str_cmp(build[type].name, "\n")) {

		/* Cancel building */
		if (GET_ACTION(ch) == ACT_BUILDING) {
			msg_to_char(ch, "You stop building.\r\n");
			act("$n stops building.", FALSE, ch, 0, 0, TO_ROOM);
			GET_ACTION(ch) = ACT_NONE;
			}

		/* Continue building */
		else if (!IS_COMPLETE(ch->in_room)) {
			if (IS_DISMANTLING(ch->in_room))
				msg_to_char(ch, "The building is being dismantled, you can't rebuild it now.\r\n");
			else if (GET_ACTION(ch) != ACT_NONE)
				msg_to_char(ch, "You're kinda busy right now.\r\n");
			else {
				GET_ACTION(ch) = ACT_BUILDING;
				GET_ACTION_ROTATION(ch) = last_action_rotation;
				GET_ACTION_ROOM(ch) = ch->in_room;
				msg_to_char(ch, "You start building.\r\n");
				act("$n starts building.", FALSE, ch, 0, 0, TO_ROOM);
				}
			}

		/* Send output */
		else {
			msg_to_char(ch, "What type of structure are you trying to build?\r\n");
			for (type = 0; str_cmp(build[type].name, "\n"); type++)
				if (GET_SCIENCE(ch) >= build[type].science && GET_INTELLIGENCE(ch) >= build[type].intelligence && GET_LEADERSHIP(ch) >= build[type].leadership) {
					if (!str_cmp(build[type].name, "\t")) {
						if (c > 0) {
							msg_to_char(ch, "\r\n");
							c = 0;
							}
						}
					else if (str_cmp(build[type].name, "\r") && str_cmp(build[type].name, BUILD_UPGRADE) && str_cmp(build[type].name, BUILD_DISMANTLE) && (++c))
						msg_to_char(ch, " %s", build[type].name);
					}
			}
		}
	else if (GET_ACTION(ch) != ACT_NONE)
		msg_to_char(ch, "You're already busy.\r\n");
	else if (GET_INTELLIGENCE(ch) < build[type].intelligence || GET_SCIENCE(ch) < build[type].science || GET_LEADERSHIP(ch) < build[type].leadership)
		msg_to_char(ch, "You don't have the skill to erect that structure.\r\n");
	else if ((build[type].sect == SECT_MONUMENT_CLOSED || build[type].sect == SECT_MONUMENT_OPEN) && (e = real_empire(GET_LOYALTY(ch))) == -1)
		msg_to_char(ch, "You can't build a monument if you're not a member of an empire.\r\n");
	else if ((e = real_empire(get_id_by_empire(ch))) == -1 && 0)
		msg_to_char(ch, "You will never see this line, it's only here to set up an empire!\r\n");
	else if (e != -1 && GET_RANK(ch) < empire[e].priv[PRIV_BUILD])
		msg_to_char(ch, "You don't have permission to build anything.\r\n");
	else
		found = TRUE;

	/* 'found' is used for clean viewing */
	if (!found)
		return;

	/* special handling: parameters */
	switch (build[type].special) {
		case 0:
			if (!*buf || (id = get_id_by_name(buf)) <= 0) {
				msg_to_char(ch, "To whom would you like to dedicate this monument?\r\n");
				return;
				}
			break;
		case 1:
		case 2:
			if (!*buf || (dir = parse_direction(buf)) < 0) {
				msg_to_char(ch, "Which direction would you like to face this building?\r\n");
				return;
				}
			if (build[type].special == 1)
				break;

			/* type 2 only */

			/* map_dir tells it whether or not to map by dir */
			map_dir = dir;

			/* type 2's must go n,e,s,w */
			if (dir >= NUM_SIMPLE_DIRS || build[type].map[dir][0][0] == -1) {
				msg_to_char(ch, "You can't face it that direction.\r\n");
				return;
				}
			break;
		}

	/* Now that we're sure we can do this otherwise, lets build the map */
	if (!build_monument_map(ch, type, map_dir, map))
		return;


	/* At this point we have the map designated and the type chosen.. */

	/* For closed-type monuments only */
	if (build[type].closed) {
		/* The 'facing' room */
		to_room = real_shift(ch->in_room, shift_dir[dir][0], shift_dir[dir][1]);

		if (!((IS_SET(build[type].facing, BUILD_FIELD) && CLEAR_FIELD(to_room)) || (IS_SET(build[type].facing, BUILD_TUNNEL) && BUILDING_TYPE(to_room) == BUILDING_TUNNEL && IS_COMPLETE(to_room)) || (IS_SET(build[type].facing, BUILD_MOUNTAIN) && SECT(to_room) == SECT_MOUNTAIN) || (IS_SET(build[type].facing, BUILD_DESERT) && CLEAR_DESERT(to_room)) || (IS_SET(build[type].facing, BUILD_RIVER) && SECT(to_room) == SECT_RIVER) || (IS_SET(build[type].facing, BUILD_FOREST) && SECT(to_room) == SECT_FOREST_4) || (IS_SET(build[type].facing, BUILD_WATER) && (SECT(to_room) == SECT_OCEAN || SECT(to_room) == SECT_RIVER)))) {
			msg_to_char(ch, "You need to build facing: ");

			*buf = '\0';

			if (IS_SET(build[type].facing, BUILD_FIELD))
				sprintf(buf + strlen(buf), "%sfield", *buf ? ", " : "");
			if (IS_SET(build[type].facing, BUILD_WATER | BUILD_RIVER))
				sprintf(buf + strlen(buf), "%swater", *buf ? ", " : "");
			if (IS_SET(build[type].facing, BUILD_TUNNEL))
				sprintf(buf + strlen(buf), "%stunnel", *buf ? ", " : "");
			if (IS_SET(build[type].facing, BUILD_BRIDGE))
				sprintf(buf + strlen(buf), "%sbridge", *buf ? ", " : "");
			if (IS_SET(build[type].facing, BUILD_MOUNTAIN))
				sprintf(buf + strlen(buf), "%smountain", *buf ? ", " : "");
			if (IS_SET(build[type].facing, BUILD_DESERT))
				sprintf(buf + strlen(buf), "%sdesert", *buf ? ", " : "");
			if (IS_SET(build[type].facing, BUILD_FOREST))
				sprintf(buf + strlen(buf), "%sforest", *buf ? ", " : "");

			msg_to_char(ch, buf);

			return;
			}

		/* The 'reverse' room */
		if (build[type].reverse != -1) {
			to_rev = real_shift(ch->in_room, shift_dir[rev_dir[dir]][0], shift_dir[rev_dir[dir]][1]);

			if (!((IS_SET(build[type].reverse, BUILD_FIELD) && CLEAR_FIELD(to_rev)) || (IS_SET(build[type].reverse, BUILD_TUNNEL) && (BUILDING_TYPE(to_rev) == BUILDING_TUNNEL || BUILDING_TYPE(to_rev) == BUILDING_TUNNEL2) && IS_COMPLETE(to_rev)) || (IS_SET(build[type].reverse, BUILD_MOUNTAIN) && SECT(to_rev) == SECT_MOUNTAIN) || (IS_SET(build[type].reverse, BUILD_DESERT) && CLEAR_DESERT(to_rev)) || (IS_SET(build[type].reverse, BUILD_RIVER) && SECT(to_rev) == SECT_RIVER) || (IS_SET(build[type].reverse, BUILD_FOREST) && SECT(to_rev) == SECT_FOREST_4) || (IS_SET(build[type].reverse, BUILD_WATER) && (SECT(to_rev) == SECT_OCEAN || SECT(to_rev) == SECT_RIVER)))) {
				msg_to_char(ch, "You need to build with the reverse side facing ");

				if (IS_SET(build[type].reverse, BUILD_TUNNEL))
					msg_to_char(ch, "another tunnel.\r\n");
				else if (IS_SET(build[type].reverse, BUILD_FIELD))
					msg_to_char(ch, "cleared field.\r\n");
				else if (IS_SET(build[type].reverse, BUILD_WATER | BUILD_RIVER))
					msg_to_char(ch, "the water.\r\n");
				else if (IS_SET(build[type].reverse, BUILD_MOUNTAIN))
					msg_to_char(ch, "a mountain.\r\n");
				else if (IS_SET(build[type].reverse, BUILD_DESERT))
					msg_to_char(ch, "the desert.\r\n");
				else if (IS_SET(build[type].reverse, BUILD_FOREST))
					msg_to_char(ch, "the forest.\r\n");
				else if (IS_SET(build[type].reverse, BUILD_BRIDGE))
					msg_to_char(ch, "a bridge.\r\n");

				return;
				}
			}

		/* If we're going to be closing a room off, we need to kick people out */
		for (j = 0; j < build[type].height; j++)
			for (i = 0; i < build[type].width; i++) {
				while (world[map[j][i]].people && map[j][i] != ch->in_room)
					char_to_room(world[map[j][i]].people, to_room);
				while (world[map[j][i]].contents && map[j][i] != ch->in_room)
					obj_to_room(world[map[j][i]].contents, ch->in_room);
				}
		}

	/* Now set up the rooms, open or closed */
	for (j = 0; j < build[type].height; j++)
		for (i = 0; i < build[type].width; i++) {
			/* type2 for multi-build land recovery */
			if (SECT(map[j][i]) == SECT_FIELD)			world[map[j][i]].type2 = 0;
			else if (SECT(map[j][i]) == SECT_FOREST_4)	world[map[j][i]].type2 = 1;
			else if (SECT(map[j][i]) == SECT_DESERT)	world[map[j][i]].type2 = 2;

			/* Or if it's declared explicitly */
			if (build[type].type2 != -1)
				world[map[j][i]].type2 = build[type].type2;

			SECT(map[j][i]) = build[type].sect;
			world[map[j][i]].type = build[type].map[map_dir][j][i];

			/* Clean up set values */
			if (world[map[j][i]].name) {
				free(world[map[j][i]].name);
				world[map[j][i]].name = NULL;
				}
			if (world[map[j][i]].description) {
				free(world[map[j][i]].description);
				world[map[j][i]].description = NULL;
				}
			if (world[map[j][i]].icon) {
				free(world[map[j][i]].icon);
				world[map[j][i]].icon = NULL;
				}
			world[map[j][i]].build_value = 0;
			world[map[j][i]].base_affects = build[type].base_affects;
			SET_BIT(world[map[j][i]].affects, build[type].base_affects);

			/* special handling: each room in the map */
			switch (build[type].special) {
				case 0:
					world[map[j][i]].spare = id;
					break;
				case 3:
					GET_BUILD_VALUE(map[j][i]) = 1000;
					break;
				}

			/* Extra special handling for mines */
			if (BUILDING_TYPE(map[j][i]) == BUILDING_MINE && world[map[j][i]].type2 == 0) {
				world[map[j][i]].spare = number(40, 60);
				switch(number(0, 25)) {
					case 24:
					case 23:	world[map[j][i]].type2 = ITEM_MAT_SILVER;	world[map[j][i]].spare /= 2;	break;
					default:	world[map[j][i]].type2 = ITEM_MAT_IRON;		break;
					}
				}

			if (build[type].closed) {
				if (map[j][i] != ch->in_room)
					world[map[j][i]].home_room = world[ch->in_room].number;
				world[map[j][i]].building_entrance = -1;
				}
			if (!build[type].closed || map[j][i] == ch->in_room)
				setup_monument_resources(map[j][i], type);

			if (can_claim(ch) || world[map[j][i]].home_room != NOWHERE) {
				world[map[j][i]].owner = get_id_by_empire(ch);
				if (world[map[j][i]].home_room == NOWHERE)
					empire[e].territory++;
				}
			IS_DISMANTLING(map[j][i]) = FALSE;
			}

	/* type2 if it's declared explicitly (overrides setting above) */
	if (build[type].type2 != -1)
		world[ch->in_room].type2 = build[type].type2;

	/* ch->in_room is already set up, but we need to give it an exit */
	if (build[type].closed) {
		CREATE(world[ch->in_room].dir_option[dir], struct room_direction_data, 1);
		world[ch->in_room].dir_option[dir]->to_room = to_room;
		world[ch->in_room].dir_option[dir]->exit_info = 0;
		world[ch->in_room].dir_option[dir]->keyword = NULL;

		if (build[type].reverse != -1) {
			CREATE(world[ch->in_room].dir_option[rev_dir[dir]], struct room_direction_data, 1);
			world[ch->in_room].dir_option[rev_dir[dir]]->to_room = to_rev;
			world[ch->in_room].dir_option[rev_dir[dir]]->exit_info = 0;
			world[ch->in_room].dir_option[rev_dir[dir]]->keyword = NULL;
			}

		/* All entrances default to south */
		world[ch->in_room].building_entrance = rev_dir[dir];
		}

	GET_ACTION(ch) = ACT_BUILDING;
	GET_ACTION_ROOM(ch) = ch->in_room;
	GET_ACTION_ROTATION(ch) = last_action_rotation;

	msg_to_char(ch, "You start to build %s %s!\r\n", AN(build[type].name), build[type].name);
	sprintf(buf, "$n begins to build %s %s!", AN(build[type].name), build[type].name);
	act(buf, FALSE, ch, 0, 0, TO_ROOM);
	}


ACMD(do_upgrade) {
	if (BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER3 || BUILDING_TYPE(ch->in_room) == BUILDING_SHIPYARD2 || BUILDING_TYPE(ch->in_room) == BUILDING_TUNNEL2)
		msg_to_char(ch, "You can't upgrade it any more.\r\n");
	else if (BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER || BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER2) {
		if ((BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER && GET_SCIENCE(ch) < 4) || (BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER2 && GET_SCIENCE(ch) < 5))
			msg_to_char(ch, "You don't have the skill needed to upgrade this tower.\r\n");
		else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
			msg_to_char(ch, "You don't have permission to upgrade this tower.\r\n");
		else if (!IS_COMPLETE(ch->in_room))
			msg_to_char(ch, "You can't upgrade it until the original construction is complete.\r\n");
		else if (GET_ACTION(ch) != ACT_NONE)
			msg_to_char(ch, "You're already building.\r\n");
		else {
			GET_ACTION(ch) = ACT_BUILDING;
			GET_ACTION_ROOM(ch) = ch->in_room;
			GET_ACTION_ROTATION(ch) = last_action_rotation;

			if (BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER)
				world[ch->in_room].type = BUILDING_GUARD_TOWER2;
			else
				world[ch->in_room].type = BUILDING_GUARD_TOWER3;

			world[ch->in_room].res.logs = 4;
			world[ch->in_room].res.sticks = 30;
			world[ch->in_room].res.rocks = 0;
			world[ch->in_room].res.iron = 20 * (1+(BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER3));
			msg_to_char(ch, "You begin to upgrade the tower.\r\n");
			act("$n starts upgrading the tower.", FALSE, ch, 0, 0, TO_ROOM);
			}
		return;
		}
	else if (BUILDING_TYPE(ch->in_room) == BUILDING_SHIPYARD) {
		if (GET_SCIENCE(ch) < 4)
			msg_to_char(ch, "You don't have the skill needed to upgrade this shipyard.\r\n");
		else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
			msg_to_char(ch, "You don't have permission to upgrade this shipyard.\r\n");
		else if (!IS_COMPLETE(ch->in_room))
			msg_to_char(ch, "You can't upgrade it until the original construction is complete.\r\n");
		else if (GET_ACTION(ch) != ACT_NONE)
			msg_to_char(ch, "You're already building.\r\n");
		else {
			GET_ACTION(ch) = ACT_BUILDING;
			GET_ACTION_ROOM(ch) = ch->in_room;
			GET_ACTION_ROTATION(ch) = last_action_rotation;

			world[ch->in_room].type = BUILDING_SHIPYARD2;

			world[ch->in_room].res.logs = 75;
			world[ch->in_room].res.sticks = 0;
			world[ch->in_room].res.rocks = 0;
			world[ch->in_room].res.iron = 35;
			msg_to_char(ch, "You begin to upgrade the shipyard.\r\n");
			act("$n starts upgrading the shipyard.", FALSE, ch, 0, 0, TO_ROOM);
			}
		return;
		}
	else if (BUILDING_TYPE(ch->in_room) == BUILDING_TUNNEL) {
		if (GET_SCIENCE(ch) < 4)
			msg_to_char(ch, "You don't have the skill needed to upgrade this tunnel.\r\n");
		else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
			msg_to_char(ch, "You don't have permission to upgrade this tunnel.\r\n");
		else if (!IS_COMPLETE(ch->in_room))
			msg_to_char(ch, "You can't upgrade it until the original construction is complete.\r\n");
		else if (GET_ACTION(ch) != ACT_NONE)
			msg_to_char(ch, "You're already building.\r\n");
		else {
			GET_ACTION(ch) = ACT_BUILDING;
			GET_ACTION_ROOM(ch) = ch->in_room;
			GET_ACTION_ROTATION(ch) = last_action_rotation;

			world[ch->in_room].type = BUILDING_TUNNEL2;

			world[ch->in_room].res.logs = 20;
			world[ch->in_room].res.sticks = 0;
			world[ch->in_room].res.rocks = 0;
			world[ch->in_room].res.iron = 0;
			msg_to_char(ch, "You begin to upgrade the tunnel.\r\n");
			act("$n starts upgrading the tunnel.", FALSE, ch, 0, 0, TO_ROOM);
			}
		return;
		}
	else
		msg_to_char(ch, "You can only upgrade guard towers, shipyards, and tunnels.\r\n");
	}


ACMD(do_plant) {
	extern const char *crops[];
	Object obj;
	Creature c;
	bool found = FALSE;

	if (IS_NPC(ch))
		return;

	for (c = world[ch->in_room].people; c; c = c->next_in_room)
		if (!IS_NPC(c) && GET_ACTION(c) == ACT_PLANTING)
			found = TRUE;

	one_argument(argument, arg);

	if (GET_ACTION(ch) == ACT_PLANTING)
		msg_to_char(ch, "You're already planting something.\r\n");
	else if (GET_ACTION(ch) != ACT_NONE)
		msg_to_char(ch, "You're already busy doing something else.\r\n");
	else if (SECT(ch->in_room) != SECT_FIELD)
		msg_to_char(ch, "You can only plant in open field.\r\n");
	else if (found)
		msg_to_char(ch, "Someone else is already planting here.\r\n");
	else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
		msg_to_char(ch, "You don't have permission to plant anything here.\r\n");
	else if (real_empire(world[ch->in_room].owner) != -1 && GET_RANK(ch) < empire[real_empire(world[ch->in_room].owner)].priv[PRIV_HARVEST])
		msg_to_char(ch, "You don't have permission to plant crops.\r\n");
	else if (!*arg)
		msg_to_char(ch, "What do you want to plant?\r\n");
	else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying)))
		msg_to_char(ch, "You don't seem to have any %s.\r\n", arg);
	else if (!OBJ_FLAGGED(obj, ITEM_PLANTABLE))
		msg_to_char(ch, "You can't plant that!\r\n");
	else {
		SECT(ch->in_room) = SECT_SEEDED;
		world[ch->in_room].type = GET_OBJ_VAL(obj, 1);
		extract_obj(obj);
		GET_BUILD_VALUE(ch->in_room) = 120;
		GET_ACTION(ch) = ACT_PLANTING;
		GET_ACTION_TIMER(ch) = 4;
		GET_ACTION_ROOM(ch) = ch->in_room;
		GET_ACTION_ROTATION(ch) = last_action_rotation;
		msg_to_char(ch, "You begin planting %s here.\r\n", crops[(int) world[ch->in_room].type]);
		sprintf(buf, "$n kneels and begins to plant %s here.", crops[(int) world[ch->in_room].type]);
		act(buf, FALSE, ch, 0, 0, TO_ROOM);
		}
	}


room_rnum create_room(room_vnum vnum) {
	Room new_world;
	Creature c;
	Object o;
	int i, j, n = 0;
	bool found = FALSE;

	if (vnum < MAP_SIZE) {
		syslog(0, TRUE, "SYSERR: create_room() attempting to create low vnum %d", vnum);
		return NOWHERE;
		}

	if (real_room(vnum) != NOWHERE) {
		syslog(0, TRUE, "SYSERR: create_room() room %d already exists", vnum);
		return NOWHERE;
		}

	CREATE(new_world, struct room_data, top_of_world+2);

	for (i = 0; i <= top_of_world; i++)
		if (world[i].number < vnum)
			new_world[i] = world[i];
		else if (world[i].number > vnum) {
			if (!found) {
				found = TRUE;

				new_world[i].number = vnum;
				new_world[i].zone = NUM_MAP_ZONES;
				new_world[i].sector_type = SECT_INSIDE;
				for (j = 0; j < NUM_OF_DIRS; j++)
					new_world[i].dir_option[j] = NULL;
				new_world[i].type = 0;
				new_world[i].type2 = 0;
				new_world[i].build_value = 0;
				new_world[i].building_entrance = 0;
				new_world[i].spare = 0;
				new_world[i].owner = 0;
				new_world[i].home_room = NOWHERE;
				new_world[i].dismantling = 0;
				new_world[i].res.iron = 0;
				new_world[i].res.rocks = 0;
				new_world[i].res.logs = 0;
				new_world[i].res.sticks = 0;
				new_world[i].light = 0;
				new_world[i].contents = NULL;
				new_world[i].people = NULL;
				n = i;
				}

			new_world[i+1] = world[i];
			for (c = world[i].people; c; c = c->next_in_room)
				c->in_room = c->in_room + 1;
			for (o = world[i].contents; o; o = o->next_content)
				o->in_room = o->in_room + 1;
			}

	if (!found) {
		new_world[i].number = vnum;
		new_world[i].zone = NUM_MAP_ZONES;
		new_world[i].sector_type = SECT_INSIDE;
		for (j = 0; j < NUM_OF_DIRS; j++)
			new_world[i].dir_option[j] = NULL;
		new_world[i].type = 0;
		new_world[i].type2 = 0;
		new_world[i].build_value = 0;
		new_world[i].building_entrance = 0;
		new_world[i].spare = 0;
		new_world[i].owner = 0;
		new_world[i].home_room = NOWHERE;
		new_world[i].dismantling = 0;
		new_world[i].res.iron = 0;
		new_world[i].res.rocks = 0;
		new_world[i].res.logs = 0;
		new_world[i].res.sticks = 0;
		new_world[i].light = 0;
		new_world[i].contents = NULL;
		new_world[i].people = NULL;
		n = i;
		}

	top_of_world++;

	free(world);
	world = new_world;

	for (i = 0; i <= top_of_world; i++)
		for (j = 0; j < NUM_OF_DIRS; j++)
			if (world[i].dir_option[j] && world[i].dir_option[j]->to_room >= n)
				world[i].dir_option[j]->to_room++;

	return n;
	}


void delete_room(room_rnum rnum) {
	void Crash_rentsave(Creature ch);

	Room new_world;
	Creature c;
	Object o;
	int i, j;

	if (rnum > top_of_world || world[rnum].number < MAP_SIZE) {
		syslog(0, TRUE, "SYSERR: delete_room() attempting to delete rnum %d", rnum);
		return;
		}

	/* Remove the people */
	while (world[rnum].people) {
		if (!IS_NPC(world[rnum].people)) {
			Crash_rentsave(world[rnum].people);
			save_char(world[rnum].people, NOWHERE);
			}
		extract_char(world[rnum].people);
		}

	/* Remove the objects */
	while (world[rnum].contents)
		extract_obj(world[rnum].contents);

	CREATE(new_world, struct room_data, top_of_world);

	for (i = 0; i < top_of_world; i++)
		if (i < rnum)
			new_world[i] = world[i];
		else if (i >= rnum) {
			for (c = world[i+1].people; c; c = c->next_in_room)
				if (c->in_room != NOWHERE)
					c->in_room = i;
			for (o = world[i+1].contents; o; o = o->next_content)
				if (o->in_room != NOWHERE)
					o->in_room = i;
			new_world[i] = world[i+1];
			}

	top_of_world--;

	free(world);
	world = new_world;

	for (i = 0; i <= top_of_world; i++)
		for (j = 0; j < NUM_OF_DIRS; j++) {
			if (world[i].dir_option[j] && world[i].dir_option[j]->to_room == rnum) {
				if (world[i].dir_option[j]->keyword)
					free(world[i].dir_option[j]->keyword);
				free(world[i].dir_option[j]);
				world[i].dir_option[j] = NULL;
				}
			if (world[i].dir_option[j] && world[i].dir_option[j]->to_room > rnum)
				world[i].dir_option[j]->to_room--;
			}
	}


room_vnum find_free_vnum(void) {
	room_vnum i;

	for (i = MAP_SIZE;; i++)
		if (real_room(i) == NOWHERE)
			return i;
	/* We should NEVER get here.. but if we do.. */
	log("SYSERR: find_free_vnum() ended the for() loop");
	exit(1);
	}


/*
 * subcmd 0 = designate
 * subcmd 1 = redesignate
 */
ACMD(do_designate) {
	extern const int room_designate_flags[NUM_RTYPES][2];

	int dir = -1, type, b, r = HOME_ROOM(ch->in_room);
	Object o;
	room_rnum new;

	const char *rtypes[] = {
		"\r", "armory", "bedroom", "dining room",
		"forge", "great hall", "hall", "kitchen", "sitting room",
		"study", "throne room", "storage", "vault",
		"\r", "\r", "\r", "\r",	/* ship room types */
		"tunnel", "skybridge", "baths", "shield racks",
		"armor storage", "closet", "\n"
		};

	/*
	 * arg = direction
	 * buf = room type
	 */
	if (!subcmd)
		argument = one_argument(argument, arg);

	skip_spaces(&argument);
	strcpy(buf, argument);

	if ((b = find_building_list_entry(ch->in_room, FIND_BUILD_NORMAL)) == -1)
		msg_to_char(ch, "You can't designate rooms here!\r\n");
	else if (!subcmd && ((dir = parse_direction(arg)) < 0))
		msg_to_char(ch, "Which direction would you like to designate a room?\r\n");
	else if ((type = search_block(buf, rtypes, FALSE)) < 0) {
		msg_to_char(ch, "Invalid room type.  Valid choices are: armory");
		for (type = 2; str_cmp(rtypes[type], "\n"); type++)
			if (strcmp(rtypes[type], "\r"))
				msg_to_char(ch, ", %s", rtypes[type]);
		}
	else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
		msg_to_char(ch, "You don't have permission to designate rooms here.\r\n");
	else if (GET_LOYALTY(ch) && GET_RANK(ch) < empire[real_empire(GET_LOYALTY(ch))].priv[PRIV_BUILD])
		msg_to_char(ch, "You don't have permission to designate rooms.\r\n");
	else if (!subcmd && SECT(ch->in_room) != SECT_INSIDE && dir != world[ch->in_room].building_entrance)
		msg_to_char(ch, "You may only designate %s from here.\r\n", dirs[(int) world[ch->in_room].building_entrance]);
	else if (IS_OUTDOORS(ch))
		msg_to_char(ch, "You can't designate outside of a building.\r\n");
	else if (SECT(ch->in_room) != SECT_INSIDE && subcmd)
		msg_to_char(ch, "You can't redesignate here.\r\n");
	else if (build[b].max_rooms <= 0)
		msg_to_char(ch, "You can't designate here.\r\n");
	else if (!subcmd && world[ch->in_room].dir_option[dir] && world[ch->in_room].dir_option[dir]->to_room != NOWHERE)
		msg_to_char(ch, "There is already a room that direction.\r\n");
	else if (!subcmd && world[r].inside_rooms >= build[b].max_rooms)
		msg_to_char(ch, "There's no more free space.\r\n");
	else if (IS_SET(room_designate_flags[type][0], DES_NEVER))
		msg_to_char(ch, "You can't designate that type of room!\r\n");
	else if (room_designate_flags[type][0] != 0 && !IS_SET(build[b].designate_flags, room_designate_flags[type][0]))
		msg_to_char(ch, "You can't designate that here!\r\n");
	else if (room_designate_flags[type][1] != 0 && IS_SET(build[b].designate_flags, room_designate_flags[type][0]))
		msg_to_char(ch, "You can't designate that here!\r\n");
	else {
		if (subcmd)
			new = ch->in_room;
		else {
			if (!world[ch->in_room].dir_option[dir])
				CREATE(world[ch->in_room].dir_option[dir], struct room_direction_data, 1);
			world[ch->in_room].dir_option[dir]->to_room = (new = create_room(find_free_vnum()));
			world[ch->in_room].dir_option[dir]->exit_info = 0;
			world[ch->in_room].dir_option[dir]->keyword = NULL;

			CREATE(world[new].dir_option[rev_dir[dir]], struct room_direction_data, 1);
			world[new].dir_option[rev_dir[dir]]->to_room = ch->in_room;
			world[new].dir_option[rev_dir[dir]]->exit_info = 0;
			world[new].dir_option[rev_dir[dir]]->keyword = NULL;

			world[r].inside_rooms++;
			}

		/* remove old board */
		if (world[ch->in_room].type == RTYPE_STUDY)
			for (o = world[ch->in_room].contents; o; o = o->next_content)
				if (GET_OBJ_VNUM(o) == BOARD_MORT)
					extract_obj(o);

		/* add new board */
		if (type == RTYPE_STUDY)
			obj_to_room(read_object(BOARD_MORT, VIRTUAL), new);

		/* set applicable values */
		world[new].type = type;
		world[new].home_room = world[r].number;
		world[new].owner = world[r].owner;

		/* send messages */
		if (subcmd) {
			msg_to_char(ch, "You redesignate this room as a %s.\r\n", rtypes[type]);
			sprintf(buf, "$n redesignates this room as a %s.\r\n", rtypes[type]);
			act(buf, FALSE, ch, 0, 0, TO_ROOM);
			}
		else {
			msg_to_char(ch, "You designate the room %s as a %s.\r\n", dirs[dir], rtypes[type]);
			sprintf(buf, "$n designates the room %s as a %s.\r\n", dirs[dir], rtypes[type]);
			act(buf, FALSE, ch, 0, 0, TO_ROOM);
			}
		}
	}


void process_build(Creature ch, room_rnum room) {
	void read_empire_territory();

	struct resource_data *res = &world[room].res;
	Object obj = NULL;
	Creature c = NULL;
	bool found = FALSE;

	if (res->logs && !found) {
		for (obj = ch->carrying; obj; obj = obj->next_content)
			if (!found && GET_OBJ_VNUM(obj) == o_LOG && (found = 1) && (res->logs--))
				break;
		if (!found)
			for (obj = world[room].contents; obj; obj = obj->next_content)
				if (!found && GET_OBJ_VNUM(obj) == o_LOG && (found = 1) && (res->logs--))
					break;
		}

	if (res->sticks && !found) {
		for (obj = ch->carrying; obj; obj = obj->next_content)
			if (!found && GET_OBJ_VNUM(obj) == o_STICK && (found = 1) && (res->sticks--))
				break;
		if (!found)
			for (obj = world[room].contents; obj; obj = obj->next_content)
				if (!found && GET_OBJ_VNUM(obj) == o_STICK && (found = 1) && (res->sticks--))
					break;
		}

	if (res->rocks && !found) {
		for (obj = ch->carrying; obj; obj = obj->next_content)
			if (!found && GET_OBJ_VNUM(obj) == o_ROCK && (found = 1) && (res->rocks--))
				break;
		if (!found)
			for (obj = world[room].contents; obj; obj = obj->next_content)
				if (!found && GET_OBJ_VNUM(obj) == o_ROCK && (found = 1) && (res->rocks--))
					break;
		}

	if (res->iron && !found) {
		for (obj = ch->carrying; obj; obj = obj->next_content)
			if (!found && GET_OBJ_VNUM(obj) == o_IRON && (found = 1) && (res->iron--))
				break;
		if (!found)
			for (obj = world[room].contents; obj; obj = obj->next_content)
				if (!found && GET_OBJ_VNUM(obj) == o_IRON && (found = 1) && (res->iron--))
					break;
		}

	/* small chance of error here.. */
	if (!IS_COMPLETE(room)) {
		if (!found || !obj) {
			msg_to_char(ch, "You run out of resources and stop building.\r\n");
			act("$n runs out of resources and stops building.", FALSE, ch, 0, 0, TO_ROOM);
			GET_ACTION(ch) = ACT_NONE;
			return;
			}

		act("$n places $p carefully in the structure.", FALSE, ch, obj, 0, TO_ROOM);
		act("You carefully place $p in the structure.", FALSE, ch, obj, 0, TO_CHAR);
		}

	if (IS_COMPLETE(room)) {
		msg_to_char(ch, "You complete the construction!\r\n");
		act("$n has completed the construction!", FALSE, ch, 0, 0, TO_ROOM);
		for (c = world[ch->in_room].people; c; c = c->next_in_room)
			if (!IS_NPC(c) && GET_ACTION(c) == ACT_BUILDING)
				GET_ACTION(c) = ACT_NONE;

		if (SECT(room) == SECT_MONUMENT_OPEN || SECT(room) == SECT_MONUMENT_CLOSED)
			read_empire_territory();
		}
	if (obj)
		extract_obj(obj);
	}


void disassociate_building(room_rnum room) {
	int i, j, k, sect = SECT_FIELD;

	world[room].inside_rooms = 0;
	IS_DISMANTLING(room) = 0;
	for (i = 0; i < NUM_OF_DIRS; i++)
		if (world[room].dir_option[i]) {
			if (world[room].dir_option[i]->keyword)
				free(world[room].dir_option[i]->keyword);
			free(world[room].dir_option[i]);
			world[room].dir_option[i] = NULL;
			}

	if (world[room].name) {
		free(world[room].name);
		world[room].name = NULL;
		}

	if (world[room].description) {
		free(world[room].description);
		world[room].description = NULL;
		}

	if (world[room].icon) {
		free(world[room].icon);
		world[room].icon = NULL;
		}

	world[room].base_affects = 0;
	world[room].affects = 0;

	if ((k = find_building_list_entry(room, FIND_BUILD_NORMAL)) != -1) {
		if (IS_SET(build[k].built_on, BUILD_WATER | BUILD_RIVER))
			sect = SECT_RIVER;
		else if (IS_SET(build[k].built_on, BUILD_FOREST) && (count_bits(build[k].built_on) < 2 || world[room].type2 == 1))
			sect = SECT_FOREST_4;
		else if (IS_SET(build[k].built_on, BUILD_DESERT) && (count_bits(build[k].built_on) < 2 || world[room].type2 == 2))
			sect = SECT_DESERT;
		else if (IS_SET(build[k].built_on, BUILD_MOUNTAIN | BUILD_TUNNEL))
			sect = SECT_MOUNTAIN;
		else
			sect = SECT_FIELD;
		}

	SECT(room) = sect;
	world[room].type = 0;
	if (SECT(room) != SECT_MOUNTAIN)
		world[room].type2 = 0;

	for (j = 0; j <= top_of_world; j++) {
		if (HOME_ROOM(j) != room || j == room)
			continue;
		while (world[j].people)
			char_to_room(world[j].people, room);
		while (world[j].contents)
			obj_to_room(world[j].contents, room);

		world[j].home_room = NOWHERE;
		if (j < MAP_SIZE) {
			SECT(j) = sect;
			world[j].type = 0;
			if (SECT(j) != SECT_MOUNTAIN)
				world[j].type2 = 0;
			}
		else {
			delete_room(j);
			j--;
			}
		}
	}


void process_dismantling(Creature ch, room_rnum room) {
	struct resource_data *res = &world[room].res;
	Object obj = NULL;
	Creature c = NULL;
	bool found = FALSE;

	if (res->logs && !found) {
		obj = read_object(o_LOG, VIRTUAL);
		found = TRUE;
		res->logs--;
		}

	if (res->sticks && !found) {
		obj = read_object(o_STICK, VIRTUAL);
		found = TRUE;
		res->sticks--;
		}

	if (res->rocks && !found) {
		obj = read_object(o_ROCK, VIRTUAL);
		found = TRUE;
		res->rocks--;
		}

	if (res->iron && !found) {
		obj = read_object(o_IRON, VIRTUAL);
		found = TRUE;
		res->iron--;
		}

	if (obj) {
		if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
			obj_to_room(obj, ch->in_room);
		else
			obj_to_char(obj, ch);
		act("$n removes $p from the structure.", FALSE, ch, obj, 0, TO_ROOM);
		act("You carefully remove $p from the structure.", FALSE, ch, obj, 0, TO_CHAR);
		}

	if (IS_COMPLETE(room)) {
		msg_to_char(ch, "You finish dismantling the building.\r\n");
		act("$n finishes dismantling the building.", FALSE, ch, 0, 0, TO_ROOM);
		for (c = world[ch->in_room].people; c; c = c->next_in_room)
			if (!IS_NPC(c) && GET_ACTION(c) == ACT_DISMANTLING)
				GET_ACTION(c) = ACT_NONE;
		disassociate_building(room);
		}
	}


ACMD(do_dismantle) {
	Object obj, next_obj;
	Creature targ, next_targ;
	int i, j;

	if (IS_NPC(ch))
		return;

	if (GET_ACTION(ch) == ACT_DISMANTLING) {
		msg_to_char(ch, "You stop dismantling the building.\r\n");
		act("$n stops dismantling the building.", FALSE, ch, 0, 0, TO_ROOM);
		GET_ACTION(ch) = ACT_NONE;
		return;
		}

	if (GET_ACTION(ch) != ACT_NONE) {
		msg_to_char(ch, "You're kinda busy right now.\r\n");
		return;
		}

	if (IS_DISMANTLING(ch->in_room)) {
		msg_to_char(ch, "You begin to dismantle the building.\r\n");
		act("$n begins to dismantle the building.", FALSE, ch, 0, 0, TO_ROOM);
		GET_ACTION(ch) = ACT_DISMANTLING;
		GET_ACTION_ROTATION(ch) = last_action_rotation;
		GET_ACTION_ROOM(ch) = ch->in_room;
		return;
		}

	if ((i = find_building_list_entry(ch->in_room, FIND_BUILD_NORMAL)) == -1) {
		msg_to_char(ch, "You can't dismantle this building.\r\n");
		return;
		}

	if (!CAN_USE_ROOM(ch, ch->in_room, 1)) {
		msg_to_char(ch, "You don't have permission to dismantle this building.\r\n");
		return;
		}
	if (GET_LOYALTY(ch) && GET_RANK(ch) < empire[real_empire(GET_LOYALTY(ch))].priv[PRIV_BUILD]) {
		msg_to_char(ch, "You don't have permission to dismantle anything.\r\n");
		return;
		}
	if (GET_INTELLIGENCE(ch) < build[i].intelligence || GET_SCIENCE(ch) < build[i].science) {
		msg_to_char(ch, "You don't have the skill needed to dismantle this building properly.\r\n");
		return;
		}

	for (j = MAP_SIZE; j <= top_of_world; j++) {
		if (HOME_ROOM(j) != ch->in_room)
			continue;
		for (obj = world[j].contents; obj; obj = next_obj) {
			next_obj = obj->next_content;
			obj_to_room(obj, ch->in_room);
			if (GET_OBJ_TYPE(obj) == ITEM_BOARD)
				extract_obj(obj);
			}
		for (targ = world[j].people; targ; targ = next_targ) {
			next_targ = targ->next_in_room;
			char_from_room(targ);
			char_to_room(targ, ch->in_room);
			}
		}

	if (!IS_COMPLETE(ch->in_room)) {
		world[ch->in_room].res.logs = (build[i].logs - world[ch->in_room].res.logs) / 2;
		world[ch->in_room].res.sticks = (build[i].sticks - world[ch->in_room].res.sticks) / 2;
		world[ch->in_room].res.rocks = (build[i].rocks - world[ch->in_room].res.rocks) / 2;
		world[ch->in_room].res.iron = (build[i].iron - world[ch->in_room].res.iron) / 2;
		}
	else {
		world[ch->in_room].res.logs = build[i].logs / 2;
		world[ch->in_room].res.sticks = build[i].sticks / 2;
		world[ch->in_room].res.rocks = build[i].rocks / 2;
		world[ch->in_room].res.iron = build[i].iron / 2;
		}

	IS_DISMANTLING(ch->in_room) = TRUE;
	GET_ACTION(ch) = ACT_DISMANTLING;
	GET_ACTION_ROTATION(ch) = last_action_rotation;
	GET_ACTION_ROOM(ch) = ch->in_room;

	msg_to_char(ch, "You begin to dismantle the building.\r\n\r\n");
	act("$n begins to dismantle the building.\r\n", FALSE, ch, 0, 0, TO_ROOM);
	process_dismantling(ch, ch->in_room);
	WAIT_STATE(ch, 2 RL_SEC);
	}


ACMD(do_lay) {
	int i;
	Object obj, next_obj;

	for (i = 0, obj = ch->carrying; obj; obj = obj->next_content)
		if (GET_OBJ_VNUM(obj) == o_ROCK)
			i++;
	for (obj = world[ch->in_room].contents; obj; obj = obj->next_content)
		if (GET_OBJ_VNUM(obj) == o_ROCK)
			i++;

	if (!CAN_USE_ROOM(ch, ch->in_room, 1))
		msg_to_char(ch, "You can't lay road here!\r\n");
	else if (real_empire(GET_LOYALTY(ch)) != -1 && GET_RANK(ch) < empire[real_empire(GET_LOYALTY(ch))].priv[PRIV_BUILD])
		msg_to_char(ch, "You don't have permission to lay road.\r\n");
	else if (GET_INTELLIGENCE(ch) < 2 || GET_SCIENCE(ch) < 1)
		msg_to_char(ch, "You don't have the skill to properly do that.\r\n");
	else if (SECT(ch->in_room) == SECT_ROAD && !world[ch->in_room].type) {
		for (i = 0; i < 20; i++) {
			obj = read_object(o_ROCK, VIRTUAL);
			if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
				obj_to_room(obj, ch->in_room);
			else
				obj_to_char(obj, ch);
			}
		msg_to_char(ch, "You pull up the road.\r\n");
		act("$n pulls up the road.", FALSE, ch, 0, 0, TO_ROOM);
		if (world[ch->in_room].type2 == 1)
			SECT(ch->in_room) = SECT_DESERT;
		else
			SECT(ch->in_room) = SECT_FIELD;
		WAIT_STATE(ch, PULSE_VIOLENCE * 2);
		}
	else if (SECT(ch->in_room) != SECT_FIELD && SECT(ch->in_room) != SECT_DESERT)
		msg_to_char(ch, "You can't lay road here!\r\n");
	else if (i < 20)
		msg_to_char(ch, "You don't have enough rocks to do that.\r\n");
	else {
		for (i = 20, obj = ch->carrying; obj && i > 0; obj = next_obj) {
			next_obj = obj->next_content;
			if (GET_OBJ_VNUM(obj) == o_ROCK) {
				i--;
				extract_obj(obj);
				}
			}
		for (obj = world[ch->in_room].contents; obj && i > 0; obj = next_obj) {
			next_obj = obj->next_content;
			if (GET_OBJ_VNUM(obj) == o_ROCK) {
				i--;
				extract_obj(obj);
				}
			}
		msg_to_char(ch, "You lay a road here.\r\n");
		act("$n lays a road here.", FALSE, ch, 0, 0, TO_ROOM);
		world[ch->in_room].type = 0;
		if (SECT(ch->in_room) == SECT_DESERT)
			world[ch->in_room].type2 = 1;
		else
			world[ch->in_room].type2 = 0;
		SECT(ch->in_room) = SECT_ROAD;
		WAIT_STATE(ch, PULSE_VIOLENCE * 2);
		}
	}


void disperse_resources(room_rnum room) {
	int i, j;

	if ((i = find_building_list_entry(room, FIND_BUILD_NORMAL)) == -1)
		return;

	if (str_cmp(build[i].name, "\n")) {
		for (j = build[i].logs; j; j--)
			obj_to_room(read_object(o_LOG, VIRTUAL), room);
		for (j = build[i].sticks; j; j--)
			obj_to_room(read_object(o_STICK, VIRTUAL), room);
		for (j = build[i].rocks; j; j--)
			obj_to_room(read_object(o_ROCK, VIRTUAL), room);
		for (j = build[i].iron; j; j--)
			obj_to_room(read_object(o_IRON, VIRTUAL), room);
		}
	}