<NME> DefaultFaction.java
<BEF> package com.planet_ink.coffee_mud.Common;
import com.planet_ink.coffee_mud.core.database.DBInterface;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.core.CMClass.CMObjectType;
import com.planet_ink.coffee_mud.core.collections.*;
import com.planet_ink.coffee_mud.Abilities.Misc.PresenceReaction;
import com.planet_ink.coffee_mud.Abilities.interfaces.*;
import com.planet_ink.coffee_mud.Areas.interfaces.*;
import com.planet_ink.coffee_mud.Behaviors.interfaces.*;
import com.planet_ink.coffee_mud.CharClasses.interfaces.*;
import com.planet_ink.coffee_mud.Commands.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.Faction.FData;
import com.planet_ink.coffee_mud.Common.interfaces.Faction.FRange;
import com.planet_ink.coffee_mud.Common.interfaces.Faction.FactionChangeEvent.MiscTrigger;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.ChannelsLibrary;
import com.planet_ink.coffee_mud.Libraries.interfaces.EnglishParsing;
import com.planet_ink.coffee_mud.Libraries.interfaces.MaskingLibrary;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;

import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//import java.lang.reflect.*;
/**
 * Portions Copyright (c) 2003 Jeremy Vyska
 * Portions Copyright (c) 2004-2022 Bo Zimmerman
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  	  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class DefaultFaction implements Faction, MsgListener
{
	@Override
	public String ID()
	{
		return "DefaultFaction";
	}

	@Override
	public CMObject newInstance()
	{
		try
		{
			return getClass().newInstance();
		}
		catch (final Exception e)
		{
			return new DefaultFaction();
		}
	}

	@Override
	public void initializeClass()
	{
	}

	@Override
	public CMObject copyOf()
	{
		try
		{
			return (CMObject) this.clone();
		}
		catch (final Exception e)
		{
			return newInstance();
		}
	}

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

	protected String	 _factionID			= "";
	protected String	 name				= "";
	protected String	 upName				= "";
	protected String	 choiceIntro		= "";
	protected long[]	 lastDataChange		= new long[1];
	protected int   	 minimum			= Integer.MIN_VALUE;
	protected int   	 middle				= 0;
	protected int   	 difference;
	protected int   	 maximum			= Integer.MAX_VALUE;
	protected int   	 highest			= Integer.MAX_VALUE;
	protected int   	 lowest				= Integer.MIN_VALUE;
	protected long  	 internalFlagBitmap	= 0;
	protected String	 experienceFlag		= "";
	protected boolean    useLightReactions	= false;
	protected boolean    isDisabled			= false;
	protected boolean    showInScore		= false;
	protected boolean    showInSpecialReport= false;
	protected boolean    showInEditor		= false;
	protected boolean    showInFacCommand	= true;
	protected boolean    isInherited		= true;
	protected boolean    destroyed			= false;

	protected CList<String>   					defaults		 = new SVector<String>();
	protected CList<String>   					autoDefaults	 = new SVector<String>();
	protected CMap<String,FRange> 				ranges			 = new SHashtable<String,FRange>();
	protected Map<Integer,FRange> 				rangeRangeMap	 = new PrioritizingLimitedMap<Integer,FRange>(10,60000,600000,100);
	protected CMap<String,String[]>   			affBehavs		 = new SHashtable<String,String[]>();
	protected double							rateModifier	 = 1.0;
	protected CMap<String,FactionChangeEvent[]>	changes			 = new SHashtable<String,FactionChangeEvent[]>();
	protected CMap<String,FactionChangeEvent[]>	abilChangeCache	 = new SHashtable<String,FactionChangeEvent[]>();
	protected CMap<String,FactionChangeEvent[]>	socChangeCache	 = new SHashtable<String,FactionChangeEvent[]>();
	protected CMap<Integer,FactionChangeEvent[]>msgChangeCache	 = new SHashtable<Integer,FactionChangeEvent[]>();
	protected CList<Faction.FZapFactor>			factors			 = new SVector<Faction.FZapFactor>();
	protected CMap<String,Double> 				relations		 = new SHashtable<String,Double>();
	protected CList<Faction.FAbilityUsage>		abilityUsages	 = new SVector<Faction.FAbilityUsage>();
	protected Map<String,Faction.FAbilityUsage> abilityUseCache	 = new STreeMap<String,Faction.FAbilityUsage>();
	protected Set<String> 						abilityUseMisses = new STreeSet<String>();
	protected CList<String>   					choices			 = new SVector<String>();
	protected CList<Faction.FReactionItem>		reactions		 = new SVector<Faction.FReactionItem>();
	protected CMap<String,CList<FReactionItem>>	reactionHash	 = new SHashtable<String,CList<Faction.FReactionItem>>();

	@Override
	public Enumeration<Faction.FReactionItem> reactions()
	{
		return reactions.elements();
	}

	@Override
	public Enumeration<Faction.FReactionItem> reactions(final String rangeName)
	{
		final CList<Faction.FReactionItem> V=reactionHash.get(rangeName.toUpperCase().trim());
		if(V!=null)
			return V.elements();
		return new Vector<Faction.FReactionItem>().elements();
	}

	protected Ability presenceReactionPrototype=null;

	@Override
	public String factionID()
	{
		return _factionID;
	}

	@Override
	public String name()
	{
		return name;
	}

	@Override
	public String upperName()
	{
		return upName;
	}

	@Override
	public long getInternalFlags()
	{
		return internalFlagBitmap;
	}

	@Override
	public String choiceIntro()
	{
		return choiceIntro;
	}

	@Override
	public boolean isInheritable()
	{
		return this.isInherited;
	}

	@Override
	public int minimum()
	{
		return minimum;
	}

	@Override
	public int middle()
	{
		return middle;
	}

	@Override
	public int difference()
	{
		return difference;
	}

	@Override
	public int maximum()
	{
		return maximum;
	}

	@Override
	public boolean isDisabled()
	{
		return isDisabled;
	}

	@Override
	public void disable(final boolean truefalse)
	{
		isDisabled = truefalse;
	}

	public int highest()
	{
		return highest;
	}

	public int lowest()
	{
		return lowest;
	}

	@Override
	public String experienceFlag()
	{
		return experienceFlag;
	}

	@Override
	public boolean showInScore()
	{
		return showInScore;
	}

	@Override
	public boolean showInSpecialReported()
	{
		return showInSpecialReport;
	}

	@Override
	public boolean showInEditor()
	{
		return showInEditor;
	}

	@Override
	public boolean showInFactionsCommand()
	{
		return showInFacCommand;
	}

	@Override
	public Enumeration<Faction.FRange> ranges()
	{
		return ranges.elements();
	}

	@Override
	public Enumeration<String> defaults()
	{
		return defaults.elements();
	}

	@Override
	public Enumeration<String> autoDefaults()
	{
		return autoDefaults.elements();
	}

	@Override
	public double rateModifier()
	{
		return rateModifier;
	}

	@Override
	public Enumeration<String> changeEventKeys()
	{
		return changes.keys();
	}

	@Override
	public Enumeration<Faction.FZapFactor> factors()
	{
		return factors.elements();
	}

	@Override
	public Enumeration<String> relationFactions()
	{
		return relations.keys();
	}

	@Override
	public Enumeration<Faction.FAbilityUsage> abilityUsages()
	{
		return abilityUsages.elements();
	}

	@Override
	public Enumeration<String> choices()
	{
		return choices.elements();
	}

	@Override
	public Enumeration<String> affectsBehavs()
	{
		return affBehavs.keys();
	}

	@Override
	public void setLightReactions(final boolean truefalse)
	{
		useLightReactions = truefalse;
	}

	@Override
	public boolean useLightReactions()
	{
		return useLightReactions;
	}

	@Override
	public void setFactionID(final String newStr)
	{
		_factionID = newStr;
	}

	@Override
	public void setName(final String newStr)
	{
		name = newStr;
	}

	@Override
	public void setInternalFlags(final long bitmap)
	{
		internalFlagBitmap = bitmap;
	}

	@Override
	public void setChoiceIntro(final String newStr)
	{
		choiceIntro = newStr;
	}

	@Override
	public void setExperienceFlag(final String newStr)
	{
		experienceFlag = newStr;
	}

	@Override
	public void setShowInScore(final boolean truefalse)
	{
		showInScore = truefalse;
	}

	@Override
	public void setInherited(final boolean truefalse)
	{
		this.isInherited=truefalse;
	}

	@Override
	public void setShowInSpecialReported(final boolean truefalse)
	{
		showInSpecialReport = truefalse;
	}

	@Override
	public void setShowInEditor(final boolean truefalse)
	{
		showInEditor = truefalse;
	}

	@Override
	public void setShowInFactionsCommand(final boolean truefalse)
	{
		showInFacCommand = truefalse;
	}

	@Override
	public void setChoices(final List<String> v)
	{
		choices = new SVector<String>(v);
	}

	@Override
	public void setAutoDefaults(final List<String> v)
	{
		autoDefaults = new SVector<String>(v);
	}

	@Override
	public void setDefaults(final List<String> v)
	{
		defaults = new SVector<String>(v);
	}

	@Override
	public void setRateModifier(final double d)
	{
		rateModifier = d;
	}

	@Override
	public boolean isPreLoaded()
	{
		return CMParms.parseSemicolons(CMProps.getVar(CMProps.Str.PREFACTIONS).toUpperCase(),true).contains(factionID().toUpperCase());
	}

	@Override
	public Faction.FAbilityUsage getAbilityUsage(final int x)
	{
		return ((x>=0)&&(x<abilityUsages.size()))
				?(Faction.FAbilityUsage)abilityUsages.get(x)
				:null;
	}

	@Override
	public boolean delFactor(final Faction.FZapFactor f)
	{
		if(!factors.remove(f))
			return false;
		factors.trimToSize();
		return true;
	}

	@Override
	public Faction.FZapFactor getFactor(final int x)
	{
		return ((x >= 0) && (x < factors.size())) ? factors.get(x) : null;
	}

	@Override
	public Faction.FZapFactor addFactor(final double gain, final double loss, final String mask)
	{
		final Faction.FZapFactor o=new DefaultFactionZapFactor(gain,loss,mask);
		factors.add(o);
		factors.trimToSize();
		return o;
	}

	@Override
	public boolean delRelation(final String factionID)
	{
		if(relations.remove(factionID)==null)
			return false;
		return true;
	}

	@Override
	public boolean addRelation(final String factionID, final double relation)
	{
		if(relations.containsKey(factionID))
			return false;
		relations.put(factionID,Double.valueOf(relation));
		return true;
	}

	@Override
	public double getRelation(final String factionID)
	{
		if(relations.containsKey(factionID))
			return relations.get(factionID).doubleValue();
		return 0.0;
	}

	public DefaultFaction()
	{
		super();
	}

	@Override
	public void initializeFaction(final String aname)
	{
		_factionID=aname;
		name=aname;
		upName=aname.toUpperCase();
		minimum=0;
		middle=50;
		maximum=100;
		highest=100;
		lowest=0;
		difference=CMath.abs(maximum-minimum);
		experienceFlag="EXTREME";
		addRange("0;100;Sample Range;SAMPLE;");
		defaults.add("0");
	}

	@Override
	public void initializeFaction(final StringBuffer file, final String fID)
	{
		final boolean debug = false;

		_factionID = fID;
		final CMProps facProps = new CMProps();
		for(final String line : Resources.getFileLineVector(file))
		{
			final String s=line.trim();
			if(s.startsWith("#")||(s.length()==0))
				continue;
			final int x=s.indexOf('=');
			if(x<0)
			{
				Log.errOut("Unknown line '"+s+"' in faction "+fID);
				continue;
			}
			final String key=s.substring(0,x);
			final String val=s.substring(x+1);
			facProps.put(key, val);
		}
		if(facProps.isEmpty())
			return;
		name=facProps.getStr("NAME");
		upName=name.toUpperCase();
		choiceIntro=facProps.getStr("CHOICEINTRO");
		minimum=facProps.getInt("MINIMUM");
		maximum=facProps.getInt("MAXIMUM");
		if(maximum<minimum)
		{
			minimum=maximum;
			maximum=facProps.getInt("MINIMUM");
		}
		recalc();
		experienceFlag=facProps.getStr("EXPERIENCE").toUpperCase().trim();
		if(experienceFlag.length()==0)
			experienceFlag="NONE";
		rateModifier=facProps.getDouble("RATEMODIFIER");
		showInScore=facProps.getBoolean("SCOREDISPLAY");
		showInFacCommand=facProps.getBoolean("SHOWINFACTIONSCMD");
		showInSpecialReport=facProps.getBoolean("SPECIALREPORTED");
		showInEditor=facProps.getBoolean("EDITALONE");
		final String s=facProps.getStr("INHERITED");
		if(s.trim().length()==0)
			isInherited=true;
		else
			isInherited=facProps.getBoolean("INHERITED");
		defaults=new SVector<String>(CMParms.parseSemicolons(facProps.getStr("DEFAULT"),true));
		autoDefaults =new SVector<String>(CMParms.parseSemicolons(facProps.getStr("AUTODEFAULTS"),true));
		choices =new SVector<String>(CMParms.parseSemicolons(facProps.getStr("AUTOCHOICES"),true));
		useLightReactions=facProps.getBoolean("USELIGHTREACTIONS");
		ranges=new SHashtable<String,FRange>();
		changes=new SHashtable<String,FactionChangeEvent[]>();
		factors=new SVector<FZapFactor>();
		relations=new SHashtable<String,Double>();
		abilityUsages=new SVector<FAbilityUsage>();
		abilityUseCache=new STreeMap<String,FAbilityUsage>();
		abilityUseMisses=new STreeSet<String>();
		reactions=new SVector<FReactionItem>();
		reactionHash=new SHashtable<String,CList<FReactionItem>>();
		for(final Enumeration<Object> e=facProps.keys();e.hasMoreElements();)
		{
			if(debug)
				Log.sysOut("FACTIONS","Starting Key Loop");
			final String key = (String) e.nextElement();
			if(debug)
				Log.sysOut("FACTIONS","  Key Found     :"+key);
			final String words = (String) facProps.get(key);
			if(debug)
				Log.sysOut("FACTIONS","  Words Found   :"+words);
			if(key.startsWith("RANGE"))
				addRange(words);
			if(key.startsWith("CHANGE"))
				createChangeEvent(key, words);
			if(key.startsWith("AFFBEHAV"))
			{
				final Object[] O=CMParms.parseSafeSemicolonList(words,false).toArray();
				if(O.length==3)
					addAffectBehav((String)O[0],(String)O[1],(String)O[2]);
			}
			if(key.startsWith("FACTOR"))
			{
				final List<String> factor=CMParms.parseSemicolons(words,false);
				if(factor.size()>2)
					factors.add(new DefaultFactionZapFactor(CMath.s_double(factor.get(0)),
											 CMath.s_double(factor.get(1)),
											 factor.get(2)));
			}
			if(key.startsWith("RELATION"))
			{
				final Vector<String> V=CMParms.parse(words);
				if(V.size()>=2)
				{
					final String who=V.elementAt(0);
					double factor;
					final String amt=V.elementAt(1).trim();
					if(amt.endsWith("%"))
						factor=CMath.s_pct(amt);
					else
						factor=1;
					relations.put(who,Double.valueOf(factor));
				}
			}
			if(key.startsWith("ABILITY"))
				addAbilityUsage(words);
			if(key.startsWith("REACTION"))
			{
				final DefaultFactionReactionItem item = new DefaultFactionReactionItem(words);
				addReaction(item.rangeCodeName(), item.presentMOBMask(), item.reactionObjectID(), item.parameters());
			}
		}
	}

	private void recalc()
	{
		minimum=Integer.MAX_VALUE;
		maximum=Integer.MIN_VALUE;
		int num=0;
		for(final Enumeration<Faction.FRange> e=ranges();e.hasMoreElements();)
		{
			final Faction.FRange FR=e.nextElement();
			if(FR.high()>maximum)
				maximum=FR.high();
			if(FR.low()<minimum)
				minimum=FR.low();
			num++;
		}
		if(minimum==Integer.MAX_VALUE)
			minimum=Integer.MIN_VALUE;
		if(maximum==Integer.MIN_VALUE)
			maximum=Integer.MAX_VALUE;
		if(maximum<minimum)
		{
			final int oldMin=minimum;
			minimum=maximum;
			maximum=oldMin;
		}
		middle=minimum+(int)Math.round(CMath.div(maximum-minimum,2.0));
		difference=CMath.abs(maximum-minimum);
		lastDataChange[0]=System.currentTimeMillis();
		rangeRangeMap=new PrioritizingLimitedMap<Integer,FRange>(num*5,60000,600000,100);
	}

	@Override
	public String getTagValue(final String tag)
	{
		final FacTag tagRef=CMLib.factions().getFactionTag(tag);
		if(tagRef==null)
			return "";
		int numCall=-1;
		if((tagRef.maskPrefix!=null)
		&&(CMath.isInteger(tag.substring(tagRef.maskPrefix.length()))))
			numCall=CMath.s_int(tag.substring(tagRef.maskPrefix.length()));
		switch(tagRef)
		{
		case NAME:
			return name;
		case MINIMUM:
			return "" + minimum;
		case MAXIMUM:
			return "" + maximum;
		case SCOREDISPLAY:
			return Boolean.toString(showInScore).toUpperCase();
		case SHOWINFACTIONSCMD:
			return Boolean.toString(showInFacCommand).toUpperCase();
		case SPECIALREPORTED:
			return Boolean.toString(showInSpecialReport).toUpperCase();
		case EDITALONE:
			return Boolean.toString(showInEditor).toUpperCase();
		case DEFAULT:
			return CMParms.toSemicolonListString(defaults);
		case AUTODEFAULTS:
			return CMParms.toSemicolonListString(autoDefaults);
		case CHOICEINTRO:
			return choiceIntro;
		case AUTOCHOICES:
			return CMParms.toSemicolonListString(choices);
		case RATEMODIFIER:
			return "" + rateModifier;
		case EXPERIENCE:
			return "" + experienceFlag;
		case INHERITABLE:
			return Boolean.toString(isInherited).toUpperCase();
		case RANGE_:
		{
			if((numCall<0)||(numCall>=ranges.size()))
				return ""+ranges.size();
			int x=0;
			for(final Enumeration<Faction.FRange> e=ranges();e.hasMoreElements();)
			{
				final Faction.FRange FR=e.nextElement();
				if(x==numCall)
					return FR.toString();
				x++;
			}
			return "";
		}
		case CHANGE_:
		{
			int sz=0;
			for(final Enumeration<Faction.FactionChangeEvent[]> es=changes.elements();es.hasMoreElements();)
				sz+=es.nextElement().length;
			if((numCall<0)||(numCall>=sz))
				return ""+sz;
			int i=0;
			for(final Enumeration<Faction.FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)
			{
				final Faction.FactionChangeEvent[] FCs=e.nextElement();
				for (final FactionChangeEvent fc : FCs)
				{
					if(i==numCall)
						return fc.toString();
					i++;
				}
			}
			return "";
		}
		case ABILITY_:
		{
			if((numCall<0)||(numCall>=abilityUsages.size()))
				return ""+abilityUsages.size();
			return abilityUsages.get(numCall).toString();
		}
		case FACTOR_:
		{
			if((numCall<0)||(numCall>=factors.size()))
				return ""+factors.size();
			return factors.get(numCall).toString();
		}
		case RELATION_:
		{
			if((numCall<0)||(numCall>=relations.size()))
				return ""+relations.size();
			int i=0;
			for(final Enumeration<String> e=relations.keys();e.hasMoreElements();)
			{
				final String factionName=e.nextElement();
				final Double D=relations.get(factionName);
				if(i==numCall)
					return factionName+" "+CMath.toPct(D.doubleValue());
				i++;
			}
			return "";
		}
		case AFFBEHAV_:
		{
			if((numCall<0)||(numCall>=affBehavs.size()))
				return ""+affBehavs.size();
			int i=0;
			for(final Enumeration<String> e=affBehavs.keys();e.hasMoreElements();)
			{
				final String ID=e.nextElement();
				final String[] data=affBehavs.get(ID);
				if(i==numCall)
					return ID+";"+CMParms.toSafeSemicolonListString(data);
				i++;
			}
			return "";
		}
		case REACTION_:
		{
			if((numCall<0)||(numCall>=reactions.size()))
				return ""+reactions.size();
			final Faction.FReactionItem item = reactions.get(numCall);
			return item.toString();
		}
		case USELIGHTREACTIONS:
			return "" + useLightReactions;
		}
		return "";
	}

	@Override
	public String getINIDef(final String tag, final String delimeter)
	{
		final FacTag tagRef=CMLib.factions().getFactionTag(tag);
		if(tagRef==null)
			return "";
		if(tagRef.maskPrefix!=null)
		{
			final int number=CMath.s_int(getTagValue(tagRef.name()));
			final StringBuffer str=new StringBuffer("");
			for(int i=0;i<number;i++)
			{
				final String value=getTagValue(tagRef.maskPrefix+i);
				str.append(tagRef.maskPrefix+(i+1)+"="+value+delimeter);
			}
			return str.toString();
		}
		return tagRef.name()+"="+getTagValue(tag)+delimeter;
	}

	@Override
	public void updateFactionData(final MOB mob, final FData data)
	{
		data.resetFactionData(this);
		final List<Ability> aV=new ArrayList<Ability>();
		final List<Behavior> bV=new ArrayList<Behavior>();
		String ID=null;
		String[] stuff=null;
		if(mob.isMonster())
		{
			for(final Enumeration<String> e=affectsBehavs();e.hasMoreElements();)
			{
				ID=e.nextElement();
				stuff=getAffectBehav(ID);
				if(CMLib.masking().maskCheck(stuff[1],mob,true))
				{
					final Behavior B=CMClass.getBehavior(ID);
					if(B!=null)
					{
						B.setParms(stuff[0]);
						bV.add(B);
					}
					else
					{
						final Ability A=CMClass.getAbility(ID);
						A.setMiscText(stuff[0]);
						A.setAffectedOne(mob);
						aV.add(A);
					}
				}
			}
		}
		data.addHandlers(aV,bV);
	}

	@Override
	public FData makeFactionData(final MOB mob)
	{
		final FData data=new DefaultFactionData(this);
		updateFactionData(mob,data);
		return data;
	}

	@Override
	public boolean delAffectBehav(final String ID)
	{
		final boolean b=affBehavs.remove(ID.toUpperCase().trim())!=null;
		if(b)
			lastDataChange[0]=System.currentTimeMillis();
		return b;
	}

	@Override
	public boolean addAffectBehav(final String ID, final String parms, final String gainMask)
	{
		if(affBehavs.containsKey(ID.toUpperCase().trim()))
			return false;
		if((CMClass.getBehavior(ID)==null)&&(CMClass.getAbility(ID)==null))
			return false;
		affBehavs.put(ID.toUpperCase().trim(),new String[]{parms,gainMask});
		lastDataChange[0]=System.currentTimeMillis();
		return true;
	}

	@Override
	public String[] getAffectBehav(final String ID)
	{
		if(affBehavs.containsKey(ID.toUpperCase().trim()))
			return CMParms.toStringArray(new XVector<String>(affBehavs.get(ID.toUpperCase().trim())));
		return null;
	}

	@Override
	public boolean delReaction(final Faction.FReactionItem item)
	{
		final CList<Faction.FReactionItem> V=reactionHash.get(item.rangeCodeName().toUpperCase().trim());
		if(V!=null)
			V.remove(item);
		final boolean res = reactions.remove(item);
		if(reactions.size()==0)
			reactionHash.clear();
		lastDataChange[0]=System.currentTimeMillis();
		return res;
	}

	@Override
	public boolean addReaction(final String range, final String mask, final String abilityID, final String parms)
	{
		CList<Faction.FReactionItem> V=reactionHash.get(range.toUpperCase().trim());
		final DefaultFactionReactionItem item = new DefaultFactionReactionItem();
		item.setRangeName(range);
		item.setPresentMOBMask(mask);
		item.setReactionObjectID(abilityID);
		item.setParameters(parms);
		if(V==null)
		{
			V=new SVector<Faction.FReactionItem>();
			reactionHash.put(range.toUpperCase().trim(), V);
		}
		V.add(item);
		reactions.add(item);
		lastDataChange[0]=System.currentTimeMillis();
		return true;
	}

	@Override
	public FactionChangeEvent[] getChangeEvents(final String key)
	{
		return changes.get(key);
	}

	@Override
	public List<Integer> findChoices(final MOB mob)
	{
		final List<Integer> mine=new Vector<Integer>();
		String s;
		for(final Enumeration<String> e=choices.elements();e.hasMoreElements();)
		{
			s=e.nextElement();
			if(CMath.isInteger(s))
				mine.add(Integer.valueOf(CMath.s_int(s)));
			else
			if(CMLib.masking().maskCheck(s, mob,false))
			{
				final List<String> V=CMParms.parse(s);
				for(int j=0;j<V.size();j++)
				{
					if(CMath.isInteger(V.get(j)))
						mine.add(Integer.valueOf(CMath.s_int(V.get(j))));
				}
			}
		}
		return mine;
	}

	protected Map<String,Integer> getCMMsgTypeMap()
	{
		@SuppressWarnings("unchecked")
		Map<String,Integer> msgTypeCache=(Map<String,Integer>)Resources.getResource("SYSTEM_FACTION_GLOBAL_CMMSG_CODES");
		if(msgTypeCache==null)
		{
			msgTypeCache=new HashMap<String,Integer>();
			for(int typ = 0; typ < CMMsg.TYPE_DESCS.length; typ++)
				msgTypeCache.put("MSG_"+CMMsg.TYPE_DESCS[typ],Integer.valueOf(typ));
			Resources.submitResource("SYSTEM_FACTION_GLOBAL_CMMSG_CODES", msgTypeCache);
		}
		return msgTypeCache;
	}

	@Override
	public FactionChangeEvent[] findMsgChangeEvents(final CMMsg msg)
	{
		if(msgChangeCache.size()==0)
		{
			final Map<String,Integer> msgTypeCache=getCMMsgTypeMap();
			final Map<Integer,List<FactionChangeEvent>> msgClassMap=new HashMap<Integer,List<FactionChangeEvent>>();
			for (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)
			{
				final FactionChangeEvent[] Cs=e.nextElement();
				for(final FactionChangeEvent C : Cs)
				{
					if(msgTypeCache.containsKey(C.eventID()))
					{
						final Integer code=msgTypeCache.get(C.eventID());
						if(!msgClassMap.containsKey(code))
							msgClassMap.put(code, new ArrayList<FactionChangeEvent>());
						msgClassMap.get(code).add(C);
					}
				}
			}
			for(final Integer code : msgClassMap.keySet())
			{
				final List<FactionChangeEvent> list=msgClassMap.get(code);
				msgChangeCache.put(code, list.toArray(new FactionChangeEvent[list.size()]));
			}
		}
		return msgChangeCache.get(Integer.valueOf(msg.sourceMinor()));
	}

	@Override
	public FactionChangeEvent[] findAbilityChangeEvents(final Ability key)
	{
		if(key==null)
			return null;
		if(abilChangeCache.size()==0)
		{
			if(CMClass.numPrototypes(CMObjectType.ABILITY)==0)
				return null;
			final Map<Integer,List<FactionChangeEvent>> abilityClassMap=new HashMap<Integer,List<FactionChangeEvent>>();
			for(int classificationCode = 0;classificationCode < Ability.ACODE_DESCS.length;classificationCode++)
			{
				for (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)
				{
					final FactionChangeEvent[] Cs=e.nextElement();
					for(final FactionChangeEvent C : Cs)
					{
						if(classificationCode==C.IDclassFilter())
						{
							if(!abilityClassMap.containsKey(Integer.valueOf(classificationCode)))
								abilityClassMap.put(Integer.valueOf(classificationCode), new ArrayList<FactionChangeEvent>());
							abilityClassMap.get(Integer.valueOf(classificationCode)).add(C);
						}
					}
				}
			}
			final Map<Integer,List<FactionChangeEvent>> abilityDomainMap=new HashMap<Integer,List<FactionChangeEvent>>();
			for(int domainCode = 0;domainCode < Ability.DOMAIN_DESCS.length;domainCode++)
			{
				final int domainID = domainCode << 5;
				for (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)
				{
					final FactionChangeEvent[] Cs=e.nextElement();
					for(final FactionChangeEvent C : Cs)
					{
						if(domainID==C.IDdomainFilter())
						{
							if(!abilityDomainMap.containsKey(Integer.valueOf(domainID)))
								abilityDomainMap.put(Integer.valueOf(domainID), new ArrayList<FactionChangeEvent>());
							abilityDomainMap.get(Integer.valueOf(domainID)).add(C);
						}
					}
				}
			}
			final Map<Long,List<FactionChangeEvent>> abilityFlagMap=new HashMap<Long,List<FactionChangeEvent>>();
			for(int flagIndex = 0;flagIndex < Ability.FLAG_DESCS.length;flagIndex++)
			{
				final long flagMask = Math.round(Math.pow(2, flagIndex));
				for (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)
				{
					final FactionChangeEvent[] Cs=e.nextElement();
					for(final FactionChangeEvent C : Cs)
					{
						if((C.IDflagFilter()>0)&&(CMath.bset(C.IDflagFilter(), flagMask)))
						{
							if(!abilityFlagMap.containsKey(Long.valueOf(flagMask)))
								abilityFlagMap.put(Long.valueOf(flagMask), new ArrayList<FactionChangeEvent>());
							abilityFlagMap.get(Long.valueOf(flagMask)).add(C);
						}
					}
				}
			}
			for(final Enumeration<Ability> a=CMClass.abilities();a.hasMoreElements();)
			{
				final Ability A=a.nextElement();
				final ArrayList<FactionChangeEvent> set=new ArrayList<FactionChangeEvent>(0);
				if(changes.containsKey(A.ID()))
					set.addAll(Arrays.asList(changes.get(A.ID())));
				if(abilityClassMap.containsKey(Integer.valueOf(A.classificationCode()&Ability.ALL_ACODES)))
					set.addAll(abilityClassMap.get(Integer.valueOf(A.classificationCode()&Ability.ALL_ACODES)));
				if(abilityDomainMap.containsKey(Integer.valueOf(A.classificationCode()&Ability.ALL_DOMAINS)))
					set.addAll(abilityDomainMap.get(Integer.valueOf(A.classificationCode()&Ability.ALL_DOMAINS)));
				if(A.flags()>0)
				{
					for(int flagIndex = 0;flagIndex < Ability.FLAG_DESCS.length;flagIndex++)
					{
						final long flagMask = Math.round(Math.pow(2, flagIndex));
						if(CMath.bset(A.flags(), flagMask))
						{
							if(abilityFlagMap.containsKey(Long.valueOf(flagMask)))
								set.addAll(abilityFlagMap.get(Long.valueOf(flagMask)));
						}
					}
				}
				if(set.size()>0)
					abilChangeCache.put(A.ID(), set.toArray(new FactionChangeEvent[0]));
			}
			if(abilChangeCache.size()==0)
				abilChangeCache.put("StdAbility", new FactionChangeEvent[0]);
		}
		return abilChangeCache.get(key.ID());
	}

	@Override
	public FactionChangeEvent[] findSocialChangeEvents(final Social soc)
	{
		if(soc==null)
			return null;
		if(socChangeCache.size()==0)
		{

			final Enumeration<Social> s=CMLib.socials().getAllSocials();
			if(s == null)
				return null;
			for(;s.hasMoreElements();)
			{
				final Social S = s.nextElement();
				if(changes.containsKey(S.name()))
					socChangeCache.put(S.name(), changes.get(S.name()));
				else
				if(changes.containsKey(S.baseName()+" *"))
					socChangeCache.put(S.name(), changes.get(S.baseName()+" *"));
			}
			if(socChangeCache.size()==0)
				socChangeCache.put("DefaultSocial", new FactionChangeEvent[0]);
		}
		return socChangeCache.get(soc.name());
	}

	@Override
	public Faction.FRange fetchRange(final String codeName)
	{
		return ranges.get(codeName.toUpperCase().trim());
	}

	@Override
	public FRange fetchRange(final int faction)
	{
		final Integer I=Integer.valueOf(faction);
		FRange R=rangeRangeMap.get(I);
		if(R!=null)
			return R;
		for (final Enumeration<FRange> e=ranges.elements();e.hasMoreElements();)
		{
			R = e.nextElement();
			if ( (faction >= R.low()) && (faction <= R.high()))
			{
				rangeRangeMap.put(I, R);
				return R;
			}
		}
		return null;
	}

	@Override
	public String fetchRangeName(final int faction)
	{
		final FRange R= fetchRange(faction);
		if(R!=null)
			return R.name();
		return "";
	}

	@Override
	public int asPercent(final int faction)
	{
		return (int)Math.round(CMath.mul(CMath.div(faction-minimum,(maximum-minimum)),100));
	}

	@Override
	public int asPercentFromAvg(final int faction)
	{
		// =(( (B2+A2) / 2 ) - C2) / (B2-A2) * 100
		// C = current, A = min, B = Max
		return (int)Math.round(CMath.mul(CMath.div(((maximum+minimum)/2)-faction,maximum-minimum),100));
	}

	@Override
	public int randomFaction()
	{
		final Random gen = new Random();
		return maximum - gen.nextInt(maximum-minimum);
	}

	@Override
	public int findDefault(final MOB mob)
	{
		String s;
		for(final Enumeration<String> e=defaults.elements();e.hasMoreElements();)
		{
			s=e.nextElement();
			if(CMath.isNumber(s))
				return CMath.s_int(s);
			else
			if(CMLib.masking().maskCheck(s, mob,false))
			{
				final Vector<String> V=CMParms.parse(s);
				for(int j=0;j<V.size();j++)
				{
					if(CMath.isNumber(V.elementAt(j)))
						return CMath.s_int(V.elementAt(j));
				}
			}
		}
		return 0;
	}

	@Override
	public int findAutoDefault(final MOB mob)
	{
		String s;
		for(final Enumeration<String> e=autoDefaults.elements();e.hasMoreElements();)
		{
			s=e.nextElement();
			if(CMath.isNumber(s))
				return CMath.s_int(s);
			else
			if(CMLib.masking().maskCheck(s, mob,false))
			{
				final Vector<String> V=CMParms.parse(s);
				for(int j=0;j<V.size();j++)
				{
					if(CMath.isNumber(V.elementAt(j)))
						return CMath.s_int(V.elementAt(j));
				}
			}
		}
		return Integer.MAX_VALUE;
	}

	@Override
	public boolean hasFaction(final MOB mob)
	{
		return (mob.fetchFaction(_factionID)!=Integer.MAX_VALUE);
	}

	protected FAbilityUsage getAbilityUsage(final Ability A)
	{
		if(A==null)
			return null;
		if(abilityUseCache.containsKey(A.ID()))
			return abilityUseCache.get(A.ID());
		if(abilityUseMisses.contains(A.ID()))
			return null;

		for(final FAbilityUsage usage : abilityUsages)
		{
			if(usage.possibleAbilityID()
			&&(!usage.abilityFlags().equalsIgnoreCase(A.ID())))
				continue;

			if(usage.possibleAbilityID()
			||(((usage.type()<0)||((A.classificationCode()&Ability.ALL_ACODES)==usage.type()))
				&&((usage.flag()<0)||(CMath.bset(A.flags(),usage.flag())))
				&&((usage.notflag()<0)||(!CMath.bset(A.flags(),usage.notflag())))
				&&((usage.domain()<0)||((A.classificationCode()&Ability.ALL_DOMAINS)==usage.domain()))))
			{
				abilityUseCache.put(A.ID(), usage);
				return usage;
			}
		}
		abilityUseMisses.add(A.ID());
		return null;
	}

	@Override
	public boolean hasUsage(final Ability A)
	{
		return getAbilityUsage(A) != null;
	}

	@Override
	public boolean canUse(final MOB mob, final Ability A)
	{
		final FAbilityUsage usage = this.getAbilityUsage(A);
		if(usage == null)
			return true;
		final int faction=mob.fetchFaction(_factionID);
		if((faction < usage.low()) || (faction > usage.high()))
			return false;
		return true;
	}

	@Override
	public double findFactor(final MOB mob, final boolean gain)
	{
		for(final Faction.FZapFactor factor : factors)
		{
			if(CMLib.masking().maskCheck(factor.compiledMOBMask(),mob,false))
				return gain?factor.gainFactor():factor.lossFactor();
		}
		return 1.0;
	}

	private boolean checkApplyEventWait(final FactionChangeEvent event, final MOB mob)
	{
		final Faction.FData data = mob.fetchFactionData(factionID());
		if(data != null)
		{
			if(System.currentTimeMillis() < data.getNextChangeTimers(event))
				return false;
			final long newTime=event.getWaitBetweenMs();
			if(newTime > 0)
				data.setNextChangeTimers(event, System.currentTimeMillis()+newTime);
		}
		return true;
	}

	@Override
	public void executeMsg(final Environmental myHost, final CMMsg msg)
	{
		FactionChangeEvent[] events;
		switch(msg.sourceMinor())
		{
		case CMMsg.TYP_ENTER:
		{
			if((msg.source() == myHost)
			&&(msg.source().isPlayer())
			&&(msg.target() instanceof Room))
			{
				events=getChangeEvents(MiscTrigger.AREAEXPLORE.toString());
				if(events != null)
				{
					final Room R=(Room)msg.target();
					if(!msg.source().playerStats().hasVisited(R))
					{
						final Area A=R.getArea();
						for (final FactionChangeEvent event : events)
						{
							if(event.applies(msg.source(),msg.source()))
							{
								final int pct = CMath.s_int(event.getTriggerParm("PCT"));
								if(pct==0)
								{
									if(msg.source().playerStats().totalVisitedRooms(msg.source(), A)>0)
										continue;
								}
								else
								{
									if(msg.source().playerStats().percentVisited(msg.source(),A) < pct)
										continue;
								}
								if(this.checkApplyEventWait(event, msg.source()))
									executeChange(msg.source(),msg.source(),event);
							}
						}
					}
				}
			}
			break;
		}
		case CMMsg.TYP_DEATH:
			if((msg.source()==myHost)||(msg.tool()==myHost))
			{
				final MOB killedM=msg.source();
				if(msg.tool() instanceof MOB)
				{
					final MOB killingBlowM=(MOB)msg.tool();
					events=getChangeEvents(((msg.source()==myHost)?MiscTrigger.MURDER:MiscTrigger.KILL).toString());
					if(events!=null)
					{
						for (final FactionChangeEvent event : events)
						{
							if(event.applies(killingBlowM,killedM))
							{
								final CharClass combatCharClass=CMLib.combat().getCombatDominantClass(killingBlowM,killedM);
								final Set<MOB> combatBeneficiaries=CMLib.combat().getCombatBeneficiaries(killingBlowM,killedM,combatCharClass);
								for (final MOB mob : combatBeneficiaries)
								{
									if(checkApplyEventWait(event, mob))
										executeChange(mob,killedM,event);
								}
							}
						}
					}
					final Room R = msg.source().location();
					if((R!=null)&&(R.getArea()!=null))
					{
						events=getChangeEvents(MiscTrigger.AREAASS.toString());
						if((events!=null)
						&&(killedM!=null)
						&&(killedM.phyStats().level()==R.getArea().getAreaIStats()[Area.Stats.MAX_LEVEL.ordinal()])
						&&(killingBlowM!=killedM)
						&&(killedM.isMonster())
						&&(killedM.getStartRoom()!=null)
						&&(killedM.location()!=null)
						&&(killedM.getStartRoom().getArea()==killingBlowM.location().getArea()))
						{
							final Area A=R.getArea();
							for (final FactionChangeEvent event : events)
							{
								final CharClass combatCharClass=CMLib.combat().getCombatDominantClass(killingBlowM,killedM);
								final Set<MOB> combatBeneficiaries=CMLib.combat().getCombatBeneficiaries(killingBlowM,killedM,combatCharClass);
								final int pct = CMath.s_int(event.getTriggerParm("PCT"));
								for (final MOB mob : combatBeneficiaries)
								{
									if(mob.isPlayer())
									{
										if(event.applies(mob,killedM))
										{
											final double population = A.getAreaIStats()[Area.Stats.MAX_LEVEL_MOBS.ordinal()];
											final Faction.FData data = mob.fetchFactionData(factionID());
											final int count = data.getCounter(""+event)+1;
											data.setCounter(""+event, count);
											final int myPct = (int)Math.round(100.0*CMath.div(count, population));
											if(myPct < pct)
												continue;
											if(checkApplyEventWait(event, mob))
												executeChange(mob,killedM,event);
										}
									}
								}
							}
						}
						events=getChangeEvents(MiscTrigger.AREAKILL.toString());
						if((events!=null)
						&&(killedM!=null)
						&&(killingBlowM!=killedM)
						&&(killedM.isMonster())
						&&(killedM.getStartRoom()!=null)
						&&(killedM.location()!=null)
						&&(killedM.getStartRoom().getArea()==killedM.location().getArea()))
						{
							final Area A=R.getArea();
							for (final FactionChangeEvent event : events)
							{
								final int pct = CMath.s_int(event.getTriggerParm("PCT"));
								final CharClass combatCharClass=CMLib.combat().getCombatDominantClass(killingBlowM,killedM);
			{
				if((msg.target()==myHost)	// Arrested watching
				&&(msg.source().isMonster())
				&&(msg.tool().ID().equals("Skill_HandCuff")))
				{
					final Room R=msg.source().location();
					if((R!=null)&&(R.getArea()!=null))
											final double population = A.getAreaIStats()[Area.Stats.POPULATION.ordinal()];
											final int count = data.getCounter(""+event)+1;
											data.setCounter(""+event, count);
											final int myPct = (int)Math.round(100.0*CMath.div(count, population));
											if(myPct < pct)
												continue;
											if(checkApplyEventWait(event, mob))
												executeChange(mob,killedM,event);
										}
									}
								}
							}
						}
					}
				}
				if(msg.source()==myHost)
				{
					events=getChangeEvents(MiscTrigger.DYING.toString());
					if(events!=null)
					{
						for (final FactionChangeEvent event : events)
						{
							if(event.applies(killedM,killedM))
							{
								if(checkApplyEventWait(event, killedM))
									executeChange(killedM,killedM,event);
							}
						}
					}
				}
			}
			break;
		case CMMsg.TYP_CAUSESINK:
			if((myHost instanceof MOB)
			&&(msg.target() instanceof Boardable))
			{
				final MOB killerM=msg.source();
				final Area shipArea=((Boardable)msg.target()).getArea();
				if(CMLib.map().areaLocation(killerM)==shipArea)
					events=getChangeEvents(MiscTrigger.SUNK.toString());
				else
				if(killerM == myHost)
					events=getChangeEvents(MiscTrigger.SINK.toString());
				else
					events=null;
				if(events!=null)
				{
					final MOB targetM=(killerM==myHost)?null:(MOB)myHost;
					for (final FactionChangeEvent event : events)
					{
						if(event.applies(killerM, targetM))
							executeChange(killerM,targetM,event);
					}
				}
			}
			break;
		case CMMsg.TYP_GIVE:
			if((msg.source()==myHost)
			&&(msg.tool() instanceof Coins)
			&&(msg.target() instanceof MOB)
			&&(!(msg.target() instanceof ShopKeeper))
			)
			{
				events=getChangeEvents(MiscTrigger.BRIBE.toString());
				if(events!=null)
				{
					for (final FactionChangeEvent event : events)
					{
						if(event.applies(msg.source(),(MOB)msg.target()))
						{
							double amount=CMath.s_double(event.getTriggerParm("AMOUNT"));
							final double pctAmount = CMath.s_pct(event.getTriggerParm("PCT"))
											 * CMLib.beanCounter().getTotalAbsoluteNativeValue((MOB)msg.target());
							if(pctAmount>amount)
								amount=pctAmount;
							if(amount==0)
								amount=1.0;
							if(((Coins)msg.tool()).getTotalValue()>=amount)
								executeChange(msg.source(),(MOB)msg.target(),event);
						}
					}
				}
			}
			break;
		case CMMsg.TYP_TEACH:
		case CMMsg.TYP_CHANNEL:
			// don't do the defaults!
			break;
		case CMMsg.TYP_SPEAK:
			if((msg.othersMessage()!=null)
			&&(msg.source()==myHost))
			{
				events=getChangeEvents(MiscTrigger.TALK.toString());
				if((events!=null)&&(events.length>0))
				{
					final Room R=msg.source().location();
					final List<MOB> targets=new ArrayList<MOB>();
					if(msg.target() instanceof MOB)
						targets.add((MOB)msg.target());
					else
					for(int m=0;m<R.numInhabitants();m++)
					{
						final MOB M=R.fetchInhabitant(m);
						if((M!=null)&&(M.isMonster())
						&&(CMLib.flags().canBeHeardSpeakingBy(msg.source(),M))
						&&(M.amFollowing()!=msg.source()))
							targets.add(M);
					}
					final String sayMsg=CMStrings.getSayFromMessage(msg.othersMessage().toLowerCase());
					Matcher M=null;
					if((sayMsg!=null)&&(sayMsg.length()>0)&&(R!=null))
					{
						final MOB mob=msg.source();
						final Faction.FData data = mob.fetchFactionData(factionID());
						for (final FactionChangeEvent event : events)
						{
							Pattern P=(Pattern)event.stateVariable(0);
							if(P==null)
							{
								String mask=event.getTriggerParm("REGEX");
								if((mask==null)||(mask.trim().length()==0))
									mask=".*";
								P=Pattern.compile(mask.toLowerCase());
								event.setStateVariable(0,P);
							}
							M=P.matcher(sayMsg);
							if(M.matches())
							{
								if((data != null) && (System.currentTimeMillis() < data.getNextChangeTimers(event)))
									continue;
								boolean foundOne=false;
								for(final MOB target : targets)
								{
									if(event.applies(mob,target))
									{
										executeChange(mob,target,event);
										foundOne=true;
										break;
									}
								}
								if(foundOne)
									checkApplyEventWait(event, mob);
							}
						}
					}
				}
				events=getChangeEvents(MiscTrigger.MUDCHAT.toString());
				if((events!=null)&&(events.length>0))
				{
					final Room R=msg.source().location();
					final List<MOB> targets=new ArrayList<MOB>();
					if(msg.target() instanceof MOB)
						targets.add((MOB)msg.target());
					else
					for(int m=0;m<R.numInhabitants();m++)
					{
						final MOB M=R.fetchInhabitant(m);
						if((M!=null)&&(M.isMonster())
						&&(CMLib.flags().canBeHeardSpeakingBy(msg.source(),M))
						&&(M.amFollowing()!=msg.source()))
							targets.add(M);
					}
					boolean foundOne=false;
					for(final MOB target : targets)
					{
						ChattyBehavior mudChatB=null;
						Behavior B=null;
						for(final Enumeration<Behavior> e=target.behaviors();e.hasMoreElements();)
						{
							B=e.nextElement();
							if(B instanceof ChattyBehavior)
								mudChatB=(ChattyBehavior)B;
						}
						if(mudChatB!=null)
						{
							final String sayMsg=CMStrings.getSayFromMessage(msg.othersMessage().toLowerCase());
							if((sayMsg!=null)&&(sayMsg.length()>0))
							{
								final MOB mob=msg.source();
								for (final FactionChangeEvent event : events)
								{
									if(event.applies(mob,target))
									{
										if((mudChatB.getLastRespondedTo()==mob)
										&&(mudChatB.getLastThingSaid()!=null)
										&&(!mudChatB.getLastThingSaid().equalsIgnoreCase(sayMsg)))
										{
											if(checkApplyEventWait(event, mob))
											{
												executeChange(mob,target,event);
												foundOne=true;
											}
										}
									}
								}
							}
							if(foundOne)
								break;
						}
					}
				}
			}
			break;
		default:
			if((events=findMsgChangeEvents(msg))!=null)
			{
				final EnglishParsing elib=CMLib.english();
				for (final FactionChangeEvent C : events)
				{
					final MOB target;
					if((msg.target() instanceof MOB)
					&&(C.applies(msg.source(),(MOB)msg.target())))
						target=(MOB)msg.target();
					else
					if((!(msg.target() instanceof MOB))
					&&(C.applies(msg.source(), null)))
						target=null;
					else
						continue;
					String s;
					s=C.getTriggerParm("SMSG");
					if((s.length()>0)&&((msg.sourceMessage()==null)||(!elib.containsString(msg.sourceMessage(), s))))
						continue;
					s=C.getTriggerParm("TMSG");
					if((s.length()>0)&&((msg.targetMessage()==null)||(!elib.containsString(msg.targetMessage(), s))))
						continue;
					s=C.getTriggerParm("OMSG");
					if((s.length()>0)&&((msg.othersMessage()==null)||(!elib.containsString(msg.othersMessage(), s))))
						continue;
					s=C.getTriggerParm("SRC");
					if(s.length()>0)
					{
						if(s.equalsIgnoreCase("me") && (msg.source()!=myHost))
							continue;
						if(!elib.containsString(msg.source().Name(), s))
							continue;
					}
					s=C.getTriggerParm("TGT");
					if(s.length()>0)
					{
						if(s.equalsIgnoreCase("me") && (msg.target()!=myHost))
							continue;
						if((msg.target()==null)||(!elib.containsString(msg.target().Name(), s)))
							continue;
					}
					s=C.getTriggerParm("OTH");
					if(s.length()>0)
					{
						if(s.equalsIgnoreCase("me") && (msg.tool()!=myHost))
							continue;
						if((msg.tool()==null)||(!elib.containsString(msg.tool().Name(), s)))
							continue;
					}
					if(checkApplyEventWait(C, msg.source()))
						executeChange(msg.source(),target,C);
				}
			}
			if(msg.tool() instanceof Ability)
			{
				if((msg.target()==myHost)	// Arrested watching
				&&(msg.source().isMonster())
				&&(msg.tool().ID().equals("Skill_HandCuff"))
				&&(msg.sourceMinor()!=CMMsg.TYP_TEACH))
				{
					final Room R=msg.source().location();
					if((R!=null)&&(R.getArea()!=null))
					{
						events=getChangeEvents(MiscTrigger.ARRESTED.toString());
						if(events!=null)
						{
							final LegalBehavior B=CMLib.law().getLegalBehavior(R);
							if((B!=null)&&(B.isAnyOfficer(R.getArea(), msg.source())))
							{
								for (final FactionChangeEvent event : events)
								{
									// reversed because the target is the one getting factioned
									if(event.applies(msg.source(),(MOB)msg.target()))
										executeChange((MOB)msg.target(),msg.source(),event);
								}
							}
						}
					}
				}
				if((msg.othersMessage()!=null)
				&&(msg.source()==myHost)
				&&((events=findAbilityChangeEvents((Ability)msg.tool()))!=null))
				{
					for (final FactionChangeEvent C : events)
					{
						final MOB target;
						if((msg.target() instanceof MOB)&&(C.applies(msg.source(),(MOB)msg.target())))
							target=(MOB)msg.target();
						else
						if (!(msg.target() instanceof MOB))
							target=null;
						else
							continue;
						if(checkApplyEventWait(C, msg.source()))
							executeChange(msg.source(),target,C);
					}
				}
			}
			else
			if((msg.tool() instanceof Social)		// socials
			&&(msg.source()==myHost)
			&&(msg.target() instanceof MOB)
			&&(((Social)msg.tool()).targetable(msg.source()))
			&&(msg.sourceMinor()!=CMMsg.TYP_CHANNEL))
			{
				events=getChangeEvents(MiscTrigger.SOCIAL.toString());
				if(events == null)
					events=findSocialChangeEvents((Social)msg.tool());
				if(events!=null)
				{
					final Social social = (Social)msg.tool();
					final String socialName = social.baseName();
					final MOB mob=msg.source();
					for (final FactionChangeEvent event : events)
					{
						if(event.miscEvent()==MiscTrigger.SOCIAL)
						{
							final String triggerID=event.getTriggerParm("ID");
							if(triggerID.length()==0)
								continue;
							if(!socialName.equals(triggerID)
							&&(!triggerID.equalsIgnoreCase("ALL")))
								continue;
						}
						if((event.applies(mob,(MOB)msg.target())))
						{
							if(checkApplyEventWait(event, mob))
								executeChange(mob,(MOB)msg.target(),event);
						}
					}
				}
			}
			break;
		}
	}

	@Override
	public boolean okMessage(final Environmental myHost, final CMMsg msg)
	{
		if(((msg.sourceMinor()==CMMsg.TYP_EXPCHANGE)  // Experience is being altered
			||(msg.sourceMinor()==CMMsg.TYP_RPXPCHANGE))
		&&(msg.target() instanceof MOB) 		  // because a mob died
		&&(myHost==msg.source())	  // this Faction is on the mob that killed them
		&&(!experienceFlag.equals("NONE"))
		&&(msg.value()>0))
		{
			final MOB killer=msg.source();
			final MOB vic=(MOB)msg.target();

			if(experienceFlag.equals("HIGHER"))
				msg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(killer.fetchFaction(_factionID)-minimum),(maximum - minimum)))));
			else
			if(experienceFlag.equals("LOWER"))
				msg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(maximum-killer.fetchFaction(_factionID)),(maximum - minimum)))));
			else
			if(vic.fetchFaction(_factionID)!=Integer.MAX_VALUE)
			{
				if(experienceFlag.equals("EXTREME"))
					msg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(vic.fetchFaction(_factionID) - killer.fetchFaction(_factionID)),(maximum - minimum)))));
				else
				if(experienceFlag.equals("FOLLOWHIGHER"))
					msg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(vic.fetchFaction(_factionID)-minimum),(maximum - minimum)))));
				else
				if(experienceFlag.equals("FOLLOWLOWER"))
					msg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(maximum-vic.fetchFaction(_factionID)),(maximum - minimum)))));
				if(msg.value()<=0)
					msg.setValue(0);
			}
		}
		return true;
	}

	@Override
	public void executeChange(final MOB source, MOB target, final FactionChangeEvent event)
	{
		final int sourceFaction= source.fetchFaction(_factionID);
		int targetFaction = sourceFaction * -1;
		if((source==target)
		&&(!event.selfTargetOK())
		&&(event.miscEvent() != MiscTrigger.TIME))
			return;

		if(target!=null)
		{
			if(hasFaction(target))
				targetFaction=target.fetchFaction(_factionID);
			else
			if(!event.outsiderTargetOK())
				return;
		}
		else
			target = source;

		if((event.getPctChance()<100)
		&&(event.getPctChance()>0)
		&& (CMLib.dice().rollPercentage()<event.getPctChance()))
			return;

		double baseChangeAmount=100.0;
		if((source!=target)
		&&(!event.just100()))
		{
			final int levelLimit=CMProps.getIntVar(CMProps.Int.EXPRATE);
			final int levelDiff=target.phyStats().level()-source.phyStats().level();

			if(levelDiff<(-levelLimit) )
				baseChangeAmount=0.0;
			else
			if(levelLimit>0)
			{
				double levelFactor=CMath.div(levelDiff,levelLimit);
				if(levelFactor> (levelLimit))
					levelFactor=(levelLimit);
				baseChangeAmount=baseChangeAmount+CMath.mul(levelFactor,100);
			}
		}
		if(event.getBonusXP()!=0)
			CMLib.leveler().postExperience(source, target, "", event.getBonusXP(), false);
		if(event.getBonusRoleplayXP()!=0)
			CMLib.leveler().postRPExperience(source, target, "", event.getBonusRoleplayXP(), true);

		final String resetTimerEventID = event.getFlagValue("RESTIME");
		if(resetTimerEventID.length()>0)
		{
			for(String resEventID : CMParms.parseCommas(resetTimerEventID, true))
			{
				final Integer which;
				final int x=resEventID.indexOf('.');
				if(x>0)
				{
					which=Integer.valueOf(CMath.s_int(resEventID.substring(x+1)));
					resEventID=resEventID.substring(0,x);
				}
				else
					which=null;
				final boolean reset;
				Faction.FactionChangeEvent[] events;
				if(resetTimerEventID.startsWith("-"))
				{
					reset=false;
					events = getChangeEvents(resEventID.substring(1));
				}
				else
				{
					events = getChangeEvents(resEventID);
					reset=true;
				}
				if(events != null)
				{
					if((which != null)
					&&(events.length>=which.intValue())
					&&(which.intValue()>0))
						events=new Faction.FactionChangeEvent[] { events[which.intValue()-1] };
					final Faction.FData sdata = source.fetchFactionData(factionID());
					final Faction.FData tdata = target.fetchFactionData(factionID());
					for(final Faction.FactionChangeEvent event2 : events)
					{
						if(sdata != null)
						{
							if(reset)
								sdata.resetEventTimers(event2.eventID());
							else
								sdata.setNextChangeTimers(event2, Long.MAX_VALUE);
						}
						if(tdata != null)
						{
							if(reset)
								tdata.resetEventTimers(event2.eventID());
							else
								tdata.setNextChangeTimers(event2, Long.MAX_VALUE);
						}
					}
				}
			}
		}

		int factionAdj=1;
		int changeDir=0;
		switch(event.direction())
		{
		case FactionChangeEvent.CHANGE_DIRECTION_MAXIMUM:
			factionAdj=maximum-sourceFaction;
			break;
		case FactionChangeEvent.CHANGE_DIRECTION_MINIMUM:
			factionAdj=minimum-sourceFaction;
			break;
		case FactionChangeEvent.CHANGE_DIRECTION_UP:
			changeDir=1;
			break;
		case FactionChangeEvent.CHANGE_DIRECTION_DOWN:
			changeDir=-1;
			break;
		case FactionChangeEvent.CHANGE_DIRECTION_OPPOSITE:
			if(source!=target)
			{
				if(targetFaction==middle)
					changeDir=(sourceFaction>middle)?1:-1;
				else
					changeDir=(targetFaction>middle)?-1:1;
				if((sourceFaction>middle)&&(targetFaction>middle))
					changeDir=-1;
				baseChangeAmount=CMath.div(baseChangeAmount,2.0)
								+(int)Math.round(CMath.div(baseChangeAmount,2.0)
										*Math.abs((sourceFaction-targetFaction)
												/Math.abs((double)difference)));
			}
			else
				factionAdj=0;
			break;
		case FactionChangeEvent.CHANGE_DIRECTION_AWAY:
			if(source!=target)
				changeDir=targetFaction>=sourceFaction?-1:1;
			else
				factionAdj=0;
			break;
		case FactionChangeEvent.CHANGE_DIRECTION_TOWARD:
			if(source!=target)
				changeDir=targetFaction>=sourceFaction?1:-1;
			else
				factionAdj=0;
			break;
		case FactionChangeEvent.CHANGE_DIRECTION_REMOVE:
			factionAdj=Integer.MAX_VALUE;
			break;
		case FactionChangeEvent.CHANGE_DIRECTION_ADD:
			factionAdj=findDefault(source);
			if(!hasFaction(source))
				source.addFaction(_factionID,0);
			else
				factionAdj=0;
			break;
		}
		if(changeDir!=0)
		{
			//int baseExp=(int)Math.round(theAmount);

			// Pardon the completely random seeming 1.42 and 150.
			// They're the result of making graphs of scenarios and massaging the formula, nothing more or less.
			if((hasFaction(target))||(event.outsiderTargetOK()))
				factionAdj=changeDir*(int)Math.round(rateModifier*baseChangeAmount);
			else
				factionAdj=0;
			factionAdj*=event.factor();
			factionAdj=(int)Math.round(CMath.mul(factionAdj,findFactor(source,(factionAdj>=0))));
		}

		if((factionAdj==0)&&(event.factor()!=0.0))
			return;

		final String announceMsg = event.getFlagValue("ANNOUNCE");
		final String seenMsg = announceMsg.length()>0 ? announceMsg : null;
		if(seenMsg != null)
		{
			final List<String> channels=CMLib.channels().getFlaggedChannelNames(ChannelsLibrary.ChannelFlag.FACTIONANNOUNCEMENTS, source);
			if(channels.size()>0)
			{
				final String msgStr = source.Name()+" ("+name()+"): "+seenMsg;
				for(int i=0;i<channels.size();i++)
					CMLib.commands().postChannel(channels.get(i),source.clans(),msgStr,true);
			}
		}
		CMMsg facMsg=CMClass.getMsg(source,target,null,CMMsg.MASK_ALWAYS|CMMsg.TYP_FACTIONCHANGE,seenMsg,CMMsg.NO_EFFECT,null,CMMsg.NO_EFFECT,_factionID);
		facMsg.setValue(factionAdj);
		final Room R=source.location();
		if(R!=null)
		{
			if(R.okMessage(source,facMsg))
			{
				R.send(source, facMsg);
				factionAdj=facMsg.value();
				if((factionAdj!=Integer.MAX_VALUE)&&(factionAdj!=Integer.MIN_VALUE))
				{
					// Now execute the changes on the relation.  We do this AFTER the execution of the first so
					// that any changes from okMessage are incorporated
					if(relations.size()>0)
					{
						for(final Enumeration<String> e=relations.keys();e.hasMoreElements();)
						{
							final String relID=(e.nextElement());
							facMsg=CMClass.getMsg(source,target,null,CMMsg.MASK_ALWAYS|CMMsg.TYP_FACTIONCHANGE,null,CMMsg.NO_EFFECT,null,CMMsg.NO_EFFECT,relID);
							facMsg.setValue((int)Math.round(CMath.mul(factionAdj, relations.get(relID).doubleValue())));
							if(R.okMessage(source,facMsg))
								R.send(source, facMsg);
						}
					}
				}
			}
		}
		else
		if((factionAdj==Integer.MAX_VALUE)||(factionAdj==Integer.MIN_VALUE))
			source.removeFaction(_factionID);
		else
			source.adjustFaction(_factionID,factionAdj);
	}

	@Override
	public String usageFactorRangeDescription(final Ability A)
	{
		final StringBuffer rangeStr=new StringBuffer();
		final HashSet<String> namesAdded=new HashSet<String>();
		final FAbilityUsage usage = getAbilityUsage(A);
		if(usage != null)
		{
			for(final Enumeration<FRange> e=ranges();e.hasMoreElements();)
			{
				final FRange R=e.nextElement();
				if((((R.high()<=usage.high())&&(R.high()>=usage.low()))
					||((R.low()>=usage.low()))&&(R.low()<=usage.high()))
				&&(!namesAdded.contains(R.name())))
				{
					namesAdded.add(R.name());
					if(rangeStr.length()>0)
						rangeStr.append(", ");
					rangeStr.append(R.name());
				}
			}
		}
		return rangeStr.toString();
	}

	private static String _ALL_TYPES=null;

	@Override
	public String ALL_CHANGE_EVENT_TYPES()
	{
		final StringBuffer ALL_TYPES=new StringBuffer("");
		if(_ALL_TYPES!=null)
			return _ALL_TYPES;
		for (final MiscTrigger element : Faction.FactionChangeEvent.MiscTrigger.values())
			ALL_TYPES.append(element.name()+", ");
		for (final String element : Ability.ACODE_DESCS)
			ALL_TYPES.append(element+", ");
		for (final String element : Ability.DOMAIN_DESCS)
			ALL_TYPES.append(element+", ");
		for (final String element : Ability.FLAG_DESCS)
			ALL_TYPES.append(element+", ");
		final Set<String> doneSoc=new HashSet<String>();
		for(final Enumeration<Social> s = CMLib.socials().getAllSocials();s.hasMoreElements();)
		{
			final Social S=s.nextElement();
			ALL_TYPES.append(S.name()).append(", ");
			if(!doneSoc.contains(S.baseName()))
			{
				doneSoc.add(S.baseName());
				ALL_TYPES.append(S.baseName()+" *, ");
			}
		}
		_ALL_TYPES=ALL_TYPES.toString()+" a valid Skill, Spell, Chant, etc. ID.";
		return _ALL_TYPES;
	}

	@Override
	public Faction.FactionChangeEvent createChangeEvent(final String eventKey, final String eventData)
	{
		Faction.FactionChangeEvent event;
		if(eventData==null)
			return null;
		if(eventData.indexOf(';')<0)
		{
			event=new DefaultFaction.DefaultFactionChangeEvent(this);
			if(!event.setEventID(eventData))
				return null;
		}
		else
			event=new DefaultFaction.DefaultFactionChangeEvent(this,eventKey,eventData);
		abilChangeCache.clear();
		socChangeCache.clear();
		msgChangeCache.clear();
		Faction.FactionChangeEvent[] events=changes.get(event.eventID().toUpperCase().trim());
		if(events==null)
			events=new Faction.FactionChangeEvent[0];
		events=Arrays.copyOf(events, events.length+1);
		events[events.length-1]=event;
		changes.put(event.eventID().toUpperCase().trim(), events);
		return event;
	}

	private boolean replaceEvents(final String key, final Faction.FactionChangeEvent event, final boolean strict)
	{
		final Faction.FactionChangeEvent[] events=changes.get(key);
		if(events==null)
			return false;
		final Faction.FactionChangeEvent[] nevents=new Faction.FactionChangeEvent[events.length-1];
		int ne1=0;
		boolean done=false;
		for (final FactionChangeEvent event2 : events)
		{
			if((strict&&(event2 == event))||((!strict)&&(event2.toString().equals(event.toString()))))
			{
				if(nevents.length==0)
					changes.remove(key);
				else
					changes.put(key,nevents);
				done=true;
			}
			else
			if(ne1<nevents.length)
				nevents[ne1++]=event2;
		}
		if(done)
		{
			abilChangeCache.clear();
			msgChangeCache.clear();
			socChangeCache.clear();
		}
		return done;
	}

	@Override
	public void clearChangeEvents()
	{
		abilChangeCache.clear();
		socChangeCache.clear();
		changes.clear();
		msgChangeCache.clear();
	}

	@Override
	public boolean delChangeEvent(final Faction.FactionChangeEvent event)
	{
		for(final Enumeration<String> e=changes.keys();e.hasMoreElements();)
		{
			if(replaceEvents(e.nextElement(),event,true))
			{
				abilChangeCache.clear();
				socChangeCache.clear();
				msgChangeCache.clear();
				msgChangeCache.clear();
				return true;
			}
		}
		for(final Enumeration<String> e=changes.keys();e.hasMoreElements();)
		{
			if(replaceEvents(e.nextElement(),event,false))
			{
				abilChangeCache.clear();
				socChangeCache.clear();
				msgChangeCache.clear();
				msgChangeCache.clear();
				return true;
			}
		}
		return false;
	}

	public class DefaultFactionChangeEvent implements Faction.FactionChangeEvent
	{
		private String		eventTriggerID	= "";
		private MiscTrigger miscEventTrigger= null;
		private String		flagCache		= "";
		private int			IDclassFilter	= -1;
		private long		IDflagFilter	= -1;
		private int			IDdomainFilter	= -1;
		private int			direction		= 0;
		private double		factor			= 0.0;
		private String		targetZapperStr	= "";
		private boolean		outsiderTargetOK= false;
		private boolean		selfTargetOK	= false;
		private boolean		just100			= false;
		private int			bonusXP			= 0;
		private int			bonusRPXP		= 0;
		private Object[]	stateVariables	= new Object[0];
		private String		triggerParms	= "";
		private int			withinTicks		= -1;
		private long		waitMs			= -1;
		private int			pctChance		= 100;

		private final Faction	myFaction;

		private Map<String, String>				flags					= new Hashtable<String, String>();
		private Map<String, String>				savedTriggerParms		= new Hashtable<String, String>();
		private MaskingLibrary.CompiledZMask	compiledTargetZapper	= null;
		private MaskingLibrary.CompiledZMask	compiledSourceZapper	= null;

		@Override
		public String eventID()
		{
			return eventTriggerID;
		}

		@Override
		public MiscTrigger miscEvent()
		{
			return miscEventTrigger;
		}

		@Override
		public String flagCache()
		{
			return flagCache;
		}

		@Override
		public int IDclassFilter()
		{
			return IDclassFilter;
		}

		@Override
		public long IDflagFilter()
		{
			return IDflagFilter;
		}

		@Override
		public int IDdomainFilter()
		{
			return IDdomainFilter;
		}

		@Override
		public int direction()
		{
			return direction;
		}

		@Override
		public double factor()
		{
			return factor;
		}

		@Override
		public int getBonusXP()
		{
			return bonusXP;
		}

		@Override
		public int getWithinTicks()
		{
			return withinTicks;
		}

		@Override
		public long getWaitBetweenMs()
		{
			return this.waitMs;
		}

		@Override
		public int getPctChance()
		{
			return pctChance;
		}

		@Override
		public int getBonusRoleplayXP()
		{
			return bonusRPXP;
		}

		@Override
		public String targetZapper()
		{
			return targetZapperStr;
		}

		@Override
		public boolean outsiderTargetOK()
		{
			return outsiderTargetOK;
		}

		@Override
		public boolean selfTargetOK()
		{
			return selfTargetOK;
		}

		@Override
		public boolean just100()
		{
			return just100;
		}

		@Override
		public void setDirection(final int newVal)
		{
			direction = newVal;
		}

		@Override
		public void setFactor(final double newVal)
		{
			factor = newVal;
		}

		@Override
		public void setTargetZapper(final String newVal)
		{
			targetZapperStr = newVal;
		}

		@Override
		public MaskingLibrary.CompiledZMask compiledTargetZapper()
		{
			if(compiledTargetZapper == null)
			{
				if(targetZapperStr.trim().length()>0)
					compiledTargetZapper=CMLib.masking().maskCompile(targetZapperStr);
			}
			return compiledTargetZapper;
		}

		@Override
		public MaskingLibrary.CompiledZMask compiledSourceZapper()
		{
			if(compiledSourceZapper == null)
			{
				final String sourceZapperStr=savedTriggerParms.get("MASK");
				if((sourceZapperStr!=null)&&(sourceZapperStr.length()>0))
					compiledSourceZapper=CMLib.masking().maskCompile(sourceZapperStr);
			}
			return compiledSourceZapper;
		}

		@Override
		public String getTriggerParm(final String parmName)
		{
			if((triggerParms==null)||(triggerParms.length()==0))
				return "";
			final String S=savedTriggerParms.get(parmName);
			if(S!=null)
				return S;
			return "";
		}

		@Override
		public String toString()
		{
			if(triggerParms.trim().length()>0)
				return eventTriggerID+"("+triggerParms.replace(';',',')+");"+CHANGE_DIRECTION_DESCS[direction]+";"+((int)Math.round(factor*100.0))+"%;"+flagCache+";"+targetZapperStr;
			else
				return eventTriggerID+";"+CHANGE_DIRECTION_DESCS[direction]+";"+((int)Math.round(factor*100.0))+"%;"+flagCache+";"+targetZapperStr;
		}

		public DefaultFactionChangeEvent(final Faction F)
		{
			myFaction = F;
		}

		public DefaultFactionChangeEvent(final Faction F, final String eventKey, final String eventData)
		{
			myFaction=F;
			final List<String> v = CMParms.parseSemicolons(eventData,false);

			String trigger =v.get(0);
			triggerParms="";
			final int x=trigger.indexOf('(');
			if((x>0)&&(trigger.endsWith(")")))
			{
				setTriggerParameters(trigger.substring(x+1,trigger.length()-1));
				trigger=trigger.substring(0,x);
			}

			setEventID(trigger);
			setDirection(v.get(1));
			final String amt=v.get(2).trim();
			if(amt.endsWith("%"))
				setFactor(CMath.s_pct(amt));
			else
				setFactor(1.0);

			if(v.size()>3)
				setFlags(v.get(3));
			if(v.size()>4)
				setTargetZapper(v.get(4));
		}

		@Override
		public boolean setEventID(final String newID)
		{
			IDclassFilter=-1;
			IDflagFilter=-1;
			IDdomainFilter=-1;
			miscEventTrigger = null;
			for (final MiscTrigger element : MiscTrigger.values())
			{
				if(element.name().equalsIgnoreCase(newID))
				{
					eventTriggerID = element.name();
					miscEventTrigger = element;
					return true;
				}
			}
			for(int i=0;i<Ability.ACODE_DESCS.length;i++)
			{
				if(Ability.ACODE_DESCS[i].equalsIgnoreCase(newID))
				{
					IDclassFilter = i;
					eventTriggerID = newID;
					return true;
				}
			}
			for(int i=0;i<Ability.DOMAIN_DESCS.length;i++)
			{
				if(Ability.DOMAIN_DESCS[i].equalsIgnoreCase(newID))
				{
					IDdomainFilter = i << 5;
					eventTriggerID = newID;
					return true;
				}
			}
			for(int i=0;i< Ability.FLAG_DESCS.length;i++)
			{
				if(Ability.FLAG_DESCS[i].equalsIgnoreCase(newID))
				{
					IDflagFilter = Math.round(Math.pow(2, i));
					eventTriggerID = newID;
					return true;
				}
			}
			if(CMClass.getAbility(newID)!=null)
			{
				eventTriggerID = newID;
				return true;
			}
			if(CMLib.socials().fetchSocial(newID, true)!=null)
			{
				eventTriggerID=newID.toUpperCase();
				return true;
			}
			if((newID.endsWith(" *"))
			&&(CMLib.socials().fetchSocial(newID.substring(0,newID.length()-2).trim(), true)!=null))
			{
				eventTriggerID=newID.toUpperCase().trim();
				return true;
			}
			if(getCMMsgTypeMap().containsKey(newID.toUpperCase().trim()))
			{
				eventTriggerID=newID.toUpperCase().trim();
				return true;
			}
			return false;
		}

		public boolean setDirection(final String d)
		{
			if(CMath.isInteger(d))
				direction=CMath.s_int(d);
			else
			if(d.startsWith("U"))
			{
				direction = CHANGE_DIRECTION_UP;
			}
			else
			if(d.startsWith("D"))
			{
				direction = CHANGE_DIRECTION_DOWN;
			}
			else
			if(d.startsWith("OPP"))
			{
				direction = CHANGE_DIRECTION_OPPOSITE;
			}
			else
			if(d.startsWith("REM"))
			{
				direction = CHANGE_DIRECTION_REMOVE;
			}
			else
			if(d.startsWith("MIN"))
			{
				direction = CHANGE_DIRECTION_MINIMUM;
			}
			else
			if(d.startsWith("MAX"))
			{
				direction = CHANGE_DIRECTION_MAXIMUM;
			}
			else
			if(d.startsWith("ADD"))
			{
				direction = CHANGE_DIRECTION_ADD;
			}
			else
			if(d.startsWith("TOW"))
			{
				direction = CHANGE_DIRECTION_TOWARD;
			}
			else
			if(d.startsWith("AWA"))
			{
				direction = CHANGE_DIRECTION_AWAY;
			}
			else
				return false;
			return true;
		}

		@Override
		public void setFlags(final String newFlagCache)
		{
			flagCache=newFlagCache.toUpperCase().trim();
			flags=CMParms.parseStrictEQParms(newFlagCache);
			outsiderTargetOK=flags.containsKey("OUTSIDER");
			selfTargetOK=flags.containsKey("SELFOK");
			just100=flags.containsKey("JUST100");
			bonusXP=flags.containsKey("XP")?CMath.s_int(flags.get("XP")):0;
			bonusRPXP=flags.containsKey("RPXP")?CMath.s_int(flags.get("RPXP")):0;
		}

		@Override
		public String getFlagValue(String key)
		{
			key=key.toUpperCase().trim();
			return flags.containsKey(key) ? flags.get(key) : "";
		}

		@Override
		public boolean applies(final MOB source, final MOB target)
		{
			if(!CMLib.masking().maskCheck(compiledTargetZapper(),target,false))
				return false;
			if(!CMLib.masking().maskCheck(compiledSourceZapper(),source,false))
				return false;
			final Faction F=getFaction();
			if(F!=null)
			{
				if(withinTicks > 0)
				{
					final long now=System.currentTimeMillis() - (withinTicks * CMProps.getTickMillis());
					Faction.FData data;
					data = source.fetchFactionData(F.factionID());
					if(data != null)
					{
						if(now > data.getEventTime(eventTriggerID))
							return false;
					}
					if(source != target)
					{
						data = target.fetchFactionData(F.factionID());
						if(data != null)
						{
							if(now > data.getEventTime(eventTriggerID))
								return false;
						}
					}
				}
			}
			return true;
		}

		@Override
		public String triggerParameters()
		{
			return triggerParms;
		}

		@Override
		public void setTriggerParameters(final String newVal)
		{
			triggerParms=newVal;
			savedTriggerParms=CMParms.parseStrictEQParms(newVal);
			compiledSourceZapper=null;
			withinTicks=savedTriggerParms.containsKey("WITHIN")?CMath.s_int(savedTriggerParms.get("WITHIN")):-1;
			pctChance=savedTriggerParms.containsKey("CHANCE")?CMath.s_int(savedTriggerParms.get("CHANCE")):100;
			waitMs=savedTriggerParms.containsKey("WAIT")?(CMath.s_long(savedTriggerParms.get("WAIT"))*CMProps.getTickMillis()):-1;
		}

		@Override
		public Object stateVariable(final int x)
		{
			return ((x >= 0) && (x < stateVariables.length)) ? stateVariables[x] : null;
		}

		@Override
		public void setStateVariable(final int x, final Object newVal)
		{
			if(x<0)
				return;
			if(x>=stateVariables.length)
				stateVariables=Arrays.copyOf(stateVariables,x+1);
			stateVariables[x]=newVal;
		}

		@Override
		public Faction getFaction()
		{
			return myFaction;
		}
	}

	@Override
	public Faction.FRange addRange(final String key)
	{
		final Faction.FRange FR=new DefaultFaction.DefaultFactionRange(this,key);
		ranges.put(FR.codeName().toUpperCase().trim(),FR);
		recalc();
		return FR;
	}

	@Override
	public boolean delRange(final FRange FR)
	{
		if(!ranges.containsKey(FR.codeName().toUpperCase().trim()))
			return false;
		ranges.remove(FR.codeName().toUpperCase().trim());
		recalc();
		return true;
	}

	public class DefaultFactionRange implements Faction.FRange, Comparable<Faction.FRange>
	{
		public int				low;
		public int				high;
		public String			name		= "";
		public String			codeName	= "";
		public Faction.Align	alignEquiv;
		public Faction			faction		= null;

		@Override
		public int low()
		{
			return low;
		}

		@Override
		public int high()
		{
			return high;
		}

		@Override
		public String name()
		{
			return name;
		}

		@Override
		public String codeName()
		{
			return codeName;
		}

		@Override
		public Align alignEquiv()
		{
			return alignEquiv;
		}

		@Override
		public Faction getFaction()
		{
			return faction;
		}

		@Override
		public void setLow(final int newVal)
		{
			low = newVal;
		}

		@Override
		public void setHigh(final int newVal)
		{
			high = newVal;
		}

		@Override
		public void setName(final String newVal)
		{
			name = newVal;
		}

		@Override
		public void setAlignEquiv(final Faction.Align newVal)
		{
			alignEquiv = newVal;
		}

		public DefaultFactionRange(final Faction F, final String key)
		{
			faction=F;
			final List<String> v = CMParms.parseSemicolons(key,false);
			name = v.get(2);
			low = CMath.s_int( v.get(0));
			high = CMath.s_int( v.get(1));
			if(v.size()>3)
				codeName=v.get(3);
			if(v.size()>4)
				alignEquiv = CMLib.factions().getAlignEnum(v.get(4));
			else
				alignEquiv = Faction.Align.INDIFF;
		}

		@Override
		public String toString()
		{
			return low +";"+high+";"+name+";"+codeName+";"+alignEquiv.toString();
		}

		@Override
		public int random()
		{
			final Random gen = new Random();
			return high - gen.nextInt(high-low);
		}

		@Override
		public int med()
		{
			return high - (high-low)/2;
		}

		@Override
		public int compareTo(final FRange o)
		{
			if(low < o.low())
				return -1;
			if(high > o.high())
				return 1;
			return 0;
		}
	}

	@Override
	public Faction.FAbilityUsage addAbilityUsage(final String key)
	{
		final Faction.FAbilityUsage usage=
			(key==null)?new DefaultFaction.DefaultFactionAbilityUsage()
					  : new DefaultFaction.DefaultFactionAbilityUsage(key);
		abilityUsages.add(usage);
		abilityUsages.trimToSize();
		abilityUseCache.clear();
		return usage;
	}

	@Override
	public boolean delAbilityUsage(final Faction.FAbilityUsage usage)
	{
		if(!abilityUsages.remove(usage))
			return false;
		abilityUsages.trimToSize();
		abilityUseCache.clear();
		return true;
	}

	public class DefaultFactionData implements FData
	{
		private int				value;
		private boolean			noListeners;
		private boolean			noTickers;
		private boolean			noStatAffectors;
		private long			lastUpdated;
		private Ability[]		myEffects;
		private Behavior[]		myBehaviors;
		private Ability			lightPresenceAbilities[];
		private Faction.FRange	currentRange;
		private boolean			erroredOut;
		private Faction			myFaction;
		public boolean			isReset	= false;
		private DVector			currentReactionSets;
		private long			birthTime = System.currentTimeMillis();

		private final CMap<String, Long>				timers	= new SHashtable<String, Long>();
		private final CMap<String, int[]>				counters= new SHashtable<String, int[]>();
		private Map<Faction.FactionChangeEvent, Long>	nextChangeTime;

		public DefaultFactionData(final Faction F)
		{
			resetFactionData(F);
		}

		@Override
		public void resetFactionData(final Faction F)
		{
			if(!isReset)
			{
				myFaction=F;
				value=0;
				noListeners=false;
				noTickers=false;
				noStatAffectors=false;
				lastUpdated=System.currentTimeMillis();
				myEffects=new Ability[0];
				myBehaviors=new Behavior[0];
				currentReactionSets = new DVector(2);
				lightPresenceAbilities = new Ability[0];
				currentRange = null;
				erroredOut=false;
				isReset = true;
				nextChangeTime = new Hashtable<Faction.FactionChangeEvent, Long>();
				timers.clear();
				counters.clear();
			}
		}

		@Override
		public long getEventTime(final String eventID)
		{
			if(!timers.containsKey(eventID))
				return this.birthTime;
			return timers.get(eventID).longValue();
		}

		@Override
		public void resetEventTimers(final String eventID)
		{
			this.birthTime = System.currentTimeMillis();
			if(eventID == null)
			{
				timers.clear();
				nextChangeTime.clear();
			}
			else
			{
				timers.put(eventID, Long.valueOf(System.currentTimeMillis()));
				for(final Iterator<Faction.FactionChangeEvent> e = nextChangeTime.keySet().iterator();e.hasNext();)
				{
					final Faction.FactionChangeEvent event = e.next();
					if(event.eventID().equalsIgnoreCase(eventID))
					{
						nextChangeTime.remove(event);
						break;
					}
				}
			}
		}

		@Override
		public int value()
		{
			return value;
		}

		@Override
		public Faction getFaction()
		{
			return myFaction;
		}

		@Override
		public long getNextChangeTimers(final Faction.FactionChangeEvent event)
		{
			if(nextChangeTime.containsKey(event))
				return nextChangeTime.get(event).longValue();
			return 0;
		}

		@Override
		public void setNextChangeTimers(final Faction.FactionChangeEvent event, final long time)
		{
			nextChangeTime.put(event, Long.valueOf(time));
		}

		@SuppressWarnings("unchecked")
		@Override
		public void setValue(final int newValue)
		{
			this.value=newValue;
			if((currentRange==null)||(this.value<currentRange.low())||(this.value>currentRange.high()))
			{
				synchronized(this)
				{
					if((currentRange!=null)&&(this.value>=currentRange.low())&&(this.value<=currentRange.high()))
						return;
					currentRange = fetchRange(value);
					if(currentRange==null)
					{
						if(!erroredOut)
							Log.errOut("DefaultFactionData","Faction "+factionID()+" does not define a range for "+this.value);
						erroredOut=true;
					}
					else
					{
						erroredOut=false;
						currentReactionSets=new DVector(2);
						for(final Enumeration<Faction.FReactionItem> e=reactions();e.hasMoreElements();)
						{
							Faction.FReactionItem react = e.nextElement();
							if(!react.rangeCodeName().equalsIgnoreCase(currentRange.codeName()))
								continue;
							Faction.FReactionItem sampleReact = null;
							Vector<Faction.FReactionItem> reactSet=null;
							for(int r=0;r<currentReactionSets.size();r++)
							{
								reactSet=(Vector<Faction.FReactionItem>)currentReactionSets.elementAt(r,2);
								sampleReact=reactSet.firstElement();
								if(react.presentMOBMask().trim().equalsIgnoreCase(sampleReact.presentMOBMask().trim()))
								{
									reactSet.addElement(react);
									react=null; break;
								}
							}
							if(react!=null)
								currentReactionSets.addElement(react.compiledPresentMOBMask(),new XVector<Faction.FReactionItem>(react));
						}
						//noReactions=currentReactionSets.size()==0;
					}
					noListeners=(myEffects.length==0) && (myBehaviors.length==0) && (currentReactionSets.size()==0);
					noTickers=(myBehaviors.length==0) && (myEffects.length==0) &&((currentReactionSets.size()==0)||(!useLightReactions()));
				}
			}
		}

		@Override
		public void affectPhyStats(final Physical affected, final PhyStats affectableStats)
		{
			if(!noStatAffectors)
				for(final Ability A : myEffects) A.affectPhyStats(affected, affectableStats);
		}

		@Override
		public void affectCharStats(final MOB affectedMob, final CharStats affectableStats)
		{
			if(!noStatAffectors)
				for(final Ability A : myEffects) A.affectCharStats(affectedMob, affectableStats);
		}

		@Override
		public void affectCharState(final MOB affectedMob, final CharState affectableMaxState)
		{
			if(!noStatAffectors)
				for(final Ability A : myEffects) A.affectCharState(affectedMob, affectableMaxState);
		}

		@Override
		public void addHandlers(final List<Ability> listeners, final List<Behavior> tickers)
		{
			this.myEffects=listeners.toArray(new Ability[0]);
			this.myBehaviors=tickers.toArray(new Behavior[0]);
			noListeners=(listeners.size()==0) && (tickers.size()==0) && (currentReactionSets.size()==0);
			noTickers=(listeners.size()==0) && (tickers.size()==0) && ((currentReactionSets.size()==0)||(!useLightReactions()));
			noStatAffectors=(listeners.size()==0);
			isReset = false;
		}

		@Override
		public boolean requiresUpdating()
		{
			return lastDataChange[0] > lastUpdated;
		}

		@SuppressWarnings("unchecked")
		private Ability setPresenceReaction(final MOB M, final Physical myHost)
		{
			if((!CMLib.flags().canBeSeenBy(myHost, M))
			&&(!CMLib.flags().canBeHeardMovingBy(myHost,M)))
				return null;
			if((M.amUltimatelyFollowing()!=null)
			&&(!M.amUltimatelyFollowing().isMonster()))
				return null;
			Vector<String> myReactions=null;
			List<Faction.FReactionItem> tempReactSet=null;
			for(int d=0;d<currentReactionSets.size();d++)
			{
				if(CMLib.masking().maskCheck((MaskingLibrary.CompiledZMask)currentReactionSets.elementAt(d,1),M,true))
				{
					if(myReactions==null)
						myReactions=new Vector<String>();
					tempReactSet=(List<Faction.FReactionItem>)currentReactionSets.elementAt(d,2);
					for(final Faction.FReactionItem reactionItem : tempReactSet)
						myReactions.add(reactionItem.reactionObjectID()+"="+reactionItem.parameters(myHost.Name()));
				}
			}
			if(myReactions!=null)
			{
				if(useLightReactions())
				{
					final Ability A=(Ability)presenceReactionPrototype.copyOf();
					A.invoke(M,myReactions,myHost,false,0);
					A.setInvoker(M);
					return A;
				}
				else
				if(M.fetchEffect(presenceReactionPrototype.ID())==null)
				{
					final Ability A=(Ability)presenceReactionPrototype.copyOf();
					A.invoke(M,myReactions,myHost,true,0);
				}
			}
			return null;
		}

		@Override
		public void executeMsg(final Environmental myHost, final CMMsg msg)
		{
			if(noListeners)
				return;
			synchronized(lightPresenceAbilities)
			{
				if((currentReactionSets.size()>0)
				&&(msg.sourceMinor()==CMMsg.TYP_ENTER)
				&&(msg.target() instanceof Room))
				{
					if(presenceReactionPrototype==null)
					{
						if((presenceReactionPrototype=CMClass.getAbility("PresenceReaction"))==null)
							return;
					}
					if((msg.source()==myHost)
					&&(!msg.source().isMonster()))
					{
						MOB M=null;
						final Room R=(Room)msg.target();
						final List<Ability> lightPresenceReactions=new LinkedList<Ability>();
						Ability A=null;
						for(int m=0;m<R.numInhabitants();m++)
						{
							M=R.fetchInhabitant(m);
							if((M!=null)
							&&(M!=myHost)
							&&(M.isMonster())) // follow checks are in setPresenceReaction
							{
								A=setPresenceReaction(M,msg.source());
								if(A!=null) // means yes, we are using light, and yes, heres a reaction to add
									lightPresenceReactions.add(A);
							}
						}
						lightPresenceAbilities = lightPresenceReactions.toArray(new Ability[0]);
					}
					else
					if((msg.source().isMonster())
					&&(msg.target()==CMLib.map().roomLocation(myHost))
					&&(myHost instanceof Physical))
					{
						if(!(myHost instanceof MOB))
						{
							// follow checks are in setPresenceReaction
							final Ability A=setPresenceReaction(msg.source(),(Physical)myHost);
							if(A!=null)
							{ // means yes, we are using light, and yes, heres a reaction to add
								lightPresenceAbilities = Arrays.copyOf(lightPresenceAbilities, lightPresenceAbilities.length+1);
								lightPresenceAbilities[lightPresenceAbilities.length-1]=A;
							}
						}
					}
				}
				else
				if((lightPresenceAbilities.length>0)
				&&(msg.sourceMinor()==CMMsg.TYP_LEAVE)
				&&(msg.target() instanceof Room))
				{
					if((msg.source()==myHost)
					&&(!msg.source().isMonster()))
					{
						final Room R=(Room)msg.target();
						MOB M=null;
						for(int m=0;m<R.numInhabitants();m++)
						{
							M=R.fetchInhabitant(m);
							if((M!=null)
							&&(M!=myHost)
							&&(M.isMonster()))
								presenceReactionPrototype.invoke(M,new Vector<String>(),null,true,0); // this shuts it down
						}
						lightPresenceAbilities=new Ability[0];
					}
					else
					if((msg.source().isMonster())
					&&(myHost instanceof Physical))
					{
						presenceReactionPrototype.invoke(msg.source(),new Vector<String>(),null,true,0);
						final Ability[] newAbilities = new Ability[lightPresenceAbilities.length];
						int l=0;
						for (final Ability lightPresenceAbilitie : lightPresenceAbilities)
						{
							if(lightPresenceAbilitie.affecting()==null)
							{
							}
							else
							if(lightPresenceAbilitie.affecting()==msg.source())
								lightPresenceAbilitie.invoke(msg.source(),new Vector<String>(),null,true,0);
							else
								newAbilities[l++]=lightPresenceAbilitie;
						}
						if(l==0)
							lightPresenceAbilities=new Ability[0];
						else
						if(l<lightPresenceAbilities.length)
							lightPresenceAbilities = Arrays.copyOf(newAbilities, l);
					}
				}
			}
			for(final Ability A : lightPresenceAbilities)
				A.executeMsg(A.invoker(), msg);
			for(final Ability A : myEffects)
				A.executeMsg(myHost, msg);
			for(final Behavior B : myBehaviors)
				B.executeMsg(myHost, msg);
		}

		@Override
		public boolean okMessage(final Environmental myHost, final CMMsg msg)
		{
			if(noListeners)
				return true;
			for(final Ability A : myEffects)
			{
				if(!A.okMessage(myHost, msg))
					return false;
			}
			for(final Behavior B : myBehaviors)
			{
				if(!B.okMessage(myHost, msg))
					return false;
			}
			for(final Ability A : lightPresenceAbilities)
			{
				if(!A.okMessage(A.invoker(), msg))
					return false;
			}
			return true;
		}

		@Override
		public boolean tick(final Tickable ticking, final int tickID)
		{
			if(noTickers)
				return true;
			for(final Ability A : myEffects)
			{
				if(!A.tick(ticking, tickID))
					return false;
			}
			for(final Behavior B : myBehaviors)
			{
				if(!B.tick(ticking, tickID))
					return false;
			}
			for(final Ability A : lightPresenceAbilities)
			{
				if(!A.tick(A.invoker(), tickID))
					return false;
			}
			return true;
		}

		@Override
		public int getCounter(final String key)
		{
			if(counters.containsKey(key))
				return counters.get(key)[0];
			return 0;
		}

		@Override
		public void setCounter(final String key, final int newValue)
		{
			if(key == null)
				counters.clear();
			else
			if(counters.containsKey(key))
				counters.get(key)[0]=newValue;
			else
				counters.put(key, new int[] {newValue});
		}
	}

	public class DefaultFactionZapFactor implements Faction.FZapFactor
	{
		private double gainF= 1.0;
		private double lossF= 1.0;
		private String mask	= "";
		private MaskingLibrary.CompiledZMask compiledMask=null;

		public DefaultFactionZapFactor(final double gain, final double loss, final String mask)
		{
			setGainFactor(gain);
			setLossFactor(loss);
			setMOBMask(mask);
		}

		@Override
		public double gainFactor()
		{
			return gainF;
		}

		@Override
		public void setGainFactor(final double val)
		{
			gainF = val;
		}

		@Override
		public double lossFactor()
		{
			return lossF;
		}

		@Override
		public void setLossFactor(final double val)
		{
			lossF = val;
		}

		@Override
		public String MOBMask()
		{
			return mask;
		}

		@Override
		public MaskingLibrary.CompiledZMask compiledMOBMask()
		{
			return compiledMask;
		}

		@Override
		public void setMOBMask(final String str)
		{
			mask=str;
			compiledMask=CMLib.masking().maskCompile(str);
		}

		@Override
		public String toString()
		{
			return gainF + ";" + lossF + ";" + mask;
		}
	}

	public class DefaultFactionReactionItem implements Faction.FReactionItem
	{
		private String reactionObjectID	="";
		private String mobMask			="";
		private String rangeName		="";
		private String parms			="";

		private MaskingLibrary.CompiledZMask compiledMobMask=null;

		@Override
		public String reactionObjectID()
		{
			return reactionObjectID;
		}

		@Override
		public void setReactionObjectID(final String str)
		{
			reactionObjectID = str;
		}

		@Override
		public String presentMOBMask()
		{
			return mobMask;
		}

		@Override
		public void setPresentMOBMask(final String str)
		{
			mobMask=str;
			if((str==null)||(str.trim().length()==0))
				compiledMobMask=null;
			else
				compiledMobMask=CMLib.masking().maskCompile(str);
		}

		@Override
		public MaskingLibrary.CompiledZMask compiledPresentMOBMask()
		{
			return compiledMobMask;
		}

		@Override
		public String rangeCodeName()
		{
			return rangeName;
		}

		@Override
		public void setRangeName(final String str)
		{
			rangeName = str.toUpperCase().trim();
		}

		@Override
		public String parameters()
		{
			return parms;
		}

		@Override
		public String parameters(final String name)
		{
			return CMStrings.replaceAll(parms, "<TARGET>", name);
		}

		@Override
		public void setParameters(final String str)
		{
			parms = str;
		}

		@Override
		public String toString()
		{
			return rangeName + ";" + mobMask + ";" + reactionObjectID + ";" + parms;
		}

		public DefaultFactionReactionItem()
		{
		}

		public DefaultFactionReactionItem(final String key)
		{
			int x=key.indexOf(';');
			String str = key.substring(0,x).toUpperCase().trim();
			String rest = key.substring(x+1);
			setRangeName(str);

			x=rest.indexOf(';');
			str = rest.substring(0,x).trim();
			rest = rest.substring(x+1);
			setPresentMOBMask(str);

			x=rest.indexOf(';');
			str = rest.substring(0,x).trim();
			rest = rest.substring(x+1);
			setReactionObjectID(str);
			setParameters(rest);
		}

	}

	public class DefaultFactionAbilityUsage implements Faction.FAbilityUsage
	{
		public String	ID					= "";
		public boolean	possibleAbilityID	= false;
		public int		type				= -1;
		public int		domain				= -1;
		public long		flag				= -1;
		public int		low					= 0;
		public int		high				= 0;
		public long		notflag				= -1;

		@Override
		public String abilityFlags()
		{
			return ID;
		}

		@Override
		public boolean possibleAbilityID()
		{
			return possibleAbilityID;
		}

		@Override
		public int type()
		{
			return type;
		}

		@Override
		public int domain()
		{
			return domain;
		}

		@Override
		public long flag()
		{
			return flag;
		}

		@Override
		public int low()
		{
			return low;
		}

		@Override
		public int high()
		{
			return high;
		}

		@Override
		public long notflag()
		{
			return notflag;
		}

		@Override
		public void setLow(final int newVal)
		{
			low = newVal;
		}

		@Override
		public void setHigh(final int newVal)
		{
			high = newVal;
		}

		public DefaultFactionAbilityUsage()
		{
		}

		public DefaultFactionAbilityUsage(final String key)
		{
			final List<String> v = CMParms.parseSemicolons(key,false);
			setAbilityFlag(v.get(0));
			low = CMath.s_int( v.get(1));
			high = CMath.s_int( v.get(2));
		}

		@Override
		public String toString()
		{
			return ID+";"+low+";"+high;
		}

		@Override
		public List<String> setAbilityFlag(final String str)
		{
			ID=str;
			final List<String> flags=CMParms.parse(ID);
			final List<String> unknowns=new Vector<String>();
			possibleAbilityID=false;
			for(int f=0;f<flags.size();f++)
			{
				String strflag=flags.get(f);
				final boolean not=strflag.startsWith("!");
				if(not)
					strflag=strflag.substring(1);
				switch(CMLib.factions().getAbilityFlagType(strflag))
				{
				case ACODE:
					type=CMParms.indexOfIgnoreCase(Ability.ACODE_DESCS, strflag);
					break;
				case DOMAIN:
					domain=CMParms.indexOfIgnoreCase(Ability.DOMAIN_DESCS, strflag);
					break;
				case FLAG:
				{
					final int val=CMParms.indexOfIgnoreCase(Ability.FLAG_DESCS, strflag);
					if(not)
					{
						if(notflag<0)
							notflag=0;
						notflag=notflag|CMath.pow(2,val);
					}
					else
					{
						if(flag<0)
							flag=0;
						flag=flag|CMath.pow(2,val);
					}
					break;
				}
				default:
					unknowns.add(strflag);
					break;
				}
			}
			if((type<0)&&(domain<0)&&(flag<0))
				possibleAbilityID=true;
			return unknowns;
		}
	}

	@Override
	public void destroy()
	{
		CMLib.factions().removeFaction(this.factionID());
		this.destroyed=true;
		defaults.clear();
		autoDefaults.clear();
		ranges.clear();
		affBehavs.clear();
		changes.clear();
		abilChangeCache.clear();
		msgChangeCache.clear();
		socChangeCache.clear();
		factors.clear();
		relations.clear();
		abilityUsages.clear();
		abilityUseCache.clear();
		choices.clear();
		reactions.clear();
		reactionHash.clear();
	}

	@Override
	public boolean isSavable()
	{
		return (internalFlagBitmap & Faction.IFLAG_NEVERSAVE) == 0;
	}

	@Override
	public void setSavable(final boolean truefalse)
	{
	}

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

<MSG> some more teach/cast fixes

git-svn-id: 0cdf8356e41b2d8ccbb41bb76c82068fe80b2514@19624 0d6f1817-ed0e-0410-87c9-987e46238f29

<DFF> @@ -1392,7 +1392,8 @@ public class DefaultFaction implements Faction, MsgListener
 			{
 				if((msg.target()==myHost)	// Arrested watching
 				&&(msg.source().isMonster())
-				&&(msg.tool().ID().equals("Skill_HandCuff")))
+				&&(msg.tool().ID().equals("Skill_HandCuff"))
+				&&(msg.sourceMinor()!=CMMsg.TYP_TEACH))
 				{
 					final Room R=msg.source().location();
 					if((R!=null)&&(R.getArea()!=null))

{'commit': 'diff --git a/com/planet_ink/coffee_mud/Abilities/Properties/Prop_AbilityImmunity.java b/com/planet_ink/coffee_mud/Abilities/Properties/Prop_AbilityImmunity.java\nindex de035df0f6..37761ebd14 100644\n--- a/com/planet_ink/coffee_mud/Abilities/Properties/Prop_AbilityImmunity.java\n+++ b/com/planet_ink/coffee_mud/Abilities/Properties/Prop_AbilityImmunity.java\n@@ -119,6 +119,7 @@ public class Prop_AbilityImmunity extends Property implements TriggeredAffect\n \t{\r\n \t\tif ((msg.target() != null)\r\n \t\t&& (msg.tool() instanceof Ability )\r\n+\t\t&&(msg.sourceMinor()!=CMMsg.TYP_TEACH)\r\n \t\t&& ((msg.amITarget(affected))\r\n \t\t\t||(affected instanceof Area)\r\n \t\t\t||(owner && (affected instanceof Item) && (msg.target()==((Item)affected).owner()))\r\ndiff --git a/com/planet_ink/coffee_mud/CharClasses/Barbarian.java b/com/planet_ink/coffee_mud/CharClasses/Barbarian.java\nindex 0723fd50bf..2b35523ed6 100644\n--- a/com/planet_ink/coffee_mud/CharClasses/Barbarian.java\n+++ b/com/planet_ink/coffee_mud/CharClasses/Barbarian.java\n@@ -332,7 +332,8 @@ public class Barbarian extends StdCharClass\n \t\t\telse\r\n \t\t\tif((CMath.bset(msg.targetMajor(),CMMsg.MASK_MALICIOUS))\r\n \t\t\t&&(msg.tool() instanceof Ability)\r\n-\t\t\t&&((((Ability)msg.tool()).classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_ENCHANTMENT))\r\n+\t\t\t&&((((Ability)msg.tool()).classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_ENCHANTMENT)\r\n+\t\t\t&&(msg.sourceMinor()!=CMMsg.TYP_TEACH))\r\n \t\t\t{\r\n \t\t\t\tif(CMLib.dice().rollPercentage()<=myChar.charStats().getClassLevel(this))\r\n \t\t\t\t{\r\ndiff --git a/com/planet_ink/coffee_mud/Common/DefaultFaction.java b/com/planet_ink/coffee_mud/Common/DefaultFaction.java\nindex 213788893d..29bac91a03 100644\n--- a/com/planet_ink/coffee_mud/Common/DefaultFaction.java\n+++ b/com/planet_ink/coffee_mud/Common/DefaultFaction.java\n@@ -1392,7 +1392,8 @@ public class DefaultFaction implements Faction, MsgListener\n \t\t\t{\r\n \t\t\t\tif((msg.target()==myHost)\t// Arrested watching\r\n \t\t\t\t&&(msg.source().isMonster())\r\n-\t\t\t\t&&(msg.tool().ID().equals("Skill_HandCuff")))\r\n+\t\t\t\t&&(msg.tool().ID().equals("Skill_HandCuff"))\r\n+\t\t\t\t&&(msg.sourceMinor()!=CMMsg.TYP_TEACH))\r\n \t\t\t\t{\r\n \t\t\t\t\tfinal Room R=msg.source().location();\r\n \t\t\t\t\tif((R!=null)&&(R.getArea()!=null))\r\n', 'commit_subject': 'some more teach/cast fixes', 'repo_name': 'bozimmerman/CoffeeMud', 'committer': {'name': 'bozimmerman', 'email': 'dc45fe023482b3b890b5e574e53c1d051f45b1ef@zimmers.net', 'time_sec': '1593196090', 'tz_offset': '0', 'date': {'seconds': '1593196090'}}, 'commit_tree': '33813351e767ebe20e9bfb8cc7750c339550e127', 'commit_message': 'some more teach/cast fixes\n\ngit-svn-id: 0cdf8356e41b2d8ccbb41bb76c82068fe80b2514@19624 0d6f1817-ed0e-0410-87c9-987e46238f29\n', 'language_name': 'JavaScript', 'license': 'apache-2.0', 'hunks': '@@ -1392,7 +1392,8 @@ public class DefaultFaction implements Faction, MsgListener\n \t\t\t{\r\n \t\t\t\tif((msg.target()==myHost)\t// Arrested watching\r\n \t\t\t\t&&(msg.source().isMonster())\r\n-\t\t\t\t&&(msg.tool().ID().equals("Skill_HandCuff")))\r\n+\t\t\t\t&&(msg.tool().ID().equals("Skill_HandCuff"))\r\n+\t\t\t\t&&(msg.sourceMinor()!=CMMsg.TYP_TEACH))\r\n \t\t\t\t{\r\n \t\t\t\t\tfinal Room R=msg.source().location();\r\n \t\t\t\t\tif((R!=null)&&(R.getArea()!=null))\r\n', 'addition_count': 2, 'deletion_count': 1, 'src_file': 'a/com/planet_ink/coffee_mud/Common/DefaultFaction.java', 'tgt_file': 'b/com/planet_ink/coffee_mud/Common/DefaultFaction.java', 'file_extension': '.java', 'before_file': 'package com.planet_ink.coffee_mud.Common;\nimport com.planet_ink.coffee_mud.core.database.DBInterface;\nimport com.planet_ink.coffee_mud.core.interfaces.*;\nimport com.planet_ink.coffee_mud.core.*;\nimport com.planet_ink.coffee_mud.core.CMClass.CMObjectType;\nimport com.planet_ink.coffee_mud.core.collections.*;\nimport com.planet_ink.coffee_mud.Abilities.Misc.PresenceReaction;\nimport com.planet_ink.coffee_mud.Abilities.interfaces.*;\nimport com.planet_ink.coffee_mud.Areas.interfaces.*;\nimport com.planet_ink.coffee_mud.Behaviors.interfaces.*;\nimport com.planet_ink.coffee_mud.CharClasses.interfaces.*;\nimport com.planet_ink.coffee_mud.Commands.interfaces.*;\nimport com.planet_ink.coffee_mud.Common.interfaces.*;\nimport com.planet_ink.coffee_mud.Common.interfaces.Faction.FData;\nimport com.planet_ink.coffee_mud.Common.interfaces.Faction.FRange;\nimport com.planet_ink.coffee_mud.Common.interfaces.Faction.FactionChangeEvent.MiscTrigger;\nimport com.planet_ink.coffee_mud.Exits.interfaces.*;\nimport com.planet_ink.coffee_mud.Items.interfaces.*;\nimport com.planet_ink.coffee_mud.Libraries.interfaces.ChannelsLibrary;\nimport com.planet_ink.coffee_mud.Libraries.interfaces.EnglishParsing;\nimport com.planet_ink.coffee_mud.Libraries.interfaces.MaskingLibrary;\nimport com.planet_ink.coffee_mud.Locales.interfaces.*;\nimport com.planet_ink.coffee_mud.MOBS.interfaces.*;\nimport com.planet_ink.coffee_mud.Races.interfaces.*;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.*;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n//import java.lang.reflect.*;\n/**\n * Portions Copyright (c) 2003 Jeremy Vyska\n * Portions Copyright (c) 2004-2022 Bo Zimmerman\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *  \t  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npublic class DefaultFaction implements Faction, MsgListener\n{\n\t@Override\n\tpublic String ID()\n\t{\n\t\treturn "DefaultFaction";\n\t}\n\n\t@Override\n\tpublic CMObject newInstance()\n\t{\n\t\ttry\n\t\t{\n\t\t\treturn getClass().newInstance();\n\t\t}\n\t\tcatch (final Exception e)\n\t\t{\n\t\t\treturn new DefaultFaction();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void initializeClass()\n\t{\n\t}\n\n\t@Override\n\tpublic CMObject copyOf()\n\t{\n\t\ttry\n\t\t{\n\t\t\treturn (CMObject) this.clone();\n\t\t}\n\t\tcatch (final Exception e)\n\t\t{\n\t\t\treturn newInstance();\n\t\t}\n\t}\n\n\t@Override\n\tpublic int compareTo(final CMObject o)\n\t{\n\t\treturn CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o));\n\t}\n\n\tprotected String\t _factionID\t\t\t= "";\n\tprotected String\t name\t\t\t\t= "";\n\tprotected String\t upName\t\t\t\t= "";\n\tprotected String\t choiceIntro\t\t= "";\n\tprotected long[]\t lastDataChange\t\t= new long[1];\n\tprotected int   \t minimum\t\t\t= Integer.MIN_VALUE;\n\tprotected int   \t middle\t\t\t\t= 0;\n\tprotected int   \t difference;\n\tprotected int   \t maximum\t\t\t= Integer.MAX_VALUE;\n\tprotected int   \t highest\t\t\t= Integer.MAX_VALUE;\n\tprotected int   \t lowest\t\t\t\t= Integer.MIN_VALUE;\n\tprotected long  \t internalFlagBitmap\t= 0;\n\tprotected String\t experienceFlag\t\t= "";\n\tprotected boolean    useLightReactions\t= false;\n\tprotected boolean    isDisabled\t\t\t= false;\n\tprotected boolean    showInScore\t\t= false;\n\tprotected boolean    showInSpecialReport= false;\n\tprotected boolean    showInEditor\t\t= false;\n\tprotected boolean    showInFacCommand\t= true;\n\tprotected boolean    isInherited\t\t= true;\n\tprotected boolean    destroyed\t\t\t= false;\n\n\tprotected CList<String>   \t\t\t\t\tdefaults\t\t = new SVector<String>();\n\tprotected CList<String>   \t\t\t\t\tautoDefaults\t = new SVector<String>();\n\tprotected CMap<String,FRange> \t\t\t\tranges\t\t\t = new SHashtable<String,FRange>();\n\tprotected Map<Integer,FRange> \t\t\t\trangeRangeMap\t = new PrioritizingLimitedMap<Integer,FRange>(10,60000,600000,100);\n\tprotected CMap<String,String[]>   \t\t\taffBehavs\t\t = new SHashtable<String,String[]>();\n\tprotected double\t\t\t\t\t\t\trateModifier\t = 1.0;\n\tprotected CMap<String,FactionChangeEvent[]>\tchanges\t\t\t = new SHashtable<String,FactionChangeEvent[]>();\n\tprotected CMap<String,FactionChangeEvent[]>\tabilChangeCache\t = new SHashtable<String,FactionChangeEvent[]>();\n\tprotected CMap<String,FactionChangeEvent[]>\tsocChangeCache\t = new SHashtable<String,FactionChangeEvent[]>();\n\tprotected CMap<Integer,FactionChangeEvent[]>msgChangeCache\t = new SHashtable<Integer,FactionChangeEvent[]>();\n\tprotected CList<Faction.FZapFactor>\t\t\tfactors\t\t\t = new SVector<Faction.FZapFactor>();\n\tprotected CMap<String,Double> \t\t\t\trelations\t\t = new SHashtable<String,Double>();\n\tprotected CList<Faction.FAbilityUsage>\t\tabilityUsages\t = new SVector<Faction.FAbilityUsage>();\n\tprotected Map<String,Faction.FAbilityUsage> abilityUseCache\t = new STreeMap<String,Faction.FAbilityUsage>();\n\tprotected Set<String> \t\t\t\t\t\tabilityUseMisses = new STreeSet<String>();\n\tprotected CList<String>   \t\t\t\t\tchoices\t\t\t = new SVector<String>();\n\tprotected CList<Faction.FReactionItem>\t\treactions\t\t = new SVector<Faction.FReactionItem>();\n\tprotected CMap<String,CList<FReactionItem>>\treactionHash\t = new SHashtable<String,CList<Faction.FReactionItem>>();\n\n\t@Override\n\tpublic Enumeration<Faction.FReactionItem> reactions()\n\t{\n\t\treturn reactions.elements();\n\t}\n\n\t@Override\n\tpublic Enumeration<Faction.FReactionItem> reactions(final String rangeName)\n\t{\n\t\tfinal CList<Faction.FReactionItem> V=reactionHash.get(rangeName.toUpperCase().trim());\n\t\tif(V!=null)\n\t\t\treturn V.elements();\n\t\treturn new Vector<Faction.FReactionItem>().elements();\n\t}\n\n\tprotected Ability presenceReactionPrototype=null;\n\n\t@Override\n\tpublic String factionID()\n\t{\n\t\treturn _factionID;\n\t}\n\n\t@Override\n\tpublic String name()\n\t{\n\t\treturn name;\n\t}\n\n\t@Override\n\tpublic String upperName()\n\t{\n\t\treturn upName;\n\t}\n\n\t@Override\n\tpublic long getInternalFlags()\n\t{\n\t\treturn internalFlagBitmap;\n\t}\n\n\t@Override\n\tpublic String choiceIntro()\n\t{\n\t\treturn choiceIntro;\n\t}\n\n\t@Override\n\tpublic boolean isInheritable()\n\t{\n\t\treturn this.isInherited;\n\t}\n\n\t@Override\n\tpublic int minimum()\n\t{\n\t\treturn minimum;\n\t}\n\n\t@Override\n\tpublic int middle()\n\t{\n\t\treturn middle;\n\t}\n\n\t@Override\n\tpublic int difference()\n\t{\n\t\treturn difference;\n\t}\n\n\t@Override\n\tpublic int maximum()\n\t{\n\t\treturn maximum;\n\t}\n\n\t@Override\n\tpublic boolean isDisabled()\n\t{\n\t\treturn isDisabled;\n\t}\n\n\t@Override\n\tpublic void disable(final boolean truefalse)\n\t{\n\t\tisDisabled = truefalse;\n\t}\n\n\tpublic int highest()\n\t{\n\t\treturn highest;\n\t}\n\n\tpublic int lowest()\n\t{\n\t\treturn lowest;\n\t}\n\n\t@Override\n\tpublic String experienceFlag()\n\t{\n\t\treturn experienceFlag;\n\t}\n\n\t@Override\n\tpublic boolean showInScore()\n\t{\n\t\treturn showInScore;\n\t}\n\n\t@Override\n\tpublic boolean showInSpecialReported()\n\t{\n\t\treturn showInSpecialReport;\n\t}\n\n\t@Override\n\tpublic boolean showInEditor()\n\t{\n\t\treturn showInEditor;\n\t}\n\n\t@Override\n\tpublic boolean showInFactionsCommand()\n\t{\n\t\treturn showInFacCommand;\n\t}\n\n\t@Override\n\tpublic Enumeration<Faction.FRange> ranges()\n\t{\n\t\treturn ranges.elements();\n\t}\n\n\t@Override\n\tpublic Enumeration<String> defaults()\n\t{\n\t\treturn defaults.elements();\n\t}\n\n\t@Override\n\tpublic Enumeration<String> autoDefaults()\n\t{\n\t\treturn autoDefaults.elements();\n\t}\n\n\t@Override\n\tpublic double rateModifier()\n\t{\n\t\treturn rateModifier;\n\t}\n\n\t@Override\n\tpublic Enumeration<String> changeEventKeys()\n\t{\n\t\treturn changes.keys();\n\t}\n\n\t@Override\n\tpublic Enumeration<Faction.FZapFactor> factors()\n\t{\n\t\treturn factors.elements();\n\t}\n\n\t@Override\n\tpublic Enumeration<String> relationFactions()\n\t{\n\t\treturn relations.keys();\n\t}\n\n\t@Override\n\tpublic Enumeration<Faction.FAbilityUsage> abilityUsages()\n\t{\n\t\treturn abilityUsages.elements();\n\t}\n\n\t@Override\n\tpublic Enumeration<String> choices()\n\t{\n\t\treturn choices.elements();\n\t}\n\n\t@Override\n\tpublic Enumeration<String> affectsBehavs()\n\t{\n\t\treturn affBehavs.keys();\n\t}\n\n\t@Override\n\tpublic void setLightReactions(final boolean truefalse)\n\t{\n\t\tuseLightReactions = truefalse;\n\t}\n\n\t@Override\n\tpublic boolean useLightReactions()\n\t{\n\t\treturn useLightReactions;\n\t}\n\n\t@Override\n\tpublic void setFactionID(final String newStr)\n\t{\n\t\t_factionID = newStr;\n\t}\n\n\t@Override\n\tpublic void setName(final String newStr)\n\t{\n\t\tname = newStr;\n\t}\n\n\t@Override\n\tpublic void setInternalFlags(final long bitmap)\n\t{\n\t\tinternalFlagBitmap = bitmap;\n\t}\n\n\t@Override\n\tpublic void setChoiceIntro(final String newStr)\n\t{\n\t\tchoiceIntro = newStr;\n\t}\n\n\t@Override\n\tpublic void setExperienceFlag(final String newStr)\n\t{\n\t\texperienceFlag = newStr;\n\t}\n\n\t@Override\n\tpublic void setShowInScore(final boolean truefalse)\n\t{\n\t\tshowInScore = truefalse;\n\t}\n\n\t@Override\n\tpublic void setInherited(final boolean truefalse)\n\t{\n\t\tthis.isInherited=truefalse;\n\t}\n\n\t@Override\n\tpublic void setShowInSpecialReported(final boolean truefalse)\n\t{\n\t\tshowInSpecialReport = truefalse;\n\t}\n\n\t@Override\n\tpublic void setShowInEditor(final boolean truefalse)\n\t{\n\t\tshowInEditor = truefalse;\n\t}\n\n\t@Override\n\tpublic void setShowInFactionsCommand(final boolean truefalse)\n\t{\n\t\tshowInFacCommand = truefalse;\n\t}\n\n\t@Override\n\tpublic void setChoices(final List<String> v)\n\t{\n\t\tchoices = new SVector<String>(v);\n\t}\n\n\t@Override\n\tpublic void setAutoDefaults(final List<String> v)\n\t{\n\t\tautoDefaults = new SVector<String>(v);\n\t}\n\n\t@Override\n\tpublic void setDefaults(final List<String> v)\n\t{\n\t\tdefaults = new SVector<String>(v);\n\t}\n\n\t@Override\n\tpublic void setRateModifier(final double d)\n\t{\n\t\trateModifier = d;\n\t}\n\n\t@Override\n\tpublic boolean isPreLoaded()\n\t{\n\t\treturn CMParms.parseSemicolons(CMProps.getVar(CMProps.Str.PREFACTIONS).toUpperCase(),true).contains(factionID().toUpperCase());\n\t}\n\n\t@Override\n\tpublic Faction.FAbilityUsage getAbilityUsage(final int x)\n\t{\n\t\treturn ((x>=0)&&(x<abilityUsages.size()))\n\t\t\t\t?(Faction.FAbilityUsage)abilityUsages.get(x)\n\t\t\t\t:null;\n\t}\n\n\t@Override\n\tpublic boolean delFactor(final Faction.FZapFactor f)\n\t{\n\t\tif(!factors.remove(f))\n\t\t\treturn false;\n\t\tfactors.trimToSize();\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Faction.FZapFactor getFactor(final int x)\n\t{\n\t\treturn ((x >= 0) && (x < factors.size())) ? factors.get(x) : null;\n\t}\n\n\t@Override\n\tpublic Faction.FZapFactor addFactor(final double gain, final double loss, final String mask)\n\t{\n\t\tfinal Faction.FZapFactor o=new DefaultFactionZapFactor(gain,loss,mask);\n\t\tfactors.add(o);\n\t\tfactors.trimToSize();\n\t\treturn o;\n\t}\n\n\t@Override\n\tpublic boolean delRelation(final String factionID)\n\t{\n\t\tif(relations.remove(factionID)==null)\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic boolean addRelation(final String factionID, final double relation)\n\t{\n\t\tif(relations.containsKey(factionID))\n\t\t\treturn false;\n\t\trelations.put(factionID,Double.valueOf(relation));\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic double getRelation(final String factionID)\n\t{\n\t\tif(relations.containsKey(factionID))\n\t\t\treturn relations.get(factionID).doubleValue();\n\t\treturn 0.0;\n\t}\n\n\tpublic DefaultFaction()\n\t{\n\t\tsuper();\n\t}\n\n\t@Override\n\tpublic void initializeFaction(final String aname)\n\t{\n\t\t_factionID=aname;\n\t\tname=aname;\n\t\tupName=aname.toUpperCase();\n\t\tminimum=0;\n\t\tmiddle=50;\n\t\tmaximum=100;\n\t\thighest=100;\n\t\tlowest=0;\n\t\tdifference=CMath.abs(maximum-minimum);\n\t\texperienceFlag="EXTREME";\n\t\taddRange("0;100;Sample Range;SAMPLE;");\n\t\tdefaults.add("0");\n\t}\n\n\t@Override\n\tpublic void initializeFaction(final StringBuffer file, final String fID)\n\t{\n\t\tfinal boolean debug = false;\n\n\t\t_factionID = fID;\n\t\tfinal CMProps facProps = new CMProps();\n\t\tfor(final String line : Resources.getFileLineVector(file))\n\t\t{\n\t\t\tfinal String s=line.trim();\n\t\t\tif(s.startsWith("#")||(s.length()==0))\n\t\t\t\tcontinue;\n\t\t\tfinal int x=s.indexOf(\'=\');\n\t\t\tif(x<0)\n\t\t\t{\n\t\t\t\tLog.errOut("Unknown line \'"+s+"\' in faction "+fID);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfinal String key=s.substring(0,x);\n\t\t\tfinal String val=s.substring(x+1);\n\t\t\tfacProps.put(key, val);\n\t\t}\n\t\tif(facProps.isEmpty())\n\t\t\treturn;\n\t\tname=facProps.getStr("NAME");\n\t\tupName=name.toUpperCase();\n\t\tchoiceIntro=facProps.getStr("CHOICEINTRO");\n\t\tminimum=facProps.getInt("MINIMUM");\n\t\tmaximum=facProps.getInt("MAXIMUM");\n\t\tif(maximum<minimum)\n\t\t{\n\t\t\tminimum=maximum;\n\t\t\tmaximum=facProps.getInt("MINIMUM");\n\t\t}\n\t\trecalc();\n\t\texperienceFlag=facProps.getStr("EXPERIENCE").toUpperCase().trim();\n\t\tif(experienceFlag.length()==0)\n\t\t\texperienceFlag="NONE";\n\t\trateModifier=facProps.getDouble("RATEMODIFIER");\n\t\tshowInScore=facProps.getBoolean("SCOREDISPLAY");\n\t\tshowInFacCommand=facProps.getBoolean("SHOWINFACTIONSCMD");\n\t\tshowInSpecialReport=facProps.getBoolean("SPECIALREPORTED");\n\t\tshowInEditor=facProps.getBoolean("EDITALONE");\n\t\tfinal String s=facProps.getStr("INHERITED");\n\t\tif(s.trim().length()==0)\n\t\t\tisInherited=true;\n\t\telse\n\t\t\tisInherited=facProps.getBoolean("INHERITED");\n\t\tdefaults=new SVector<String>(CMParms.parseSemicolons(facProps.getStr("DEFAULT"),true));\n\t\tautoDefaults =new SVector<String>(CMParms.parseSemicolons(facProps.getStr("AUTODEFAULTS"),true));\n\t\tchoices =new SVector<String>(CMParms.parseSemicolons(facProps.getStr("AUTOCHOICES"),true));\n\t\tuseLightReactions=facProps.getBoolean("USELIGHTREACTIONS");\n\t\tranges=new SHashtable<String,FRange>();\n\t\tchanges=new SHashtable<String,FactionChangeEvent[]>();\n\t\tfactors=new SVector<FZapFactor>();\n\t\trelations=new SHashtable<String,Double>();\n\t\tabilityUsages=new SVector<FAbilityUsage>();\n\t\tabilityUseCache=new STreeMap<String,FAbilityUsage>();\n\t\tabilityUseMisses=new STreeSet<String>();\n\t\treactions=new SVector<FReactionItem>();\n\t\treactionHash=new SHashtable<String,CList<FReactionItem>>();\n\t\tfor(final Enumeration<Object> e=facProps.keys();e.hasMoreElements();)\n\t\t{\n\t\t\tif(debug)\n\t\t\t\tLog.sysOut("FACTIONS","Starting Key Loop");\n\t\t\tfinal String key = (String) e.nextElement();\n\t\t\tif(debug)\n\t\t\t\tLog.sysOut("FACTIONS","  Key Found     :"+key);\n\t\t\tfinal String words = (String) facProps.get(key);\n\t\t\tif(debug)\n\t\t\t\tLog.sysOut("FACTIONS","  Words Found   :"+words);\n\t\t\tif(key.startsWith("RANGE"))\n\t\t\t\taddRange(words);\n\t\t\tif(key.startsWith("CHANGE"))\n\t\t\t\tcreateChangeEvent(key, words);\n\t\t\tif(key.startsWith("AFFBEHAV"))\n\t\t\t{\n\t\t\t\tfinal Object[] O=CMParms.parseSafeSemicolonList(words,false).toArray();\n\t\t\t\tif(O.length==3)\n\t\t\t\t\taddAffectBehav((String)O[0],(String)O[1],(String)O[2]);\n\t\t\t}\n\t\t\tif(key.startsWith("FACTOR"))\n\t\t\t{\n\t\t\t\tfinal List<String> factor=CMParms.parseSemicolons(words,false);\n\t\t\t\tif(factor.size()>2)\n\t\t\t\t\tfactors.add(new DefaultFactionZapFactor(CMath.s_double(factor.get(0)),\n\t\t\t\t\t\t\t\t\t\t\t CMath.s_double(factor.get(1)),\n\t\t\t\t\t\t\t\t\t\t\t factor.get(2)));\n\t\t\t}\n\t\t\tif(key.startsWith("RELATION"))\n\t\t\t{\n\t\t\t\tfinal Vector<String> V=CMParms.parse(words);\n\t\t\t\tif(V.size()>=2)\n\t\t\t\t{\n\t\t\t\t\tfinal String who=V.elementAt(0);\n\t\t\t\t\tdouble factor;\n\t\t\t\t\tfinal String amt=V.elementAt(1).trim();\n\t\t\t\t\tif(amt.endsWith("%"))\n\t\t\t\t\t\tfactor=CMath.s_pct(amt);\n\t\t\t\t\telse\n\t\t\t\t\t\tfactor=1;\n\t\t\t\t\trelations.put(who,Double.valueOf(factor));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(key.startsWith("ABILITY"))\n\t\t\t\taddAbilityUsage(words);\n\t\t\tif(key.startsWith("REACTION"))\n\t\t\t{\n\t\t\t\tfinal DefaultFactionReactionItem item = new DefaultFactionReactionItem(words);\n\t\t\t\taddReaction(item.rangeCodeName(), item.presentMOBMask(), item.reactionObjectID(), item.parameters());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void recalc()\n\t{\n\t\tminimum=Integer.MAX_VALUE;\n\t\tmaximum=Integer.MIN_VALUE;\n\t\tint num=0;\n\t\tfor(final Enumeration<Faction.FRange> e=ranges();e.hasMoreElements();)\n\t\t{\n\t\t\tfinal Faction.FRange FR=e.nextElement();\n\t\t\tif(FR.high()>maximum)\n\t\t\t\tmaximum=FR.high();\n\t\t\tif(FR.low()<minimum)\n\t\t\t\tminimum=FR.low();\n\t\t\tnum++;\n\t\t}\n\t\tif(minimum==Integer.MAX_VALUE)\n\t\t\tminimum=Integer.MIN_VALUE;\n\t\tif(maximum==Integer.MIN_VALUE)\n\t\t\tmaximum=Integer.MAX_VALUE;\n\t\tif(maximum<minimum)\n\t\t{\n\t\t\tfinal int oldMin=minimum;\n\t\t\tminimum=maximum;\n\t\t\tmaximum=oldMin;\n\t\t}\n\t\tmiddle=minimum+(int)Math.round(CMath.div(maximum-minimum,2.0));\n\t\tdifference=CMath.abs(maximum-minimum);\n\t\tlastDataChange[0]=System.currentTimeMillis();\n\t\trangeRangeMap=new PrioritizingLimitedMap<Integer,FRange>(num*5,60000,600000,100);\n\t}\n\n\t@Override\n\tpublic String getTagValue(final String tag)\n\t{\n\t\tfinal FacTag tagRef=CMLib.factions().getFactionTag(tag);\n\t\tif(tagRef==null)\n\t\t\treturn "";\n\t\tint numCall=-1;\n\t\tif((tagRef.maskPrefix!=null)\n\t\t&&(CMath.isInteger(tag.substring(tagRef.maskPrefix.length()))))\n\t\t\tnumCall=CMath.s_int(tag.substring(tagRef.maskPrefix.length()));\n\t\tswitch(tagRef)\n\t\t{\n\t\tcase NAME:\n\t\t\treturn name;\n\t\tcase MINIMUM:\n\t\t\treturn "" + minimum;\n\t\tcase MAXIMUM:\n\t\t\treturn "" + maximum;\n\t\tcase SCOREDISPLAY:\n\t\t\treturn Boolean.toString(showInScore).toUpperCase();\n\t\tcase SHOWINFACTIONSCMD:\n\t\t\treturn Boolean.toString(showInFacCommand).toUpperCase();\n\t\tcase SPECIALREPORTED:\n\t\t\treturn Boolean.toString(showInSpecialReport).toUpperCase();\n\t\tcase EDITALONE:\n\t\t\treturn Boolean.toString(showInEditor).toUpperCase();\n\t\tcase DEFAULT:\n\t\t\treturn CMParms.toSemicolonListString(defaults);\n\t\tcase AUTODEFAULTS:\n\t\t\treturn CMParms.toSemicolonListString(autoDefaults);\n\t\tcase CHOICEINTRO:\n\t\t\treturn choiceIntro;\n\t\tcase AUTOCHOICES:\n\t\t\treturn CMParms.toSemicolonListString(choices);\n\t\tcase RATEMODIFIER:\n\t\t\treturn "" + rateModifier;\n\t\tcase EXPERIENCE:\n\t\t\treturn "" + experienceFlag;\n\t\tcase INHERITABLE:\n\t\t\treturn Boolean.toString(isInherited).toUpperCase();\n\t\tcase RANGE_:\n\t\t{\n\t\t\tif((numCall<0)||(numCall>=ranges.size()))\n\t\t\t\treturn ""+ranges.size();\n\t\t\tint x=0;\n\t\t\tfor(final Enumeration<Faction.FRange> e=ranges();e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal Faction.FRange FR=e.nextElement();\n\t\t\t\tif(x==numCall)\n\t\t\t\t\treturn FR.toString();\n\t\t\t\tx++;\n\t\t\t}\n\t\t\treturn "";\n\t\t}\n\t\tcase CHANGE_:\n\t\t{\n\t\t\tint sz=0;\n\t\t\tfor(final Enumeration<Faction.FactionChangeEvent[]> es=changes.elements();es.hasMoreElements();)\n\t\t\t\tsz+=es.nextElement().length;\n\t\t\tif((numCall<0)||(numCall>=sz))\n\t\t\t\treturn ""+sz;\n\t\t\tint i=0;\n\t\t\tfor(final Enumeration<Faction.FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal Faction.FactionChangeEvent[] FCs=e.nextElement();\n\t\t\t\tfor (final FactionChangeEvent fc : FCs)\n\t\t\t\t{\n\t\t\t\t\tif(i==numCall)\n\t\t\t\t\t\treturn fc.toString();\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn "";\n\t\t}\n\t\tcase ABILITY_:\n\t\t{\n\t\t\tif((numCall<0)||(numCall>=abilityUsages.size()))\n\t\t\t\treturn ""+abilityUsages.size();\n\t\t\treturn abilityUsages.get(numCall).toString();\n\t\t}\n\t\tcase FACTOR_:\n\t\t{\n\t\t\tif((numCall<0)||(numCall>=factors.size()))\n\t\t\t\treturn ""+factors.size();\n\t\t\treturn factors.get(numCall).toString();\n\t\t}\n\t\tcase RELATION_:\n\t\t{\n\t\t\tif((numCall<0)||(numCall>=relations.size()))\n\t\t\t\treturn ""+relations.size();\n\t\t\tint i=0;\n\t\t\tfor(final Enumeration<String> e=relations.keys();e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal String factionName=e.nextElement();\n\t\t\t\tfinal Double D=relations.get(factionName);\n\t\t\t\tif(i==numCall)\n\t\t\t\t\treturn factionName+" "+CMath.toPct(D.doubleValue());\n\t\t\t\ti++;\n\t\t\t}\n\t\t\treturn "";\n\t\t}\n\t\tcase AFFBEHAV_:\n\t\t{\n\t\t\tif((numCall<0)||(numCall>=affBehavs.size()))\n\t\t\t\treturn ""+affBehavs.size();\n\t\t\tint i=0;\n\t\t\tfor(final Enumeration<String> e=affBehavs.keys();e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal String ID=e.nextElement();\n\t\t\t\tfinal String[] data=affBehavs.get(ID);\n\t\t\t\tif(i==numCall)\n\t\t\t\t\treturn ID+";"+CMParms.toSafeSemicolonListString(data);\n\t\t\t\ti++;\n\t\t\t}\n\t\t\treturn "";\n\t\t}\n\t\tcase REACTION_:\n\t\t{\n\t\t\tif((numCall<0)||(numCall>=reactions.size()))\n\t\t\t\treturn ""+reactions.size();\n\t\t\tfinal Faction.FReactionItem item = reactions.get(numCall);\n\t\t\treturn item.toString();\n\t\t}\n\t\tcase USELIGHTREACTIONS:\n\t\t\treturn "" + useLightReactions;\n\t\t}\n\t\treturn "";\n\t}\n\n\t@Override\n\tpublic String getINIDef(final String tag, final String delimeter)\n\t{\n\t\tfinal FacTag tagRef=CMLib.factions().getFactionTag(tag);\n\t\tif(tagRef==null)\n\t\t\treturn "";\n\t\tif(tagRef.maskPrefix!=null)\n\t\t{\n\t\t\tfinal int number=CMath.s_int(getTagValue(tagRef.name()));\n\t\t\tfinal StringBuffer str=new StringBuffer("");\n\t\t\tfor(int i=0;i<number;i++)\n\t\t\t{\n\t\t\t\tfinal String value=getTagValue(tagRef.maskPrefix+i);\n\t\t\t\tstr.append(tagRef.maskPrefix+(i+1)+"="+value+delimeter);\n\t\t\t}\n\t\t\treturn str.toString();\n\t\t}\n\t\treturn tagRef.name()+"="+getTagValue(tag)+delimeter;\n\t}\n\n\t@Override\n\tpublic void updateFactionData(final MOB mob, final FData data)\n\t{\n\t\tdata.resetFactionData(this);\n\t\tfinal List<Ability> aV=new ArrayList<Ability>();\n\t\tfinal List<Behavior> bV=new ArrayList<Behavior>();\n\t\tString ID=null;\n\t\tString[] stuff=null;\n\t\tif(mob.isMonster())\n\t\t{\n\t\t\tfor(final Enumeration<String> e=affectsBehavs();e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tID=e.nextElement();\n\t\t\t\tstuff=getAffectBehav(ID);\n\t\t\t\tif(CMLib.masking().maskCheck(stuff[1],mob,true))\n\t\t\t\t{\n\t\t\t\t\tfinal Behavior B=CMClass.getBehavior(ID);\n\t\t\t\t\tif(B!=null)\n\t\t\t\t\t{\n\t\t\t\t\t\tB.setParms(stuff[0]);\n\t\t\t\t\t\tbV.add(B);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal Ability A=CMClass.getAbility(ID);\n\t\t\t\t\t\tA.setMiscText(stuff[0]);\n\t\t\t\t\t\tA.setAffectedOne(mob);\n\t\t\t\t\t\taV.add(A);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdata.addHandlers(aV,bV);\n\t}\n\n\t@Override\n\tpublic FData makeFactionData(final MOB mob)\n\t{\n\t\tfinal FData data=new DefaultFactionData(this);\n\t\tupdateFactionData(mob,data);\n\t\treturn data;\n\t}\n\n\t@Override\n\tpublic boolean delAffectBehav(final String ID)\n\t{\n\t\tfinal boolean b=affBehavs.remove(ID.toUpperCase().trim())!=null;\n\t\tif(b)\n\t\t\tlastDataChange[0]=System.currentTimeMillis();\n\t\treturn b;\n\t}\n\n\t@Override\n\tpublic boolean addAffectBehav(final String ID, final String parms, final String gainMask)\n\t{\n\t\tif(affBehavs.containsKey(ID.toUpperCase().trim()))\n\t\t\treturn false;\n\t\tif((CMClass.getBehavior(ID)==null)&&(CMClass.getAbility(ID)==null))\n\t\t\treturn false;\n\t\taffBehavs.put(ID.toUpperCase().trim(),new String[]{parms,gainMask});\n\t\tlastDataChange[0]=System.currentTimeMillis();\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic String[] getAffectBehav(final String ID)\n\t{\n\t\tif(affBehavs.containsKey(ID.toUpperCase().trim()))\n\t\t\treturn CMParms.toStringArray(new XVector<String>(affBehavs.get(ID.toUpperCase().trim())));\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean delReaction(final Faction.FReactionItem item)\n\t{\n\t\tfinal CList<Faction.FReactionItem> V=reactionHash.get(item.rangeCodeName().toUpperCase().trim());\n\t\tif(V!=null)\n\t\t\tV.remove(item);\n\t\tfinal boolean res = reactions.remove(item);\n\t\tif(reactions.size()==0)\n\t\t\treactionHash.clear();\n\t\tlastDataChange[0]=System.currentTimeMillis();\n\t\treturn res;\n\t}\n\n\t@Override\n\tpublic boolean addReaction(final String range, final String mask, final String abilityID, final String parms)\n\t{\n\t\tCList<Faction.FReactionItem> V=reactionHash.get(range.toUpperCase().trim());\n\t\tfinal DefaultFactionReactionItem item = new DefaultFactionReactionItem();\n\t\titem.setRangeName(range);\n\t\titem.setPresentMOBMask(mask);\n\t\titem.setReactionObjectID(abilityID);\n\t\titem.setParameters(parms);\n\t\tif(V==null)\n\t\t{\n\t\t\tV=new SVector<Faction.FReactionItem>();\n\t\t\treactionHash.put(range.toUpperCase().trim(), V);\n\t\t}\n\t\tV.add(item);\n\t\treactions.add(item);\n\t\tlastDataChange[0]=System.currentTimeMillis();\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic FactionChangeEvent[] getChangeEvents(final String key)\n\t{\n\t\treturn changes.get(key);\n\t}\n\n\t@Override\n\tpublic List<Integer> findChoices(final MOB mob)\n\t{\n\t\tfinal List<Integer> mine=new Vector<Integer>();\n\t\tString s;\n\t\tfor(final Enumeration<String> e=choices.elements();e.hasMoreElements();)\n\t\t{\n\t\t\ts=e.nextElement();\n\t\t\tif(CMath.isInteger(s))\n\t\t\t\tmine.add(Integer.valueOf(CMath.s_int(s)));\n\t\t\telse\n\t\t\tif(CMLib.masking().maskCheck(s, mob,false))\n\t\t\t{\n\t\t\t\tfinal List<String> V=CMParms.parse(s);\n\t\t\t\tfor(int j=0;j<V.size();j++)\n\t\t\t\t{\n\t\t\t\t\tif(CMath.isInteger(V.get(j)))\n\t\t\t\t\t\tmine.add(Integer.valueOf(CMath.s_int(V.get(j))));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn mine;\n\t}\n\n\tprotected Map<String,Integer> getCMMsgTypeMap()\n\t{\n\t\t@SuppressWarnings("unchecked")\n\t\tMap<String,Integer> msgTypeCache=(Map<String,Integer>)Resources.getResource("SYSTEM_FACTION_GLOBAL_CMMSG_CODES");\n\t\tif(msgTypeCache==null)\n\t\t{\n\t\t\tmsgTypeCache=new HashMap<String,Integer>();\n\t\t\tfor(int typ = 0; typ < CMMsg.TYPE_DESCS.length; typ++)\n\t\t\t\tmsgTypeCache.put("MSG_"+CMMsg.TYPE_DESCS[typ],Integer.valueOf(typ));\n\t\t\tResources.submitResource("SYSTEM_FACTION_GLOBAL_CMMSG_CODES", msgTypeCache);\n\t\t}\n\t\treturn msgTypeCache;\n\t}\n\n\t@Override\n\tpublic FactionChangeEvent[] findMsgChangeEvents(final CMMsg msg)\n\t{\n\t\tif(msgChangeCache.size()==0)\n\t\t{\n\t\t\tfinal Map<String,Integer> msgTypeCache=getCMMsgTypeMap();\n\t\t\tfinal Map<Integer,List<FactionChangeEvent>> msgClassMap=new HashMap<Integer,List<FactionChangeEvent>>();\n\t\t\tfor (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal FactionChangeEvent[] Cs=e.nextElement();\n\t\t\t\tfor(final FactionChangeEvent C : Cs)\n\t\t\t\t{\n\t\t\t\t\tif(msgTypeCache.containsKey(C.eventID()))\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal Integer code=msgTypeCache.get(C.eventID());\n\t\t\t\t\t\tif(!msgClassMap.containsKey(code))\n\t\t\t\t\t\t\tmsgClassMap.put(code, new ArrayList<FactionChangeEvent>());\n\t\t\t\t\t\tmsgClassMap.get(code).add(C);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(final Integer code : msgClassMap.keySet())\n\t\t\t{\n\t\t\t\tfinal List<FactionChangeEvent> list=msgClassMap.get(code);\n\t\t\t\tmsgChangeCache.put(code, list.toArray(new FactionChangeEvent[list.size()]));\n\t\t\t}\n\t\t}\n\t\treturn msgChangeCache.get(Integer.valueOf(msg.sourceMinor()));\n\t}\n\n\t@Override\n\tpublic FactionChangeEvent[] findAbilityChangeEvents(final Ability key)\n\t{\n\t\tif(key==null)\n\t\t\treturn null;\n\t\tif(abilChangeCache.size()==0)\n\t\t{\n\t\t\tif(CMClass.numPrototypes(CMObjectType.ABILITY)==0)\n\t\t\t\treturn null;\n\t\t\tfinal Map<Integer,List<FactionChangeEvent>> abilityClassMap=new HashMap<Integer,List<FactionChangeEvent>>();\n\t\t\tfor(int classificationCode = 0;classificationCode < Ability.ACODE_DESCS.length;classificationCode++)\n\t\t\t{\n\t\t\t\tfor (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)\n\t\t\t\t{\n\t\t\t\t\tfinal FactionChangeEvent[] Cs=e.nextElement();\n\t\t\t\t\tfor(final FactionChangeEvent C : Cs)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(classificationCode==C.IDclassFilter())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(!abilityClassMap.containsKey(Integer.valueOf(classificationCode)))\n\t\t\t\t\t\t\t\tabilityClassMap.put(Integer.valueOf(classificationCode), new ArrayList<FactionChangeEvent>());\n\t\t\t\t\t\t\tabilityClassMap.get(Integer.valueOf(classificationCode)).add(C);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinal Map<Integer,List<FactionChangeEvent>> abilityDomainMap=new HashMap<Integer,List<FactionChangeEvent>>();\n\t\t\tfor(int domainCode = 0;domainCode < Ability.DOMAIN_DESCS.length;domainCode++)\n\t\t\t{\n\t\t\t\tfinal int domainID = domainCode << 5;\n\t\t\t\tfor (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)\n\t\t\t\t{\n\t\t\t\t\tfinal FactionChangeEvent[] Cs=e.nextElement();\n\t\t\t\t\tfor(final FactionChangeEvent C : Cs)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(domainID==C.IDdomainFilter())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(!abilityDomainMap.containsKey(Integer.valueOf(domainID)))\n\t\t\t\t\t\t\t\tabilityDomainMap.put(Integer.valueOf(domainID), new ArrayList<FactionChangeEvent>());\n\t\t\t\t\t\t\tabilityDomainMap.get(Integer.valueOf(domainID)).add(C);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinal Map<Long,List<FactionChangeEvent>> abilityFlagMap=new HashMap<Long,List<FactionChangeEvent>>();\n\t\t\tfor(int flagIndex = 0;flagIndex < Ability.FLAG_DESCS.length;flagIndex++)\n\t\t\t{\n\t\t\t\tfinal long flagMask = Math.round(Math.pow(2, flagIndex));\n\t\t\t\tfor (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)\n\t\t\t\t{\n\t\t\t\t\tfinal FactionChangeEvent[] Cs=e.nextElement();\n\t\t\t\t\tfor(final FactionChangeEvent C : Cs)\n\t\t\t\t\t{\n\t\t\t\t\t\tif((C.IDflagFilter()>0)&&(CMath.bset(C.IDflagFilter(), flagMask)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(!abilityFlagMap.containsKey(Long.valueOf(flagMask)))\n\t\t\t\t\t\t\t\tabilityFlagMap.put(Long.valueOf(flagMask), new ArrayList<FactionChangeEvent>());\n\t\t\t\t\t\t\tabilityFlagMap.get(Long.valueOf(flagMask)).add(C);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(final Enumeration<Ability> a=CMClass.abilities();a.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal Ability A=a.nextElement();\n\t\t\t\tfinal ArrayList<FactionChangeEvent> set=new ArrayList<FactionChangeEvent>(0);\n\t\t\t\tif(changes.containsKey(A.ID()))\n\t\t\t\t\tset.addAll(Arrays.asList(changes.get(A.ID())));\n\t\t\t\tif(abilityClassMap.containsKey(Integer.valueOf(A.classificationCode()&Ability.ALL_ACODES)))\n\t\t\t\t\tset.addAll(abilityClassMap.get(Integer.valueOf(A.classificationCode()&Ability.ALL_ACODES)));\n\t\t\t\tif(abilityDomainMap.containsKey(Integer.valueOf(A.classificationCode()&Ability.ALL_DOMAINS)))\n\t\t\t\t\tset.addAll(abilityDomainMap.get(Integer.valueOf(A.classificationCode()&Ability.ALL_DOMAINS)));\n\t\t\t\tif(A.flags()>0)\n\t\t\t\t{\n\t\t\t\t\tfor(int flagIndex = 0;flagIndex < Ability.FLAG_DESCS.length;flagIndex++)\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal long flagMask = Math.round(Math.pow(2, flagIndex));\n\t\t\t\t\t\tif(CMath.bset(A.flags(), flagMask))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(abilityFlagMap.containsKey(Long.valueOf(flagMask)))\n\t\t\t\t\t\t\t\tset.addAll(abilityFlagMap.get(Long.valueOf(flagMask)));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(set.size()>0)\n\t\t\t\t\tabilChangeCache.put(A.ID(), set.toArray(new FactionChangeEvent[0]));\n\t\t\t}\n\t\t\tif(abilChangeCache.size()==0)\n\t\t\t\tabilChangeCache.put("StdAbility", new FactionChangeEvent[0]);\n\t\t}\n\t\treturn abilChangeCache.get(key.ID());\n\t}\n\n\t@Override\n\tpublic FactionChangeEvent[] findSocialChangeEvents(final Social soc)\n\t{\n\t\tif(soc==null)\n\t\t\treturn null;\n\t\tif(socChangeCache.size()==0)\n\t\t{\n\n\t\t\tfinal Enumeration<Social> s=CMLib.socials().getAllSocials();\n\t\t\tif(s == null)\n\t\t\t\treturn null;\n\t\t\tfor(;s.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal Social S = s.nextElement();\n\t\t\t\tif(changes.containsKey(S.name()))\n\t\t\t\t\tsocChangeCache.put(S.name(), changes.get(S.name()));\n\t\t\t\telse\n\t\t\t\tif(changes.containsKey(S.baseName()+" *"))\n\t\t\t\t\tsocChangeCache.put(S.name(), changes.get(S.baseName()+" *"));\n\t\t\t}\n\t\t\tif(socChangeCache.size()==0)\n\t\t\t\tsocChangeCache.put("DefaultSocial", new FactionChangeEvent[0]);\n\t\t}\n\t\treturn socChangeCache.get(soc.name());\n\t}\n\n\t@Override\n\tpublic Faction.FRange fetchRange(final String codeName)\n\t{\n\t\treturn ranges.get(codeName.toUpperCase().trim());\n\t}\n\n\t@Override\n\tpublic FRange fetchRange(final int faction)\n\t{\n\t\tfinal Integer I=Integer.valueOf(faction);\n\t\tFRange R=rangeRangeMap.get(I);\n\t\tif(R!=null)\n\t\t\treturn R;\n\t\tfor (final Enumeration<FRange> e=ranges.elements();e.hasMoreElements();)\n\t\t{\n\t\t\tR = e.nextElement();\n\t\t\tif ( (faction >= R.low()) && (faction <= R.high()))\n\t\t\t{\n\t\t\t\trangeRangeMap.put(I, R);\n\t\t\t\treturn R;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic String fetchRangeName(final int faction)\n\t{\n\t\tfinal FRange R= fetchRange(faction);\n\t\tif(R!=null)\n\t\t\treturn R.name();\n\t\treturn "";\n\t}\n\n\t@Override\n\tpublic int asPercent(final int faction)\n\t{\n\t\treturn (int)Math.round(CMath.mul(CMath.div(faction-minimum,(maximum-minimum)),100));\n\t}\n\n\t@Override\n\tpublic int asPercentFromAvg(final int faction)\n\t{\n\t\t// =(( (B2+A2) / 2 ) - C2) / (B2-A2) * 100\n\t\t// C = current, A = min, B = Max\n\t\treturn (int)Math.round(CMath.mul(CMath.div(((maximum+minimum)/2)-faction,maximum-minimum),100));\n\t}\n\n\t@Override\n\tpublic int randomFaction()\n\t{\n\t\tfinal Random gen = new Random();\n\t\treturn maximum - gen.nextInt(maximum-minimum);\n\t}\n\n\t@Override\n\tpublic int findDefault(final MOB mob)\n\t{\n\t\tString s;\n\t\tfor(final Enumeration<String> e=defaults.elements();e.hasMoreElements();)\n\t\t{\n\t\t\ts=e.nextElement();\n\t\t\tif(CMath.isNumber(s))\n\t\t\t\treturn CMath.s_int(s);\n\t\t\telse\n\t\t\tif(CMLib.masking().maskCheck(s, mob,false))\n\t\t\t{\n\t\t\t\tfinal Vector<String> V=CMParms.parse(s);\n\t\t\t\tfor(int j=0;j<V.size();j++)\n\t\t\t\t{\n\t\t\t\t\tif(CMath.isNumber(V.elementAt(j)))\n\t\t\t\t\t\treturn CMath.s_int(V.elementAt(j));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic int findAutoDefault(final MOB mob)\n\t{\n\t\tString s;\n\t\tfor(final Enumeration<String> e=autoDefaults.elements();e.hasMoreElements();)\n\t\t{\n\t\t\ts=e.nextElement();\n\t\t\tif(CMath.isNumber(s))\n\t\t\t\treturn CMath.s_int(s);\n\t\t\telse\n\t\t\tif(CMLib.masking().maskCheck(s, mob,false))\n\t\t\t{\n\t\t\t\tfinal Vector<String> V=CMParms.parse(s);\n\t\t\t\tfor(int j=0;j<V.size();j++)\n\t\t\t\t{\n\t\t\t\t\tif(CMath.isNumber(V.elementAt(j)))\n\t\t\t\t\t\treturn CMath.s_int(V.elementAt(j));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn Integer.MAX_VALUE;\n\t}\n\n\t@Override\n\tpublic boolean hasFaction(final MOB mob)\n\t{\n\t\treturn (mob.fetchFaction(_factionID)!=Integer.MAX_VALUE);\n\t}\n\n\tprotected FAbilityUsage getAbilityUsage(final Ability A)\n\t{\n\t\tif(A==null)\n\t\t\treturn null;\n\t\tif(abilityUseCache.containsKey(A.ID()))\n\t\t\treturn abilityUseCache.get(A.ID());\n\t\tif(abilityUseMisses.contains(A.ID()))\n\t\t\treturn null;\n\n\t\tfor(final FAbilityUsage usage : abilityUsages)\n\t\t{\n\t\t\tif(usage.possibleAbilityID()\n\t\t\t&&(!usage.abilityFlags().equalsIgnoreCase(A.ID())))\n\t\t\t\tcontinue;\n\n\t\t\tif(usage.possibleAbilityID()\n\t\t\t||(((usage.type()<0)||((A.classificationCode()&Ability.ALL_ACODES)==usage.type()))\n\t\t\t\t&&((usage.flag()<0)||(CMath.bset(A.flags(),usage.flag())))\n\t\t\t\t&&((usage.notflag()<0)||(!CMath.bset(A.flags(),usage.notflag())))\n\t\t\t\t&&((usage.domain()<0)||((A.classificationCode()&Ability.ALL_DOMAINS)==usage.domain()))))\n\t\t\t{\n\t\t\t\tabilityUseCache.put(A.ID(), usage);\n\t\t\t\treturn usage;\n\t\t\t}\n\t\t}\n\t\tabilityUseMisses.add(A.ID());\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean hasUsage(final Ability A)\n\t{\n\t\treturn getAbilityUsage(A) != null;\n\t}\n\n\t@Override\n\tpublic boolean canUse(final MOB mob, final Ability A)\n\t{\n\t\tfinal FAbilityUsage usage = this.getAbilityUsage(A);\n\t\tif(usage == null)\n\t\t\treturn true;\n\t\tfinal int faction=mob.fetchFaction(_factionID);\n\t\tif((faction < usage.low()) || (faction > usage.high()))\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic double findFactor(final MOB mob, final boolean gain)\n\t{\n\t\tfor(final Faction.FZapFactor factor : factors)\n\t\t{\n\t\t\tif(CMLib.masking().maskCheck(factor.compiledMOBMask(),mob,false))\n\t\t\t\treturn gain?factor.gainFactor():factor.lossFactor();\n\t\t}\n\t\treturn 1.0;\n\t}\n\n\tprivate boolean checkApplyEventWait(final FactionChangeEvent event, final MOB mob)\n\t{\n\t\tfinal Faction.FData data = mob.fetchFactionData(factionID());\n\t\tif(data != null)\n\t\t{\n\t\t\tif(System.currentTimeMillis() < data.getNextChangeTimers(event))\n\t\t\t\treturn false;\n\t\t\tfinal long newTime=event.getWaitBetweenMs();\n\t\t\tif(newTime > 0)\n\t\t\t\tdata.setNextChangeTimers(event, System.currentTimeMillis()+newTime);\n\t\t}\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void executeMsg(final Environmental myHost, final CMMsg msg)\n\t{\n\t\tFactionChangeEvent[] events;\n\t\tswitch(msg.sourceMinor())\n\t\t{\n\t\tcase CMMsg.TYP_ENTER:\n\t\t{\n\t\t\tif((msg.source() == myHost)\n\t\t\t&&(msg.source().isPlayer())\n\t\t\t&&(msg.target() instanceof Room))\n\t\t\t{\n\t\t\t\tevents=getChangeEvents(MiscTrigger.AREAEXPLORE.toString());\n\t\t\t\tif(events != null)\n\t\t\t\t{\n\t\t\t\t\tfinal Room R=(Room)msg.target();\n\t\t\t\t\tif(!msg.source().playerStats().hasVisited(R))\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal Area A=R.getArea();\n\t\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(event.applies(msg.source(),msg.source()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfinal int pct = CMath.s_int(event.getTriggerParm("PCT"));\n\t\t\t\t\t\t\t\tif(pct==0)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif(msg.source().playerStats().totalVisitedRooms(msg.source(), A)>0)\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif(msg.source().playerStats().percentVisited(msg.source(),A) < pct)\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(this.checkApplyEventWait(event, msg.source()))\n\t\t\t\t\t\t\t\t\texecuteChange(msg.source(),msg.source(),event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase CMMsg.TYP_DEATH:\n\t\t\tif((msg.source()==myHost)||(msg.tool()==myHost))\n\t\t\t{\n\t\t\t\tfinal MOB killedM=msg.source();\n\t\t\t\tif(msg.tool() instanceof MOB)\n\t\t\t\t{\n\t\t\t\t\tfinal MOB killingBlowM=(MOB)msg.tool();\n\t\t\t\t\tevents=getChangeEvents(((msg.source()==myHost)?MiscTrigger.MURDER:MiscTrigger.KILL).toString());\n\t\t\t\t\tif(events!=null)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(event.applies(killingBlowM,killedM))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfinal CharClass combatCharClass=CMLib.combat().getCombatDominantClass(killingBlowM,killedM);\n\t\t\t\t\t\t\t\tfinal Set<MOB> combatBeneficiaries=CMLib.combat().getCombatBeneficiaries(killingBlowM,killedM,combatCharClass);\n\t\t\t\t\t\t\t\tfor (final MOB mob : combatBeneficiaries)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif(checkApplyEventWait(event, mob))\n\t\t\t\t\t\t\t\t\t\texecuteChange(mob,killedM,event);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfinal Room R = msg.source().location();\n\t\t\t\t\tif((R!=null)&&(R.getArea()!=null))\n\t\t\t\t\t{\n\t\t\t\t\t\tevents=getChangeEvents(MiscTrigger.AREAASS.toString());\n\t\t\t\t\t\tif((events!=null)\n\t\t\t\t\t\t&&(killedM!=null)\n\t\t\t\t\t\t&&(killedM.phyStats().level()==R.getArea().getAreaIStats()[Area.Stats.MAX_LEVEL.ordinal()])\n\t\t\t\t\t\t&&(killingBlowM!=killedM)\n\t\t\t\t\t\t&&(killedM.isMonster())\n\t\t\t\t\t\t&&(killedM.getStartRoom()!=null)\n\t\t\t\t\t\t&&(killedM.location()!=null)\n\t\t\t\t\t\t&&(killedM.getStartRoom().getArea()==killingBlowM.location().getArea()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfinal Area A=R.getArea();\n\t\t\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfinal CharClass combatCharClass=CMLib.combat().getCombatDominantClass(killingBlowM,killedM);\n\t\t\t\t\t\t\t\tfinal Set<MOB> combatBeneficiaries=CMLib.combat().getCombatBeneficiaries(killingBlowM,killedM,combatCharClass);\n\t\t\t\t\t\t\t\tfinal int pct = CMath.s_int(event.getTriggerParm("PCT"));\n\t\t\t\t\t\t\t\tfor (final MOB mob : combatBeneficiaries)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif(mob.isPlayer())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif(event.applies(mob,killedM))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tfinal double population = A.getAreaIStats()[Area.Stats.MAX_LEVEL_MOBS.ordinal()];\n\t\t\t\t\t\t\t\t\t\t\tfinal Faction.FData data = mob.fetchFactionData(factionID());\n\t\t\t\t\t\t\t\t\t\t\tfinal int count = data.getCounter(""+event)+1;\n\t\t\t\t\t\t\t\t\t\t\tdata.setCounter(""+event, count);\n\t\t\t\t\t\t\t\t\t\t\tfinal int myPct = (int)Math.round(100.0*CMath.div(count, population));\n\t\t\t\t\t\t\t\t\t\t\tif(myPct < pct)\n\t\t\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t\t\tif(checkApplyEventWait(event, mob))\n\t\t\t\t\t\t\t\t\t\t\t\texecuteChange(mob,killedM,event);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tevents=getChangeEvents(MiscTrigger.AREAKILL.toString());\n\t\t\t\t\t\tif((events!=null)\n\t\t\t\t\t\t&&(killedM!=null)\n\t\t\t\t\t\t&&(killingBlowM!=killedM)\n\t\t\t\t\t\t&&(killedM.isMonster())\n\t\t\t\t\t\t&&(killedM.getStartRoom()!=null)\n\t\t\t\t\t\t&&(killedM.location()!=null)\n\t\t\t\t\t\t&&(killedM.getStartRoom().getArea()==killedM.location().getArea()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfinal Area A=R.getArea();\n\t\t\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfinal int pct = CMath.s_int(event.getTriggerParm("PCT"));\n\t\t\t\t\t\t\t\tfinal CharClass combatCharClass=CMLib.combat().getCombatDominantClass(killingBlowM,killedM);\n\t\t\t{\r\n\t\t\t\tif((msg.target()==myHost)\t// Arrested watching\r\n\t\t\t\t&&(msg.source().isMonster())\r\n\t\t\t\t&&(msg.tool().ID().equals("Skill_HandCuff")))\r\n\t\t\t\t{\r\n\t\t\t\t\tfinal Room R=msg.source().location();\r\n\t\t\t\t\tif((R!=null)&&(R.getArea()!=null))\r\n\t\t\t\t\t\t\t\t\t\t\tfinal double population = A.getAreaIStats()[Area.Stats.POPULATION.ordinal()];\n\t\t\t\t\t\t\t\t\t\t\tfinal int count = data.getCounter(""+event)+1;\n\t\t\t\t\t\t\t\t\t\t\tdata.setCounter(""+event, count);\n\t\t\t\t\t\t\t\t\t\t\tfinal int myPct = (int)Math.round(100.0*CMath.div(count, population));\n\t\t\t\t\t\t\t\t\t\t\tif(myPct < pct)\n\t\t\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t\t\tif(checkApplyEventWait(event, mob))\n\t\t\t\t\t\t\t\t\t\t\t\texecuteChange(mob,killedM,event);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(msg.source()==myHost)\n\t\t\t\t{\n\t\t\t\t\tevents=getChangeEvents(MiscTrigger.DYING.toString());\n\t\t\t\t\tif(events!=null)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(event.applies(killedM,killedM))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif(checkApplyEventWait(event, killedM))\n\t\t\t\t\t\t\t\t\texecuteChange(killedM,killedM,event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase CMMsg.TYP_CAUSESINK:\n\t\t\tif((myHost instanceof MOB)\n\t\t\t&&(msg.target() instanceof Boardable))\n\t\t\t{\n\t\t\t\tfinal MOB killerM=msg.source();\n\t\t\t\tfinal Area shipArea=((Boardable)msg.target()).getArea();\n\t\t\t\tif(CMLib.map().areaLocation(killerM)==shipArea)\n\t\t\t\t\tevents=getChangeEvents(MiscTrigger.SUNK.toString());\n\t\t\t\telse\n\t\t\t\tif(killerM == myHost)\n\t\t\t\t\tevents=getChangeEvents(MiscTrigger.SINK.toString());\n\t\t\t\telse\n\t\t\t\t\tevents=null;\n\t\t\t\tif(events!=null)\n\t\t\t\t{\n\t\t\t\t\tfinal MOB targetM=(killerM==myHost)?null:(MOB)myHost;\n\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(event.applies(killerM, targetM))\n\t\t\t\t\t\t\texecuteChange(killerM,targetM,event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase CMMsg.TYP_GIVE:\n\t\t\tif((msg.source()==myHost)\n\t\t\t&&(msg.tool() instanceof Coins)\n\t\t\t&&(msg.target() instanceof MOB)\n\t\t\t&&(!(msg.target() instanceof ShopKeeper))\n\t\t\t)\n\t\t\t{\n\t\t\t\tevents=getChangeEvents(MiscTrigger.BRIBE.toString());\n\t\t\t\tif(events!=null)\n\t\t\t\t{\n\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(event.applies(msg.source(),(MOB)msg.target()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble amount=CMath.s_double(event.getTriggerParm("AMOUNT"));\n\t\t\t\t\t\t\tfinal double pctAmount = CMath.s_pct(event.getTriggerParm("PCT"))\n\t\t\t\t\t\t\t\t\t\t\t * CMLib.beanCounter().getTotalAbsoluteNativeValue((MOB)msg.target());\n\t\t\t\t\t\t\tif(pctAmount>amount)\n\t\t\t\t\t\t\t\tamount=pctAmount;\n\t\t\t\t\t\t\tif(amount==0)\n\t\t\t\t\t\t\t\tamount=1.0;\n\t\t\t\t\t\t\tif(((Coins)msg.tool()).getTotalValue()>=amount)\n\t\t\t\t\t\t\t\texecuteChange(msg.source(),(MOB)msg.target(),event);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase CMMsg.TYP_TEACH:\n\t\tcase CMMsg.TYP_CHANNEL:\n\t\t\t// don\'t do the defaults!\n\t\t\tbreak;\n\t\tcase CMMsg.TYP_SPEAK:\n\t\t\tif((msg.othersMessage()!=null)\n\t\t\t&&(msg.source()==myHost))\n\t\t\t{\n\t\t\t\tevents=getChangeEvents(MiscTrigger.TALK.toString());\n\t\t\t\tif((events!=null)&&(events.length>0))\n\t\t\t\t{\n\t\t\t\t\tfinal Room R=msg.source().location();\n\t\t\t\t\tfinal List<MOB> targets=new ArrayList<MOB>();\n\t\t\t\t\tif(msg.target() instanceof MOB)\n\t\t\t\t\t\ttargets.add((MOB)msg.target());\n\t\t\t\t\telse\n\t\t\t\t\tfor(int m=0;m<R.numInhabitants();m++)\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal MOB M=R.fetchInhabitant(m);\n\t\t\t\t\t\tif((M!=null)&&(M.isMonster())\n\t\t\t\t\t\t&&(CMLib.flags().canBeHeardSpeakingBy(msg.source(),M))\n\t\t\t\t\t\t&&(M.amFollowing()!=msg.source()))\n\t\t\t\t\t\t\ttargets.add(M);\n\t\t\t\t\t}\n\t\t\t\t\tfinal String sayMsg=CMStrings.getSayFromMessage(msg.othersMessage().toLowerCase());\n\t\t\t\t\tMatcher M=null;\n\t\t\t\t\tif((sayMsg!=null)&&(sayMsg.length()>0)&&(R!=null))\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal MOB mob=msg.source();\n\t\t\t\t\t\tfinal Faction.FData data = mob.fetchFactionData(factionID());\n\t\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tPattern P=(Pattern)event.stateVariable(0);\n\t\t\t\t\t\t\tif(P==null)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tString mask=event.getTriggerParm("REGEX");\n\t\t\t\t\t\t\t\tif((mask==null)||(mask.trim().length()==0))\n\t\t\t\t\t\t\t\t\tmask=".*";\n\t\t\t\t\t\t\t\tP=Pattern.compile(mask.toLowerCase());\n\t\t\t\t\t\t\t\tevent.setStateVariable(0,P);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tM=P.matcher(sayMsg);\n\t\t\t\t\t\t\tif(M.matches())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif((data != null) && (System.currentTimeMillis() < data.getNextChangeTimers(event)))\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\tboolean foundOne=false;\n\t\t\t\t\t\t\t\tfor(final MOB target : targets)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif(event.applies(mob,target))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\texecuteChange(mob,target,event);\n\t\t\t\t\t\t\t\t\t\tfoundOne=true;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(foundOne)\n\t\t\t\t\t\t\t\t\tcheckApplyEventWait(event, mob);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tevents=getChangeEvents(MiscTrigger.MUDCHAT.toString());\n\t\t\t\tif((events!=null)&&(events.length>0))\n\t\t\t\t{\n\t\t\t\t\tfinal Room R=msg.source().location();\n\t\t\t\t\tfinal List<MOB> targets=new ArrayList<MOB>();\n\t\t\t\t\tif(msg.target() instanceof MOB)\n\t\t\t\t\t\ttargets.add((MOB)msg.target());\n\t\t\t\t\telse\n\t\t\t\t\tfor(int m=0;m<R.numInhabitants();m++)\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal MOB M=R.fetchInhabitant(m);\n\t\t\t\t\t\tif((M!=null)&&(M.isMonster())\n\t\t\t\t\t\t&&(CMLib.flags().canBeHeardSpeakingBy(msg.source(),M))\n\t\t\t\t\t\t&&(M.amFollowing()!=msg.source()))\n\t\t\t\t\t\t\ttargets.add(M);\n\t\t\t\t\t}\n\t\t\t\t\tboolean foundOne=false;\n\t\t\t\t\tfor(final MOB target : targets)\n\t\t\t\t\t{\n\t\t\t\t\t\tChattyBehavior mudChatB=null;\n\t\t\t\t\t\tBehavior B=null;\n\t\t\t\t\t\tfor(final Enumeration<Behavior> e=target.behaviors();e.hasMoreElements();)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tB=e.nextElement();\n\t\t\t\t\t\t\tif(B instanceof ChattyBehavior)\n\t\t\t\t\t\t\t\tmudChatB=(ChattyBehavior)B;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(mudChatB!=null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfinal String sayMsg=CMStrings.getSayFromMessage(msg.othersMessage().toLowerCase());\n\t\t\t\t\t\t\tif((sayMsg!=null)&&(sayMsg.length()>0))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfinal MOB mob=msg.source();\n\t\t\t\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif(event.applies(mob,target))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif((mudChatB.getLastRespondedTo()==mob)\n\t\t\t\t\t\t\t\t\t\t&&(mudChatB.getLastThingSaid()!=null)\n\t\t\t\t\t\t\t\t\t\t&&(!mudChatB.getLastThingSaid().equalsIgnoreCase(sayMsg)))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif(checkApplyEventWait(event, mob))\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\texecuteChange(mob,target,event);\n\t\t\t\t\t\t\t\t\t\t\t\tfoundOne=true;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(foundOne)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif((events=findMsgChangeEvents(msg))!=null)\n\t\t\t{\n\t\t\t\tfinal EnglishParsing elib=CMLib.english();\n\t\t\t\tfor (final FactionChangeEvent C : events)\n\t\t\t\t{\n\t\t\t\t\tfinal MOB target;\n\t\t\t\t\tif((msg.target() instanceof MOB)\n\t\t\t\t\t&&(C.applies(msg.source(),(MOB)msg.target())))\n\t\t\t\t\t\ttarget=(MOB)msg.target();\n\t\t\t\t\telse\n\t\t\t\t\tif((!(msg.target() instanceof MOB))\n\t\t\t\t\t&&(C.applies(msg.source(), null)))\n\t\t\t\t\t\ttarget=null;\n\t\t\t\t\telse\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tString s;\n\t\t\t\t\ts=C.getTriggerParm("SMSG");\n\t\t\t\t\tif((s.length()>0)&&((msg.sourceMessage()==null)||(!elib.containsString(msg.sourceMessage(), s))))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\ts=C.getTriggerParm("TMSG");\n\t\t\t\t\tif((s.length()>0)&&((msg.targetMessage()==null)||(!elib.containsString(msg.targetMessage(), s))))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\ts=C.getTriggerParm("OMSG");\n\t\t\t\t\tif((s.length()>0)&&((msg.othersMessage()==null)||(!elib.containsString(msg.othersMessage(), s))))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\ts=C.getTriggerParm("SRC");\n\t\t\t\t\tif(s.length()>0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(s.equalsIgnoreCase("me") && (msg.source()!=myHost))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tif(!elib.containsString(msg.source().Name(), s))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\ts=C.getTriggerParm("TGT");\n\t\t\t\t\tif(s.length()>0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(s.equalsIgnoreCase("me") && (msg.target()!=myHost))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tif((msg.target()==null)||(!elib.containsString(msg.target().Name(), s)))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\ts=C.getTriggerParm("OTH");\n\t\t\t\t\tif(s.length()>0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(s.equalsIgnoreCase("me") && (msg.tool()!=myHost))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tif((msg.tool()==null)||(!elib.containsString(msg.tool().Name(), s)))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif(checkApplyEventWait(C, msg.source()))\n\t\t\t\t\t\texecuteChange(msg.source(),target,C);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(msg.tool() instanceof Ability)\n\t\t\t{\n\t\t\t\tif((msg.target()==myHost)\t// Arrested watching\n\t\t\t\t&&(msg.source().isMonster())\n\t\t\t\t&&(msg.tool().ID().equals("Skill_HandCuff"))\n\t\t\t\t&&(msg.sourceMinor()!=CMMsg.TYP_TEACH))\n\t\t\t\t{\n\t\t\t\t\tfinal Room R=msg.source().location();\n\t\t\t\t\tif((R!=null)&&(R.getArea()!=null))\n\t\t\t\t\t{\n\t\t\t\t\t\tevents=getChangeEvents(MiscTrigger.ARRESTED.toString());\n\t\t\t\t\t\tif(events!=null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfinal LegalBehavior B=CMLib.law().getLegalBehavior(R);\n\t\t\t\t\t\t\tif((B!=null)&&(B.isAnyOfficer(R.getArea(), msg.source())))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// reversed because the target is the one getting factioned\n\t\t\t\t\t\t\t\t\tif(event.applies(msg.source(),(MOB)msg.target()))\n\t\t\t\t\t\t\t\t\t\texecuteChange((MOB)msg.target(),msg.source(),event);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif((msg.othersMessage()!=null)\n\t\t\t\t&&(msg.source()==myHost)\n\t\t\t\t&&((events=findAbilityChangeEvents((Ability)msg.tool()))!=null))\n\t\t\t\t{\n\t\t\t\t\tfor (final FactionChangeEvent C : events)\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal MOB target;\n\t\t\t\t\t\tif((msg.target() instanceof MOB)&&(C.applies(msg.source(),(MOB)msg.target())))\n\t\t\t\t\t\t\ttarget=(MOB)msg.target();\n\t\t\t\t\t\telse\n\t\t\t\t\t\tif (!(msg.target() instanceof MOB))\n\t\t\t\t\t\t\ttarget=null;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tif(checkApplyEventWait(C, msg.source()))\n\t\t\t\t\t\t\texecuteChange(msg.source(),target,C);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\tif((msg.tool() instanceof Social)\t\t// socials\n\t\t\t&&(msg.source()==myHost)\n\t\t\t&&(msg.target() instanceof MOB)\n\t\t\t&&(((Social)msg.tool()).targetable(msg.source()))\n\t\t\t&&(msg.sourceMinor()!=CMMsg.TYP_CHANNEL))\n\t\t\t{\n\t\t\t\tevents=getChangeEvents(MiscTrigger.SOCIAL.toString());\n\t\t\t\tif(events == null)\n\t\t\t\t\tevents=findSocialChangeEvents((Social)msg.tool());\n\t\t\t\tif(events!=null)\n\t\t\t\t{\n\t\t\t\t\tfinal Social social = (Social)msg.tool();\n\t\t\t\t\tfinal String socialName = social.baseName();\n\t\t\t\t\tfinal MOB mob=msg.source();\n\t\t\t\t\tfor (final FactionChangeEvent event : events)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(event.miscEvent()==MiscTrigger.SOCIAL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfinal String triggerID=event.getTriggerParm("ID");\n\t\t\t\t\t\t\tif(triggerID.length()==0)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\tif(!socialName.equals(triggerID)\n\t\t\t\t\t\t\t&&(!triggerID.equalsIgnoreCase("ALL")))\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif((event.applies(mob,(MOB)msg.target())))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(checkApplyEventWait(event, mob))\n\t\t\t\t\t\t\t\texecuteChange(mob,(MOB)msg.target(),event);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean okMessage(final Environmental myHost, final CMMsg msg)\n\t{\n\t\tif(((msg.sourceMinor()==CMMsg.TYP_EXPCHANGE)  // Experience is being altered\n\t\t\t||(msg.sourceMinor()==CMMsg.TYP_RPXPCHANGE))\n\t\t&&(msg.target() instanceof MOB) \t\t  // because a mob died\n\t\t&&(myHost==msg.source())\t  // this Faction is on the mob that killed them\n\t\t&&(!experienceFlag.equals("NONE"))\n\t\t&&(msg.value()>0))\n\t\t{\n\t\t\tfinal MOB killer=msg.source();\n\t\t\tfinal MOB vic=(MOB)msg.target();\n\n\t\t\tif(experienceFlag.equals("HIGHER"))\n\t\t\t\tmsg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(killer.fetchFaction(_factionID)-minimum),(maximum - minimum)))));\n\t\t\telse\n\t\t\tif(experienceFlag.equals("LOWER"))\n\t\t\t\tmsg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(maximum-killer.fetchFaction(_factionID)),(maximum - minimum)))));\n\t\t\telse\n\t\t\tif(vic.fetchFaction(_factionID)!=Integer.MAX_VALUE)\n\t\t\t{\n\t\t\t\tif(experienceFlag.equals("EXTREME"))\n\t\t\t\t\tmsg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(vic.fetchFaction(_factionID) - killer.fetchFaction(_factionID)),(maximum - minimum)))));\n\t\t\t\telse\n\t\t\t\tif(experienceFlag.equals("FOLLOWHIGHER"))\n\t\t\t\t\tmsg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(vic.fetchFaction(_factionID)-minimum),(maximum - minimum)))));\n\t\t\t\telse\n\t\t\t\tif(experienceFlag.equals("FOLLOWLOWER"))\n\t\t\t\t\tmsg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(maximum-vic.fetchFaction(_factionID)),(maximum - minimum)))));\n\t\t\t\tif(msg.value()<=0)\n\t\t\t\t\tmsg.setValue(0);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void executeChange(final MOB source, MOB target, final FactionChangeEvent event)\n\t{\n\t\tfinal int sourceFaction= source.fetchFaction(_factionID);\n\t\tint targetFaction = sourceFaction * -1;\n\t\tif((source==target)\n\t\t&&(!event.selfTargetOK())\n\t\t&&(event.miscEvent() != MiscTrigger.TIME))\n\t\t\treturn;\n\n\t\tif(target!=null)\n\t\t{\n\t\t\tif(hasFaction(target))\n\t\t\t\ttargetFaction=target.fetchFaction(_factionID);\n\t\t\telse\n\t\t\tif(!event.outsiderTargetOK())\n\t\t\t\treturn;\n\t\t}\n\t\telse\n\t\t\ttarget = source;\n\n\t\tif((event.getPctChance()<100)\n\t\t&&(event.getPctChance()>0)\n\t\t&& (CMLib.dice().rollPercentage()<event.getPctChance()))\n\t\t\treturn;\n\n\t\tdouble baseChangeAmount=100.0;\n\t\tif((source!=target)\n\t\t&&(!event.just100()))\n\t\t{\n\t\t\tfinal int levelLimit=CMProps.getIntVar(CMProps.Int.EXPRATE);\n\t\t\tfinal int levelDiff=target.phyStats().level()-source.phyStats().level();\n\n\t\t\tif(levelDiff<(-levelLimit) )\n\t\t\t\tbaseChangeAmount=0.0;\n\t\t\telse\n\t\t\tif(levelLimit>0)\n\t\t\t{\n\t\t\t\tdouble levelFactor=CMath.div(levelDiff,levelLimit);\n\t\t\t\tif(levelFactor> (levelLimit))\n\t\t\t\t\tlevelFactor=(levelLimit);\n\t\t\t\tbaseChangeAmount=baseChangeAmount+CMath.mul(levelFactor,100);\n\t\t\t}\n\t\t}\n\t\tif(event.getBonusXP()!=0)\n\t\t\tCMLib.leveler().postExperience(source, target, "", event.getBonusXP(), false);\n\t\tif(event.getBonusRoleplayXP()!=0)\n\t\t\tCMLib.leveler().postRPExperience(source, target, "", event.getBonusRoleplayXP(), true);\n\n\t\tfinal String resetTimerEventID = event.getFlagValue("RESTIME");\n\t\tif(resetTimerEventID.length()>0)\n\t\t{\n\t\t\tfor(String resEventID : CMParms.parseCommas(resetTimerEventID, true))\n\t\t\t{\n\t\t\t\tfinal Integer which;\n\t\t\t\tfinal int x=resEventID.indexOf(\'.\');\n\t\t\t\tif(x>0)\n\t\t\t\t{\n\t\t\t\t\twhich=Integer.valueOf(CMath.s_int(resEventID.substring(x+1)));\n\t\t\t\t\tresEventID=resEventID.substring(0,x);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\twhich=null;\n\t\t\t\tfinal boolean reset;\n\t\t\t\tFaction.FactionChangeEvent[] events;\n\t\t\t\tif(resetTimerEventID.startsWith("-"))\n\t\t\t\t{\n\t\t\t\t\treset=false;\n\t\t\t\t\tevents = getChangeEvents(resEventID.substring(1));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tevents = getChangeEvents(resEventID);\n\t\t\t\t\treset=true;\n\t\t\t\t}\n\t\t\t\tif(events != null)\n\t\t\t\t{\n\t\t\t\t\tif((which != null)\n\t\t\t\t\t&&(events.length>=which.intValue())\n\t\t\t\t\t&&(which.intValue()>0))\n\t\t\t\t\t\tevents=new Faction.FactionChangeEvent[] { events[which.intValue()-1] };\n\t\t\t\t\tfinal Faction.FData sdata = source.fetchFactionData(factionID());\n\t\t\t\t\tfinal Faction.FData tdata = target.fetchFactionData(factionID());\n\t\t\t\t\tfor(final Faction.FactionChangeEvent event2 : events)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(sdata != null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(reset)\n\t\t\t\t\t\t\t\tsdata.resetEventTimers(event2.eventID());\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tsdata.setNextChangeTimers(event2, Long.MAX_VALUE);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(tdata != null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(reset)\n\t\t\t\t\t\t\t\ttdata.resetEventTimers(event2.eventID());\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\ttdata.setNextChangeTimers(event2, Long.MAX_VALUE);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tint factionAdj=1;\n\t\tint changeDir=0;\n\t\tswitch(event.direction())\n\t\t{\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_MAXIMUM:\n\t\t\tfactionAdj=maximum-sourceFaction;\n\t\t\tbreak;\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_MINIMUM:\n\t\t\tfactionAdj=minimum-sourceFaction;\n\t\t\tbreak;\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_UP:\n\t\t\tchangeDir=1;\n\t\t\tbreak;\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_DOWN:\n\t\t\tchangeDir=-1;\n\t\t\tbreak;\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_OPPOSITE:\n\t\t\tif(source!=target)\n\t\t\t{\n\t\t\t\tif(targetFaction==middle)\n\t\t\t\t\tchangeDir=(sourceFaction>middle)?1:-1;\n\t\t\t\telse\n\t\t\t\t\tchangeDir=(targetFaction>middle)?-1:1;\n\t\t\t\tif((sourceFaction>middle)&&(targetFaction>middle))\n\t\t\t\t\tchangeDir=-1;\n\t\t\t\tbaseChangeAmount=CMath.div(baseChangeAmount,2.0)\n\t\t\t\t\t\t\t\t+(int)Math.round(CMath.div(baseChangeAmount,2.0)\n\t\t\t\t\t\t\t\t\t\t*Math.abs((sourceFaction-targetFaction)\n\t\t\t\t\t\t\t\t\t\t\t\t/Math.abs((double)difference)));\n\t\t\t}\n\t\t\telse\n\t\t\t\tfactionAdj=0;\n\t\t\tbreak;\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_AWAY:\n\t\t\tif(source!=target)\n\t\t\t\tchangeDir=targetFaction>=sourceFaction?-1:1;\n\t\t\telse\n\t\t\t\tfactionAdj=0;\n\t\t\tbreak;\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_TOWARD:\n\t\t\tif(source!=target)\n\t\t\t\tchangeDir=targetFaction>=sourceFaction?1:-1;\n\t\t\telse\n\t\t\t\tfactionAdj=0;\n\t\t\tbreak;\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_REMOVE:\n\t\t\tfactionAdj=Integer.MAX_VALUE;\n\t\t\tbreak;\n\t\tcase FactionChangeEvent.CHANGE_DIRECTION_ADD:\n\t\t\tfactionAdj=findDefault(source);\n\t\t\tif(!hasFaction(source))\n\t\t\t\tsource.addFaction(_factionID,0);\n\t\t\telse\n\t\t\t\tfactionAdj=0;\n\t\t\tbreak;\n\t\t}\n\t\tif(changeDir!=0)\n\t\t{\n\t\t\t//int baseExp=(int)Math.round(theAmount);\n\n\t\t\t// Pardon the completely random seeming 1.42 and 150.\n\t\t\t// They\'re the result of making graphs of scenarios and massaging the formula, nothing more or less.\n\t\t\tif((hasFaction(target))||(event.outsiderTargetOK()))\n\t\t\t\tfactionAdj=changeDir*(int)Math.round(rateModifier*baseChangeAmount);\n\t\t\telse\n\t\t\t\tfactionAdj=0;\n\t\t\tfactionAdj*=event.factor();\n\t\t\tfactionAdj=(int)Math.round(CMath.mul(factionAdj,findFactor(source,(factionAdj>=0))));\n\t\t}\n\n\t\tif((factionAdj==0)&&(event.factor()!=0.0))\n\t\t\treturn;\n\n\t\tfinal String announceMsg = event.getFlagValue("ANNOUNCE");\n\t\tfinal String seenMsg = announceMsg.length()>0 ? announceMsg : null;\n\t\tif(seenMsg != null)\n\t\t{\n\t\t\tfinal List<String> channels=CMLib.channels().getFlaggedChannelNames(ChannelsLibrary.ChannelFlag.FACTIONANNOUNCEMENTS, source);\n\t\t\tif(channels.size()>0)\n\t\t\t{\n\t\t\t\tfinal String msgStr = source.Name()+" ("+name()+"): "+seenMsg;\n\t\t\t\tfor(int i=0;i<channels.size();i++)\n\t\t\t\t\tCMLib.commands().postChannel(channels.get(i),source.clans(),msgStr,true);\n\t\t\t}\n\t\t}\n\t\tCMMsg facMsg=CMClass.getMsg(source,target,null,CMMsg.MASK_ALWAYS|CMMsg.TYP_FACTIONCHANGE,seenMsg,CMMsg.NO_EFFECT,null,CMMsg.NO_EFFECT,_factionID);\n\t\tfacMsg.setValue(factionAdj);\n\t\tfinal Room R=source.location();\n\t\tif(R!=null)\n\t\t{\n\t\t\tif(R.okMessage(source,facMsg))\n\t\t\t{\n\t\t\t\tR.send(source, facMsg);\n\t\t\t\tfactionAdj=facMsg.value();\n\t\t\t\tif((factionAdj!=Integer.MAX_VALUE)&&(factionAdj!=Integer.MIN_VALUE))\n\t\t\t\t{\n\t\t\t\t\t// Now execute the changes on the relation.  We do this AFTER the execution of the first so\n\t\t\t\t\t// that any changes from okMessage are incorporated\n\t\t\t\t\tif(relations.size()>0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor(final Enumeration<String> e=relations.keys();e.hasMoreElements();)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfinal String relID=(e.nextElement());\n\t\t\t\t\t\t\tfacMsg=CMClass.getMsg(source,target,null,CMMsg.MASK_ALWAYS|CMMsg.TYP_FACTIONCHANGE,null,CMMsg.NO_EFFECT,null,CMMsg.NO_EFFECT,relID);\n\t\t\t\t\t\t\tfacMsg.setValue((int)Math.round(CMath.mul(factionAdj, relations.get(relID).doubleValue())));\n\t\t\t\t\t\t\tif(R.okMessage(source,facMsg))\n\t\t\t\t\t\t\t\tR.send(source, facMsg);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\tif((factionAdj==Integer.MAX_VALUE)||(factionAdj==Integer.MIN_VALUE))\n\t\t\tsource.removeFaction(_factionID);\n\t\telse\n\t\t\tsource.adjustFaction(_factionID,factionAdj);\n\t}\n\n\t@Override\n\tpublic String usageFactorRangeDescription(final Ability A)\n\t{\n\t\tfinal StringBuffer rangeStr=new StringBuffer();\n\t\tfinal HashSet<String> namesAdded=new HashSet<String>();\n\t\tfinal FAbilityUsage usage = getAbilityUsage(A);\n\t\tif(usage != null)\n\t\t{\n\t\t\tfor(final Enumeration<FRange> e=ranges();e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal FRange R=e.nextElement();\n\t\t\t\tif((((R.high()<=usage.high())&&(R.high()>=usage.low()))\n\t\t\t\t\t||((R.low()>=usage.low()))&&(R.low()<=usage.high()))\n\t\t\t\t&&(!namesAdded.contains(R.name())))\n\t\t\t\t{\n\t\t\t\t\tnamesAdded.add(R.name());\n\t\t\t\t\tif(rangeStr.length()>0)\n\t\t\t\t\t\trangeStr.append(", ");\n\t\t\t\t\trangeStr.append(R.name());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn rangeStr.toString();\n\t}\n\n\tprivate static String _ALL_TYPES=null;\n\n\t@Override\n\tpublic String ALL_CHANGE_EVENT_TYPES()\n\t{\n\t\tfinal StringBuffer ALL_TYPES=new StringBuffer("");\n\t\tif(_ALL_TYPES!=null)\n\t\t\treturn _ALL_TYPES;\n\t\tfor (final MiscTrigger element : Faction.FactionChangeEvent.MiscTrigger.values())\n\t\t\tALL_TYPES.append(element.name()+", ");\n\t\tfor (final String element : Ability.ACODE_DESCS)\n\t\t\tALL_TYPES.append(element+", ");\n\t\tfor (final String element : Ability.DOMAIN_DESCS)\n\t\t\tALL_TYPES.append(element+", ");\n\t\tfor (final String element : Ability.FLAG_DESCS)\n\t\t\tALL_TYPES.append(element+", ");\n\t\tfinal Set<String> doneSoc=new HashSet<String>();\n\t\tfor(final Enumeration<Social> s = CMLib.socials().getAllSocials();s.hasMoreElements();)\n\t\t{\n\t\t\tfinal Social S=s.nextElement();\n\t\t\tALL_TYPES.append(S.name()).append(", ");\n\t\t\tif(!doneSoc.contains(S.baseName()))\n\t\t\t{\n\t\t\t\tdoneSoc.add(S.baseName());\n\t\t\t\tALL_TYPES.append(S.baseName()+" *, ");\n\t\t\t}\n\t\t}\n\t\t_ALL_TYPES=ALL_TYPES.toString()+" a valid Skill, Spell, Chant, etc. ID.";\n\t\treturn _ALL_TYPES;\n\t}\n\n\t@Override\n\tpublic Faction.FactionChangeEvent createChangeEvent(final String eventKey, final String eventData)\n\t{\n\t\tFaction.FactionChangeEvent event;\n\t\tif(eventData==null)\n\t\t\treturn null;\n\t\tif(eventData.indexOf(\';\')<0)\n\t\t{\n\t\t\tevent=new DefaultFaction.DefaultFactionChangeEvent(this);\n\t\t\tif(!event.setEventID(eventData))\n\t\t\t\treturn null;\n\t\t}\n\t\telse\n\t\t\tevent=new DefaultFaction.DefaultFactionChangeEvent(this,eventKey,eventData);\n\t\tabilChangeCache.clear();\n\t\tsocChangeCache.clear();\n\t\tmsgChangeCache.clear();\n\t\tFaction.FactionChangeEvent[] events=changes.get(event.eventID().toUpperCase().trim());\n\t\tif(events==null)\n\t\t\tevents=new Faction.FactionChangeEvent[0];\n\t\tevents=Arrays.copyOf(events, events.length+1);\n\t\tevents[events.length-1]=event;\n\t\tchanges.put(event.eventID().toUpperCase().trim(), events);\n\t\treturn event;\n\t}\n\n\tprivate boolean replaceEvents(final String key, final Faction.FactionChangeEvent event, final boolean strict)\n\t{\n\t\tfinal Faction.FactionChangeEvent[] events=changes.get(key);\n\t\tif(events==null)\n\t\t\treturn false;\n\t\tfinal Faction.FactionChangeEvent[] nevents=new Faction.FactionChangeEvent[events.length-1];\n\t\tint ne1=0;\n\t\tboolean done=false;\n\t\tfor (final FactionChangeEvent event2 : events)\n\t\t{\n\t\t\tif((strict&&(event2 == event))||((!strict)&&(event2.toString().equals(event.toString()))))\n\t\t\t{\n\t\t\t\tif(nevents.length==0)\n\t\t\t\t\tchanges.remove(key);\n\t\t\t\telse\n\t\t\t\t\tchanges.put(key,nevents);\n\t\t\t\tdone=true;\n\t\t\t}\n\t\t\telse\n\t\t\tif(ne1<nevents.length)\n\t\t\t\tnevents[ne1++]=event2;\n\t\t}\n\t\tif(done)\n\t\t{\n\t\t\tabilChangeCache.clear();\n\t\t\tmsgChangeCache.clear();\n\t\t\tsocChangeCache.clear();\n\t\t}\n\t\treturn done;\n\t}\n\n\t@Override\n\tpublic void clearChangeEvents()\n\t{\n\t\tabilChangeCache.clear();\n\t\tsocChangeCache.clear();\n\t\tchanges.clear();\n\t\tmsgChangeCache.clear();\n\t}\n\n\t@Override\n\tpublic boolean delChangeEvent(final Faction.FactionChangeEvent event)\n\t{\n\t\tfor(final Enumeration<String> e=changes.keys();e.hasMoreElements();)\n\t\t{\n\t\t\tif(replaceEvents(e.nextElement(),event,true))\n\t\t\t{\n\t\t\t\tabilChangeCache.clear();\n\t\t\t\tsocChangeCache.clear();\n\t\t\t\tmsgChangeCache.clear();\n\t\t\t\tmsgChangeCache.clear();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tfor(final Enumeration<String> e=changes.keys();e.hasMoreElements();)\n\t\t{\n\t\t\tif(replaceEvents(e.nextElement(),event,false))\n\t\t\t{\n\t\t\t\tabilChangeCache.clear();\n\t\t\t\tsocChangeCache.clear();\n\t\t\t\tmsgChangeCache.clear();\n\t\t\t\tmsgChangeCache.clear();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic class DefaultFactionChangeEvent implements Faction.FactionChangeEvent\n\t{\n\t\tprivate String\t\teventTriggerID\t= "";\n\t\tprivate MiscTrigger miscEventTrigger= null;\n\t\tprivate String\t\tflagCache\t\t= "";\n\t\tprivate int\t\t\tIDclassFilter\t= -1;\n\t\tprivate long\t\tIDflagFilter\t= -1;\n\t\tprivate int\t\t\tIDdomainFilter\t= -1;\n\t\tprivate int\t\t\tdirection\t\t= 0;\n\t\tprivate double\t\tfactor\t\t\t= 0.0;\n\t\tprivate String\t\ttargetZapperStr\t= "";\n\t\tprivate boolean\t\toutsiderTargetOK= false;\n\t\tprivate boolean\t\tselfTargetOK\t= false;\n\t\tprivate boolean\t\tjust100\t\t\t= false;\n\t\tprivate int\t\t\tbonusXP\t\t\t= 0;\n\t\tprivate int\t\t\tbonusRPXP\t\t= 0;\n\t\tprivate Object[]\tstateVariables\t= new Object[0];\n\t\tprivate String\t\ttriggerParms\t= "";\n\t\tprivate int\t\t\twithinTicks\t\t= -1;\n\t\tprivate long\t\twaitMs\t\t\t= -1;\n\t\tprivate int\t\t\tpctChance\t\t= 100;\n\n\t\tprivate final Faction\tmyFaction;\n\n\t\tprivate Map<String, String>\t\t\t\tflags\t\t\t\t\t= new Hashtable<String, String>();\n\t\tprivate Map<String, String>\t\t\t\tsavedTriggerParms\t\t= new Hashtable<String, String>();\n\t\tprivate MaskingLibrary.CompiledZMask\tcompiledTargetZapper\t= null;\n\t\tprivate MaskingLibrary.CompiledZMask\tcompiledSourceZapper\t= null;\n\n\t\t@Override\n\t\tpublic String eventID()\n\t\t{\n\t\t\treturn eventTriggerID;\n\t\t}\n\n\t\t@Override\n\t\tpublic MiscTrigger miscEvent()\n\t\t{\n\t\t\treturn miscEventTrigger;\n\t\t}\n\n\t\t@Override\n\t\tpublic String flagCache()\n\t\t{\n\t\t\treturn flagCache;\n\t\t}\n\n\t\t@Override\n\t\tpublic int IDclassFilter()\n\t\t{\n\t\t\treturn IDclassFilter;\n\t\t}\n\n\t\t@Override\n\t\tpublic long IDflagFilter()\n\t\t{\n\t\t\treturn IDflagFilter;\n\t\t}\n\n\t\t@Override\n\t\tpublic int IDdomainFilter()\n\t\t{\n\t\t\treturn IDdomainFilter;\n\t\t}\n\n\t\t@Override\n\t\tpublic int direction()\n\t\t{\n\t\t\treturn direction;\n\t\t}\n\n\t\t@Override\n\t\tpublic double factor()\n\t\t{\n\t\t\treturn factor;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getBonusXP()\n\t\t{\n\t\t\treturn bonusXP;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getWithinTicks()\n\t\t{\n\t\t\treturn withinTicks;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getWaitBetweenMs()\n\t\t{\n\t\t\treturn this.waitMs;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getPctChance()\n\t\t{\n\t\t\treturn pctChance;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getBonusRoleplayXP()\n\t\t{\n\t\t\treturn bonusRPXP;\n\t\t}\n\n\t\t@Override\n\t\tpublic String targetZapper()\n\t\t{\n\t\t\treturn targetZapperStr;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean outsiderTargetOK()\n\t\t{\n\t\t\treturn outsiderTargetOK;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean selfTargetOK()\n\t\t{\n\t\t\treturn selfTargetOK;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean just100()\n\t\t{\n\t\t\treturn just100;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setDirection(final int newVal)\n\t\t{\n\t\t\tdirection = newVal;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setFactor(final double newVal)\n\t\t{\n\t\t\tfactor = newVal;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setTargetZapper(final String newVal)\n\t\t{\n\t\t\ttargetZapperStr = newVal;\n\t\t}\n\n\t\t@Override\n\t\tpublic MaskingLibrary.CompiledZMask compiledTargetZapper()\n\t\t{\n\t\t\tif(compiledTargetZapper == null)\n\t\t\t{\n\t\t\t\tif(targetZapperStr.trim().length()>0)\n\t\t\t\t\tcompiledTargetZapper=CMLib.masking().maskCompile(targetZapperStr);\n\t\t\t}\n\t\t\treturn compiledTargetZapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic MaskingLibrary.CompiledZMask compiledSourceZapper()\n\t\t{\n\t\t\tif(compiledSourceZapper == null)\n\t\t\t{\n\t\t\t\tfinal String sourceZapperStr=savedTriggerParms.get("MASK");\n\t\t\t\tif((sourceZapperStr!=null)&&(sourceZapperStr.length()>0))\n\t\t\t\t\tcompiledSourceZapper=CMLib.masking().maskCompile(sourceZapperStr);\n\t\t\t}\n\t\t\treturn compiledSourceZapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getTriggerParm(final String parmName)\n\t\t{\n\t\t\tif((triggerParms==null)||(triggerParms.length()==0))\n\t\t\t\treturn "";\n\t\t\tfinal String S=savedTriggerParms.get(parmName);\n\t\t\tif(S!=null)\n\t\t\t\treturn S;\n\t\t\treturn "";\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString()\n\t\t{\n\t\t\tif(triggerParms.trim().length()>0)\n\t\t\t\treturn eventTriggerID+"("+triggerParms.replace(\';\',\',\')+");"+CHANGE_DIRECTION_DESCS[direction]+";"+((int)Math.round(factor*100.0))+"%;"+flagCache+";"+targetZapperStr;\n\t\t\telse\n\t\t\t\treturn eventTriggerID+";"+CHANGE_DIRECTION_DESCS[direction]+";"+((int)Math.round(factor*100.0))+"%;"+flagCache+";"+targetZapperStr;\n\t\t}\n\n\t\tpublic DefaultFactionChangeEvent(final Faction F)\n\t\t{\n\t\t\tmyFaction = F;\n\t\t}\n\n\t\tpublic DefaultFactionChangeEvent(final Faction F, final String eventKey, final String eventData)\n\t\t{\n\t\t\tmyFaction=F;\n\t\t\tfinal List<String> v = CMParms.parseSemicolons(eventData,false);\n\n\t\t\tString trigger =v.get(0);\n\t\t\ttriggerParms="";\n\t\t\tfinal int x=trigger.indexOf(\'(\');\n\t\t\tif((x>0)&&(trigger.endsWith(")")))\n\t\t\t{\n\t\t\t\tsetTriggerParameters(trigger.substring(x+1,trigger.length()-1));\n\t\t\t\ttrigger=trigger.substring(0,x);\n\t\t\t}\n\n\t\t\tsetEventID(trigger);\n\t\t\tsetDirection(v.get(1));\n\t\t\tfinal String amt=v.get(2).trim();\n\t\t\tif(amt.endsWith("%"))\n\t\t\t\tsetFactor(CMath.s_pct(amt));\n\t\t\telse\n\t\t\t\tsetFactor(1.0);\n\n\t\t\tif(v.size()>3)\n\t\t\t\tsetFlags(v.get(3));\n\t\t\tif(v.size()>4)\n\t\t\t\tsetTargetZapper(v.get(4));\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean setEventID(final String newID)\n\t\t{\n\t\t\tIDclassFilter=-1;\n\t\t\tIDflagFilter=-1;\n\t\t\tIDdomainFilter=-1;\n\t\t\tmiscEventTrigger = null;\n\t\t\tfor (final MiscTrigger element : MiscTrigger.values())\n\t\t\t{\n\t\t\t\tif(element.name().equalsIgnoreCase(newID))\n\t\t\t\t{\n\t\t\t\t\teventTriggerID = element.name();\n\t\t\t\t\tmiscEventTrigger = element;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(int i=0;i<Ability.ACODE_DESCS.length;i++)\n\t\t\t{\n\t\t\t\tif(Ability.ACODE_DESCS[i].equalsIgnoreCase(newID))\n\t\t\t\t{\n\t\t\t\t\tIDclassFilter = i;\n\t\t\t\t\teventTriggerID = newID;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(int i=0;i<Ability.DOMAIN_DESCS.length;i++)\n\t\t\t{\n\t\t\t\tif(Ability.DOMAIN_DESCS[i].equalsIgnoreCase(newID))\n\t\t\t\t{\n\t\t\t\t\tIDdomainFilter = i << 5;\n\t\t\t\t\teventTriggerID = newID;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(int i=0;i< Ability.FLAG_DESCS.length;i++)\n\t\t\t{\n\t\t\t\tif(Ability.FLAG_DESCS[i].equalsIgnoreCase(newID))\n\t\t\t\t{\n\t\t\t\t\tIDflagFilter = Math.round(Math.pow(2, i));\n\t\t\t\t\teventTriggerID = newID;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(CMClass.getAbility(newID)!=null)\n\t\t\t{\n\t\t\t\teventTriggerID = newID;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif(CMLib.socials().fetchSocial(newID, true)!=null)\n\t\t\t{\n\t\t\t\teventTriggerID=newID.toUpperCase();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif((newID.endsWith(" *"))\n\t\t\t&&(CMLib.socials().fetchSocial(newID.substring(0,newID.length()-2).trim(), true)!=null))\n\t\t\t{\n\t\t\t\teventTriggerID=newID.toUpperCase().trim();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif(getCMMsgTypeMap().containsKey(newID.toUpperCase().trim()))\n\t\t\t{\n\t\t\t\teventTriggerID=newID.toUpperCase().trim();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic boolean setDirection(final String d)\n\t\t{\n\t\t\tif(CMath.isInteger(d))\n\t\t\t\tdirection=CMath.s_int(d);\n\t\t\telse\n\t\t\tif(d.startsWith("U"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_UP;\n\t\t\t}\n\t\t\telse\n\t\t\tif(d.startsWith("D"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_DOWN;\n\t\t\t}\n\t\t\telse\n\t\t\tif(d.startsWith("OPP"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_OPPOSITE;\n\t\t\t}\n\t\t\telse\n\t\t\tif(d.startsWith("REM"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_REMOVE;\n\t\t\t}\n\t\t\telse\n\t\t\tif(d.startsWith("MIN"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_MINIMUM;\n\t\t\t}\n\t\t\telse\n\t\t\tif(d.startsWith("MAX"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_MAXIMUM;\n\t\t\t}\n\t\t\telse\n\t\t\tif(d.startsWith("ADD"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_ADD;\n\t\t\t}\n\t\t\telse\n\t\t\tif(d.startsWith("TOW"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_TOWARD;\n\t\t\t}\n\t\t\telse\n\t\t\tif(d.startsWith("AWA"))\n\t\t\t{\n\t\t\t\tdirection = CHANGE_DIRECTION_AWAY;\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn false;\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setFlags(final String newFlagCache)\n\t\t{\n\t\t\tflagCache=newFlagCache.toUpperCase().trim();\n\t\t\tflags=CMParms.parseStrictEQParms(newFlagCache);\n\t\t\toutsiderTargetOK=flags.containsKey("OUTSIDER");\n\t\t\tselfTargetOK=flags.containsKey("SELFOK");\n\t\t\tjust100=flags.containsKey("JUST100");\n\t\t\tbonusXP=flags.containsKey("XP")?CMath.s_int(flags.get("XP")):0;\n\t\t\tbonusRPXP=flags.containsKey("RPXP")?CMath.s_int(flags.get("RPXP")):0;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getFlagValue(String key)\n\t\t{\n\t\t\tkey=key.toUpperCase().trim();\n\t\t\treturn flags.containsKey(key) ? flags.get(key) : "";\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean applies(final MOB source, final MOB target)\n\t\t{\n\t\t\tif(!CMLib.masking().maskCheck(compiledTargetZapper(),target,false))\n\t\t\t\treturn false;\n\t\t\tif(!CMLib.masking().maskCheck(compiledSourceZapper(),source,false))\n\t\t\t\treturn false;\n\t\t\tfinal Faction F=getFaction();\n\t\t\tif(F!=null)\n\t\t\t{\n\t\t\t\tif(withinTicks > 0)\n\t\t\t\t{\n\t\t\t\t\tfinal long now=System.currentTimeMillis() - (withinTicks * CMProps.getTickMillis());\n\t\t\t\t\tFaction.FData data;\n\t\t\t\t\tdata = source.fetchFactionData(F.factionID());\n\t\t\t\t\tif(data != null)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(now > data.getEventTime(eventTriggerID))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif(source != target)\n\t\t\t\t\t{\n\t\t\t\t\t\tdata = target.fetchFactionData(F.factionID());\n\t\t\t\t\t\tif(data != null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(now > data.getEventTime(eventTriggerID))\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic String triggerParameters()\n\t\t{\n\t\t\treturn triggerParms;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setTriggerParameters(final String newVal)\n\t\t{\n\t\t\ttriggerParms=newVal;\n\t\t\tsavedTriggerParms=CMParms.parseStrictEQParms(newVal);\n\t\t\tcompiledSourceZapper=null;\n\t\t\twithinTicks=savedTriggerParms.containsKey("WITHIN")?CMath.s_int(savedTriggerParms.get("WITHIN")):-1;\n\t\t\tpctChance=savedTriggerParms.containsKey("CHANCE")?CMath.s_int(savedTriggerParms.get("CHANCE")):100;\n\t\t\twaitMs=savedTriggerParms.containsKey("WAIT")?(CMath.s_long(savedTriggerParms.get("WAIT"))*CMProps.getTickMillis()):-1;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object stateVariable(final int x)\n\t\t{\n\t\t\treturn ((x >= 0) && (x < stateVariables.length)) ? stateVariables[x] : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setStateVariable(final int x, final Object newVal)\n\t\t{\n\t\t\tif(x<0)\n\t\t\t\treturn;\n\t\t\tif(x>=stateVariables.length)\n\t\t\t\tstateVariables=Arrays.copyOf(stateVariables,x+1);\n\t\t\tstateVariables[x]=newVal;\n\t\t}\n\n\t\t@Override\n\t\tpublic Faction getFaction()\n\t\t{\n\t\t\treturn myFaction;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Faction.FRange addRange(final String key)\n\t{\n\t\tfinal Faction.FRange FR=new DefaultFaction.DefaultFactionRange(this,key);\n\t\tranges.put(FR.codeName().toUpperCase().trim(),FR);\n\t\trecalc();\n\t\treturn FR;\n\t}\n\n\t@Override\n\tpublic boolean delRange(final FRange FR)\n\t{\n\t\tif(!ranges.containsKey(FR.codeName().toUpperCase().trim()))\n\t\t\treturn false;\n\t\tranges.remove(FR.codeName().toUpperCase().trim());\n\t\trecalc();\n\t\treturn true;\n\t}\n\n\tpublic class DefaultFactionRange implements Faction.FRange, Comparable<Faction.FRange>\n\t{\n\t\tpublic int\t\t\t\tlow;\n\t\tpublic int\t\t\t\thigh;\n\t\tpublic String\t\t\tname\t\t= "";\n\t\tpublic String\t\t\tcodeName\t= "";\n\t\tpublic Faction.Align\talignEquiv;\n\t\tpublic Faction\t\t\tfaction\t\t= null;\n\n\t\t@Override\n\t\tpublic int low()\n\t\t{\n\t\t\treturn low;\n\t\t}\n\n\t\t@Override\n\t\tpublic int high()\n\t\t{\n\t\t\treturn high;\n\t\t}\n\n\t\t@Override\n\t\tpublic String name()\n\t\t{\n\t\t\treturn name;\n\t\t}\n\n\t\t@Override\n\t\tpublic String codeName()\n\t\t{\n\t\t\treturn codeName;\n\t\t}\n\n\t\t@Override\n\t\tpublic Align alignEquiv()\n\t\t{\n\t\t\treturn alignEquiv;\n\t\t}\n\n\t\t@Override\n\t\tpublic Faction getFaction()\n\t\t{\n\t\t\treturn faction;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLow(final int newVal)\n\t\t{\n\t\t\tlow = newVal;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setHigh(final int newVal)\n\t\t{\n\t\t\thigh = newVal;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setName(final String newVal)\n\t\t{\n\t\t\tname = newVal;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setAlignEquiv(final Faction.Align newVal)\n\t\t{\n\t\t\talignEquiv = newVal;\n\t\t}\n\n\t\tpublic DefaultFactionRange(final Faction F, final String key)\n\t\t{\n\t\t\tfaction=F;\n\t\t\tfinal List<String> v = CMParms.parseSemicolons(key,false);\n\t\t\tname = v.get(2);\n\t\t\tlow = CMath.s_int( v.get(0));\n\t\t\thigh = CMath.s_int( v.get(1));\n\t\t\tif(v.size()>3)\n\t\t\t\tcodeName=v.get(3);\n\t\t\tif(v.size()>4)\n\t\t\t\talignEquiv = CMLib.factions().getAlignEnum(v.get(4));\n\t\t\telse\n\t\t\t\talignEquiv = Faction.Align.INDIFF;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString()\n\t\t{\n\t\t\treturn low +";"+high+";"+name+";"+codeName+";"+alignEquiv.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic int random()\n\t\t{\n\t\t\tfinal Random gen = new Random();\n\t\t\treturn high - gen.nextInt(high-low);\n\t\t}\n\n\t\t@Override\n\t\tpublic int med()\n\t\t{\n\t\t\treturn high - (high-low)/2;\n\t\t}\n\n\t\t@Override\n\t\tpublic int compareTo(final FRange o)\n\t\t{\n\t\t\tif(low < o.low())\n\t\t\t\treturn -1;\n\t\t\tif(high > o.high())\n\t\t\t\treturn 1;\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Faction.FAbilityUsage addAbilityUsage(final String key)\n\t{\n\t\tfinal Faction.FAbilityUsage usage=\n\t\t\t(key==null)?new DefaultFaction.DefaultFactionAbilityUsage()\n\t\t\t\t\t  : new DefaultFaction.DefaultFactionAbilityUsage(key);\n\t\tabilityUsages.add(usage);\n\t\tabilityUsages.trimToSize();\n\t\tabilityUseCache.clear();\n\t\treturn usage;\n\t}\n\n\t@Override\n\tpublic boolean delAbilityUsage(final Faction.FAbilityUsage usage)\n\t{\n\t\tif(!abilityUsages.remove(usage))\n\t\t\treturn false;\n\t\tabilityUsages.trimToSize();\n\t\tabilityUseCache.clear();\n\t\treturn true;\n\t}\n\n\tpublic class DefaultFactionData implements FData\n\t{\n\t\tprivate int\t\t\t\tvalue;\n\t\tprivate boolean\t\t\tnoListeners;\n\t\tprivate boolean\t\t\tnoTickers;\n\t\tprivate boolean\t\t\tnoStatAffectors;\n\t\tprivate long\t\t\tlastUpdated;\n\t\tprivate Ability[]\t\tmyEffects;\n\t\tprivate Behavior[]\t\tmyBehaviors;\n\t\tprivate Ability\t\t\tlightPresenceAbilities[];\n\t\tprivate Faction.FRange\tcurrentRange;\n\t\tprivate boolean\t\t\terroredOut;\n\t\tprivate Faction\t\t\tmyFaction;\n\t\tpublic boolean\t\t\tisReset\t= false;\n\t\tprivate DVector\t\t\tcurrentReactionSets;\n\t\tprivate long\t\t\tbirthTime = System.currentTimeMillis();\n\n\t\tprivate final CMap<String, Long>\t\t\t\ttimers\t= new SHashtable<String, Long>();\n\t\tprivate final CMap<String, int[]>\t\t\t\tcounters= new SHashtable<String, int[]>();\n\t\tprivate Map<Faction.FactionChangeEvent, Long>\tnextChangeTime;\n\n\t\tpublic DefaultFactionData(final Faction F)\n\t\t{\n\t\t\tresetFactionData(F);\n\t\t}\n\n\t\t@Override\n\t\tpublic void resetFactionData(final Faction F)\n\t\t{\n\t\t\tif(!isReset)\n\t\t\t{\n\t\t\t\tmyFaction=F;\n\t\t\t\tvalue=0;\n\t\t\t\tnoListeners=false;\n\t\t\t\tnoTickers=false;\n\t\t\t\tnoStatAffectors=false;\n\t\t\t\tlastUpdated=System.currentTimeMillis();\n\t\t\t\tmyEffects=new Ability[0];\n\t\t\t\tmyBehaviors=new Behavior[0];\n\t\t\t\tcurrentReactionSets = new DVector(2);\n\t\t\t\tlightPresenceAbilities = new Ability[0];\n\t\t\t\tcurrentRange = null;\n\t\t\t\terroredOut=false;\n\t\t\t\tisReset = true;\n\t\t\t\tnextChangeTime = new Hashtable<Faction.FactionChangeEvent, Long>();\n\t\t\t\ttimers.clear();\n\t\t\t\tcounters.clear();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic long getEventTime(final String eventID)\n\t\t{\n\t\t\tif(!timers.containsKey(eventID))\n\t\t\t\treturn this.birthTime;\n\t\t\treturn timers.get(eventID).longValue();\n\t\t}\n\n\t\t@Override\n\t\tpublic void resetEventTimers(final String eventID)\n\t\t{\n\t\t\tthis.birthTime = System.currentTimeMillis();\n\t\t\tif(eventID == null)\n\t\t\t{\n\t\t\t\ttimers.clear();\n\t\t\t\tnextChangeTime.clear();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttimers.put(eventID, Long.valueOf(System.currentTimeMillis()));\n\t\t\t\tfor(final Iterator<Faction.FactionChangeEvent> e = nextChangeTime.keySet().iterator();e.hasNext();)\n\t\t\t\t{\n\t\t\t\t\tfinal Faction.FactionChangeEvent event = e.next();\n\t\t\t\t\tif(event.eventID().equalsIgnoreCase(eventID))\n\t\t\t\t\t{\n\t\t\t\t\t\tnextChangeTime.remove(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic int value()\n\t\t{\n\t\t\treturn value;\n\t\t}\n\n\t\t@Override\n\t\tpublic Faction getFaction()\n\t\t{\n\t\t\treturn myFaction;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getNextChangeTimers(final Faction.FactionChangeEvent event)\n\t\t{\n\t\t\tif(nextChangeTime.containsKey(event))\n\t\t\t\treturn nextChangeTime.get(event).longValue();\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setNextChangeTimers(final Faction.FactionChangeEvent event, final long time)\n\t\t{\n\t\t\tnextChangeTime.put(event, Long.valueOf(time));\n\t\t}\n\n\t\t@SuppressWarnings("unchecked")\n\t\t@Override\n\t\tpublic void setValue(final int newValue)\n\t\t{\n\t\t\tthis.value=newValue;\n\t\t\tif((currentRange==null)||(this.value<currentRange.low())||(this.value>currentRange.high()))\n\t\t\t{\n\t\t\t\tsynchronized(this)\n\t\t\t\t{\n\t\t\t\t\tif((currentRange!=null)&&(this.value>=currentRange.low())&&(this.value<=currentRange.high()))\n\t\t\t\t\t\treturn;\n\t\t\t\t\tcurrentRange = fetchRange(value);\n\t\t\t\t\tif(currentRange==null)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(!erroredOut)\n\t\t\t\t\t\t\tLog.errOut("DefaultFactionData","Faction "+factionID()+" does not define a range for "+this.value);\n\t\t\t\t\t\terroredOut=true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\terroredOut=false;\n\t\t\t\t\t\tcurrentReactionSets=new DVector(2);\n\t\t\t\t\t\tfor(final Enumeration<Faction.FReactionItem> e=reactions();e.hasMoreElements();)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFaction.FReactionItem react = e.nextElement();\n\t\t\t\t\t\t\tif(!react.rangeCodeName().equalsIgnoreCase(currentRange.codeName()))\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\tFaction.FReactionItem sampleReact = null;\n\t\t\t\t\t\t\tVector<Faction.FReactionItem> reactSet=null;\n\t\t\t\t\t\t\tfor(int r=0;r<currentReactionSets.size();r++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treactSet=(Vector<Faction.FReactionItem>)currentReactionSets.elementAt(r,2);\n\t\t\t\t\t\t\t\tsampleReact=reactSet.firstElement();\n\t\t\t\t\t\t\t\tif(react.presentMOBMask().trim().equalsIgnoreCase(sampleReact.presentMOBMask().trim()))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\treactSet.addElement(react);\n\t\t\t\t\t\t\t\t\treact=null; break;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(react!=null)\n\t\t\t\t\t\t\t\tcurrentReactionSets.addElement(react.compiledPresentMOBMask(),new XVector<Faction.FReactionItem>(react));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t//noReactions=currentReactionSets.size()==0;\n\t\t\t\t\t}\n\t\t\t\t\tnoListeners=(myEffects.length==0) && (myBehaviors.length==0) && (currentReactionSets.size()==0);\n\t\t\t\t\tnoTickers=(myBehaviors.length==0) && (myEffects.length==0) &&((currentReactionSets.size()==0)||(!useLightReactions()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void affectPhyStats(final Physical affected, final PhyStats affectableStats)\n\t\t{\n\t\t\tif(!noStatAffectors)\n\t\t\t\tfor(final Ability A : myEffects) A.affectPhyStats(affected, affectableStats);\n\t\t}\n\n\t\t@Override\n\t\tpublic void affectCharStats(final MOB affectedMob, final CharStats affectableStats)\n\t\t{\n\t\t\tif(!noStatAffectors)\n\t\t\t\tfor(final Ability A : myEffects) A.affectCharStats(affectedMob, affectableStats);\n\t\t}\n\n\t\t@Override\n\t\tpublic void affectCharState(final MOB affectedMob, final CharState affectableMaxState)\n\t\t{\n\t\t\tif(!noStatAffectors)\n\t\t\t\tfor(final Ability A : myEffects) A.affectCharState(affectedMob, affectableMaxState);\n\t\t}\n\n\t\t@Override\n\t\tpublic void addHandlers(final List<Ability> listeners, final List<Behavior> tickers)\n\t\t{\n\t\t\tthis.myEffects=listeners.toArray(new Ability[0]);\n\t\t\tthis.myBehaviors=tickers.toArray(new Behavior[0]);\n\t\t\tnoListeners=(listeners.size()==0) && (tickers.size()==0) && (currentReactionSets.size()==0);\n\t\t\tnoTickers=(listeners.size()==0) && (tickers.size()==0) && ((currentReactionSets.size()==0)||(!useLightReactions()));\n\t\t\tnoStatAffectors=(listeners.size()==0);\n\t\t\tisReset = false;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean requiresUpdating()\n\t\t{\n\t\t\treturn lastDataChange[0] > lastUpdated;\n\t\t}\n\n\t\t@SuppressWarnings("unchecked")\n\t\tprivate Ability setPresenceReaction(final MOB M, final Physical myHost)\n\t\t{\n\t\t\tif((!CMLib.flags().canBeSeenBy(myHost, M))\n\t\t\t&&(!CMLib.flags().canBeHeardMovingBy(myHost,M)))\n\t\t\t\treturn null;\n\t\t\tif((M.amUltimatelyFollowing()!=null)\n\t\t\t&&(!M.amUltimatelyFollowing().isMonster()))\n\t\t\t\treturn null;\n\t\t\tVector<String> myReactions=null;\n\t\t\tList<Faction.FReactionItem> tempReactSet=null;\n\t\t\tfor(int d=0;d<currentReactionSets.size();d++)\n\t\t\t{\n\t\t\t\tif(CMLib.masking().maskCheck((MaskingLibrary.CompiledZMask)currentReactionSets.elementAt(d,1),M,true))\n\t\t\t\t{\n\t\t\t\t\tif(myReactions==null)\n\t\t\t\t\t\tmyReactions=new Vector<String>();\n\t\t\t\t\ttempReactSet=(List<Faction.FReactionItem>)currentReactionSets.elementAt(d,2);\n\t\t\t\t\tfor(final Faction.FReactionItem reactionItem : tempReactSet)\n\t\t\t\t\t\tmyReactions.add(reactionItem.reactionObjectID()+"="+reactionItem.parameters(myHost.Name()));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(myReactions!=null)\n\t\t\t{\n\t\t\t\tif(useLightReactions())\n\t\t\t\t{\n\t\t\t\t\tfinal Ability A=(Ability)presenceReactionPrototype.copyOf();\n\t\t\t\t\tA.invoke(M,myReactions,myHost,false,0);\n\t\t\t\t\tA.setInvoker(M);\n\t\t\t\t\treturn A;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\tif(M.fetchEffect(presenceReactionPrototype.ID())==null)\n\t\t\t\t{\n\t\t\t\t\tfinal Ability A=(Ability)presenceReactionPrototype.copyOf();\n\t\t\t\t\tA.invoke(M,myReactions,myHost,true,0);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic void executeMsg(final Environmental myHost, final CMMsg msg)\n\t\t{\n\t\t\tif(noListeners)\n\t\t\t\treturn;\n\t\t\tsynchronized(lightPresenceAbilities)\n\t\t\t{\n\t\t\t\tif((currentReactionSets.size()>0)\n\t\t\t\t&&(msg.sourceMinor()==CMMsg.TYP_ENTER)\n\t\t\t\t&&(msg.target() instanceof Room))\n\t\t\t\t{\n\t\t\t\t\tif(presenceReactionPrototype==null)\n\t\t\t\t\t{\n\t\t\t\t\t\tif((presenceReactionPrototype=CMClass.getAbility("PresenceReaction"))==null)\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif((msg.source()==myHost)\n\t\t\t\t\t&&(!msg.source().isMonster()))\n\t\t\t\t\t{\n\t\t\t\t\t\tMOB M=null;\n\t\t\t\t\t\tfinal Room R=(Room)msg.target();\n\t\t\t\t\t\tfinal List<Ability> lightPresenceReactions=new LinkedList<Ability>();\n\t\t\t\t\t\tAbility A=null;\n\t\t\t\t\t\tfor(int m=0;m<R.numInhabitants();m++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tM=R.fetchInhabitant(m);\n\t\t\t\t\t\t\tif((M!=null)\n\t\t\t\t\t\t\t&&(M!=myHost)\n\t\t\t\t\t\t\t&&(M.isMonster())) // follow checks are in setPresenceReaction\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tA=setPresenceReaction(M,msg.source());\n\t\t\t\t\t\t\t\tif(A!=null) // means yes, we are using light, and yes, heres a reaction to add\n\t\t\t\t\t\t\t\t\tlightPresenceReactions.add(A);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlightPresenceAbilities = lightPresenceReactions.toArray(new Ability[0]);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\tif((msg.source().isMonster())\n\t\t\t\t\t&&(msg.target()==CMLib.map().roomLocation(myHost))\n\t\t\t\t\t&&(myHost instanceof Physical))\n\t\t\t\t\t{\n\t\t\t\t\t\tif(!(myHost instanceof MOB))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// follow checks are in setPresenceReaction\n\t\t\t\t\t\t\tfinal Ability A=setPresenceReaction(msg.source(),(Physical)myHost);\n\t\t\t\t\t\t\tif(A!=null)\n\t\t\t\t\t\t\t{ // means yes, we are using light, and yes, heres a reaction to add\n\t\t\t\t\t\t\t\tlightPresenceAbilities = Arrays.copyOf(lightPresenceAbilities, lightPresenceAbilities.length+1);\n\t\t\t\t\t\t\t\tlightPresenceAbilities[lightPresenceAbilities.length-1]=A;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\tif((lightPresenceAbilities.length>0)\n\t\t\t\t&&(msg.sourceMinor()==CMMsg.TYP_LEAVE)\n\t\t\t\t&&(msg.target() instanceof Room))\n\t\t\t\t{\n\t\t\t\t\tif((msg.source()==myHost)\n\t\t\t\t\t&&(!msg.source().isMonster()))\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal Room R=(Room)msg.target();\n\t\t\t\t\t\tMOB M=null;\n\t\t\t\t\t\tfor(int m=0;m<R.numInhabitants();m++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tM=R.fetchInhabitant(m);\n\t\t\t\t\t\t\tif((M!=null)\n\t\t\t\t\t\t\t&&(M!=myHost)\n\t\t\t\t\t\t\t&&(M.isMonster()))\n\t\t\t\t\t\t\t\tpresenceReactionPrototype.invoke(M,new Vector<String>(),null,true,0); // this shuts it down\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlightPresenceAbilities=new Ability[0];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\tif((msg.source().isMonster())\n\t\t\t\t\t&&(myHost instanceof Physical))\n\t\t\t\t\t{\n\t\t\t\t\t\tpresenceReactionPrototype.invoke(msg.source(),new Vector<String>(),null,true,0);\n\t\t\t\t\t\tfinal Ability[] newAbilities = new Ability[lightPresenceAbilities.length];\n\t\t\t\t\t\tint l=0;\n\t\t\t\t\t\tfor (final Ability lightPresenceAbilitie : lightPresenceAbilities)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(lightPresenceAbilitie.affecting()==null)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\tif(lightPresenceAbilitie.affecting()==msg.source())\n\t\t\t\t\t\t\t\tlightPresenceAbilitie.invoke(msg.source(),new Vector<String>(),null,true,0);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tnewAbilities[l++]=lightPresenceAbilitie;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(l==0)\n\t\t\t\t\t\t\tlightPresenceAbilities=new Ability[0];\n\t\t\t\t\t\telse\n\t\t\t\t\t\tif(l<lightPresenceAbilities.length)\n\t\t\t\t\t\t\tlightPresenceAbilities = Arrays.copyOf(newAbilities, l);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(final Ability A : lightPresenceAbilities)\n\t\t\t\tA.executeMsg(A.invoker(), msg);\n\t\t\tfor(final Ability A : myEffects)\n\t\t\t\tA.executeMsg(myHost, msg);\n\t\t\tfor(final Behavior B : myBehaviors)\n\t\t\t\tB.executeMsg(myHost, msg);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean okMessage(final Environmental myHost, final CMMsg msg)\n\t\t{\n\t\t\tif(noListeners)\n\t\t\t\treturn true;\n\t\t\tfor(final Ability A : myEffects)\n\t\t\t{\n\t\t\t\tif(!A.okMessage(myHost, msg))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor(final Behavior B : myBehaviors)\n\t\t\t{\n\t\t\t\tif(!B.okMessage(myHost, msg))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor(final Ability A : lightPresenceAbilities)\n\t\t\t{\n\t\t\t\tif(!A.okMessage(A.invoker(), msg))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean tick(final Tickable ticking, final int tickID)\n\t\t{\n\t\t\tif(noTickers)\n\t\t\t\treturn true;\n\t\t\tfor(final Ability A : myEffects)\n\t\t\t{\n\t\t\t\tif(!A.tick(ticking, tickID))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor(final Behavior B : myBehaviors)\n\t\t\t{\n\t\t\t\tif(!B.tick(ticking, tickID))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor(final Ability A : lightPresenceAbilities)\n\t\t\t{\n\t\t\t\tif(!A.tick(A.invoker(), tickID))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getCounter(final String key)\n\t\t{\n\t\t\tif(counters.containsKey(key))\n\t\t\t\treturn counters.get(key)[0];\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setCounter(final String key, final int newValue)\n\t\t{\n\t\t\tif(key == null)\n\t\t\t\tcounters.clear();\n\t\t\telse\n\t\t\tif(counters.containsKey(key))\n\t\t\t\tcounters.get(key)[0]=newValue;\n\t\t\telse\n\t\t\t\tcounters.put(key, new int[] {newValue});\n\t\t}\n\t}\n\n\tpublic class DefaultFactionZapFactor implements Faction.FZapFactor\n\t{\n\t\tprivate double gainF= 1.0;\n\t\tprivate double lossF= 1.0;\n\t\tprivate String mask\t= "";\n\t\tprivate MaskingLibrary.CompiledZMask compiledMask=null;\n\n\t\tpublic DefaultFactionZapFactor(final double gain, final double loss, final String mask)\n\t\t{\n\t\t\tsetGainFactor(gain);\n\t\t\tsetLossFactor(loss);\n\t\t\tsetMOBMask(mask);\n\t\t}\n\n\t\t@Override\n\t\tpublic double gainFactor()\n\t\t{\n\t\t\treturn gainF;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setGainFactor(final double val)\n\t\t{\n\t\t\tgainF = val;\n\t\t}\n\n\t\t@Override\n\t\tpublic double lossFactor()\n\t\t{\n\t\t\treturn lossF;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLossFactor(final double val)\n\t\t{\n\t\t\tlossF = val;\n\t\t}\n\n\t\t@Override\n\t\tpublic String MOBMask()\n\t\t{\n\t\t\treturn mask;\n\t\t}\n\n\t\t@Override\n\t\tpublic MaskingLibrary.CompiledZMask compiledMOBMask()\n\t\t{\n\t\t\treturn compiledMask;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setMOBMask(final String str)\n\t\t{\n\t\t\tmask=str;\n\t\t\tcompiledMask=CMLib.masking().maskCompile(str);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString()\n\t\t{\n\t\t\treturn gainF + ";" + lossF + ";" + mask;\n\t\t}\n\t}\n\n\tpublic class DefaultFactionReactionItem implements Faction.FReactionItem\n\t{\n\t\tprivate String reactionObjectID\t="";\n\t\tprivate String mobMask\t\t\t="";\n\t\tprivate String rangeName\t\t="";\n\t\tprivate String parms\t\t\t="";\n\n\t\tprivate MaskingLibrary.CompiledZMask compiledMobMask=null;\n\n\t\t@Override\n\t\tpublic String reactionObjectID()\n\t\t{\n\t\t\treturn reactionObjectID;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setReactionObjectID(final String str)\n\t\t{\n\t\t\treactionObjectID = str;\n\t\t}\n\n\t\t@Override\n\t\tpublic String presentMOBMask()\n\t\t{\n\t\t\treturn mobMask;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setPresentMOBMask(final String str)\n\t\t{\n\t\t\tmobMask=str;\n\t\t\tif((str==null)||(str.trim().length()==0))\n\t\t\t\tcompiledMobMask=null;\n\t\t\telse\n\t\t\t\tcompiledMobMask=CMLib.masking().maskCompile(str);\n\t\t}\n\n\t\t@Override\n\t\tpublic MaskingLibrary.CompiledZMask compiledPresentMOBMask()\n\t\t{\n\t\t\treturn compiledMobMask;\n\t\t}\n\n\t\t@Override\n\t\tpublic String rangeCodeName()\n\t\t{\n\t\t\treturn rangeName;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setRangeName(final String str)\n\t\t{\n\t\t\trangeName = str.toUpperCase().trim();\n\t\t}\n\n\t\t@Override\n\t\tpublic String parameters()\n\t\t{\n\t\t\treturn parms;\n\t\t}\n\n\t\t@Override\n\t\tpublic String parameters(final String name)\n\t\t{\n\t\t\treturn CMStrings.replaceAll(parms, "<TARGET>", name);\n\t\t}\n\n\t\t@Override\n\t\tpublic void setParameters(final String str)\n\t\t{\n\t\t\tparms = str;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString()\n\t\t{\n\t\t\treturn rangeName + ";" + mobMask + ";" + reactionObjectID + ";" + parms;\n\t\t}\n\n\t\tpublic DefaultFactionReactionItem()\n\t\t{\n\t\t}\n\n\t\tpublic DefaultFactionReactionItem(final String key)\n\t\t{\n\t\t\tint x=key.indexOf(\';\');\n\t\t\tString str = key.substring(0,x).toUpperCase().trim();\n\t\t\tString rest = key.substring(x+1);\n\t\t\tsetRangeName(str);\n\n\t\t\tx=rest.indexOf(\';\');\n\t\t\tstr = rest.substring(0,x).trim();\n\t\t\trest = rest.substring(x+1);\n\t\t\tsetPresentMOBMask(str);\n\n\t\t\tx=rest.indexOf(\';\');\n\t\t\tstr = rest.substring(0,x).trim();\n\t\t\trest = rest.substring(x+1);\n\t\t\tsetReactionObjectID(str);\n\t\t\tsetParameters(rest);\n\t\t}\n\n\t}\n\n\tpublic class DefaultFactionAbilityUsage implements Faction.FAbilityUsage\n\t{\n\t\tpublic String\tID\t\t\t\t\t= "";\n\t\tpublic boolean\tpossibleAbilityID\t= false;\n\t\tpublic int\t\ttype\t\t\t\t= -1;\n\t\tpublic int\t\tdomain\t\t\t\t= -1;\n\t\tpublic long\t\tflag\t\t\t\t= -1;\n\t\tpublic int\t\tlow\t\t\t\t\t= 0;\n\t\tpublic int\t\thigh\t\t\t\t= 0;\n\t\tpublic long\t\tnotflag\t\t\t\t= -1;\n\n\t\t@Override\n\t\tpublic String abilityFlags()\n\t\t{\n\t\t\treturn ID;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean possibleAbilityID()\n\t\t{\n\t\t\treturn possibleAbilityID;\n\t\t}\n\n\t\t@Override\n\t\tpublic int type()\n\t\t{\n\t\t\treturn type;\n\t\t}\n\n\t\t@Override\n\t\tpublic int domain()\n\t\t{\n\t\t\treturn domain;\n\t\t}\n\n\t\t@Override\n\t\tpublic long flag()\n\t\t{\n\t\t\treturn flag;\n\t\t}\n\n\t\t@Override\n\t\tpublic int low()\n\t\t{\n\t\t\treturn low;\n\t\t}\n\n\t\t@Override\n\t\tpublic int high()\n\t\t{\n\t\t\treturn high;\n\t\t}\n\n\t\t@Override\n\t\tpublic long notflag()\n\t\t{\n\t\t\treturn notflag;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLow(final int newVal)\n\t\t{\n\t\t\tlow = newVal;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setHigh(final int newVal)\n\t\t{\n\t\t\thigh = newVal;\n\t\t}\n\n\t\tpublic DefaultFactionAbilityUsage()\n\t\t{\n\t\t}\n\n\t\tpublic DefaultFactionAbilityUsage(final String key)\n\t\t{\n\t\t\tfinal List<String> v = CMParms.parseSemicolons(key,false);\n\t\t\tsetAbilityFlag(v.get(0));\n\t\t\tlow = CMath.s_int( v.get(1));\n\t\t\thigh = CMath.s_int( v.get(2));\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString()\n\t\t{\n\t\t\treturn ID+";"+low+";"+high;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> setAbilityFlag(final String str)\n\t\t{\n\t\t\tID=str;\n\t\t\tfinal List<String> flags=CMParms.parse(ID);\n\t\t\tfinal List<String> unknowns=new Vector<String>();\n\t\t\tpossibleAbilityID=false;\n\t\t\tfor(int f=0;f<flags.size();f++)\n\t\t\t{\n\t\t\t\tString strflag=flags.get(f);\n\t\t\t\tfinal boolean not=strflag.startsWith("!");\n\t\t\t\tif(not)\n\t\t\t\t\tstrflag=strflag.substring(1);\n\t\t\t\tswitch(CMLib.factions().getAbilityFlagType(strflag))\n\t\t\t\t{\n\t\t\t\tcase ACODE:\n\t\t\t\t\ttype=CMParms.indexOfIgnoreCase(Ability.ACODE_DESCS, strflag);\n\t\t\t\t\tbreak;\n\t\t\t\tcase DOMAIN:\n\t\t\t\t\tdomain=CMParms.indexOfIgnoreCase(Ability.DOMAIN_DESCS, strflag);\n\t\t\t\t\tbreak;\n\t\t\t\tcase FLAG:\n\t\t\t\t{\n\t\t\t\t\tfinal int val=CMParms.indexOfIgnoreCase(Ability.FLAG_DESCS, strflag);\n\t\t\t\t\tif(not)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(notflag<0)\n\t\t\t\t\t\t\tnotflag=0;\n\t\t\t\t\t\tnotflag=notflag|CMath.pow(2,val);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif(flag<0)\n\t\t\t\t\t\t\tflag=0;\n\t\t\t\t\t\tflag=flag|CMath.pow(2,val);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tunknowns.add(strflag);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif((type<0)&&(domain<0)&&(flag<0))\n\t\t\t\tpossibleAbilityID=true;\n\t\t\treturn unknowns;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy()\n\t{\n\t\tCMLib.factions().removeFaction(this.factionID());\n\t\tthis.destroyed=true;\n\t\tdefaults.clear();\n\t\tautoDefaults.clear();\n\t\tranges.clear();\n\t\taffBehavs.clear();\n\t\tchanges.clear();\n\t\tabilChangeCache.clear();\n\t\tmsgChangeCache.clear();\n\t\tsocChangeCache.clear();\n\t\tfactors.clear();\n\t\trelations.clear();\n\t\tabilityUsages.clear();\n\t\tabilityUseCache.clear();\n\t\tchoices.clear();\n\t\treactions.clear();\n\t\treactionHash.clear();\n\t}\n\n\t@Override\n\tpublic boolean isSavable()\n\t{\n\t\treturn (internalFlagBitmap & Faction.IFLAG_NEVERSAVE) == 0;\n\t}\n\n\t@Override\n\tpublic void setSavable(final boolean truefalse)\n\t{\n\t}\n\n\t@Override\n\tpublic boolean amDestroyed()\n\t{\n\t\treturn destroyed;\n\t}\n}\n', 'message': 'some more teach/cast fixes\n\ngit-svn-id: 0cdf8356e41b2d8ccbb41bb76c82068fe80b2514@19624 0d6f1817-ed0e-0410-87c9-987e46238f29\n', 'author_name': 'bozimmerman', 'lang': 'java'}