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/
/*
 * movement.cpp
 *	 Functions dealing with player movement.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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 "commands.h"
#include <string>
#include "guilds.h"
#include "property.h"
#include "move.h"
#include "unique.h"
#include "calendar.h"
#include "magic.h"

//*********************************************************************
//						tooFarAway
//*********************************************************************

bool Move::tooFarAway(BaseRoom* pRoom, BaseRoom* tRoom, bool track) {
	if(pRoom == tRoom)
		return(false);
	if(!pRoom || !tRoom || pRoom->flagIsSet(R_JAIL) || tRoom->flagIsSet(R_JAIL))
		return(true);

	const CatRefInfo*	pr = gConfig->getCatRefInfo(pRoom);
	if(!pr)
		return(true);
	const CatRefInfo*	tr = gConfig->getCatRefInfo(tRoom);
	if(!tr)
		return(true);

	if(pr->teleportZone != tr->teleportZone)
		return(true);
	if(track && pr->trackZone != tr->trackZone)
		return(true);

	return(false);
}

bool Move::tooFarAway(Creature *player, BaseRoom* room) {
	if(player->isStaff())
		return(false);

	if(!room || Move::tooFarAway(player->getRoom(), room, false)) {
		player->print("That location is too far away.\n");
		return(true);
	}

	return(false);
}

bool Move::tooFarAway(Creature *player, Creature *target, bstring action) {
	if(player->isStaff())
		return(false);

	BaseRoom* tRoom = target->getRoom();
	// target is offline, so we need to load their room
	if(!tRoom) {
		Room *room=0;
		if(target->room.id && loadRoom(target->room, &room))
			tRoom = room;
	}

	if(!tRoom || Move::tooFarAway(player->getRoom(), tRoom, action == "track")) {
		player->print("%M is too far away to %s.\n", target, action.c_str());
		return(true);
	}

	return(false);
}

//*********************************************************************
//						broadcast
//*********************************************************************

void Move::broadcast(Creature* player, BaseRoom* room, bool ordinal, bstring exit, bool hiddenExit) {
	bstring strAction = Move::getString(player, ordinal, exit);
	bool noShow = (player->isPlayer() && player->flagIsSet(P_DM_INVIS));

	if(!noShow) {
		if(player->isMonster() || !player->flagIsSet(P_MISTED)) {
			if(hiddenExit)
				broadcast(player->getSock(), room, "%M slips out of sight.", player);
			else
				broadcast(player->getSock(), room, "%M %s %s.", player, strAction.c_str(), exit.c_str());
		} else if(player->flagIsSet(P_MISTED) && !player->flagIsSet(P_DM_INVIS)) {
			if(hiddenExit)
				broadcast(player->getSock(), room, "A light mist slips out of sight.");
			else
				broadcast(player->getSock(), room, "A light mist %s %s.", strAction.c_str(), exit.c_str());
		}
	}

	if(noShow || hiddenExit) {
		if(player->isDm())
			broadcast(isDm, player->getSock(), room, "*STAFF* %M %s %s.", player, strAction.c_str(), exit.c_str());
		if(player->getClass() == CARETAKER)
			broadcast(isCt, player->getSock(), room, "*STAFF* %M %s %s.", player, strAction.c_str(), exit.c_str());
		if(!player->isCt())
			broadcast(isStaff, player->getSock(), room, "*STAFF* %M %s %s.", player, strAction.c_str(), exit.c_str());
	}
}


//*********************************************************************
//						formatFindExit
//*********************************************************************
// This function allows for multi-word desc-only exits.

bstring Move::formatFindExit(cmd* cmnd) {
	bstring str;
	int		i=0;

	str = "";
	for(i=1; i<cmnd->num; i++) {
		if(cmnd->str[i][0]) {
			str += cmnd->str[i];
			str += " ";
		}
	}
	if(str.length()>1)
		str = str.substr(0, str.length() - 1);
	return(str);
}


//*********************************************************************
//						isSneaking
//*********************************************************************
// if we're sneaking

bool Move::isSneaking(cmd* cmnd) {
	return(!strncmp(cmnd->str[0], "sn", 2));
}

//*********************************************************************
//						isOrdinal
//*********************************************************************
// if it's an ordinal move

bool Move::isOrdinal(cmd* cmnd) {
	// Ordinal if not go, enter, exit, or sneak
	return(	strncmp(cmnd->str[0], "go", 2) &&
			strncmp(cmnd->str[0], "en", 2) &&
			strncmp(cmnd->str[0], "ex", 2) &&
			!Move::isSneaking(cmnd) );
}

//*********************************************************************
//						recycle
//*********************************************************************
// given the room we just left (everyone is out) this code handles the
// recycling of the room

AreaRoom *Move::recycle(AreaRoom* room, Exit* exit) {
	if(room->canDelete()) {
		room->setMapMarker(&exit->target.mapmarker);
		room->recycle();
	} else {
		room = new AreaRoom(room->area, &exit->target.mapmarker);
		room->area->rooms[room->mapmarker.str()] = room;
	}
	return(room);
}

//*********************************************************************
//						update
//*********************************************************************
// updates some settings on the character once they move

void Move::update(Player* player) {
	if(	player->getRoom()->isUnderwater() && !player->flagIsSet(P_FREE_ACTION)) {
		player->lasttime[LT_MOVED].ltime = time(0);
		player->lasttime[LT_MOVED].interval = 2L;
	}

	if(player->flagIsSet(P_SITTING)) {
		player->print("You stand up.\n");
		if(player->getRoom())
			broadcast(player->getSock(), player->getRoom(), "%M stands up.", player);
		player->clearFlag(P_SITTING);
	}

	player->clearFlag(P_JUST_TRAINED);

	player->lasttime[LT_MOVED].misc++;
}


//*********************************************************************
//						broadMove
//*********************************************************************
// announces to the room we're leaving that we're leaving

void Move::broadMove(Creature* player, Exit* exit, cmd* cmnd, bool sneaking) {

	if(exit->getEnter() != "")
		player->printColor("%s\n", exit->getEnter().c_str());

	// sneak failure is decided earlier
	if(!sneaking) {
		Move::broadcast(
			player,
			player->getRoom(),
			Move::isOrdinal(cmnd),
			exit->name,
			exit->flagIsSet(X_SECRET) || exit->isConcealed() || exit->flagIsSet(X_DESCRIPTION_ONLY)
		);
	} else {
		if(player->isDm())
			broadcast(isDm, player->getSock(), player->getRoom(), "*DM* %M snuck to the %s.", player, exit->name);
		if(player->getClass() == CARETAKER)
			broadcast(isCt, player->getSock(), player->getRoom(), "*DM* %M snuck to the %s.", player, exit->name);
		if(!player->isCt())
			broadcast(isStaff, player->getSock(), player->getRoom(), "*DM* %M snuck to the %s.", player, exit->name);
		player->checkImprove("sneak", true);
	}
}



//*********************************************************************
//						track
//*********************************************************************
// takes care of any tracks we leave

bool Move::track(Room* room, MapMarker *mapmarker, Exit* exit, Player* player, bool reset) {
	if(room && room->flagIsSet(R_PERMENANT_TRACKS))
		return(reset);
	if(exit->flagIsSet(X_DESCRIPTION_ONLY))
		return(reset);

	if(	player &&
		!player->isEffected("fly") &&
		!player->isEffected("levitate") &&
		!player->isEffected("pass-without-trace") &&
		!player->isStaff()
	) {
		Track *track=0;

		if(room)
			track = &room->track;
		else if(mapmarker) {

			Area *area = gConfig->getArea(mapmarker->getArea());
			if(area) {
				track = area->getTrack(mapmarker);
				// only make tracks if they will last longer than 0 minutes
				if(!track && area->getTrackDuration(mapmarker)) {
					AreaTrack *aTrack = new AreaTrack;

					*&aTrack->mapmarker = *mapmarker;
					aTrack->setDuration(area->getTrackDuration(mapmarker));

					area->addTrack(aTrack);
					track = &aTrack->track;
				}
			}
		}

		if(track) {
			if(!reset) {
				track->setNum(0);
				track->setSize(NO_SIZE);
			}
			track->setDirection(exit->name);
			if(player->getSize() > track->getSize())
				track->setSize(player->getSize());
			track->setNum(track->getNum()-1);
			return(true);
		}
	}
	return(reset);
}

void Move::track(Room* room, MapMarker *mapmarker, Exit* exit, Player *leader, std::list<Creature*> *followers) {
	std::list<Creature*>::iterator it;
	bool	reset=false;

	if(!room && !mapmarker)
		return;
	if(room && room->flagIsSet(R_PERMENANT_TRACKS))
		return;
	if(exit->flagIsSet(X_DESCRIPTION_ONLY))
		return;

	// the leader is not stored in the list
	reset = Move::track(room, mapmarker, exit, leader, reset);

	for(it = followers->begin() ; it != followers->end() ; it++)
		reset = Move::track(room, mapmarker, exit, (*it)->getPlayer(), reset);
}


//*********************************************************************
//						sneak
//*********************************************************************
// handles our attempted sneaking

bool Move::sneak(Player* player, bool sneaking) {

	if(sneaking && player->flagIsSet(P_MISTED))
		player->setFlag(P_SNEAK_WHILE_MISTED);

	if(!player->isStaff() && !player->flagIsSet(P_MISTED)) {

		// see if they failed sneaking or not
		if(sneaking && (
				!player->flagIsSet(P_HIDDEN) ||
				mrand(1, 100) > player->getSneakChance()
			)
		) {
			player->checkImprove("sneak", false);
			player->print("You failed to sneak.\n");
			sneaking = false;
		}

	}

	if(!sneaking)
		player->unhide();

	return(sneaking);
}

//*********************************************************************
//						canEnter
//*********************************************************************
// this function determines if we're allowed to go in the exit provided
// it should print the reason for failure

bool Move::canEnter(Player* player, Exit* exit, bool leader) {
	Monster* pet = player->getPet();

	// this also keeps builders out of overland rooms
	if(!player->checkBuilder(exit->target.room))
		return(false);

	// sending true to this function will print the reason
	// why they can't enter
	if(!player->canEnter(exit, true))
		return(false);
	if(pet && !pet->canEnter(exit) && !player->checkStaff("%M cannot go that way.\n", pet))
		return(false);

	if(player->isStaff())
		return(true);

	// This is handled here and not in canEnter. If it were in canEnter,
	// they wouldn't be able to flee past the monster.
	ctag *cp = player->getRoom()->first_mon;
	while(cp) {
		Monster* mon = cp->crt->getMonster();
		if(	mon->flagIsSet(M_BLOCK_EXIT) &&
			mon->isEnmCrt(player->name) &&
			mon->canSee(player)
		) {
			player->print("%M blocks your exit.\n", mon);
			return(false);
		}
		cp = cp->next_tag;
	}


	if(	(exit->flagIsSet(X_NEEDS_CLIMBING_GEAR) || exit->flagIsSet(X_CLIMBING_GEAR_TO_REPEL)) &&
	    !player->isEffected("levitate") &&
		!player->flagIsSet(P_MISTED)
	) {
		int fall = (exit->flagIsSet(X_DIFFICULT_CLIMB) ? 50 : 0) + 50 - player->getFallBonus();

		if(mrand(1, 100) < fall) {
			int dmg = mrand(5, 15 + fall / 10);

			player->printColor("You fell and hurt yourself for %s%d^x damage.\n", player->customColorize("*CC:DAMAGE*"), dmg);
			broadcast(player->getSock(), player->getRoom(), "%M fell down.", player);
			broadcastGroup(false, player, "%M fell and took *CC:DAMAGE*%d^x damage, %s%s\n",
				player, dmg, player->heShe(), player->getStatusStr(dmg));

			player->hp.decrease(dmg);
			if(player->hp.getCur() <= 0) {
				player->print("You fell to your death.\n");
				player->hp.setCur(0);
				broadcast(player->getSock(), player->getRoom(), "%M died from the fall.\n", player);
				player->die(FALL);
				return(false);
			}

			if(exit->flagIsSet(X_NEEDS_CLIMBING_GEAR)) {
				player->print("You need climbing gear to go that way.\n");
				return(false);
			}
		}
	}

	// don't follow someone to an incorrect bound room
	// only if you arent trying to walk yourself through
	if(	!leader &&
		exit->flagIsSet(X_TO_BOUND_ROOM) &&
		player->following &&
		player->following->getPlayer() &&
		player->bound != player->following->getPlayer()->bound
	)
		return(false);

	return(true);
}


//*********************************************************************
//						canMove
//*********************************************************************
// this runs the checks to see if we're even able to go anywhere
// failure should print a message

bool Move::canMove(Player* player, cmd* cmnd) {

	player->clearFlag(P_AFK);

	if(!player->ableToDoCommand())
		return(false);

	if(player->isStaff())
		return(true);

	if(player->isEffected("hold-person")) {
		player->print("You are unable to move right now.\n");
		return(false);
	}

	if(	player->getTotalBulk() > player->getMaxBulk() ||
		player->getWeight() > player->maxWeight()
	) {
		player->print("You are carrying too many things to move!\n");
		return(false);
	}

	if(!player->flagIsSet(P_STUNNED))
		if(player->checkConfusion())
			return(false);

	if(Move::isSneaking(cmnd)) {
	 	if(!player->flagIsSet(P_HIDDEN) && !player->flagIsSet(P_MISTED)) {
	 		player->print("You need to hide first.\n");
	 		return(false);
	 	}
		if(player->getRoom()->isUnderwater()) {
			player->print("You can't sneak here! You're too busy swimming!\n");
	        return(false);
		}
		if(player->inCombat()) {
			player->print("How do you expect to sneak in the middle of battle?!\n");
			return(false);
		}
		if(player->flagIsSet(P_SITTING)) {
			player->print("You have to stand up first.\n");
			return(false);
		}
	}


	int		chance=0, moves=0;
	long	t = time(0);
	long	s = LT(player, LT_SPELL);
	long	u = LT(player, LT_MOVED);


	if(u - t > 0 && player->getRoom()->isUnderwater() && !player->flagIsSet(P_FREE_ACTION)) {
		player->pleaseWait(u - t);
		return(0);
	}

	if(Move::isSneaking(cmnd) || player->flagIsSet(P_RUNNING)) {
		if(t < s) {
			player->pleaseWait(s - t);
			return(0);
		}
		if(!player->checkAttackTimer())
			return(0);
	} else {
		chance = MAX(1, ((5+(player->dexterity.getCur()/10)*3) - player->getArmorWeight() + player->strength.getCur()));

		if(player->getClass() == RANGER || player->getClass() == DRUID)
			chance += 5;
		if(player->isEffected("levitate"))
			chance += 5;

		if(	player->getRoom()->flagIsSet(R_DIFFICULT_TO_MOVE) &&
			!player->isEffected("fly") &&
			!player->flagIsSet(P_MISTED) &&
			!player->flagIsSet(P_FREE_ACTION)
		)
			moves = 1;
		else
			moves = 3;

		// check for speed move
		if(	player->lasttime[LT_MOVED].ltime == t || (
				player->getRoom()->flagIsSet(R_DIFFICULT_TO_MOVE) &&
				!player->isEffected("fly") &&
				!player->flagIsSet(P_FREE_ACTION) &&
		        !player->flagIsSet(P_MISTED) &&
		        mrand(1,100) > chance
			)
		) {
			if(player->lasttime[LT_MOVED].misc > moves) {
				if(moves == 1) {
					if(player->getRoom()->flagIsSet(R_EARTH_BONUS)) {
						player->print("You are stuck in the mud!\n");
						broadcast(player->getSock(), player->getRoom(), "%M got stuck in the mud!", player);
					} else if(player->getRoom()->flagIsSet(R_AIR_BONUS)) {
						player->print("The strong wind knocks you from your feet!\n");
						broadcast(player->getSock(), player->getRoom(), "%M got blown over by the wind!", player);
					} else if(player->getRoom()->flagIsSet(R_FIRE_BONUS)) {
						player->print("You are knocked down by heat waves!\n");
						broadcast(player->getSock(), player->getRoom(), "%M got knocked down by heat waves!", player);
					} else if(player->getRoom()->flagIsSet(R_WATER_BONUS)) {
						player->print("Strong water currents make you lose balance!\n");
						broadcast(player->getSock(), player->getRoom(), "%M got knocked down by the current!", player);
					} else if(player->getRoom()->flagIsSet(R_COLD_BONUS) || player->getRoom()->isWinter()) {
						player->print("You are stuck in the ice and snow!\n");
						broadcast(player->getSock(), player->getRoom(), "%M got stuck in the ice and snow!", player);
					} else if(player->getRoom()->flagIsSet(R_ELEC_BONUS)) {
						player->print("Strong magnetic forces knock you down!\n");
						broadcast(player->getSock(), player->getRoom(), "%M got knocked down by magnetic forces!", player);
					} else {
						player->print("You are stuck!!\n");
						broadcast(player->getSock(), player->getRoom(), "%M got stuck!", player);
					}
				}
				player->pleaseWait(1);
				return(0);
			}
		} else {
			player->lasttime[LT_MOVED].ltime = t;
			player->lasttime[LT_MOVED].misc = 1;
		}


		if(player->lasttime[LT_PLAYER_STUNNED].ltime+(player->lasttime[LT_PLAYER_STUNNED].interval) > t) {
			player->pleaseWait((player->lasttime[LT_PLAYER_STUNNED].interval + 1) - t + player->lasttime[LT_PLAYER_STUNNED].ltime - 1 );
			return(0);
		}

		// fix walking bug here
		if(player->getLTAttack()+3 > t) {
			player->pleaseWait(3-t+player->getLTAttack());
			return(false);
		// and here
		} else if(player->lasttime[LT_SPELL].ltime+3 > t) {
			player->pleaseWait(3-t+player->lasttime[LT_SPELL].ltime);
			return(false);
		// this fixes walking steal
		} else if(player->lasttime[LT_STEAL].ltime+3 > t) {
			player->pleaseWait(3-t+player->lasttime[LT_STEAL].ltime);
			return(false);
		}

	}

	return(true);
}

//*********************************************************************
//						getExit
//*********************************************************************
// this looks through the exits in the room and finds the one we want
// to go to

Exit *Move::getExit(Creature* player, cmd* cmnd) {
	BaseRoom* room = player->getRoom();
	xtag	*xp=0;
	Exit	*exit=0;

	if(player->isPet())
		player = player->following;

	if(Move::isOrdinal(cmnd)) {
		xp = room->first_ext;
		while(xp) {
			if(	!strcmp(xp->ext->name, cmnd->str[1]) &&
				player->canSee(xp->ext) &&
				!(!player->isStaff() && xp->ext->flagIsSet(X_DESCRIPTION_ONLY))
			) {
				exit = xp->ext;
				break;
			}
			xp = xp->next_tag;
		}
	} else {
		if(strlen(cmnd->fullstr) < 3)
			return(0);

		exit = findExit(player, Move::formatFindExit(cmnd), cmnd->val[cmnd->num-1], room->first_ext);
	}
	return(exit);
}

//*********************************************************************
//						drunkenStumble
//*********************************************************************
// whether or not a person should stumble when drunk

bool drunkenStumble(const EffectInfo* effect) {
	AlcoholState state = getAlcoholState(effect);
	switch(state) {
	case ALCOHOL_TIPSY:
		// 33%
		return(!mrand(0,2));
	case ALCOHOL_DRUNK:
		// 75%
		return(!!mrand(0,3));
	case ALCOHOL_INEBRIATED:
		// 100%
		return(true);
	default:
		// 0%
		return(false);
	}
}

//*********************************************************************
//						getString
//*********************************************************************
// gives us the text of the movement string

bstring Move::getString(Creature* creature, bool ordinal, bstring exit) {
	bstring str = "";
	int		num=0;

	if(creature->getPlayer()) {

		if(creature->isStaff())
			str = "wanders to the";
		else if(creature->getRoom()->isUnderwater())
			str = "swam to the";
		else if(creature->isEffected("fly"))
			str = "flew to the";
		else if(creature->isEffected("levitate") || creature->flagIsSet(P_MISTED))
			str = "floats to the";
		else if(creature->isEffected("confusion") || drunkenStumble(creature->getEffect("drunkenness")))
			str = "stumbles to the";
		// Not ordinal, not up, not down, and not out
		else if( !ordinal &&
			exit != "up" &&
			exit != "down" &&
			exit != "out"
		)
			str = "went to the";
		else
			str = "leaves";

	} else {

		if(	creature->movetype[0][0] ||
			creature->movetype[1][0] ||
			creature->movetype[2][0]
		) {

			do {
				num = mrand(1, 3);
				if(creature->movetype[num-1][0])
					str = creature->movetype[num-1];
			} while(!creature->movetype[num-1][0]);

		} else if(creature->getRoom()->isUnderwater())
			str = "swam to the";
		else if(creature->isEffected("fly"))
			str = "flew to the";
		else if(creature->isEffected("levitate"))
			str = "floats to the";
		else
			str = "wanders";

	}

	return(str);
}



//*********************************************************************
//						checkFollowed
//*********************************************************************
// this sees if any monsters plan on following the people leaving the
// room, adding them to the list if they want to tag along for the ride

void Move::checkFollowed(Player* player, Exit* exit, BaseRoom* room, std::list<Creature*> *followers) {
	Monster *target=0;
	ctag	*cp=0;
	if(!room)
		return;

	cp = room->first_mon;
	while(cp) {
		target = (Monster*)cp->crt;
		cp = cp->next_tag;

		if(!target->flagIsSet(M_FOLLOW_ATTACKER) || target->flagIsSet(M_DM_FOLLOW))
			continue;
		if(!target->first_enm)
			continue;
		if(strcmp(target->first_enm->enemy, player->name))
			continue;

		// Protect the newbie areas from aggro-dragging
		if(target->flagIsSet(M_AGGRESSIVE) && exit->flagIsSet(X_PASSIVE_GUARD))
			continue;

		if(!target->canSee(player))
			continue;
		if(!target->canEnter(exit))
			continue;

		if(mrand(1,20) > 10 - (player->dexterity.getCur()/10) + target->dexterity.getCur()/10)
			continue;

		player->print("%M followed you.\n", target);
		broadcast(player->getSock(), room, "%M follows %N.", target, player);

		// prevent players from continuously creating new monsters
		if(target->flagIsSet(M_PERMENANT_MONSTER))
			target->diePermCrt();

		target->clearFlag(M_PERMENANT_MONSTER);
		gServer->addActive(target);

		target->deleteFromRoom();

		followers->push_back(target);
	}

}



//*********************************************************************
//						finish
//*********************************************************************
// this finishes up all the work of adding people to the room

void Move::finish(Creature* creature, BaseRoom* room, Room* uRoom, bool self, std::list<Creature*> *followers) {
	Player	*player = creature->getPlayer();
	Monster *monster = creature->getMonster();

	if(player)
		player->addToRoom(room);
	else
		monster->addToRoom(room);

	if(followers && !followers->empty()) {
		while(!followers->empty()) {
			Move::finish(followers->front(), room, uRoom, false, 0);
			followers->pop_front();
		}
		followers->clear();
	}

	if(player && uRoom)
		player->checkTraps(uRoom, self);
}


//*********************************************************************
//						getRoom
//*********************************************************************
// loads up the room. handles moving into the room through an exit
// (walk/flee), looking into the room (scout/yell), and appearing in
// the room (teleport)
// creature is allowed to be null if we're just trying to load the room
// out of the exit.

bool Move::getRoom(Creature* creature, Exit* exit, Room **uRoom, AreaRoom **aRoom, bool justLooking, MapMarker* teleport, bool recycle) {
	Player* player = creature->getPlayer();
	Location l;

	// pets can go where players can go
	if(!player && creature && creature->isPet())
		player = creature->following->getPlayer();

	// find out where the exit actually points

	if(creature && exit && (
		exit->flagIsSet(X_TO_BOUND_ROOM) ||
		exit->flagIsSet(X_TO_PREVIOUS) ||
		exit->flagIsSet(X_TO_STORAGE_ROOM)
	) ) {
		// flags can cause us to completely ignore where the exit points
		if(!player)
			l.room = creature->room;
		else if(exit->flagIsSet(X_TO_STORAGE_ROOM)) {
			l.room = gConfig->getSingleProperty(player, PROP_STORAGE);
			if(!l.room.id) {
				player->print("You must first purchase a storage room to go to this exit.\n");
				return(0);
			} else if(l.room.id == -1) {
				player->print("You may not enter that room when you are affiliated with more than one\n");
				player->print("storage room. Type \"property\" for instructions on how to remove yourself\n");
				player->print("as partial owner from other storage rooms if you no longer wish to be\n");
				player->print("affiliated with them.\n");
				return(0);
			}
		} else if(exit->flagIsSet(X_TO_BOUND_ROOM))
			l = player->getBound();
		else
			l = player->previousRoom;
	} else if(!exit || teleport) {
		// if we're teleporting
		l.mapmarker = *teleport;
	} else if(exit->target.mapmarker.getArea()) {
		l.mapmarker = exit->target.mapmarker;
	} else {
		l.room = exit->target.room;
	}

	if(l.mapmarker.getArea()) {
		Area *area = gConfig->getArea(l.mapmarker.getArea());
		if(!area) {
			if(!teleport && creature) {
				creature->print("Off the map in that direction.\n");
				if(creature->isStaff())
					creature->printColor("^eMove::getRoom failed on an area room.\n");
			}
			return(false);
		}
		// if we're in a unique room, don't activate any unique-room triggers on
		// the overland unless we're teleporting
		if(teleport || !creature || !creature->parent_rom)
			l.room = area->getUnique(&l.mapmarker);
		if(!l.room.id) {
			// don't recycle if we are teleporting or leaving
			// a unique room
			if(	teleport ||
				(creature && creature->area_room && creature->area_room->unique.id)
			)
				recycle = false;
			// if we're only looking, don't use the function that will create a new room
			// if one doesnt already exit
			if(justLooking)
				(*aRoom) = area->getRoom(&l.mapmarker);
			else
				(*aRoom) = area->loadRoom(creature, &l.mapmarker, recycle);
			if(!*aRoom)
				return(false);
			// getUnique gets called again later, so skip the decrement process here
			// or the compass will use 2 shots
			if(teleport || !creature || !creature->parent_rom)
				l.room = (*aRoom)->getUnique(creature, true);
		}
	}

	if(l.room.id) {
		if(	(creature && creature->parent_rom && l.room == creature->room) ||
			!loadRoom(l.room, uRoom)
		) {
			if(!teleport && creature)
				creature->print("Off map in that direction.\n");
			return(false);
		}

		(*aRoom)=0;

		if(creature) {
			// sending true to this function tells the player why
			// they cant enter the room: if teleporting send false
			if(!creature->canEnter(*uRoom, !teleport)) {
				(*uRoom)=0;
				return(false);
			}

			// the rest of these rules are for players only
			// exclude pets
			if(player && !creature->isPet()) {
				Monster* pet = player->getPet();
				if(pet && !pet->canEnter(*uRoom, !teleport)) {
					if(!teleport)
						player->print("%M won't follow you there.\n", pet);
					(*uRoom)=0;
					return(false);
				}

				// if they're leaving limbo
				if(!justLooking && player->getLocation() == player->getLimboRoom())
					player->clearFlag(P_KILLED_BY_MOB);

				if(player->parent_rom && player->parent_rom->info.isArea("stor"))
					gConfig->saveStorage(player->parent_rom);

			}

		}
	}


	BaseRoom* room = (*aRoom);
	if(!room)
		room = (*uRoom);

	// when entering the room, we may have to unmist them
	if( !justLooking &&
		player &&
		player->flagIsSet(P_MISTED) &&
		!player->isStaff() &&
		(room->flagIsSet(R_DISPERSE_MIST) || room->flagIsSet(R_ETHEREAL_PLANE) || room->isUnderwater())
	) {
		if(room->isUnderwater())
			player->print("Water currents disperse your mist.\n");
		else {
			player->print("Swirling vapors disperse your mist.\n");
			player->stun(mrand(5,8));
		}
		player->unmist();
	}

	return(true);
}
/*
bool Move::getRoom(Creature* creature, Exit* exit, Room **uRoom, AreaRoom **aRoom, bool justLooking, MapMarker* tMapmarker) {
	Player* player = creature->getPlayer();
	BaseRoom* room=0;
	bool teleporting=false, recycle=true;
	CatRef	cr;

	// if we're teleporting, we wont get an exit,
	// we'll only have the teleport mapmarker
	if(tMapmarker)
		teleporting = true;
	else if(exit && exit->target.mapmarker.getArea())
		tMapmarker = &exit->target.mapmarker;

	(*uRoom)=0;
	(*aRoom)=0;

	// special exits to take us special places
	if(exit) {
		if(exit->flagIsSet(X_TO_BOUND_ROOM) || exit->flagIsSet(X_TO_PREVIOUS)) {
			if(!player)
				cr = creature->room;
			else {
				Location l = player->previousRoom;
				if(exit->flagIsSet(X_TO_BOUND_ROOM))
					l = player->getBound();

				if(l.room.id)
					cr = l.room;
				else if(l.mapmarker.getArea())
					tMapmarker = &l.mapmarker;
			}
		}
	}

	// use the exit to figure out what kind of room we're getting
	if(tMapmarker) {
		Area *area = gConfig->getArea(tMapmarker->getArea());
		if(!area) {
			if(!teleporting && creature)
				creature->printColor("Off the map in that direction. ^e(gr)\n");
			return(false);
		}
		// if we're in a unique room, don't activate any unique-room triggers on
		// the overland unless we're teleporting
		if(teleporting || !creature || !creature->parent_rom)
			cr = area->getUnique(tMapmarker);
		if(!cr.id) {
			// don't recycle if we are teleporting or leaving
			// a unique room
			if(	teleporting ||
				(creature && creature->area_room && creature->area_room->unique.id)
			)
				recycle=false;
			// if we're only looking, don't use the function that will create a new room
			// if one doesnt already exit
			if(justLooking)
				(*aRoom) = area->getRoom(tMapmarker);
			else
				(*aRoom) = area->loadRoom(creature, tMapmarker, recycle);
			if(!*aRoom)
				return(false);
			// getUnique gets called again later, so skip the decrement process here
			// or the compass will use 2 shots
			if(teleporting || !creature || !creature->parent_rom)
				cr = (*aRoom)->getUnique(creature, true);
		}
	}

	if(cr.id) {
	} else if(!tMapmarker) {
		Player* player = 0;
		if(creature)
			player = creature->getPlayer();
		(*uRoom) = Move::getUniqueRoom(creature, player, exit, 0);
		if(!*uRoom)
			return(false);
		(*aRoom)=0;
	}


	room = (*aRoom);
	if(!room)
		room = (*uRoom);

	if(!justLooking && creature) {
		if( creature->isPlayer() &&
			creature->flagIsSet(P_MISTED) &&
			!creature->isStaff() &&
			(room->flagIsSet(R_DISPERSE_MIST) || room->flagIsSet(R_ETHEREAL_PLANE) || room->isUnderwater())
		) {
			if(room->isUnderwater())
				creature->print("Water currents disperse your mist.\n");
			else {
				creature->print("Swirling vapors disperse your mist.\n");
				creature->stun(mrand(5,8));
			}
			creature->unmist();
		}
	}

	return(true);
}
*/

//*********************************************************************
//						start
//*********************************************************************
// this function starts everyone moving - it finds the room, finds
// the exit, sees if they can enter, then removes them from the current
// room. the final step is completed in Move::finish

bool deletePortal(Player* player, BaseRoom* room, bstring name);

bool Move::start(Creature* creature, cmd* cmnd, Exit *gExit, bool leader, std::list<Creature*> *followers, int* numPeople, bool& roomPurged) {
	BaseRoom *oldRoom = creature->getRoom(), *newRoom=0;
	Creature *pet=0, *follower=0;
	Room	*uRoom=0;
	AreaRoom* aRoom=0;
	Exit	*exit=0;
	Player	*player = creature->getPlayer();
	Monster* monster = creature->getMonster();
	bool	sneaking=false, wasSneaking=false, mem=false;
	ctag	*cp=0;

	if(player) {
		if(!Move::canMove(player, cmnd))
			return(false);
		// only players sneak
		sneaking = wasSneaking = Move::isSneaking(cmnd);
	}

	exit = Move::getExit(creature, cmnd);
	if(!exit) {
		creature->print("You don't see that exit.\n");
		if(monster && monster->following)
			monster->following->print("Your pet doesn't see that exit.\n");
		return(false);
	}


	if(player && !Move::canEnter(player, exit, leader))
		return(false);

	if(!Move::getRoom(creature, exit, &uRoom, &aRoom))
		return(false);

	// Rangers and F/T can't sneak with heavy armor on!
	if(sneaking && player && player->checkHeavyRestrict("sneak"))
		return(false);

	if(aRoom) {
		mem = aRoom->getStayInMemory();
		aRoom->setStayInMemory(true);
		newRoom = aRoom;
	} else
		newRoom = uRoom;

	// we have to run a manual isFull check here because nobody is
	// in the room yet
	(*numPeople)++;
	if(!monster && !player->isStaff()) {
		if(newRoom->maxCapacity() && (newRoom->countVisPly() + *numPeople) > newRoom->maxCapacity()) {
			creature->print("That room is full.\n");
			// reset stayInMemory
			if(aRoom)
				aRoom->setStayInMemory(mem);
			return(false);
		}
	}

	// were they killed by exit effect damage?
	if(exit->doEffectDamage(creature))
		return(false);

	// save a copy of the exit for the track function
	if(leader) {
		strcpy(gExit->name, exit->name);
		strcpy(gExit->flags, exit->flags);
	}


	if(player) {
		Move::update(player);
		sneaking = Move::sneak(player, sneaking);
	}
	Move::broadMove(creature, exit, cmnd, sneaking);

	// Was the area room purged?  If so we have no monsters to follow is in it so
	// no need to check that later
	int del = creature->deleteFromRoom(false);
	if(del & DEL_ROOM_DESTROYED) {
		// Room was purged and oldRoom is no longer valid
		roomPurged = true;
		exit = 0;
		oldRoom = 0;
	}

	// we store the room here so we can add them in the near future
	if(uRoom)
		creature->parent_rom = uRoom;
	else
		creature->area_room = aRoom;

	// the leader doesnt use the list
	if(!leader)
		followers->push_back(creature);


	// sneaking means only your pet will follow you, even if you fail
	// also do this for destroyed portals
	bool portal = false;
	if(!exit)
		portal = true;
	if(!portal && player && exit->flagIsSet(X_PORTAL)) {
		exit->setKey(exit->getKey() - 1);
		portal = exit->getKey() < 1;
	}
	if(player && (wasSneaking || portal)) {
		// TODO: Make pet unhide during failed sneak
		pet = player->getPet();
		if(pet && oldRoom == pet->getRoom())
			Move::start(pet, cmnd, 0, 0, followers, numPeople, roomPurged);
		// reset stayInMemory
		if(aRoom)
			aRoom->setStayInMemory(mem);
		if(portal && oldRoom && exit)
			deletePortal(player, oldRoom, exit->getPassPhrase());
		return(true);
	}

	cp = creature->first_fol;
	while(cp) {
		follower = cp->crt;
		cp = cp->next_tag;

		if(oldRoom == follower->getRoom())
			Move::start(follower, cmnd, 0, 0, followers, numPeople, roomPurged);
		if(roomPurged)
			oldRoom = NULL;
	}

	if(player && !sneaking && !roomPurged && oldRoom)
		Move::checkFollowed(player, exit, oldRoom, followers);

	// reset stayInMemory
	if(aRoom)
		aRoom->setStayInMemory(mem);

	// portal owners close once they exit the room, but this means their group can follow
	if(player && player->flagIsSet(P_PORTAL)) {
		deletePortal(player, oldRoom, player->name);
		player->clearFlag(P_PORTAL);
	}
	return(true);
}



//*********************************************************************
//						cmdGo
//*********************************************************************
// the base go command - it is called by the leader and causes everyone
// following to run the Move::start and Move::finish functions

int cmdGo(Player* player, cmd* cmnd) {
	MapMarker *oldMarker=0;
	Room	*oldRoom = player->parent_rom;
	Exit	exit;
	int		numPeople=0;

	if(!player->getRoom()) {
		player->print("You must be in a room to go anywhere!\n");
		return(0);
	}

	if(cmnd->num < 2) {
		player->print("Go where?\n");
		return(0);
	}

	// keep track of this room
	AreaRoom* aRoom = player->area_room;
	std::list<Creature*> followers;

	if(aRoom) {
		oldMarker = new MapMarker;
		*oldMarker = aRoom->mapmarker;
	}

	bool roomPurged = false;
	// this removes everyone from the room
	if(!Move::start(player, cmnd, &exit, true, &followers, &numPeople, roomPurged))
		return(0);

	if(!roomPurged)
		Move::track(oldRoom, oldMarker, &exit, player, &followers);

	if(oldMarker)
		delete oldMarker;

	// for display reasons, we only need to kill objects in
	// the room they're entering
	player->getRoom()->killMortalObjectsOnFloor();

	// loadRoom is telling us the room the player used to be in is
	// a candidate for recycling
	if(player->area_room && aRoom == player->area_room)
		player->area_room = Move::recycle(aRoom, Move::getExit(player, cmnd));

	// this adds everyone to the room
	Move::finish(player, player->getRoom(), player->parent_rom, true, &followers);
	// we killed objects already, we can skip those this time around
	player->getRoom()->killMortalObjects(false);
	return(0);
}


//*********************************************************************
//						cmdMove
//*********************************************************************
// This function attempts to move a player in one of the
// cardinal directions (n,s,e,w,u,d).

int cmdMove(Player* player, cmd* cmnd) {
	bstring dir = "", str = "";

	player->clearFlag(P_AFK);

	// find the ordinal direction
	str = cmnd->str[0];
	if(!player->ableToDoCommand())
		return(0);

	if(str == "sw" || !strncmp(str.c_str(), "southw", 6))
		dir = "southwest";
	else if(str == "nw" || !strncmp(str.c_str(), "northw", 6))
		dir = "northwest";
	else if(str == "se" || !strncmp(str.c_str(), "southe", 6))
		dir = "southeast";
	else if(str == "ne" || !strncmp(str.c_str(), "northe", 6))
		dir = "northeast";

	/*	else if(!strcmp(str, "aft")
			strcpy(tempstr, "aft");
		else if(!strcmp(str, "fore")
			strcpy(tempstr, "fore");
		else if(!strcmp(str, "starb")
			strcpy(tempstr, "starboard");
		else if(!strcmp(str, "port")
			strcpy(tempstr, "port");  */

	else {
		switch(str[0]) {
		case 'n':
			dir = "north";
			break;
		case 's':
			dir = "south";
			break;
		case 'e':
			dir = "east";
			break;
		case 'w':
			dir = "west";
			break;
		case 'u':
			dir = "up";
			break;
		case 'd':
			dir = "down";
			break;
		case 'o':
		case 'l':
			dir = "out";
			break;
		}
	}

	// fake a "go north" type thing
	cmnd->num = 2;
	strcpy(cmnd->str[1], dir.c_str());
	cmnd->val[1] = 1;

	return(cmdGo(player, cmnd));
}


//*********************************************************************
//						cmdFlee
//*********************************************************************
// wrapper which allows a player to flee

int cmdFlee(Player* player, cmd* cmnd) {
	player->flee();
	return(0);
}


//*********************************************************************
//						cmdOpen
//*********************************************************************
// This function allows a player to open a door if it is not already
// open and if it is not locked.

int cmdOpen(Player* player, cmd* cmnd) {
	Exit	*exit=0;

	player->clearFlag(P_AFK);


	if(!player->ableToDoCommand())
		return(0);

	if(player->flagIsSet(P_SITTING)) {
		player->print("You have to stand up first.\n");
		return(0);
	}

	if(cmnd->num < 2) {
		player->print("Open what?\n");
		return(0);
	}

	exit = findExit(player, cmnd);


	if(!exit) {
		player->print("You don't see that openable exit.\n");
		return(0);
	}

	if(!exit->flagIsSet(X_CLOSED) && !exit->flagIsSet(X_CLOSABLE)) {
		player->print("You don't see that openable exit.\n");
		return(0);
	}

	if(exit->flagIsSet(X_TOLL_TO_PASS) && player->getRoom()->getTollkeeper() && !player->isCt()) {
		player->print("You must pay a toll of %ld gold coins to go through the %s.\n", tollcost(player, exit, 0), exit->name);
		return(0);
	}

	Monster* guard = player->getRoom()->getGuardingExit(exit);
	if(guard && !player->checkStaff("%M won't let you open it.\n", guard))
		return(0);

	if(exit->flagIsSet(X_LOCKED) && !player->checkStaff("It's locked.\n"))
		return(0);

	exit->clearFlag(X_LOCKED);

	if(!exit->flagIsSet(X_CLOSED)) {
		player->print("It's already open.\n");
		return(0);
	}

	player->unhide();

	exit->clearFlag(X_CLOSED);
	exit->ltime.ltime = time(0);

	player->print("You open the %s.\n", exit->name);
	broadcast(player->getSock(), player->getRoom(), "%M opens the %s.", player, exit->name);

	if(exit->getOpen() != "") {
		if(exit->flagIsSet(X_ONOPEN_PLAYER)) {
			player->print("%s.\n", exit->getOpen().c_str());
		} else {
			broadcast(0, player->getRoom(), exit->getOpen().c_str());
		}
	}

	return(0);
}

//*********************************************************************
//						cmdClose
//*********************************************************************
// This function allows a player to close a door, if the door is not
// already closed, and if indeed it is a door.

int cmdClose(Player* player, cmd* cmnd) {
	Exit	*exit=0;
	ctag	*cp=0;


	player->clearFlag(P_AFK);


	if(!player->ableToDoCommand())
		return(0);

	if(cmnd->num < 2) {
		player->print("Close what?\n");
		return(0);
	}

	if(player->flagIsSet(P_SITTING)) {
		player->print("You have to stand up first.\n");
		return(0);
	}

	exit = findExit(player, cmnd);

	if(!exit) {
		player->print("You don't see that closeable exit.\n");
		return(0);
	}

	if(!exit->flagIsSet(X_CLOSABLE)) {
		player->print("You don't see that closeable exit.\n");
		return(0);
	}

	if(exit->flagIsSet(X_CLOSED)) {
		player->print("It's already closed.\n");
		return(0);
	}

	cp = player->getRoom()->first_ply;
	while(cp) {
		if(cp->crt->inCombat()) {
			player->print("You cannot do that right now.\n");
			return(0);
		}
		cp = cp->next_tag;
	}

	player->unhide();

	exit->setFlag(X_CLOSED);

	player->print("You close the %s.\n", exit->name);
	broadcast(player->getSock(), player->getRoom(), "%M closes the %s.", player, exit->name);

	return(0);

}

//*********************************************************************
//						cmdUnlock
//*********************************************************************
// This function allows a player to unlock a door if they have the correct
// key, and it is locked.

unsigned short Object::getKey() const { return(keyVal); }
void Object::setKey(unsigned short k) { keyVal = k; }

int cmdUnlock(Player* player, cmd* cmnd) {
	Object	*object=0;
	Exit	*exit=0;

	player->clearFlag(P_AFK);


	if(!player->ableToDoCommand())
		return(0);



	if(player->flagIsSet(P_SITTING)) {
		player->print("You have to stand up first.\n");
		return(0);
	}

	if(cmnd->num < 2) {
		player->print("Unlock what?\n");
		return(0);
	}

	exit = findExit(player, cmnd);

	if(!exit) {
		player->print("Unlock what?\n");
		return(0);
	}

	Monster* guard = player->getRoom()->getGuardingExit(exit);
	if(guard && !player->checkStaff("%M won't let you unlock it.\n", guard))
		return(0);

	if(!exit->flagIsSet(X_LOCKED) && !player->checkStaff("It's not locked.\n"))
		return(0);

	if(player->inJail()) {
		if(player->parent_rom->countVisPly() > 1) {
			player->print("You can't do that! Someone else might get out!\n");
			return(0);
		}
	}

	if(exit->flagIsSet(X_TO_STORAGE_ROOM)) {
		CatRef	sr = gConfig->getSingleProperty(player, PROP_STORAGE);
		if(!sr.id) {
			player->print("You must first purchase a storage room to unlock this exit.\n");
			return(0);
		}
	}

	if(exit->flagIsSet(X_WATCHER_UNLOCK) && (player->isWatcher() || player->isCt())) {
		player->unhide();

		exit->clearFlag(X_LOCKED);
		exit->ltime.ltime = time(0);
		player->print("Click.\n");

		broadcast(player->getSock(), player->getRoom(), "%M unlocks the %s.", player, exit->name);

		broadcast(isWatcher, "^C%s unlocked the %s exit in room %s.\n",
			player->name, exit->name, player->getRoom()->fullName().c_str());

		logn("log.watchers", "%s unlocked the %s exit in room %s.\n",
			player->name, exit->name, player->getRoom()->fullName().c_str());

		return(0);

	}

	if(cmnd->num < 3) {
		player->print("Unlock it with what?\n");
		return(0);
	}

	object = findObject(player->getConstPlayer(), player->first_obj, cmnd, 2);

	if(!object) {
		player->print("You don't have that.\n");
		return(0);
	}


	if(object->getType() == WAND && object->getMagicpower() == S_KNOCK)
		return(cmdUseWand(player, cmnd));
	if(object->getType() != KEY) {
		player->print("That's not a key.\n");
		return(0);
	}

	if(object->getShotscur() < 1) {
		player->printColor("%O is broken.\n", object);
		return(0);
	}
	if(!object->isKey(player->parent_rom, exit)) {
		player->print("Wrong key.\n");
		return(0);
	}

	player->unhide();

	exit->clearFlag(X_LOCKED);
	exit->ltime.ltime = time(0);
	object->decShotscur();

	if(object->use_output[0])
		player->print("%s\n", object->use_output);
	else
		player->print("Click.\n");
	broadcast(player->getSock(), player->getRoom(), "%M unlocks the %s.", player, exit->name);

	if(object->getShotscur() < 1 && Unique::isUnique(object)) {
		player->delObj(object, true);
		delete object;
	}
	return(0);
}

//*********************************************************************
//						cmdLock
//*********************************************************************
// This function allows a player to lock a door with the correct key.

int cmdLock(Player* player, cmd* cmnd) {
	Object	*object=0;
	Exit	*exit=0;

	player->clearFlag(P_AFK);

	if(!player->ableToDoCommand())
		return(0);

	if(cmnd->num < 2) {
		player->print("Lock what?\n");
		return(0);
	}

	if(player->flagIsSet(P_SITTING)) {
		player->print("You have to stand up first.\n");
		return(0);
	}

	exit = findExit(player, cmnd);

	if(!exit) {
		player->print("Lock what?\n");
		return(0);
	}

	if(exit->flagIsSet(X_LOCKED)) {
		player->print("It's already locked.\n");
		return(0);
	}

	if(cmnd->num < 3) {
		player->print("Lock it with what?\n");
		return(0);
	}

	object = findObject(player, player->first_obj, cmnd, 2);

	if(!object) {
		player->print("You don't have that.\n");
		return(0);
	}

	if(object->getType() != KEY) {
		player->printColor("%O is not a key.\n", object);
		return(0);
	}

	if(!exit->flagIsSet(X_LOCKABLE)) {
		player->print("You can't lock it.\n");
		return(0);
	}

	if(!exit->flagIsSet(X_CLOSED)) {
		player->print("You have to close it first.\n");
		return(0);
	}

	if(object->getShotscur() < 1) {
		player->printColor("%O is broken.\n", object);
		return(0);
	}

	if(!object->isKey(player->parent_rom, exit)) {
		player->print("Wrong key.\n");
		return(0);
	}

	player->unhide();
	exit->setFlag(X_LOCKED);

	player->print("Click.\n");
	broadcast(player->getSock(), player->getRoom(), "%M locks the %s.", player, exit->name);

	if(object->getShotscur() < 1 && Unique::isUnique(object)) {
		player->delObj(object, true);
		delete object;
	}
	return(0);
}


//*********************************************************************
//						getCatRef
//*********************************************************************
// we're given a string and expected to find a) the area and
// b) the room id.

void getCatRef(bstring str, CatRef* cr, const Creature* target) {
	cr->setDefault(target);

	// chop off the end!
	bstring::size_type pos = str.Find(" ");
	if(pos != bstring::npos)
		str = str.substr(0, pos);

	pos = str.Find(".");
	if(pos == bstring::npos)
		pos = str.Find(":");
	if(pos != bstring::npos) {
		cr->setArea(str.substr(0, pos));
		str.erase(0, pos+1);
	}

	if(str != "" && isdigit(str.getAt(0)))
		cr->id = atoi(str.c_str());
	else {
		if(str != "")
			cr->setArea(str);
		cr->id = -1;
	}
}

//*********************************************************************
//						getDestination
//*********************************************************************
// we're given a string and expected to find a) a MapMarker or
// b) a CatRef. the string will start at the point we wish
// to search, but may contain extra crap at the end

void getDestination(bstring str, Location* l, const Creature* target) {
	l->mapmarker.reset();
	l->room.id = 0;
	getDestination(str, &l->mapmarker, &l->room, target);
}

void getDestination(bstring str, MapMarker* mapmarker, CatRef* cr, const Creature* target) {
	bstring::size_type pos=0;
	char	*txt;
	int		x=0, y=0, z=0;

	// chop off the end!
	pos = str.find(" ", 0);
	if(pos != bstring::npos)
		str = str.substr(0, pos);

	// 1.-10.7
	txt = (char*)strstr(str.c_str(), ".");
	if(txt && isdigit(str.getAt(0))) {
		txt++;
		x = atoi(txt);

		txt = strstr(txt, ".");
		if(txt) {
			txt++;
			y = atoi(txt);
			txt = strstr(txt, ".");
			if(txt) {
				txt++;
				z = atoi(txt);
			}
		}

		mapmarker->set(atoi(str.c_str()), x, y, z);
	} else
		getCatRef(str, cr, target);
}