package com.planet_ink.coffee_mud.Common; 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.AchievementLibrary.Achievement; import com.planet_ink.coffee_mud.Libraries.interfaces.AchievementLibrary.ExpertiseAward; import com.planet_ink.coffee_mud.Libraries.interfaces.AchievementLibrary.Tracker; import com.planet_ink.coffee_mud.Libraries.interfaces.ExpertiseLibrary.ExpertiseDefinition; import com.planet_ink.coffee_mud.Libraries.interfaces.XMLLibrary.XMLTag; import com.planet_ink.coffee_mud.Libraries.interfaces.XMLLibrary.XMLTag; import com.planet_ink.coffee_mud.core.interfaces.*; import com.planet_ink.coffee_mud.core.*; import com.planet_ink.coffee_mud.core.CMSecurity.SecGroup; import com.planet_ink.coffee_mud.core.collections.*; import com.planet_ink.coffee_mud.core.exceptions.CMException; 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.AccountStats.PrideStat; import com.planet_ink.coffee_mud.Common.interfaces.PlayerAccount.AccountFlag; import com.planet_ink.coffee_mud.Common.interfaces.TimeClock.TimePeriod; 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.StdMOB; import com.planet_ink.coffee_mud.MOBS.interfaces.*; import com.planet_ink.coffee_mud.MOBS.interfaces.MOB.Attrib; import com.planet_ink.coffee_mud.Races.interfaces.*; import java.util.*; /* Copyright 2003-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 DefaultPlayerStats implements PlayerStats { @Override public String ID() { return "DefaultPlayerStats"; } @Override public String name() { return ID(); } protected final static int TELL_STACK_MAX_SIZE=50; protected final static int GTELL_STACK_MAX_SIZE=50; protected long hygiene = 0; protected int theme = Area.THEME_FANTASY; protected String[] xtraValues = null; protected String lastIP = ""; protected long lLastDateTime = System.currentTimeMillis(); protected long lastXPDateTime = 0; protected long lastUpdated = 0; protected int rolePlayXP = 0; protected int maxRolePlayXP = Integer.MAX_VALUE; protected long lastRolePlayTm = System.currentTimeMillis(); protected int deferredXP = 0; protected int maxDeferredXP = 0; protected int channelMask; protected String email = ""; protected String password = ""; protected String colorStr = ""; protected String prompt = ""; protected String poofin = ""; protected String poofout = ""; protected String tranpoofin = ""; protected String tranpoofout = ""; protected String deathPoof = ""; protected String announceMsg = ""; protected String savedPose = ""; protected String notes = ""; protected int wrap = 78; protected int bonusCommonSk = 0; protected int bonusCraftSk = 0; protected int bonusNonCraftSk= 0; protected int bonusLanguages = 0; protected int bonusCharStatPt= 0; protected int pageBreak = CMProps.getIntVar(CMProps.Int.PAGEBREAK); protected int[] birthday = null; protected MOB replyTo = null; protected int replyType = 0; protected long replyTime = 0; protected Set<String> friends = new SHashSet<String>(); protected Set<String> ignored = new SHashSet<String>(); protected Set<String> subscriptions = new SHashSet<String>(); protected List<String> tellStack = new SVector<String>(); protected List<String> gtellStack = new SVector<String>(); protected List<String> titles = new SVector<String>(); protected Set<String> autoInvokeSet = new TreeSet<String>(); protected PlayerAccount account = null; protected SecGroup securityFlags = new SecGroup(new CMSecurity.SecFlag[]{}); protected long accountExpires = 0; protected RoomnumberSet visitedRoomSet = null; protected Set<String> introductions = new SHashSet<String>(); protected long[] prideExpireTime= new long[TimeClock.TimePeriod.values().length]; protected int[][] prideStats = new int[TimeClock.TimePeriod.values().length][AccountStats.PrideStat.values().length]; protected long[][] combatStats = new long[0][PlayerCombatStat.values().length]; protected ItemCollection extItems; protected volatile boolean isSavable = true; protected Map<String,Tracker> achievementers = new STreeMap<String,Tracker>(); protected Map<String,String> alias = new STreeMap<String,String>(); protected Map<String,Integer> legacy = new STreeMap<String,Integer>(); protected Map<String,int[]> combatSpams = new STreeMap<String,int[]>(); protected Set<PlayerFlag> playFlags = new SHashSet<PlayerFlag>(); protected Map<String, AbilityMapping> ableMap = new SHashtable<String, AbilityMapping>(); protected Map<String, ExpertiseDefinition> experMap = new SHashtable<String, ExpertiseDefinition>(); protected Map<CharClass,Map<String,Object>> classMap = new STreeMap<CharClass,Map<String,Object>>(); protected QuadVector<Integer, Long, String, Long> levelInfo = new QuadVector<Integer, Long, String, Long>(); public DefaultPlayerStats() { super(); xtraValues=CMProps.getExtraStatCodesHolder(this); extItems=(ItemCollection)CMClass.getCommon("WeakItemCollection"); } @Override public CMObject newInstance() { try { return getClass().newInstance(); } catch(final Exception e) { return new DefaultPlayerStats(); } } @Override public void initializeClass() { } @Override public CMObject copyOf() { try { final DefaultPlayerStats O=(DefaultPlayerStats)this.clone(); O.levelInfo=new QuadVector<Integer, Long, String, Long>(); O.levelInfo.addAll(levelInfo); if(visitedRoomSet!=null) O.visitedRoomSet=(RoomnumberSet)visitedRoomSet.copyOf(); else O.visitedRoomSet=null; O.securityFlags=securityFlags.copyOf(); O.friends=new SHashSet<String>(friends); O.ignored=new SHashSet<String>(ignored); O.subscriptions=new SHashSet<String>(subscriptions); O.tellStack=new SVector<String>(tellStack); O.gtellStack=new SVector<String>(gtellStack); O.titles=new SVector<String>(titles); O.alias=new SHashtable<String,String>(alias); O.legacy=new SHashtable<String,Integer>(legacy); O.xtraValues=(xtraValues==null)?null:(String[])xtraValues.clone(); O.extItems=(ItemCollection)extItems.copyOf(); O.playFlags = new SHashSet<PlayerFlag>(playFlags); return O; } catch(final CloneNotSupportedException e) { return new DefaultPlayerStats(); } } @Override public String getLastIP() { return lastIP; } @Override public void setLastIP(final String ip) { lastIP=ip; if(account != null) account.setLastIP(ip); } @Override public String getEmail() { if(account != null) return account.getEmail(); if(email==null) return ""; return email; } @Override public void setEmail(final String newAdd) { email=newAdd; if(account != null) account.setEmail(newAdd); } @Override public int getTheme() { return theme; } @Override public void setTheme(final int theme) { this.theme=theme; } @Override public long getLastUpdated() { return lastUpdated; } @Override public void setLastUpdated(final long time) { lastUpdated=time; if(account != null) account.setLastUpdated(time); } @Override public long getLastDateTime() { return lLastDateTime; } @Override public void setLastDateTime(final long C) { lLastDateTime=C; if(account != null) account.setLastDateTime(C); } @Override public String getPasswordStr() { return (account!=null)?account.getPasswordStr():password; } @Override public void setPassword(final String newPassword) { if(CMProps.getBoolVar(CMProps.Bool.HASHPASSWORDS) &&(!CMLib.encoder().isARandomHashString(newPassword))) password=CMLib.encoder().makeRandomHashString(newPassword); else password=newPassword; if(account != null) account.setPassword(password); } @Override public boolean matchesPassword(final String checkPass) { if(account!=null) return account.matchesPassword(checkPass); return CMLib.encoder().passwordCheck(checkPass, password); } @Override public int getWrap() { return wrap; } @Override public void setWrap(int newWrap) { if(newWrap > CMStrings.SPACES.length()) newWrap=CMStrings.SPACES.length(); wrap=newWrap; } @Override public int getPageBreak() { return pageBreak; } @Override public void setPageBreak(final int newBreak) { pageBreak=newBreak; } @Override public String getNotes() { return notes; } @Override public void setNotes(final String newnotes) { notes=newnotes; } @Override public boolean isSet(final PlayerFlag flag) { return playFlags.contains(flag); } @Override public void setFlag(final PlayerFlag flag, final boolean setOrUnset) { if(setOrUnset) playFlags.add(flag); else playFlags.remove(flag); } @Override public void setChannelMask(final int newMask) { channelMask=newMask; } @Override public int getChannelMask() { return channelMask; } @Override public MOB getReplyToMOB() { return replyTo; } @Override public int getReplyType() { return replyType; } @Override public long getReplyToTime() { return replyTime; } @Override public void setReplyTo(final MOB mob, final int replyType) { replyTo=mob; this.replyType=replyType; } @Override public void setPrompt(final String newPrompt) { prompt=newPrompt; } @Override public String getColorStr() { return colorStr; } @Override public void setColorStr(final String newColors) { colorStr=newColors; } @Override public String getAnnounceMessage() { return announceMsg; } @Override public void setAnnounceMessage(final String msg) { announceMsg=msg; } @Override public String getSavedPose() { return savedPose; } @Override public void setSavedPose(final String msg) { savedPose=msg; } @Override public String getPrompt() { if((prompt==null)||(prompt.length()==0)) { prompt=CMProps.getVar(CMProps.Str.DEFAULTPROMPT); if((prompt==null)||(prompt.length()==0)) return "^N%E<^h%hhp ^m%mm ^v%vmv^N>"; } return prompt; } @Override public boolean isIntroducedTo(final String name) { return introductions.contains(name.toUpperCase().trim()); } @Override public void introduceTo(final String name) { if((!isIntroducedTo(name))&&(name.trim().length()>0)) introductions.add(name.toUpperCase().trim()); } public SHashSet<String> getHashFrom(String str, final boolean trim) { final SHashSet<String> h=new SHashSet<String>(); if((str==null)||(str.length()==0)) return h; str=CMStrings.replaceAll(str,"<FRIENDS>",""); str=CMStrings.replaceAll(str,"<SUBSCRIPTIONS>",""); str=CMStrings.replaceAll(str,"<IGNORED>",""); str=CMStrings.replaceAll(str,"<INTROS>",""); str=CMStrings.replaceAll(str,"</INTROS>",""); str=CMStrings.replaceAll(str,"</FRIENDS>",""); str=CMStrings.replaceAll(str,"</SUBSCRIPTIONS>",""); str=CMStrings.replaceAll(str,"</IGNORED>",""); int x=str.indexOf(';'); while(x>=0) { final String fi=(trim?str.substring(0,x).trim():str.substring(0,x)); if(fi.length()>0) h.add(fi); str=str.substring(x+1); x=str.indexOf(';'); } if(str.trim().length()>0) h.add(trim?str.trim():str); return h; } @Override public void addTellStack(final String msg) { if(tellStack.size()>TELL_STACK_MAX_SIZE) tellStack.remove(0); tellStack.add(msg); } @Override public List<String> getTellStack() { return new ReadOnlyList<String>(tellStack); } private RoomnumberSet roomSet() { if(visitedRoomSet==null) visitedRoomSet=((RoomnumberSet)CMClass.getCommon("DefaultRoomnumberSet")); return visitedRoomSet; } @Override public void addGTellStack(final String msg) { if(gtellStack.size()>GTELL_STACK_MAX_SIZE) gtellStack.remove(0); gtellStack.add(msg); } @Override public List<String> getGTellStack() { return new ReadOnlyList<String>(gtellStack); } @Override public Set<String> getFriends() { if(account != null) return account.getFriends(); return friends; } @Override public Set<String> getSubscriptions() { if(account != null) return account.getSubscriptions(); return subscriptions; } @Override public Set<String> getIgnored() { if(account != null) return account.getIgnored(); return ignored; } @Override public boolean isIgnored(MOB mob) { if(mob==null) return false; if(account != null) return account.isIgnored(mob); if (mob.soulMate() != null) mob=mob.soulMate(); if(ignored.contains(mob.Name())) return true; final PlayerStats stats=mob.playerStats(); if(stats ==null) return false; final PlayerAccount account=stats.getAccount(); if(account == null) return false; return ignored.contains(account.getAccountName()+"*"); } @Override public boolean isIgnored(final String name) { if(name==null) return false; if(account != null) return account.isIgnored(name); return (ignored.contains(name) || ignored.contains(name+"*")); } @Override public Map<String,Object> getClassVariableMap(final CharClass charClass) { final Map<String,Object> map=this.classMap.get(charClass); if(map != null) return map; final Map<String,Object> newMap = new TreeMap<String,Object>(); this.classMap.put(charClass, newMap); return newMap; } @Override public String[] getAliasNames() { return alias.keySet().toArray(new String[0]); } @Override public String getAlias(final String named) { if(alias.containsKey(named.toUpperCase().trim())) return alias.get(named.toUpperCase().trim()); return ""; } @Override public void addAliasName(String named) { named=named.toUpperCase().trim(); if(getAlias(named).length()==0) alias.put(named,""); } @Override public void delAliasName(final String named) { alias.remove(named.toUpperCase().trim()); } @Override public void setAlias(final String named, final String value) { alias.put(named.toUpperCase().trim(),value); } public String getAliasXML() { if(alias.size()==0) return ""; final StringBuilder str=new StringBuilder(""); alias.remove(""); for(final String key : alias.keySet()) str.append("<ALIAS CMD=\"").append(key).append("\" VAL=\"").append(CMLib.xml().parseOutAngleBracketsAndQuotes(alias.get(key))).append("\" />"); return str.toString(); } public String getLegacyXML() { if(legacy.size()==0) return ""; final StringBuilder str=new StringBuilder(""); for(final String key : legacy.keySet()) str.append("<LEGACY CAT=\"").append(key).append("\" LVL=\"").append(legacy.get(key)).append("\" />"); return str.toString(); } @Override public String getActiveTitle() { if((titles==null)||(titles.size()==0)) return null; final String s=titles.get(0); if((s.length()<2)||(s.charAt(0)!='{')||(s.charAt(s.length()-1)!='}')) return s; return s.substring(1,s.length()-1); } @Override public List<String> getTitles() { return titles; } private String getTitleXML() { if(titles.size()==0) return ""; for(int t=titles.size()-1;t>=0;t--) { final String s=titles.get(t); if(s.length()==0) titles.remove(t); } final StringBuilder str=new StringBuilder(""); for(int t=0;t<titles.size();t++) { final String s=titles.get(t); str.append("<TITLE>"+CMLib.xml().parseOutAngleBrackets(CMLib.coffeeFilter().safetyFilter(s))+"</TITLE>"); } return str.toString(); } @Override public String getDeathPoof() { return deathPoof; } @Override public void setDeathPoof(final String poof) { if(poof != null) this.deathPoof=poof.trim(); } @Override public String getPoofIn() { return poofin; } @Override public String getPoofOut() { return poofout; } @Override public String getTranPoofIn() { return tranpoofin; } @Override public String getTranPoofOut() { return tranpoofout; } @Override public int[] getBirthday() { return birthday; } @Override public int initializeBirthday(TimeClock clock, int ageHours, final Race R) { if(clock == null) clock=CMLib.time().globalClock(); birthday=new int[4]; birthday[0]=clock.getDayOfMonth(); birthday[1]=clock.getMonth(); birthday[2]=clock.getYear(); birthday[3]=clock.getYear(); while(ageHours>15) { birthday[2]-=1; ageHours-=15; } if(ageHours>0) { birthday[1]=CMLib.dice().roll(1,clock.getMonthsInYear(),0); birthday[0]=CMLib.dice().roll(1,clock.getDaysInMonth(),0); } final int month=clock.getMonth(); final int day=clock.getDayOfMonth(); if((month<birthday[1])||((month==birthday[1])&&(birthday[0]<day))) return (R.getAgingChart()[Race.AGE_YOUNGADULT]+clock.getYear()-birthday[2])-1; return (R.getAgingChart()[Race.AGE_YOUNGADULT]+clock.getYear()-birthday[2]); } protected String getPrivateList(final Set<String> h) { if((h==null)||(h.size()==0)) return ""; final StringBuffer list=new StringBuffer(""); for (final String string : h) list.append((string)+";"); return list.toString(); } @Override public void bumpPrideStat(final PrideStat stat, final int amt) { final long now=System.currentTimeMillis(); if(stat!=null) for(final TimeClock.TimePeriod period : TimeClock.TimePeriod.values()) { if(period==TimeClock.TimePeriod.ALLTIME) prideStats[period.ordinal()][stat.ordinal()]+=amt; else { if(now>prideExpireTime[period.ordinal()]) { for(final AccountStats.PrideStat stat2 : AccountStats.PrideStat.values()) prideStats[period.ordinal()][stat2.ordinal()]=0; prideExpireTime[period.ordinal()]=period.nextPeriod(); } prideStats[period.ordinal()][stat.ordinal()]+=amt; } } } @Override public int getPrideStat(final TimePeriod period, final PrideStat stat) { if((period==null)||(stat==null)) return 0; return prideStats[period.ordinal()][stat.ordinal()]; } @Override public String getXML() { final String friendsStr=getPrivateList(getFriends()); final String ignoredStr=getPrivateList(getIgnored()); final String subscriptionStr=getPrivateList(getSubscriptions()); final String privateListStr=getPrivateList(introductions); final StringBuffer rest=new StringBuffer(""); final String[] codes=getStatCodes(); for(int x=getSaveStatIndex();x<codes.length;x++) { final String code=codes[x].toUpperCase(); rest.append("<"+code+">"+CMLib.xml().parseOutAngleBrackets(getStat(code))+"</"+code+">"); } rest.append("<NEXTPRIDEPERIODS>").append(CMParms.toTightListString(prideExpireTime)).append("</NEXTPRIDEPERIODS>"); rest.append("<PRIDESTATS>"); for(final TimeClock.TimePeriod period : TimeClock.TimePeriod.values()) rest.append(CMParms.toTightListString(prideStats[period.ordinal()])).append(";"); rest.append("</PRIDESTATS>"); rest.append("<ACHIEVEMENTS"); for(final Iterator<Tracker> i=achievementers.values().iterator();i.hasNext();) { final Tracker T = i.next(); if(T.getAchievement().isSavableTracker() && (T.getCount(null) != 0)) rest.append(" ").append(T.getAchievement().getTattoo()).append("=").append(T.getCount(null)); // getCount(null) should be ok, because it's only the un-savable trackers that need the mob obj } rest.append(" />"); rest.append("<PCCSTATS>") .append(bonusCommonSk).append(';') .append(bonusCraftSk).append(';') .append(bonusNonCraftSk).append(';') .append(bonusLanguages).append(';') .append(bonusCharStatPt).append(';') .append("</PCCSTATS>"); return ((friendsStr.length()>0)?"<FRIENDS>"+friendsStr+"</FRIENDS>":"") +((ignoredStr.length()>0)?"<IGNORED>"+ignoredStr+"</IGNORED>":"") +((privateListStr.length()>0)?"<INTROS>"+privateListStr+"</INTROS>":"") +((subscriptionStr.length()>0)?"<SUBSCRIPTIONS>"+subscriptionStr+"</SUBSCRIPTIONS>":"") +"<WRAP>"+wrap+"</WRAP>" +"<THEME>"+theme+"</THEME>" +"<PAGEBREAK>"+pageBreak+"</PAGEBREAK>" +((account!=null)?("<ACCOUNT>"+account.getAccountName()+"</ACCOUNT>"):"") +getTitleXML() +getAliasXML() +getLegacyXML() +"<ACCTEXP>"+accountExpires+"</ACCTEXP>" +((birthday!=null)?"<BIRTHDAY>"+CMParms.toListString(birthday)+"</BIRTHDAY>":"") +((deathPoof.length()>0)?"<DEATHPOOF>"+CMLib.xml().parseOutAngleBrackets(deathPoof)+"</DEATHPOOF>":"") +((poofin.length()>0)?"<POOFIN>"+CMLib.xml().parseOutAngleBrackets(poofin)+"</POOFIN>":"") +((notes.length()>0)?"<NOTES>"+CMLib.xml().parseOutAngleBrackets(notes)+"</NOTES>":"") +((poofout.length()>0)?"<POOFOUT>"+CMLib.xml().parseOutAngleBrackets(poofout)+"</POOFOUT>":"") +((announceMsg.length()>0)?"<ANNOUNCE>"+CMLib.xml().parseOutAngleBrackets(announceMsg)+"</ANNOUNCE>":"") +((savedPose.length()>0)?"<POSE>"+CMLib.xml().parseOutAngleBrackets(savedPose)+"</POSE>":"") +((tranpoofin.length()>0)?"<TRANPOOFIN>"+CMLib.xml().parseOutAngleBrackets(tranpoofin)+"</TRANPOOFIN>":"") +((tranpoofout.length()>0)?"<TRANPOOFOUT>"+CMLib.xml().parseOutAngleBrackets(tranpoofout)+"</TRANPOOFOUT>":"") +"<DATES>"+CMLib.xml().parseOutAngleBrackets(this.getLevelDateTimesStr())+"</DATES>" +"<SECGRPS>"+CMLib.xml().parseOutAngleBrackets(getSetSecurityFlags(null))+"</SECGRPS>" +"<AUTOINVSET>"+CMLib.xml().parseOutAngleBrackets(getStat("AUTOINVSET"))+"</AUTOINVSET>" +"<XP RP="+this.rolePlayXP+" MAXRP="+this.maxRolePlayXP+" DEF="+this.deferredXP+" MAXDEF="+this.maxDeferredXP+" />" +"<LASTXPMILLIS>"+this.lastXPDateTime+"</LASTXPMILLIS>" +((playFlags.size()>0)?"<FLAGS>"+this.getStat("FLAGS")+"</FLAGS>":"") +roomSet().xml() +rest.toString(); } private void setBirthday(final String bday) { if((bday!=null)&&(bday.length()>0)) { final List<String> V=CMParms.parseCommas(bday,true); birthday=new int[4]; for(int v=0;(v<V.size()) && (v<birthday.length);v++) birthday[v]=CMath.s_int(V.get(v)); if(V.size()<4) { final TimeClock C=CMLib.time().globalClock(); birthday[3]=C.getYear(); } } } private void setAliasXML(final List<XMLTag> xml) { alias.clear(); for (final XMLTag piece : xml) { if((piece.tag().equals("ALIAS"))&&(piece.parms()!=null)) { final String command=piece.getParmValue( "CMD"); final String value=piece.getParmValue( "VAL"); if((command!=null)&&(value!=null)) alias.put(command, CMLib.xml().restoreAngleBrackets(value)); } } int a=-1; while((++a)>=0) { final String name=CMLib.xml().getValFromPieces(xml,"ALIAS"+a); final String value=CMLib.xml().getValFromPieces(xml,"ALIASV"+a); if((name.length()==0)||(value.length()==0)) break; alias.put(name.toUpperCase().trim(),CMLib.xml().restoreAngleBrackets(value)); } } private void setLegacyXML(final List<XMLTag> xml) { legacy.clear(); for (final XMLTag piece : xml) { if((piece.tag().equals("LEGACY"))&&(piece.parms()!=null)) { final String category=piece.getParmValue( "CAT"); final String levelStr=piece.getParmValue( "LVL"); if((category!=null)&&(levelStr!=null)) legacy.put(category, Integer.valueOf(levelStr)); } } } private void setTitleXML(final List<XMLTag> xml) { titles.clear(); for (final XMLTag piece : xml) { if(piece.tag().equals("TITLE")) titles.add(CMLib.xml().restoreAngleBrackets(piece.value())); } int t=-1; while((++t)>=0) { final String title=CMLib.xml().restoreAngleBrackets(CMLib.xml().getValFromPieces(xml,"TITLE"+t)); if(title.length()==0) break; titles.add(title); } } @Override public Map<String, AbilityMapping> getExtraQualifiedSkills() { return ableMap; } @Override public void setXML(final String xmlStr) { account = null; if(xmlStr==null) return; final XMLLibrary xmlLib=CMLib.xml(); final boolean debug=CMSecurity.isDebugging(CMSecurity.DbgFlag.PLAYERSTATS); if(debug) Log.debugOut("XML="+xmlStr); final List<XMLLibrary.XMLTag> xml = xmlLib.parseAllXML(xmlStr); String str=xmlLib.getValFromPieces(xml,"FRIENDS"); if(debug) Log.debugOut("FRIENDS="+str); friends.clear(); friends.addAll(getHashFrom(str,true)); str=xmlLib.getValFromPieces(xml,"SUBSCRIPTIONS"); if(debug) Log.debugOut("SUBSCRIPTIONS="+str); subscriptions.clear(); subscriptions.addAll(getHashFrom(str,false)); final List<String> addThese=new ArrayList<String>(); for(final String s : subscriptions) { if((s.length()>3) &&(Character.isLetter(s.charAt(0))) &&(s.charAt(1)==' ') &&(s.charAt(2)==':')) addThese.add(s); } for(final String s : addThese) { subscriptions.remove(s); subscriptions.add(" "+s); } str=xmlLib.getValFromPieces(xml,"IGNORED"); if(debug) Log.debugOut("IGNORED="+str); ignored.clear(); ignored.addAll(getHashFrom(str,true)); str=xmlLib.getValFromPieces(xml,"INTROS"); if(debug) Log.debugOut("INTROS="+str); introductions.clear(); introductions.addAll(getHashFrom(str,true)); str=xmlLib.getValFromPieces(xml, "THEME"); if(debug) Log.debugOut("THEME="+str); if(CMath.isInteger(str)) theme=CMath.s_int(str); str = xmlLib.getValFromPieces(xml,"ACCTEXP"); if(debug) Log.debugOut("ACCTEXP="+str); if((str!=null)&&(str.length()>0)) setAccountExpiration(CMath.s_long(str)); else { final Calendar C=Calendar.getInstance(); C.add(Calendar.DATE,CMProps.getIntVar(CMProps.Int.TRIALDAYS)); setAccountExpiration(C.getTimeInMillis()); } str=xmlLib.getValFromPieces(xml,"WRAP"); if(debug) Log.debugOut("WRAP="+str); if(CMath.isInteger(str)) setWrap(CMath.s_int(str)); str=xmlLib.getValFromPieces(xml,"PAGEBREAK"); if(debug) Log.debugOut("PAGEBREAK="+str); if(CMath.isInteger(str)) pageBreak=CMath.s_int(str); else pageBreak=CMProps.getIntVar(CMProps.Int.PAGEBREAK); str=xmlLib.restoreAngleBrackets(xmlLib.getValFromPieces(xml,"SECGRPS")); if(debug) Log.debugOut("SECGRPS="+str); getSetSecurityFlags(str); setAliasXML(xml); setTitleXML(xml); setLegacyXML(xml); str=xmlLib.getValFromPieces(xml,"BIRTHDAY"); if(debug) Log.debugOut("BIRTHDAY="+str); setBirthday(str); deathPoof=xmlLib.getValFromPieces(xml,"DEATHPOOF"); if(debug) Log.debugOut("POOFIN="+deathPoof); if(deathPoof==null) deathPoof=""; deathPoof=xmlLib.restoreAngleBrackets(deathPoof); poofin=xmlLib.getValFromPieces(xml,"POOFIN"); if(debug) Log.debugOut("POOFIN="+poofin); if(poofin==null) poofin=""; poofin=xmlLib.restoreAngleBrackets(poofin); poofout=xmlLib.getValFromPieces(xml,"POOFOUT"); if(debug) Log.debugOut("POOFOUT="+poofout); if(poofout==null) poofout=""; poofout=xmlLib.restoreAngleBrackets(poofout); tranpoofin=xmlLib.getValFromPieces(xml,"TRANPOOFIN"); if(debug) Log.debugOut("TRANPOOFIN="+tranpoofin); if(tranpoofin==null) tranpoofin=""; tranpoofin=xmlLib.restoreAngleBrackets(tranpoofin); tranpoofout=xmlLib.getValFromPieces(xml,"TRANPOOFOUT"); if(debug) Log.debugOut("TRANPOOFOUT="+tranpoofout); if(tranpoofout==null) tranpoofout=""; tranpoofout=xmlLib.restoreAngleBrackets(tranpoofout); announceMsg=xmlLib.getValFromPieces(xml,"ANNOUNCE"); if(debug) Log.debugOut("ANNOUNCE="+announceMsg); if(announceMsg==null) announceMsg=""; announceMsg=xmlLib.restoreAngleBrackets(announceMsg); savedPose=xmlLib.getValFromPieces(xml,"POSE"); if(debug) Log.debugOut("POSE="+savedPose); if(savedPose==null) savedPose=""; savedPose=xmlLib.restoreAngleBrackets(savedPose); notes=xmlLib.getValFromPieces(xml,"NOTES"); if(debug) Log.debugOut("NOTES="+notes); if(notes==null) notes=""; notes=xmlLib.restoreAngleBrackets(notes); this.setStat("FLAGS", xmlLib.getValFromPieces(xml, "FLAGS")); str=xmlLib.restoreAngleBrackets(xmlLib.getValFromPieces(xml,"DATES")); if(debug) Log.debugOut("DATES="+str); if(str==null) str=""; // now parse all the level date/times int lastNum=Integer.MIN_VALUE; levelInfo.clear(); if(str.length()>0) { final List<String> sets=CMParms.parseSemicolons(str,true); for(int ss=0;ss<sets.size();ss++) { final String sStr=sets.get(ss); final List<String> twin=CMParms.parseCommas(sStr,true); if((twin.size()!=2)&&(twin.size()!=3)&&(twin.size()!=4)) continue; if(CMath.s_int(twin.get(0))>=lastNum) { lastNum=CMath.s_int(twin.get(0)); levelInfo.addElement(Integer.valueOf(lastNum), Long.valueOf(CMath.s_long(twin.get(1))), (twin.size()>2)?(String)twin.get(2):"", (twin.size()>3)?Long.valueOf(CMath.s_long(twin.get(3))):Long.valueOf(0)); } } } if(levelInfo.size()==0) levelInfo.addElement(Integer.valueOf(0),Long.valueOf(System.currentTimeMillis()),"",Long.valueOf(0)); str = xmlLib.getValFromPieces(xml,"AREAS"); if(debug) Log.debugOut("AREAS="+str); if(str!=null) roomSet().parseXML("<AREAS>"+str+"</AREAS>"); else roomSet().parseXML("<AREAS />"); final XMLTag achievePiece = xmlLib.getPieceFromPieces(xml, "ACHIEVEMENTS"); achievementers.clear(); for(final Enumeration<Achievement> a=CMLib.achievements().achievements(Agent.PLAYER);a.hasMoreElements();) { final Achievement A=a.nextElement(); if((achievePiece != null) && achievePiece.parms().containsKey(A.getTattoo())) achievementers.put(A.getTattoo(), A.getTracker(CMath.s_int(achievePiece.parms().get(A.getTattoo()).trim()))); else achievementers.put(A.getTattoo(), A.getTracker(0)); } final String[] codes=getStatCodes(); for(int i=getSaveStatIndex();i<codes.length;i++) { str=xmlLib.getValFromPieces(xml,codes[i].toUpperCase()); if(str==null) str=""; setStat(codes[i].toUpperCase(),xmlLib.restoreAngleBrackets(str)); } final String[] nextPeriods=xmlLib.getValFromPieces(xml, "NEXTPRIDEPERIODS").split(","); final String[] prideStats=xmlLib.getValFromPieces(xml, "PRIDESTATS").split(";"); final Pair<Long,int[]>[] finalPrideStats = CMLib.players().parsePrideStats(nextPeriods, prideStats); for(final TimeClock.TimePeriod period : TimeClock.TimePeriod.values()) { if(period.ordinal()<finalPrideStats.length) { this.prideExpireTime[period.ordinal()]=finalPrideStats[period.ordinal()].first.longValue(); this.prideStats[period.ordinal()]=finalPrideStats[period.ordinal()].second; } } str = xmlLib.getValFromPieces(xml,"ACCOUNT"); if(debug) Log.debugOut("ACCOUNT="+str); if(CMProps.isUsingAccountSystem()) { if((str != null)&&(str.length()>0)) account = CMLib.players().getLoadAccount(str); } final String[] allAccStats=xmlLib.getValFromPieces(xml, "PCCSTATS").split(";"); if(allAccStats.length>=5) { bonusCommonSk=CMath.s_int(allAccStats[0]); bonusCraftSk=CMath.s_int(allAccStats[1]); bonusNonCraftSk=CMath.s_int(allAccStats[2]); bonusLanguages=CMath.s_int(allAccStats[3]); bonusCharStatPt=CMath.s_int(allAccStats[4]); } setStat("AUTOINVSET",CMLib.xml().restoreAngleBrackets(xmlLib.getValFromPieces(xml,"AUTOINVSET"))); final XMLLibrary.XMLTag xpPiece = CMLib.xml().getPieceFromPieces(xml, "XP"); if(xpPiece != null) { this.maxRolePlayXP = CMath.s_int(xpPiece.getParmValue("MAXRP")); this.rolePlayXP = CMath.s_int(xpPiece.getParmValue("RP")); this.maxDeferredXP = CMath.s_int(xpPiece.getParmValue("MAXDEF")); this.deferredXP = CMath.s_int(xpPiece.getParmValue("DEF")); } this.lastXPDateTime=CMath.s_long(xmlLib.getValFromPieces(xml, "LASTXPMILLIS")); } private String getLevelDateTimesStr() { if(levelInfo.size()==0) levelInfo.add(Integer.valueOf(0),Long.valueOf(System.currentTimeMillis()),"",Long.valueOf(0)); final StringBuilder buf=new StringBuilder(""); for(int ss=0;ss<levelInfo.size();ss++) { buf.append(levelInfo.elementAtFirst(ss).toString()).append(","); buf.append(levelInfo.elementAtSecond(ss).toString()).append(","); buf.append(levelInfo.elementAtThird(ss).toString()).append(","); buf.append(levelInfo.elementAtFourth(ss).toString()).append(";"); } return buf.toString(); } @Override public String getSetSecurityFlags(final String newFlags) { if(newFlags != null) { securityFlags=CMSecurity.instance().createGroup("", CMParms.parseSemicolons(newFlags,true)); } return securityFlags.toString(';'); } @Override public CMSecurity.SecGroup getSecurityFlags() { return securityFlags; } @Override public void setPoofs(final String poofIn, final String poofOut, final String tranPoofIn, final String tranPoofOut) { poofin=poofIn; poofout=poofOut; tranpoofin=tranPoofIn; tranpoofout=tranPoofOut; } @Override public long getHygiene() { return hygiene; } @Override public void setHygiene(final long newVal) { hygiene=newVal; } @Override public boolean adjHygiene(final long byThisMuch) { hygiene+=byThisMuch; if(hygiene<1) { hygiene=0; return false; } return true; } @Override public Map<String, int[]> getCombatSpams() { return this.combatSpams; } // Acct Expire Code @Override public long getAccountExpiration() { return (account != null) ? account.getAccountExpiration() : accountExpires; } @Override public void setAccountExpiration(final long newVal) { if(account != null) account.setAccountExpiration(newVal); accountExpires=newVal; } @Override public boolean addRoomVisit(final Room R) { if((!CMSecurity.isDisabled(CMSecurity.DisFlag.ROOMVISITS)) &&(R!=null) &&(!CMath.bset(R.phyStats().sensesMask(),PhyStats.SENSE_ROOMUNEXPLORABLE)) &&(!(R.getArea() instanceof AutoGenArea)) &&(R.getArea()!=null) &&(!hasVisited(R))) { roomSet().add(CMLib.map().getExtendedRoomID(R)); return true; } return false; } @Override public boolean hasVisited(final Room R) { return roomSet().contains(CMLib.map().getExtendedRoomID(R)); } @Override public boolean hasVisited(final Area A) { final int numRooms=A.getAreaIStats()[Area.Stats.VISITABLE_ROOMS.ordinal()]; if(numRooms<=0) return true; return roomSet().roomCount(A.Name())>0; } @Override public void unVisit(final Room R) { if(R != null) { if(roomSet().contains(CMLib.map().getExtendedRoomID(R))) roomSet().remove(CMLib.map().getExtendedRoomID(R)); } } @Override public void unVisit(final Area A) { if(A != null) { Room R; for(final Enumeration<Room> r=A.getCompleteMap();r.hasMoreElements();) { R=r.nextElement(); if(roomSet().contains(CMLib.map().getExtendedRoomID(R))) roomSet().remove(CMLib.map().getExtendedRoomID(R)); } } } @Override public int percentVisited(final MOB mob, Area A) { if(A==null) { long totalRooms=0; long totalVisits=0; for(final Enumeration<Area> e=CMLib.map().areas();e.hasMoreElements();) { A=e.nextElement(); if((!CMLib.flags().isHidden(A)) &&(!CMath.bset(A.flags(),Area.FLAG_INSTANCE_CHILD))) { final int[] stats=A.getAreaIStats(); if(stats[Area.Stats.VISITABLE_ROOMS.ordinal()]>0) { totalRooms+=stats[Area.Stats.VISITABLE_ROOMS.ordinal()]; totalVisits+=roomSet().roomCount(A.Name()); } } } if(totalRooms==0) return 100; final double pct=CMath.div(totalVisits,totalRooms); return (int)Math.round(100.0*pct); } final int numRooms=A.getAreaIStats()[Area.Stats.VISITABLE_ROOMS.ordinal()]; if(numRooms<=0) return 100; final double pct=CMath.div(roomSet().roomCount(A.Name()),numRooms); return (int)Math.round(100.0*pct); } @Override public void killAchievementTracker(final Achievement A, final Tattooable tracked, final MOB mob) { if(achievementers.containsKey(A.getTattoo())) { achievementers.remove(A.getTattoo()); if(mob != null) { mob.delTattoo(A.getTattoo()); } } } @Override public Tracker getAchievementTracker(final Achievement A, final Tattooable tracked, final MOB mob) { final Tracker T; if(achievementers.containsKey(A.getTattoo())) { T=achievementers.get(A.getTattoo()); } else { T=A.getTracker(0); achievementers.put(A.getTattoo(), T); } return T; } @Override public void rebuildAchievementTracker(final Tattooable tracked, final MOB mob, final String achievementTattoo) { final Achievement A=CMLib.achievements().getAchievement(achievementTattoo); if(A!=null) { if(achievementers.containsKey(A.getTattoo())) achievementers.put(A.getTattoo(), A.getTracker(achievementers.get(A.getTattoo()).getCount(mob))); else achievementers.put(A.getTattoo(), A.getTracker(0)); } else achievementers.remove(achievementTattoo); } @Override public long leveledDateTime(final int level) { if(levelInfo.size()==0) levelInfo.add(Integer.valueOf(0),Long.valueOf(System.currentTimeMillis()),"",Long.valueOf(0)); long lowest=levelInfo.elementAtSecond(0).longValue(); for(int l=1;l<levelInfo.size();l++) { if(level==levelInfo.elementAtFirst(l).intValue()) return levelInfo.elementAtSecond(l).longValue(); else if(level<levelInfo.elementAtFirst(l).intValue()) return lowest; lowest=levelInfo.elementAtSecond(l).longValue(); } return lowest; } @Override public String leveledRoomID(final int level) { if(levelInfo.size()==0) levelInfo.add(Integer.valueOf(0),Long.valueOf(System.currentTimeMillis()),"",Long.valueOf(0)); for(int l=1;l<levelInfo.size();l++) { if(level==levelInfo.elementAtFirst(l).intValue()) return levelInfo.elementAtThird(l); else if(level<levelInfo.elementAtFirst(l).intValue()) return levelInfo.elementAtThird(l-1); } return ""; } @Override public long leveledMinutesPlayed(final int level) { if(levelInfo.size()==0) levelInfo.add(Integer.valueOf(0),Long.valueOf(System.currentTimeMillis()),"",Long.valueOf(0)); long age=levelInfo.elementAtFourth(0).longValue(); for(int l=1;l<levelInfo.size();l++) { if(level<levelInfo.elementAtFirst(l).intValue()) return age; age=levelInfo.elementAtFourth(l).longValue(); } return age; } @Override public void setLeveledDateTime(final int level, final long ageHours, final Room R) { if(levelInfo.size()==0) levelInfo.add(Integer.valueOf(0),Long.valueOf(System.currentTimeMillis()),"",Long.valueOf(0)); long lastTime=0; for(int l=0;l<levelInfo.size();l++) { final Quad<Integer, Long, String, Long> quad = levelInfo.elementAt(l); if(level==quad.first.intValue()) { quad.second = Long.valueOf(System.currentTimeMillis()); quad.third = CMLib.map().getExtendedRoomID(R); quad.fourth = Long.valueOf(ageHours); return; } else if((System.currentTimeMillis()-lastTime)<TimeManager.MILI_SECOND) return; else if(level<quad.first.intValue()) { levelInfo.insertElementAt(new Quad<Integer,Long,String,Long>( Integer.valueOf(level), Long.valueOf(System.currentTimeMillis()), CMLib.map().getExtendedRoomID(R), Long.valueOf(ageHours)),l); return; } lastTime=quad.second.longValue(); } if((System.currentTimeMillis()-lastTime)<TimeManager.MILI_SECOND) return; levelInfo.addElement(Integer.valueOf(level),Long.valueOf(System.currentTimeMillis()),CMLib.map().getExtendedRoomID(R),Long.valueOf(ageHours)); } @Override public int getTotalLegacyLevels() { int total=0; for(final Integer value : legacy.values()) total+=value.intValue(); return total; } @Override public void addLegacyLevel(final String category) { final Integer level=legacy.get(category); if(level != null) legacy.put(category, Integer.valueOf(level.intValue()+1)); else legacy.put(category, Integer.valueOf(1)); } @Override public int getLegacyLevel(final String category) { final Integer level=legacy.get(category); if(level != null) return level.intValue(); return 0; } @Override public Map<String,ExpertiseDefinition> getExtraQualifiedExpertises() { return experMap; } @Override public PlayerAccount getAccount() { return account; } @Override public void setAccount(final PlayerAccount account) { this.account = account; } @Override public ItemCollection getExtItems() { return extItems; } @Override public int getBonusCharStatPoints() { return this.bonusCharStatPt; } @Override public void setBonusCharStatPoints(final int bonus) { this.bonusCharStatPt = bonus; } @Override public int getBonusCommonSkillLimits() { return this.bonusCommonSk; } @Override public void setBonusCommonSkillLimits(final int bonus) { this.bonusCommonSk = bonus; } @Override public int getBonusCraftingSkillLimits() { return this.bonusCraftSk; } @Override public void setBonusCraftingSkillLimits(final int bonus) { this.bonusCraftSk = bonus; } @Override public int getBonusNonCraftingSkillLimits() { return this.bonusNonCraftSk; } @Override public void setBonusNonCraftingSkillLimits(final int bonus) { this.bonusNonCraftSk = bonus; } @Override public int getBonusLanguageLimits() { return this.bonusLanguages; } @Override public void setBonusLanguageLimits(final int bonus) { this.bonusLanguages = bonus; } @Override public int getMaxRolePlayXP() { return this.maxRolePlayXP; } @Override public void setMaxRolePlayXP(final int amt) { this.maxRolePlayXP = amt; } @Override public int getRolePlayXP() { return this.rolePlayXP; } @Override public void setRolePlayXP(final int amt) { if(amt < 0) return; if(amt > this.getMaxRolePlayXP()) this.rolePlayXP = this.getMaxRolePlayXP(); else this.rolePlayXP = amt; } @Override public long getLastRolePlayXPTime() { return this.lastRolePlayTm; } @Override public void setLastRolePlayXPTime(final long tm) { this.lastRolePlayTm = tm; } @Override public int getMaxDeferredXP() { return this.maxDeferredXP; } @Override public void setMaxDeferredXP(final int amt) { this.maxDeferredXP = amt; } @Override public int getDeferredXP() { return this.deferredXP; } @Override public void setDeferredXP(final int amt) { if(amt > getMaxDeferredXP()) this.deferredXP = this.getMaxDeferredXP(); else this.deferredXP = amt; } @Override public long getLastXPAwardMillis() { return this.lastXPDateTime; } @Override public void setLastXPAwardMillis(final long time) { this.lastXPDateTime = time; } protected static String[] CODES={"CLASS","FRIENDS","IGNORE","TITLES", "ALIAS","LASTIP","LASTDATETIME", "CHANNELMASK", "COLORSTR","PROMPT","POOFIN", "POOFOUT","TRANPOOFIN","TRAINPOOFOUT", "ANNOUNCEMSG","NOTES","WRAP","BIRTHDAY", "ACCTEXPIRATION","INTRODUCTIONS","PAGEBREAK", "SAVEDPOSE","THEME", "LEGLEVELS","BONUSCOMMON", "BONUSCRAFT","BONUSNONCRAFT","BONUSLANGS", "BONUSCHARSTATS","AUTOINVSET", "MAXRPXP","CURRRPXP", "MAXDEFXP","CURRDEFXP", "LASTXPAWARD","FLAGS","SUBSCRIPTIONS", "COMBATSTATS"}; @Override public String getStat(final String code) { switch(getCodeNum(code)) { case 0: return ID(); case 1: return getPrivateList(getFriends()); case 2: return getPrivateList(getIgnored()); case 3: return getTitleXML(); case 4: return getAliasXML(); case 5: return lastIP; case 6: return "" + lLastDateTime; case 7: return "" + channelMask; case 8: return colorStr; case 9: return prompt; case 10: return poofin; case 11: return poofout; case 12: return tranpoofin; case 13: return tranpoofout; case 14: return announceMsg; case 15: return notes; case 16: return "" + wrap; case 17: return CMParms.toListString(birthday); case 18: return "" + accountExpires; case 19: return getPrivateList(introductions); case 20: return "" + pageBreak; case 21: return "" + savedPose; case 22: return "" + theme; case 23: return "" + getTotalLegacyLevels(); case 24: return "" + bonusCommonSk; case 25: return "" + bonusCraftSk; case 26: return "" + bonusNonCraftSk; case 27: return "" + bonusLanguages; case 28: return "" + bonusCharStatPt; case 29: return CMParms.combineWith(autoInvokeSet, ','); case 30: return ""+this.maxRolePlayXP; case 31: return ""+this.rolePlayXP; case 32: return ""+this.maxDeferredXP; case 33: return ""+this.deferredXP; case 34: return ""+this.lastXPDateTime; case 35: return CMParms.toListString(playFlags); case 36: return getPrivateList(getSubscriptions()); case 37: { final StringBuilder str=new StringBuilder(""); if(combatStats.length>0) { for(final long[] list : this.combatStats) { if(list != null) str.append(CMParms.toTightListString(list)); str.append(';'); } while((str.length()>0) &&(str.charAt(str.length()-1)==';')) str.deleteCharAt(str.length()-1); } return str.toString(); } default: return CMProps.getStatCodeExtensionValue(getStatCodes(), xtraValues, code); } } @Override public void setStat(final String code, final String val) { switch(getCodeNum(code)) { case 0: break; case 1: { friends.clear(); friends.addAll(getHashFrom(val,true)); break; } case 2: { ignored.clear(); ignored.addAll(getHashFrom(val,true)); break; } case 3: setTitleXML(CMLib.xml().parseAllXML(val)); break; case 4: setAliasXML(CMLib.xml().parseAllXML(val)); break; case 5: lastIP = val; break; case 6: lLastDateTime = CMath.s_parseLongExpression(val); break; case 7: channelMask = CMath.s_parseIntExpression(val); break; case 8: colorStr = val; break; case 9: prompt = val; break; case 10: poofin = val; break; case 11: poofout = val; break; case 12: tranpoofin = val; break; case 13: tranpoofout = val; break; case 14: announceMsg = val; break; case 15: notes = val; break; case 16: setWrap(CMath.s_parseIntExpression(val)); break; case 17: setBirthday(val); break; case 18: accountExpires = CMath.s_parseLongExpression(val); break; case 19: { introductions.clear(); introductions.addAll(getHashFrom(val,true)); break; } case 20: pageBreak = CMath.s_parseIntExpression(val); break; case 21: savedPose = val; break; case 22: theme = CMath.s_parseIntExpression(val); break; case 23: break; // legacy levels case 24: bonusCommonSk = CMath.s_parseIntExpression(val); break; case 25: bonusCraftSk = CMath.s_parseIntExpression(val); break; case 26: bonusNonCraftSk = CMath.s_parseIntExpression(val); break; case 27: bonusLanguages = CMath.s_parseIntExpression(val); break; case 28: bonusCharStatPt = CMath.s_parseIntExpression(val); break; case 29: autoInvokeSet = new XTreeSet<String>(CMParms.parseAny(val,',',true)); break; case 30: this.maxRolePlayXP = CMath.s_parseIntExpression(val); break; case 31: this.setRolePlayXP(CMath.s_parseIntExpression(val)); break; case 32: this.maxDeferredXP = CMath.s_parseIntExpression(val); break; case 33: this.setDeferredXP(CMath.s_parseIntExpression(val)); break; case 34: this.lastXPDateTime = CMath.s_parseLongExpression(val); break; case 35: { playFlags = new SHashSet<PlayerFlag>(); for(final String s : CMParms.parseCommas(val.toUpperCase(),true)) { final PlayerFlag flag = (PlayerFlag)CMath.s_valueOf(PlayerFlag.class, s); if(flag != null) playFlags.add(flag); } break; } case 36: { subscriptions.clear(); subscriptions.addAll(getHashFrom(val,false)); final List<String> addThese=new ArrayList<String>(); for(final String s : subscriptions) { if((s.length()>3) &&(Character.isLetter(s.charAt(0))) &&(s.charAt(1)==' ') &&(s.charAt(2)==':')) addThese.add(s); } for(final String s : addThese) { subscriptions.remove(s); subscriptions.add(" "+s); } break; } case 37: { final List<String> lines = CMParms.parseSemicolons(val, false); while((lines.size()>0) && (lines.get(lines.size()-1).trim().length()==0)) lines.remove(lines.size()-1); combatStats=new long[lines.size()][PlayerCombatStat.values().length]; for(int level = 0; level<combatStats.length; level++) { final long[] levelLine = CMParms.parseLongList(lines.get(level), ','); if(levelLine.length < PlayerCombatStat.values().length) combatStats[level] = Arrays.copyOf(levelLine, PlayerCombatStat.values().length); else combatStats[level] = levelLine; } break; } default: CMProps.setStatCodeExtensionValue(getStatCodes(), xtraValues, code, val); break; } } @Override public boolean isOnAutoInvokeList(final String abilityID) { if(abilityID != null) { if(abilityID.equals("ANYTHING")) return this.autoInvokeSet.size()>0; return this.autoInvokeSet.contains(abilityID); } return false; } @Override public void addAutoInvokeList(final String abilityID) { this.autoInvokeSet.add(abilityID); } @Override public void removeAutoInvokeList(final String abilityID) { this.autoInvokeSet.remove(abilityID); } @Override public long bumpLevelCombatStat(final PlayerCombatStat stat, final int level, final int amt) { if((stat == null) || (level <= 0) || (CMSecurity.isDisabled(CMSecurity.DisFlag.COMBATSTATS)) || (level >= CMProps.getIntVar(CMProps.Int.LASTPLAYERLEVEL)+10)) return 0; if(level > combatStats.length) combatStats = Arrays.copyOf(combatStats, level); if(combatStats[level-1] == null) { combatStats[level-1] = new long[PlayerCombatStat.values().length]; combatStats[level-1][PlayerCombatStat.STATS_LEVEL.ordinal()] = level; } if((amt > 0) &&(amt < Integer.MAX_VALUE/2)) { if(Long.MAX_VALUE-combatStats[level-1][stat.ordinal()] > amt) combatStats[level-1][stat.ordinal()] += amt; } return combatStats[level-1][stat.ordinal()]; } @Override public int getSaveStatIndex() { return (xtraValues == null) ? getStatCodes().length : getStatCodes().length - xtraValues.length; } private static String[] codes=null; @Override public String[] getStatCodes() { if(codes==null) codes=CMProps.getStatCodesList(CODES,this); return codes; } @Override public boolean isStat(final String code) { return CMParms.indexOf(getStatCodes(), code.toUpperCase().trim()) >= 0; } protected int getCodeNum(final String code) { for(int i=0;i<CODES.length;i++) { if(code.equalsIgnoreCase(CODES[i])) return i; } return -1; } @Override public boolean sameAs(final PlayerStats E) { if(!(E instanceof DefaultPlayerStats)) return false; for(int i=0;i<getStatCodes().length;i++) { if(!E.getStat(getStatCodes()[i]).equals(getStat(getStatCodes()[i]))) return false; } return true; } @Override public int compareTo(final CMObject o) { return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o)); } @Override public void destroy() { friends.clear(); subscriptions.clear(); ignored.clear(); tellStack.clear(); gtellStack.clear(); titles.clear(); autoInvokeSet.clear(); account = null; visitedRoomSet = null; introductions.clear(); extItems.delAllItems(true); achievementers.clear(); alias.clear(); legacy.clear(); combatSpams.clear(); ableMap.clear(); experMap.clear(); levelInfo.clear(); combatStats=new long[0][PlayerCombatStat.values().length]; } @Override public boolean isSavable() { return isSavable; } @Override public boolean amDestroyed() { return false; } @Override public void setSavable(final boolean truefalse) { synchronized(this) { isSavable=truefalse; } } }