@Override
						public final void apply(final MOB M)
						{
							if((M instanceof ShopKeeper)
							&&(M.isSavable())
							&&(M.getStartRoom()!=me)
							&&(M.getStartRoom()!=null))
								M.getStartRoom().bringMobHere(M,false);
						} 
					});
				}
			}
			catch(final NoSuchElementException e)
			{
			}
		}

		if(msg.amITarget(this)&&(msg.targetMinor()==CMMsg.TYP_EXPIRE))
		{
			synchronized(("SYNC"+roomID()).intern())
			{
				final LinkedList<DeadBody> deadBodies=new LinkedList<DeadBody>();
				eachItem(new EachApplicable<Item>()
				{
					@Override public final void apply(final Item I)
					{
						if((I instanceof DeadBody)
						&&(((DeadBody)I).isPlayerCorpse()))
							deadBodies.add((DeadBody)I);
					} 
				});
				for(final DeadBody D : deadBodies)
				{
					MOB M=CMLib.players().getLoadPlayer(D.getMobName());
					if(M==null)
						M=D.getSavedMOB();
					if((M!=null)&&(M.getStartRoom()!=null))
					{
						final Room startRoom=CMLib.map().getRoom(M.getStartRoom());
						M.tell(L("Your corpse has been moved to @x1",startRoom.displayText()));
						startRoom.moveItemTo(D);
					}
				}
				if(gridParent!=null)
					gridParent.executeMsg(myHost,msg);
				else
				if((roomID().length()>0)
				&&((getArea()==null)||(!CMath.bset(getArea().flags(), Area.FLAG_INSTANCE_CHILD)))
				&&(CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMMOBS)
					||CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMITEMS)
					||CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMSHOPS)))
				{
					final ArrayList<MOB> shopmobs=new ArrayList<MOB>(1);
					final ArrayList<Item> bodies=new ArrayList<Item>(1);
					if(CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMMOBS))
					{
						eachInhabitant(new EachApplicable<MOB>()
						{ 
							@Override
							public final void apply(final MOB M)
							{
								if(M.isSavable())
								{
									M.setStartRoom(me);
									M.text(); // this permanizes his current state
								}
							} 
						});
						CMLib.database().DBUpdateMOBs(this);
					}
					else
					if(CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMSHOPS))
					{
						eachInhabitant(new EachApplicable<MOB>()
						{ 
							@Override
							public final void apply(final MOB M)
							{
								if((M.isSavable())
								&&(M instanceof ShopKeeper)
								&&(M.getStartRoom()==me))
									shopmobs.add(M);
							} 
						});
						if(!shopmobs.isEmpty())
							CMLib.database().DBUpdateTheseMOBs(this,shopmobs);
					}
					if(CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMITEMS))
					{
						eachItem(new EachApplicable<Item>()
						{ 
							@Override public final void apply(final Item I)
							{
								if(I instanceof DeadBody)
									bodies.add(I);
							}
						});
						for(int i=0;i<bodies.size();i++)
							bodies.get(i).destroy();
						CMLib.database().DBUpdateItems(this);
					}
				}
				final Area A=getArea();
				final String roomID=roomID();
				setGridParent(null);
				if(!CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN))
				{
					CMLib.map().emptyRoom(this,null,true);
					destroy();
					if(roomID.length()>0)
						A.addProperRoomnumber(roomID);
				}
			}
		}
	}

	@Override
	public void startItemRejuv()
	{
		eachItem(new EachApplicable<Item>()
		{ 
			@Override
			public final void apply(final Item item)
			{
				if(item.container()==null)
				{
					final ItemTicker I=(ItemTicker)CMClass.getAbility("ItemRejuv");
					I.unloadIfNecessary(item);
					if((item.phyStats().rejuv()!=PhyStats.NO_REJUV)
					&&(item.phyStats().rejuv()>0))
						I.loadMeUp(item,me);
				}
			} 
		});
	}

	@Override
	public int getTickStatus()
	{
		return tickStatus;
	}

	@Override
	public boolean tick(final Tickable ticking, final int tickID)
	{
		tickStatus=Tickable.STATUS_START;
		if(tickID==Tickable.TICKID_ROOM_BEHAVIOR)
		{
			if((numBehaviors()<=0)&&(numScripts()<=0))
				return false;
			tickStatus=Tickable.STATUS_BEHAVIOR;
			eachBehavior(new EachApplicable<Behavior>()
			{ 
				@Override
				public final void apply(final Behavior B)
				{
					B.tick(ticking, tickID);
				} 
			});
			tickStatus=Tickable.STATUS_SCRIPT;
			eachScript(new EachApplicable<ScriptingEngine>()
			{ 
				@Override
				public final void apply(final ScriptingEngine S)
				{
					S.tick(ticking, tickID);
				} 
			});
		}
		else
		{
			tickStatus=Tickable.STATUS_AFFECT;
			if(numEffects()>0)
			{
				eachEffect(new EachApplicable<Ability>()
				{ 
					@Override
					public final void apply(final Ability A)
					{
						if(!A.tick(ticking,tickID))
							A.unInvoke();
					} 
				});
			}
		}
		tickStatus=Tickable.STATUS_NOT;
		return !amDestroyed();
	}

	@Override
	public PhyStats phyStats()
	{
		return phyStats;
	}

	@Override
	public PhyStats basePhyStats()
	{
		return basePhyStats;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void recoverPhyStats()
	{
		basePhyStats.copyInto(phyStats);
		final Area myArea=getArea();
		if(myArea!=null)
			myArea.affectPhyStats(this,phyStats());

		eachEffect(affectPhyStats);
		eachItem(affectPhyStats);
		eachInhabitant(affectPhyStats);
	}

	private final static EachApplicable<Item> recoverRoomStatsItemApplicable=new EachApplicable.ApplyRecoverPhyStats<Item>();

	private final static EachApplicable<MOB> recoverRoomStatsInhabitantApplicable=new EachApplicable<MOB>()
	{
		@Override
		public final void apply(final MOB M)
		{
			M.recoverCharStats();
			M.recoverPhyStats();
			M.recoverMaxState();
		}
	};

	private void reallyRecoverRoomStats()
	{
		recoverPhyStats();
		eachInhabitant(recoverRoomStatsInhabitantApplicable);
		for(final Exit X : exits)
		{
			if(X!=null)
				X.recoverPhyStats();
		}
		eachItem(recoverRoomStatsItemApplicable);
	}
	
	@Override
	public void recoverRoomStats()
	{
		synchronized(roomRecoverMarker)
		{
			roomRecoverMarker[0]++;
			if(roomRecoverMarker[0]!=1)
			{
				return;
			}
			try
			{
				reallyRecoverRoomStats();
				roomRecoverMarker[0]--;
				if(roomRecoverMarker[0]>0)
					reallyRecoverRoomStats();
			}
			finally
			{
				roomRecoverMarker[0]=0;
			}
		}
	}

	@Override
	public void setBasePhyStats(PhyStats newStats)
	{
		basePhyStats=(PhyStats)newStats.copyOf();
	}

	private final static int phyStatsMaskOut = ~(PhyStats.IS_DARK|PhyStats.IS_LIGHTSOURCE|PhyStats.IS_SLEEPING|PhyStats.IS_HIDDEN|PhyStats.IS_SWIMMING|PhyStats.IS_NOT_SEEN); 
	
	@Override
	public void affectPhyStats(final Physical affected, final PhyStats affectableStats)
	{
		getArea().affectPhyStats(affected,affectableStats);
		final int disposition=phyStats().disposition() & phyStatsMaskOut;
		if(disposition>0)
			affectableStats.setDisposition(affectableStats.disposition()|disposition);
		eachEffect(new EachApplicable<Ability>()
		{ 
			@Override
			public final void apply(final Ability A)
			{
				if(A.bubbleAffect()) 
					A.affectPhyStats(affected,affectableStats);
			} 
		});
	}

	@Override
	public void affectCharStats(final MOB affectedMob, final CharStats affectableStats)
	{
		getArea().affectCharStats(affectedMob,affectableStats);
		eachEffect(new EachApplicable<Ability>(){ 
			@Override
			public final void apply(final Ability A)
			{
				if(A.bubbleAffect()) 
					A.affectCharStats(affectedMob,affectableStats);
			} 
		});
	}

	@Override
	public void affectCharState(final MOB affectedMob, final CharState affectableMaxState)
	{
		getArea().affectCharState(affectedMob,affectableMaxState);
		eachEffect(new EachApplicable<Ability>(){ 
			@Override
			public final void apply(final Ability A)
			{
				if(A.bubbleAffect()) 
					A.affectCharState(affectedMob,affectableMaxState);
			} 
		});
	}

	@Override
	public int compareTo(CMObject o)
	{
		return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o));
	}

	protected String parseVariesCodes(final MOB mob, final Area A, final String text)
	{
		final StringBuilder buf=new StringBuilder("");
		int aligatorDex=text.indexOf('<');
		int curDex=0;
		boolean addMe = true;
		while(aligatorDex>=0)
		{
			for(final VariationCode code : VariationCode.values())
			{
				if(text.startsWith(code.openTag, aligatorDex))
				{
					buf.append(text.substring(curDex, aligatorDex));
					int y=text.indexOf(code.closeTag,aligatorDex+code.openTag.length());
					if(y<0)
					{
						curDex = text.length();
						y=text.length();
					}
					else
						curDex = y+code.closeTag.length();
					switch(code.c)
					{
					case '\n':
						addMe = !addMe;
						break;
					case '\r':
						addMe = true;
						break;
					case 'W':
						addMe = A.getClimateObj().weatherType(null) == code.num;
						break;
					case 'C':
						addMe = A.getTimeObj().getTODCode().ordinal() == code.num;
						break;
					case 'S':
						addMe = A.getTimeObj().getSeasonCode().ordinal() == code.num;
						break;
					case 'M':
						addMe = ((mob != null) && (CMath.bset(mob.phyStats().disposition(), code.num)));
						break;
					case 'V':
						addMe = ((mob != null) && (mob.playerStats() != null) && (mob.playerStats().hasVisited(this)));
						break;
					}
					if(addMe)
						buf.append(parseVariesCodes(mob,A,text.substring(aligatorDex+code.openTag.length(),y)));
					aligatorDex=curDex-1;
					break;
				}
			}
			if(aligatorDex >= text.length()-1)
				break;
			aligatorDex=text.indexOf('<',aligatorDex+1);
		}
		if(curDex < text.length())
		{
			if(text.startsWith("</VARIES>",curDex))
				buf.append(text.substring(curDex+9));
			else
				buf.append(text.substring(curDex));
		}
		return buf.toString();
	}

	protected String parseVaries(MOB mob, String text)
	{
		if(text.startsWith("<VARIES>"))
			return parseVariesCodes(mob,getArea(),text.substring(8));
		return text;
	}

	@Override
	public String displayText(MOB mob)
	{
		return parseVaries(mob,displayText());
	}

	@Override
	public String description(MOB mob)
	{
		return parseVaries(mob,description());
	}

	@Override
	public void bringMobHere(MOB mob, boolean andFollowers)
	{
		if(mob==null)
			return;
		final Room oldRoom=mob.location();
		if(oldRoom!=null)
			oldRoom.delInhabitant(mob);
		addInhabitant(mob);
		mob.setLocation(this);

		if((andFollowers)&&(oldRoom!=null))
		{
			for(final Enumeration<Pair<MOB,Short>> f=mob.followers();f.hasMoreElements();)
			{
				final MOB folM=f.nextElement().first;
				if(folM.location()==oldRoom)
					bringMobHere(folM,true);
			}
		}
		final Rideable RI=mob.riding();
		if((RI!=null)&&(CMLib.map().roomLocation(RI)==oldRoom))
		{
			if((RI.isMobileRideBasis())
			&&((!(RI instanceof Item))||(!CMLib.flags().isMobile(RI))))
			{
				if(RI instanceof MOB)
					bringMobHere((MOB)RI,andFollowers);
				else
				if(RI instanceof Item)
				{
					if(andFollowers)
						moveItemTo((Item)RI,ItemPossessor.Expire.Player_Drop,Move.Followers);
					else
						moveItemTo((Item)RI,ItemPossessor.Expire.Player_Drop);
				}
				// refuse is good for above, since mostly moving player stuff around
			}
			else
				mob.setRiding(null);
		}
		if((oldRoom!=null)&&(mob instanceof Rideable)&&(oldRoom!=this))
		{
			for(final Enumeration<Rider> r=((Rideable)mob).riders();r.hasMoreElements();)
			{
				final Rider RR=r.nextElement();
				if(CMLib.map().roomLocation(RR)==oldRoom)
				{
					if(((Rideable)mob).isMobileRideBasis())
					{
						if((RR instanceof MOB)&&(andFollowers))
							bringMobHere((MOB)RR,andFollowers);
						else
						if(RR instanceof Item)
						{
							if(andFollowers)
								moveItemTo((Item)RR,ItemPossessor.Expire.Player_Drop,Move.Followers);
							else
								moveItemTo((Item)RR,ItemPossessor.Expire.Player_Drop);
							// refuse is good for above, since mostly moving player stuff around
						}
					}
					else
						RR.setRiding(null);
				}
			}
		}
		if(oldRoom!=null)
			oldRoom.recoverRoomStats();
		recoverRoomStats();
	}

	@Override
	public void moveItemTo(Item container)
	{
		moveItemTo(container, Expire.Never);
	}

	@Override
	public void moveItemTo(Item item, Expire expire, Move... moveFlags)
	{
		if(item==null)
			return;

		if(item.owner()==null)
			return;
		final Environmental o=item.owner();

		List<Item> V=new ArrayList<Item>();
		if(item instanceof Container)
			V=((Container)item).getDeepContents();
		if(o instanceof MOB)
			((MOB)o).delItem(item);
		if(o instanceof Room)
			((Room)o).delItem(item);

		addItem(item, expire);
		for(int v=0;v<V.size();v++)
		{
			final Item i2=V.get(v);
			if(o instanceof MOB) 
				((MOB)o).delItem(i2);
			if(o instanceof Room) 
				((Room)o).delItem(i2);
			addItem(i2);
		}
		item.setContainer(null);

		final Rideable RI=item.riding();
		if((RI!=null)&&(o instanceof Room)&&(CMLib.map().roomLocation(RI)==o))
		{
			if((RI.isMobileRideBasis())
			&&((!(RI instanceof Item))||(!CMLib.flags().isMobile(RI))))
			{
				if(RI instanceof MOB)
					bringMobHere((MOB)RI,true);
				else
				if(RI instanceof Item)
					moveItemTo((Item)RI,null,ItemPossessor.Move.Followers);
			}
			else
				item.setRiding(null);
		}
		if(CMParms.contains(moveFlags, Move.Followers)
		&&(o instanceof Room)
		&&(item instanceof Rideable)
		&&(o!=this))
		{
			Rider RR=null;
			for(int r=0;r<((Rideable)item).numRiders();r++)
			{
				RR=((Rideable)item).fetchRider(r);
				if(CMLib.map().roomLocation(RR)==o)
				{
					if((((Rideable)item).isMobileRideBasis())
					&&(!CMLib.flags().isMobile(item)))
					{
						if(RR instanceof MOB)
							bringMobHere((MOB)RR,true);
						else
						if(RR instanceof Item)
							moveItemTo((Item)RR,ItemPossessor.Expire.Player_Drop,ItemPossessor.Move.Followers);
					}
					else
						RR.setRiding(null);
				}
			}
		}

		if(o instanceof Room)
			((Room)o).recoverRoomStats();
		else
		if(o instanceof MOB)
		{
			((MOB)o).recoverCharStats();
			((MOB)o).recoverPhyStats();
			((MOB)o).recoverMaxState();
		}
		recoverRoomStats();
	}

	@Override
	public Exit getReverseExit(int direction)
	{
		if((direction<0)||(direction>=Directions.NUM_DIRECTIONS()))
			return null;
		final Room opRoom=getRoomInDir(direction);
		if(opRoom!=null)
			return opRoom.getExitInDir(Directions.getOpDirectionCode(direction));
		return null;
	}

	@Override
	public Exit getPairedExit(int direction)
	{
		final Exit opExit=getReverseExit(direction);
		final Exit myExit=getExitInDir(direction);
		if((myExit==null)||(opExit==null))
			return null;
		if(myExit.hasADoor()!=opExit.hasADoor())
			return null;
		return opExit;
	}

	@Override
	public Room prepareRoomInDir(Room R, int direction)
	{
		if(amDestroyed)
		{
			if(roomID().length()>0)
			{
				final Room thinMeR=CMClass.getLocale("ThinRoom");
				thinMeR.setRoomID(roomID());
				thinMeR.setArea(myArea);
				if(R.rawDoors()[direction]==this)
					R.rawDoors()[direction]=thinMeR;
				return thinMeR.prepareRoomInDir(R,direction);
			}
			return null;
		}
		if(expirationDate()!=0)
			setExpirationDate(System.currentTimeMillis()+WorldMap.ROOM_EXPIRATION_MILLIS);
		return this;
	}

	@Override
	public Room getRoomInDir(int direction)
	{
		if((direction<0)||(direction>=doors.length)||(amDestroyed))
			return null;
		Room nextRoom=rawDoors()[direction];
		if(gridParent!=null)
			nextRoom=gridParent.prepareGridLocale(this,nextRoom,direction);
		if(nextRoom!=null)
		{
			nextRoom=nextRoom.prepareRoomInDir(this,direction);
			if((nextRoom!=null)&&(nextRoom.amDestroyed()))
				return null;
		}
		return nextRoom;
	}

	@Override
	public Exit getExitInDir(int direction)
	{
		if((direction<0)||(direction>=exits.length))
			return null;
		if((gridParent!=null)&&(getRawExit(direction)==null))
			getRoomInDir(direction);
		return getRawExit(direction);
	}

	protected void reallyReallySend(MOB source, CMMsg msg)
	{
		if((Log.debugChannelOn())&&(CMSecurity.isDebugging(CMSecurity.DbgFlag.MESSAGES)))
			Log.debugOut("StdRoom",msg.source().ID()+":"+msg.sourceCode()+":"+msg.sourceMessage()+"/"+((msg.target()!=null)?msg.target().ID():"null")+":"+msg.targetCode()+":"+msg.targetMessage()+"/"+((msg.tool()!=null)?msg.tool().ID():"null")+"/"+msg.othersCode()+":"+msg.othersMessage());
		for(final MOB otherMOB : inhabitants)
		{
			if(otherMOB!=source)
				otherMOB.executeMsg(otherMOB,msg);
		}
		executeMsg(source,msg);
		CMLib.commands().monitorGlobalMessage(this, msg);
	}

	protected void reallySend(MOB source, CMMsg msg, int depth)
	{
		reallyReallySend(source,msg);
		// now handle trailer msgs
		if(depth<3)
		{
			if(msg.trailerMsgs()!=null)
			{
				for(final CMMsg msg2 : msg.trailerMsgs())
				{
					if((msg!=msg2)
					&&((msg2.target()==null)
					   ||(!(msg2.target() instanceof MOB))
					   ||((!((MOB)msg2.target()).amDead())||(msg2.sourceMinor()==CMMsg.TYP_DEATH)))
					&&(okMessage(source,msg2)))
					{
						source.executeMsg(source,msg2);
						reallySend(source,msg2,depth+1);
					}
				}
			}
			if(msg.trailerRunnables()!=null)
			{
				for(final Runnable r : msg.trailerRunnables())
					CMLib.threads().executeRunnable(r);
			}
		}
	}

	@Override
	public void send(final MOB source, final CMMsg msg)
	{
		source.executeMsg(source,msg);
		reallySend(source,msg,0);
	}

	@Override
	public void sendOthers(final MOB source, final CMMsg msg)
	{
		reallySend(source,msg,0);
	}

	@Override
	public void showHappens(final int allCode, final String allMessage)
	{
		final MOB everywhereMOB=CMLib.map().getFactoryMOB(this);
		final CMMsg msg=CMClass.getMsg(everywhereMOB,null,null,allCode,allCode,allCode,allMessage);
		sendOthers(everywhereMOB,msg);
		everywhereMOB.destroy();
	}

	@Override
	public void showHappens(final int allCode, final Environmental like, final String allMessage)
	{
		final MOB everywhereMOB=CMClass.getFactoryMOB();
		everywhereMOB.setName(like.name());
		if(like instanceof Physical)
			everywhereMOB.setBasePhyStats(((Physical)like).phyStats());
		everywhereMOB.setLocation(this);
		everywhereMOB.recoverPhyStats();
		final CMMsg msg=CMClass.getMsg(everywhereMOB,null,null,allCode,allCode,allCode,allMessage);
		send(everywhereMOB,msg);
		everywhereMOB.destroy();
	}

	@Override
	public boolean show(final MOB source, final Environmental target, final int allCode, final String allMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,null,allCode,allCode,allCode,allMessage);
		if((!CMath.bset(allCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		send(source,msg);
		return true;
	}

	@Override
	public boolean show(final MOB source, final Environmental target, final Environmental tool, final int allCode, final String allMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,tool,allCode,allCode,allCode,allMessage);
		if((!CMath.bset(allCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		send(source,msg);
		return true;
	}

	@Override
	public boolean show(MOB source,
						Environmental target,
						Environmental tool,
						int srcCode,
						int tarCode,
						int othCode,
						String allMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,tool,srcCode,tarCode,othCode,allMessage);
		if((!CMath.bset(srcCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		send(source,msg);
		return true;
	}

	@Override
	public boolean show(MOB source,
						Environmental target,
						Environmental tool,
						int allCode,
						String srcMessage,
						String tarMessage,
						String othMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,tool,allCode,srcMessage,allCode,tarMessage,allCode,othMessage);
		if((!CMath.bset(allCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		send(source,msg);
		return true;
	}

	@Override
	public boolean show(MOB source,
						Environmental target,
						Environmental tool,
						int srcCode,
						String srcMessage,
						int tarCode,
						String tarMessage,
						int othCode,
						String othMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,tool,srcCode,srcMessage,tarCode,tarMessage,othCode,othMessage);
		if((!CMath.bset(srcCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		send(source,msg);
		return true;
	}

	@Override
	public boolean showOthers(MOB source,
							  Environmental target,
							  int allCode,
							  String allMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,null,allCode,allCode,allCode,allMessage);
		if((!CMath.bset(allCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		reallySend(source,msg,0);
		return true;
	}

	@Override
	public boolean showOthers(MOB source,
						   Environmental target,
						   Environmental tool,
						   int allCode,
						   String allMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,tool,allCode,allCode,allCode,allMessage);
		if((!CMath.bset(allCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		reallySend(source,msg,0);
		return true;
	}

	@Override
	public boolean showSource(MOB source,
						   Environmental target,
						   int allCode,
						   String allMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,null,allCode,allCode,allCode,allMessage);
		if((!CMath.bset(allCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		source.executeMsg(source,msg);
		return true;
	}

	@Override
	public boolean showSource(MOB source,
						   Environmental target,
						   Environmental tool,
						   int allCode,
						   String allMessage)
	{
		final CMMsg msg=CMClass.getMsg(source,target,tool,allCode,allCode,allCode,allMessage);
		if((!CMath.bset(allCode,CMMsg.MASK_ALWAYS))&&(!okMessage(source,msg)))
			return false;
		source.executeMsg(source,msg);
		return true;
	}

	@Override
	public Exit getRawExit(final int dir)
	{
		if(dir<exits.length)
			return exits[dir];
		return null;
	}

	@Override
	public Room[] rawDoors()
	{
		return doors;
	}

	@Override
	public boolean isSavable()
	{
		return ((roomID().length()>0)
				&&((getArea()==null)
					|| (!CMath.bset(getArea().flags(),Area.FLAG_INSTANCE_CHILD)))
				&&(CMLib.flags().isSavable(this)));
	}

	@Override
	public void setSavable(boolean truefalse)
	{
		CMLib.flags().setSavable(this, truefalse);
	}

	@Override
	public void destroy()
	{
		if((phyStats().sensesMask()&PhyStats.SENSE_UNDESTROYABLE)>0)
			return;
		CMLib.map().registerWorldObjectDestroyed(getArea(),this,this);
		delAllEffects(true);
		delAllInhabitants(true);
		delAllBehaviors();
		delAllScripts();
		CMLib.threads().deleteTick(this,-1);
		delAllItems(true);
		if(this instanceof GridLocale)
			((GridLocale)this).clearGrid(null);
		clearSky();
		if((roomID().length()==0)&&(rawDoors()!=null))
		{
			Room roomDir=null;
			for(int d=Directions.NUM_DIRECTIONS()-1;d>=0;d--)
			{
				roomDir=rawDoors()[d];
				if((roomDir!=null)&&(roomDir.rawDoors()!=null))
				{
					for(int d2=Directions.NUM_DIRECTIONS()-1;d2>=0;d2--)
					{
						if(roomDir.rawDoors()[d2]==this)
						{
							roomDir.rawDoors()[d2]=null;
							roomDir.setRawExit(d2,null);
						}
					}
				}
			}
		}
		rawImageName=null;
		cachedImageName=null;
		setArea(null); // this actually deletes the room from the cache map
		basePhyStats=(PhyStats)CMClass.getCommon("DefaultPhyStats");
		phyStats=basePhyStats;
		for(int d=Directions.NUM_DIRECTIONS()-1;d>=0;d--)
			setRawExit(d,null);
		Arrays.fill(exits, null);
		Arrays.fill(doors, null);
		affects=null;
		behaviors=null;
		scripts=null;
		contents.setSize(0);
		inhabitants.setSize(0);
		gridParent=null;
		amDestroyed=true;
	}

	@Override
	public final boolean amDestroyed()
	{
		return amDestroyed;
	}

	@Override
	public int getCombatTurnMobIndex()
	{
		return combatTurnMobIndex;
	}

	@Override
	public void setCombatTurnMobIndex(final int index)
	{
		combatTurnMobIndex = (short)index;
	}

	@Override
	public boolean isHere(Environmental E)
	{
		if(E instanceof Item)
			return isContent((Item)E);
		else
		if(E instanceof MOB)
			return isInhabitant((MOB)E);
		else
		if(E instanceof Exit)
		{
			for(int d=Directions.NUM_DIRECTIONS()-1;d>=0;d--)
			{
				if(getRawExit(d)==E)
					return true;
			}
		}
		else
		if(E instanceof Room)
		{
			if (E == this)
				return true;
			if (E instanceof Room)
			{
				if (CMLib.map().getExtendedRoomID(this).equals(CMLib.map().getExtendedRoomID((Room) E)))
					return true;
			}
			return false;
		}
		else
		if(E instanceof Ability)
			return fetchEffect(E.ID())!=null;
		else
		if(E instanceof Behavior)
			return fetchBehavior(E.ID())!=null;
		return false;
	}

	@Override
	public MOB fetchRandomInhabitant()
	{
		if(inhabitants.isEmpty())
			return null;
		return fetchInhabitant(CMLib.dice().roll(1,numInhabitants(),-1));
	}

	@Override
	public MOB fetchInhabitant(String inhabitantID)
	{
		if(inhabitants.isEmpty())
			return null;
		MOB mob=(MOB)CMLib.english().fetchEnvironmental(inhabitants,inhabitantID,true);
		if(mob==null)
			mob=(MOB)CMLib.english().fetchEnvironmental(inhabitants,inhabitantID, false);
		return mob;
	}

	private static final ReadOnlyVector<MOB> emptyMOBV=new ReadOnlyVector<MOB>(1);

	@SuppressWarnings("unchecked")
	@Override
	public List<MOB> fetchInhabitants(String inhabitantID)
	{
		if(inhabitants.isEmpty())
			return emptyMOBV;
		@SuppressWarnings("rawtypes")
		List inhabs=CMLib.english().fetchEnvironmentals(inhabitants,inhabitantID,true);
		if(inhabs.isEmpty())
			inhabs=CMLib.english().fetchEnvironmentals(inhabitants,inhabitantID, false);
		return inhabs;
	}

	@Override
	public void addInhabitant(MOB mob)
	{
		inhabitants.addElement(mob);
	}

	@Override
	public Enumeration<MOB> inhabitants()
	{
		return inhabitants.elements();
	}

	@Override
	public int numInhabitants()
	{
		return inhabitants.size();
	}

	@Override
	public int numPCInhabitants()
	{
		final Set<MOB> playerInhabitants=CMLib.players().getPlayersHere(this);
		if(playerInhabitants.isEmpty())
			return 0;
		int num=0;
		for(final MOB M : playerInhabitants)
		{
			if((M!=null)&&(M.session()!=null))
				num++;
		}
		return num;
	}

	@Override
	public boolean isInhabitant(MOB mob)
	{
		return inhabitants.contains(mob);
	}

	@Override
	public MOB fetchInhabitant(int i)
	{
		try
		{
			return inhabitants.elementAt(i);
		}
		catch(final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}

	@Override
	public void eachInhabitant(final EachApplicable<MOB> applier)
	{
		final List<MOB> inhabitants=this.inhabitants;
		if((inhabitants!=null)&&(!inhabitants.isEmpty()))
		{
			try
			{
				for(int a=0;a<inhabitants.size();a++)
				{
					final MOB M=inhabitants.get(a);
					if(M!=null)
						applier.apply(M);
				}
			}
			catch(final ArrayIndexOutOfBoundsException e)
			{
			}
		}
	}

	@Override
	public void delInhabitant(MOB mob)
	{
		inhabitants.removeElement(mob);
	}

	@Override
	public void delAllInhabitants(boolean destroy)
	{
		try
		{
			for(int i=numInhabitants()-1;i>=0;i--)
			{
				final MOB M=fetchInhabitant(i);
				if(M!=null)
				{
					if(destroy || (M.location()==this))
						M.setLocation(null);
					M.destroy();
				}
			}
			inhabitants.clear();
		}
		catch(final Exception e)
		{
		}
	}

	@Override
	public Exit fetchExit(String itemID)
	{
		int dir=CMLib.directions().getGoodDirectionCode(itemID);
		Exit E=null;
		if(dir >= 0)
			E=getExitInDir(dir);
		final List<Exit> exitList=Arrays.asList(exits);
		if(E==null)
			E=CMLib.english().fetchExit(exitList, itemID, true);
		if(E==null)
			E=CMLib.english().fetchExit(exitList, itemID, false);
		if(contents.isEmpty())
			return E;
		if(E==null)
			E=CMLib.english().fetchExit(contents, itemID, true);
		if(E==null)
			E=CMLib.english().fetchExit(contents, itemID, false);
		return E;
	}

	@Override
	public Item findItem(String itemID)
	{
		if(contents.isEmpty())
			return null;
		Item item=(Item)CMLib.english().fetchEnvironmental(contents,itemID,true);
		if(item==null)
			item=(Item)CMLib.english().fetchEnvironmental(contents,itemID,false);
		return item;
	}

	@Override
	public Enumeration<Item> items()
	{
		return contents.elements();
	}

	@Override
	public Item findItem(Item goodLocation, String itemID)
	{
		if(contents.isEmpty())
			return null;
		Item item=CMLib.english().fetchAvailableItem(contents,itemID,goodLocation,Wearable.FILTER_ANY,true);
		if(item==null)
			item=CMLib.english().fetchAvailableItem(contents,itemID,goodLocation,Wearable.FILTER_ANY,false);
		return item;
	}

	@Override
	public List<Item> findItems(Item goodLocation, String itemID)
	{
		if(contents.isEmpty())
			return new Vector<Item>(1);
		List<Item> items=CMLib.english().fetchAvailableItems(contents,itemID,goodLocation,Wearable.FILTER_ANY,true);
		if(items.isEmpty())
			items=CMLib.english().fetchAvailableItems(contents,itemID,goodLocation,Wearable.FILTER_ANY,false);
		return items;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public List<Item> findItems(String itemID)
	{
		if(contents.isEmpty())
			return new Vector<Item>(1);
		List items=CMLib.english().fetchEnvironmentals(contents,itemID,true);
		if(items.isEmpty())
			items=CMLib.english().fetchEnvironmentals(contents,itemID, false);
		return items;
	}

	@Override
	public void addItem(Item item, Expire expire)
	{
		if(expire == null)
		{
			expire=Expire.Never;
		}
		int numMins = 0;
		switch(expire)
		{
		case Monster_EQ: 
			addItem(item);
			numMins = CMProps.getIntVar(CMProps.Int.EXPIRE_MONSTER_EQ); 
			break;
		case Monster_Body: 
			insertItemUpTop(item);
			numMins = CMProps.getIntVar(CMProps.Int.EXPIRE_MONSTER_BODY); 
			break;
		case Player_Body: 
			insertItemUpTop(item);
			numMins = CMProps.getIntVar(CMProps.Int.EXPIRE_PLAYER_BODY); 
			break;
		case Player_Drop: 
			addItem(item);
			numMins = CMProps.getIntVar(CMProps.Int.EXPIRE_PLAYER_DROP); 
			break;
		case Resource: 
			addItem(item);
			numMins = CMProps.getIntVar(CMProps.Int.EXPIRE_RESOURCE); 
			break;
		case Never: 
			addItem(item);
			break;
		}
		if(numMins==0)
			item.setExpirationDate(0);
		else
			item.setExpirationDate(System.currentTimeMillis()+(numMins * TimeManager.MILI_MINUTE));
	}

	protected void insertItemUpTop(Item item)
	{
		if((item!=null)&&(!item.amDestroyed()))
		{
			item.setOwner(this);
			if(!contents.isEmpty())
				contents.add(0,item);
			else
				contents.add(item);
			item.recoverPhyStats();
		}
	}

	@Override
	public void addItem(Item item)
	{
		if((item!=null)&&(!item.amDestroyed()))
		{
			item.setOwner(this);
			contents.addElement(item);
			item.recoverPhyStats();
		}
	}

	@Override
	public void delItem(Item item)
	{
		contents.removeElement(item);
		item.recoverPhyStats();
	}

	@Override
	public void delAllItems(boolean destroy)
	{
		if(destroy)
		{
			for(int i=numItems()-1;i>=0;i--)
			{
				final Item I=getItem(i);
				if(I!=null)
				{
					// since were deleting you AND all your peers, no need for Item to do it.
					I.setOwner(null);
					I.destroy();
				}
			}
		}
		contents.clear();
	}

	@Override
	public int numItems()
	{
		return contents.size();
	}

	@Override
	public boolean isContent(Item item)
	{
		return contents.contains(item);
	}

	@Override
	public Item getItem(int i)
	{
		try
		{
			return contents.elementAt(i);
		}
		catch(final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}

	@Override
	public void eachItem(final EachApplicable<Item> applier)
	{
		final List<Item> contents=this.contents;
		if((contents!=null)&&(!contents.isEmpty()))
		{
			try
			{
				for(int a=0;a<contents.size();a++)
				{
					final Item I=contents.get(a);
					if(I!=null)
						applier.apply(I);
				}
			}
			catch(final ArrayIndexOutOfBoundsException e)
			{
			}
		}
	}

	@Override
	public Item getRandomItem()
	{
		if(numItems()==0)
			return null;
		return getItem(CMLib.dice().roll(1,numItems(),-1));
	}

	@Override
	public String getContextName(Environmental E)
	{
		if(E instanceof Exit)
		{
			for(int e=0;e<exits.length;e++)
			{
				if(exits[e]==E)
				{
					if((this instanceof BoardableShip)||(this.getArea() instanceof BoardableShip))
						return CMLib.directions().getShipDirectionName(e);
					else
						return CMLib.directions().getDirectionName(e);
				}
			}
			return E.Name();
		}
		else
		if(E instanceof MOB)
		{
			final String ctxName=CMLib.english().getContextName(inhabitants,E);
			if(ctxName!=null)
				return ctxName;
		}
		else
		if(E instanceof Item)
		{
			final String ctxName=CMLib.english().getContextName(contents,E);
			if(ctxName!=null)
				return ctxName;
		}
		else
		if(E!=null)
			return E.name();
		return "nothing";
	}

	@Override
	public PhysicalAgent fetchFromMOBRoomItemExit(MOB mob, Item goodLocation, String thingName, final Filterer<Environmental> filter)
	{
		PhysicalAgent found=null;
		String newThingName=CMLib.lang().preItemParser(thingName);
		if(newThingName!=null)
			thingName=newThingName;
		final boolean mineOnly=(mob!=null)&&(thingName.toUpperCase().trim().startsWith("MY "));
		if(mineOnly)
			thingName=thingName.trim().substring(3).trim();
		if((mob!=null)&&((filter!=Wearable.FILTER_WORNONLY)))
		{
			found=mob.fetchItem(goodLocation, new Filterer<Environmental>()
			{
				@Override
				public boolean passesFilter(Environmental obj)
				{
					return filter.passesFilter(obj) && Wearable.FILTER_UNWORNONLY.passesFilter(obj);
				}
			}, thingName);
		}
		if((found==null)&&(!mineOnly))
		{
			found=(Exit)CMLib.english().fetchEnvironmental(Arrays.asList(exits),thingName,true);
			if(found==null)
				found=CMLib.english().fetchAvailableItem(contents,thingName,goodLocation,filter,true);
			if(found==null)
				found=(Exit)CMLib.english().fetchEnvironmental(Arrays.asList(exits),thingName,false);
			if(found==null)
				found=CMLib.english().fetchAvailableItem(contents,thingName,goodLocation,filter,false);

			if((found instanceof Item)  // the smurfy well/gate exception
			&&(goodLocation==null)
			&&(found.displayText().length()==0)
			&&(thingName.indexOf('.')<0))
			{
				PhysicalAgent visibleItem=null;
				visibleItem=(Exit)CMLib.english().fetchEnvironmental(Arrays.asList(exits),thingName,false);
				if(visibleItem==null)
					visibleItem=fetchFromMOBRoomItemExit(null,null,thingName+".2",filter);
				if(visibleItem!=null)
					found=visibleItem;
			}

			if((found!=null)&&(CMLib.flags().canBeSeenBy(found,mob)))
				return found;
			while((found!=null)&&(!CMLib.flags().canBeSeenBy(found,mob)))
			{
				newThingName=CMLib.english().bumpDotNumber(thingName);
				if(!newThingName.equals(thingName))
				{
					thingName=newThingName;
					found=fetchFromRoomFavorItems(goodLocation, thingName);
				}
				else
					found=null;
			}
		}
		if((mob!=null)&&(found==null)&&((filter!=Wearable.FILTER_UNWORNONLY)))
		{
			found=mob.fetchItem(null, new Filterer<Environmental>()
			{
				@Override
				public boolean passesFilter(Environmental obj)
				{
					return filter.passesFilter(obj) && Wearable.FILTER_WORNONLY.passesFilter(obj);
				}
			}, thingName);
		}
		if(found==null)
		{
			newThingName=CMLib.lang().failedItemParser(thingName);
			if(newThingName!=null)
				return fetchFromMOBRoomItemExit(mob,goodLocation,newThingName,filter);
		}
		return found;
	}

	@Override
	public PhysicalAgent fetchFromRoomFavorItems(Item goodLocation, String thingName)
	{
		// def was Wearable.FILTER_UNWORNONLY;
		String newThingName=CMLib.lang().preItemParser(thingName);
		if(newThingName!=null)
			thingName=newThingName;
		PhysicalAgent found=null;
		final int[] contextNumber=new int[]{0};
		if(!contents.isEmpty())
			found=(PhysicalAgent)CMLib.english().fetchAvailable(contents,thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		if(found==null)
			found=(PhysicalAgent)CMLib.english().fetchAvailable(Arrays.asList(exits),thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		if((found==null)&&(!inhabitants.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(inhabitants,thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		contextNumber[0]=0;
		if((found==null)&&(!contents.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(contents,thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);
		if(found==null)
			found=(PhysicalAgent)CMLib.english().fetchAvailable(Arrays.asList(exits),thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);
		if((found==null)&&(!inhabitants.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(inhabitants,thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);

		if((found!=null) // the smurfy well exception
		&&(found instanceof Item)
		&&(goodLocation==null)
		&&(found.displayText().length()==0)
		&&(thingName.indexOf('.')<0))
		{
			final PhysicalAgent visibleItem=fetchFromRoomFavorItems(null,thingName+".2");
			if(visibleItem!=null)
				found=visibleItem;
		}
		if(found==null)
		{
			newThingName=CMLib.lang().failedItemParser(thingName);
			if(newThingName!=null)
				return fetchFromRoomFavorItems(goodLocation,newThingName);
		}
		return found;
	}

	@Override
	public PhysicalAgent fetchFromRoomFavorExits(String thingName)
	{
		String newThingName=CMLib.lang().preItemParser(thingName);
		if(newThingName!=null)
			thingName=newThingName;
		final Item goodLocation=null;
		PhysicalAgent found=null;
		final int dirCode = CMLib.directions().getGoodDirectionCode(thingName);
		final int[] contextNumber=new int[]{0};
		if(dirCode>=0)
			found=getRoomInDir(dirCode);
		if(found==null)
			found=(PhysicalAgent)CMLib.english().fetchAvailable(Arrays.asList(exits),thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		if((found==null)&&(!contents.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(contents,thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		if((found==null)&&(!inhabitants.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(inhabitants,thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		contextNumber[0]=0;
		if(found==null)
			found=(PhysicalAgent)CMLib.english().fetchAvailable(Arrays.asList(exits),thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);
		if((found==null)&&(!contents.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(contents,thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);
		if((found==null)&&(!inhabitants.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(inhabitants,thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);
		if(found==null)
		{
			newThingName=CMLib.lang().failedItemParser(thingName);
			if(newThingName!=null)
				return fetchFromRoomFavorMOBs(goodLocation,newThingName);
		}
		return found;
	}
	
	@Override
	public PhysicalAgent fetchFromRoomFavorMOBs(Item goodLocation, String thingName)
	{
		// def was Wearable.FILTER_UNWORNONLY;
		String newThingName=CMLib.lang().preItemParser(thingName);
		if(newThingName!=null)
			thingName=newThingName;
		final int[] contextNumber = new int[]{0};
		PhysicalAgent found=null;
		if(!inhabitants.isEmpty())
			found=(PhysicalAgent)CMLib.english().fetchAvailable(inhabitants,thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		if((found==null)&&(!contents.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(contents,thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		if(found==null)
			found=(PhysicalAgent)CMLib.english().fetchAvailable(Arrays.asList(exits),thingName,goodLocation,Wearable.FILTER_ANY,true,contextNumber);
		contextNumber[0]=0;
		if((found==null)&&(!inhabitants.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(inhabitants,thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);
		if((found==null)&&(!contents.isEmpty()))
			found=(PhysicalAgent)CMLib.english().fetchAvailable(contents,thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);
		if(found==null)
			found=(PhysicalAgent)CMLib.english().fetchAvailable(Arrays.asList(exits),thingName,goodLocation,Wearable.FILTER_ANY,false,contextNumber);
		if(found==null)
		{
			newThingName=CMLib.lang().failedItemParser(thingName);
			if(newThingName!=null)
				return fetchFromRoomFavorMOBs(goodLocation,newThingName);
		}
		return found;
	}

	@Override
	public PhysicalAgent fetchFromMOBRoomFavorsItems(MOB mob, Item goodLocation, String thingName, Filterer<Environmental> filter)
	{
		return fetchFromMOBRoom(mob,goodLocation,thingName,filter,true);
	}

	@Override
	public PhysicalAgent fetchFromMOBRoomFavorsMOBs(MOB mob, Item goodLocation, String thingName, Filterer<Environmental> filter)
	{
		return fetchFromMOBRoom(mob,goodLocation,thingName,filter,false);
	}

	private PhysicalAgent fetchFromMOBRoom(MOB mob, Item goodLocation, String thingName, final Filterer<Environmental> filter, boolean favorItems)
	{
		PhysicalAgent found=null;
		String newThingName=CMLib.lang().preItemParser(thingName);
		if(newThingName!=null)
			thingName=newThingName;
		final boolean mineOnly=(mob!=null)&&(thingName.toUpperCase().trim().startsWith("MY "));
		if(mineOnly)
			thingName=thingName.trim().substring(3).trim();
		if((mob!=null)&&(favorItems)&&(filter!=Wearable.FILTER_WORNONLY))
		{
			found=mob.fetchItem(goodLocation, new Filterer<Environmental>()
			{
				@Override
				public boolean passesFilter(Environmental obj)
				{
					return filter.passesFilter(obj) && Wearable.FILTER_UNWORNONLY.passesFilter(obj);
				}
			}, thingName);
		}
		if((found==null)&&(!mineOnly))
		{
			if(favorItems)
				found=fetchFromRoomFavorItems(goodLocation, thingName);
			else
				found=fetchFromRoomFavorMOBs(goodLocation, thingName);
			if((found!=null)&&(CMLib.flags().canBeSeenBy(found,mob)))
				return found;
			while((found!=null)&&(!CMLib.flags().canBeSeenBy(found,mob)))
			{
				newThingName=CMLib.english().bumpDotNumber(thingName);
				if(!newThingName.equals(thingName))
				{
					thingName=newThingName;
					if(favorItems)
						found=fetchFromRoomFavorItems(goodLocation, thingName);
					else
						found=fetchFromRoomFavorMOBs(goodLocation, thingName);
				}
				else
					found=null;
			}
		}
		if((mob!=null)&&(!favorItems)&&(filter!=Wearable.FILTER_WORNONLY))
		{
			found=mob.fetchItem(goodLocation, new Filterer<Environmental>()
			{
				@Override
				public boolean passesFilter(Environmental obj)
				{
					return filter.passesFilter(obj) && Wearable.FILTER_UNWORNONLY.passesFilter(obj);
				}
			}, thingName);
		}
		if((mob!=null)&&(found==null)&&(filter!=Wearable.FILTER_UNWORNONLY))
		{
			found=mob.fetchItem(null, new Filterer<Environmental>()
			{
				@Override
				public boolean passesFilter(Environmental obj)
				{
					return filter.passesFilter(obj) && Wearable.FILTER_WORNONLY.passesFilter(obj);
				}
			}, thingName);
		}
		if((mob!=null)&&(found==null))
			found=mob.fetchItem(goodLocation,filter,thingName);
		if(found==null)
		{
			final boolean inShip=(this instanceof BoardableShip)||(this.getArea() instanceof BoardableShip);
			for(int d=0;d<exits.length;d++)
			{
				if((exits[d]!=null)
				&&(thingName.equalsIgnoreCase(inShip?CMLib.directions().getShipDirectionName(d):CMLib.directions().getDirectionName(d))))
					return getExitInDir(d);
			}
		}
		if(found==null)
		{
			newThingName=CMLib.lang().failedItemParser(thingName);
			if(newThingName!=null)
				return fetchFromMOBRoom(mob,goodLocation,newThingName,filter,favorItems);
		}
		return found;
	}

	@Override
	public int pointsPerMove()
	{
		return getArea().getClimateObj().adjustMovement(phyStats().weight(),this);
	}

	protected int baseThirst()
	{
		return 1;
	}

	@Override
	public int thirstPerRound()
	{
		final int derivedClimate=getClimateType();
		int adjustment=0;
		if(CMath.bset(derivedClimate, Places.CLIMASK_HOT))
			adjustment+=1;
		if(CMath.bset(derivedClimate, Places.CLIMASK_WET))
			adjustment-=1;
		if(CMath.bset(derivedClimate, Places.CLIMASK_DRY))
			adjustment+=1;
		if(CMath.bset(derivedClimate, Places.CLIMASK_WINDY))
			adjustment+=1;
		if(getArea().getClimateObj()!=null)
			return getArea().getClimateObj().adjustWaterConsumption(baseThirst()+adjustment,this);
		return 0;
	}

	@Override
	public int minRange()
	{
		return Integer.MIN_VALUE;
	}

	@Override
	public int maxRange()
	{
		return((domainType()&Room.INDOORS)>0)?1:10;
	}

	@Override
	public void addEffect(Ability to)
	{
		if(to==null)
			return;
		if(fetchEffect(to.ID())!=null)
			return;
		if(affects==null)
			affects=new SVector<Ability>(1);
		if(affects.contains(to))
			return;
		affects.addElement(to);
		to.setAffectedOne(this);
	}

	@Override
	public void addNonUninvokableEffect(Ability to)
	{
		if(to==null)
			return;
		if(fetchEffect(to.ID())!=null)
			return;
		if(affects==null)
			affects=new SVector<Ability>(1);
		to.makeNonUninvokable();
		to.makeLongLasting();
		affects.addElement(to);
		to.setAffectedOne(this);
	}

	@Override
	public void delEffect(Ability to)
	{
		if(affects==null)
			return;
		if(affects.remove(to))
		{
			to.setAffectedOne(null);
			if(affects.isEmpty())
				affects=new SVector<Ability>(1);
		}
	}

	@Override
	public void eachEffect(final EachApplicable<Ability> applier)
	{
		final List<Ability> affects=this.affects;
		if((affects!=null)&&(!affects.isEmpty()))
		try
		{
			for(int a=0;a<affects.size();a++)
			{
				final Ability A=affects.get(a);
				if(A!=null)
					applier.apply(A);
			}
		}
		catch(final ArrayIndexOutOfBoundsException e)
		{
		}
	}

	@Override
	public void delAllEffects(boolean unInvoke)
	{
		if(affects==null)
			return;
		for(int a=numEffects()-1;a>=0;a--)
		{
			final Ability A=fetchEffect(a);
			if(A!=null)
			{
				if(unInvoke)
					A.unInvoke();
				A.setAffectedOne(null);
			}
		}
		affects=new SVector<Ability>(1);
	}

	@Override
	public int numEffects()
	{
		if(affects==null)
			return 0;
		return affects.size();
	}

	@SuppressWarnings("unchecked")
	@Override
	public Enumeration<Ability> effects()
	{
		return (affects==null)?EmptyEnumeration.INSTANCE:affects.elements();
	}

	@Override
	public Ability fetchEffect(int index)
	{
		if(affects==null)
			return null;
		try
		{
			return affects.elementAt(index);
		}
		catch(final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}

	@Override
	public Ability fetchEffect(String ID)
	{
		if(affects==null)
			return null;
		for(final Enumeration<Ability> a=effects();a.hasMoreElements();)
		{
			final Ability A=a.nextElement();
			if(A.ID().equals(ID))
				return A;
		}
		return null;
	}

	/** Manipulation of Behavior objects, which includes
	 * movement, speech, spellcasting, etc, etc.*/
	@Override
	public void addBehavior(Behavior to)
	{
		if(to==null)
			return;
		if(behaviors==null)
			behaviors=new SVector<Behavior>(1);
		for(final Behavior B : behaviors)
			if(B.ID().equals(to.ID()))
			   return;
		if(behaviors.isEmpty())
			CMLib.threads().startTickDown(this,Tickable.TICKID_ROOM_BEHAVIOR,1);
		to.startBehavior(this);
		behaviors.addElement(to);
	}

	@Override
	public void delBehavior(Behavior to)
	{
		if(behaviors==null)
			return;
		if(behaviors.remove(to))
		{
			if(behaviors.isEmpty())
				behaviors=new SVector<Behavior>(1);
			if(((behaviors==null)||(behaviors.isEmpty()))&&((scripts==null)||(scripts.isEmpty())))
				CMLib.threads().deleteTick(this,Tickable.TICKID_ROOM_BEHAVIOR);
		}
	}

	@Override
	public void delAllBehaviors()
	{
		final boolean didSomething=(behaviors!=null)&&(!behaviors.isEmpty());
		if(didSomething)
			behaviors.clear();
		behaviors=null;
		if(didSomething && ((scripts==null)||(scripts.isEmpty())))
			CMLib.threads().deleteTick(this,Tickable.TICKID_ROOM_BEHAVIOR);
	}

	@Override
	public int numBehaviors()
	{
		if(behaviors==null)
			return 0;
		return behaviors.size();
	}

	@SuppressWarnings("unchecked")
	@Override
	public Enumeration<Behavior> behaviors()
	{
		return (behaviors==null)?EmptyEnumeration.INSTANCE:behaviors.elements();
	}

	@Override
	public Behavior fetchBehavior(int index)
	{
		if(behaviors==null)
			return null;
		try
		{
			return behaviors.elementAt(index);
		}
		catch(final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}

	@Override
	public Behavior fetchBehavior(String ID)
	{
		if(behaviors==null)
			return null;
		for(final Behavior B : behaviors)
		{
			if(B.ID().equalsIgnoreCase(ID))
				return B;
		}
		return null;
	}

	@Override
	public void eachBehavior(final EachApplicable<Behavior> applier)
	{
		final List<Behavior> behaviors=this.behaviors;
		if((behaviors!=null)&&(!behaviors.isEmpty()))
		try
		{
			for(int a=0;a<behaviors.size();a++)
			{
				final Behavior B=behaviors.get(a);
				if(B!=null)
					applier.apply(B);
			}
		}
		catch(final ArrayIndexOutOfBoundsException e)
		{
		}
	}

	/** Manipulation of the scripts list */
	@Override
	public void addScript(ScriptingEngine S)
	{
		if(scripts==null)
			scripts=new SVector<ScriptingEngine>(1);
		if(S==null)
			return;
		if(!scripts.contains(S))
		{
			for(final Enumeration<ScriptingEngine> s2=scripts();s2.hasMoreElements();)
			{
				final ScriptingEngine S2=s2.nextElement();
				if(S2.getScript().equalsIgnoreCase(S.getScript()))
					return;
			}
			if(scripts.isEmpty())
				CMLib.threads().startTickDown(this,Tickable.TICKID_ROOM_BEHAVIOR,1);
			scripts.addElement(S);
		}
	}

	@Override
	public void delScript(ScriptingEngine S)
	{
		if(scripts!=null)
		{
			if(scripts.remove(S))
			{
				if(scripts.isEmpty())
					scripts=new SVector<ScriptingEngine>(1);
				if(((behaviors==null)||(behaviors.isEmpty()))&&((scripts==null)||(scripts.isEmpty())))
					CMLib.threads().deleteTick(this,Tickable.TICKID_ROOM_BEHAVIOR);
			}
		}
	}

	@Override
	public void delAllScripts()
	{
		final boolean didSomething=(scripts!=null)&&(!scripts.isEmpty());
		if(didSomething)
			scripts.clear();
		scripts=null;
		if(didSomething && ((behaviors==null)||(behaviors.isEmpty())))
		  CMLib.threads().deleteTick(this,Tickable.TICKID_ROOM_BEHAVIOR);
	}

	@Override
	public int numScripts()
	{
		return (scripts==null)?0:scripts.size();
	}

	@SuppressWarnings("unchecked")
	@Override
	public Enumeration<ScriptingEngine> scripts()
	{
		return (scripts==null)?EmptyEnumeration.INSTANCE:scripts.elements();
	}

	@Override
	public ScriptingEngine fetchScript(int x)
	{
		try
		{
			return scripts.elementAt(x);
		}
		catch (final Exception e)
		{
		}
		return null;
	}

	@Override
	public void eachScript(final EachApplicable<ScriptingEngine> applier)
	{
		final List<ScriptingEngine> scripts=this.scripts;
		if((scripts!=null)&&(!scripts.isEmpty()))
		try
		{
			for(int a=0;a<scripts.size();a++)
			{
				final ScriptingEngine S=scripts.get(a);
				if(S!=null)
					applier.apply(S);
			}
		}
		catch(final ArrayIndexOutOfBoundsException e)
		{
		}
	}

	@Override
	public String L(final String str, final String... xs)
	{
		return CMLib.lang().fullSessionTranslation(str, xs);
	}

	@Override
	public int getSaveStatIndex()
	{
		return (xtraValues == null) ? getStatCodes().length : getStatCodes().length - xtraValues.length;
	}

	protected static final String[]	STDCODES	= { "CLASS", "DISPLAY", "DESCRIPTION", "TEXT", "AFFBEHAV", "IMAGE", "CLIMATE", "ATMOSPHERE" };
	private static String[]			codes		= null;

	@Override
	public String[] getStatCodes()
	{
		if (codes == null)
			codes = CMProps.getStatCodesList(STDCODES, this);
		return codes;
	}

	@Override
	public boolean isStat(String code)
	{
		return CMParms.indexOf(getStatCodes(), code.toUpperCase().trim()) >= 0;
	}

	protected int getCodeNum(String code)
	{
		return CMParms.indexOf(codes, code.toUpperCase());
	}

	@Override
	public String getStat(String code)
	{
		switch (getCodeNum(code))
		{
		case 0:
			return CMClass.classID(this);
		case 1:
			return displayText();
		case 2:
			return description();
		case 3:
			return text();
		case 4:
			return CMLib.coffeeMaker().getExtraEnvPropertiesStr(this);
		case 5:
			return rawImage();
		case 6:
			return "" + getClimateTypeCode();
		case 7:
			return "" + getAtmosphereCode();
		default:
			return CMProps.getStatCodeExtensionValue(getStatCodes(), xtraValues, code);
		}
	}

	@Override
	public void setStat(String code, String val)
	{
		switch (getCodeNum(code))
		{
		case 0:
			return;
		case 1:
			setDisplayText(val);
			break;
		case 2:
			setDescription(val);
			break;
		case 3:
			setMiscText(val);
			break;
		case 4:
		{
			delAllEffects(true);
			delAllBehaviors();
			CMLib.coffeeMaker().setExtraEnvProperties(this, CMLib.xml().parseAllXML(val));
			break;
		}