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.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.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
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.lang.reflect.*;
/**
* <p>Portions Copyright (c) 2003 Jeremy Vyska</p>
* <p>Portions Copyright (c) 2004 Bo Zimmerman</p>
* <p>Licensed under the Apache License, Version 2.0 (the "License");
* <p>you may not use this file except in compliance with the License.
* <p>You may obtain a copy of the License at
*
* <p> http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software
* <p>distributed under the License is distributed on an "AS IS" BASIS,
* <p>WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* <p>See the License for the specific language governing permissions and
* <p>limitations under the License.
*/
public class DefaultFaction implements Faction, MsgListener
{
public String ID(){return "DefaultFaction";}
public CMObject newInstance(){try{return (CMObject)getClass().newInstance();}catch(Exception e){return new DefaultFaction();}}
public void initializeClass(){}
public CMObject copyOf(){try{return (CMObject)this.clone();}catch(Exception e){return newInstance();}}
public int compareTo(Object o){ return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o));}
public String ID="";
public String name="";
public String choiceIntro="";
public int minimum=Integer.MIN_VALUE;
public int middle=0;
public int difference;
public int maximum=Integer.MAX_VALUE;
public int highest=Integer.MAX_VALUE;
public int lowest=Integer.MIN_VALUE;
public String experienceFlag="";
public boolean showinscore=false;
public boolean showinspecialreported=false;
public boolean showineditor=false;
public boolean showinfactionscommand=true;
public Vector ranges=new Vector();
public Vector defaults=new Vector();
public Vector autoDefaults=new Vector();
public double rateModifier=1.0;
public Hashtable Changes=new Hashtable();
public Vector factors=new Vector();
public Hashtable relations=new Hashtable();
public Vector abilityUsages=new Vector();
public Vector choices=new Vector();
public String factionID(){return ID;}
public String name(){return name;}
public String choiceIntro(){return choiceIntro;}
public int minimum(){return minimum;}
public int middle(){return middle;}
public int difference(){return difference;}
public int maximum(){return maximum;}
public int highest(){return highest;}
public int lowest(){return lowest;}
public String experienceFlag(){return experienceFlag;}
public boolean showinscore(){return showinscore;}
public boolean showinspecialreported(){return showinspecialreported;}
public boolean showineditor(){return showineditor;}
public boolean showinfactionscommand(){return showinfactionscommand;}
public Vector ranges(){return ranges;}
public Vector defaults(){return defaults;}
public Vector autoDefaults(){return autoDefaults;}
public double rateModifier(){return rateModifier;}
public Hashtable Changes(){return Changes;}
public Vector factors(){return factors;}
public Hashtable relations(){return relations;}
public Vector abilityUsages(){return abilityUsages;}
public Vector choices(){return choices;}
public void setFactionID(String newStr){ID=newStr;}
public void setName(String newStr){name=newStr;}
public void setChoiceIntro(String newStr){choiceIntro=newStr;}
public void setMinimum(int newVal){minimum=newVal;}
public void setMiddle(int newVal){middle=newVal;}
public void setDifference(int newVal){difference=newVal;}
public void setMaximum(int newVal){maximum=newVal;}
public void setHighest(int newVal){highest=newVal;}
public void setLowest(int newVal){lowest=newVal;}
public void setExperienceFlag(String newStr){experienceFlag=newStr;}
public void setShowinscore(boolean truefalse){showinscore=truefalse;}
public void setShowinspecialreported(boolean truefalse){showinspecialreported=truefalse;}
public void setShowineditor(boolean truefalse){showineditor=truefalse;}
public void setShowinfactionscommand(boolean truefalse){showinfactionscommand=truefalse;}
public void setChoices(Vector v){choices=v;}
public void setAutoDefaults(Vector v){autoDefaults=v;}
public void setDefaults(Vector v){defaults=v;}
public void setRateModifier(double d){rateModifier=d;}
public DefaultFaction(){super();}
public void initializeFaction(String aname)
{
ID=aname;
name=aname;
minimum=0;
middle=50;
maximum=100;
highest=100;
lowest=0;
difference=CMath.abs(maximum-minimum);
experienceFlag="EXTREME";
ranges.addElement(newRange("0;100;Sample Range;SAMPLE;"));
defaults.addElement("0");
}
public void initializeFaction(StringBuffer file, String fID)
{
boolean debug = false;
ID = fID;
CMProps alignProp = new CMProps(new ByteArrayInputStream(CMStrings.strToBytes(file.toString())));
if(alignProp.isEmpty()) return;
name=alignProp.getStr("NAME");
choiceIntro=alignProp.getStr("CHOICEINTRO");
minimum=alignProp.getInt("MINIMUM");
maximum=alignProp.getInt("MAXIMUM");
if(maximum<minimum)
{
minimum=maximum;
maximum=alignProp.getInt("MINIMUM");
}
middle=minimum+(int)Math.round(CMath.div(maximum-minimum,2.0));
difference=CMath.abs(maximum-minimum);
experienceFlag=alignProp.getStr("EXPERIENCE").toUpperCase().trim();
if(experienceFlag.length()==0) experienceFlag="NONE";
rateModifier=alignProp.getDouble("RATEMODIFIER");
showinscore=alignProp.getBoolean("SCOREDISPLAY");
showinfactionscommand=alignProp.getBoolean("SHOWINFACTIONSCMD");
showinspecialreported=alignProp.getBoolean("SPECIALREPORTED");
showineditor=alignProp.getBoolean("EDITALONE");
defaults =CMParms.parseSemicolons(alignProp.getStr("DEFAULT"),true);
autoDefaults =CMParms.parseSemicolons(alignProp.getStr("AUTODEFAULTS"),true);
choices =CMParms.parseSemicolons(alignProp.getStr("AUTOCHOICES"),true);
ranges=new Vector();
Changes=new Hashtable();
factors=new Vector();
relations=new Hashtable();
abilityUsages=new Vector();
highest=Integer.MIN_VALUE;
lowest=Integer.MAX_VALUE;
for(Enumeration e=alignProp.keys();e.hasMoreElements();)
{
if(debug) Log.sysOut("FACTIONS","Starting Key Loop");
String key = (String) e.nextElement();
if(debug) Log.sysOut("FACTIONS"," Key Found :"+key);
String words = (String) alignProp.get(key);
if(debug) Log.sysOut("FACTIONS"," Words Found :"+words);
if(key.startsWith("RANGE"))
{
FactionRange R=newRange(words);
ranges.add(R);
if(R.low()<lowest) lowest=R.low();
if(R.high()>highest) highest=R.high();
}
if(key.startsWith("CHANGE"))
{
FactionChangeEvent C=newChangeEvent(words);
Changes.put(C.eventID().toUpperCase(),C);
}
if(key.startsWith("FACTOR"))
{
Vector factor=CMParms.parseSemicolons(words,false);
factors.add(factor);
}
if(key.startsWith("RELATION"))
{
Vector v=CMParms.parse(words);
if(v.size()>=2)
{
String who=(String)v.elementAt(0);
double factor;
String amt=((String)v.elementAt(1)).trim();
if(amt.endsWith("%"))
factor=CMath.div(CMath.s_int(amt.substring(0,amt.length()-1)),100.0);
else
factor=1;
relations.put(who,new Double(factor));
}
}
if(key.startsWith("ABILITY"))
{
FactionAbilityUsage A=newAbilityUsage(words);
abilityUsages.add(A);
}
}
}
public String getTagValue(String tag)
{
int tagRef=CMLib.factions().isFactionTag(tag);
if(tagRef<0) return "";
int numCall=-1;
if((tagRef<ALL_TAGS.length)&&(ALL_TAGS[tagRef].endsWith("*")))
if(CMath.isInteger(tag.substring(ALL_TAGS[tagRef].length()-1)))
numCall=CMath.s_int(tag.substring(ALL_TAGS[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(showinfactionscommand).toUpperCase();
case TAG_SPECIALREPORTED: return Boolean.toString(showinspecialreported).toUpperCase();
case TAG_EDITALONE: return Boolean.toString(showineditor).toUpperCase();
case TAG_DEFAULT: return CMParms.toSemicolonList(defaults);
case TAG_AUTODEFAULTS: return CMParms.toSemicolonList(autoDefaults);
case TAG_CHOICEINTRO: return choiceIntro;
case TAG_AUTOCHOICES: return CMParms.toSemicolonList(choices);
case TAG_RATEMODIFIER: return ""+rateModifier;
case TAG_EXPERIENCE: return ""+experienceFlag;
case TAG_RANGE_:
{
if((numCall<0)||(numCall>=ranges.size()))
return ""+ranges.size();
return ((FactionRange)ranges.elementAt(numCall)).toString();
}
case TAG_CHANGE_:
{
if((numCall<0)||(numCall>=Changes.size()))
return ""+Changes.size();
int i=0;
for(Enumeration e=Changes.elements();e.hasMoreElements();)
{
FactionChangeEvent FC=(FactionChangeEvent)e.nextElement();
if(i==numCall)
return FC.toString();
i++;
}
return "";
}
case TAG_ABILITY_:
{
if((numCall<0)||(numCall>=abilityUsages.size()))
return ""+abilityUsages.size();
return ((FactionAbilityUsage)abilityUsages.elementAt(numCall)).toString();
}
case TAG_FACTOR_:
{
if((numCall<0)||(numCall>=factors.size()))
return ""+factors.size();
return CMParms.toSemicolonList((Vector)factors.elementAt(numCall));
}
case TAG_RELATION_:
{
if((numCall<0)||(numCall>=relations.size()))
return ""+relations.size();
int i=0;
for(Enumeration e=relations.keys();e.hasMoreElements();)
{
String factionName=(String)e.nextElement();
Double D=(Double)relations.get(factionName);
if(i==numCall)
return factionName+" "+((int)Math.round(D.doubleValue()*100.0))+"%";
i++;
}
return "";
}
}
return "";
}
public String getINIDef(String tag, String delimeter)
{
int tagRef=CMLib.factions().isFactionTag(tag);
if(tagRef<0)
return "";
String rawTagName=ALL_TAGS[tagRef];
if(ALL_TAGS[tagRef].endsWith("*"))
{
int number=CMath.s_int(getTagValue(rawTagName));
StringBuffer str=new StringBuffer("");
for(int i=0;i<number;i++)
{
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;
}
public FactionChangeEvent findChangeEvent(String key)
{
if(Changes.containsKey(key))
return (FactionChangeEvent)Changes.get(key.toUpperCase());
return null;
}
public Vector findChoices(MOB mob)
{
Vector mine=new Vector();
if(choices!=null)
{
for(int i=0;i<choices.size();i++)
{
if(CMath.isInteger((String)choices.elementAt(i)))
mine.addElement(new Integer(CMath.s_int((String)choices.elementAt(i))));
else
if(CMLib.masking().maskCheck((String)choices.elementAt(i), mob))
{
Vector v=CMParms.parse((String)choices.elementAt(i));
for(int j=0;j<v.size();j++)
{
if(CMath.isInteger((String)v.elementAt(j)))
mine.addElement(new Integer(CMath.s_int((String)v.elementAt(j))));
}
}
}
}
return mine;
}
public FactionChangeEvent findChangeEvent(Ability key)
{
if(key==null) return null;
// Direct ability ID's
if(Changes.containsKey(key.ID()))
return (FactionChangeEvent)Changes.get(key.ID().toUpperCase());
// By TYPE or FLAGS
FactionChangeEvent C =null;
for (Enumeration e=Changes.elements();e.hasMoreElements();)
{
C= (FactionChangeEvent)e.nextElement();
if((key.classificationCode()&Ability.ALL_ACODES)==C.IDclassFilter())
return C;
if((key.classificationCode()&Ability.ALL_DOMAINS)==C.IDdomainFilter())
return C;
if((C.IDflagFilter()>0)&&(CMath.bset(key.flags(),C.IDflagFilter())))
return C;
}
return null;
}
public Vector fetchRanges()
{
return ranges;
}
public FactionRange fetchRange(int faction)
{
if(ranges!=null)
{
for (int i = 0; i < ranges.size(); i++)
{
FactionRange R = (FactionRange) ranges.elementAt(i);
if ( (faction >= R.low()) && (faction <= R.high()))
return R;
}
}
return null;
}
public String fetchRangeName(int faction)
{
if(ranges!=null)
{
for (int i = 0; i < ranges.size(); i++)
{
FactionRange R = (FactionRange) ranges.elementAt(i);
if ( (faction >= R.low()) && (faction <= R.high()))
return R.name();
}
}
return "";
}
public int asPercent(int faction)
{
return (int)Math.round(CMath.mul(CMath.div(faction-minimum,(maximum-minimum)),100));
}
public int asPercentFromAvg(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));
}
public int randomFaction()
{
Random gen = new Random();
return maximum - gen.nextInt(maximum-minimum);
}
public int findDefault(MOB mob)
{
if(defaults!=null)
{
for(int i=0;i<defaults.size();i++)
{
if(CMLib.masking().maskCheck((String)defaults.elementAt(i), mob))
{
Vector v=CMParms.parse((String)defaults.elementAt(i));
for(int j=0;j<v.size();j++)
{
if(CMath.isNumber((String)v.elementAt(j)))
return CMath.s_int((String)v.elementAt(j));
}
}
else
{
if(CMath.isNumber((String)defaults.elementAt(i)))
return CMath.s_int((String)defaults.elementAt(i));
}
}
}
return 0;
}
public int findAutoDefault(MOB mob)
{
if(autoDefaults!=null)
{
for(int i=0;i<autoDefaults.size();i++)
{
if(CMLib.masking().maskCheck((String)autoDefaults.elementAt(i), mob))
{
Vector v=CMParms.parse((String)autoDefaults.elementAt(i));
for(int j=0;j<v.size();j++)
{
if(CMath.isNumber((String)v.elementAt(j)))
return CMath.s_int((String)v.elementAt(j));
}
}
else
{
if(CMath.isNumber((String)autoDefaults.elementAt(i)))
return CMath.s_int((String)autoDefaults.elementAt(i));
}
}
}
return Integer.MAX_VALUE;
}
public boolean hasFaction(MOB mob)
{
return (mob.fetchFaction(ID)!=Integer.MAX_VALUE);
}
public boolean hasUsage(Ability A)
{
FactionAbilityUsage usage=null;
for(int i=0;i<abilityUsages.size();i++)
{
usage=(FactionAbilityUsage)abilityUsages.elementAt(i);
if((usage.possibleAbilityID()&&usage.usageID().equalsIgnoreCase(A.ID()))
||(((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()))))
return true;
}
return false;
}
public boolean canUse(MOB mob, Ability A)
{
FactionAbilityUsage usage=null;
for(int i=0;i<abilityUsages.size();i++)
{
usage=(FactionAbilityUsage)abilityUsages.elementAt(i);
if((usage.possibleAbilityID()&&usage.usageID().equalsIgnoreCase(A.ID()))
||(((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()))))
{
int faction=mob.fetchFaction(ID);
if((faction < usage.low()) || (faction > usage.high()))
return false;
}
}
return true;
}
public double findFactor(MOB mob, boolean gain)
{
for(int i=0;i<factors.size();i++)
{
Vector factor=(Vector)factors.elementAt(i);
if((factor.size()>2)
&&(CMLib.masking().maskCheck(((String)factor.elementAt(2)),mob)))
{
if(gain)
return CMath.s_double(((String)factor.elementAt(1)));
return CMath.s_double(((String)factor.elementAt(0)));
}
}
return 1.0;
}
public void executeMsg(Environmental myHost, CMMsg msg)
{
if((msg.sourceMinor()==CMMsg.TYP_DEATH) // A death occured
&&(msg.source()==myHost)
&&(msg.tool() instanceof MOB))
{
FactionChangeEvent eventC=findChangeEvent("MURDER");
if(eventC!=null)
{
CharClass combatCharClass=CMLib.combat().getCombatDominantClass((MOB)msg.tool(),msg.source());
HashSet combatBeneficiaries=CMLib.combat().getCombatBeneficiaries((MOB)msg.tool(),msg.source(),combatCharClass);
for(Iterator I=combatBeneficiaries.iterator();I.hasNext();)
{
MOB killer=(MOB)I.next();
if(eventC.applies(killer))
executeChange(killer,msg.source(),eventC);
}
}
}
// Ability Watching
if((msg.tool() instanceof Ability)
&&(msg.othersMessage()!=null)
&&(findChangeEvent((Ability)msg.tool())!=null))
{
FactionChangeEvent C=findChangeEvent((Ability)msg.tool());
if((msg.target() instanceof MOB)&&(C.applies((MOB)msg.target())))
executeChange(msg.source(),(MOB)msg.target(),C);
else
if (!(msg.target() instanceof MOB))
executeChange(msg.source(),null,C);
}
}
public boolean okMessage(Environmental myHost, CMMsg msg)
{
if((msg.sourceMinor()==CMMsg.TYP_EXPCHANGE) // Experience is being altered
&&(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))
{
MOB killer=msg.source();
MOB vic=(MOB)msg.target();
if(experienceFlag.equals("HIGHER"))
msg.setValue( (int)Math.round((msg.value()/2.0) +( (msg.value()/2.0) * CMath.div(Math.abs(killer.fetchFaction(ID)-minimum),(maximum - minimum)))));
else
if(experienceFlag.equals("LOWER"))
msg.setValue( (int)Math.round((msg.value()/2.0) +( (msg.value()/2.0) * 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()/2.0) +( (msg.value()/2.0) * CMath.div(Math.abs(vic.fetchFaction(ID) - killer.fetchFaction(ID)),(maximum - minimum)))));
else
if(experienceFlag.equals("FOLLOWHIGHER"))
msg.setValue( (int)Math.round((msg.value()/2.0) +( (msg.value()/2.0) * CMath.div(Math.abs(vic.fetchFaction(ID)-minimum),(maximum - minimum)))));
else
if(experienceFlag.equals("FOLLOWLOWER"))
msg.setValue( (int)Math.round((msg.value()/2.0) +( (msg.value()/2.0) * CMath.div(Math.abs(maximum-vic.fetchFaction(ID)),(maximum - minimum)))));
if(msg.value()<=0)
msg.setValue(0);
}
}
return true;
}
public void executeChange(MOB source, MOB target, FactionChangeEvent event)
{
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;
double baseChangeAmount=100.0;
if((source!=target)&&(target!=null)&&(!event.just100()))
{
int levelLimit=CMProps.getIntVar(CMProps.SYSTEMI_EXPRATE);
int levelDiff=target.envStats().level()-source.envStats().level();
if(levelDiff<(-levelLimit) )
baseChangeAmount=0.0;
else
if(levelLimit>0)
{
double levelFactor=CMath.div(levelDiff,levelLimit);
if(levelFactor>new Integer(levelLimit).doubleValue())
levelFactor=new Integer(levelLimit).doubleValue();
baseChangeAmount=baseChangeAmount+CMath.mul(levelFactor,100);
}
}
int factionAdj=1;
int changeDir=0;
switch(event.direction())
{
case FactionChangeEvent.FACTION_MAXIMUM:
factionAdj=maximum-sourceFaction;
break;
case FactionChangeEvent.FACTION_MINIMUM:
factionAdj=minimum-sourceFaction;
break;
case FactionChangeEvent.FACTION_UP:
changeDir=1;
break;
case FactionChangeEvent.FACTION_DOWN:
changeDir=-1;
break;
case FactionChangeEvent.FACTION_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(new Integer(sourceFaction-targetFaction).doubleValue()
/Math.abs(new Integer(difference).doubleValue())));
}
else
factionAdj=0;
break;
case FactionChangeEvent.FACTION_AWAY:
if(source!=target)
changeDir=targetFaction>=sourceFaction?-1:1;
else
factionAdj=0;
break;
case FactionChangeEvent.FACTION_TOWARD:
if(source!=target)
changeDir=targetFaction>=sourceFaction?1:-1;
else
factionAdj=0;
break;
case FactionChangeEvent.FACTION_REMOVE:
factionAdj=Integer.MAX_VALUE;
break;
case FactionChangeEvent.FACTION_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);
if(source.location()!=null)
{
if(source.location().okMessage(source,FacMsg))
{
source.location().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
for(Enumeration e=relations.keys();e.hasMoreElements();)
{
String relID=((String)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, ((Double)relations.get(relID)).doubleValue())));
if(source.location().okMessage(source,FacMsg))
source.location().send(source, FacMsg);
}
}
}
}
else
if((factionAdj==Integer.MAX_VALUE)||(factionAdj==Integer.MIN_VALUE))
source.removeFaction(ID);
else
source.adjustFaction(ID,factionAdj);
}
public String usageFactors(Ability A)
{
StringBuffer rangeStr=new StringBuffer();
FactionAbilityUsage usage=null;
HashSet namesAdded=new HashSet();
for(int i=0;i<abilityUsages.size();i++)
{
usage=(FactionAbilityUsage)abilityUsages.elementAt(i);
if((usage.possibleAbilityID()&&usage.usageID().equalsIgnoreCase(A.ID()))
||(((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()))))
{
for(int r=0;r<ranges.size();r++)
{
FactionRange R=(FactionRange)ranges.elementAt(r);
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;
public String ALL_CHANGE_EVENT_TYPES()
{
StringBuffer ALL_TYPES=new StringBuffer("");
if(_ALL_TYPES!=null) return _ALL_TYPES;
for(int i=0;i<Faction.FactionChangeEvent.MISC_TRIGGERS.length;i++)
ALL_TYPES.append(Faction.FactionChangeEvent.MISC_TRIGGERS[i]+", ");
for(int i=0;i<Ability.ACODE_DESCS.length;i++)
ALL_TYPES.append(Ability.ACODE_DESCS[i]+", ");
for(int i=0;i<Ability.DOMAIN_DESCS.length;i++)
ALL_TYPES.append(Ability.DOMAIN_DESCS[i]+", ");
for(int i=0;i<Ability.FLAG_DESCS.length;i++)
ALL_TYPES.append(Ability.FLAG_DESCS[i]+", ");
_ALL_TYPES=ALL_TYPES.toString()+" a valid Skill, Spell, Chant, etc. ID.";
return _ALL_TYPES;
}
public Faction.FactionChangeEvent newChangeEvent(String key){return new DefaultFaction.DefaultFactionChangeEvent(key);}
public Faction.FactionChangeEvent newChangeEvent(){return new DefaultFaction.DefaultFactionChangeEvent();}
public static class DefaultFactionChangeEvent implements Faction.FactionChangeEvent
{
public String ID="";
public String flagCache="";
public int IDclassFilter=-1;
public int IDflagFilter=-1;
public int IDdomainFilter=-1;
public int direction=0;
public double factor=0.0;
public String zapper="";
public boolean outsiderTargetOK=false;
public boolean selfTargetOK=false;
public boolean just100=false;
public String eventID(){return ID;}
public String flagCache(){return flagCache;}
public int IDclassFilter(){return IDclassFilter;}
public int IDflagFilter(){return IDflagFilter;}
public int IDdomainFilter(){return IDdomainFilter;}
public int direction(){return direction;}
public double factor(){return factor;}
public String zapper(){return zapper;}
public boolean outsiderTargetOK(){return outsiderTargetOK;}
public boolean selfTargetOK(){return selfTargetOK;}
public boolean just100(){return just100;}
public void setEventID(String newVal){ID=newVal;}
public void setFlagCache(String newVal){flagCache=newVal;}
public void setIDclassFilter(int newVal){IDclassFilter=newVal;}
public void setIDflagFilter(int newVal){IDflagFilter=newVal;}
public void setIDdomainFilter(int newVal){IDdomainFilter=newVal;}
public void setDirection(int newVal){direction=newVal;}
public void setFactor(double newVal){factor=newVal;}
public void setZapper(String newVal){zapper=newVal;}
public void setOutsiderTargetOK(boolean newVal){outsiderTargetOK=newVal;}
public void setSelfTargetOK(boolean newVal){selfTargetOK=newVal;}
public void setJust100(boolean newVal){just100=newVal;}
public static final int FACTION_UP = 0;
public static final int FACTION_DOWN = 1;
public static final int FACTION_OPPOSITE = 2;
public static final int FACTION_MINIMUM = 3;
public static final int FACTION_MAXIMUM = 4;
public static final int FACTION_REMOVE = 5;
public static final int FACTION_ADD = 6;
public static final int FACTION_AWAY = 7;
public static final int FACTION_TOWARD= 8;
public static final String[] FACTION_DIRECTIONS={
"UP",
"DOWN",
"OPPOSITE",
"MINIMUM",
"MAXIMUM",
"REMOVE",
"ADD",
"AWAY",
"TOWARD"
};
public static final String[] VALID_FLAGS={
"OUTSIDER","SELFOK","JUST100"
};
public static final String[] MISC_TRIGGERS={
"MURDER","TIME","ADDOUTSIDER"
};
public String toString()
{
return ID+";"+FACTION_DIRECTIONS[direction]+";"+((int)Math.round(factor*100.0))+"%;"+flagCache+";"+zapper;
}
public DefaultFactionChangeEvent(){}
public DefaultFactionChangeEvent(String key)
{
Vector v = CMParms.parseSemicolons(key,false);
setFilterID((String)v.elementAt(0));
setDirection((String)v.elementAt(1));
String amt=((String)v.elementAt(2)).trim();
if(amt.endsWith("%"))
factor=CMath.div(CMath.s_int(amt.substring(0,amt.length()-1)),100.0);
else
factor=1.0;
if(v.size()>3)
setFlags((String)v.elementAt(3));
if(v.size()>4)
zapper = (String)v.elementAt(4);
}
public boolean setFilterID(String newID)
{
for(int i=0;i<MISC_TRIGGERS.length;i++)
if(MISC_TRIGGERS[i].equalsIgnoreCase(newID))
{ ID=newID; 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=(int)CMath.pow(2,i); ID=newID; return true;}
if(CMClass.getAbility(newID)!=null)
{ ID=newID; return true;}
return false;
}
public boolean setDirection(String d)
{
if(d.startsWith("U")) {
direction = FACTION_UP;
}
else
if(d.startsWith("D")) {
direction = FACTION_DOWN;
}
else
if(d.startsWith("OPP")) {
direction = FACTION_OPPOSITE;
}
else
if(d.startsWith("REM")) {
direction = FACTION_REMOVE;
}
else
if(d.startsWith("MIN")) {
direction = FACTION_MINIMUM;
}
else
if(d.startsWith("MAX")) {
direction = FACTION_MAXIMUM;
}
else
if(d.startsWith("ADD")) {
direction = FACTION_ADD;
}
else
if(d.startsWith("TOW")) {
direction = FACTION_TOWARD;
}
else
if(d.startsWith("AWA")) {
direction = FACTION_AWAY;
}
else
return false;
return true;
}
public void setFlags(String newFlagCache)
{
flagCache=newFlagCache.toUpperCase().trim();
Vector flags=CMParms.parse(flagCache);
if(flags.contains("OUTSIDER")) outsiderTargetOK=true;
if(flags.contains("SELFOK")) selfTargetOK=true;
if(flags.contains("JUST100")) just100=true;
}
public boolean applies(MOB mob)
{
if(zapper==null) return true;
return CMLib.masking().maskCheck(zapper,mob);
}
}
public Faction.FactionRange newRange(String key){return new DefaultFaction.DefaultFactionRange(this,key);}
public static class DefaultFactionRange implements Faction.FactionRange
{
public String ID="";
public int low;
public int high;
public String Name="";
public String CodeName="";
public int AlignEquiv;
public Faction myFaction=null;
public String rangeID(){return ID;}
public int low(){return low;}
public int high(){return high;}
public String name(){return Name;}
public String codeName(){return CodeName;}
public int alignEquiv(){return AlignEquiv;}
public Faction myFaction(){return myFaction;}
public void setRangeID(String newVal){ID=newVal;}
public void setLow(int newVal){low=newVal;}
public void setHigh(int newVal){high=newVal;}
public void setName(String newVal){Name=newVal;}
public void setCodeName(String newVal){CodeName=newVal;}
public void setAlignEquiv(int newVal){AlignEquiv=newVal;}
public DefaultFactionRange(Faction F, String key)
{
myFaction=F;
Vector v = CMParms.parseSemicolons(key,false);
Name = (String) v.elementAt(2);
low = CMath.s_int( (String) v.elementAt(0));
high = CMath.s_int( (String) v.elementAt(1));
if(v.size()>3)
CodeName=(String)v.elementAt(3);
if(v.size()>4)
AlignEquiv = CMLib.factions().getAlignEquiv((String)v.elementAt(4));
else
AlignEquiv = Faction.ALIGN_INDIFF;
}
public String toString()
{
return low +";"+high+";"+Name+";"+CodeName+";"+ALIGN_NAMES[AlignEquiv];
}
public int random()
{
Random gen = new Random();
return high - gen.nextInt(high-low);
}
}
public Faction.FactionAbilityUsage newAbilityUsage(String key){return new DefaultFaction.DefaultFactionAbilityUsage(key);}
public Faction.FactionAbilityUsage newAbilityUsage(){return new DefaultFaction.DefaultFactionAbilityUsage();}
public static class DefaultFactionAbilityUsage implements Faction.FactionAbilityUsage
{
public String ID="";
public boolean possibleAbilityID=false;
public int type=-1;
public int domain=-1;
public int flag=-1;
public int low=0;
public int high=0;
public int notflag=-1;
public String usageID(){return ID;}
public boolean possibleAbilityID(){return possibleAbilityID;}
public int type(){return type;}
public int domain(){return domain;}
public int flag(){return flag;}
public int low(){return low;}
public int high(){return high;}
public int notflag(){return notflag;}
public void setUsageID(String newVal){ID=newVal;}
public void setPossibleAbilityID(boolean truefalse){possibleAbilityID=truefalse;}
public void setType(int newVal){type=newVal;}
public void setDomain(int newVal){domain=newVal;}
public void setFlag(int newVal){flag=newVal;}
public void setLow(int newVal){low=newVal;}
public void setHigh(int newVal){high=newVal;}
public void setNotflag(int newVal){notflag=newVal;}
public DefaultFactionAbilityUsage(){}
public DefaultFactionAbilityUsage(String key)
{
Vector v = CMParms.parseSemicolons(key,false);
setAbilityFlag((String)v.firstElement());
low = CMath.s_int( (String) v.elementAt(1));
high = CMath.s_int( (String) v.elementAt(2));
}
public String toString()
{
return ID+";"+low+";"+high;
}
public Vector setAbilityFlag(String str)
{
ID=str;
Vector flags=CMParms.parse(ID);
Vector unknowns=new Vector();
for(int f=0;f<flags.size();f++)
{
String strflag=(String)flags.elementAt(f);
boolean not=strflag.startsWith("!");
if(not) strflag=strflag.substring(1);
boolean known=false;
for(int i=0;i<Ability.ACODE_DESCS.length;i++)
if(Ability.ACODE_DESCS[i].equalsIgnoreCase(strflag))
{
type=i;
known=true;
}
if(!known)
for(int i=0;i<Ability.DOMAIN_DESCS.length;i++)
if(Ability.DOMAIN_DESCS[i].equalsIgnoreCase(strflag))
{
domain=i<<5;
known=true;
}
if(!known)
for(int i=0;i< Ability.FLAG_DESCS.length;i++)
if(Ability.FLAG_DESCS[i].equalsIgnoreCase(strflag))
{
known=true;
if(not)
{
if(notflag<0) notflag=0;
notflag=notflag|(int)CMath.pow(2,i);
}
else
{
if(flag<0) flag=0;
flag=flag|(int)CMath.pow(2,i);
}
}
if(!known)
unknowns.addElement(strflag);
}
if((type<0)&&(domain<0)&&(flag<0))
possibleAbilityID=true;
return unknowns;
}
}
}