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.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
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-2019 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 ID = "";
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 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 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 ID;
}
@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 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)
{
ID = 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 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)
{
ID=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;
ID = fID;
final CMProps alignProp = new CMProps(new ByteArrayInputStream(CMStrings.strToBytes(file.toString())));
if(alignProp.isEmpty())
return;
name=alignProp.getStr("NAME");
upName=name.toUpperCase();
choiceIntro=alignProp.getStr("CHOICEINTRO");
minimum=alignProp.getInt("MINIMUM");
maximum=alignProp.getInt("MAXIMUM");
if(maximum<minimum)
{
minimum=maximum;
maximum=alignProp.getInt("MINIMUM");
}
recalc();
experienceFlag=alignProp.getStr("EXPERIENCE").toUpperCase().trim();
if(experienceFlag.length()==0)
experienceFlag="NONE";
rateModifier=alignProp.getDouble("RATEMODIFIER");
showInScore=alignProp.getBoolean("SCOREDISPLAY");
showInFacCommand=alignProp.getBoolean("SHOWINFACTIONSCMD");
showInSpecialReport=alignProp.getBoolean("SPECIALREPORTED");
showInEditor=alignProp.getBoolean("EDITALONE");
defaults=new SVector<String>(CMParms.parseSemicolons(alignProp.getStr("DEFAULT"),true));
autoDefaults =new SVector<String>(CMParms.parseSemicolons(alignProp.getStr("AUTODEFAULTS"),true));
choices =new SVector<String>(CMParms.parseSemicolons(alignProp.getStr("AUTOCHOICES"),true));
useLightReactions=alignProp.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=alignProp.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) alignProp.get(key);
if(debug)
Log.sysOut("FACTIONS"," Words Found :"+words);
if(key.startsWith("RANGE"))
addRange(words);
if(key.startsWith("CHANGE"))
createChangeEvent(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 int tagRef=CMLib.factions().isFactionTag(tag);
if(tagRef<0)
return "";
int numCall=-1;
if((tagRef<TAG_NAMES.length)&&(TAG_NAMES[tagRef].endsWith("*")))
{
if(CMath.isInteger(tag.substring(TAG_NAMES[tagRef].length()-1)))
numCall=CMath.s_int(tag.substring(TAG_NAMES[tagRef].length()-1));
}
switch(tagRef)
{
case TAG_NAME:
return name;
case TAG_MINIMUM:
return "" + minimum;
case TAG_MAXIMUM:
return "" + maximum;
case TAG_SCOREDISPLAY:
return Boolean.toString(showInScore).toUpperCase();
case TAG_SHOWINFACTIONSCMD:
return Boolean.toString(showInFacCommand).toUpperCase();
case TAG_SPECIALREPORTED:
return Boolean.toString(showInSpecialReport).toUpperCase();
case TAG_EDITALONE:
return Boolean.toString(showInEditor).toUpperCase();
case TAG_DEFAULT:
return CMParms.toSemicolonListString(defaults);
case TAG_AUTODEFAULTS:
return CMParms.toSemicolonListString(autoDefaults);
case TAG_CHOICEINTRO:
return choiceIntro;
case TAG_AUTOCHOICES:
return CMParms.toSemicolonListString(choices);
case TAG_RATEMODIFIER:
return "" + rateModifier;
case TAG_EXPERIENCE:
return "" + experienceFlag;
case TAG_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 TAG_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 TAG_ABILITY_:
{
if((numCall<0)||(numCall>=abilityUsages.size()))
return ""+abilityUsages.size();
return abilityUsages.get(numCall).toString();
}
case TAG_FACTOR_:
{
if((numCall<0)||(numCall>=factors.size()))
return ""+factors.size();
return factors.get(numCall).toString();
}
case TAG_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 TAG_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 TAG_REACTION_:
{
if((numCall<0)||(numCall>=reactions.size()))
return ""+reactions.size();
final Faction.FReactionItem item = reactions.get(numCall);
return item.toString();
}
case TAG_USELIGHTREACTIONS:
return "" + useLightReactions;
}
return "";
}
@Override
public String getINIDef(final String tag, final String delimeter)
{
final int tagRef=CMLib.factions().isFactionTag(tag);
if(tagRef<0)
return "";
final String rawTagName=TAG_NAMES[tagRef];
if(TAG_NAMES[tagRef].endsWith("*"))
{
final int number=CMath.s_int(getTagValue(rawTagName));
final StringBuffer str=new StringBuffer("");
for(int i=0;i<number;i++)
{
final String value=getTagValue(rawTagName.substring(0,rawTagName.length()-1)+i);
str.append(rawTagName.substring(0,rawTagName.length()-1)+(i+1)+"="+value+delimeter);
}
return str.toString();
}
return rawTagName+"="+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 Vector<Integer> mine=new Vector<Integer>();
String s;
for(final Enumeration<String> e=choices.elements();e.hasMoreElements();)
{
s=e.nextElement();
if(CMath.isInteger(s))
mine.addElement(Integer.valueOf(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.isInteger(V.elementAt(j)))
mine.addElement(Integer.valueOf(CMath.s_int(V.elementAt(j))));
}
}
}
return mine;
}
@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)
{
if(CMLib.socials().numSocialSets()==0)
return null;
for(final Enumeration<Social> s=CMLib.socials().getAllSocials();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(ID)!=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(ID);
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;
}
@Override
public void executeMsg(final Environmental myHost, final CMMsg msg)
{
FactionChangeEvent[] events;
switch(msg.sourceMinor())
{
case CMMsg.TYP_DEATH:
if(((msg.source()==myHost)||(msg.tool()==myHost))
&&(msg.tool() instanceof MOB))
{
final MOB killedM=msg.source();
final MOB killingBlowM=(MOB)msg.tool();
events=getChangeEvents((msg.source()==myHost)?"MURDER":"KILL");
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)
executeChange(mob,killedM,event);
}
}
}
}
break;
case CMMsg.TYP_CAUSESINK:
if((myHost instanceof MOB)
&&(msg.target() instanceof BoardableShip))
{
final MOB killerM=msg.source();
final Area shipArea=((BoardableShip)msg.target()).getShipArea();
if(CMLib.map().areaLocation(killerM)==shipArea)
events=getChangeEvents("SUNK");
else
if(killerM == myHost)
events=getChangeEvents("SINK");
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))
{
events=getChangeEvents("BRIBE");
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("TALK");
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();
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)
{
if(data == null)
data = mob.fetchFactionData(factionID());
if(data != null)
{
final long newTime=CMath.s_long(event.getTriggerParm("WAIT"))*CMProps.getTickMillis();
if(newTime != 0)
data.setNextChangeTimers(event, System.currentTimeMillis()+newTime);
}
}
}
}
}
}
events=getChangeEvents("MUDCHAT");
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();
Faction.FData data = mob.fetchFactionData(factionID());
for (final FactionChangeEvent event : events)
{
if(event.applies(mob,target))
{
if((mudChatB.getLastRespondedTo()==mob)
&&(mudChatB.getLastThingSaid()!=null)
&&(!mudChatB.getLastThingSaid().equalsIgnoreCase(sayMsg)))
{
if((data != null) && (System.currentTimeMillis() < data.getNextChangeTimers(event)))
continue;
executeChange(mob,target,event);
foundOne=true;
if(data == null)
data = mob.fetchFactionData(factionID());
if(data != null)
{
final long newTime=CMath.s_long(event.getTriggerParm("WAIT"))*CMProps.getTickMillis();
if(newTime != 0)
data.setNextChangeTimers(event, System.currentTimeMillis()+newTime);
}
}
}
}
}
if(foundOne)
break;
}
}
}
}
break;
default:
if(msg.tool() instanceof Ability)
{
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))
{
events=getChangeEvents("ARRESTED");
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;
Faction.FData data = msg.source().fetchFactionData(factionID());
if((data != null) && (System.currentTimeMillis() < data.getNextChangeTimers(C)))
continue;
executeChange(msg.source(),target,C);
if(data == null)
data = msg.source().fetchFactionData(factionID());
if(data != null)
{
final long newTime=CMath.s_long(C.getTriggerParm("WAIT"))*CMProps.getTickMillis();
if(newTime != 0)
data.setNextChangeTimers(C, System.currentTimeMillis()+newTime);
}
}
}
}
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("SOCIAL");
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();
Faction.FData data = mob.fetchFactionData(factionID());
for (final FactionChangeEvent event : events)
{
if(event.eventID().equals("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((data != null) && (System.currentTimeMillis() < data.getNextChangeTimers(event)))
continue;
executeChange(mob,(MOB)msg.target(),event);
if(data == null)
data = mob.fetchFactionData(factionID());
if(data != null)
{
final long newTime=CMath.s_long(event.getTriggerParm("WAIT"))*CMProps.getTickMillis();
if(newTime != 0)
data.setNextChangeTimers(event, System.currentTimeMillis()+newTime);
}
}
}
}
}
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(ID)-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(ID)),(maximum - minimum)))));
else
if(vic.fetchFaction(ID)!=Integer.MAX_VALUE)
{
if(experienceFlag.equals("EXTREME"))
msg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(vic.fetchFaction(ID) - killer.fetchFaction(ID)),(maximum - minimum)))));
else
if(experienceFlag.equals("FOLLOWHIGHER"))
msg.setValue( (int)Math.round(((msg.value())*.75) +( ((msg.value())*.25) * CMath.div(Math.abs(vic.fetchFaction(ID)-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(ID)),(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(ID);
int targetFaction = sourceFaction * -1;
if((source==target)
&&(!event.selfTargetOK())
&&(!event.eventID().equalsIgnoreCase("TIME")))
return;
if(target!=null)
{
if(hasFaction(target))
targetFaction=target.fetchFaction(ID);
else
if(!event.outsiderTargetOK())
return;
}
else
target = source;
final String chance=event.getTriggerParm("CHANCE");
if(CMath.isInteger(chance) && (CMLib.dice().rollPercentage()<CMath.s_int(chance)))
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);
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(ID,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)
return;
CMMsg facMsg=CMClass.getMsg(source,target,null,CMMsg.MASK_ALWAYS|CMMsg.TYP_FACTIONCHANGE,null,CMMsg.NO_EFFECT,null,CMMsg.NO_EFFECT,ID);
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(ID);
else
source.adjustFaction(ID,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 String element : Faction.FactionChangeEvent.MISC_TRIGGERS)
ALL_TYPES.append(element+", ");
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 key)
{
Faction.FactionChangeEvent event;
if(key==null)
return null;
if(key.indexOf(';')<0)
{
event=new DefaultFaction.DefaultFactionChangeEvent(this);
if(!event.setEventID(key))
return null;
}
else
event=new DefaultFaction.DefaultFactionChangeEvent(this,key);
abilChangeCache.clear();
socChangeCache.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();
socChangeCache.clear();
}
return done;
}
@Override
public void clearChangeEvents()
{
abilChangeCache.clear();
socChangeCache.clear();
changes.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();
return true;
}
}
for(final Enumeration<String> e=changes.keys();e.hasMoreElements();)
{
if(replaceEvents(e.nextElement(),event,false))
{
abilChangeCache.clear();
socChangeCache.clear();
return true;
}
}
return false;
}
public class DefaultFactionChangeEvent implements Faction.FactionChangeEvent
{
private String ID = "";
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 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 ID;
}
@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 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 ID+"("+triggerParms.replace(';',',')+");"+CHANGE_DIRECTION_DESCS[direction]+";"+((int)Math.round(factor*100.0))+"%;"+flagCache+";"+targetZapperStr;
else
return ID+";"+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 key)
{
myFaction=F;
final List<String> v = CMParms.parseSemicolons(key,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;
for (final String element : MISC_TRIGGERS)
{
if(element.equalsIgnoreCase(newID))
{
ID = element;
return true;
}
}
for(int i=0;i<Ability.ACODE_DESCS.length;i++)
{
if(Ability.ACODE_DESCS[i].equalsIgnoreCase(newID))
{
IDclassFilter = i;
ID = newID;
return true;
}
}
for(int i=0;i<Ability.DOMAIN_DESCS.length;i++)
{
if(Ability.DOMAIN_DESCS[i].equalsIgnoreCase(newID))
{
IDdomainFilter = i << 5;
ID = 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));
ID = newID;
return true;
}
}
if(CMClass.getAbility(newID)!=null)
{
ID = newID;
return true;
}
if(CMLib.socials().fetchSocial(newID, true)!=null)
{
ID=newID.toUpperCase();
return true;
}
if((newID.endsWith(" *"))
&&(CMLib.socials().fetchSocial(newID.substring(0,newID.length()-2).trim(), true)!=null))
{
ID=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(),target,false))
return false;
return true;
}
@Override
public String triggerParameters()
{
return triggerParms;
}
@Override
public void setTriggerParameters(final String newVal)
{
triggerParms=newVal;
savedTriggerParms=CMParms.parseEQParms(newVal);
compiledSourceZapper=null;
}
@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 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 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>();
}
}
@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;
}
}
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 1:
type=CMParms.indexOfIgnoreCase(Ability.ACODE_DESCS, strflag);
break;
case 2:
domain=CMParms.indexOfIgnoreCase(Ability.DOMAIN_DESCS, strflag);
break;
case 3:
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();
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;
}
}