package com.planet_ink.coffee_mud.Libraries; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import com.planet_ink.coffee_web.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.AbilityMapper.AbilityMapping; import com.planet_ink.coffee_mud.Libraries.interfaces.AbilityParameters.AbilityParmEditor; import com.planet_ink.coffee_mud.core.exceptions.*; import com.planet_ink.coffee_mud.core.*; import com.planet_ink.coffee_mud.core.collections.*; import com.planet_ink.coffee_mud.core.interfaces.*; import com.planet_ink.coffee_mud.Abilities.Common.CommonSkill; 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.AbilityComponent.CompLocation; import com.planet_ink.coffee_mud.Exits.interfaces.*; import com.planet_ink.coffee_mud.Items.interfaces.*; import com.planet_ink.coffee_mud.Items.interfaces.RawMaterial.Material; 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.net.Socket; import java.util.*; /* Copyright 2015-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 CMAbleComps extends StdLibrary implements AbilityComponents { @Override public String ID() { return "CMAbleComps"; } protected final boolean isRightMaterial(final long type, final long itemMaterial, final boolean mithrilOK) { if(itemMaterial == type) return true; if((mithrilOK) && (type == RawMaterial.MATERIAL_METAL)) { if(itemMaterial==RawMaterial.MATERIAL_MITHRIL) return true; } return false; } protected Item makeItemComponent(final AbilityComponent comp, final boolean mithrilOK) { if(comp.getType()==AbilityComponent.CompType.STRING) return null; else if(comp.getType()==AbilityComponent.CompType.RESOURCE) return CMLib.materials().makeItemResource((int)comp.getLongType(), comp.getSubType()); else if(comp.getType()==AbilityComponent.CompType.MATERIAL) return CMLib.materials().makeItemResource(RawMaterial.CODES.MOST_FREQUENT(((int)comp.getLongType())&RawMaterial.MATERIAL_MASK), comp.getSubType()); return null; } protected boolean IsItemComponent(final MOB mob, final AbilityComponent comp, final int[] amt, Item I, final List<Object> thisSet, final boolean mithrilOK) { if(I==null) return false; Item container=null; if((comp.getType()==AbilityComponent.CompType.STRING) &&(!CMLib.english().containsString(I.name(),comp.getStringType()))) return false; else if((comp.getType()==AbilityComponent.CompType.RESOURCE) &&((!(I instanceof RawMaterial)) ||(I.material()!=comp.getLongType()) ||((comp.getSubType().length()>0)&&(!((RawMaterial)I).getSubType().equalsIgnoreCase(comp.getSubType()))))) return false; else if((comp.getType()==AbilityComponent.CompType.MATERIAL) &&((!(I instanceof RawMaterial)) ||(!isRightMaterial(comp.getLongType(),I.material()&RawMaterial.MATERIAL_MASK,mithrilOK)) ||((comp.getSubType().length()>0)&&(!((RawMaterial)I).getSubType().equalsIgnoreCase(comp.getSubType()))))) return false; container=I.ultimateContainer(null); if(container==null) container=I; switch(comp.getLocation()) { case INVENTORY: if((container.owner() instanceof Room)||(!container.amWearingAt(Wearable.IN_INVENTORY))) return false; break; case HELD: if((container.owner() instanceof Room)||(!container.amWearingAt(Wearable.WORN_HELD))) return false; break; case WORN: if((container.owner() instanceof Room)||(container.amWearingAt(Wearable.IN_INVENTORY))) return false; break; default: case NEARBY: if(!CMLib.flags().canBeSeenBy(container, mob)) return false; break; case ONGROUND: if((!(container.owner() instanceof Room))||(!CMLib.flags().canBeSeenBy(container, mob))) return false; break; } if((comp.getType()!=AbilityComponent.CompType.STRING) &&(CMLib.flags().isOnFire(I)||CMLib.flags().isEnchanted(I))) return false; if(comp.getType()==AbilityComponent.CompType.STRING) { if(I instanceof PackagedItems) I=(Item)CMLib.materials().unbundle(I,amt[0],null); amt[0]-=I.numberOfItems(); } else if(I.phyStats().weight()>amt[0]) { I=(Item)CMLib.materials().splitBundle(I,amt[0],null); if(I==null) return false; amt[0]=amt[0]-I.phyStats().weight(); } else amt[0]=amt[0]-I.phyStats().weight(); thisSet.add(I); if(amt[0]<=0) { if(thisSet.size()>0) thisSet.add(Boolean.valueOf(comp.isConsumed())); return true; } return false; } // returns list of components for the requirement list. @Override public List<Item> componentsSample(final List<AbilityComponent> req, final boolean mithrilOK) { if((req==null)||(req.size()==0)) return new Vector<Item>(0); final List<Item> passes=new Vector<Item>(); AbilityComponent comp = null; for(int i=0;i<req.size();i++) { comp=req.get(i); final Item I=this.makeItemComponent(comp,mithrilOK); passes.add(I); } return passes; } // returns list of components found if all good, returns Integer of bad row if not. @Override public List<Object> componentCheck(final MOB mob, final List<AbilityComponent> req, final boolean mithrilOK) { if((mob==null)||(req==null)||(req.size()==0)) return new Vector<Object>(0); boolean currentAND=false; boolean previousValue=true; final int[] amt={0}; final List<Object> passes=new Vector<Object>(); final List<Object> thisSet=new ArrayList<Object>(); boolean found=false; AbilityComponent comp = null; final Room room = mob.location(); for(int i=0;i<req.size();i++) { comp=req.get(i); currentAND=comp.getConnector()==AbilityComponent.CompConnector.AND; if(previousValue&&(!currentAND)) return passes; if((!previousValue)&¤tAND) return null; // if they fail the zappermask, its like the req is NOT even there... if((comp.getCompiledMask()!=null) &&(!CMLib.masking().maskCheck(comp.getCompiledMask(),mob,true))) continue; amt[0]=comp.getAmount(); thisSet.clear(); found=false; if(comp.getLocation()!=CompLocation.ONGROUND) { for(int ii=0;ii<mob.numItems();ii++) { found=IsItemComponent(mob, comp, amt, mob.getItem(ii), thisSet,mithrilOK); if(found) break; } } if((!found) &&(room!=null) &&((comp.getLocation()==CompLocation.ONGROUND)||(comp.getLocation()==CompLocation.NEARBY))) { for(int ii=0;ii<room.numItems();ii++) { found=IsItemComponent(mob, comp, amt, room.getItem(ii), thisSet,mithrilOK); if(found) break; } } if((amt[0]>0)&&(currentAND)&&(i>0)) return null; previousValue=amt[0]<=0; if(previousValue) passes.addAll(thisSet); } if(passes.size()==0) return null; return passes; } @Override public List<AbilityComponent> getAbilityComponents(final String AID) { return getAbilityComponentMap().get(AID.toUpperCase().trim()); } protected List<PairList<String,String>> getAbilityComponentCodedPairsList(final String AID) { return getAbilityComponentCodedListLists(getAbilityComponents(AID)); } @Override public PairList<String,String> getAbilityComponentCoded(final AbilityComponent comp) { final PairList<String,String> curr=new PairVector<String,String>(); String itemDesc=null; curr.add("ANDOR",comp.getConnector()==AbilityComponent.CompConnector.AND?"&&":"||"); if(comp.getLocation()==AbilityComponent.CompLocation.HELD) curr.add("DISPOSITION","held"); else if(comp.getLocation()==AbilityComponent.CompLocation.WORN) curr.add("DISPOSITION","worn"); else if(comp.getLocation()==AbilityComponent.CompLocation.NEARBY) curr.add("DISPOSITION","nearby"); else if(comp.getLocation()==AbilityComponent.CompLocation.ONGROUND) curr.add("DISPOSITION","onground"); else if(comp.getLocation()==AbilityComponent.CompLocation.INVENTORY) curr.add("DISPOSITION","inventory"); if(comp.isConsumed()) curr.add("FATE","consumed"); else curr.add("FATE","kept"); curr.add("AMOUNT",""+comp.getAmount()); if(comp.getType()==AbilityComponent.CompType.STRING) itemDesc=comp.getStringType(); else if(comp.getType()==AbilityComponent.CompType.MATERIAL) itemDesc=RawMaterial.Material.findByMask((int)comp.getLongType()).desc().toUpperCase(); else if(comp.getType()==AbilityComponent.CompType.RESOURCE) itemDesc=RawMaterial.CODES.NAME((int)comp.getLongType()).toUpperCase(); curr.add("COMPONENTID",itemDesc); curr.add("SUBTYPE",comp.getSubType()); curr.add("MASK",comp.getMaskStr()); return curr; } @Override public void setAbilityComponentCodedFromCodedPairs(final PairList<String,String> decodedDV, final AbilityComponent comp) { final String[] s=new String[7]; for(int i=0;i<7;i++) s[i]=decodedDV.get(i).second; if(s[0].equalsIgnoreCase("||")) comp.setConnector(AbilityComponent.CompConnector.OR); else comp.setConnector(AbilityComponent.CompConnector.AND); if(s[1].equalsIgnoreCase("held")) comp.setLocation(AbilityComponent.CompLocation.HELD); else if(s[1].equalsIgnoreCase("worn")) comp.setLocation(AbilityComponent.CompLocation.WORN); else if(s[1].equalsIgnoreCase("nearby")) comp.setLocation(AbilityComponent.CompLocation.NEARBY); else if(s[1].equalsIgnoreCase("onground")) comp.setLocation(AbilityComponent.CompLocation.ONGROUND); else comp.setLocation(AbilityComponent.CompLocation.INVENTORY); if(s[2].equalsIgnoreCase("consumed")) comp.setConsumed(true); else comp.setConsumed(false); comp.setAmount(CMath.s_int(s[3])); final String compType=s[4]; final String subType=s[5]; int depth=CMLib.materials().getResourceCode(compType,false); if(depth>=0) comp.setType(AbilityComponent.CompType.RESOURCE, Integer.valueOf(depth), subType); else { depth=CMLib.materials().getMaterialCode(compType,false); if(depth>=0) comp.setType(AbilityComponent.CompType.MATERIAL, Integer.valueOf(depth), subType); else comp.setType(AbilityComponent.CompType.STRING, s[4].toUpperCase().trim(), ""); } comp.setMask(s[6]); } protected List<PairList<String,String>> getAbilityComponentCodedListLists(final List<AbilityComponent> req) { if(req==null) return null; final List<PairList<String,String>> V=new Vector<PairList<String,String>>(); for(final AbilityComponent comp : req) V.add(getAbilityComponentCoded(comp)); return V; } @Override public AbilityComponent createBlankAbilityComponent() { final AbilityComponent comp = (AbilityComponent)CMClass.getCommon("DefaultAbilityComponent"); comp.setConnector(AbilityComponent.CompConnector.AND); comp.setLocation(AbilityComponent.CompLocation.INVENTORY); comp.setConsumed(false); comp.setAmount(1); comp.setType(AbilityComponent.CompType.STRING, "resource-material-item name", ""); comp.setMask(""); return comp; } @Override public String getAbilityComponentCodedString(final List<AbilityComponent> comps) { return getAbilityComponentCodedStringFromCodedList(getAbilityComponentCodedListLists(comps)); } protected String getAbilityComponentCodedStringFromCodedList(final List<PairList<String,String>> comps) { final StringBuilder buf=new StringBuilder(""); PairList<String,String> curr=null; for(int c=0;c<comps.size();c++) { curr=comps.get(c); if(curr==null) continue; if(c>0) buf.append(curr.get(0).second); buf.append("("); buf.append(curr.get(1).second); buf.append(":"); buf.append(curr.get(2).second); buf.append(":"); buf.append(curr.get(3).second); buf.append(":"); buf.append(curr.get(4).second); if(curr.get(5).second.toString().length()>0) buf.append("(").append(curr.get(5).second).append(")"); buf.append(":"); buf.append(curr.get(6).second); buf.append(")"); } return buf.toString(); } @Override public String getAbilityComponentCodedString(final String AID) { final StringBuffer buf=new StringBuffer(""); final List<PairList<String,String>> comps=getAbilityComponentCodedPairsList(AID); buf.append(getAbilityComponentCodedStringFromCodedList(comps)); return AID+"="+buf.toString(); } @Override public String getAbilityComponentDesc(final MOB mob, final AbilityComponent comp, final boolean useConnector) { int amt=0; String itemDesc=null; final StringBuffer buf=new StringBuffer(""); if(useConnector) buf.append(comp.getConnector()==AbilityComponent.CompConnector.AND?", and ":", or "); if((mob!=null) &&(comp.getCompiledMask()!=null) &&(!CMLib.masking().maskCheck(comp.getCompiledMask(),mob,true))) return ""; if(mob==null) { if(comp.getCompiledMask()!=null) buf.append("MASK: "+comp.getMaskStr()+": "); } amt=comp.getAmount(); String subType=comp.getSubType(); if(subType.trim().length()>0) { subType=subType.trim().toLowerCase(); if(comp.getType()==AbilityComponent.CompType.STRING) itemDesc=((amt>1)?(amt+" "+CMLib.english().makePlural(comp.getStringType())):CMLib.english().startWithAorAn(comp.getStringType())); else if(comp.getType()==AbilityComponent.CompType.MATERIAL) { if(subType.indexOf(' ')>0) itemDesc=amt+" "+subType; else itemDesc=amt+" "+RawMaterial.Material.findByMask((int)comp.getLongType()).noun().toLowerCase()+" ("+subType+") "; } else if(comp.getType()==AbilityComponent.CompType.RESOURCE) { final String matName=RawMaterial.CODES.NAME((int)comp.getLongType()).toLowerCase(); if(subType.equals(matName) && (((comp.getLongType()&RawMaterial.MATERIAL_MASK)==RawMaterial.MATERIAL_CLOTH) ||((comp.getLongType()&RawMaterial.MATERIAL_MASK)==RawMaterial.MATERIAL_PAPER))) itemDesc=amt+" "+subType+" bolt"; else itemDesc=amt+" "+subType; } } else { if(comp.getType()==AbilityComponent.CompType.STRING) itemDesc=((amt>1)?(amt+" "+comp.getStringType()+"s"):CMLib.english().startWithAorAn(comp.getStringType())); else if(comp.getType()==AbilityComponent.CompType.MATERIAL) itemDesc=amt+((amt>1)?" pounds":" pound")+" of "+RawMaterial.Material.findByMask((int)comp.getLongType()).noun().toLowerCase(); else if(comp.getType()==AbilityComponent.CompType.RESOURCE) itemDesc=amt+((amt>1)?" pounds":" pound")+" of "+RawMaterial.CODES.NAME((int)comp.getLongType()).toLowerCase(); } if(comp.getLocation()==AbilityComponent.CompLocation.INVENTORY) buf.append(itemDesc); else if(comp.getLocation()==AbilityComponent.CompLocation.HELD) buf.append(itemDesc+" held"); else if(comp.getLocation()==AbilityComponent.CompLocation.WORN) buf.append(L("@x1 worn or wielded",itemDesc)); else if(comp.getLocation()==AbilityComponent.CompLocation.NEARBY) buf.append(itemDesc+" nearby"); else if(comp.getLocation()==AbilityComponent.CompLocation.ONGROUND) buf.append(L("@x1 on the ground",itemDesc)); return buf.toString(); } @Override public String getAbilityComponentDesc(final MOB mob, final String AID) { return getAbilityComponentDesc(mob,getAbilityComponents(AID)); } @Override public String getAbilityComponentDesc(final MOB mob, final List<AbilityComponent> req) { if(req==null) return null; final StringBuffer buf=new StringBuffer(""); for (int r = 0; r < req.size(); r++) { buf.append(getAbilityComponentDesc(mob, req.get(r), r>0)); } return buf.toString(); } @Override public String addAbilityComponent(final String s, final Map<String, List<AbilityComponent>> H) { int x=s.indexOf('='); if(x<0) return "Malformed component line (code 0): "+s; final String id=s.substring(0,x).toUpperCase().trim(); String parms=s.substring(x+1); String parmS=null; String rsc=null; List<AbilityComponent> parm=null; AbilityComponent build=null; int depth=0; parm=new Vector<AbilityComponent>(); String error=null; while(parms.length()>0) { build=(AbilityComponent)CMClass.getCommon("DefaultAbilityComponent"); build.setConnector(AbilityComponent.CompConnector.AND); if(parms.startsWith("||")) { build.setConnector(AbilityComponent.CompConnector.OR); parms=parms.substring(2).trim(); } else if(parms.startsWith("&&")) { parms = parms.substring(2).trim(); } if (!parms.startsWith("(")) { error = "Malformed component line (code 1): " + parms; break; } depth=0; x=1; for(;x<parms.length();x++) { if((parms.charAt(x)==')')&&(depth==0)) break; else if(parms.charAt(x)=='(') depth++; else if(parms.charAt(x)==')') depth--; } if (x == parms.length()) { error = "Malformed component line (code 2): " + parms; break; } parmS=parms.substring(1,x).trim(); parms=parms.substring(x+1).trim(); build.setLocation(AbilityComponent.CompLocation.INVENTORY); x=parmS.indexOf(':'); if(x<0) { error="Malformed component line (code 0-1): "+parmS; continue; } if(parmS.substring(0,x).equalsIgnoreCase("held")) build.setLocation(AbilityComponent.CompLocation.HELD); else if(parmS.substring(0,x).equalsIgnoreCase("worn")) build.setLocation(AbilityComponent.CompLocation.WORN); else if(parmS.substring(0,x).equalsIgnoreCase("nearby")) build.setLocation(AbilityComponent.CompLocation.NEARBY); else if(parmS.substring(0,x).equalsIgnoreCase("onground")) build.setLocation(AbilityComponent.CompLocation.ONGROUND); else if((x>0)&&(!parmS.substring(0,x).equalsIgnoreCase("inventory"))) { error="Malformed component line (code 0-2): "+parmS; continue; } parmS=parmS.substring(x+1); build.setConsumed(true); x=parmS.indexOf(':'); if (x < 0) { error = "Malformed component line (code 1-1): " + parmS; continue; } if(parmS.substring(0,x).equalsIgnoreCase("kept")) build.setConsumed(false); else if((x>0)&&(!parmS.substring(0,x).equalsIgnoreCase("consumed"))) { error="Malformed component line (code 1-2): "+parmS; continue; } parmS=parmS.substring(x+1); build.setAmount(1); x=parmS.indexOf(':'); if (x < 0) { error = "Malformed component line (code 2-1): " + parmS; continue; } if((x>0)&&(!CMath.isInteger(parmS.substring(0,x)))) { error="Malformed component line (code 2-2): "+parmS; continue; } if(x>0) build.setAmount(CMath.s_int(parmS.substring(0,x))); parmS=parmS.substring(x+1); build.setType(AbilityComponent.CompType.STRING, "", ""); x=parmS.indexOf(':'); if (x <= 0) { error = "Malformed component line (code 3-1): " + parmS; continue; } rsc=parmS.substring(0,x); String compType=rsc; String subType=""; if(rsc.endsWith(")")) { final int y=rsc.lastIndexOf('('); if(y>0) { compType=rsc.substring(0, y); subType=rsc.substring(y+1,rsc.length()-1); } } depth=CMLib.materials().getResourceCode(compType,false); if(depth>=0) build.setType(AbilityComponent.CompType.RESOURCE, Long.valueOf(depth), subType); else { depth=CMLib.materials().getMaterialCode(compType,false); if(depth>=0) build.setType(AbilityComponent.CompType.MATERIAL, Long.valueOf(depth), subType); else build.setType(AbilityComponent.CompType.STRING, rsc.toUpperCase().trim(), ""); } parmS=parmS.substring(x+1); build.setMask(parmS); parm.add(build); } if(parm instanceof Vector) ((Vector<?>)parm).trimToSize(); if(parm instanceof SVector) ((SVector<?>)parm).trimToSize(); if(error!=null) return error; if(parm.size()>0) H.put(id.toUpperCase(),parm); return null; } // format of each data entry is 1=ANDOR(B), 2=DISPO(I), 3=CONSUMED(B), 4=AMT(I), 5=MATERIAL(L)RESOURCE(I)NAME(S), 6=MASK(S) @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Map<String, List<AbilityComponent>> getAbilityComponentMap() { Map<String, List<AbilityComponent>> H=(Map)Resources.getResource("COMPONENT_MAP"); if(H==null) { H=new Hashtable<String,List<AbilityComponent>>(); final StringBuffer buf=new CMFile(Resources.makeFileResourceName("skills/components.txt"),null,CMFile.FLAG_LOGERRORS).text(); List<String> V=new Vector<String>(); if(buf!=null) V=Resources.getFileLineVector(buf); String s=null; String error=null; if(V!=null) for(int v=0;v<V.size();v++) { s=V.get(v).trim(); if(s.startsWith("#")||(s.length()==0)||s.startsWith(";")||s.startsWith(":")) continue; error=addAbilityComponent(s,H); if(error!=null) Log.errOut("CMAble",error); } Resources.submitResource("COMPONENT_MAP",H); } return H; } @Override public MaterialLibrary.DeadResourceRecord destroyAbilityComponents(final List<Object> found) { final MaterialLibrary.DeadResourceRecord record = new MaterialLibrary.DeadResourceRecord(); if((found==null)||(found.size()==0)) { return record; } final XVector<Ability> props=new XVector<Ability>(); record.lostProps=props; while(found.size()>0) { int i=0; boolean destroy=false; for(;i<found.size();i++) { if(found.get(i) instanceof Boolean) { destroy = ((Boolean) found.get(i)).booleanValue(); break; } } while(i>=0) { if((destroy) &&(found.get(0) instanceof Item)) { props.addAll(((Item)found.get(0)).effects()); record.lostAmt += ((Item)found.get(0)).basePhyStats().weight(); record.lostValue +=((Item)found.get(0)).value(); ((Item)found.get(0)).destroy(); } found.remove(0); i--; } } return record; } @Override public void alterAbilityComponentFile(final String compID, final boolean delete) { final CMFile F=new CMFile(Resources.makeFileResourceName("skills/components.txt"),null,CMFile.FLAG_LOGERRORS); if(delete) { Resources.findRemoveProperty(F, compID); return; } final String parms=getAbilityComponentCodedString(compID); final StringBuffer text=F.textUnformatted(); boolean lastWasCR=true; boolean addIt=true; int delFromHere=-1; final String upID=compID.toUpperCase(); for(int t=0;t<text.length();t++) { if(text.charAt(t)=='\n') lastWasCR=true; else if(text.charAt(t)=='\r') lastWasCR=true; else if(Character.isWhitespace(text.charAt(t))) continue; else if((lastWasCR)&&(delFromHere>=0)) { text.delete(delFromHere,t); text.insert(delFromHere,parms+'\n'); delFromHere=-1; addIt=false; break; } else if((lastWasCR)&&(Character.toUpperCase(text.charAt(t))==upID.charAt(0))) { if((text.substring(t).toUpperCase().startsWith(upID)) &&(text.substring(t+upID.length()).trim().startsWith("="))) { addIt=false; delFromHere=t; } lastWasCR=false; } else lastWasCR=false; } if(delFromHere>0) { text.delete(delFromHere,text.length()); text.append(parms+'\n'); } if(addIt) { if(!lastWasCR) text.append('\n'); text.append(parms+'\n'); } F.saveText(text.toString(),false); } @Override public AbilityLimits getSpecialSkillLimit(final MOB studentM) { final AbilityLimits aL = new AbilityLimits() { private int commonSkills = 0; private int maxCommonSkills = 0; private int craftingSkills = 0; private int maxCraftingSkills = 0; private int nonCraftingSkills = 0; private int maxNonCraftingSkills= 0; private int specificSkillLimit = 0; private int maxLanguageSkills = 0; private int languageSkills = 0; @Override public AbilityLimits commonSkills(final int newVal) { commonSkills = newVal; if(newVal > maxCommonSkills) maxCommonSkills = newVal; return this; } @Override public AbilityLimits craftingSkills(final int newVal) { craftingSkills = newVal; if(newVal > maxCraftingSkills) maxCraftingSkills = newVal; return this; } @Override public AbilityLimits nonCraftingSkills(final int newVal) { nonCraftingSkills = newVal; if(newVal > maxNonCraftingSkills) maxNonCraftingSkills = newVal; return this; } @Override public AbilityLimits languageSkills(final int newVal) { languageSkills = newVal; if(newVal > maxLanguageSkills) maxLanguageSkills = newVal; return this; } @Override public AbilityLimits specificSkillLimit(final int newVal) { specificSkillLimit = newVal; return this; } @Override public int commonSkills() { return commonSkills; } @Override public int craftingSkills() { return craftingSkills; } @Override public int languageSkills() { return languageSkills; } @Override public int nonCraftingSkills() { return nonCraftingSkills; } @Override public int maxCommonSkills() { return maxCommonSkills; } @Override public int maxCraftingSkills() { return maxCraftingSkills; } @Override public int maxNonCraftingSkills() { return maxNonCraftingSkills; } @Override public int specificSkillLimit() { return specificSkillLimit; } @Override public int maxLanguageSkills() { return maxLanguageSkills; } }; CharClass C = null; if(studentM!=null) { C=studentM.charStats().getCurrentClass(); } if(C!=null) { if(C.maxCommonSkills() == 0) aL.commonSkills(Integer.MAX_VALUE); else aL.commonSkills(C.maxCommonSkills()); if(C.maxCraftingSkills() == 0) aL.craftingSkills(Integer.MAX_VALUE); else aL.craftingSkills(C.maxCraftingSkills()); if(C.maxNonCraftingSkills() == 0) aL.nonCraftingSkills(Integer.MAX_VALUE); else aL.nonCraftingSkills(C.maxNonCraftingSkills()); if(C.maxLanguages() == 0) aL.languageSkills(Integer.MAX_VALUE); else aL.languageSkills(C.maxLanguages()); } if((studentM != null) && (studentM.playerStats() != null)) { final PlayerStats pStats = studentM.playerStats(); if (aL.commonSkills() < Integer.MAX_VALUE) { aL.commonSkills(aL.commonSkills() + pStats.getBonusCommonSkillLimits()); if(pStats.getAccount() != null) aL.commonSkills(aL.commonSkills() + pStats.getAccount().getBonusCommonSkillLimits()); } if (aL.craftingSkills() < Integer.MAX_VALUE) { aL.craftingSkills(aL.craftingSkills() + pStats.getBonusCraftingSkillLimits()); if(pStats.getAccount() != null) aL.craftingSkills(aL.craftingSkills() + pStats.getAccount().getBonusCraftingSkillLimits()); } if (aL.nonCraftingSkills() < Integer.MAX_VALUE) { aL.nonCraftingSkills(aL.nonCraftingSkills() + pStats.getBonusNonCraftingSkillLimits()); if(pStats.getAccount() != null) aL.nonCraftingSkills(aL.nonCraftingSkills() + pStats.getAccount().getBonusNonCraftingSkillLimits()); } if (aL.maxLanguageSkills() < Integer.MAX_VALUE) { aL.languageSkills(aL.languageSkills() + pStats.getBonusLanguageLimits()); if(pStats.getAccount() != null) aL.languageSkills(aL.languageSkills() + pStats.getAccount().getBonusLanguageLimits()); } } return aL; } @Override public AbilityLimits getSpecialSkillLimit(final MOB studentM, final Ability A) { final AbilityLimits aL=getSpecialSkillLimit(studentM); aL.specificSkillLimit(Integer.MAX_VALUE); if(A==null) return aL; if(A instanceof CommonSkill) { final boolean crafting = ((A.classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_CRAFTINGSKILL) ||((A.classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_BUILDINGSKILL); aL.specificSkillLimit(crafting ? aL.craftingSkills() : aL.nonCraftingSkills()); } if((A.classificationCode()&Ability.ALL_ACODES)==Ability.ACODE_LANGUAGE) { aL.specificSkillLimit(aL.languageSkills()); } return aL; } @Override public AbilityLimits getSpecialSkillRemainder(final MOB studentM, final Ability A) { final AbilityLimits aL = getSpecialSkillRemainders(studentM); aL.specificSkillLimit(Integer.MAX_VALUE); if(A==null) return aL; if(A instanceof CommonSkill) { final boolean crafting = ((A.classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_CRAFTINGSKILL) ||((A.classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_BUILDINGSKILL); aL.specificSkillLimit(crafting ? aL.craftingSkills() : aL.nonCraftingSkills()); } if((A.classificationCode()&Ability.ALL_ACODES)==Ability.ACODE_LANGUAGE) { aL.specificSkillLimit(aL.languageSkills()); } return aL; } @Override public AbilityLimits getSpecialSkillRemainders(final MOB student) { final AbilityLimits aL = getSpecialSkillLimit(student); final CharStats CS=student.charStats(); if(CS.getCurrentClass()==null) return aL; final HashSet<String> culturalAbilities=new HashSet<String>(); final QuadVector<String,Integer,Integer,Boolean> culturalAbilitiesDV = student.baseCharStats().getMyRace().culturalAbilities(); for(int i=0;i<culturalAbilitiesDV.size();i++) culturalAbilities.add(culturalAbilitiesDV.getFirst(i).toLowerCase()); for(int a=0;a<student.numAbilities();a++) { final Ability A2=student.fetchAbility(a); if(A2 instanceof CommonSkill) { if(culturalAbilities.contains(A2.ID().toLowerCase())) continue; boolean foundInAClass=false; for(int c=0;c<CS.numClasses();c++) { if(CMLib.ableMapper().getQualifyingLevel(CS.getMyClass(c).ID(), false, A2.ID())>=0) { foundInAClass=true; break; } } if(foundInAClass) continue; aL.commonSkills(aL.commonSkills()-1); final boolean crafting = ((A2.classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_CRAFTINGSKILL) ||((A2.classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_BUILDINGSKILL); if(crafting) aL.craftingSkills(aL.craftingSkills()-1); else aL.nonCraftingSkills(aL.nonCraftingSkills()-1); } else if(((A2.classificationCode()&Ability.ALL_ACODES)==Ability.ACODE_LANGUAGE) &&(!A2.ID().equals("Common"))) { if(culturalAbilities.contains(A2.ID().toLowerCase())) continue; boolean foundInAClass=false; for(int c=0;c<CS.numClasses();c++) { if(CMLib.ableMapper().getQualifyingLevel(CS.getMyClass(c).ID(), false, A2.ID())>=0) { foundInAClass=true; break; } } if(foundInAClass) continue; aL.languageSkills(aL.languageSkills()-1); } } return aL; } }