roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * 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-2009 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));
}

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

int Property::getGuild() const { return(guild); }
bstring Property::getOwner() const { return(owner); }
bstring Property::getName() const { return(name); }
bstring Property::getDateFounded() const { return(dateFounded); }
bstring Property::getLocation() const { return(location); }
PropType Property::getType() const { return(type); }
bstring	Property::getTypeStr() const { return(getTypeStr(type)); }
PropLog Property::getLogType() const { return(logType); }
void Property::setGuild(int g) { guild = g; }
void Property::setOwner(bstring str) { owner = str; }
void Property::setName(bstring str) { name = str; }
void Property::setDateFounded() {
	long    t = time(0);
	dateFounded = ctime(&t);
	dateFounded.trim();
}
void Property::setLocation(bstring str) { location = str; }
void Property::setType(PropType t) { type = t; }
void Property::setLogType(PropLog t) { logType = t; }

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

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

	while(curNode) {
			 if(NODE_NAME(curNode, "Owner")) xml::copyToBString(owner, 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);
					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;
	}
}

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

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

	xml::saveNonNullString(curNode, "Owner", owner.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(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 Room* 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)
	) {
		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->num != pGuild->num) &&
			(!prop || !prop->flagIsSet(PROP_GUILD_PUBLIC))
		) {
			if(p) player->checkStaff("You must belong to %s to go that way.\n", pGuild->name.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->name) &&
			!prop->isPartialOwner(player->name)
		) {
			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);
		}
	}

	xtag* xp = room->first_ext;
	while(xp) {
		if(!strcmp(xp->ext->name, xname.c_str())) {
			player->print("An exit with that name already exists in this room.\n");
			return(false);
		}
		xp = xp->next_tag;
	}

	return(true);
}

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

void Property::destroy() {
	BaseRoom* outside=0;
	AreaRoom* aRoom=0;
	Room	*room=0, *uRoom=0;
	xtag*	xp=0, *oxp=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 propery

				if(type != PROP_STORAGE) {
					// handle the exits that point outside
					xp = room->first_ext;
					while(xp) {
						if(	xp->ext->target.mapmarker.getArea() ||
							!xp->ext->target.room.isArea(room->info.area)
						) {
							outside = xp->ext->target.loadRoom();
							if(outside) {
								uRoom = outside->getUniqueRoom();
								aRoom = outside->getAreaRoom();

								// get rid of all exits
								oxp = outside->first_ext;
								while(oxp) {
									if(oxp->ext->target.room == room->info) {
										broadcast(NULL, outside, "%s closes its doors.", name.c_str());
										del_exit(outside, oxp->ext);
										oxp = outside->first_ext;
									}
									oxp = oxp->next_tag;
								}

								// 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();
								}
							}
						}
						xp = xp->next_tag;
					}
				}

				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(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(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;

	xmlDoc = xml::loadFile(CONFPATH "properties.xml", "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", CONFPATH);
	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

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

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

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

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->name) && !(*it)->isPartialOwner(player->name))
			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->area_room || !belongs(player->room))
		return;

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

	if(loadRoom(ranges.front().low, &uRoom)) {
		xtag *xp = uRoom->first_ext;
		uRoom = 0;

		while(xp) {
			newRoom = xp->ext->target.loadRoom(player);
			if(newRoom)
				break;
			xp = xp->next_tag;
		}
	}

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

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

	uRoom = newRoom->getUniqueRoom();
	aRoom = newRoom->getAreaRoom();

	if(offline) {
		if(uRoom)
			player->room = uRoom->info;
		else
			player->area_room = aRoom;
	} else {
		player->print("You are escorted off the premises.\n");
		broadcast(player->getSock(), player->parent_rom, "%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->name)) {
		// 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->name);
		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;
	}

	bstring name = "";
	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->name)) {
		player->print("%s is already a partial owner of this property.\n", target->name);

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

		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->name);

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

		p->assignPartialOwner(target->name);
		p->appendLog(target->name, "%s is now a partial owner.", target->name);
		player->print("%s is now a partial owner of this property.\n", target->name);
		if(!offline) {
			target->printColor( "^c%s has appointed you partial owner of %s.\n",
				player->name, 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->name);
		p->appendLog(target->name, "%s is no longer a partial owner.", target->name);
		player->print("%s is no longer a partial owner of this property.\n", target->name);
		if(!offline) {
			target->printColor( "^c%s has removed you as partial owner of %s.\n",
				player->name, 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->name)
				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->name);
	p->appendLog(player->name, "%s has resigned as partial owner.", player->name);

	Player* owner = gServer->findPlayer(p->getOwner().c_str());
	if(owner) {
		owner->printColor("^c%s has resigned as partial owner of %s.\n",
			player->name, 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->parent_rom)
		p = gConfig->getProperty(player->parent_rom->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->name);

	// 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->name) && !p->isPartialOwner(player->name)))
			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->name))
					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->name)) {

		// 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->name);
			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*propery [num]^x to view more info.\n");
		player->printColor("Properties: Type ^c*propery [type]^x to filter the list.\n");
		player->printColor("Properties: Type ^c*propery 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*propery destroy [num] [owner]^x\n");
			return(0);
		}
		cmnd->str[2][0] = up(cmnd->str[2][0]);

		player->print("Looking to destroy propery #%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 << "^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) {
		Guild *g = gConfig->getGuild(guild);

		if(!guild) {
			if(type == PROP_GUILDHALL)
				oStr << "This guildhall is broken: guild ID " << guild << " does not exist.\n";
		} else {
			oStr << "Guild:    ^c#" << guild << " ^c" << g->name << "^x\n";
			std::list<bstring>::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->name;

	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();
}

//*********************************************************************
//						getProperties
//*********************************************************************

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(Room* room, char* name);
void setupShop(Player* player, Guild* guild, Room* shop, Room* storage);

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

	if(type == PROP_STORAGE) {
		if(loadRoom(ranges.front().low, &storage)) {
			storageName(storage, player->name);
			setName(storage->name);
			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(player, 0, shop, storage);
					setName(shop->name);
				}
			}
		}
	}
}

//*********************************************************************
//						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(Room *room, const Guild* guild, bool outside) {
	sprintf(room->name, "%s's Guild Hall", guild->name.c_str());

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

	room->setShortDescription("You are in the ");
	room->appendShortDescription(guild->name);
	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(Room *room, const Player* player, bool outside) {
	sprintf(room->name, "%s's Personal House", player->name);

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

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

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

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

void Property::roomSetup(Room *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) {
	Room* uRoom = outside->getUniqueRoom();
	AreaRoom* aRoom = outside->getAreaRoom();
	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->getUniqueRoom();
	aRoom = inside->getAreaRoom();
	if(uRoom) {
		link_rom(outside, uRoom->info, "out");
		uRoom->saveToFile(0);
	} else {
		link_rom(outside, &aRoom->mapmarker, "out");
		aRoom->save();
	}
}

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

Room* Property::makeNextRoom(Room* 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) {
	Room *r2 = new Room;
	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");

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

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

bool Property::isInside(const Player* player, const Room* 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 Room* room, Property** p, PropType propType) {
	if(room)
		(*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(char* str);

void Property::descEdit(Socket* sock, char *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->parent_rom, &p))
			return;

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

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

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

		ply->print("Room description replaced.\n");
		ply->parent_rom->escapeText();
		ply->parent_rom->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);
}



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

	return(false);
}


//*********************************************************************
//						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) {
	AreaRoom* aRoom = player->area_room;
	Room* uRoom = player->parent_rom;
	BaseRoom* room = player->getRoom();
	Guild* guild=0;
	CatRef	cr;

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

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

	if(propType == PROP_GUILDHALL) {
		canBuild = room->flagIsSet(R_BUILD_GUILDHALL);

		syntax = "Syntax:   guild hall ^e<^xsurvey^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>^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) {
		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(!canBuild)
			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;
	}



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



	if(propType == PROP_GUILDHALL) {
		if(player->getGuild())
			guild = gConfig->getGuild(player->getGuild());
		if(!guild) {
			player->printColor("^yYou are not a member of a guild.\n");
			player->printColor(syntax);
			return;
		}
		// everything else requires a guildmaster
		if(player->getGuildRank() != GUILD_MASTER) {
			player->print("You are not the leader of a 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)) {
		Object	*deed=0, *oHidden=0, *oConceal=0, *oInvis=0, *oFoyer=0;

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


		cr = gConfig->getSingleProperty(player, propType);
		if(cr.id) {
			if(propType == PROP_GUILDHALL)
				player->print("Your guild already owns a guild hall.\nOnly one is allowed per guild.\n");
			else if(propType == PROP_HOUSE)
				player->print("You already own a house!\n");
			return;
		}

		otag* op = player->first_obj;
		bstring oName;
		while(op) {
			// find their property related objects
			oName = op->obj->name;
			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 && op->obj->deed.belongs(uRoom->info)) ||
								(aRoom && op->obj->deed.isArea("area"))
							)
						) || (
							propType == PROP_HOUSE &&
							oName.left(10) == "house deed"
						)
				) ) {
					deed = op->obj;

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

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

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

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

				}

			}

			op = op->next_tag;
		}

		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->name;
		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->name);
			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->setOwner(player->name);
		p->setDateFounded();
		p->setLocation(player->parent_rom->name);
		p->setType(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->name + "'s Guild Hall");
		} else if(propType == PROP_HOUSE) {
			{
			bstring pName = player->name;
			pName += "'s House";
			p->setName(pName);
			}
		}

		// if they have a foyer, make one
		Room* 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") {

			Room* 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") {

			Room* nw = makeNextRoom(0, propType, cr, roomId == 1, player, guild, room, xname, "", "", false);
			cr.id++; // northeast
			Room* ne = makeNextRoom(nw, propType, cr, roomId == 2, player, guild, room, xname, "east", "west", false);
			cr.id++; // southwest
			Room* sw = makeNextRoom(nw, propType, cr, roomId == 3, player, guild, room, xname, "south", "north", false);
			cr.id++; // southeast
			Room* 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") {

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

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

				Room* 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") {

			Room* 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];
			Room* 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->getRoom(), "%M just opened a guild hall!", player);
				broadcast("### %s, leader of %s, just opened a guild hall!", player->name, guild->name.c_str());
			}
		} 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->getRoom(), "%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->print("Exit '%s' is now hidden.\n", exit->name);
			} 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->print("Exit '%s' is now concealed.\n", exit->name);
			} 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->setFlag(X_INVISIBLE);
				player->print("Exit '%s' is now invisible.\n", exit->name);
			} 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->parent_rom->clearFlag(R_BUILD_GUILDHALL);
			player->parent_rom->setFlag(R_WAS_BUILD_GUILDHALL);
		} else if(propType == PROP_HOUSE) {
			player->parent_rom->clearFlag(R_BUILD_HOUSE);
			player->parent_rom->setFlag(R_WAS_BUILD_HOUSE);
		}
		player->parent_rom->saveToFile(0);
		return;
	}


	Property *p=0;
	if(!Property::requireInside(player, player->parent_rom, &p, propType))
		return;

	if(!strncmp(cmnd->str[2-x], "extend", len)) {

		Object* obj = findObject(player, player->first_obj, cmnd, 3-x);

		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->name;
		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;
		}


		Room* target = new Room;
		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->parent_rom, 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();

	} else if(!strncmp(cmnd->str[2-x], "desc", len)) {

		char	file[80];
		int		ff=0;


		checkDirExists(POSTPATH, true);


		switch(propType) {
		case PROP_GUILDHALL:
			sprintf(file, "%s/%s_guildhall.txt", POSTPATH, player->name);
			break;
		case PROP_HOUSE:
			sprintf(file, "%s/%s_house.txt", POSTPATH, player->name);
			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;

	} else if(!strncmp(cmnd->str[2-x], "short", len)) {

		bstring desc = getFullstrText(cmnd->fullstr, 3-x);

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

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

	} else if(!strncmp(cmnd->str[2-x], "name", len)) {

		bstring name = getFullstrText(cmnd->fullstr, 3-x);

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

		strcpy(player->parent_rom->name, name.c_str());
		player->print("Room renamed to '%s'.\n", player->parent_rom->name);
		player->parent_rom->saveToFile(0);

	} else if(!strncmp(cmnd->str[2-x], "rename", len)) {

		bstring origExit = cmnd->str[3-x];
		bstring newExit = getFullstrText(cmnd->fullstr, 4-x);

		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;


		xtag *xp = player->parent_rom->first_ext, *found=0;
		bool unique=true;
		while(xp) {
			// exact match
			if(!strcmp(xp->ext->name, origExit.c_str())) {
				unique = true;
				found = xp;
				break;
			}
			if(!strncmp(xp->ext->name, origExit.c_str(), origExit.getLength())) {
				if(found)
					unique = false;
				found = xp;
			}
			xp = xp->next_tag;
		}

		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->ext->name)) {
			player->print("Cardinal directions cannot be renamed.\n");
			return;
		}

		strcpy(found->ext->name, newExit.c_str());
		player->parent_rom->arrangeExits();
		player->print("Exit renamed to '%s'.\n", newExit.c_str());
		player->parent_rom->saveToFile(0);

	}
}