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,false)) { 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,false)) { 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,false)) { 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,false))) { 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,false); } } 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; } } }