roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * property.h
 *	 Code dealing with properties
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "property.h"
#include "commands.h"
#include "guilds.h"
#include "dm.h"
#include "login.h"
#include "move.h"
#include <sstream>
#include <iomanip>
#include <locale>


//*********************************************************************
//						PartialOwner
//*********************************************************************

PartialOwner::PartialOwner() {
	name = "";
	zero(flags, sizeof(flags));
}

void PartialOwner::defaultFlags(PropType type) {
	switch(type) {
	case PROP_SHOP:
		setFlag(PROP_SHOP_CAN_STOCK);
		break;
	default:
		break;
	}
}

bstring PartialOwner::getName() const { return(name); }
void PartialOwner::setName(bstring str) { name = str; }

bool PartialOwner::flagIsSet(int flag) const {
	return(flags[flag/8] & 1<<(flag%8));
}
void PartialOwner::setFlag(int flag) {
	flags[flag/8] |= 1<<(flag%8);
}
void PartialOwner::clearFlag(int flag) {
	flags[flag/8] &= ~(1<<(flag%8));
}
bool PartialOwner::toggleFlag(int flag) {
	if(flagIsSet(flag))
		clearFlag(flag);
	else
		setFlag(flag);
	return(flagIsSet(flag));
}

void PartialOwner::load(xmlNodePtr rootNode) {
	xml::copyPropToBString(name, rootNode, "Name");
	loadBits(rootNode, flags);
}

void PartialOwner::save(xmlNodePtr rootNode) const {
	xmlNodePtr curNode = xml::newStringChild(rootNode, "Owner") ;

	xml::newProp(curNode, "Name", name.c_str());
	for(int i=0; i<32; i++) {
		if(BIT_ISSET(flags, i))
			saveBit(curNode, i);
	}
}

//*********************************************************************
//						Property
//*********************************************************************

Property::Property() {
	guild = 0;
	owner = dateFounded = location = "";
	logType = LOG_PARTIAL;
	type = PROP_NONE;
	zero(flags, sizeof(flags));
}

//*********************************************************************
//						flagIsSet
//*********************************************************************

bool Property::flagIsSet(int flag) const {
	return(flags[flag/8] & 1<<(flag%8));
}

//*********************************************************************
//						setFlag
//*********************************************************************

void Property::setFlag(int flag) {
	flags[flag/8] |= 1<<(flag%8);
}

//*********************************************************************
//						clearFlag
//*********************************************************************

void Property::clearFlag(int flag) {
	flags[flag/8] &= ~(1<<(flag%8));
}

//*********************************************************************
//						toggleFlag
//*********************************************************************

bool Property::toggleFlag(int flag) {
	if(flagIsSet(flag))
		clearFlag(flag);
	else
		setFlag(flag);
	return(flagIsSet(flag));
}

//*********************************************************************
//						getGuild
//*********************************************************************

int Property::getGuild() const { return(guild); }

//*********************************************************************
//						getArea
//*********************************************************************

bstring Property::getArea() const { return(area); }

//*********************************************************************
//						getOwner
//*********************************************************************

bstring Property::getOwner() const { return(owner); }

//*********************************************************************
//						getName
//*********************************************************************

bstring Property::getName() const { return(name); }

//*********************************************************************
//						getDateFounded
//*********************************************************************

bstring Property::getDateFounded() const { return(dateFounded); }

//*********************************************************************
//						getLocation
//*********************************************************************

bstring Property::getLocation() const { return(location); }

//*********************************************************************
//						getType
//*********************************************************************

PropType Property::getType() const { return(type); }

//*********************************************************************
//						getTypeStr
//*********************************************************************

bstring	Property::getTypeStr() const { return(getTypeStr(type)); }

//*********************************************************************
//						getLogType
//*********************************************************************

PropLog Property::getLogType() const { return(logType); }

//*********************************************************************
//						setGuild
//*********************************************************************

void Property::setGuild(int g) { guild = g; }

//*********************************************************************
//						setArea
//*********************************************************************

void Property::setArea(bstring str) { area = str; }

//*********************************************************************
//						setOwner
//*********************************************************************

void Property::setOwner(bstring str) { owner = str; }

//*********************************************************************
//						setName
//*********************************************************************

void Property::setName(bstring str) { name = str; }

//*********************************************************************
//						setDateFounded
//*********************************************************************

void Property::setDateFounded() {
	long    t = time(0);
	dateFounded = ctime(&t);
	dateFounded.trim();
}

//*********************************************************************
//						setLocation
//*********************************************************************

void Property::setLocation(bstring str) { location = str; }

//*********************************************************************
//						setType
//*********************************************************************

void Property::setType(PropType t) { type = t; }

//*********************************************************************
//						setLogType
//*********************************************************************

void Property::setLogType(PropLog t) { logType = t; }

//*********************************************************************
//						load
//*********************************************************************

void Property::load(xmlNodePtr rootNode) {
	xmlNodePtr childNode, curNode = rootNode->children;
	bstring temp = "";
	CatRef low;

	while(curNode) {
			 if(NODE_NAME(curNode, "Owner")) xml::copyToBString(owner, curNode);
		else if(NODE_NAME(curNode, "Area")) xml::copyToBString(area, curNode);
		else if(NODE_NAME(curNode, "Name")) xml::copyToBString(name, curNode);
		else if(NODE_NAME(curNode, "DateFounded")) xml::copyToBString(dateFounded, curNode);
		else if(NODE_NAME(curNode, "Location")) xml::copyToBString(location, curNode);
		else if(NODE_NAME(curNode, "Guild")) xml::copyToNum(guild, curNode);
		else if(NODE_NAME(curNode, "Type")) type = (PropType)xml::toNum<int>(curNode);
		else if(NODE_NAME(curNode, "Flags")) loadBits(curNode, flags);

		else if(NODE_NAME(curNode, "Ranges")) {
			childNode = curNode->children;
			while(childNode) {
				if(NODE_NAME(childNode, "Range")) {
					Range r;
					r.load(childNode);

					// find the first in the range
					if(!low.id)
						low = r.low;

					ranges.push_back(r);
				}
				childNode = childNode->next;
			}
		}
		else if(NODE_NAME(curNode, "PartialOwners")) {
			childNode = curNode->children;
			while(childNode) {
				if(NODE_NAME(childNode, "Owner")) {
					PartialOwner po;
					po.load(childNode);
					if(po.getName() != "")
						partialOwners.push_back(po);
				}
				childNode = childNode->next;
			}
		}
		else if(NODE_NAME(curNode, "LogType")) logType = (PropLog)xml::toNum<int>(curNode);
		else if(NODE_NAME(curNode, "Log")) {
			childNode = curNode->children;
			while(childNode) {
				if(NODE_NAME(childNode, "Entry")) {
					xml::copyToBString(temp, childNode);
					log.push_back(temp);
				}
				childNode = childNode->next;
			}
		}
		curNode = curNode->next;
	}

	// backwards compatability - removable when all are updated
	if(type != PROP_STORAGE && area == "") {
		// load intro room, find the out exit, look at the room info
		UniqueRoom* room=0;
		if(loadRoom(low, &room)) {
			for(Exit* ext : room->exits) {
				if(ext->target.room.area != "shop" && low.area != ext->target.room.area) {
					area = ext->target.room.area;
					break;
				}
			}
		}
	}
}

//*********************************************************************
//						save
//*********************************************************************

void Property::save(xmlNodePtr rootNode) const {
	xmlNodePtr childNode, curNode = xml::newStringChild(rootNode, "Property");

	xml::saveNonNullString(curNode, "Owner", owner.c_str());
	xml::saveNonNullString(curNode, "Area", area.c_str());
	xml::saveNonNullString(curNode, "Name", name.c_str());
	xml::saveNonNullString(curNode, "DateFounded", dateFounded.c_str());
	xml::saveNonNullString(curNode, "Location", location.c_str());
	xml::saveNonZeroNum(curNode, "Guild", guild);
	xml::saveNonZeroNum(curNode, "Type", (int)type);
	saveBits(curNode, "Flags", 32, flags);

	if(!ranges.empty()) {
		std::list<Range>::const_iterator rt;
		childNode = xml::newStringChild(curNode, "Ranges");

		for(rt = ranges.begin() ; rt != ranges.end() ; rt++)
			(*rt).save(childNode, "Range");
	}

	if(!partialOwners.empty()) {
		std::list<PartialOwner>::const_iterator pt;
		childNode = xml::newStringChild(curNode, "PartialOwners");

		for(pt = partialOwners.begin() ; pt != partialOwners.end() ; pt++)
			(*pt).save(childNode);
	}
	xml::saveNonZeroNum(curNode, "LogType", logType);
	if(!log.empty()) {
		std::list<bstring>::const_iterator it;
		childNode = xml::newStringChild(curNode, "Log");

		for(it = log.begin() ; it != log.end() ; it++) {
			xml::saveNonNullString(childNode, "Entry", (*it).c_str());
		}
	}
}

//*********************************************************************
//						getTypeStr
//*********************************************************************

bstring Property::getTypeStr(PropType propType) {
	switch(propType) {
	case PROP_STORAGE:
		return("storage room");
	case PROP_SHOP:
		return("shop");
	case PROP_GUILDHALL:
		return("guild hall");
	case PROP_HOUSE:
		return("personal house");
	default:
		break;
	}
	return("unknown type");
}

//*********************************************************************
//						getTypeArea
//*********************************************************************

bstring Property::getTypeArea(PropType propType) {
	switch(propType) {
	case PROP_SHOP:
		return("shop");
	case PROP_STORAGE:
		return("stor");
	case PROP_GUILDHALL:
		return("guild");
	case PROP_HOUSE:
		return("house");
	default:
		break;
	}

	return("");
}

//*********************************************************************
//						getLogTypeStr
//*********************************************************************

bstring Property::getLogTypeStr() const {
	switch(logType) {
	case LOG_NONE:
		return("This property is not recording actions.");
		break;
	case LOG_PARTIAL:
		return("This property is recording all actions of partial owners.");
		break;
	case LOG_ALL:
	default:
		break;
	}
	return("This property is recording all actions.");
}

//*********************************************************************
//						addRange
//*********************************************************************

void Property::addRange(CatRef cr) {
	// first of all, let us intelligently try to update existing ranges
	std::list<Range>::iterator rt;
	for(rt = ranges.begin() ; rt != ranges.end() ; rt++) {
		if((*rt).isArea(cr.area) && (*rt).high == cr.id - 1) {
			(*rt).high = cr.id;
			return;
		}
	}
	Range r;
	r.low = cr;
	r.high = r.low.id;
	ranges.push_back(r);
}

void Property::addRange(bstring area, int low, int high) {
	// first of all, let us intelligently try to update existing ranges
	std::list<Range>::iterator rt;
	for(rt = ranges.begin() ; rt != ranges.end() ; rt++) {
		if((*rt).isArea(area) && (*rt).high == low - 1) {
			(*rt).high = high;
			return;
		}
	}
	Range r;
	r.low.setArea(area);
	r.low.id = low;
	r.high = high;
	ranges.push_back(r);
}

//*********************************************************************
//						isOwner
//*********************************************************************

bool Property::isOwner(const bstring& str) const {
	return(owner == str);
}

//*********************************************************************
//						belongs
//*********************************************************************

bool Property::belongs(CatRef cr) const {
	std::list<Range>::const_iterator rt;
	for(rt = ranges.begin() ; rt != ranges.end() ; rt++)
		if((*rt).belongs(cr))
			return(true);
	return(false);
}

//*********************************************************************
//						getFlagList
//*********************************************************************

std::map<int, MudFlag>* Property::getFlagList() {
	switch(type) {
	case PROP_STORAGE:
		return(&gConfig->propStorFlags);
	case PROP_SHOP:
		return(&gConfig->propShopFlags);
	case PROP_GUILDHALL:
		return(&gConfig->propGuildFlags);
	case PROP_HOUSE:
		return(&gConfig->propHouseFlags);
	default:
		break;
	}
	return(0);
}

//*********************************************************************
//						viewLogFlag
//*********************************************************************

int Property::viewLogFlag() const {
	switch(type) {
	case PROP_STORAGE:
		return(PROP_STOR_VIEW_LOG);
	case PROP_SHOP:
		return(PROP_SHOP_VIEW_LOG);
	default:
		// other proprties do not use this function
		break;
	}
	return(-1);
}

//*********************************************************************
//						usePropFlags
//*********************************************************************

bool Property::usePropFlags(PropType propType) {
	return(propType == PROP_HOUSE || propType == PROP_GUILDHALL);
}

//*********************************************************************
//						canEnter
//*********************************************************************

bool Property::canEnter(const Player* player, const UniqueRoom* room, bool p) {
	// staff may always go anywhere
	int staff = player->isStaff();

	if(room->info.isArea(getTypeArea(PROP_STORAGE))) {
		CatRef cr = gConfig->getSingleProperty(player, PROP_STORAGE);
		if(cr != room->info) {
			if(p) player->checkStaff("You are not permited in there.\n");
			if(!staff) return(false);
		}

		if(player->getLevel() < 10) {
			if(p) player->checkStaff("You must be level 10 to go there.\n");
			if(!staff) return(false);
		}
	}

	if(	room->info.isArea(getTypeArea(PROP_GUILDHALL)) &&
		!room->flagIsSet(R_GUILD_OPEN_ACCESS)
	) {
		const Guild *guild=0, *pGuild=0;

		if(player && player->getGuild())
			guild = gConfig->getGuild(player->getGuild());

		Property *prop = gConfig->getProperty(room->info);
		if(prop && prop->getGuild())
			pGuild = gConfig->getGuild(prop->getGuild());
		if(!pGuild) {
			if(p) player->checkStaff("Sorry, that guildhall is broken.\n");
			if(!staff) return(false);
		}

		if(	(!guild || guild->getNum() != pGuild->getNum()) &&
			(!prop || !prop->flagIsSet(PROP_GUILD_PUBLIC))
		) {
			if(p) player->checkStaff("You must belong to %s to go that way.\n", pGuild->getName().c_str());
			if(!staff) return(false);
		}
	}

	if(room->info.isArea(getTypeArea(PROP_HOUSE))) {
		Property *prop = gConfig->getProperty(room->info);

		if(	prop &&
			prop->flagIsSet(PROP_HOUSE_PRIVATE) &&
			!prop->isOwner(player->getName()) &&
			!prop->isPartialOwner(player->getName())
		) {
			if(p) player->checkStaff("That personal house is private property.\n");
			if(!staff) return(false);
		}
	}

	return(true);
}

//*********************************************************************
//						goodNameDesc
//*********************************************************************

bool Property::goodNameDesc(const Player* player, bstring str, bstring fail, bstring disallow) {
	if(str == "") {
		player->print("%s\n", fail.c_str());
		return(false);
	}
	if(str.getLength() > 79) {
		player->print("Too long.\n");
		return(false);
	}
	if(Pueblo::is(str)) {
		player->print("That %s is not allowed.\n", disallow.c_str());
		return(false);
	}
	return(true);
}

//*********************************************************************
//						goodExit
//*********************************************************************

bool Property::goodExit(const Player* player, const BaseRoom* room, const char *type, bstring xname) {
	if(xname.getLength() > 19) {
		player->print("%s exit name is too long!\n", type);
		return(false);
	}
	if(xname.getLength() < 3) {
		player->print("%s exit name is too short!\n", type);
		return(false);
	}

	if(isCardinal(xname)) {
		player->print("Exits cannot be made cardinal directions.\n");
		return(false);
	}

	int len = xname.getLength();
	for(int i=0; i<len; i++) {
		if(isupper(xname.getAt(i))) {
			player->print("Do not use capital letters in exit names.\n");
			return(false);
		}
		if(xname.getAt(i) == '^') {
			player->print("Carets (^) are not allowed in exit names.\n");
			return(false);
		}
	}

	for(Exit* ext : room->exits) {
		if(ext->getName() == xname) {
			player->print("An exit with that name already exists in this room.\n");
			return(false);
		}
	}

	return(true);
}

//*********************************************************************
//						destroy
//*********************************************************************

void Property::destroy() {
	BaseRoom* outside=0;
	AreaRoom* aRoom=0;
	UniqueRoom	*room=0, *uRoom=0;
	std::list<Range>::iterator rt;

	for(rt = ranges.begin() ; rt != ranges.end() ; rt++) {
		for(; (*rt).low.id <= (*rt).high; (*rt).low.id++) {
			if(loadRoom((*rt).low, &room)) {
				// for every property besides storage rooms, we have to delete the
				// exit leading to the property

				if(type != PROP_STORAGE) {
					// handle the exits that point outside
					for(Exit* ext : room->exits) {
						if(	ext->target.mapmarker.getArea() ||
							!ext->target.room.isArea(room->info.area) )
						{
							outside = ext->target.loadRoom();
							if(outside) {
								uRoom = outside->getAsUniqueRoom();
								aRoom = outside->getAsAreaRoom();

								// get rid of all exits
								ExitList::iterator xit;
								for(xit = outside->exits.begin() ; xit != outside->exits.end() ; ) {
									Exit* oExit = (*xit++);
									if(oExit->target.room == room->info) {
										broadcast(NULL, outside, "%s closes its doors.", name.c_str());
										outside->delExit(oExit);
									}
								}

								// reset flags
								if(uRoom) {
									if(type == PROP_SHOP && uRoom->flagIsSet(R_WAS_BUILD_SHOP)) {
										uRoom->clearFlag(R_WAS_BUILD_SHOP);
										uRoom->setFlag(R_BUILD_SHOP);
									} else if(type == PROP_GUILDHALL && uRoom->flagIsSet(R_WAS_BUILD_GUILDHALL)) {
										uRoom->clearFlag(R_WAS_BUILD_GUILDHALL);
										uRoom->setFlag(R_BUILD_GUILDHALL);
									}

									uRoom->saveToFile(0);
								} else if(aRoom) {
									aRoom->save();
								}
							}
						}
					}
				}

				broadcast(NULL, room, "%s closes its doors.", name.c_str());
				room->destroy();
			}
		}
	}

	delete this;
}

//*********************************************************************
//						destroyProperties
//*********************************************************************
// This function is called when a player is destroyed and everything
// they own must be destroyed as well.

void Config::destroyProperties(bstring pOwner) {
	std::list<Property*>::iterator it;

	// giving guildhalls a new owner occurs when the player leaves the guild

	for(it = properties.begin() ; it != properties.end() ; ) {
		if((*it)->isOwner(pOwner)) {
			(*it)->destroy();
			it = properties.erase(it);
			continue;
		} else if((*it)->isPartialOwner(pOwner)) {
			(*it)->unassignPartialOwner(pOwner);
			(*it)->appendLog(pOwner, "%s has resigned as partial owner.", pOwner.c_str());
		}
		it++;
	}

	saveProperties();
}

//*********************************************************************
//						destroyProperty
//*********************************************************************

void Config::destroyProperty(Property *p) {
	std::list<Property*>::iterator it;

	for(it = properties.begin() ; it != properties.end() ; it++) {
		if((*it) == p) {
			p->destroy();
			properties.erase(it);
			saveProperties();
			return;
		}
	}
}


//*********************************************************************
//						partial owner functions
//*********************************************************************
// guildhalls do not use the partialowner list: they rely on getting
// their information from the guild

PartialOwner* Property::getPartialOwner(const bstring& pOwner) {
	std::list<PartialOwner>::iterator it;
	for(it = partialOwners.begin() ; it != partialOwners.end() ; it++) {
		if(pOwner == (*it).getName())
			return(&(*it));
	}
	return(0);
}

bool Property::isPartialOwner(const bstring& pOwner) {
	// shops will also check guild membership, if they're assigned to a guild
	if(type == PROP_SHOP) {
		if(!!getPartialOwner(pOwner))
			return(true);
	} else if(type != PROP_GUILDHALL)
		return(!!getPartialOwner(pOwner));
	if(!guild)
		return(false);
	Guild *g = gConfig->getGuild(guild);
	return(g && g->isMember(pOwner));
}

void Property::assignPartialOwner(bstring pOwner) {
	if(type == PROP_GUILDHALL)
		return;
	PartialOwner po;
	po.defaultFlags(type);
	po.setName(pOwner);
	partialOwners.push_back(po);
}

void Property::unassignPartialOwner(bstring pOwner) {
	std::list<PartialOwner>::iterator it;
	for(it = partialOwners.begin() ; it != partialOwners.end() ; it++) {
		if(pOwner == (*it).getName()) {
			partialOwners.erase(it);
			return;
		}
	}
}


//*********************************************************************
//						addProperty
//*********************************************************************

void Config::addProperty(Property* p) {
	properties.push_back(p);
	saveProperties();
}

//*********************************************************************
//						loadProperties
//*********************************************************************

bool Config::loadProperties() {
	xmlDocPtr xmlDoc;
	xmlNodePtr curNode;
	Property *p=0;

	char filename[80];
	snprintf(filename, 80, "%s/properties.xml", Path::PlayerData);
	xmlDoc = xml::loadFile(filename, "Properties");

	if(xmlDoc == NULL)
		return(false);

	curNode = xmlDocGetRootElement(xmlDoc);

	curNode = curNode->children;
	while(curNode && xmlIsBlankNode(curNode))
		curNode = curNode->next;

	if(curNode == 0) {
		xmlFreeDoc(xmlDoc);
		return(false);
	}

	clearProperties();
	while(curNode != NULL) {
		if(NODE_NAME(curNode, "Property")) {
			p = new Property;
			p->load(curNode);
			properties.push_back(p);
		}
		curNode = curNode->next;
	}
	xmlFreeDoc(xmlDoc);
	xmlCleanupParser();

	return(true);
}

//*********************************************************************
//						saveProperties
//*********************************************************************

bool Config::saveProperties() const {
	std::list<Property*>::const_iterator it;
	xmlDocPtr	xmlDoc;
	xmlNodePtr	rootNode;
	char			filename[80];

	xmlDoc = xmlNewDoc(BAD_CAST "1.0");
	rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Properties", NULL);
	xmlDocSetRootElement(xmlDoc, rootNode);

	for(it = properties.begin() ; it != properties.end() ; it++) {
		(*it)->save(rootNode);
	}

	sprintf(filename, "%s/properties.xml", Path::PlayerData);
	xml::saveFile(filename, xmlDoc);
	xmlFreeDoc(xmlDoc);
	return(true);
}

//*********************************************************************
//						getSingleProperty
//*********************************************************************
// cr.id = 0 means they have no property
// cr.id = -1 means they have too many properties
// otherwise, cr points to the property's first room

CatRef Config::getSingleProperty(const Player* player, PropType type) {
	std::list<Property*>::iterator it;
	CatRef	cr;

	for(it = gConfig->properties.begin() ; it != gConfig->properties.end() ; it++) {
		if((*it)->getType() != type)
			continue;
		if(type == PROP_STORAGE && !(*it)->isOwner(player->getName()) && !(*it)->isPartialOwner(player->getName()))
			continue;
		if(type == PROP_GUILDHALL && player->getGuild() != (*it)->getGuild())
			continue;

		if(cr.id)
			cr.id = -1;
		else
			cr = (*it)->ranges.front().low;
	}
	return(cr);
}

//*********************************************************************
//						expelOnRemove
//*********************************************************************

bool Property::expelOnRemove() const {
	return(	type == PROP_STORAGE ||
			type == PROP_GUILDHALL ||
			(type == PROP_HOUSE && flagIsSet(PROP_HOUSE_PRIVATE))
	);
}

//*********************************************************************
//						expelToExit
//*********************************************************************
// can safely call this function; it will decide if the player needs
// to be kicked out or not

void Property::expelToExit(Player* player, bool offline) {
	if(!expelOnRemove() || player->inAreaRoom() || !belongs(player->currentLocation.room))
		return;

	AreaRoom* aRoom=0;
	UniqueRoom*	uRoom=0;
	BaseRoom* newRoom=0;

	if(loadRoom(ranges.front().low, &uRoom)) {
		for(Exit* ext : uRoom->exits ) {
			if(!ext->target.room.id || !belongs(ext->target.room)) {
				newRoom = ext->target.loadRoom(player);
				if(newRoom)
					break;
			}
		}
		uRoom = 0;
	}

	if(!newRoom)
		newRoom = player->bound.loadRoom(player);

	if(!newRoom)
		newRoom = abortFindRoom(player, "expelToExit");

	uRoom = newRoom->getAsUniqueRoom();
	aRoom = newRoom->getAsAreaRoom();

	if(offline) {
		player->currentLocation.room.clear();
		player->currentLocation.mapmarker.reset();
		if(uRoom)
			player->currentLocation.room = uRoom->info;
		else
			player->currentLocation.mapmarker = aRoom->mapmarker;
	} else {
		player->print("You are escorted off the premises.\n");
		broadcast(player->getSock(), player->getParent(), "%M is escorted off the premises.", player);
		player->deleteFromRoom();
		player->addToRoom(newRoom);
		player->doPetFollow();
	}
	player->save();
}

//*********************************************************************
//						propCommands
//*********************************************************************

void propCommands(Player* player, Property *p) {
	player->print("Commands for this property:\n");

	if(p->isOwner(player->getName())) {
		// example showing width
		//player->printColor("           <commands>            - description\n");

		switch(p->getType()) {
		case PROP_STORAGE:
		case PROP_HOUSE:
			player->printColor("  property ^e<^xassign^e>^x ^e<^cplayer^e>^x     ^e-^x add a partial owner\n");
			player->printColor("           ^e<^xunassign^e>^x ^e<^cplayer^e>^x   ^e-^x remove a partial owner\n");
			break;
		case PROP_SHOP:
			player->printColor("  property ^e<^xhire^e>^x ^e<^cplayer^e>^x       ^e-^x add a partial owner\n");
			player->printColor("           ^e<^xfire^e>^x ^e<^cplayer^e>^x       ^e-^x remove a partial owner\n");
			if(player->getGuild())
				player->printColor("           ^e<^xguild^e>^x ^e<^xassign^e|^xremove^e>\n");
			break;
		case PROP_GUILDHALL:
			player->printColor("  property ^e<^xdestroy^e>^x             ^e-^x close this property down\n");
			break;
		default:
			player->print("  None.\n");
			return;
		}


		if(Property::usePropFlags(p->getType()))
			player->printColor("           ^e<^xflags^e>^x               ^e-^x view / set flags on property\n");
		else
			player->printColor("           ^e<^xflags^e>^x               ^e-^x view / set flags on partial owners\n");

		if(p->getType() != PROP_GUILDHALL) {
			player->printColor("           ^e<^xlog^e>^x ^e<^xdelete^e|^xrecord^e>^x ^e-^x view / delete / set log type\n");
			player->printColor("           ^e<^xdestroy^e>^x             ^e-^x close this property down\n");
		}
		player->printColor("           ^e<^xhelp^e>\n");
	} else {
		PartialOwner *po = p->getPartialOwner(player->getName());
		if(!po)
			player->print("  none.\n");
		else {
			player->printColor("  property ^e<^xunassign^e>\n");

			if(p->getType() != PROP_GUILDHALL) {
				player->printColor("           ^e<^xflags^e>\n");

				if(	p->getType() != PROP_HOUSE &&
					po &&
					po->flagIsSet(p->viewLogFlag())
				)
					player->printColor("           ^e<^xlog^e>\n");
			}
		}
	}

	player->print("\n");
}

//*********************************************************************
//						propLog
//*********************************************************************
// handles property logging

void propLog(Player* player, cmd* cmnd, Property *p) {
	if(!cmnd || cmnd->num == 2) {
		player->print("Property Log For %s:\n", p->getName().c_str());
		player->printColor("^b--------------------------------------------------------------\n");
		player->printColor("%s\n", p->getLog().c_str());
	} else if(!strcmp(cmnd->str[2], "delete")) {
		player->print("Property log deleted.\n");
		p->clearLog();
		gConfig->saveProperties();
	} else if(!strcmp(cmnd->str[2], "record")) {
		if(cmnd->num == 3) {
			player->print("%s\n", p->getLogTypeStr().c_str());
			player->printColor("To change this, type ^yproperty log record <all|partial|none>^x.\n");
		} else {
			if(!strncmp(cmnd->str[3], "all", strlen(cmnd->str[3])))
				p->setLogType(LOG_ALL);
			else if(!strncmp(cmnd->str[3], "partial", strlen(cmnd->str[3])))
				p->setLogType(LOG_PARTIAL);
			else if(!strncmp(cmnd->str[3], "none", strlen(cmnd->str[3])))
				p->setLogType(LOG_NONE);
			else {
				player->printColor("Log recording type not understood.\nType ^yproperty log record <all|partial|none>^x.\n");
				return;
			}
			player->print("Property log type set.\n");
			gConfig->saveProperties();
		}
	} else {
		player->print("Command not understood.\n");
		propCommands(player, p);
	}
	return;
}

//*********************************************************************
//						propDestroy
//*********************************************************************
// handles property destruction

void propDestroy(Player* player, cmd* cmnd, Property *p) {
	if(strcmp(cmnd->str[2], "confirm")) {
		player->printColor("^rAre you sure you wish to destroy this property?\n");
		player->printColor("Type \"property destroy confirm\" to destroy it.\n");
	} else {
		gConfig->destroyProperty(p);
	}
}

//*********************************************************************
//						propAssignUnassign
//*********************************************************************
// handles assigning/unassigning of partial owners

void propAssignUnassign(Player* player, cmd* cmnd, Property *p, bool assign) {
	if(p->getType() == PROP_GUILDHALL) {
		player->print("Partial ownership of guildhalls is handled by guild membership.\n");
		return;
	}

	bool	offline=false;

	// find out who they're trying to work with
	if(cmnd->num < 3) {
		player->print("Player does not exist.\n");
		return;
	}

	cmnd->str[2][0] = up(cmnd->str[2][0]);
	Player* target = gServer->findPlayer(cmnd->str[2]);

	if(!target) {
		if(!loadPlayer(cmnd->str[2], &target)) {
			player->print("Player does not exist.\n");
			return;
		}
		offline = true;
	}
	if((target->isStaff() && !player->isStaff()) || target == player) {
		player->print("That player is not a valid target.\n");

		if(offline) free_crt(target);
		return;
	}


	// is this action even valid?
	if(assign && p->getPartialOwner(target->getName())) {
		player->print("%s is already a partial owner of this property.\n", target->getCName());

		if(offline) free_crt(target);
		return;
	} else if(!assign && !p->getPartialOwner(target->getName())) {
		player->print("%s is not a partial owner of this property.\n", target->getCName());

		if(offline) free_crt(target);
		return;
	}

	// their action is valid: let's continue
	if(assign) {

		if(Move::tooFarAway(player, target, "appoint as partial owner of this property")) {
			if(offline) free_crt(target);
			return;
		}

		// people can only belong to one storage room
		if(p->getType() == PROP_STORAGE) {
			CatRef	cr = gConfig->getSingleProperty(target, PROP_STORAGE);
			if(cr.id) {
				player->print("%s may only be affiliated with one storage room at a time.\n", target->getCName());

				if(offline) free_crt(target);
				return;
			}
		}

		p->assignPartialOwner(target->getName());
		p->appendLog(target->getName(), "%s is now a partial owner.", target->getCName());
		player->print("%s is now a partial owner of this property.\n", target->getCName());
		if(!offline) {
			target->printColor( "^c%s has appointed you partial owner of %s.\n",
				player->getCName(), p->getName().c_str());
			target->print("Type \"property\" for instructions on how to remove yourself\nif you do not wish to be partial owner.\n");
		}
	} else {
		p->unassignPartialOwner(target->getName());
		p->appendLog(target->getName(), "%s is no longer a partial owner.", target->getCName());
		player->print("%s is no longer a partial owner of this property.\n", target->getCName());
		if(!offline) {
			target->printColor( "^c%s has removed you as partial owner of %s.\n",
				player->getCName(), p->getName().c_str());
		}
		p->expelToExit(target, offline);
	}

	gConfig->saveProperties();
	if(offline) free_crt(target);
}

//*********************************************************************
//						propFlags
//*********************************************************************
// handles viewing/setting of flags on partial owners

void propFlags(Player* player, cmd* cmnd, Property *p) {
	std::map<int, MudFlag>* list = p->getFlagList();
	std::map<int, MudFlag>::iterator it;
	PartialOwner *po=0;
	MudFlag f;
	bool propFlag = Property::usePropFlags(p->getType());

	if(cmnd->num == 2) {

		player->printColor("^yFlags for %sproperty type: %s^x\n\n",
			propFlag ? "" : "Partial Owners for ", p->getTypeStr().c_str());

		for(it = list->begin(); it != list->end() ; it++) {
			f = (*it).second;
			player->printColor("^c#%-2d^x %-20s ^e-^x %s\n",
				f.id, f.name.c_str(), f.desc.c_str());
		}

		player->print("\nThese commands allow you to change flags on %s:\n",
			propFlag ? "this property" : "partial owners");
		player->printColor("   property flags %s^e<^xview^e>\n",
			propFlag ? "" : "^e<^cplayer^e>^x ");
		player->printColor("   property flags %s^e<^xset^e|^xclear^e|^xtoggle^e>^x ^e<^cflag num^e>^x\n\n",
			propFlag ? "" : "^e<^cplayer^e>^x ");

	} else if(propFlag) {

		bstring action = cmnd->str[2];

		if(action == "" || action == "view") {

			player->printColor("^yFlags set for this property:^x\n\n");
			for(it = list->begin(); it != list->end() ; it++) {
				f = (*it).second;
				if(p->flagIsSet(f.id-1))
					player->printColor("^c#%-2d^x %s\n", f.id, f.name.c_str());
			}
			player->print("\n");

		} else if(action == "set" || action == "clear" || action == "toggle") {

			int num = atoi(getFullstrText(cmnd->fullstr, 3).c_str());
			bool found=false;

			for(it = list->begin(); it != list->end() ; it++) {
				f = (*it).second;
				if(num == f.id) {
					found = true;
					break;
				}
			}
			if(!found) {
				player->print("Invalid flag!\n");
				return;
			}

			num--;
			if(action == "set")
				p->setFlag(num);
			else if(action == "clear")
				p->clearFlag(num);
			else
				p->toggleFlag(num);


			if(p->flagIsSet(num))
				player->printColor("Flag ^c""%s""^x set on this property.\n", f.name.c_str());
			else
				player->printColor("Flag ^c""%s""^x cleared on this property.\n", f.name.c_str());

			gConfig->saveProperties();

		} else {
			player->print("Command not understood.\n");
			propCommands(player, p);
		}

	} else {

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		po = p->getPartialOwner(cmnd->str[2]);
		if(!po) {
			player->print("%s is not a partial owner of this property!\n", cmnd->str[2]);
			return;
		}

		bstring action = cmnd->str[3];

		if(action == "" || action == "view") {

			// if viewing self, show property name instead
			bstring title = po->getName();
			if(title == player->getName())
				title = p->getName();

			player->printColor("^yFlags set for %s:^x\n\n", title.c_str());
			for(it = list->begin(); it != list->end() ; it++) {
				f = (*it).second;
				if(po->flagIsSet(f.id-1))
					player->printColor("^c#%-2d^x %s\n", f.id, f.name.c_str());
			}
			player->print("\n");

		} else if(action == "set" || action == "clear" || action == "toggle") {

			int num = atoi(getFullstrText(cmnd->fullstr, 4).c_str());
			bool found=false;

			for(it = list->begin(); it != list->end() ; it++) {
				f = (*it).second;
				if(num == f.id) {
					found = true;
					break;
				}
			}
			if(!found) {
				player->print("Invalid flag!\n");
				return;
			}

			num--;
			if(action == "set")
				po->setFlag(num);
			else if(action == "clear")
				po->clearFlag(num);
			else
				po->toggleFlag(num);

			Player* target = gServer->findPlayer(po->getName().c_str());
			if(po->flagIsSet(num)) {
				player->printColor("Flag ^c""%s""^x set on %s.\n", f.name.c_str(),
					po->getName().c_str());
				if(target)
					target->printColor("Flag ^c""%s""^x has been set on you for %s.\n",
						f.name.c_str(), p->getName().c_str());
			} else {
				player->printColor("Flag ^c""%s""^x cleared on %s.\n", f.name.c_str(),
					po->getName().c_str());
				if(target)
					target->printColor("Flag ^c""%s""^x has been cleared on you for %s.\n",
						f.name.c_str(), p->getName().c_str());
			}

			gConfig->saveProperties();

		} else {
			player->print("Command not understood.\n");
			propCommands(player, p);
		}
	}
}

//*********************************************************************
//						propRemove
//*********************************************************************
// handles assigning/unassigning of partial owners

void propRemove(Player* player, Property *p) {
	if(p->getType() == PROP_GUILDHALL) {
		player->print("Partial ownership of guildhalls is handled by guild membership.\n");
		return;
	}

	p->unassignPartialOwner(player->getName());
	p->appendLog(player->getName(), "%s has resigned as partial owner.", player->getCName());

	Player* owner = gServer->findPlayer(p->getOwner().c_str());
	if(owner) {
		owner->printColor("^c%s has resigned as partial owner of %s.\n",
			player->getCName(), p->getName().c_str());
	}

	player->print("You are no longer a partial owner of %s.\n", p->getName().c_str());
	gConfig->saveProperties();
}

//*********************************************************************
//						propHelp
//*********************************************************************

void propHelp(Player* player, cmd* cmnd, PropType propType) {
	if(propType == PROP_GUILDHALL)
		strcpy(cmnd->str[1], "guildhalls");
	else if(propType == PROP_HOUSE)
		strcpy(cmnd->str[1], "houses");
	else
		strcpy(cmnd->str[1], "property");
	cmdHelp(player, cmnd);
}

//*********************************************************************
//						cmdProperties
//*********************************************************************

int cmdProperties(Player* player, cmd* cmnd) {
	Property *p=0;
	PartialOwner *po=0;

	if(player->inUniqueRoom())
		p = gConfig->getProperty(player->getUniqueRoomParent()->info);

	int len = strlen(cmnd->str[1]);
	if(len && !strncmp(cmnd->str[1], "help", len)) {
		propHelp(player, cmnd, p ? p->getType() : PROP_NONE);
		return(0);
	}

	if(p)
		po = p->getPartialOwner(player->getName());

	// they only want to see their properties
	if(cmnd->num < 2) {

		player->printColor("Properties You Own\n");
		player->printColor("^b--------------------------------------------------------------\n");
		gConfig->showProperties(player, player);

		if(!p || (!p->isOwner(player->getName()) && !p->isPartialOwner(player->getName())))
			return(0);

		propCommands(player, p);

	} else if(!p) {

		// not in a property, trying to do stuff
		if(!strcmp(cmnd->str[1], "remove")) {
			int i=0;
			std::list<Property*>::iterator it;

			for(it = gConfig->properties.begin() ; it != gConfig->properties.end() ; it++) {
				if((*it)->isPartialOwner(player->getName()))
					i++;
				if(i == cmnd->val[1]) {
					propRemove(player, *it);
					return(0);
				}
			}

			player->print("Property not found!\n");
		} else {
			player->print("Command not understood.\n");
			player->print("To manage your own properties, you must be on the premises.\n");
			player->print("Type \"property remove [num]\" to remove yourself as partial owner from a property.\n");
		}

	} else if(p->isOwner(player->getName())) {

		// they want to do something with this property
		bool found=true, assign=false;

		// figure out what they're trying to do
		if(!strcmp(cmnd->str[1], "destroy")) {

			propDestroy(player, cmnd, p);

		} else if(!strcmp(cmnd->str[1], "log") && p->getType() != PROP_HOUSE) {

			propLog(player, cmnd, p);

		} else if(p->getType() == PROP_SHOP && !strcmp(cmnd->str[1], "guild") && cmnd->num > 2) {

			// give them a cross-command shortcut
			cmdShop(player, cmnd);

		} else if(!strcmp(cmnd->str[1], "flags")) {

			propFlags(player, cmnd, p);

		} else {

			switch(p->getType()) {
			case PROP_STORAGE:
			case PROP_HOUSE:
				if(!strcmp(cmnd->str[1], "assign"))
					assign = true;
				else if(strcmp(cmnd->str[1], "unassign"))
					found = false;
				break;
			case PROP_SHOP:
				if(!strcmp(cmnd->str[1], "hire"))
					assign = true;
				else if(strcmp(cmnd->str[1], "fire"))
					found = false;
				break;
			default:
				found = false;
				break;
			}

			if(!found) {
				player->print("Command not understood.\n");
				propCommands(player, p);
				return(0);
			}

			propAssignUnassign(player, cmnd, p, assign);

		}

	} else if(po) {

		if(	!strcmp(cmnd->str[1], "log") &&
			p->viewLogFlag() != -1 &&
			po->flagIsSet(p->viewLogFlag())
		) {
			propLog(player, 0, p);
		} else if(!strcmp(cmnd->str[1], "flags") && p->getType() != PROP_HOUSE) {
			cmnd->num = 4;
			strcpy(cmnd->str[2], player->getCName());
			strcpy(cmnd->str[3], "view");
			propFlags(player, cmnd, p);
		} else if(!strcmp(cmnd->str[1], "unassign")) {
			propRemove(player, p);
			p->expelToExit(player, false);
		} else {
			player->print("Command not understood.\n");
			propCommands(player, p);
		}
	}

	return(0);
}


//*********************************************************************
//						dmProperties
//*********************************************************************

int dmProperties(Player* player, cmd* cmnd) {
	bstring id = getFullstrText(cmnd->fullstr, 1);
	if(id == "") {
		player->printColor("Properties: Type ^c*property [num]^x to view more info.\n");
		player->printColor("Properties: Type ^c*property [type]^x to filter the list.\n");
		player->printColor("Properties: Type ^c*property destroy [num] [owner]^x to destroy a property.\n");
		player->printColor("^b--------------------------------------------------------------\n");
		gConfig->showProperties(player, 0);
	} else if(!strcmp(cmnd->str[1], "destroy")) {
		int num = cmnd->val[1];
		int i=1;

		if(!strlen(cmnd->str[2])) {
			player->printColor("You must specify the owner of the property you wish to destroy.\nType ^c*property destroy [num] [owner]^x\n");
			return(0);
		}
		cmnd->str[2][0] = up(cmnd->str[2][0]);

		player->print("Looking to destroy property #%d owned by %s.\n", num, cmnd->str[2]);
		std::list<Property*>::iterator it;
		for(it = gConfig->properties.begin() ; it != gConfig->properties.end() ; it++) {
			if(num == i++ && (*it)->isOwner(cmnd->str[2])) {
				player->printColor("^rProperty found...^x\n\n%s\n^rProperty destroyed!\n", (*it)->show().c_str());
				gConfig->destroyProperty(*it);
				return(0);
			}
		}
		player->print("Property not found!\n");
	} else if(!isdigit(id.getAt(0))) {
		PropType propType = PROP_NONE, i;
		int len = strlen(cmnd->str[1]);

		for(i = PROP_NONE; i < PROP_END && propType == PROP_NONE; i = (PropType)((int)i+1)) {
			if(	!strncmp(cmnd->str[1], Property::getTypeStr(i).c_str(), len) ||
				(i == PROP_HOUSE && !strncmp(cmnd->str[1], "house", len))
			)
				propType = i;
		}

		player->printColor("Properties filtered on type: %s.\n", Property::getTypeStr(propType).c_str());
		player->printColor("^b--------------------------------------------------------------\n");
		gConfig->showProperties(player, 0, propType);
	} else {
		int num = atoi(id.c_str());
		int i=1;

		player->print("Property #%d\n", num);
		player->printColor("^b--------------------------------------------------------------\n");
		std::list<Property*>::iterator it;
		for(it = gConfig->properties.begin() ; it != gConfig->properties.end() ; it++) {
			if(num == i++) {
				player->printColor("%s\n", (*it)->show().c_str());
				return(0);
			}
		}
		player->print("Property not found!\n");
	}
	return(0);
}


//*********************************************************************
//						show
//*********************************************************************

bstring Property::show(bool isOwner, bstring player, int *i) {
	std::ostringstream oStr;
	oStr.setf(std::ios::left, std::ios::adjustfield);

	oStr << "Name:     ^e" << name;
	if(player != "" && !!getPartialOwner(player))
		oStr << " (#" << (*i)++ << ")";

	oStr << "^x\n"
		 << "Location: ^c" << location;
	if(area != "")
		oStr << " in " << gConfig->catRefName(area);

	oStr << "^x\n"
		 << "Founded:  ^c" << std::setw(30) << dateFounded << "^x";

	if(!isOwner)
		oStr << " Owner: ^c" << std::setw(15) << owner << "^x";
	oStr << "Type: ^c" << getTypeStr() << "^x\n";

	// show them who else is part of this property
	if(guild) {
		const Guild *g = gConfig->getGuild(guild);

		if(!g) {
			if(type == PROP_GUILDHALL)
				oStr << "This guildhall is broken: guild ID " << guild << " does not exist.\n";
		} else {
			oStr << "Guild:    ^c#" << guild << " ^c" << g->getName() << "^x\n";
			std::list<bstring>::const_iterator pt;
			bool initial=false;

			oStr << "Guild Members: ^c";
			for(pt = g->members.begin() ; pt != g->members.end() ; pt++) {
				if(initial)
					oStr << ", ";

				initial = true;
				if(!isOwner && player == (*pt))
					oStr << "^e";
				oStr << (*pt);
				if(!isOwner && player == (*pt))
					oStr << "^c";
			}
			oStr << "^x\n";
		}
	}

	if(!partialOwners.empty()) {
		std::list<PartialOwner>::const_iterator pt;
		bool initial=false;

		oStr << "Partial Owners: ^c";
		for(pt = partialOwners.begin() ; pt != partialOwners.end() ; pt++) {
			if(initial)
				oStr << ", ";

			initial = true;
			if(!isOwner && player == (*pt).getName())
				oStr << "^m";
			oStr << (*pt).getName();
			if(!isOwner && player == (*pt).getName())
				oStr << "^c";
		}
		oStr << "^x\n";
	}

	// admin info
	if(player == "") {
		oStr << "Ranges:\n";
		std::list<Range>::const_iterator rt;
		for(rt = ranges.begin() ; rt != ranges.end() ; rt++)
			oStr << "Low: ^c" << (*rt).low.str() << "^x  High: ^c" << (*rt).high << "^x\n";

		oStr << "Log Type: ^c" << getLogTypeStr() << "^x\n";
		if(!log.empty()) {
			oStr << "Log:\n^b-----------------^x\n";
			oStr << getLog();
		}
	}

	return(oStr.str());
}

//*********************************************************************
//						showProperties
//*********************************************************************
// player=0 means we're using the admin version

void Config::showProperties(Player* viewer, Player* player, PropType propType) {
	std::list<Property*>::iterator it;
	std::ostringstream oStr;
	Property *p=0;
	bstring name = "";
	bool	isOwner=false, partialOwnerList=false;
	int		i=0;

	oStr.setf(std::ios::left, std::ios::adjustfield);
	if(player)
		name = player->getName();

	for(it = properties.begin() ; it != properties.end() ; it++) {
		p = (*it);


		if(player) {
			isOwner = p->isOwner(name);
			// guild halls don't count toward the partial owner list, since they can't
			// remove themselves with the property interface
			if(!partialOwnerList && player && p->getType() != PROP_GUILDHALL)
				partialOwnerList = !!p->getPartialOwner(name);
			if(!isOwner && !p->isPartialOwner(name))
				continue;
		}

		// when filtering, we still increment so we can show the correct id
		i++;

		if(propType != PROP_NONE && p->getType() != propType)
			continue;

		if(!player) {
			oStr << "^c#" << std::setw(3) << i << "^x Name: ^y" << std::setw(50) << p->getName()
				 << "^x Range: ^c" << p->ranges.front().str() << "^x\n";
			continue;
		}

		oStr << p->show(isOwner, name, &i) << "\n";
	}

	if(partialOwnerList) {
		oStr << "To remove yourself as partial owner from a property,\n"
			 << "type \"property remove [num]\".\n\n";
	}

	viewer->printColor("%s", oStr.str().c_str());
}

//*********************************************************************
//						clearProperties
//*********************************************************************

void Config::clearProperties() {
	Property* p;

	while(!properties.empty()) {
		p = properties.front();
		delete p;
		properties.pop_front();
	}
	properties.clear();
}

//*********************************************************************
//						getProperty
//*********************************************************************

Property* Config::getProperty(CatRef cr) {
	std::list<Property*>::iterator it;

	for(it = properties.begin() ; it != properties.end() ; it++) {
		if((*it)->belongs(cr))
			return(*it);
	}

	return(0);
}

//*********************************************************************
//						getAvailableProperty
//*********************************************************************

CatRef Config::getAvailableProperty(PropType type, int numRequired) {
	std::list<Property*>::iterator it;
	std::list<Range>::iterator rt;
	std::map<int, bool> sort;
	std::map<int, bool>::iterator st;
	Property *p;
	CatRef	cr;
	int		i=0;

	cr.setArea(Property::getTypeArea(type));

	if(cr.isArea(""))
		return(cr);

	for(it = properties.begin() ; it != properties.end() ; it++) {
		p = (*it);

		if(p->getType() != type)
			continue;

		for(rt = p->ranges.begin() ; rt != p->ranges.end() ; rt++) {
			if(!cr.isArea((*rt).low.area))
				continue;
			for(cr.id = (*rt).low.id; cr.id <= (*rt).high; cr.id++)
				sort[cr.id] = true;
		}
	}

	// if a entire-area range is found, we fail
	if(sort.find(-1) != sort.end()) {
		cr.id = 0;
		return(cr);
	}

	cr.id = 1;
	for(st = sort.begin() ; st != sort.end() ; st++) {
		i = (*st).first;

		// this room is used, keep looking
		if(cr.id == i) {
			cr.id++;
			continue;
		}

		// we've jumped over some empty rooms. we need to know if there's
		// enough space to fit this property
		if(i - cr.id >= numRequired)
			return(cr);

		// not enough room; keep looking
		cr.id = i + 1;
	}

	if(!validRoomId(cr))
		cr.id = 0;

	return(cr);
}

//*********************************************************************
//						rename
//*********************************************************************

void storageName(UniqueRoom* room, const Player* player);
void setupShop(Property *p, Player* player, const Guild* guild, UniqueRoom* shop, UniqueRoom* storage);

void Property::rename(Player *player) {
	UniqueRoom	*shop=0, *storage=0;
	setOwner(player->getName());

	if(type == PROP_STORAGE) {
		if(loadRoom(ranges.front().low, &storage)) {
			storageName(storage, player);
			setName(storage->getName());
			storage->saveToFile(0);
		}
	} else if(type == PROP_SHOP) {
		CatRef cr = ranges.front().low;
		if(loadRoom(cr, &shop)) {
			cr.id++;
			if(loadRoom(cr, &storage)) {
				// only rename shops that aren't affiliated with a guild
				if(!guild)
					setupShop(this, player, 0, shop, storage);
			}
		}
	}
}

//*********************************************************************
//						renamePropertyOwner
//*********************************************************************

void Config::renamePropertyOwner(bstring oldName, Player *player) {
	std::list<Property*>::iterator it;

	for(it = properties.begin() ; it != properties.end() ; it++) {
		if((*it)->getOwner() == oldName)
			(*it)->rename(player);
	}

	saveProperties();
}


//*********************************************************************
//						getLog
//*********************************************************************

bstring Property::getLog() const {
	if(log.empty())
		return("No entries in the log.\n");

	bstring str = "";
	std::list<bstring>::const_iterator it;

	for(it = log.begin() ; it != log.end() ; it++) {
		str += (*it);
		str += "\n";
	}

	return(str);
}

//*********************************************************************
//						appendLog
//*********************************************************************

void Property::appendLog(bstring user, const char *fmt, ...) {
	if(logType == LOG_NONE)
		return;
	if(logType == LOG_PARTIAL && isOwner(user))
		return;

	char	*str;
	va_list ap;

	va_start(ap, fmt);
	if(vasprintf(&str, fmt, ap) == -1) {
		printf("Error in Property::appendLog\n");
		return;
	}
	va_end(ap);

	long    t = time(0);
	bstring txt;
	txt = "^c";
	txt += ctime(&t);
	txt.trim();
	txt += ":^x ";
	txt += str;

	log.push_front(txt);
	while(log.size() > PROP_LOG_SIZE)
		log.pop_back();

	gConfig->saveProperties();
}

//*********************************************************************
//						clearLog
//*********************************************************************

void Property::clearLog() {
	log.clear();
}


//*********************************************************************
//						guildRoomSetup
//*********************************************************************
// this sets up the room to be part of the guild, then deletes it

void Property::guildRoomSetup(UniqueRoom *room, const Guild* guild, bool outside) {
	room->setName( guild->getName() + "'s Guild Hall");

	if(!outside) {
		room->setFlag(R_INDOORS);
		room->setFlag(R_SAFE_ROOM);
	}

	room->setShortDescription("You are in the ");
	room->appendShortDescription(guild->getName());
	room->appendShortDescription("'s guild hall.");

	room->saveToFile(0);
	delete room;
}

//*********************************************************************
//						houseRoomSetup
//*********************************************************************
// this sets up the room as a personal house, then deletes it

void Property::houseRoomSetup(UniqueRoom *room, const Player* player, bool outside) {
	room->setName( player->getName() + "'s Personal House");

	if(!outside) {
		room->setFlag(R_INDOORS);
		room->setFlag(R_SAFE_ROOM);
	}

	room->setShortDescription("You are in ");
	room->appendShortDescription(player->getName());
	room->appendShortDescription("'s personal house.");

	room->saveToFile(0);
	delete room;
}

//*********************************************************************
//						roomSetup
//*********************************************************************

void Property::roomSetup(UniqueRoom *room, PropType propType, const Player* player, const Guild* guild, bool outside) {
	if(propType == PROP_GUILDHALL)
		guildRoomSetup(room, guild, outside);
	else if(propType == PROP_HOUSE)
		houseRoomSetup(room, player, outside);
}

//*********************************************************************
//						linkRoom
//*********************************************************************

void Property::linkRoom(BaseRoom* inside, BaseRoom* outside, bstring xname) {
	UniqueRoom* uRoom = outside->getAsUniqueRoom();
	AreaRoom* aRoom = outside->getAsAreaRoom();
	if(uRoom) {
		link_rom(inside, uRoom->info, xname.c_str());
		uRoom->saveToFile(0);
	} else {
		link_rom(inside, &aRoom->mapmarker, xname.c_str());
		aRoom->save();
	}

	uRoom = inside->getAsUniqueRoom();
	aRoom = inside->getAsAreaRoom();
	if(uRoom) {
		link_rom(outside, uRoom->info, "out");
		uRoom->saveToFile(0);
	} else {
		link_rom(outside, &aRoom->mapmarker, "out");
		aRoom->save();
	}
}

//*********************************************************************
//						makeNextRoom
//*********************************************************************

UniqueRoom* Property::makeNextRoom(UniqueRoom* r1, PropType propType, CatRef cr, bool exits, const Player* player, const Guild* guild, BaseRoom* room, bstring xname, const char *go, const char *back, bool save) {
	UniqueRoom *r2 = new UniqueRoom;
	r2->info = cr;

	if(r1) {
		link_rom(r1, r2->info, go);
		link_rom(r2, r1->info, back);
	}

	if(exits)
		linkRoom(room, r2, xname);

	if(save) {
		roomSetup(r2, propType, player, guild);
		return(0);
	}
	return(r2);
}

//*********************************************************************
//						rotateHouse
//*********************************************************************

int Property::rotateHouse(char *dir1, char *dir2, int rotation) {

	if(!rotation)
		strcpy(dir1, "west");
	else if(rotation == 1)
		strcpy(dir1, "north");
	else if(rotation == 2)
		strcpy(dir1, "east");
	else if(rotation == 3)
		strcpy(dir1, "south");

	strcpy(dir2, opposite_exit_name(dir1).c_str());
	return((rotation + 1) % 4);
}

//*********************************************************************
//						isInside
//*********************************************************************

bool Property::isInside(const Player* player, const UniqueRoom* room, Property** p) {
	if(!(*p) || !room)
		return(false);

	if((*p)->getType() == PROP_GUILDHALL) {
		if(	!(*p)->getGuild() ||
			!player->getGuild() ||
			player->getGuild() != (*p)->getGuild()
		)
			return(false);
	}
	return(true);
}

//*********************************************************************
//						requireInside
//*********************************************************************

bool Property::requireInside(const Player* player, const UniqueRoom* room, Property** p, PropType propType) {
	if(room && !(*p))
		(*p) = gConfig->getProperty(room->info);

	if(!isInside(player, room, p)) {
		player->print("You must be inside your %s to perform this action.\n", getTypeStr(propType).c_str());
		return(false);
	}
	return(true);
}

//*********************************************************************
//						descEdit
//*********************************************************************

bstring postText(bstring str);

void Property::descEdit(Socket* sock, bstring str) {
	bstring outstr = "";
	char	outcstr[160];
	int		ff=0;

	Player* ply = sock->getPlayer();
	if((str[0] == '.' || str[0] == '*') && !str[1]) {
		ply->clearFlag(P_READING_FILE);
		sock->restoreState();

		Property *p=0;
		if(!Property::requireInside(ply, ply->getUniqueRoomParent(), &p))
			return;

		FILE* fp = fopen(sock->tempstr[0], "r");
		if(!fp) {
			ply->print("Error replacing room description.\n");
			return;
		}

		ply->getUniqueRoomParent()->setLongDescription("");
		while(!feof(fp)) {
			fgets(outcstr, sizeof(outcstr), fp);
			ply->getUniqueRoomParent()->appendLongDescription(outcstr);
			strcpy(outcstr, "");
		}

		ply->getUniqueRoomParent()->setLongDescription(ply->getUniqueRoomParent()->getLongDescription().left(ply->getUniqueRoomParent()->getLongDescription().getLength()-1));
		fclose(fp);
		unlink(sock->tempstr[0]);

		ply->print("Room description replaced.\n");
		ply->getUniqueRoomParent()->escapeText();
		ply->getUniqueRoomParent()->saveToFile(0);
		return;
	}


	if(str[0] == '\\' && !str[1]) {
		unlink(sock->tempstr[0]);
		ply->clearFlag(P_READING_FILE);
		ply->print("Description editting cancelled.\n");
		sock->restoreState();
		return;
	}

	ff = open(sock->tempstr[0], O_CREAT | O_APPEND | O_RDWR, ACC);
	if(ff < 0)
		merror("Property::descEdit", FATAL);

	outstr = postText(str);
	write(ff, outstr.c_str(), outstr.getLength());
	close(ff);
	ply->print("-: ");

	gServer->processOutput();
	sock->intrpt &= ~1;
}

//*********************************************************************
//						cmdHouse
//*********************************************************************

int cmdHouse(Player* player, cmd* cmnd) {
	Property::manage(player, cmnd, PROP_HOUSE, 1);
	return(0);
}

//*********************************************************************
//						houseCanBuild
//*********************************************************************

bool Property::houseCanBuild(AreaRoom* aRoom, BaseRoom* room) {
	if(room->flagIsSet(R_BUILD_HOUSE))
		return(true);

	return(false);
}

//*********************************************************************
//						buildFlag
//*********************************************************************

int Property::buildFlag(int propType) {
	if(propType == PROP_GUILDHALL)
		return(R_BUILD_GUILDHALL);
	return(0);
}

//*********************************************************************
//						manageDesc
//*********************************************************************

void Property::manageDesc(Player* player, cmd* cmnd, PropType propType, int x) {
	char	file[80];
	int		ff=0;

	switch(propType) {
	case PROP_GUILDHALL:
		sprintf(file, "%s/%s_guildhall.txt", Path::Post, player->getCName());
		break;
	case PROP_HOUSE:
		sprintf(file, "%s/%s_house.txt", Path::Post, player->getCName());
		break;
	default:
		player->print("Error: this property type is not supported.\n");
		return;
	}

	ff = open(file, O_RDONLY, 0);
	close(ff);

	if(file_exists(file)) {
		player->print("Room description so far:\n\n");
		viewLoginFile(player->getSock(), file);
		player->print("\n\n");
	}

	player->print("You may edit this room's long description now.\nType '.' or '*' on a line by itself to finish or '\\' to cancel.\nEach line should be NO LONGER THAN 80 CHARACTERS.\n-: ");

	strcpy(player->getSock()->tempstr[0], file);

	player->setFlag(P_READING_FILE);
	gServer->processOutput();
	player->getSock()->setState(CON_EDIT_PROPERTY);
	player->getSock()->intrpt &= ~1;
}

//*********************************************************************
//						manageShort
//*********************************************************************

void Property::manageShort(Player* player, cmd* cmnd, PropType propType, int x) {
	bstring desc = getFullstrText(cmnd->fullstr, 3-x);

	if(!Property::goodNameDesc(player, desc, "Set room short description to what?", "description string"))
		return;

	player->getUniqueRoomParent()->setShortDescription(desc);
	player->print("Property short description set to '%s'.\n", desc.c_str());
	player->getUniqueRoomParent()->saveToFile(0);
}

//*********************************************************************
//						manageName
//*********************************************************************

void Property::manageName(Player* player, cmd* cmnd, PropType propType, int x) {
	bstring name = getFullstrText(cmnd->fullstr, 3-x);

	if(!Property::goodNameDesc(player, name, "Rename this room to what?", "room name"))
		return;


	player->getUniqueRoomParent()->setName(name);
	player->print("Room renamed to '%s'.\n", player->getUniqueRoomParent()->getCName());
	player->getUniqueRoomParent()->saveToFile(0);
}

//*********************************************************************
//						manageFound
//*********************************************************************

void Property::manageFound(Player* player, cmd* cmnd, PropType propType, const Guild* guild, int x) {
	Object	*deed=0, *oHidden=0, *oConceal=0, *oInvis=0, *oFoyer=0;
	AreaRoom* aRoom = player->getAreaRoomParent();
	UniqueRoom* uRoom = player->getUniqueRoomParent();
	BaseRoom* room = player->getRoomParent();
	int canBuildFlag = Property::buildFlag(propType);
	CatRef cr;

	bstring xNameType = getTypeStr(propType);
	// caps!
	xNameType.setAt(0, toupper(xNameType.getAt(0)));

	if(!canBuildFlag || !room->flagIsSet(canBuildFlag)) {
		player->print("You can't build a %s here!\n", getTypeStr(propType).c_str());
		return;
	}


	const CatRefInfo* cri = gConfig->getCatRefInfo(room);

	if(!cri) {
		player->print("This area cannot support a %s.\n", getTypeStr(propType).c_str());
		return;
	}

	
	std::list<Property*>::const_iterator it;

	for(it = gConfig->properties.begin() ; it !=  gConfig->properties.end() ; it++) {
		if((*it)->getType() != propType)
			continue;
		if((*it)->getArea() != cri->getArea())
			continue;
		if(propType == PROP_STORAGE && !(*it)->isOwner(player->getName()) && !(*it)->isPartialOwner(player->getName()))
			continue;
		if(propType == PROP_GUILDHALL && player->getGuild() != (*it)->getGuild())
			continue;

		if(propType == PROP_GUILDHALL)
			player->print("Your guild already owns a guild hall in %s!\n", gConfig->catRefName(cri->getArea()).c_str());
		else if(propType == PROP_HOUSE)
			player->print("You already own a house in %s!\n", gConfig->catRefName(cri->getArea()).c_str());

		return;
	}

	
	bstring oName;
	for(Object* obj : player->objects) {
		// find their property related objects
		oName = obj->getName();
		if(	(propType == PROP_GUILDHALL && oName.left(10) == "guildhall ") ||
			(propType == PROP_HOUSE && oName.left(6) == "house ") )
		{

			if(	!deed && (
					(	propType == PROP_GUILDHALL &&
						oName.left(14) == "guildhall deed" &&
						(	(uRoom && obj->deed.belongs(uRoom->info)) ||
							(aRoom && obj->deed.isArea("area"))
						)
					) || (
						propType == PROP_HOUSE &&
						oName.left(10) == "house deed"
					)
				) )
			{
				deed = obj;

			// see if they want the entrance hidden
			} else if(oName.right(15) == "hidden entrance") {
				oHidden = obj;

			// see if they want the entrance concealed
			} else if(oName.right(18) == "concealed entrance") {
				oConceal = obj;

			// see if they want the entrance invisible
			} else if(oName.right(18) == "invisible entrance") {
				oInvis = obj;

			// see if they want a foyer
			} else if(oName.right(5) == "foyer") {
				oFoyer = obj;

			}

		}
	}

	if(!deed) {
		player->print("You need a deed to build a %s!\nVisit a real estate office.\n", getTypeStr(propType).c_str());
		return;
	}



	bstring xname = getFullstrText(cmnd->fullstr, 3-x);
	if(xname == "") {
		player->print("Please enter an exit name followed by the number of the room you wish to connect to.\n");
		return;
	}
	int roomId=0;
	for(int i = xname.getLength()-1; i>0; i--) {
		if(xname.getAt(i) == ' ') {
			roomId = atoi(xname.right(xname.getLength()-i).c_str());
			xname = xname.left(i);
			break;
		}
	}

	xname.Replace("_", " ");

	if(!Property::goodExit(player, room, xNameType.c_str(), xname))
		return;

	// determine what layout we're using!
	bstring layout = deed->getName();
	bstring orientation = "";
	int extra=0;
	int req=0;

	if(layout.right(12) == "5 room cross") {
		layout = layout.right(12);
		req = 5;
	} else if(layout.right(13) == "4 room square") {
		layout = layout.right(13);
		req = 4;
	} else if(layout.right(5) == "tower") {
		// 5 room tower
		layout = layout.right(12);
		req = atoi(layout.left(1).c_str());
		layout = layout.right(5);
	} else if(layout.right(11) == "small house") {
		layout = layout.right(11);
		roomId = req = 1;
	} else if(layout.right(12) == "medium house") {
		orientation = getFullstrText(layout, 3).left(1);
		if(orientation != "n" && orientation != "e")
			orientation = "n";
		layout = layout.right(12);
		req = 2;
	} else if(layout.right(11) == "large house") {
		orientation = getFullstrText(layout, 3).left(1);
		if(orientation == "n")
			extra = 0;
		else if(orientation == "e")
			extra = 1;
		else if(orientation == "s")
			extra = 2;
		else {
			orientation = "w";
			extra = 3;
		}
		layout = layout.right(11);
		req = 4;
	} else {
		player->print("The layout specified by your %s deed '%s' could not be determined!\n", getTypeStr(propType).c_str(), deed->getCName());
		return;
	}

	if(!roomId) {
		player->print("That is not a valid room number to connect to.\n");
		return;
	}

	cr = gConfig->getAvailableProperty(propType, req);
	if(cr.id < 1) {
		player->print("Sorry, you can't build a new %s right now; try again later!\n", getTypeStr(propType).c_str());
		return;
	}

	if(	roomId < 1 ||
		roomId > req ||
		(layout == "5 room cross" && roomId == 1)
	) {
		player->print("That is not a valid room number to connect to.\n");
		return;
	}


	Property *p = new Property;
	p->found(player, propType);

	// foyer needs 1 extra room
	p->addRange(cr.area, cr.id, cr.id + req - (oFoyer ? 0 : 1));

	if(propType == PROP_GUILDHALL) {
		p->setGuild(player->getGuild());
		p->setName(guild->getName() + "'s Guild Hall");
	} else if(propType == PROP_HOUSE) {
		bstring pName = player->getName();
		pName += "'s House";
		p->setName(pName);
	}

	// if they have a foyer, make one
	UniqueRoom* rFoyer=0;
	bstring xPropName = xname;
	if(oFoyer) {
		rFoyer = makeNextRoom(0, propType, cr, true, player, guild, room, xname, "", "", false);
		if(propType == PROP_GUILDHALL) {
			rFoyer->setFlag(R_GUILD_OPEN_ACCESS);
			xname = "guild";
		} else if(propType == PROP_HOUSE)
			xname = "house";
		room = rFoyer;
		cr.id++;
	}


	// this is where the work of creating the rooms is done.
	if(layout == "5 room cross") {

		UniqueRoom* r1 = makeNextRoom(0, propType, cr, false, player, guild, room, xname, "", "", false);

		cr.id++; // north
		makeNextRoom(r1, propType, cr, roomId == 2, player, guild, room, xname, "north", "south", true);
		cr.id++; // east
		makeNextRoom(r1, propType, cr, roomId == 3, player, guild, room, xname, "east", "west", true);
		cr.id++; // south
		makeNextRoom(r1, propType, cr, roomId == 4, player, guild, room, xname, "south", "north", true);
		cr.id++; // west
		makeNextRoom(r1, propType, cr, roomId == 5, player, guild, room, xname, "west", "east", true);

		roomSetup(r1, propType, player, guild);

	} else if(layout == "4 room square") {

		UniqueRoom* nw = makeNextRoom(0, propType, cr, roomId == 1, player, guild, room, xname, "", "", false);
		cr.id++; // northeast
		UniqueRoom* ne = makeNextRoom(nw, propType, cr, roomId == 2, player, guild, room, xname, "east", "west", false);
		cr.id++; // southwest
		UniqueRoom* sw = makeNextRoom(nw, propType, cr, roomId == 3, player, guild, room, xname, "south", "north", false);
		cr.id++; // southeast
		UniqueRoom* se = makeNextRoom(ne, propType, cr, roomId == 4, player, guild, room, xname, "south", "north", false);

		link_rom(se, sw->info, "west");
		link_rom(sw, se->info, "east");

		nw->arrangeExits();
		roomSetup(nw, propType, player, guild);
		ne->arrangeExits();
		roomSetup(ne, propType, player, guild);
		se->arrangeExits();
		roomSetup(se, propType, player, guild);
		sw->arrangeExits();
		roomSetup(sw, propType, player, guild);

	} else if(layout == "tower") {

		UniqueRoom* r1 = makeNextRoom(0, propType, cr, roomId == 1, player, guild, room, xname, "", "", false);
		int i=1;

		while(i < req) {
			i++;
			cr.id++;

			UniqueRoom* r2 = makeNextRoom(r1, propType, cr, roomId == i, player, guild, room, xname, "up", "down", false);

			r1->arrangeExits();
			roomSetup(r1, propType, player, guild);
			r1 = r2;
		}

		r1->arrangeExits();
		roomSetup(r1, propType, player, guild);

	} else if(layout == "small house") {

		makeNextRoom(0, propType, cr, true, player, guild, room, xname, "", "", true);

	} else if(layout == "medium house") {

		UniqueRoom* r1 = makeNextRoom(0, propType, cr, roomId == 1, player, guild, room, xname, "", "", false);

		cr.id++;
		if(orientation == "n")
			makeNextRoom(r1, propType, cr, roomId == 2, player, guild, room, xname, "south", "north", true);
		else
			makeNextRoom(r1, propType, cr, roomId == 2, player, guild, room, xname, "east", "west", true);
		roomSetup(r1, propType, player, guild);

	} else if(layout == "large house") {

		char dir1[10], dir2[10];
		UniqueRoom* r1 = makeNextRoom(0, propType, cr, roomId == 1, player, guild, room, xname, "", "", false);

		cr.id++;
		extra = rotateHouse(dir1, dir2, extra);
		makeNextRoom(r1, propType, cr, roomId == 2, player, guild, room, xname, dir1, dir2, true);

		cr.id++;
		extra = rotateHouse(dir1, dir2, extra);
		makeNextRoom(r1, propType, cr, roomId == 3, player, guild, room, xname, dir1, dir2, true);

		cr.id++;
		extra = rotateHouse(dir1, dir2, extra);
		makeNextRoom(r1, propType, cr, roomId == 4, player, guild, room, xname, dir1, dir2, true);

		r1->arrangeExits();
		roomSetup(r1, propType, player, guild);

	} else {

		if(rFoyer)
			delete rFoyer;

		player->print("There was an error in construction of your %s!\n", getTypeStr(propType).c_str());
		delete p;
		return;

	}

	if(rFoyer)
		roomSetup(rFoyer, propType, player, guild, true);
	gConfig->addProperty(p);

	if(propType == PROP_GUILDHALL) {
		player->print("Congratulations! Your guild is now the owner of a brand new guild hall.\n");
		if(!player->flagIsSet(P_DM_INVIS)) {
			broadcast(player->getSock(), player->getParent(), "%M just opened a guild hall!", player);
			broadcast("### %s, leader of %s, just opened a guild hall!", player->getCName(), guild->getName().c_str());
		}

		if(player->inUniqueRoom())
			sendMail(gConfig->getReviewer(), player->getName() + " (" + guild->getName() + ") opened a guild hall in " + gConfig->catRefName(player->getUniqueRoomParent()->info.area) + ".\n");
	} else if(propType == PROP_HOUSE) {
		player->print("Congratulations! You are now the owner of a brand new house.\n");
		if(!player->flagIsSet(P_DM_INVIS))
			broadcast(player->getSock(), player->getParent(), "%M just built a house!", player);
	}

	player->delObj(deed, true, false, true, false);
	delete deed;
	Exit* exit = findExit(player, xPropName, 1);
	if(oHidden) {
		if(exit) {
			player->delObj(oHidden, true, false, true, false);
			delete oHidden;
			exit->setFlag(X_SECRET);
			player->printColor("Exit '%s^x' is now hidden.\n", exit->getCName());
		} else {
			player->print("There was an error making the %s entrance hidden!\n", getTypeStr(propType).c_str());
		}
	}
	if(oConceal) {
		if(exit) {
			player->delObj(oConceal, true, false, true, false);
			delete oConceal;
			exit->setFlag(X_CONCEALED);
			player->printColor("Exit '%s^x' is now concealed.\n", exit->getCName());
		} else {
			player->print("There was an error making the %s entrance concealed!\n", getTypeStr(propType).c_str());
		}
	}
	if(oInvis) {
		if(exit) {
			player->delObj(oInvis, true, false, true, false);
			delete oInvis;
			exit->addEffect("invisibility", -1);
			player->printColor("Exit '%s^x' is now invisible.\n", exit->getCName());
		} else {
			player->print("There was an error making the %s entrance invisible!\n", getTypeStr(propType).c_str());
		}
	}
	if(oFoyer) {
		player->delObj(oFoyer, true, false, true, false);
		delete oFoyer;
	}
	player->checkDarkness();

	if(propType == PROP_GUILDHALL) {
		player->getUniqueRoomParent()->clearFlag(R_BUILD_GUILDHALL);
		player->getUniqueRoomParent()->setFlag(R_WAS_BUILD_GUILDHALL);
	} else if(propType == PROP_HOUSE) {
		player->getUniqueRoomParent()->clearFlag(R_BUILD_HOUSE);
		player->getUniqueRoomParent()->setFlag(R_WAS_BUILD_HOUSE);
	}
	player->getUniqueRoomParent()->saveToFile(0);
}

//*********************************************************************
//						manageExtend
//*********************************************************************

void Property::manageExtend(Player* player, cmd* cmnd, PropType propType, Property* p, const Guild* guild, int x) {
	BaseRoom* room = player->getRoomParent();
	Object* obj = player->findObject(player, cmnd, 3-x);
	CatRef cr;

	bstring xNameType = getTypeStr(propType);
	// caps!
	xNameType.setAt(0, toupper(xNameType.getAt(0)));
	
	if(!obj) {
		player->print("Object not found.\nYou need to purchase %s extensions from a realty office.\n", getTypeStr(propType).c_str());
		return;
	}


	bstring layout = obj->getName();
	if(	(propType == PROP_GUILDHALL && layout.left(19) != "guildhall extension") ||
		(propType == PROP_HOUSE && layout.left(15) != "house extension")
	) {
		player->printColor("%O is not a %s extension permit.\nYou need to purchase %s extensions from a realty office.\n",
			obj, getTypeStr(propType).c_str(), getTypeStr(propType).c_str());
		return;
	}
	layout = layout.right(layout.getLength() - 21);



	bstring xname = getFullstrText(cmnd->fullstr, 4-x);
	if(xname != "" && isdigit(xname.getAt(0)))
		xname = getFullstrText(xname, 1);

	xname.Replace("_", " ");
	if(!Property::goodExit(player, room, xNameType.c_str(), xname))
		return;


	cr = gConfig->getAvailableProperty(propType, 1);
	if(cr.id < 1) {
		player->print("Sorry, you can't expand your %s right now, try again later!\n", getTypeStr(propType).c_str());
		return;
	}


	UniqueRoom* target = new UniqueRoom;
	bool outside=false;

	if(layout == "normal room") {

		// normal rooms are acceptable

	} else if(layout == "outdoors") {

		outside = true;

	} else if(layout == "clinic") {

		target->setFlag(R_FAST_HEAL);

	} else if(layout == "post office") {

		target->setFlag(R_POST_OFFICE);

	} else if(layout == "recycling room") {

		target->setFlag(R_DUMP_ROOM);

	} else if(layout == "magic atrium") {

		target->setFlag(R_FAST_HEAL);
		target->setFlag(R_MAGIC_BONUS);

	} else {
		player->print("The extension type for this permit could not be determined!\n");
		delete target;
		return;
	}

	target->info = cr;
	linkRoom(player->getUniqueRoomParent(), target, xname);
	roomSetup(target, propType, player, guild, outside);

	player->delObj(obj, true);
	delete obj;

	player->print("Extension has been added to your property!\n");
	p->addRange(cr.area, cr.id, cr.id);
	gConfig->saveProperties();
}

//*********************************************************************
//						manageRename
//*********************************************************************

void Property::manageRename(Player* player, cmd* cmnd, PropType propType, int x) {
	BaseRoom* room = player->getRoomParent();
	bstring origExit = cmnd->str[3-x];
	bstring newExit = getFullstrText(cmnd->fullstr, 4-x);

	bstring xNameType = getTypeStr(propType);
	// caps!
	xNameType.setAt(0, toupper(xNameType.getAt(0)));

	if(origExit == "" || newExit == "") {
		player->print("Rename which exit to what?\n");
		return;
	}

	if(isCardinal(newExit)) {
		player->print("Exits cannot be made cardinal directions.\n");
		return;
	}
	if(!Property::goodExit(player, room, xNameType.c_str(), newExit))
		return;


	Exit* found = 0;
	bool unique=true;
	for(Exit* ext : room->exits ) {
		// exact match
		if(ext->getName() == origExit) {
			unique = true;
			found = ext;
			break;
		}
		if(!strncmp(ext->getCName(), origExit.c_str(), origExit.getLength())) {
			if(found)
				unique = false;
			found = ext;
		}
	}

	if(!unique) {
		player->print("That exit name is not unique.\n");
		return;
	}
	if(!found) {
		player->print("That exit was not found in this room.\n");
		return;
	}

	if(isCardinal(found->getName())) {
		player->print("Cardinal directions cannot be renamed.\n");
		return;
	}

	found->setName( newExit.c_str());
	player->getUniqueRoomParent()->arrangeExits();
	player->print("Exit renamed to '%s'.\n", newExit.c_str());
	player->getUniqueRoomParent()->saveToFile(0);
}

//*********************************************************************
//						manage
//*********************************************************************
// This function handles the commands for editting a property. It
// currently supports:
//		PROP_GUILDHALL
//		PROP_HOUSE

void Property::manage(Player* player, cmd* cmnd, PropType propType, int x) {
	BaseRoom* room = player->getRoomParent();
	const Guild* guild=0;
	Property *p=0;
	int canBuildFlag = Property::buildFlag(propType);

	int len = strlen(cmnd->str[2-x]);
	const char *syntax;

	if(player->getClass() == BUILDER) {
		player->print("Builders have no need to manage property.");
		return;
	}

	if(propType == PROP_GUILDHALL) {
		if(player->getGuild())
			guild = gConfig->getGuild(player->getGuild());

		if(!guild) {
			syntax = "Syntax:   guild hall ^e<^xsurvey^e> [^call^e]^x\n"
				"Shortcut: ^cgh         ^e<^xhelp^e>^x\n\n";
		} else {

			syntax = "Syntax:   guild hall ^e<^xsurvey^e> [^call^e]^x\n"
				"Shortcut: ^cgh         ^e<^xfound^e> <^cexit name^e> <^croom #^e>^x\n"
				"                     ^e<^xname^e> <^croom name^e>^x\n"
				"                     ^e<^xshort^e> <^cshort description^e>^x\n"
				"                     ^e<^xdesc^e>^x - will enter editor\n"
				"                     ^e<^xrename^e> <^cexit name^e> <^cnew name^e>^x\n"
				"                     ^e<^xextend^e> <^cobject^e> <^cexit name^e>^x\n"
				"                     ^e<^xhelp^e>^x\n\n";
		}
	} else if(propType == PROP_HOUSE) {
		// TODO: can-do rules will be complicated

		syntax = "Syntax: house ^e<^xsurvey^e> [^call^e]^x\n"
			"              ^e<^xfound^e> <^cexit name^e> <^croom #^e>^x\n"
			"              ^e<^xname^e> <^croom name^e>^x\n"
			"              ^e<^xshort^e> <^cshort description^e>^x\n"
			"              ^e<^xdesc^e>^x - will enter editor\n"
			"              ^e<^xrename^e> <^cexit name^e> <^cnew name^e>^x\n"
			"              ^e<^xextend^e> <^cobject^e> <^cexit name^e>^x\n"
			"              ^e<^xhelp^e>^x\n\n";
	}


	if(!len) {
		if(!guild)
			player->printColor("^yYou are not a member of a guild.\n");
		else
			guild->guildhallLocations(player, "Your guildhall is located at %s in %s.\n");
		player->printColor(syntax);
		return;
	}

	if(!strncmp(cmnd->str[2-x], "help", len)) {
		propHelp(player, cmnd, propType);
		return;
	}

	if(!strncmp(cmnd->str[2-x], "survey", len)) {
		if(canBuildFlag && !strcmp(cmnd->str[3-x], "all")) {
			player->print("Searching for suitable %s locations in this city.\n", getTypeStr(propType).c_str());
			findRoomsWithFlag(player, player->getUniqueRoomParent()->info, canBuildFlag);
		} else {
			if(!canBuildFlag || !room->flagIsSet(canBuildFlag))
				player->print("You are unable to build a %s here.\n", getTypeStr(propType).c_str());
			else
				player->print("This site is open for a %s to be constructed.\n", getTypeStr(propType).c_str());
		}
		return;
	}


	
	if(propType == PROP_GUILDHALL) {
		if(!guild) {
			player->printColor("^yYou are not a member of a guild.\n");
			player->printColor(syntax);
			return;
		}

		// inside correct guild?
	}


	// guild bankers can perform these commands
	if(propType != PROP_GUILDHALL || player->getGuildRank() >= GUILD_BANKER) {
		if(!strncmp(cmnd->str[2-x], "desc", len)) {
			if(!Property::requireInside(player, player->getConstUniqueRoomParent(), &p, propType))
				return;
			
			Property::manageDesc(player, cmnd, propType, x);
			return;
		}

		if(!strncmp(cmnd->str[2-x], "short", len)) {
			if(!Property::requireInside(player, player->getConstUniqueRoomParent(), &p, propType))
				return;

			Property::manageShort(player, cmnd, propType, x);
			return;
		}

		if(!strncmp(cmnd->str[2-x], "name", len)) {
			if(!Property::requireInside(player, player->getConstUniqueRoomParent(), &p, propType))
				return;

			Property::manageName(player, cmnd, propType, x);
			return;
		}
	}



	if(propType == PROP_GUILDHALL) {
		// everything else requires a guildmaster
		if(player->getGuildRank() != GUILD_MASTER) {
			player->print("You are not the leader of the guild.\n");
			return;
		}
	} else if(propType == PROP_HOUSE) {
		if(player->getLevel() < 15) {
			player->print("You must be atleast level 15 to build a personal house.\n");
			return;
		}
	}



	if(!strncmp(cmnd->str[2-x], "found", len)) {
		Property::manageFound(player, cmnd, propType, guild, x);
		return;
	}


	if(!Property::requireInside(player, player->getConstUniqueRoomParent(), &p, propType))
		return;

	if(!strncmp(cmnd->str[2-x], "extend", len)) {
		Property::manageExtend(player, cmnd, propType, p, guild, x);
		return;
	}
	if(!strncmp(cmnd->str[2-x], "rename", len)) {
		Property::manageRename(player, cmnd, propType, x);
		return;
	}


	if(!guild)
		player->printColor("^yYou are not a member of a guild.\n");
	else
		guild->guildhallLocations(player, "Your guildhall is located at %s in %s.\n");
	
	player->printColor(syntax);
}

//*********************************************************************
//						found
//*********************************************************************

void Property::found(const Player* player, PropType propType, bstring location, bool shouldSetArea) {
	setOwner(player->getName());
	setDateFounded();
	if(location == "")
		location = player->getConstUniqueRoomParent()->getName();
	setLocation(location);
	if(shouldSetArea && player->inUniqueRoom()) {
		bstring pArea = player->getConstUniqueRoomParent()->info.area;
		if(player->getConstUniqueRoomParent()->info.isArea("guild")) {
			// load the guild entrance, look for the out exit, load that room, get the area
			Property* p = gConfig->getProperty(player->getConstUniqueRoomParent()->info);

			CatRef cr = p->ranges.front().low;
			UniqueRoom* room=0;
			if(loadRoom(cr, &room)) {
				// Look for the first exit not linking to the shop
				for(Exit* ext : room->exits) {
					if(!ext->target.room.isArea("guild")) {
						pArea = ext->target.room.area;
						break;
					}
				}
			}
		}
		setArea(pArea);
	}
	setType(propType);
}