package com.planet_ink.coffee_mud.Common; import com.planet_ink.coffee_mud.core.interfaces.*; import com.planet_ink.coffee_mud.core.threads.ServiceEngine; import com.planet_ink.coffee_mud.core.*; import com.planet_ink.coffee_mud.core.collections.*; import com.planet_ink.coffee_mud.core.database.DBConnections; 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.Clan.Function; import com.planet_ink.coffee_mud.Common.interfaces.Clan.Authority; import com.planet_ink.coffee_mud.Common.interfaces.Clan.ClanVote; import com.planet_ink.coffee_mud.Common.interfaces.Clan.MemberRecord; import com.planet_ink.coffee_mud.Exits.interfaces.*; import com.planet_ink.coffee_mud.Items.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.DatabaseEngine.PlayerData; import com.planet_ink.coffee_mud.Libraries.interfaces.JournalsLibrary.ForumJournal; import com.planet_ink.coffee_mud.Libraries.interfaces.XMLLibrary.XMLTag; 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.util.*; /** * Portions Copyright (c) 2003 Jeremy Vyska * Portions Copyright (c) 2004-2016 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 DefaultClan implements Clan { @Override public String ID() { return "DefaultClan"; } private final int tickStatus = Tickable.STATUS_NOT; @Override public int getTickStatus() { return tickStatus; } protected String clanName=""; protected String clanCategory=null; protected String clanPremise=""; protected String clanRecall=""; protected String clanMorgue=""; protected String clanClass=""; protected int clanLevel=0; protected String clanDonationRoom=""; protected int clanTrophies=0; protected Boolean isRivalrous=null; protected int autoPosition=-1; protected String acceptanceSettings=""; protected int clanStatus=0; protected String lastClanKillRecord=null; protected double taxRate=0.0; protected volatile long exp=0; protected Object expSync = new Object(); protected List<ClanVote> voteList=null; protected List<Long> clanKills=new Vector<Long>(); protected Integer overrideMinClanMembers=null; protected long lastPropsReload=System.currentTimeMillis(); protected ItemCollection extItems = (ItemCollection)CMClass.getCommon("WeakItemCollection"); protected Map<String,long[]>relations=new Hashtable<String,long[]>(); protected int government=0; protected long lastGovernmentLoadTime=-1; protected ClanGovernment govt = null; protected final static List<Ability> empty=new XVector<Ability>(1,true); protected final List<Pair<Clan,Integer>> channelSet = new XVector<Pair<Clan,Integer>>(1,true); /** return a new instance of the object*/ @Override public CMObject newInstance() { try { return getClass().newInstance(); } catch (final Exception e) { return new DefaultClan(); } } @Override public void initializeClass() { } @Override public int compareTo(CMObject o) { return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o)); } @Override public CMObject copyOf() { try { final DefaultClan C=(DefaultClan)this.clone(); C.extItems=(ItemCollection)extItems.copyOf(); return C; } catch(final CloneNotSupportedException e) { return new DefaultClan(); } } @Override public ClanGovernment getGovernment() { return govt(); } protected ClanGovernment govt() { if((govt != null) && ((government < 0) || (lastGovernmentLoadTime == CMLib.clans().getLastGovernmentLoad()))) return govt; else { ClanGovernment govt = CMLib.clans().getStockGovernment(government); if(govt == null) { govt = CMLib.clans().getDefaultGovernment(); government = govt.getID(); } lastGovernmentLoadTime = CMLib.clans().getLastGovernmentLoad(); return govt; } } private synchronized void clanKills() { if(lastClanKillRecord==null) { final List<PlayerData> V=CMLib.database().DBReadData(clanID(),"CLANKILLS",clanID()+"/CLANKILLS"); clanKills.clear(); if(V.size()==0) lastClanKillRecord=""; else { lastClanKillRecord=V.get(0).xml(); final List<String> V2=CMParms.parseSemicolons(lastClanKillRecord,true); for(int v=0;v<V2.size();v++) clanKills.add(Long.valueOf(CMath.s_long(V2.get(v)))); } } } private void updateClanKills() { Long date=null; final StringBuffer str=new StringBuffer(""); for(int i=clanKills.size()-1;i>=0;i--) { date=clanKills.get(i); if(date.longValue()<(System.currentTimeMillis())) clanKills.remove(i); else str.append(date.longValue()+";"); } if((lastClanKillRecord==null)||(!lastClanKillRecord.equals(str.toString()))) { lastClanKillRecord=str.toString(); CMLib.database().DBReCreateData(clanID(),"CLANKILLS",clanID()+"/CLANKILLS",str.toString()); } } @Override public void updateVotes() { final StringBuffer str=new StringBuffer(""); for(final Enumeration<ClanVote> e=votes();e.hasMoreElements();) { final ClanVote CV=e.nextElement(); str.append(CMLib.xml().convertXMLtoTag("BY",CV.voteStarter)); str.append(CMLib.xml().convertXMLtoTag("FUNC",CV.function)); str.append(CMLib.xml().convertXMLtoTag("ON",""+CV.voteStarted)); str.append(CMLib.xml().convertXMLtoTag("STATUS",""+CV.voteStatus)); str.append(CMLib.xml().convertXMLtoTag("CMD",CV.matter)); if((CV.votes!=null)&&(CV.votes.size()>0)) { str.append("<VOTES>"); for(int v=0;v<CV.votes.size();v++) { str.append("<VOTE>"); str.append(CMLib.xml().convertXMLtoTag("BY",CV.votes.getFirst(v))); str.append(CMLib.xml().convertXMLtoTag("YN",CV.votes.getSecond(v).toString())); str.append("</VOTE>"); } str.append("</VOTES>"); } } if(str.length()>0) CMLib.database().DBReCreateData(clanID(),"CLANVOTES",clanID()+"/CLANVOTES","<BALLOTS>"+str.toString()+"</BALLOTS>"); else CMLib.database().DBDeleteData(clanID(),"CLANVOTES",clanID()+"/CLANVOTES"); } @Override public void addVote(ClanVote CV) { if(CV==null) return; votes(); voteList.add(CV); } @Override public void delVote(ClanVote CV) { votes(); voteList.remove(CV); } @Override public void recordClanKill(MOB killer, MOB killed) { clanKills(); clanKills.add(Long.valueOf(System.currentTimeMillis())); updateClanKills(); if((killer != null)&&(killed != null)) { if(killed.isMonster()) CMLib.database().DBUpdateClanKills(this.clanID(), killer.Name(), 1, 0); else CMLib.database().DBUpdateClanKills(this.clanID(), killer.Name(), 0, 1); } } @Override public int getCurrentClanKills(MOB killer) { if(killer==null) { clanKills(); return clanKills.size(); } else { final MemberRecord M = CMLib.database().DBGetClanMember(this.clanID(), killer.Name()); return M.playerpvps; } } @Override public boolean isOnlyFamilyApplicants() { return govt().isFamilyOnly(); } @Override public boolean isLoyaltyThroughItems() { return govt().isConquestItemLoyalty(); } @Override public boolean isWorshipConquest() { return govt().isConquestByWorship(); } @Override public long calculateMapPoints() { return calculateMapPoints(getControlledAreas()); } @Override public long calculateMapPoints(List<Area> controlledAreas) { long points=0; if(controlledAreas!=null) for(final Area A : controlledAreas) { final LegalBehavior B=CMLib.law().getLegalBehavior(A); if(B!=null) points+=B.controlPoints(); } return points; } @Override public List<Area> getControlledAreas() { final Vector<Area> done=new Vector<Area>(); for(final Enumeration<Area> e=CMLib.map().areas();e.hasMoreElements();) { final Area A=e.nextElement(); final LegalBehavior B=CMLib.law().getLegalBehavior(A); if(B!=null) { final String controller=B.rulingOrganization(); final Area A2=CMLib.law().getLegalObject(A); if(controller.equals(clanID())&&(!done.contains(A2))) done.addElement(A2); } } return done; } @Override public Enumeration<ClanVote> votes() { if(voteList==null) { final List<PlayerData> V=CMLib.database().DBReadData(clanID(),"CLANVOTES",clanID()+"/CLANVOTES"); voteList=new Vector<ClanVote>(); for(int v=0;v<V.size();v++) { final ClanVote CV=new ClanVote(); final String rawxml=V.get(v).xml(); if(rawxml.trim().length()==0) return new IteratorEnumeration<Clan.ClanVote>(voteList.iterator()); final List<XMLLibrary.XMLTag> xml=CMLib.xml().parseAllXML(rawxml); if(xml==null) { Log.errOut("Clans","Unable to parse: "+rawxml); return new IteratorEnumeration<Clan.ClanVote>(voteList.iterator()); } final List<XMLLibrary.XMLTag> voteData=CMLib.xml().getContentsFromPieces(xml,"BALLOTS"); if(voteData==null){ Log.errOut("Clans","Unable to get BALLOTS data."); return new IteratorEnumeration<Clan.ClanVote>(voteList.iterator());} CV.voteStarter=CMLib.xml().getValFromPieces(voteData,"BY"); CV.voteStarted=CMLib.xml().getLongFromPieces(voteData,"ON"); CV.function=CMLib.xml().getIntFromPieces(voteData,"FUNC"); CV.voteStatus=CMLib.xml().getIntFromPieces(voteData,"STATUS"); CV.matter=CMLib.xml().getValFromPieces(voteData,"CMD"); CV.votes=new PairVector<String,Boolean>(); final List<XMLLibrary.XMLTag> xV=CMLib.xml().getContentsFromPieces(voteData,"VOTES"); if((xV!=null)&&(xV.size()>0)) { for(int x=0;x<xV.size();x++) { final XMLTag iblk=xV.get(x); if((!iblk.tag().equalsIgnoreCase("VOTE"))||(iblk.contents()==null)) continue; final String userID=iblk.getValFromPieces("BY"); final boolean yn=iblk.getBoolFromPieces("YN"); CV.votes.addElement(userID,Boolean.valueOf(yn)); } } voteList.add(CV); } } return new IteratorEnumeration<Clan.ClanVote>(voteList.iterator()); } @Override public int getAutoPosition() { return autoPosition<0?govt().getAutoRole():autoPosition; } @Override public void setAutoPosition(int pos) { if(pos == govt().getAutoRole()) autoPosition=-1; else autoPosition=pos; } @Override public void setExp(long newexp) { synchronized(expSync) { final long oldxp=exp; exp=newexp; if(exp<0) exp=0; final LinkedList<CMath.CompiledOperation> form = govt().getXPCalculationFormula(); if(oldxp < exp) // we gained { double nextLevelXP = CMath.parseMathExpression(form, new double[]{getClanLevel()}, 0.0); while(exp > nextLevelXP) { setClanLevel(getClanLevel()+1); clanAnnounce(""+getGovernmentName()+" "+name()+" has attained clan level "+getClanLevel()+"!"); update(); nextLevelXP = CMath.parseMathExpression(form, new double[]{getClanLevel()}, 0.0); } } else if((oldxp > exp) && (getClanLevel()>1)) { double prevLevelXP = CMath.parseMathExpression(form, new double[]{getClanLevel()-1}, 0.0); while(exp < prevLevelXP) { setClanLevel(getClanLevel()-1); clanAnnounce(""+getGovernmentName()+" "+name()+" has reverted to clan level "+getClanLevel()+"!"); update(); prevLevelXP = CMath.parseMathExpression(form, new double[]{getClanLevel()-1}, 0.0); } } } } @Override public void adjExp(int howMuch) { if (howMuch != 0) setExp(getExp() + howMuch); } @Override public long getExp() { return exp; } @Override public int getTrophies() { return clanTrophies; } @Override public void setTrophies(int trophyFlag) { clanTrophies = trophyFlag; } @Override public void setTaxes(double rate) { taxRate=rate; } @Override public double getTaxes() { return taxRate; } @Override public int getClanRelations(String id) { final long i[]=relations.get(id.toUpperCase()); if(i!=null) return (int)i[0]; return REL_NEUTRAL; } @Override public long getLastRelationChange(String id) { final long i[]=relations.get(id.toUpperCase()); if(i!=null) return i[1]; return 0; } @Override public void setClanRelations(String id, int rel, long time) { relations.remove(id.toUpperCase()); final long[] i=new long[2]; i[0]=rel; i[1]=time; relations.put(id.toUpperCase(),i); } @Override public int getGovernmentID() { return government; } @Override public void setGovernmentID(int type) { government = type; lastGovernmentLoadTime = -1; } @Override public String getCategory() { if(clanCategory!=null) return clanCategory; return govt().getCategory(); } @Override public int getMinClanMembers() { if(overrideMinClanMembers!=null) return overrideMinClanMembers.intValue(); if(govt().getOverrideMinMembers()!=null) return govt().getOverrideMinMembers().intValue(); return CMProps.getIntVar(CMProps.Int.MINCLANMEMBERS); } @Override public void setMinClanMembers(int amt) { overrideMinClanMembers=null; if(govt().getOverrideMinMembers()!=null) { if(govt().getOverrideMinMembers().intValue()==amt) return; overrideMinClanMembers=Integer.valueOf(amt); } else { if(CMProps.getIntVar(CMProps.Int.MINCLANMEMBERS)==amt) return; overrideMinClanMembers=Integer.valueOf(amt); } } @Override public void setCategory(String newCategory) { if(govt().getCategory().equalsIgnoreCase(newCategory)) clanCategory=null; else clanCategory=newCategory; } @Override public boolean isRivalrous() { if(isRivalrous==null) return govt().isRivalrous(); return isRivalrous.booleanValue(); } @Override public void setRivalrous(boolean isRivalrous) { if(govt().isRivalrous()==isRivalrous) this.isRivalrous=null; else this.isRivalrous=Boolean.valueOf(isRivalrous); } @Override public void create() { CMLib.database().DBCreateClan(this); CMLib.clans().addClan(this); } @Override public void update() { CMLib.database().DBUpdateClan(this); } @Override public void addMember(MOB M, int role) { M.setClan(clanID(),role); CMLib.database().DBUpdateClanMembership(M.Name(), clanID(), role); updateClanPrivileges(M); } @Override public void delMember(MOB M) { CMLib.database().DBUpdateClanMembership(M.Name(), clanID(), -1); M.setClan(clanID(),-1); updateClanPrivileges(M); } @Override public boolean updateClanPrivileges(MOB M) { boolean did=false; if(M==null) return false; final Pair<Clan,Integer> p=M.getClanRole(clanID()); if((p!=null) && (getAuthority(p.second.intValue(),Function.CLAN_BENEFITS)!=Clan.Authority.CAN_NOT_DO)) { final CharClass CC=getClanClassC(); if((CC!=null) &&(CC.availabilityCode()!=0) &&(M.baseCharStats().getCurrentClass()!=CC)) { M.baseCharStats().setCurrentClass(CC); did=true; M.recoverCharStats(); } } M.delAbility(M.fetchAbility("Spell_ClanHome")); M.delAbility(M.fetchAbility("Spell_ClanDonate")); M.delAbility(M.fetchAbility("Spell_Flagportation")); if(M.playerStats()!=null) for(final ClanPosition pos : govt().getPositions()) { final String title="*, "+CMStrings.capitalizeAndLower(pos.getName())+" of "+name(); String existingTitle=null; for(final String titleCheck : M.playerStats().getTitles()) if(titleCheck.equalsIgnoreCase(title)) existingTitle=titleCheck; if((p!=null) &&(p.second.intValue()==pos.getRoleID()) &&(getAuthority(p.second.intValue(),Function.CLAN_TITLES)!=Clan.Authority.CAN_NOT_DO)) { if(!M.playerStats().getTitles().contains(title)) { if(existingTitle!=null) M.playerStats().getTitles().remove(existingTitle); M.playerStats().getTitles().add(title); } } else if(M.playerStats().getTitles().contains(title)) M.playerStats().getTitles().remove(title); else if(existingTitle!=null) M.playerStats().getTitles().remove(existingTitle); } if(p==null) { Item I=null; final Vector<Item> itemsToMove=new Vector<Item>(); for(int i=0;i<M.numItems();i++) { I=M.getItem(i); if(I instanceof ClanItem) itemsToMove.addElement(I); } for(int i=0;i<itemsToMove.size();i++) { I=itemsToMove.elementAt(i); if(I!=null) { Room R=null; if((getDonation()!=null) &&(getDonation().length()>0)) R=CMLib.map().getRoom(getDonation()); if((R==null) &&(getRecall()!=null) &&(getRecall().length()>0)) R=CMLib.map().getRoom(getRecall()); if(I instanceof Container) { final List<Item> V=((Container)I).getDeepContents(); for(int v=0;v<V.size();v++) V.get(v).setContainer(null); } I.setContainer(null); I.wearAt(Wearable.IN_INVENTORY); if(R!=null) R.moveItemTo(I); else if(M.isMine(I)) I.destroy(); did=true; } } } if((did)&&(!CMSecurity.isSaveFlag(CMSecurity.SaveFlag.NOPLAYERS))) CMLib.database().DBUpdatePlayer(M); return did; } @Override public void destroyClan() { final List<MemberRecord> members=getMemberList(); for(final MemberRecord member : members) { final MOB M=CMLib.players().getLoadPlayer(member.name); if(M!=null) { M.setClan(clanID(),-1); updateClanPrivileges(M); CMLib.database().DBUpdateClanMembership(M.Name(), clanID(), -1); } } CMLib.database().DBDeleteJournal("a Journal of "+getGovernmentName()+" "+getName(), null); CMLib.database().DBDeleteClan(this); CMLib.clans().removeClan(this); } protected CharClass getClanClassC() { if(clanClass.length()==0) return null; CharClass C=CMClass.getCharClass(clanClass); if(C==null) C=CMClass.findCharClass(clanClass); return C; } @Override public String getDetail(MOB mob) { final StringBuffer msg=new StringBuffer(""); final Pair<Clan,Integer> mobClanRole=(mob!=null)?(mob.getClanRole(clanID())):null; final boolean member=(mob!=null) &&(mobClanRole!=null) &&(getAuthority(mobClanRole.second.intValue(),Function.LIST_MEMBERS)!=Authority.CAN_NOT_DO); final boolean sysmsgs=(mob!=null)&&mob.isAttributeSet(MOB.Attrib.SYSOPMSGS); final LinkedList<CMath.CompiledOperation> form = govt().getXPCalculationFormula(); final double nextLevelXP = CMath.parseMathExpression(form, new double[]{getClanLevel()}, 0.0); msg.append(L("^x@x1 Profile :^.^N @x2\n\r" +"-----------------------------------------------------------------\n\r" +"@x3\n\r" +"-----------------------------------------------------------------\n\r" +"^xLevel :^.^N @x4"+ ((member||sysmsgs)?(" (Next at ^w@x5^Nxp)\n\r"):"\n\r") +"^xType :^.^N @x6\n\r", getGovernmentName(), clanID(), getPremise(), ""+getClanLevel(), ""+nextLevelXP, CMStrings.capitalizeAndLower(govt().getName())) ); if(getAcceptanceSettings().length()>0) { msg.append(L("^xQualifications :^.^N @x1\n\r",CMLib.masking().maskDesc(getAcceptanceSettings()))); if(getBasicRequirementMask().length()>0) msg.append(L("^x Plus :^.^N @x1\n\r",CMLib.masking().maskDesc(getBasicRequirementMask()))); } else if(getBasicRequirementMask().length()>0) msg.append(L("^xQualifications :^.^N @x1\n\r",CMLib.masking().maskDesc(getBasicRequirementMask()))); else msg.append(L("^xQualifications :^.^N Anyone may apply\n\r")); final CharClass clanC=getClanClassC(); if(clanC!=null) msg.append(L("^xClass :^.^N @x1\n\r",clanC.name())); msg.append(L("^xExp. Tax Rate :^.^N @x1%\n\r",""+((int)Math.round(getTaxes()*100)))); if(member||sysmsgs) { msg.append(L("^xExperience Pts. :^.^N @x1\n\r",""+getExp())); if(getMorgue().length()>0) { final Room R=CMLib.map().getRoom(getMorgue()); if(R!=null) msg.append(L("^xMorgue :^.^N @x1\n\r",R.displayText(mob))); } if(getDonation().length()>0) { final Room R=CMLib.map().getRoom(getDonation()); if(R!=null) msg.append(L("^xDonations :^.^N @x1\n\r",R.displayText(mob))); } if(getRecall().length()>0) { final Room R=CMLib.map().getRoom(getRecall()); if(R!=null) msg.append(L("^xRecall :^.^N @x1\n\r",R.displayText(mob))); } } final List<MemberRecord> members=getMemberList(); final Set<ClanPosition> sortedPositions=new HashSet<ClanPosition>(); for(int i=0;i<govt().getPositions().length;i++) { ClanPosition topRankedPos=null; for(final ClanPosition pos : govt().getPositions()) if((pos.isPublic()) &&(!sortedPositions.contains(pos)) &&((topRankedPos==null)||(pos.getRank() < topRankedPos.getRank()))) topRankedPos = pos; if(topRankedPos != null) { msg.append("^x"+CMStrings.padRight(CMStrings.capitalizeAndLower(topRankedPos.getPluralName()),16)+":^.^N "+crewList(members, topRankedPos.getRoleID())+"\n\r"); sortedPositions.add(topRankedPos); } } msg.append(L("^xTotal Members :^.^N @x1\n\r",""+members.size())); if(CMLib.clans().numClans()>1) { msg.append("-----------------------------------------------------------------\n\r"); msg.append("^x"+CMStrings.padRight(CMLib.lang().L("Clan Relations"),16)+":^.^N \n\r"); for(final Enumeration<Clan> e=CMLib.clans().clans();e.hasMoreElements();) { final Clan C=e.nextElement(); if((C!=this)&&(C.isRivalrous())) { msg.append("^x"+CMStrings.padRight(C.name(),16)+":^.^N "); msg.append(CMStrings.capitalizeAndLower(REL_DESCS[getClanRelations(C.clanID())])); final int orel=C.getClanRelations(clanID()); if(orel!=REL_NEUTRAL) msg.append(" (<-"+CMStrings.capitalizeAndLower(REL_DESCS[orel])+")"); msg.append("\n\r"); } } } if(member||sysmsgs) { updateClanPrivileges(mob); for(final ClanPosition pos : govt().getPositions()) { if((!pos.isPublic())&&(member) &&((pos.getRoleID()!=govt().getAutoRole())||(pos.getRoleID()==govt().getAcceptPos()))) { msg.append("-----------------------------------------------------------------\n\r" +"^x"+CMStrings.padRight(CMStrings.capitalizeAndLower(pos.getPluralName()),16) +":^.^N "+crewList(members, pos.getRoleID())+"\n\r"); } } if((mobClanRole!=null) &&(govt().getAutoRole()!=govt().getAcceptPos()) &&((getAuthority(mobClanRole.second.intValue(),Function.ACCEPT)!=Clan.Authority.CAN_NOT_DO)||sysmsgs)) { final ClanPosition pos=govt().getPositions()[getAutoPosition()]; msg.append("-----------------------------------------------------------------\n\r" +"^x"+CMStrings.padRight(CMStrings.capitalizeAndLower(pos.getPluralName()),16)+":^.^N "+crewList(members, pos.getRoleID())+"\n\r"); } } final Vector<String> control=new Vector<String>(); final List<Area> controlledAreas=getControlledAreas(); final long controlPoints=calculateMapPoints(controlledAreas); for(final Area A : controlledAreas) control.addElement(A.name()); if(control.size()>0) { msg.append("-----------------------------------------------------------------\n\r"); msg.append(L("^xClan Controlled Areas (% revolt):^.^N\n\r")); Collections.sort(control); int col=0; final int COL_LEN=CMLib.lister().fixColWidth(25.0,mob); for(int i=0;i<control.size();i++) { if((++col)>3) { msg.append("\n\r"); col=1; } final Area A=CMLib.map().getArea(control.elementAt(i)); if(A!=null) { final LegalBehavior B=CMLib.law().getLegalBehavior(A); final Area legalA=CMLib.law().getLegalObject(A); int pctRevolt=0; if((B!=null)&&(legalA!=null)) pctRevolt=B.revoltChance(); msg.append("^c"+CMStrings.padRight(A.name()+"^N ("+pctRevolt+"%)",COL_LEN)+"^N"); } } msg.append("\n\r"); } if((CMLib.clans().trophySystemActive())&&(getTrophies()!=0)) { msg.append("-----------------------------------------------------------------\n\r"); msg.append(L("^xTrophies awarded:^.^N\n\r")); for(final Trophy t : Trophy.values()) { if(CMath.bset(getTrophies(),t.flagNum())) { msg.append(t.codeString+" "); switch(t) { case Areas: msg.append("("+control.size()+") "); break; case Points: msg.append("("+controlPoints+") "); break; case Experience: msg.append("("+getExp()+") "); break; case Members: msg.append("("+members.size()+") "); break; case PlayerKills: msg.append("("+getCurrentClanKills(null)+") "); break; case MemberLevel: { msg.append("("+filterMedianLevel(getFullMemberList())+") "); break; } } msg.append(L(" Prize: @x1\n\r",CMLib.clans().translatePrize(t))); } } } if(((mobClanRole!=null)&&(getAuthority(mobClanRole.second.intValue(),Function.CLAN_BENEFITS)!=Clan.Authority.CAN_NOT_DO))||sysmsgs) { msg.append("-----------------------------------------------------------------\n\r"); msg.append(L("^xClan Level Benefits:^.^N\n\r")); final List<AbilityMapper.AbilityMapping> abilities=CMLib.ableMapper().getUpToLevelListings(govt().getName(),getClanLevel(),true,false); if(abilities.size()>0) { final List<String> names = new Vector<String>(); for(final AbilityMapper.AbilityMapping aMap : abilities) { final Ability A=CMClass.getAbility(aMap.abilityID()); if(A!=null) { if((aMap.extFields().size()==0) ||(mobClanRole==null) ||(sysmsgs) ||(aMap.extFields().containsKey(mobClanRole.second.toString()))) names.add(A.name()+(aMap.autoGain()?"":"(q)")+((aMap.extFields().size()>0)?"*":"")); } } msg.append(CMLib.lister().makeColumns(mob,names,null,3)); msg.append("\n\r"); } final int numReff=CMath.s_int(govt().getStat("NUMREFF")); for(int i=0;i<numReff;i++) { final String ableName=govt().getStat("GETREFF"+i); final String ableText=govt().getStat("GETREFFPARM"+i); final int ableLvl=CMath.s_int(govt().getStat("GETREFFLVL"+i)); final List<String> ableRoles=CMParms.parseCommas(govt().getStat("GETREFFROLE"+i),true); final Ability A=CMClass.getAbility(ableName); if((A!=null) &&(ableLvl<=this.clanLevel) &&((ableRoles.size()==0) ||(mobClanRole==null) ||(sysmsgs) ||(ableRoles.contains(mobClanRole.second.toString())))) { A.setMiscText(ableText); msg.append(A.accountForYourself()).append("\n\r"); } } } return msg.toString(); } public String L(final String str, final String ... xs) { return CMLib.lang().fullSessionTranslation(str, xs); } @Override public String getGovernmentName() { return CMStrings.capitalizeAndLower(govt().getName()); } @Override public boolean canBeAssigned(MOB mob, int role) { if(mob==null) return false; if((role<0)||(role>govt().getPositions().length)) return false; final ClanPosition pos = govt().getPositions()[role]; return CMLib.masking().maskCheck(fixRequirementMask(pos.getInnerMaskStr()), mob, true); } @Override public Authority getAuthority(int roleID, Function function) { if((roleID<0)||(roleID>=govt().getPositions().length)) return Authority.CAN_NOT_DO; return govt().getPositions()[roleID].getFunctionChart()[function.ordinal()]; } public String fixRequirementMask(final String oldMask) { if((oldMask==null)||(oldMask.trim().length()==0)) return ""; final StringBuffer mask=new StringBuffer(oldMask.trim()); if(mask.length()==0) return ""; final MOB M=getResponsibleMember(); int x=mask.indexOf("%["); while(x>=0) { final int y=mask.indexOf("]%",x+1); if(y>x) { final String tag=mask.substring(x+2,y); String value="Unknown"; if(isStat(tag)) value=getStat(tag); else if(M!=null) { if(tag.equalsIgnoreCase("WORSHIPCHARID")) { value=M.getWorshipCharID(); if(value.length()==0) value="ANY"; } else if(CMLib.coffeeMaker().isAnyGenStat(M, tag)) value=CMLib.coffeeMaker().getAnyGenStat(M, tag); } else if(tag.equalsIgnoreCase("WORSHIPCHARID")) value="ANY"; mask.replace(x, y+2, value); } if(x>=mask.length()-1) break; x=mask.indexOf("%[",x+1); } return mask.toString(); } @Override public String getBasicRequirementMask() { return fixRequirementMask(govt().getRequiredMaskStr()); } protected List<MemberRecord> getRealMemberList(int PosFilter) { final List<MemberRecord> members=getMemberList(PosFilter); if(members==null) return null; final List<MemberRecord> realMembers=new Vector<MemberRecord>(); for(final MemberRecord member : members) { if(CMLib.players().playerExists(member.name)) realMembers.add(member); } return members; } @Override public int getSize() { return CMLib.database().DBClanMembers(clanID()).size(); } @Override public String name() { return clanName; } @Override public String getName() { return clanName; } @Override public String clanID() { return clanName; } @Override public void setName(String newName) { clanName = newName; } @Override public String getPremise() { return clanPremise; } @Override public void setPremise(String newPremise) { clanPremise = newPremise; } @Override public int getClanLevel() { return clanLevel; } @Override public void setClanLevel(int newClanLevel) { if(newClanLevel<=0) clanLevel=1; else clanLevel = newClanLevel; } @Override public String getAcceptanceSettings() { return acceptanceSettings; } @Override public void setAcceptanceSettings(String newSettings) { acceptanceSettings = newSettings; } @Override public String getClanClass() { return clanClass; } @Override public void setClanClass(String newClass) { clanClass = newClass; } @Override public String getPolitics() { final StringBuffer str=new StringBuffer(""); str.append("<POLITICS>"); str.append(CMLib.xml().convertXMLtoTag("GOVERNMENT",""+getGovernmentID())); str.append(CMLib.xml().convertXMLtoTag("TAXRATE",""+getTaxes())); str.append(CMLib.xml().convertXMLtoTag("EXP",""+getExp())); str.append(CMLib.xml().convertXMLtoTag("LEVEL",""+getClanLevel())); str.append(CMLib.xml().convertXMLtoTag("CCLASS",""+getClanClass())); str.append(CMLib.xml().convertXMLtoTag("AUTOPOS",""+getAutoPosition())); if(clanCategory!=null) str.append(CMLib.xml().convertXMLtoTag("CATE",clanCategory)); if(overrideMinClanMembers!=null) str.append(CMLib.xml().convertXMLtoTag("MINM",overrideMinClanMembers.toString())); if(isRivalrous!=null) str.append(CMLib.xml().convertXMLtoTag("RIVAL",isRivalrous.toString())); if(relations.size()==0) str.append("<RELATIONS/>"); else { str.append("<RELATIONS>"); for(final Iterator<String> e=relations.keySet().iterator();e.hasNext();) { final String key=e.next(); str.append("<RELATION>"); str.append(CMLib.xml().convertXMLtoTag("CLAN",key)); final long[] i=relations.get(key); str.append(CMLib.xml().convertXMLtoTag("STATUS",""+i[0])); str.append("</RELATION>"); } str.append("</RELATIONS>"); } str.append("</POLITICS>"); return str.toString(); } @Override public void setPolitics(String politics) { XMLTag piece; relations.clear(); government=0; if(politics.trim().length()==0) return; final List<XMLLibrary.XMLTag> xml=CMLib.xml().parseAllXML(politics); if(xml==null) { Log.errOut("Clans","Unable to parse: "+politics); return; } final List<XMLLibrary.XMLTag> poliData=CMLib.xml().getContentsFromPieces(xml,"POLITICS"); if(poliData==null){ Log.errOut("Clans","Unable to get POLITICS data."); return;} government=CMLib.xml().getIntFromPieces(poliData,"GOVERNMENT"); exp=CMLib.xml().getLongFromPieces(poliData,"EXP"); setClanLevel(CMLib.xml().getIntFromPieces(poliData,"LEVEL")); setExp(exp); // may change the level taxRate=CMLib.xml().getDoubleFromPieces(poliData,"TAXRATE"); clanClass=CMLib.xml().getValFromPieces(poliData,"CCLASS"); autoPosition=CMLib.xml().getIntFromPieces(poliData,"AUTOPOS"); clanCategory=null; piece=CMLib.xml().getPieceFromPieces(poliData, "CATE"); if(piece!=null) setCategory(piece.value()); overrideMinClanMembers=null; piece=CMLib.xml().getPieceFromPieces(poliData, "MINM"); if(piece!=null) this.setMinClanMembers(CMath.s_int(piece.value())); isRivalrous=null; piece=CMLib.xml().getPieceFromPieces(poliData, "RIVAL"); if(piece!=null) setRivalrous(CMath.s_bool(piece.value())); // now RESOURCES! final List<XMLLibrary.XMLTag> xV=CMLib.xml().getContentsFromPieces(poliData,"RELATIONS"); if((xV!=null)&&(xV.size()>0)) { for(int x=0;x<xV.size();x++) { final XMLTag iblk=xV.get(x); if((!iblk.tag().equalsIgnoreCase("RELATION"))||(iblk.contents()==null)) continue; final String relClanID=iblk.getValFromPieces("CLAN"); final int rel=iblk.getIntFromPieces("STATUS"); setClanRelations(relClanID,rel,0); } } } @Override public int getStatus() { return clanStatus; } @Override public void setStatus(int newStatus) { clanStatus = newStatus; } @Override public String getRecall() { return clanRecall; } @Override public void setRecall(String newRecall) { clanRecall = newRecall; } @Override public String getMorgue() { return clanMorgue; } @Override public void setMorgue(String newMorgue) { clanMorgue = newMorgue; } @Override public String getDonation() { return clanDonationRoom; } @Override public void setDonation(String newDonation) { clanDonationRoom = newDonation; } @Override public List<MemberRecord> getMemberList() { return getMemberList(-1); } public int filterMedianLevel(List<FullMemberRecord> members) { final List<Integer> lvls=new SortedListWrap<Integer>(new XVector<Integer>()); for(final FullMemberRecord r : members) lvls.add(Integer.valueOf(r.level)); if(lvls.size()>0) return lvls.get(lvls.size()/2).intValue(); return 0; } public List<MemberRecord> filterMemberList(List<? extends MemberRecord> members, int posFilter) { final Vector<MemberRecord> filteredMembers=new Vector<MemberRecord>(); for(final MemberRecord member : members) { if((member.role==posFilter)||(posFilter<0)) filteredMembers.add(member); } return filteredMembers; } @Override public List<MemberRecord> getMemberList(int posFilter) { return filterMemberList(CMLib.database().DBClanMembers(clanID()), posFilter); } public MemberRecord getMember(String name) { return CMLib.database().DBGetClanMember(clanID(),name); } @Override public List<FullMemberRecord> getFullMemberList() { final List<FullMemberRecord> members=new Vector<FullMemberRecord>(); final List<MemberRecord> subMembers=filterMemberList(CMLib.database().DBClanMembers(clanID()), -1); for(final MemberRecord member : subMembers) { if(member!=null) { final MOB M=CMLib.players().getPlayer(member.name); if(M!=null) { final boolean isAdmin=CMSecurity.isASysOp(M) || M.phyStats().level() > CMProps.getIntVar(CMProps.Int.LASTPLAYERLEVEL); if(M.lastTickedDateTime()>0) members.add(new FullMemberRecord(member.name,M.basePhyStats().level(),member.role,M.lastTickedDateTime(),member.mobpvps,member.playerpvps,isAdmin)); else members.add(new FullMemberRecord(member.name,M.basePhyStats().level(),member.role,M.playerStats().getLastDateTime(),member.mobpvps,member.playerpvps,isAdmin)); } else { final PlayerLibrary.ThinPlayer tP = CMLib.database().getThinUser(member.name); if(tP != null) { final boolean isAdmin=CMSecurity.isASysOp(tP) || tP.level() > CMProps.getIntVar(CMProps.Int.LASTPLAYERLEVEL); members.add(new FullMemberRecord(member.name,tP.level(),member.role,tP.last(),member.mobpvps,member.playerpvps,isAdmin)); } else { Log.warnOut("Clan "+clanID()+" removed member '"+member.name+"' due to being nonexistant!"); CMLib.database().DBUpdateClanMembership(member.name, clanID(), -1); } } } } return members; } private String crewList(List<? extends MemberRecord> members, int posFilter) { final StringBuffer list=new StringBuffer(""); members = filterMemberList(members, posFilter); if(members.size()>1) { for(int j=0;j<(members.size() - 1);j++) list.append(members.get(j).name+", "); list.append("and "+members.get(members.size()-1).name); } else if(members.size()>0) list.append(members.get(0).name); return list.toString(); } @Override public int getNumVoters(Function function) { int voters=0; final List<MemberRecord> members=getMemberList(); final Function voteFunc = (function == Function.ASSIGN) ? Function.VOTE_ASSIGN : Function.VOTE_OTHER; for(final MemberRecord member : members) { if(getAuthority(member.role, voteFunc)==Authority.CAN_DO) voters++; } return voters; } @Override public List<Integer> getTopRankedRoles(Function func) { final List<ClanPosition> allRoles=new LinkedList<ClanPosition>(); for(final ClanPosition pos : govt().getPositions()) { if((func==null)||(pos.getFunctionChart()[func.ordinal()]!=Authority.CAN_NOT_DO)) allRoles.add(pos); } final List<Integer> roleIDs=new LinkedList<Integer>(); int topRank=Integer.MAX_VALUE; for(final ClanPosition pos : allRoles) { if(pos.getRank() < topRank) topRank=pos.getRank(); } for(final ClanPosition pos : allRoles) { if(pos.getRank() == topRank) roleIDs.add(Integer.valueOf(pos.getRoleID())); } return roleIDs; } @Override public int getNumberRoles() { return govt().getPositions().length; } @Override public int getTopQualifiedRoleID(Function func, MOB mob) { if(mob==null) return govt().getAutoRole(); ClanPosition topPos = null; for(final ClanPosition pos : govt().getPositions()) { if(canBeAssigned(mob,pos.getRoleID()) &&((topPos==null)||(pos.getRank() < topPos.getRank())) &&((func==null)||(getAuthority(pos.getRoleID(),func)!=Authority.CAN_NOT_DO))) topPos = pos; } if(topPos == null) return govt().getAutoRole(); return topPos.getRoleID(); } @Override public int getRoleFromName(String position) { position=position.toUpperCase().trim(); for(final ClanPosition pos : govt().getPositions()) { if(pos.getID().equalsIgnoreCase(position) ||pos.getName().equalsIgnoreCase(position) ||pos.getPluralName().equalsIgnoreCase(position)) return pos.getRoleID(); } for(final ClanPosition pos : govt().getPositions()) { if(pos.getID().toUpperCase().startsWith(position) ||pos.getName().toUpperCase().equalsIgnoreCase(position)) return pos.getRoleID(); } for(final ClanPosition pos : govt().getPositions()) { if((pos.getID().toUpperCase().indexOf(position)>0) ||(pos.getName().toUpperCase().indexOf(position)>0)) return pos.getRoleID(); } return -1; } @Override public boolean isPubliclyListedFor(MOB mob) { if((!govt().isPublic())&&(mob.getClanRole(clanID())==null)) return false; return true; } @Override public String[] getRolesList() { final List<String> roleNames=new LinkedList<String>(); for(final ClanPosition pos : govt().getPositions()) roleNames.add(pos.getName()); return roleNames.toArray(new String[0]); } @Override public int getMostInRole(int roleID) { if((roleID<0)||(roleID>=govt().getPositions().length)) return 0; return govt().getPositions()[roleID].getMax(); } @Override public String getRoleName(int roleID, boolean titleCase, boolean plural) { if((roleID<0)||(roleID>=govt().getPositions().length)) return ""; final ClanPosition pos=govt().getPositions()[roleID]; if(plural) { if(!titleCase) return pos.getPluralName().toLowerCase(); else return CMStrings.capitalizeAndLower(pos.getPluralName()); } if(!titleCase) return pos.getName().toLowerCase(); else return CMStrings.capitalizeAndLower(pos.getName()); } protected boolean isSafeFromPurge() { if(getMinClanMembers()<=0) return true; final List<String> protectedOnes=Resources.getFileLineVector(Resources.getFileResource("protectedplayers.ini",false)); if((protectedOnes!=null)&&(protectedOnes.size()>0)) { for(int b=0;b<protectedOnes.size();b++) { final String B=protectedOnes.get(b); if(B.equalsIgnoreCase(clanID())) return true; } } return false; } @Override public boolean tick(Tickable ticking, int tickID) { if(tickID!=Tickable.TICKID_CLAN) return true; if(CMSecurity.isDisabled(CMSecurity.DisFlag.CLANTICKS)) return true; if(lastPropsReload < CMProps.getLastResetTime()) { lastPropsReload=CMProps.getLastResetTime(); this.overrideMinClanMembers=null; } try { List<FullMemberRecord> members=getFullMemberList(); int activeMembers=0; final long deathMilis=CMProps.getIntVar(CMProps.Int.DAYSCLANDEATH)*CMProps.getIntVar(CMProps.Int.TICKSPERMUDDAY)*CMProps.getTickMillis(); for(final FullMemberRecord member : members) { final long lastLogin=member.timestamp; if(((System.currentTimeMillis()-lastLogin)<deathMilis)||(deathMilis==0)) activeMembers++; } final int minimumMembers = getMinClanMembers(); if(CMSecurity.isDebugging(CMSecurity.DbgFlag.CLANS)) Log.debugOut("DefaultClan","("+clanID()+"): "+activeMembers+"/"+minimumMembers+" active members."); if(activeMembers<minimumMembers) { if(!isSafeFromPurge()) { if(getStatus()==CLANSTATUS_FADING) { Log.sysOut("Clans","Clan '"+getName()+" deleted with only "+activeMembers+" having logged on lately."); destroyClan(); final StringBuffer buf=new StringBuffer(""); for(final FullMemberRecord member : members) buf.append(member.name+" on "+CMLib.time().date2String(member.timestamp)+" "); Log.sysOut("Clans","Clan '"+getName()+" had the following membership: "+buf.toString()); return true; } setStatus(CLANSTATUS_FADING); final List<Integer> topRoles=getTopRankedRoles(Function.ASSIGN); for(final MemberRecord member : members) { final String name = member.name; final int role=member.role; //long lastLogin=((Long)members.elementAt(j,3)).longValue(); if(topRoles.contains(Integer.valueOf(role))) { final MOB player=CMLib.players().getLoadPlayer(name); if(player!=null) CMLib.smtp().emailIfPossible("AutoPurge",player.Name(),"AutoPurge: "+name(), ""+getGovernmentName()+" "+name()+" is in danger of being deleted if at least "+(minimumMembers-activeMembers) +" members do not log on within 24 hours."); } } Log.sysOut("Clans","Clan '"+getName()+" fading with only "+activeMembers+" having logged on lately."); clanAnnounce(""+getGovernmentName()+" "+name()+" is in danger of being deleted if more members do not log on within 24 hours."); update(); } else if(getStatus()!=CLANSTATUS_ACTIVE) setStatus(CLANSTATUS_ACTIVE); } else switch(getStatus()) { case CLANSTATUS_FADING: setStatus(CLANSTATUS_ACTIVE); clanAnnounce(""+getGovernmentName()+" "+name()+" is no longer in danger of being deleted. Be aware that there is required activity level."); break; case CLANSTATUS_PENDING: setStatus(CLANSTATUS_ACTIVE); Log.sysOut("Clans",""+getGovernmentName()+" '"+getName()+" now active with "+activeMembers+"."); clanAnnounce(""+getGovernmentName()+" "+name()+" now has sufficient members. The "+getGovernmentName()+" is now fully approved."); break; default: break; } // handle any necessary promotions if(govt().getAutoPromoteBy() != AutoPromoteFlag.NONE) { final List<Integer> highPositionList = getTopRankedRoles(null); final List<MemberRecord> highMembers=new LinkedList<MemberRecord>(); for(final FullMemberRecord member : members) { if((((System.currentTimeMillis()-member.timestamp)<deathMilis)||(deathMilis==0)) &&(highPositionList.contains(Integer.valueOf(member.role)))) highMembers.add(member); } AutoPromoteFlag basePromoteBy = govt().getAutoPromoteBy(); boolean overWrite = false; if(basePromoteBy==AutoPromoteFlag.LEVEL_OVERWRITE) { overWrite=true; basePromoteBy=AutoPromoteFlag.LEVEL; } else if(basePromoteBy==AutoPromoteFlag.RANK_OVERWRITE) { overWrite=true; basePromoteBy=AutoPromoteFlag.RANK; } if(overWrite || (highMembers.size()==0)) { final List<MemberRecord> highestQualifiedMembers = new LinkedList<MemberRecord>(); for(final FullMemberRecord member : members) { if((member.role<0)||(member.role>=govt().getPositions().length)) continue; final MOB M=CMLib.players().getLoadPlayer(member.name); if(M==null) continue; for(final Integer posI : highPositionList) { if((((System.currentTimeMillis()-member.timestamp)<deathMilis)||(deathMilis==0)) &&(canBeAssigned(M, posI.intValue()))) highestQualifiedMembers.add(member); } } if(basePromoteBy==AutoPromoteFlag.RANK) { ClanPosition bestPos=null; for(final MemberRecord member : highestQualifiedMembers) { final ClanPosition currentPos = govt().getPositions()[member.role]; if((bestPos==null)||(currentPos.getRank() < bestPos.getRank())) bestPos=currentPos; } if(bestPos!=null) { for(final Iterator<MemberRecord> i=highestQualifiedMembers.iterator();i.hasNext();) { if(i.next().role != bestPos.getRoleID()) i.remove(); } } } int highestLevel=-1; for(final MemberRecord member : highestQualifiedMembers) { final MOB M=CMLib.players().getLoadPlayer(member.name); if(M==null) continue; if(M.basePhyStats().level() > highestLevel) highestLevel=M.basePhyStats().level(); } for(final Iterator<MemberRecord> i=highestQualifiedMembers.iterator();i.hasNext();) { final MOB M=CMLib.players().getLoadPlayer(i.next().name); if(M==null) continue; if(M.basePhyStats().level()!=highestLevel) i.remove(); } if(highestQualifiedMembers.size()>0) { if(overWrite) { final ClanPosition newRole=govt().getPositions()[govt().getAcceptPos()]; for(final MemberRecord member : highMembers) { if(!highestQualifiedMembers.contains(member)) { final MOB M=CMLib.players().getLoadPlayer(member.name); if(M==null) continue; clanAnnounce(member.name+" is now a "+newRole.getName()+" of the "+getGovernmentName()+" "+name()+"."); Log.sysOut("Clans",member.name+" of "+getGovernmentName()+" "+name()+" was autodemoted to "+newRole.getName()+"."); M.setClan(clanID(),newRole.getRoleID()); member.role=newRole.getRoleID(); CMLib.database().DBUpdateClanMembership(M.Name(), name(), newRole.getRoleID()); } } } for(final MemberRecord member : highestQualifiedMembers) { if(!highMembers.contains(member)) { final MOB M=CMLib.players().getLoadPlayer(member.name); if(M==null) continue; ClanPosition newRole=null; for(final Integer posI : highPositionList) if(canBeAssigned(M, posI.intValue())) { newRole=govt().getPositions()[posI.intValue()]; break; } if(newRole!=null) { clanAnnounce(member.name+" is now a "+newRole.getName()+" of the "+getGovernmentName()+" "+name()+"."); Log.sysOut("Clans",member.name+" of "+getGovernmentName()+" "+name()+" was autopromoted to "+newRole.getName()+"."); M.setClan(clanID(),newRole.getRoleID()); member.role=newRole.getRoleID(); CMLib.database().DBUpdateClanMembership(M.Name(), name(), newRole.getRoleID()); break; } } } } } highMembers.clear(); members=getFullMemberList(); for(final FullMemberRecord member : members) { if((((System.currentTimeMillis()-member.timestamp)<deathMilis)||(deathMilis==0)) &&(highPositionList.contains(Integer.valueOf(member.role)))) highMembers.add(member); } if(highMembers.size()==0) { if(!isSafeFromPurge()) { Log.sysOut("Clans","Clan '"+getName()+" deleted for lack of leadership."); destroyClan(); final StringBuffer buf=new StringBuffer(""); for(final FullMemberRecord member : members) buf.append(member.name+" on "+CMLib.time().date2String(member.timestamp)+" "); Log.sysOut("Clans","Clan '"+getName()+" had the following membership: "+buf.toString()); return true; } } } boolean anyVoters = false; for(final ClanPosition pos : govt().getPositions()) { if((pos.getFunctionChart()[Function.VOTE_ASSIGN.ordinal()]==Clan.Authority.CAN_DO) ||(pos.getFunctionChart()[Function.VOTE_OTHER.ordinal()]==Clan.Authority.CAN_DO)) anyVoters=true; } // now do votes if(anyVoters&&(votes()!=null)) { boolean updateVotes=false; final Vector<ClanVote> votesToRemove=new Vector<ClanVote>(); long duration=govt().getMaxVoteDays(); if(duration<=0) duration=54; duration=duration*CMProps.getIntVar(CMProps.Int.TICKSPERMUDDAY)*CMProps.getTickMillis(); for(final Enumeration<ClanVote> e=votes();e.hasMoreElements();) { final ClanVote CV=e.nextElement(); final int numVotes=getNumVoters(Function.values()[CV.function]); int quorum=govt().getVoteQuorumPct(); quorum=(int)Math.round(CMath.mul(CMath.div(quorum,100.0),numVotes)); if(quorum<2) quorum=2; if(numVotes==1) quorum=1; final long endsOn=CV.voteStarted+duration; if(CV.voteStatus==VSTAT_STARTED) { if(CV.votes==null) CV.votes=new PairVector<String,Boolean>(); boolean voteIsOver=false; if(System.currentTimeMillis()>endsOn) voteIsOver=true; else if(CV.votes.size()==numVotes) voteIsOver=true; if(voteIsOver) { CV.voteStarted=System.currentTimeMillis(); updateVotes=true; if(CV.votes.size()<quorum) CV.voteStatus=VSTAT_FAILED; else { int yeas=0; int nays=0; for(int i=0;i<CV.votes.size();i++) { if(CV.votes.getSecond(i).booleanValue()) yeas++; else nays++; } if(yeas<=nays) CV.voteStatus=VSTAT_FAILED; else { CV.voteStatus=VSTAT_PASSED; final MOB mob=CMClass.getFactoryMOB(); mob.setName(clanID()); mob.setClan(clanID(),getTopRankedRoles(Function.values()[CV.function]).get(0).intValue()); mob.basePhyStats().setLevel(1000); if(mob.location()==null) { mob.setLocation(mob.getStartRoom()); if(mob.location()==null) mob.setLocation(CMLib.map().getRandomRoom()); } final Vector<String> V=CMParms.parse(CV.matter); mob.doCommand(V,MUDCmdProcessor.METAFLAG_FORCED); mob.destroy(); } } } } else if(System.currentTimeMillis()>endsOn) { updateVotes=true; votesToRemove.addElement(CV); } } for(int v=0;v<votesToRemove.size();v++) delVote(votesToRemove.elementAt(v)); if(updateVotes) updateVotes(); } update(); // also saves exp, and trophies CMLib.database().DBUpdateClanItems(this); } catch(final Exception x2) { Log.errOut("Clans",x2); } return true; } @Override public boolean doesOutRank(int highRoleID, int lowRoleID) { final ClanGovernment govt=govt(); if((highRoleID == lowRoleID) ||(highRoleID < 0) ||(highRoleID >= govt.getPositions().length)) return false; if((lowRoleID<0) ||(lowRoleID >= govt.getPositions().length)) return true; return govt.getPositions()[highRoleID].getRank() < govt.getPositions()[lowRoleID].getRank(); } @Override public void clanAnnounce(String msg) { if(channelSet.size()==0) { synchronized(channelSet) { if(channelSet.size()==0) channelSet.add(new Pair<Clan,Integer>(this,Integer.valueOf(getGovernment().getAcceptPos()))); } } final List<String> channels=CMLib.channels().getFlaggedChannelNames(ChannelsLibrary.ChannelFlag.CLANINFO); for(int i=0;i<channels.size();i++) CMLib.commands().postChannel(channels.get(i),channelSet,msg,true); } private static final SearchIDList<Ability> emptyAbles =new CMUniqSortSVec<Ability>(1); @Override public SearchIDList<Ability> clanAbilities(MOB mob) { final Pair<Clan,Integer> p=(mob!=null)?mob.getClanRole(clanID()):null; if((mob==null)||((p!=null)&&(getAuthority(p.second.intValue(),Function.CLAN_BENEFITS)!=Clan.Authority.CAN_NOT_DO))) return govt().getClanLevelAbilities(mob,this,Integer.valueOf(getClanLevel())); return emptyAbles; } @Override public int numClanEffects(MOB mob) { return govt().getClanLevelEffects(mob, this, Integer.valueOf(getClanLevel())).size(); } @Override public ChameleonList<Ability> clanEffects(MOB mob) { return govt().getClanLevelEffects(mob,this, Integer.valueOf(getClanLevel())); } @Override public int applyExpMods(int exp) { boolean changed=false; if((getTaxes()>0.0)&&(exp>1)) { final int clanshare=(int)Math.round(CMath.mul(exp,getTaxes())); if(clanshare>0) { exp-=clanshare; adjExp(clanshare); changed=true; } } for(final Trophy t : Trophy.values()) { if(CMath.bset(getTrophies(),t.flagNum())) { String awardStr=null; switch(t) { case Areas: awardStr = CMProps.getVar(CMProps.Str.CLANTROPAREA); break; case Points: awardStr = CMProps.getVar(CMProps.Str.CLANTROPCP); break; case Experience: awardStr = CMProps.getVar(CMProps.Str.CLANTROPEXP); break; case PlayerKills: awardStr = CMProps.getVar(CMProps.Str.CLANTROPPK); break; case Members: awardStr = CMProps.getVar(CMProps.Str.CLANTROPMB); break; case MemberLevel: awardStr = CMProps.getVar(CMProps.Str.CLANTROPLVL); break; } if(awardStr!=null) { int amount=0; double pct=0.0; final Vector<String> V=CMParms.parse(awardStr); if(V.size()>=2) { final String type=V.lastElement().toUpperCase(); final String amt=V.firstElement(); if(amt.endsWith("%")) pct=CMath.div(CMath.s_int(amt.substring(0,amt.length()-1)),100.0); else amount=CMath.s_int(amt); if("EXPERIENCE".startsWith(type)) exp+=((int)Math.round(CMath.mul(exp,pct)))+amount; } } } } if(changed) update(); return exp; } @Override public MOB getResponsibleMember() { final List<MemberRecord> members=getMemberList(); final List<Integer> topRoles=getTopRankedRoles(null); MOB respMember = null; final int level = -1; for(final MemberRecord member : members) { if(topRoles.contains(Integer.valueOf(member.role))) { final MOB M=CMLib.players().getLoadPlayer(member.name); if((M!=null)&&(M.basePhyStats().level() > level)) respMember = M; } } if(respMember != null) return respMember; String memberName = null; ClanPosition newPos=null; for(final MemberRecord member : members) { if((member.role<govt().getPositions().length) &&(member.role>=0) &&((newPos==null)||(govt().getPositions()[member.role].getRank()<newPos.getRank()))) { newPos = govt().getPositions()[member.role]; memberName = member.name; } } if(memberName != null) return CMLib.players().getLoadPlayer(memberName); return null; } @Override public ItemCollection getExtItems() { return extItems; } @Override public String[] getStatCodes() { return CLAN_STATS; } @Override public int getSaveStatIndex() { return CLAN_STATS.length; } @Override public boolean isStat(String code) { return CMParms.indexOf(getStatCodes(), code.toUpperCase().trim()) >= 0; } @Override public String getStat(String code) { final int dex=CMParms.indexOf(getStatCodes(),code.toUpperCase().trim()); if(dex<0) return ""; switch(dex) { case 0: return getAcceptanceSettings(); case 1: return getDetail(null); case 2: return getDonation(); case 3: return "" + getExp(); case 4: return "" + getGovernmentName(); case 5: return getMorgue(); case 6: return getPolitics(); case 7: return getPremise(); case 8: return getRecall(); case 9: return "" + getSize(); case 10: return Clan.CLANSTATUS_DESC[getStatus()]; case 11: return "" + getTaxes(); case 12: return "" + getTrophies(); case 13: return "0"; case 14: { final List<Area> areas = getControlledAreas(); final StringBuffer list = new StringBuffer(""); for (int i = 0; i < areas.size(); i++) list.append("\"" + areas.get(i).name() + "\" "); return list.toString().trim(); } case 15: { final List<MemberRecord> members = getMemberList(); final StringBuffer list = new StringBuffer(""); for (final MemberRecord member : members) list.append("\"" + member.name + "\" "); return list.toString().trim(); } case 16: { final MOB M = getResponsibleMember(); if (M != null) return M.Name(); return ""; } case 17: return Integer.toString(getClanLevel()); case 18: return "" + getCategory(); case 19: return "" + isRivalrous(); case 20: return "" + getMinClanMembers(); case 21: return "" + getClanClass(); case 22: return "" + getName(); } return ""; } @Override public void setStat(String code, String val) { final int dex=CMParms.indexOf(getStatCodes(),code.toUpperCase().trim()); if(dex<0) return; switch(dex) { case 0: setAcceptanceSettings(val); break; case 1: break; // detail case 2: setDonation(val); break; case 3: setExp(CMath.s_long(val.trim())); break; case 4: setGovernmentID(CMath.s_int(val.trim())); break; case 5: setMorgue(val); break; case 6: setPolitics(val); break; case 7: setPremise(val); break; case 8: setRecall(val); break; case 9: break; // size case 10: setStatus(CMath.s_int(val.trim())); break; case 11: setTaxes(CMath.s_double(val.trim())); break; case 12: setTrophies(CMath.s_int(val.trim())); break; case 13: break; // type case 14: break; // areas case 15: break; // memberlist case 16: break; // topmember case 17: setClanLevel(CMath.s_int(val.trim())); break; // clanlevel case 18: setCategory(val.trim()); break; // clancategory case 19: setRivalrous(CMath.s_bool(val.trim())); break; // isrivalrous case 20: setMinClanMembers(CMath.s_int(val.trim())); break; // minmembers case 21: setClanClass(val.trim()); break; // clancharclass case 22: this.setName(val.trim()); break; // name } } }