package com.massivecraft.factions; import java.util.*; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import com.massivecraft.factions.iface.EconomyParticipator; import com.massivecraft.factions.iface.RelationParticipator; import com.massivecraft.factions.integration.Econ; import com.massivecraft.factions.integration.SpoutFeatures; import com.massivecraft.factions.util.*; import com.massivecraft.mcore.ps.PS; import com.massivecraft.mcore.store.Entity; import com.massivecraft.mcore.util.SenderUtil; import com.massivecraft.mcore.xlib.gson.annotations.SerializedName; public class Faction extends Entity implements EconomyParticipator { // -------------------------------------------- // // META // -------------------------------------------- // public static Faction get(Object oid) { return FactionColl.get().get(oid); } // -------------------------------------------- // // OVERRIDE: ENTITY // -------------------------------------------- // @Override public Faction load(Faction that) { this.relationWish = that.relationWish; this.invitedPlayerIds = that.invitedPlayerIds; this.open = that.open; this.tag = that.tag; this.setDescription(that.description); this.home = that.home; this.cape = that.cape; this.powerBoost = that.powerBoost; this.flagOverrides = that.flagOverrides; this.permOverrides = that.permOverrides; return this; } // -------------------------------------------- // // FIELDS: RAW // -------------------------------------------- // private Map relationWish; // TODO @SerializedName("invites") private Set invitedPlayerIds = null; public TreeSet getInvitedPlayerIds() { TreeSet ret = new TreeSet(String.CASE_INSENSITIVE_ORDER); if (this.invitedPlayerIds != null) ret.addAll(this.invitedPlayerIds); return ret; } public void setInvitedPlayerIds(Collection invitedPlayerIds) { if (invitedPlayerIds == null || invitedPlayerIds.isEmpty()) { this.invitedPlayerIds = null; } else { TreeSet target = new TreeSet(String.CASE_INSENSITIVE_ORDER); for (String invitedPlayerId : invitedPlayerIds) { target.add(invitedPlayerId.toLowerCase()); } this.invitedPlayerIds = target; } this.changed(); } private boolean open; public boolean isOpen() { return this.open; } public void setOpen(boolean open) { this.open = open; } // FIELD: tag private String tag; public String getTag() { return this.tag; } public String getTag(String prefix) { return prefix+this.tag; } public String getTag(RelationParticipator observer) { if (observer == null) { return getTag(); } return this.getTag(this.getColorTo(observer).toString()); } public void setTag(String str) { if (ConfServer.factionTagForceUpperCase) { str = str.toUpperCase(); } this.tag = str; } public String getComparisonTag() { return MiscUtil.getComparisonString(this.tag); } // FIELD: description private String description; public boolean hasDescription() { return this.description != null; } public String getDescription() { if (this.hasDescription()) return this.description; return Lang.FACTION_NODESCRIPTION; } public void setDescription(String description) { if (description != null) { description = description.trim(); // This code should be kept for a while to clean out the previous default text that was actually stored in the database. if (description.length() == 0 || description.equalsIgnoreCase("Default faction description :(")) { description = null; } } this.description = description; } // FIELD: home // TODO: Use a PS instead! private LazyLocation home; public void setHome(Location home) { this.home = new LazyLocation(home); } public boolean hasHome() { return this.getHome() != null; } public Location getHome() { confirmValidHome(); return (this.home != null) ? this.home.getLocation() : null; } public void confirmValidHome() { if (!ConfServer.homesMustBeInClaimedTerritory || this.home == null || (this.home.getLocation() != null && BoardColl.get().getFactionAt(PS.valueOf(this.home.getLocation())) == this)) return; msg("Your faction home has been un-set since it is no longer in your territory."); this.home = null; } // FIELD: account (fake field) // Bank functions public String getAccountId() { String accountId = "faction-"+this.getId(); // We need to override the default money given to players. if ( ! Econ.hasAccount(accountId)) { Econ.setBalance(accountId, 0); } return accountId; } // FIELD: cape private String cape; public String getCape() { return cape; } public void setCape(String val) { this.cape = val; SpoutFeatures.updateCape(this, null); } // FIELD: powerBoost // special increase/decrease to default and max power for this faction private double powerBoost; public double getPowerBoost() { return this.powerBoost; } public void setPowerBoost(double powerBoost) { this.powerBoost = powerBoost; } // FIELDS: Flag management // TODO: This will save... defaults if they where changed to... private Map flagOverrides; // Contains the modifications to the default values public boolean getFlag(FFlag flag) { Boolean ret = this.flagOverrides.get(flag); if (ret == null) ret = flag.getDefault(); return ret; } public void setFlag(FFlag flag, boolean value) { if (ConfServer.factionFlagDefaults.get(flag).equals(value)) { this.flagOverrides.remove(flag); return; } this.flagOverrides.put(flag, value); } // FIELDS: Permission <-> Groups management private Map> permOverrides; // Contains the modifications to the default values public Set getPermittedRelations(FPerm perm) { Set ret = this.permOverrides.get(perm); if (ret == null) ret = perm.getDefault(); return ret; } /* public void addPermittedRelation(FPerm perm, Rel rel) { Set newPermittedRelations = EnumSet.noneOf(Rel.class); newPermittedRelations.addAll(this.getPermittedRelations(perm)); newPermittedRelations.add(rel); this.setPermittedRelations(perm, newPermittedRelations); } public void removePermittedRelation(FPerm perm, Rel rel) { Set newPermittedRelations = EnumSet.noneOf(Rel.class); newPermittedRelations.addAll(this.getPermittedRelations(perm)); newPermittedRelations.remove(rel); this.setPermittedRelations(perm, newPermittedRelations); }*/ public void setRelationPermitted(FPerm perm, Rel rel, boolean permitted) { Set newPermittedRelations = EnumSet.noneOf(Rel.class); newPermittedRelations.addAll(this.getPermittedRelations(perm)); if (permitted) { newPermittedRelations.add(rel); } else { newPermittedRelations.remove(rel); } this.setPermittedRelations(perm, newPermittedRelations); } public void setPermittedRelations(FPerm perm, Set rels) { if (perm.getDefault().equals(rels)) { this.permOverrides.remove(perm); return; } this.permOverrides.put(perm, rels); } public void setPermittedRelations(FPerm perm, Rel... rels) { Set temp = new HashSet(); temp.addAll(Arrays.asList(rels)); this.setPermittedRelations(perm, temp); } // -------------------------------------------- // // CONSTRUCT // -------------------------------------------- // public Faction() { this.relationWish = new LinkedHashMap(); this.open = ConfServer.newFactionsDefaultOpen; this.tag = "???"; this.description = null; this.powerBoost = 0.0; this.flagOverrides = new LinkedHashMap(); this.permOverrides = new LinkedHashMap>(); } // -------------------------------------------- // // FIELDS: EXTRA // -------------------------------------------- // // TODO: Make use of a player name extractor? public boolean addInvitedPlayerId(String playerId) { TreeSet invitedPlayerIds = this.getInvitedPlayerIds(); if (invitedPlayerIds.add(playerId.toLowerCase())) { this.setInvitedPlayerIds(invitedPlayerIds); return true; } return false; } public boolean removeInvitedPlayerId(String playerId) { TreeSet invitedPlayerIds = this.getInvitedPlayerIds(); if (invitedPlayerIds.remove(playerId.toLowerCase())) { this.setInvitedPlayerIds(invitedPlayerIds); return true; } return false; } public boolean isInvited(FPlayer fplayer) { return this.getInvitedPlayerIds().contains(fplayer.getId()); } // -------------------------------------------- // // ACTIONS // -------------------------------------------- // public void invite(FPlayer fplayer) { this.addInvitedPlayerId(fplayer.getId()); } public void deinvite(FPlayer fplayer) { this.removeInvitedPlayerId(fplayer.getId()); } // -------------------------------------------- // // NONE OR NORMAL? // -------------------------------------------- // public boolean isNone() { return this.getId().equals(Const.FACTIONID_NONE); } public boolean isNormal() { return ! this.isNone(); } // -------------------------------------------- // // RELATION AND COLORS // -------------------------------------------- // @Override public String describeTo(RelationParticipator observer, boolean ucfirst) { return RelationUtil.describeThatToMe(this, observer, ucfirst); } @Override public String describeTo(RelationParticipator observer) { return RelationUtil.describeThatToMe(this, observer); } @Override public Rel getRelationTo(RelationParticipator observer) { return RelationUtil.getRelationOfThatToMe(this, observer); } @Override public Rel getRelationTo(RelationParticipator observer, boolean ignorePeaceful) { return RelationUtil.getRelationOfThatToMe(this, observer, ignorePeaceful); } @Override public ChatColor getColorTo(RelationParticipator observer) { return RelationUtil.getColorOfThatToMe(this, observer); } public Rel getRelationWish(Faction otherFaction) { if (this.relationWish.containsKey(otherFaction.getId())) { return this.relationWish.get(otherFaction.getId()); } return Rel.NEUTRAL; } public void setRelationWish(Faction otherFaction, Rel relation) { if (this.relationWish.containsKey(otherFaction.getId()) && relation.equals(Rel.NEUTRAL)) { this.relationWish.remove(otherFaction.getId()); } else { this.relationWish.put(otherFaction.getId(), relation); } } public Map> getFactionTagsPerRelation(RelationParticipator rp) { return getFactionTagsPerRelation(rp, false); } // onlyNonNeutral option provides substantial performance boost on large servers for listing only non-neutral factions public Map> getFactionTagsPerRelation(RelationParticipator rp, boolean onlyNonNeutral) { Map> ret = new HashMap>(); for (Rel rel : Rel.values()) { ret.put(rel, new ArrayList()); } for (Faction faction : FactionColl.get().getAll()) { Rel relation = faction.getRelationTo(this); if (onlyNonNeutral && relation == Rel.NEUTRAL) continue; ret.get(relation).add(faction.getTag(rp)); } return ret; } // TODO: Implement a has enough feature. // -------------------------------------------- // // POWER // -------------------------------------------- // public double getPower() { if (this.getFlag(FFlag.INFPOWER)) { return 999999; } double ret = 0; for (FPlayer fplayer : this.getFPlayers()) { ret += fplayer.getPower(); } if (ConfServer.powerFactionMax > 0 && ret > ConfServer.powerFactionMax) { ret = ConfServer.powerFactionMax; } return ret + this.powerBoost; } public double getPowerMax() { if (this.getFlag(FFlag.INFPOWER)) { return 999999; } double ret = 0; for (FPlayer fplayer : this.getFPlayers()) { ret += fplayer.getPowerMax(); } if (ConfServer.powerFactionMax > 0 && ret > ConfServer.powerFactionMax) { ret = ConfServer.powerFactionMax; } return ret + this.powerBoost; } public int getPowerRounded() { return (int) Math.round(this.getPower()); } public int getPowerMaxRounded() { return (int) Math.round(this.getPowerMax()); } public int getLandCount() { return BoardColl.get().getCount(this); } public int getLandCountInWorld(String worldName) { return BoardColl.get().get(worldName).getCount(this); } public boolean hasLandInflation() { return this.getLandCount() > this.getPowerRounded(); } // -------------------------------------------- // // FPLAYERS // -------------------------------------------- // public List getFPlayers() { List ret = new ArrayList(); for (FPlayer fplayer : FPlayerColl.get().getAll()) { if (fplayer.getFaction() != this) continue; ret.add(fplayer); } return ret; } public List getFPlayersWhereOnline(boolean online) { List ret = new ArrayList(); for (FPlayer fplayer : FPlayerColl.get().getAll()) { if (fplayer.getFaction() != this) continue; if (fplayer.isOnline() != online) continue; ret.add(fplayer); } return ret; } public List getFPlayersWhereRole(Rel role) { List ret = new ArrayList(); for (FPlayer fplayer : FPlayerColl.get().getAll()) { if (fplayer.getFaction() != this) continue; if (fplayer.getRole() != role) continue; ret.add(fplayer); } return ret; } public FPlayer getLeader() { for (FPlayer fplayer : FPlayerColl.get().getAll()) { if (fplayer.getFaction() != this) continue; if (fplayer.getRole() != Rel.LEADER) continue; return fplayer; } return null; } public List getOnlineCommandSenders() { List ret = new ArrayList(); for (CommandSender player : SenderUtil.getOnlineSenders()) { FPlayer fplayer = FPlayerColl.get().get(player); if (fplayer.getFaction() != this) continue; ret.add(player); } return ret; } public List getOnlinePlayers() { List ret = new ArrayList(); for (Player player : Bukkit.getOnlinePlayers()) { FPlayer fplayer = FPlayerColl.get().get(player); if (fplayer.getFaction() != this) continue; ret.add(player); } return ret; } // used when current leader is about to be removed from the faction; promotes new leader, or disbands faction if no other members left public void promoteNewLeader() { if ( ! this.isNormal()) return; if (this.getFlag(FFlag.PERMANENT) && ConfServer.permanentFactionsDisableLeaderPromotion) return; FPlayer oldLeader = this.getLeader(); // get list of officers, or list of normal members if there are no officers List replacements = this.getFPlayersWhereRole(Rel.OFFICER); if (replacements == null || replacements.isEmpty()) { replacements = this.getFPlayersWhereRole(Rel.MEMBER); } if (replacements == null || replacements.isEmpty()) { // faction leader is the only member; one-man faction if (this.getFlag(FFlag.PERMANENT)) { if (oldLeader != null) { oldLeader.setRole(Rel.MEMBER); } return; } // no members left and faction isn't permanent, so disband it if (ConfServer.logFactionDisband) { Factions.get().log("The faction "+this.getTag()+" ("+this.getId()+") has been disbanded since it has no members left."); } for (FPlayer fplayer : FPlayerColl.get().getAllOnline()) { fplayer.msg("The faction %s was disbanded.", this.getTag(fplayer)); } this.detach(); } else { // promote new faction leader if (oldLeader != null) { oldLeader.setRole(Rel.MEMBER); } replacements.get(0).setRole(Rel.LEADER); this.msg("Faction leader %s has been removed. %s has been promoted as the new faction leader.", oldLeader == null ? "" : oldLeader.getName(), replacements.get(0).getName()); Factions.get().log("Faction "+this.getTag()+" ("+this.getId()+") leader was removed. Replacement leader: "+replacements.get(0).getName()); } } // -------------------------------------------- // // MESSAGES // -------------------------------------------- // // These methods are simply proxied in from the SenderEntity class using a for loop. // CONVENIENCE SEND MESSAGE public boolean sendMessage(String message) { for (FPlayer fplayer : this.getFPlayers()) { fplayer.sendMessage(message); } return true; } public boolean sendMessage(String... messages) { for (FPlayer fplayer : this.getFPlayers()) { fplayer.sendMessage(messages); } return true; } public boolean sendMessage(Collection messages) { for (FPlayer fplayer : this.getFPlayers()) { fplayer.sendMessage(messages); } return true; } // CONVENIENCE MSG public boolean msg(String msg) { for (FPlayer fplayer : this.getFPlayers()) { fplayer.msg(msg); } return true; } public boolean msg(String msg, Object... args) { for (FPlayer fplayer : this.getFPlayers()) { fplayer.msg(msg, args); } return true; } public boolean msg(Collection msgs) { for (FPlayer fplayer : this.getFPlayers()) { fplayer.msg(msgs); } return true; } }