diff --git a/MobArena.jar b/MobArena.jar new file mode 100644 index 0000000..b6d4e4f Binary files /dev/null and b/MobArena.jar differ diff --git a/bin/plugin.yml b/bin/plugin.yml new file mode 100644 index 0000000..8d7f2c1 --- /dev/null +++ b/bin/plugin.yml @@ -0,0 +1,26 @@ +name: MobArena +main: com.garbagemule.MobArena.MobArena +version: 0.92 +softdepend: [MultiVerse] +commands: + ma: + description: Base command for MobArena + usage: | + /ma join - Join the arena. + /ma leave - Leave the arena. + /ma notready - List of players who aren't ready. + /ma spectate - Warp to the spectator area. + marena: + description: Base command for MobArena + usage: | + /marena join - Join the arena. + /marena leave - Leave the arena. + /marena notready - List of players who aren't ready. + /marena spectate - Warp to the spectator area. + mobarena: + description: Base command for MobArena + usage: | + /mobarena join - Join the arena. + /mobarena leave - Leave the arena. + /mobarena notready - List of players who aren't ready. + /mobarena spectate - Warp to the spectator area. \ No newline at end of file diff --git a/language files/announcements_da.properties b/language files/announcements_da.properties new file mode 100644 index 0000000..42d61f2 --- /dev/null +++ b/language files/announcements_da.properties @@ -0,0 +1,51 @@ +ARENA_START=Lad massakren begynde! +ARENA_END=Arena slut. +ARENA_DOES_NOT_EXIST=Arenaen findes ikke. Skriv /ma arenas for en liste. +JOIN_PLAYER_JOINED=Du joinede arenaen! +JOIN_NOT_ENABLED=MobArena er ikke aktiveret. +JOIN_IN_OTHER_ARENA=Du er allerede i en arena. Forlad den først. +JOIN_ARENA_NOT_ENABLED=Arenaen er deaktiveret. +JOIN_ARENA_NOT_SETUP=Arenaen er ikke blevet sat op endnu. +JOIN_ARENA_PERMISSION=Du har ikke rettigheder til den arena! +JOIN_FEE_REQUIRED=Du er for fattig. Pris: % +JOIN_FEE_PAID=Prisen for at joine var: % +JOIN_ARENA_IS_RUNNING=Arenaen er allerede startet. +JOIN_ALREADY_PLAYING=Du spiller allerede! +JOIN_ARG_NEEDED=Arenanavn pÃ¥krævet. Skriv /ma arenas for en liste. +JOIN_TOO_FAR=Du er for langt fra denne arena til at kunne joine. +JOIN_EMPTY_INV=Du skal tømme dit inventory før du kan joine arenaen. +JOIN_PLAYER_LIMIT_REACHED=Der kan ikke være flere spillere i arenaen. +JOIN_STORE_INV_FAIL=Kunne ikke gemme dit inventory. Prøv igen. +LEAVE_PLAYER_LEFT=Du forlod arenaen. +LEAVE_NOT_PLAYING=Du er ikke i en arena. +PLAYER_DIED=% døde! +SPEC_PLAYER_SPECTATE=Nyd forestillingen! +SPEC_NOT_RUNNING=Arenaen er ikke startet. +SPEC_ARG_NEEDED=Arenanavn pÃ¥krævet. Skriv /ma arenas for en liste. +SPEC_EMPTY_INV=Du skal tømme dit inventory først. +SPEC_ALREADY_PLAYING=Du spiller allerede! +NOT_READY_PLAYERS=Ikke klar: % +FORCE_START_STARTED=Arena tvunget til at starte. +FORCE_START_RUNNING=Arenaen er allerede startet. +FORCE_START_NOT_READY=Ingen spillere er klar. +FORCE_END_ENDED=Arena tvunget til at slutte. +FORCE_END_EMPTY=Der er ingen i arenaen. +FORCE_END_IDLE=Du var ikke hurtig nok! +REWARDS_GIVE=Her er alle dine præmier! +LOBBY_CLASS_PICKED=Du har valgt % som din klasse! +LOBBY_CLASS_RANDOM=Du fÃ¥r tildelt en klasse ved arena start. +LOBBY_CLASS_PERMISSION=Du har ikke rettigheder til den klasse! +LOBBY_PLAYER_READY=Du er markeret som klar! +LOBBY_DROP_ITEM=Du kan ikke dele items i lobbyen! +LOBBY_PICK_CLASS=Du skal først vælge en klasse! +LOBBY_RIGHT_CLICK=SlÃ¥ skiltene; ikke højre-klik. +WARP_TO_ARENA=Du kan ikke warpe til arenaen efter, den er startet. +WARP_FROM_ARENA=Du kan ikke warpe fra arenaen. +WAVE_DEFAULT=Bølge #%! +WAVE_SPECIAL=Bølge #%! [SPECIEL] +WAVE_REWARD=Du har lige vundet en præmie: % +MISC_LIST_ARENAS=Tilgængelige arenaer: % +MISC_LIST_PLAYERS=Levende spillere: % +MISC_COMMAND_NOT_ALLOWED=Du kan ikke bruge den kommando i arenaen. +MISC_NO_ACCESS=Du har ikke adgang til den kommando. +MISC_NONE= diff --git a/language files/announcements_fr.properties b/language files/announcements_fr.properties new file mode 100644 index 0000000..6f2b9d3 --- /dev/null +++ b/language files/announcements_fr.properties @@ -0,0 +1,51 @@ +ARENA_START=Que le massacre commence ! +ARENA_END=L'arène est terminée. +ARENA_DOES_NOT_EXIST=Cette arène n'existe pas. Entrez "/ma arenas" pour la liste. +JOIN_PLAYER_JOINED=Vous avez rejoint l'arène. Prennez plaisir ! +JOIN_NOT_ENABLED=MobArena n'est pas actif. +JOIN_IN_OTHER_ARENA=Vous êtes déjà dans l'arène! Quittez-la avant. +JOIN_ARENA_NOT_ENABLED=Cetta arène n'est pas active. +JOIN_ARENA_NOT_SETUP=Cette arène n'a pas encore été configurée. +JOIN_ARENA_PERMISSION=Vous n'avez pas la permission pour rejoindre cette arène. +JOIN_FEE_REQUIRED=Pas assez d'argent. Prix: % +JOIN_FEE_PAID=Le prix pour rejoindre était de: % +JOIN_ARENA_IS_RUNNING=L'arène est déjà occupée. +JOIN_ALREADY_PLAYING=Vous êtes déjà en train de jouer. +JOIN_ARG_NEEDED=Vous devez spécifier une arène. Entrez "/ma arenas" pour la liste. +JOIN_TOO_FAR=Vous êtes trop loins de l'arène pour pouvoir joindre en tant que joueur ou specateur. +JOIN_EMPTY_INV=Vous devez vider votre inventaire afin de joindre l'arène. +JOIN_PLAYER_LIMIT_REACHED=La limite de joueur pour cette arène a été atteinte. +JOIN_STORE_INV_FAIL=La sauvegarde de l'inventaire a échouée. Essayez encore. +LEAVE_PLAYER_LEFT=Vous avez quitté l'arène. Merci d'avoir joué ! +LEAVE_NOT_PLAYING=Vous n'êtes pas dans l'arène. +PLAYER_DIED=% est mort ! +SPEC_PLAYER_SPECTATE=Profitez bien du spectacle ! +SPEC_NOT_RUNNING=Cette arène n'est pas en cours. +SPEC_ARG_NEEDED=Vous devez spécifier une arène. Entrez "/ma arenas" pour la liste. +SPEC_EMPTY_INV=Vous devez vider votre inventaire. +SPEC_ALREADY_PLAYING=Vous ne pouvez pas être spectateur en tant que joueur de l'arène ! +NOT_READY_PLAYERS=Non prêt: % +FORCE_START_STARTED=Début forcé de l'arène. +FORCE_START_RUNNING=L'arène a commencée. +FORCE_START_NOT_READY=Ne peut pas forcer le début, il n'y a pas de joueurs prêts. +FORCE_END_ENDED=Fin forcée de l'arène. +FORCE_END_EMPTY=Il n'y a personne dans l'arène. +FORCE_END_IDLE=Vous n'avez pas été assez rapide ! +REWARDS_GIVE=Voici vos récompenses ! +LOBBY_CLASS_PICKED=Vous avez choisi % comme classe ! +LOBBY_CLASS_RANDOM=Une classe aléatoire va vous être attribuée. +LOBBY_CLASS_PERMISSION=Vous n'avez pas les permissions pour utiliser cette classe ! +LOBBY_PLAYER_READY=Vous avez été marqué comme prêt ! +LOBBY_DROP_ITEM=Pas de partage avant le début de l'arène ! +LOBBY_PICK_CLASS=Vous devez d'abord choisir une classe ! +LOBBY_RIGHT_CLICK=Vous devez frapper le panneau, pas cliquer du droit dessus. +WARP_TO_ARENA=Vous ne pouvez pas vous téléporter à l'arène pendant la bataille ! +WARP_FROM_ARENA=La téléportation est interdite dans l'arène ! +WAVE_DEFAULT=Soyez prêt pour la vague #% ! +WAVE_SPECIAL=Soyez prêt pour la vague #% ! [SPECIALE] +WAVE_REWARD=Vous avez gagné une récompense: % +MISC_LIST_ARENAS=Les arènes disponibles: % +MISC_LIST_PLAYERS=Les joueurs en live: % +MISC_COMMAND_NOT_ALLOWED=Vous ne pouvez pas utiliser cette commande dans l'arène ! +MISC_NO_ACCESS=Vous n'avez pas accès à cette commande. +MISC_NONE= diff --git a/language files/announcements_pirate.properties b/language files/announcements_pirate.properties new file mode 100644 index 0000000..0afaf05 --- /dev/null +++ b/language files/announcements_pirate.properties @@ -0,0 +1,51 @@ +ARENA_START=Hearts alive, men! +ARENA_END=Land ho! +ARENA_DOES_NOT_EXIST=Thar be no ship by that name! +JOIN_PLAYER_JOINED=Ahoy, matey! +JOIN_NOT_ENABLED=We be swabbing down the decks on all ships, matey. +JOIN_IN_OTHER_ARENA=Ye're already at sea, scallywag! +JOIN_ARENA_NOT_ENABLED=We be swabbing down the decks on this ship, matey. +JOIN_ARENA_NOT_SETUP=Arrrgh! We be missing the top sail! +JOIN_ARENA_PERMISSION=Arrgh! Ye can't board this ship, scurvy dog! +JOIN_FEE_REQUIRED=Ye don't own enough doubloons, matey! Price: % +JOIN_FEE_PAID=Booty ye gave up to join: % +JOIN_ARENA_IS_RUNNING=That ship has sailed, landlubber! +JOIN_ALREADY_PLAYING=Ye be aboard already, ye scurvy dog! +JOIN_ARG_NEEDED=Which ship are ye boarding? Type /ma arenas for a list, arrgh! +JOIN_TOO_FAR=Ye be too far from the docks, landlubber! +JOIN_EMPTY_INV=Throw ye belongings overboard, scallywag! +JOIN_PLAYER_LIMIT_REACHED=Thar be too many men aboard this ship already, landlubber! +JOIN_STORE_INV_FAIL=Ye belongings didn't fit in the storage deck, arrgh! +LEAVE_PLAYER_LEFT=Ye abandonned the ship! Arrrgh! +LEAVE_NOT_PLAYING=Ye're already on land, matey! +PLAYER_DIED=% walked the plank! +SPEC_PLAYER_SPECTATE=Welcome to the Crow's Nest! Grab ye spyglass! +SPEC_NOT_RUNNING=Thar be no one aboard that ship! +SPEC_ARG_NEEDED=Which ship are ye boarding? Type /ma arenas for a list, arrgh! +SPEC_EMPTY_INV=Throw ye belongings overboard, scallywag! +SPEC_ALREADY_PLAYING=Ye don't need ye spyglass aboard this ship, harr! +NOT_READY_PLAYERS=Landlubbers: % +FORCE_START_STARTED=Set sail! +FORCE_START_RUNNING=The ship has already set sail! +FORCE_START_NOT_READY=Thar be no scurvy dogs ready to set sail! +FORCE_END_ENDED=Forced the men to walk the plank! +FORCE_END_EMPTY=Thar be no one aboard the ship! +FORCE_END_IDLE=Arrrgh! Too slow, matey! +REWARDS_GIVE=Here's ye booty, seadog! +LOBBY_CLASS_PICKED=Ye be the %! +LOBBY_CLASS_RANDOM= +LOBBY_CLASS_PERMISSION=Ye can't use that cutlass, scurvy dog! +LOBBY_PLAYER_READY=Ready to sail! Arrrgh! +LOBBY_DROP_ITEM=Don't be sharing ye rum yet, scallywag! +LOBBY_PICK_CLASS=Grab ye cutlass first, matey! +LOBBY_RIGHT_CLICK=Ye can't be right-clickin', landlubber. +WARP_TO_ARENA=Ye can't board this ship, wench! +WARP_FROM_ARENA=Walk the plank if ye want to leave, arrrgh! +WAVE_DEFAULT=Wave %: Blow them all down! +WAVE_SPECIAL=Wave %: Thar she blows! +WAVE_REWARD=Ye earned yerself some booty: % +MISC_LIST_ARENAS=Ships: % +MISC_LIST_PLAYERS=Buccaneers: % +MISC_COMMAND_NOT_ALLOWED=Ye can't be usin' that command on the ship, landlubber! +MISC_NO_ACCESS=Only the captain uses these commands, wench! +MISC_NONE= diff --git a/src/com/garbagemule/MobArena/AbstractArena.java b/src/com/garbagemule/MobArena/AbstractArena.java new file mode 100644 index 0000000..f7a6122 --- /dev/null +++ b/src/com/garbagemule/MobArena/AbstractArena.java @@ -0,0 +1,40 @@ +package com.garbagemule.MobArena; + +import org.bukkit.entity.Player; + +public abstract class AbstractArena +{ + /** + * Start the arena session. + * This method should warp all players to their respective warp points, start all + * needed timers, clear/populate all sets and lists, and flag all booleans. + */ + public abstract void startArena(); + + /** + * Stop the arena session. + * Distribute rewards, clean up arena floor and reset everything to how it was before + * the arena session was started. + */ + public abstract void endArena(); + + /** + * Player joins the arena/lobby. + */ + public abstract void playerJoin(Player p); + + /** + * Player leaves the arena/lobby. + */ + public abstract void playerLeave(Player p); + + /** + * Player dies in the arena. + */ + public abstract void playerDeath(Player p); + + /** + * Player signals that they are ready. + */ + public abstract void playerReady(Player p); +} diff --git a/src/com/garbagemule/MobArena/Arena.java b/src/com/garbagemule/MobArena/Arena.java new file mode 100644 index 0000000..5fc08da --- /dev/null +++ b/src/com/garbagemule/MobArena/Arena.java @@ -0,0 +1,1801 @@ +package com.garbagemule.MobArena; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.CreatureType; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Wolf; +import org.bukkit.event.Event.Result; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.event.entity.EntityTargetEvent.TargetReason; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.util.config.Configuration; + +import com.garbagemule.MobArena.MAMessages.Msg; + +public class Arena +{ + private MobArena plugin; + + // Setup fields + protected String name; + protected World world; + protected boolean enabled, protect, logging, running, setup, lobbySetup, autoEquip, forceRestore, softRestore, softRestoreDrops, emptyInvJoin, emptyInvSpec, pvp, monsterInfight, allowWarp; + protected boolean edit, waveClear, detCreepers, detDamage, lightning, hellhounds, specOnDeath, shareInArena; + protected Location p1, p2, l1, l2, arenaLoc, lobbyLoc, spectatorLoc; + protected Map spawnpoints; + + // Wave/reward/entryfee fields + protected int spawnTaskId, waveDelay, waveInterval, specialModulo, spawnMonstersInt, maxIdleTime; + protected MASpawnThread spawnThread; + protected Map> everyWaveMap, afterWaveMap; + protected Map distDefault, distSpecial; + protected Map classMap; + protected Map> classItems, classArmor; + protected Map>> classBonuses; + protected Map> rewardMap; + protected List entryFee; + + // Arena sets/maps + protected Set /*livePlayers, */deadPlayers, readyPlayers, specPlayers, waitPlayers, hasPaid, arenaPlayers, lobbyPlayers, notifyPlayers, randoms; + protected Set monsters; + protected Set blocks; + protected Set pets; + protected Map petMap; + protected List repairList; + + // Spawn overriding + protected int spawnMonsters; + protected boolean allowMonsters, allowAnimals; + + // Other settings + protected int repairDelay, playerLimit, joinDistance; + protected List classes = new LinkedList(); + protected Map locations = new HashMap(); + + // Logging + protected ArenaLog log; + protected List classDistribution = new LinkedList(); + protected Map waveMap = new HashMap(); + protected Map killMap = new HashMap(); + protected Timestamp startTime; + protected Timestamp endTime; + + /** + * Primary constructor. Requires a name and a world. + */ + public Arena(String name, World world) + { + if (world == null) + throw new NullPointerException("[MobArena] ERROR! World for arena '" + name + "' does not exist!"); + + this.name = name; + this.world = world; + plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); + log = new ArenaLog(plugin, this); + + arenaPlayers = new HashSet(); + lobbyPlayers = new HashSet(); + notifyPlayers = new HashSet(); + //livePlayers = new HashSet(); + deadPlayers = new HashSet(); + readyPlayers = new HashSet(); + specPlayers = new HashSet(); + waitPlayers = new HashSet(); + hasPaid = new HashSet(); + monsters = new HashSet(); + blocks = new HashSet(); + pets = new HashSet(); + petMap = new HashMap(); + classMap = new HashMap(); + randoms = new HashSet(); + rewardMap = new HashMap>(); + repairList = new LinkedList(); + + running = false; + edit = false; + + allowMonsters = world.getAllowMonsters(); + allowAnimals = world.getAllowAnimals(); + spawnMonsters = ((net.minecraft.server.World) ((CraftWorld) world).getHandle()).spawnMonsters; + } + + public boolean startArena() + { + // Sanity-checks + if (running || lobbyPlayers.isEmpty() || !lobbyPlayers.equals(readyPlayers)) + return false; + if (!softRestore && forceRestore && !serializeRegion()) + return false; + + // Populate arenaPlayers and clear the lobby. + arenaPlayers.addAll(lobbyPlayers); + lobbyPlayers.clear(); + readyPlayers.clear(); + + // Assign random classes. + for (Player p : randoms) + assignRandomClass(p); + if (arenaPlayers.isEmpty()) + return false; + + // Teleport players, give full health, initialize maps + for (Player p : arenaPlayers) + { + p.teleport(arenaLoc); + p.setHealth(20); + rewardMap.put(p, new LinkedList()); + waveMap.put(p, 0); + killMap.put(p, 0); + } + + // Spawn pets. + spawnPets(); + + // Start spawning monsters. + startSpawning(); + + // Start logging + if (logging) + log.start(); + + // Set the boolean. + running = true; + + // Announce and notify. + MAUtils.tellAll(this, MAMessages.get(Msg.ARENA_START)); + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onArenaStart(); + + return true; + } + + /*public void startArena() + { + if (running) + return; + + if (!softRestore && forceRestore && !serializeRegion()) + return; + + // Assign random classes, and if all get kicked, return. + for (Player p : randoms) + assignRandomClass(p); + if (livePlayers.isEmpty()) + return; + + // Set the spawn flags to enable monster spawning. + MAUtils.setSpawnFlags(plugin, world, 1, allowMonsters, allowAnimals); + + // Teleport players. + for (Player p : livePlayers) + { + p.teleport(arenaLoc); + p.setHealth(20); + rewardMap.put(p, new LinkedList()); + waveMap.put(p, 0); + killMap.put(p, 0); + } + + running = true; + + // Spawn pets. + for (Map.Entry entry : petMap.entrySet()) + { + // Remove the bones from the inventory. + Player p = entry.getKey(); + p.getInventory().removeItem(new ItemStack(Material.BONE, entry.getValue())); + + for (int i = 0; i < entry.getValue(); i++) + { + Wolf wolf = (Wolf) world.spawnCreature(p.getLocation(), CreatureType.WOLF); + wolf.setTamed(true); + wolf.setOwner(p); + wolf.setHealth(20); + if (hellhounds) + wolf.setFireTicks(32768); + pets.add(wolf); + } + } + + // Start the spawnThread. + spawnThread = new MASpawnThread(plugin, this); + spawnTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, spawnThread, waveDelay, (!waveClear) ? waveInterval : 60); + + readyPlayers.clear(); + + // Logging info. + if (logging) + log.start(); + + MAUtils.tellAll(this, MAMessages.get(Msg.ARENA_START)); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onArenaStart(); + }*/ + + public boolean endArena() + { + // Sanity-checks. + if (!running || !arenaPlayers.isEmpty()) + return false; + + // Stop spawning. + stopSpawning(); + + // Set the boolean. + running = false; + + // Stop logging. + if (logging) + { + log.end(); + log.serialize(); + log.clear(); + } + + // Clean arena floor. + cleanup(); + + // Restore region. + if (softRestore) + for (int[] buffer : repairList) + world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeIdAndData(buffer[3], (byte) buffer[4], false); + else if (forceRestore) + deserializeRegion(); + + // Announce and clear sets. + MAUtils.tellAll(this, MAMessages.get(Msg.ARENA_END), true); + arenaPlayers.clear(); + notifyPlayers.clear(); + classMap.clear(); + rewardMap.clear(); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onArenaEnd(); + + return true; + } + + /** + * End this arena's session. + */ + /*public void endArena() + { + running = false; + + MAUtils.tellAll(this, MAMessages.get(Msg.ARENA_END), true); + + // Logging stuff + if (logging) + { + log.end(); + log.serialize(); + log.clear(); + } + + // If the arena was actually ever started, cancel the spawnthread. + if (spawnThread != null) + { + Bukkit.getServer().getScheduler().cancelTask(spawnThread.taskId); + Bukkit.getServer().getScheduler().cancelTask(spawnTaskId); + } + + if (!emptyInvJoin) + for (Player p : deadPlayers) + MAUtils.restoreInventory(p); + + // Clean up the arena floor and give rewards + cleanup(); + giveRewards(); + + // Clear all the sets and maps. + livePlayers.clear(); + deadPlayers.clear(); + waitPlayers.clear(); + pets.clear(); + classMap.clear(); + rewardMap.clear(); + + if (softRestore) + for (int[] buffer : repairList) + world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeIdAndData(buffer[3], (byte) buffer[4], false); + else if (forceRestore) + deserializeRegion(); + + // Set the spawn flags to restore monster spawning. + MAUtils.setSpawnFlags(plugin, world, spawnMonsters, allowMonsters, allowAnimals); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onArenaEnd(); + }*/ + + /** + * Force an arena start by forcing all not-ready players to leave. + * @precondition - The arena musn't be running, and readyPlayers must not be empty. + */ + public void forceStart() + { + // Set operations. + Set tmp = new HashSet(); + //tmp.addAll(livePlayers); + tmp.removeAll(readyPlayers); + + // Force leave. + for (Player p : tmp) + { + plugin.getAM().arenaMap.remove(p); + playerLeave(p); + } + } + + /** + * Force an arena end by forcing all players to leave. + * @precondition - livePlayers must not be empty. + */ + /*public void forceEnd() + { + // Force leave. + for (Player p : getAllPlayers()) + { + plugin.getAM().arenaMap.remove(p); + playerLeave(p); + } + }*/ + + public void forceEnd() + { + for (Player p : getAllPlayers()) + { + plugin.getAM().arenaMap.remove(p); + playerLeave(p); + } + } + + public void playerJoin(Player p, Location loc) + { + if (!locations.containsKey(p)) + locations.put(p,loc); + + // Update chunk. + updateChunk(lobbyLoc); + + MAUtils.sitPets(p); + lobbyPlayers.add(p); + p.teleport(lobbyLoc); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerJoin(p); + } + + /** + * Warp the player to the arena lobby and add to the set of live players. + */ + /*public void playerJoin(Player p, Location loc) + { + if (!locations.containsKey(p)) + locations.put(p,loc); + + if (livePlayers.isEmpty()) + { + Chunk chunk = world.getChunkAt(lobbyLoc); + if (!world.isChunkLoaded(chunk)) + world.loadChunk(chunk); + else + world.refreshChunk(chunk.getX(), chunk.getZ()); + } + + MAUtils.sitPets(p); + livePlayers.add(p); + p.teleport(lobbyLoc); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerJoin(p); + }*/ + + /** + * Add the player to the set of ready players. + * If every is ready, the arena starts. + */ + public void playerReady(Player p) + { + readyPlayers.add(p); + startArena(); + } + + /*public void playerReady(Player p) + { + readyPlayers.add(p); + + if (readyPlayers.equals(livePlayers)) + startArena(); + }*/ + + /** + * Remove the player from all the player sets, and clear his inventory if necessary. + * If the set of live players becomes empty, end the arena. + * If the set of ready players becomes equal to the set of live players, start the arena. + */ + public void playerLeave(Player p) + { + // Clear class inventory, restore old inventory and fork over rewards. + restoreInvAndGiveRewards(p, !specPlayers.contains(p)); + + // Grab the player's entry location, and warp them there. + Location entry = locations.get(p); + if (entry != null) + { + updateChunk(entry); + p.teleport(entry); + } + locations.remove(p); + + // Remove from the arenaMap and all the sets. + plugin.getAM().arenaMap.remove(p); + removePlayer(p); + + // End the arena if conditions are met. + endArena(); + } + + public void playerDeath(final Player p) + { + // If spectate-on-death: false, pass on to playerLeave. + if (!specOnDeath) + { + p.teleport(arenaLoc); + playerLeave(p); + return; + } + + // Clear class inventory, restore old inventory and fork over rewards. + restoreInvAndGiveRewards(p, true); + + // Remove player from sets, warp to spectator area, then add to specPlayers. + removePlayer(p); + p.teleport(arenaLoc); // This will sometimes force players to drop any items held (not confirmed) + p.teleport(spectatorLoc); + specPlayers.add(p); + + // Update the monster targets. + if (running && spawnThread != null) + spawnThread.updateTargets(); + + // Announce and notify + MAUtils.tellAll(this, MAMessages.get(Msg.PLAYER_DIED, p.getName())); + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerDeath(p); + + // End the arena if conditions are met. + endArena(); + } + + /*public void playerLeave(Player p) + { + boolean clear = false; + + Location old = locations.get(p); + if (old != null) + { + Chunk chunk = old.getWorld().getChunkAt(old); + if (!old.getWorld().isChunkLoaded(chunk)) + old.getWorld().loadChunk(chunk); + else + old.getWorld().refreshChunk(chunk.getX(), chunk.getZ()); + + p.teleport(old); + } + locations.remove(p); // get, then remove, because of Teleport Event + + // Only clear the inventory if the player has class items. + if (readyPlayers.remove(p)) clear = true; + if (livePlayers.remove(p)) clear = true; + deadPlayers.remove(p); + specPlayers.remove(p); + hasPaid.remove(p); + removePets(p); + + // Update the monster targets. + if (running && spawnThread != null) + spawnThread.updateTargets(); + + // Clear inventory and record current wave + if (clear) + { + if (running) waveMap.put(p, spawnThread.wave - 1); + MAUtils.clearInventory(p); + } + + // Try to restore inventory. + if (!emptyInvJoin) + MAUtils.restoreInventory(p); + + // Grant rewards. + MAUtils.giveRewards(p, rewardMap.get(p), plugin); + + if (running && livePlayers.isEmpty()) + endArena(); + else if (!readyPlayers.isEmpty() && readyPlayers.equals(livePlayers)) + startArena(); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerLeave(p); + }*/ + + /*public void playerDeath(final Player p) + { + p.teleport(arenaLoc); // This will sometimes force players to drop any items held (not confirmed) + p.teleport(spectatorLoc); + p.setFireTicks(0); + p.setHealth(20); + + // Add to the list of dead players. + livePlayers.remove(p); + deadPlayers.add(p); + removePets(p); + + // Update the monster targets. + if (running && spawnThread != null) + spawnThread.updateTargets(); + + // Has to be delayed for TombStone not to fuck shit up. + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + if (!specOnDeath) + { + plugin.getAM().arenaMap.remove(p); + playerLeave(p); + } + else MAUtils.restoreInventory(p); + + if (livePlayers.isEmpty()) + endArena(); + } + }, 8); + + MAUtils.tellAll(this, MAMessages.get(Msg.PLAYER_DIED, p.getName())); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerDeath(p); + }*/ + + public void playerSpec(Player p, Location loc) + { + if (!locations.containsKey(p)) + locations.put(p,loc); + + MAUtils.sitPets(p); + specPlayers.add(p); + p.teleport(spectatorLoc); + } + + public void removePlayer(Player p) + { + // Heal and put out fire. + p.setFireTicks(0); + p.setHealth(20); + + // Remove pets. + removePets(p); + + // readyPlayers before lobbyPlayers because of startArena sanity-checks + readyPlayers.remove(p); + specPlayers.remove(p); + arenaPlayers.remove(p); + lobbyPlayers.remove(p); + + // arenaPlayers is empty if lobbyPlayers isn’t, and vice versa + /*if (arenaPlayers.remove(p)) + endArena2(); + if (lobbyPlayers.remove(p)) + startArena2();*/ + } + + public void spawnPets() + { + for (Map.Entry entry : petMap.entrySet()) + { + // Remove the bones from the inventory. + Player p = entry.getKey(); + p.getInventory().removeItem(new ItemStack(Material.BONE, entry.getValue())); + + // Spawn wolves, set owner and health, and add to pet set. + for (int i = 0; i < entry.getValue(); i++) + { + Wolf wolf = (Wolf) world.spawnCreature(p.getLocation(), CreatureType.WOLF); + wolf.setTamed(true); + wolf.setOwner(p); + wolf.setHealth(20); + if (hellhounds) + wolf.setFireTicks(32768); + pets.add(wolf); + } + } + } + + public void startSpawning() + { + // Set the spawn flags to enable monster spawning. + MAUtils.setSpawnFlags(plugin, world, 1, allowMonsters, allowAnimals); + + // Start the spawnThread. + spawnThread = new MASpawnThread(plugin, this); + spawnTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, spawnThread, waveDelay, (!waveClear) ? waveInterval : 60); + } + + public void stopSpawning() + { + // Stop the spawn thread. + if (spawnThread != null) + { + Bukkit.getServer().getScheduler().cancelTask(spawnThread.taskId); + Bukkit.getServer().getScheduler().cancelTask(spawnTaskId); + } + + // Restore spawn flags. + MAUtils.setSpawnFlags(plugin, world, spawnMonsters, allowMonsters, allowAnimals); + } + + public void updateChunk(Location loc) + { + if (!arenaPlayers.isEmpty()) + return; + + Chunk chunk = world.getChunkAt(lobbyLoc); + if (!world.isChunkLoaded(chunk)) + world.loadChunk(chunk); + else + world.refreshChunk(chunk.getX(), chunk.getZ()); + } + + public void playerKill(Player p) + { + killMap.put(p, killMap.get(p) + 1); + } + + public void restoreInvAndGiveRewards(final Player p, final boolean clear) + { + final List rewards = rewardMap.get(p); + + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + if (clear) + MAUtils.clearInventory(p); + + if (!emptyInvJoin) + MAUtils.restoreInventory(p); + MAUtils.giveRewards(p, rewards, plugin); + } + }); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // Items & Cleanup + // + ////////////////////////////////////////////////////////////////////*/ + + public void assignClass(Player p, String className) + { + petMap.remove(p); + classMap.put(p, className); + + MAUtils.clearInventory(p); + + // If random, don't give any items yet. + if (className.equalsIgnoreCase("random")) + { + randoms.add(p); + return; + } + + MAUtils.giveItems(p, classItems.get(className), autoEquip, plugin); + MAUtils.giveItems(p, classArmor.get(className), autoEquip, plugin); + + int pets = MAUtils.getPetAmount(p); + if (pets > 0) petMap.put(p, pets); + } + + public void assignRandomClass(Player p) + { + Random r = new Random(); + List classes = new LinkedList(plugin.getAM().classes); + + String className = classes.remove(r.nextInt(classes.size())); + while (!plugin.has(p, "mobarena.classes." + className)) + { + if (classes.isEmpty()) + { + System.out.println("[MobArena] ERROR! Player '" + p.getName() + "' has no class permissions!"); + playerLeave(p); + return; + } + className = classes.remove(r.nextInt(classes.size())); + } + + assignClass(p, className); + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_CLASS_PICKED, className)); + } + + private void giveRewards() + { + for (Map.Entry> entry : rewardMap.entrySet()) + { + MAUtils.tellPlayer(entry.getKey(), MAMessages.get(Msg.REWARDS_GIVE)); + MAUtils.giveRewards(entry.getKey(), entry.getValue(), plugin); + } + } + + private void cleanup() + { + removeMonsters(); + removeBlocks(); + removePets(); + removeEntities(); + monsters.clear(); + blocks.clear(); + pets.clear(); + } + + private void removeMonsters() + { + for (LivingEntity e : monsters) + e.remove(); + } + + private void removeBlocks() + { + for (Block b : blocks) + b.setTypeId(0); + } + + private void removePets() + { + for (Wolf w : pets) + { + w.setOwner(null); + w.remove(); + } + } + + private void removePets(Player p) + { + for (Wolf w : pets) + { + if (!((Player) w.getOwner()).getName().equals(p.getName())) + continue; + + w.setOwner(null); + w.remove(); + } + petMap.remove(p); + } + + private void removeEntities() + { + Chunk c1 = world.getChunkAt(p1); + Chunk c2 = world.getChunkAt(p2); + + for (int i = c1.getX(); i <= c2.getX(); i++) + for (int j = c1.getZ(); j <= c2.getZ(); j++) + for (Entity e : world.getChunkAt(i,j).getEntities()) + if ((e instanceof Item || e instanceof Slime) && inRegion(e.getLocation())) + e.remove(); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // Initialization & Checks + // + ////////////////////////////////////////////////////////////////////*/ + + public void load(Configuration config) + { + config.load(); + + String arenaPath = "arenas." + MAUtils.nameArenaToConfig(name) + ".settings."; + String configName = MAUtils.nameArenaToConfig(name); + + enabled = config.getBoolean(arenaPath + "enabled", true); + protect = config.getBoolean(arenaPath + "protect", true); + logging = config.getBoolean(arenaPath + "logging", false); + autoEquip = config.getBoolean(arenaPath + "auto-equip-armor", true); + waveClear = config.getBoolean(arenaPath + "clear-wave-before-next", false); + detCreepers = config.getBoolean(arenaPath + "detonate-creepers", false); + detDamage = config.getBoolean(arenaPath + "detonate-damage", false); + lightning = config.getBoolean(arenaPath + "lightning", true); + forceRestore = config.getBoolean(arenaPath + "force-restore", false); + softRestore = config.getBoolean(arenaPath + "soft-restore", false); + softRestoreDrops = config.getBoolean(arenaPath + "soft-restore-drops", false); + emptyInvJoin = config.getBoolean(arenaPath + "require-empty-inv-join", true); + emptyInvSpec = config.getBoolean(arenaPath + "require-empty-inv-spec", true); + hellhounds = config.getBoolean(arenaPath + "hellhounds", false); + pvp = config.getBoolean(arenaPath + "pvp-enabled", false); + monsterInfight = config.getBoolean(arenaPath + "monster-infight", false); + allowWarp = config.getBoolean(arenaPath + "allow-teleporting", false); + specOnDeath = config.getBoolean(arenaPath + "spectate-on-death", true); + shareInArena = config.getBoolean(arenaPath + "share-items-in-arena", true); + joinDistance = config.getInt(arenaPath + "max-join-distance", 0); + playerLimit = config.getInt(arenaPath + "player-limit", 0); + repairDelay = config.getInt(arenaPath + "repair-delay", 5); + waveDelay = config.getInt(arenaPath + "first-wave-delay", 5) * 20; + waveInterval = config.getInt(arenaPath + "wave-interval", 20) * 20; + specialModulo = config.getInt(arenaPath + "special-modulo", 4); + maxIdleTime = config.getInt(arenaPath + "max-idle-time", 0) * 20; + + distDefault = MAUtils.getArenaDistributions(config, configName, "default"); + distSpecial = MAUtils.getArenaDistributions(config, configName, "special"); + everyWaveMap = MAUtils.getArenaRewardMap(config, configName, "every"); + afterWaveMap = MAUtils.getArenaRewardMap(config, configName, "after"); + entryFee = MAUtils.getEntryFee(config, configName); + + p1 = MAUtils.getArenaCoord(config, world, configName, "p1"); + p2 = MAUtils.getArenaCoord(config, world, configName, "p2"); + l1 = MAUtils.getArenaCoord(config, world, configName, "l1"); + l2 = MAUtils.getArenaCoord(config, world, configName, "l2"); + arenaLoc = MAUtils.getArenaCoord(config, world, configName, "arena"); + lobbyLoc = MAUtils.getArenaCoord(config, world, configName, "lobby"); + spectatorLoc = MAUtils.getArenaCoord(config, world, configName, "spectator"); + spawnpoints = MAUtils.getArenaSpawnpoints(config, world, configName); + + classes = plugin.getAM().classes; + classItems = plugin.getAM().classItems; + classArmor = plugin.getAM().classArmor; + + // Determine if the arena is properly set up. Then add the to arena list. + setup = MAUtils.verifyData(this); + lobbySetup = MAUtils.verifyLobby(this); + } + + public void serializeConfig() + { + String coords = "arenas." + configName() + ".coords."; + Configuration config = plugin.getConfig(); + + config.setProperty("arenas." + configName() + ".settings.enabled", enabled); + config.setProperty("arenas." + configName() + ".settings.protect", protect); + if (p1 != null) config.setProperty(coords + "p1", MAUtils.makeCoord(p1)); + if (p2 != null) config.setProperty(coords + "p2", MAUtils.makeCoord(p2)); + if (l1 != null) config.setProperty(coords + "l1", MAUtils.makeCoord(l1)); + if (l2 != null) config.setProperty(coords + "l2", MAUtils.makeCoord(l2)); + if (arenaLoc != null) config.setProperty(coords + "arena", MAUtils.makeCoord(arenaLoc)); + if (lobbyLoc != null) config.setProperty(coords + "lobby", MAUtils.makeCoord(lobbyLoc)); + if (spectatorLoc != null) config.setProperty(coords + "spectator", MAUtils.makeCoord(spectatorLoc)); + for (Map.Entry entry : spawnpoints.entrySet()) + config.setProperty(coords + "spawnpoints." + entry.getKey(), MAUtils.makeCoord(entry.getValue())); + + config.save(); + } + + public void deserializeConfig() + { + Configuration config = plugin.getConfig(); + config.load(); + load(config); + } + + public boolean serializeRegion() + { + int x1 = (int) p1.getX(); + int y1 = (int) p1.getY(); + int z1 = (int) p1.getZ(); + int x2 = (int) p2.getX(); + int y2 = (int) p2.getY(); + int z2 = (int) p2.getZ(); + + HashSet set = new HashSet(); + int[] buffer; + for (int i = x1; i <= x2; i++) + { + for (int j = y1; j <= y2; j++) + { + for (int k = z1; k <= z2; k++) + { + buffer = new int[4]; + buffer[0] = i; + buffer[1] = j; + buffer[2] = k; + buffer[3] = world.getBlockAt(i,j,k).getTypeId(); + set.add(buffer); + } + } + } + + try + { + new File(plugin.getDataFolder() + File.separator + "regions").mkdir(); + File regionFile = new File(plugin.getDataFolder() + File.separator + "regions" + File.separator + configName() + ".tmp"); + if (regionFile.exists()) + regionFile.createNewFile(); + + FileOutputStream fos = new FileOutputStream(regionFile); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(set); + oos.close(); + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR! Could not create region file. The arena will not be started!"); + e.printStackTrace(); + return false; + } + return true; + } + + @SuppressWarnings("unchecked") + public boolean deserializeRegion() + { + HashSet set = new HashSet(); + try + { + File regionFile = new File(plugin.getDataFolder() + File.separator + "regions" + File.separator + configName() + ".tmp"); + if (!regionFile.exists()) + return false; + + FileInputStream fis = new FileInputStream(regionFile); + ObjectInputStream ois = new ObjectInputStream(fis); + set = (HashSet) ois.readObject(); + ois.close(); + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR! Could not find region file. The arena cannot be restored!"); + e.printStackTrace(); + return false; + } + + for (int[] buffer : set) + world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeId(buffer[3]); + + return true; + } + + /** + * Check if a location is inside of the cuboid region + * that p1 and p2 span. + */ + public boolean inRegion(Location loc) + { + if (!loc.getWorld().getName().equals(world.getName()) || !setup) + return false; + + int x = loc.getBlockX(); + int y = loc.getBlockY(); + int z = loc.getBlockZ(); + + // Check the lobby first. + if (lobbySetup) + { + if ((x >= l1.getBlockX() && x <= l2.getBlockX()) && + (z >= l1.getBlockZ() && z <= l2.getBlockZ()) && + (y >= l1.getBlockY() && y <= l2.getBlockY())) + return true; + } + + // Returns false if the location is outside of the region. + return ((x >= p1.getBlockX() && x <= p2.getBlockX()) && + (z >= p1.getBlockZ() && z <= p2.getBlockZ()) && + (y >= p1.getBlockY() && y <= p2.getBlockY())); + } + + /** + * Check if a location is inside of the arena region, expanded + * by 'radius' blocks. Used with explosions. + */ + public boolean inRegionRadius(Location loc, int radius) + { + if (!loc.getWorld().getName().equals(world.getName()) || !setup) + return false; + + int x = loc.getBlockX(); + int y = loc.getBlockY(); + int z = loc.getBlockZ(); + + // Check the lobby first. + if (lobbySetup) + { + if ((x + radius >= l1.getBlockX() && x - radius <= l2.getBlockX()) && + (z + radius >= l1.getBlockZ() && z - radius <= l2.getBlockZ()) && + (y + radius >= l1.getBlockY() && y - radius <= l2.getBlockY())) + return true; + } + + return ((x + radius >= p1.getBlockX() && x - radius <= p2.getBlockX()) && + (z + radius >= p1.getBlockZ() && z - radius <= p2.getBlockZ()) && + (y + radius >= p1.getBlockY() && y - radius <= p2.getBlockY())); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // EventListener methods + // + ////////////////////////////////////////////////////////////////////*/ + + // Block Listener + public void onBlockBreak(BlockBreakEvent event) + { + if (!inRegion(event.getBlock().getLocation()) || edit || (!protect && running)) + return; + + Block b = event.getBlock(); + if (blocks.remove(b) || b.getType() == Material.TNT) + return; + + if (softRestore && running) + { + int[] buffer = new int[5]; + buffer[0] = b.getX(); + buffer[1] = b.getY(); + buffer[2] = b.getZ(); + buffer[3] = b.getTypeId(); + buffer[4] = (int) b.getData(); + repairList.add(buffer); + if (!softRestoreDrops) event.getBlock().setTypeId(0); + return; + } + + event.setCancelled(true); + } + + public void onBlockPlace(BlockPlaceEvent event) + { + if (!inRegion(event.getBlock().getLocation()) || edit) + return; + + Block b = event.getBlock(); + //if (running && livePlayers.contains(event.getPlayer())) + if (running && arenaPlayers.contains(event.getPlayer())) + { + blocks.add(b); + Material mat = b.getType(); + + if (mat == Material.WOODEN_DOOR || mat == Material.IRON_DOOR_BLOCK) + blocks.add(b.getRelative(0,1,0)); + return; + } + + // If the arena isn't running, or if the player isn't in the arena, cancel. + event.setCancelled(true); + } + + // Monster Listener + public void onCreatureSpawn(CreatureSpawnEvent event) + { + if (!inRegion(event.getLocation())) + return; + + // If running == true, setCancelled(false), and vice versa. + event.setCancelled(!running); + } + + public void onEntityExplode(EntityExplodeEvent event) + { + if (!monsters.contains(event.getEntity()) && !inRegionRadius(event.getLocation(), 10)) + return; + + event.setYield(0); + monsters.remove(event.getEntity()); + + // If the arena isn't running + if (!running || repairDelay == 0) + { + event.setCancelled(true); + return; + } + + // If there is a sign in the blocklist, cancel + for (Block b : event.blockList()) + { + if (!(b.getType() == Material.SIGN_POST || b.getType() == Material.WALL_SIGN)) + continue; + + event.setCancelled(true); + return; + } + + // Uncancel, just in case. + event.setCancelled(false); + + int[] buffer; + final HashMap blockMap = new HashMap(); + for (Block b : event.blockList()) + { + Material mat = b.getType(); + + if (mat == Material.LAVA) b.setType(Material.STATIONARY_LAVA); + else if (mat == Material.WATER) b.setType(Material.STATIONARY_WATER); + + if (mat == Material.WOODEN_DOOR || mat == Material.IRON_DOOR_BLOCK || mat == Material.FIRE || mat == Material.CAKE_BLOCK || mat == Material.WATER || mat == Material.LAVA) + { + blocks.remove(b); + } + else if (blocks.remove(b)) + { + world.dropItemNaturally(b.getLocation(), new ItemStack(b.getTypeId(), 1)); + } + else if (softRestore) + { + buffer = new int[5]; + buffer[0] = b.getX(); + buffer[1] = b.getY(); + buffer[2] = b.getZ(); + buffer[3] = b.getTypeId(); + buffer[4] = (int) b.getData(); + repairList.add(buffer); + blockMap.put(b, b.getTypeId() + (b.getData() * 1000)); + } + else + { + blockMap.put(b, b.getTypeId() + (b.getData() * 1000)); + } + } + + if (!protect || softRestore) + return; + + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + for (Map.Entry entry : blockMap.entrySet()) + { + Block b = entry.getKey(); + int type = entry.getValue(); + + b.getLocation().getBlock().setTypeId(type % 1000); + + if (type > 1000) + b.getLocation().getBlock().setData((byte) (type / 1000)); + } + } + }, repairDelay); + } + + public void onEntityCombust(EntityCombustEvent event) + { + if (monsters.contains(event.getEntity())) + event.setCancelled(true); + } + + public void onEntityTarget(EntityTargetEvent event) + { + if (!running || event.isCancelled()) + return; + + if (pets.contains(event.getEntity())) + { + if (event.getReason() != TargetReason.TARGET_ATTACKED_OWNER && event.getReason() != TargetReason.OWNER_ATTACKED_TARGET) + return; + + if (!(event.getTarget() instanceof Player)) + return; + + // If the target is a player, cancel. + event.setCancelled(true); + return; + } + + if (monsters.contains(event.getEntity())) + { + if (event.getReason() == TargetReason.FORGOT_TARGET) + { + event.setTarget(MAUtils.getClosestPlayer(event.getEntity(), this)); + return; + } + + if (event.getReason() == TargetReason.TARGET_DIED) + { + event.setTarget(MAUtils.getClosestPlayer(event.getEntity(), this)); + return; + } + + if (event.getReason() == TargetReason.CLOSEST_PLAYER) + //if (!livePlayers.contains(event.getTarget())) + if (!arenaPlayers.contains(event.getTarget())) + event.setCancelled(true); + return; + } + } + + // Death Listener + public void onEntityRegainHealth(EntityRegainHealthEvent event) + { + if (!running) return; + + //if (!(event.getEntity() instanceof Player) || !livePlayers.contains((Player)event.getEntity())) + if (!(event.getEntity() instanceof Player) || !arenaPlayers.contains((Player)event.getEntity())) + return; + + if (event.getRegainReason() == RegainReason.REGEN) + event.setCancelled(true); + } + + public void onEntityDeath(EntityDeathEvent event) + { + if (event.getEntity() instanceof Player) + { + Player p = (Player) event.getEntity(); + + //if (!livePlayers.contains(p)) + if (!arenaPlayers.contains(p)) + return; + + event.getDrops().clear(); + waveMap.put(p, spawnThread.wave - 1); + playerDeath(p); + //p.getInventory().clear(); // For TombStone + return; + } + + if (monsters.remove(event.getEntity())) + { + EntityDamageEvent e1 = event.getEntity().getLastDamageCause(); + EntityDamageByEntityEvent e2 = (e1 instanceof EntityDamageByEntityEvent) ? (EntityDamageByEntityEvent) e1 : null; + Entity damager = (e2 != null) ? e2.getDamager() : null; + + if (e2 != null && damager instanceof Player) + playerKill((Player) damager); + + event.getDrops().clear(); + resetIdleTimer(); + return; + } + } + + public void onEntityDamage(EntityDamageEvent event) + { + if (!running) return; + + EntityDamageByEntityEvent e = (event instanceof EntityDamageByEntityEvent) ? (EntityDamageByEntityEvent) event : null; + Entity damager = (e != null) ? e.getDamager() : null; + Entity damagee = event.getEntity(); + + // Damagee - Pet Wolf - cancel all damage. + if (damagee instanceof Wolf && pets.contains(damagee)) + { + if (event.getCause() == DamageCause.FIRE_TICK) + { + damagee.setFireTicks(32768); // For mcMMO + event.setCancelled(true); + } + if (e != null && damager instanceof Player) + event.setCancelled(true); + + event.setDamage(0); + return; + } + + // Damager - Pet Wolf - lower damage + if (e != null && damager instanceof Wolf && pets.contains(damager)) + { + event.setDamage(1); + return; + } + + // Damagee & Damager - Player - cancel if pvp disabled + if (damagee instanceof Player && damager instanceof Player) + { + //if (livePlayers.contains(damagee) && !pvp) + if (arenaPlayers.contains(damagee) && !pvp) + event.setCancelled(true); + + return; + } + + // Damagee & Damager - Monsters - cancel if no monsterInfight + if (e != null && monsters.contains(damagee) && monsters.contains(damager)) + { + if (!monsterInfight) + event.setCancelled(true); + + return; + } + + // Creeper detonations + if (inRegion(damagee.getLocation())) + { + //if (!detDamage || !(damagee instanceof Player) || !livePlayers.contains((Player) damagee)) + if (!detDamage || !(damagee instanceof Player) || !arenaPlayers.contains((Player) damagee)) + return; + + if (event.getCause() == DamageCause.BLOCK_EXPLOSION) + event.setCancelled(true); + + return; + } + } + + // Lobby Listener + public void onPlayerDropItem(PlayerDropItemEvent event) + { + if (running && shareInArena) return; + + Player p = event.getPlayer(); + //if (!livePlayers.contains(p)) + if (!arenaPlayers.contains(p) && !lobbyPlayers.contains(p)) + return; + + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_DROP_ITEM)); + event.setCancelled(true); + } + + public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) + { + //if (!readyPlayers.contains(event.getPlayer()) && !livePlayers.contains(event.getPlayer())) + if (!readyPlayers.contains(event.getPlayer()) && !arenaPlayers.contains(event.getPlayer())) + return; + + if (!running) + { + event.getBlockClicked().getFace(event.getBlockFace()).setTypeId(0); + event.setCancelled(true); + return; + } + + Block liquid = event.getBlockClicked().getFace(event.getBlockFace()); + blocks.add(liquid); + } + + public void onPlayerInteract(PlayerInteractEvent event) + { + //if (!livePlayers.contains(event.getPlayer())) + if (!arenaPlayers.contains(event.getPlayer()) && !lobbyPlayers.contains(event.getPlayer())) + return; + + if (running) + { + if (event.hasBlock() && event.getClickedBlock().getType() == Material.SAPLING) + addTrunkAndLeaves(event.getClickedBlock()); + return; + } + + Action a = event.getAction(); + Player p = event.getPlayer(); + if (a == Action.RIGHT_CLICK_AIR || a == Action.RIGHT_CLICK_BLOCK) + { + event.setUseItemInHand(Result.DENY); + event.setCancelled(true); + } + + // Iron block + if (event.hasBlock() && event.getClickedBlock().getTypeId() == 42) + { + if (classMap.containsKey(p)) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_PLAYER_READY)); + playerReady(p); + } + else + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_PICK_CLASS)); + } + return; + } + + // Sign + if (event.hasBlock() && event.getClickedBlock().getState() instanceof Sign) + { + if (a == Action.RIGHT_CLICK_BLOCK) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_RIGHT_CLICK)); + return; + } + + // Cast the block to a sign to get the text on it. + Sign sign = (Sign) event.getClickedBlock().getState(); + + // Check if the first line of the sign is a class name. + String className = sign.getLine(0); + if (!classes.contains(className) && !className.equalsIgnoreCase("random")) + return; + + if (!plugin.hasDefTrue(p, "mobarena.classes." + className) && !className.equalsIgnoreCase("random")) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_CLASS_PERMISSION)); + return; + } + + // Set the player's class. + assignClass(p, className); + if (!className.equalsIgnoreCase("random")) + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_CLASS_PICKED, className)); + else + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_CLASS_RANDOM)); + + return; + } + } + + // Disconnect Listener + public void onPlayerQuit(PlayerQuitEvent event) + { + Player p = event.getPlayer(); + //if (!enabled || !livePlayers.contains(p)) + if (!enabled || (!arenaPlayers.contains(p) && !lobbyPlayers.contains(p))) + return; + + //MAUtils.clearInventory(p); + plugin.getAM().arenaMap.remove(p); + playerLeave(p); + } + + public void onPlayerKick(PlayerKickEvent event) + { + Player p = event.getPlayer(); + //if (!enabled || !livePlayers.contains(p)) + if (!enabled || (!arenaPlayers.contains(p) && !lobbyPlayers.contains(p))) + return; + + //MAUtils.clearInventory(p); + plugin.getAM().arenaMap.remove(p); + playerLeave(p); + } + + // Teleport Listener + public void onPlayerTeleport(PlayerTeleportEvent event) + { + if (edit || !enabled || !setup || allowWarp) + return; + + if (!inRegion(event.getTo()) && !inRegion(event.getFrom())) + return; + + Player p = event.getPlayer(); + Location old = locations.get(p); + Location to = event.getTo(); + Location from = event.getFrom(); + + //if (livePlayers.contains(p) || specPlayers.contains(p)) + if (arenaPlayers.contains(p) || lobbyPlayers.contains(p) || specPlayers.contains(p)) + { + if (inRegion(from)) + { + if (to.equals(arenaLoc) || to.equals(lobbyLoc) || to.equals(spectatorLoc) || to.equals(old)) + return; + + MAUtils.tellPlayer(p, MAMessages.get(Msg.WARP_FROM_ARENA)); + event.setCancelled(true); + return; + } + + if (inRegion(to)) + { + if (to.equals(arenaLoc) || to.equals(lobbyLoc) || to.equals(spectatorLoc) || to.equals(old)) + return; + + MAUtils.tellPlayer(p, MAMessages.get(Msg.WARP_TO_ARENA)); + event.setCancelled(true); + return; + } + + return; + } + + if (running && inRegion(to)) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.WARP_TO_ARENA)); + event.setCancelled(true); + return; + } + } + + // Command Listener + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) + { + Player p = event.getPlayer(); + + //if (!livePlayers.contains(p)) + if (!arenaPlayers.contains(p) && !lobbyPlayers.contains(p)) + return; + + String[] args = event.getMessage().split(" "); + + if ((args.length > 1 && MACommands.COMMANDS.contains(args[1].trim())) || + MACommands.ALLOWED_COMMANDS.contains(event.getMessage().substring(1).trim()) || + MACommands.ALLOWED_COMMANDS.contains(args[0])) + return; + + event.setCancelled(true); + MAUtils.tellPlayer(p, MAMessages.get(Msg.MISC_COMMAND_NOT_ALLOWED)); + } + + + /*//////////////////////////////////////////////////////////////////// + // + // Getters & Misc + // + ////////////////////////////////////////////////////////////////////*/ + + public String configName() + { + return MAUtils.nameArenaToConfig(name); + } + + public String arenaName() + { + return name; + } + + /*public List getAllPlayers() + { + List result = new LinkedList(); + result.addAll(livePlayers); + result.addAll(deadPlayers); + result.addAll(specPlayers); + return result; + }*/ + + public List getAllPlayers() + { + List result = new LinkedList(); + result.addAll(arenaPlayers); + result.addAll(lobbyPlayers); + result.addAll(specPlayers); + return result; + } + + public List getLivingPlayers() + { + List result = new LinkedList(); + //result.addAll(livePlayers); + result.addAll(arenaPlayers); + return result; + } + + public List getNonreadyPlayers() + { + List result = new LinkedList(); + //result.addAll(livePlayers); + result.addAll(lobbyPlayers); + result.removeAll(readyPlayers); + return result; + } + + public List getDeadPlayers() + { + List result = new LinkedList(); + result.addAll(deadPlayers); + return result; + } + + public void resetIdleTimer() + { + if (maxIdleTime <= 0) + return; + + // Reset the previousSize, cancel the previous timer, and start the new timer. + spawnThread.previousSize = monsters.size(); + Bukkit.getServer().getScheduler().cancelTask(spawnThread.taskId); + spawnThread.taskId = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + // Make sure to remove any dead/removed entities first. + List tmp = new LinkedList(monsters); + for (Entity e : tmp) + if (e.isDead()) + monsters.remove(e); + + // Compare the current size with the previous size. + if (monsters.size() < spawnThread.previousSize || spawnThread.previousSize == 0) + { + resetIdleTimer(); + return; + } + + // Clear all player inventories, and "kill" all players. + //for (Player p : livePlayers) + for (Player p : arenaPlayers) + { + MAUtils.clearInventory(p); + MAUtils.tellPlayer(p, MAMessages.get(Msg.FORCE_END_IDLE)); + playerDeath(p); + } + } + }, maxIdleTime); + } + + public void delayRestoreInventory(final Player p, final String method) + { + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + if (method.equals("restoreInventory")) + MAUtils.restoreInventory(p); + else if (method.equals("giveRewards")) + MAUtils.giveRewards(p, rewardMap.get(p), plugin); + } + }, 10); + } + + public void addTrunkAndLeaves(Block b) + { + final int x = b.getX(); + final int y = b.getY(); + final int z = b.getZ(); + + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + List result = new LinkedList(); + for (int i = x-2; i <= x+2; i++) + for (int j = y; j <= y+10; j++) + for (int k = z-2; k <= z+2; k++) + if (world.getBlockAt(i,j,k).getType() == Material.LOG || world.getBlockAt(i,j,k).getType() == Material.LEAVES) + result.add(world.getBlockAt(i,j,k)); + + if (running) blocks.addAll(result); + } + }, 10); + } + + public boolean canAfford(Player p) + { + if (entryFee.isEmpty()) + return true; + + PlayerInventory inv = p.getInventory(); + for (ItemStack stack : entryFee) + { + // Economy money + if (stack.getTypeId() == MobArena.ECONOMY_MONEY_ID) + { + if (plugin.Methods.hasMethod() && !plugin.Method.getAccount(p.getName()).hasEnough(stack.getAmount())) + return false; + } + // Normal stack + else + { + if (!inv.contains(stack.getTypeId(), stack.getAmount())) + return false; + } + } + + return true; + } + + public boolean takeFee(Player p) + { + if (entryFee.isEmpty()) + return true; + + PlayerInventory inv = p.getInventory(); + for (ItemStack stack : entryFee) + { + // Economy money + if (stack.getTypeId() == MobArena.ECONOMY_MONEY_ID) + { + if (plugin.Methods.hasMethod() && !plugin.Method.getAccount(p.getName()).subtract(stack.getAmount())) + return false; + } + + // Normal stack + else + { + int id = stack.getTypeId(); + int amount = stack.getAmount(); + + while (amount > 0) + { + int pos = inv.first(id); + if (pos == -1) return false; + + ItemStack is = inv.getItem(pos); + if (is.getAmount() > amount) + { + is.setAmount(is.getAmount() - amount); + amount = 0; + } + else + { + amount -= is.getAmount(); + inv.setItem(pos, null); + } + } + } + } + + hasPaid.add(p); + return true; + } + + public void refund(Player p) + { + if (!hasPaid.contains(p)) + return; + + MAUtils.giveItems(p, entryFee, false, plugin); + } + + /** + * The "perfect equals method" cf. "Object-Oriented Design and Patterns" + * by Cay S. Horstmann. + */ + public boolean equals(Object other) + { + if (this == other) return true; + if (other == null) return false; + if (getClass() != other.getClass()) return false; + + // Arenas must have different names. + if (other instanceof Arena && ((Arena)other).name.equals(name)) + return true; + + return false; + } + + public String toString() + { + return ((enabled && setup) ? ChatColor.GREEN : ChatColor.GRAY) + configName(); + } +} diff --git a/src/com/garbagemule/MobArena/ArenaLog.java b/src/com/garbagemule/MobArena/ArenaLog.java new file mode 100644 index 0000000..3da9500 --- /dev/null +++ b/src/com/garbagemule/MobArena/ArenaLog.java @@ -0,0 +1,137 @@ +package com.garbagemule.MobArena; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.sql.Timestamp; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.bukkit.entity.Player; + +public class ArenaLog +{ + protected MobArena plugin; + protected Arena arena; + protected List log, classDistribution; + protected Timestamp startTime, endTime; + + public ArenaLog(MobArena plugin, Arena arena) + { + this.plugin = plugin; + this.arena = arena; + log = new LinkedList(); + classDistribution = new LinkedList(); + } + + public void start() + { + startTime = new Timestamp((new Date()).getTime()); + + // Class distribution + int length = 0; + for (String c : plugin.getAM().classes) + if (c.length() > length) + length = c.length(); + + List classList = new LinkedList(arena.classMap.values()); + for (String c : plugin.getAM().classes) + { + int count = 0; + int id = classList.indexOf(c); + while (id != -1) + { + classList.remove(id); + count++; + id = classList.indexOf(c); + } + //int percentage = (int) (((double) count) / ((double) arena.livePlayers.size())) * 100; + int percentage = (int) (((double) count) / ((double) arena.arenaPlayers.size())) * 100; + classDistribution.add(MAUtils.padRight(c + ": ", length + 2) + MAUtils.padLeft("" + count, 2) + " (" + percentage + "%)"); + } + } + + public void end() + { + endTime = new Timestamp((new Date()).getTime()); + + // General stuff + log.add("--------------------------------------------------- ENTRY ---"); + log.add("Start: " + startTime); + log.add("End: " + endTime); + log.add("Duration: " + MAUtils.getDuration(endTime.getTime() - startTime.getTime())); + log.add("Last wave: " + (arena.spawnThread.wave - 1)); + log.add(" "); + + // Class distribution + log.add("Class Distribution: " + plugin.getAM().classes.size() + " classes"); + for (String c : classDistribution) + log.add("- " + c); + classDistribution.clear(); + log.add(" "); + + // Player data + int NAME = 12; + int CLASS = 0; + int WAVE = 4; + int KILLS = 5; + for (String c : plugin.getAM().classes) + if (c.length() > CLASS) + CLASS = c.length(); + + log.add("Player Data: " + arena.classMap.keySet().size() + " players"); + log.add("- " + MAUtils.padRight("Name", NAME + 2, ' ') + MAUtils.padRight("Class", CLASS + 2, ' ') + MAUtils.padRight("Wave", WAVE + 2, ' ') + MAUtils.padRight("Kills", KILLS + 2, ' ') + "Rewards"); + for (Map.Entry entry : arena.classMap.entrySet()) + { + Player p = entry.getKey(); + StringBuffer buffy = new StringBuffer(); + buffy.append(" "); + // Name + String name = (p.getName().length() <= NAME) ? p.getName() : p.getName().substring(0, NAME+1); + buffy.append(MAUtils.padRight(name, NAME + 2, ' ')); + // Class + buffy.append(MAUtils.padRight(entry.getValue(), CLASS + 2, ' ')); + // Wave + buffy.append(MAUtils.padLeft(arena.waveMap.remove(p).toString(), WAVE, ' ') + " "); + // Kills + buffy.append(MAUtils.padLeft(arena.killMap.remove(p).toString(), KILLS, ' ') + " "); + // Rewards + buffy.append(MAUtils.listToString(arena.rewardMap.get(p), plugin)); + log.add(buffy.toString()); + } + + log.add(" "); + } + + public void serialize() + { + try + { + new File(plugin.getDataFolder() + File.separator + "logs").mkdir(); + File logFile = new File(plugin.getDataFolder() + File.separator + "logs" + File.separator + arena.configName() + ".log"); + if (logFile.exists()) + logFile.createNewFile(); + + FileWriter fw = new FileWriter(logFile, true); + BufferedWriter bw = new BufferedWriter(fw); + for (String l : log) + { + bw.write(l); + bw.write(System.getProperty("line.separator")); + } + + bw.close(); + } + catch (Exception e) + { + e.printStackTrace(); + System.out.println("[MobArena] ERROR! Could not create log file!"); + return; + } + } + + public void add(String s) { log.add(s); } + public void clear() { log.clear(); } +} diff --git a/src/com/garbagemule/MobArena/ArenaMaster.java b/src/com/garbagemule/MobArena/ArenaMaster.java new file mode 100644 index 0000000..41119e6 --- /dev/null +++ b/src/com/garbagemule/MobArena/ArenaMaster.java @@ -0,0 +1,386 @@ +package com.garbagemule.MobArena; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.config.Configuration; + +public class ArenaMaster +{ + private MobArena plugin; + private Configuration config; + protected Arena selectedArena; + //protected Lobby masterLobby; + + // Settings + protected boolean enabled, updateNotify; + + // Classes + protected List classes; + protected Map> classItems, classArmor; + protected Map>> classBonuses; + protected Map arenaMap; + + // Location map + protected Map locations = new HashMap(); + + // Arena list + protected List arenas; + + // Listeners + protected Set listeners = new HashSet(); + + + + /** + * Default constructor. + */ + public ArenaMaster(MobArena instance) + { + plugin = instance; + config = plugin.getConfig(); + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Arena getters + // + /////////////////////////////////////////////////////////////////////////*/ + + public List getEnabledArenas() + { + List result = new LinkedList(); + for (Arena arena : arenas) + if (arena.enabled) + result.add(arena); + return result; + } + + public Arena getArenaAtLocation(Location loc) + { + for (Arena arena : arenas) + if (arena.inRegion(loc)) + return arena; + return null; + } + + public List getArenasInWorld(World world) + { + List result = new LinkedList(); + for (Arena arena : arenas) + if (arena.world.equals(world)) + result.add(arena); + return result; + } + + public List getAllPlayers() + { + List result = new LinkedList(); + for (Arena arena : arenas) + result.addAll(arena.getAllPlayers()); + return result; + } + + public List getAllPlayersInArena(String arenaName) + { + Arena arena = getArenaWithName(arenaName); + return (arena != null) ? arena.getLivingPlayers() : new LinkedList(); + } + + public List getAllLivingPlayers() + { + List result = new LinkedList(); + for (Arena arena : arenas) + result.addAll(arena.getLivingPlayers()); + return result; + } + + public List getLivingPlayersInArena(String arenaName) + { + Arena arena = getArenaWithName(arenaName); + return (arena != null) ? arena.getLivingPlayers() : new LinkedList(); + } + + public Arena getArenaWithPlayer(Player p) + { + return arenaMap.get(p); + } + + public Arena getArenaWithPlayer(String playerName) + { + return arenaMap.get(Bukkit.getServer().getPlayer(playerName)); + } + + public Arena getArenaWithSpectator(Player p) + { + for (Arena arena : arenas) + { + if (arena.specPlayers.contains(p)) + return arena; + } + return null; + } + + public Arena getArenaWithMonster(Entity e) + { + for (Arena arena : arenas) + if (arena.monsters.contains(e)) + return arena; + return null; + } + + public Arena getArenaWithPet(Entity e) + { + for (Arena arena : arenas) + if (arena.pets.contains(e)) + return arena; + return null; + } + + public Arena getArenaWithName(String configName) + { + for (Arena arena : arenas) + if (arena.configName().equals(configName)) + return arena; + return null; + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Initialization + // + /////////////////////////////////////////////////////////////////////////*/ + + public void initialize() + { + config.load(); + loadSettings(); + loadClasses(); + loadArenas(); + config.save(); + } + + /** + * Load the global settings. + */ + public void loadSettings() + { + if (config.getKeys("global-settings") == null) + { + config.setProperty("global-settings.enabled", true); + config.setProperty("global-settings.update-notification", true); + } + + enabled = config.getBoolean("global-settings.enabled", true); + updateNotify = config.getBoolean("global-settings.update-notification", true); + } + + /** + * Load all class-related stuff. + */ + public void loadClasses() + { + if (config.getKeys("classes") == null) + { + config.setProperty("classes.Archer.items", "wood_sword, bow, arrow:128, grilled_pork"); + config.setProperty("classes.Archer.armor", "298,299,300,301"); + config.setProperty("classes.Knight.items", "diamond_sword, grilled_pork:2"); + config.setProperty("classes.Knight.armor", "306,307,308,309"); + config.setProperty("classes.Tank.items", "iron_sword, grilled_pork:3, apple"); + config.setProperty("classes.Tank.armor", "310,311,312,313"); + config.setProperty("classes.Oddjob.items", "stone_sword, flint_and_steel, netherrack:2, wood_pickaxe, tnt:4, fishing_rod, apple, grilled_pork:3"); + config.setProperty("classes.Oddjob.armor", "298,299,300,301"); + config.setProperty("classes.Chef.items", "stone_sword, bread:6, grilled_pork:4, mushroom_soup, cake:3, cookie:12"); + config.setProperty("classes.Chef.armor", "314,315,316,317"); + } + classes = config.getKeys("classes"); + classItems = MAUtils.getClassItems(config, "items"); + classArmor = MAUtils.getClassItems(config, "armor"); + } + + /** + * Load all arena-related stuff. + */ + public void loadArenas() + { + arenas = new LinkedList(); + + if (config.getKeys("arenas") == null) + createArenaNode("default", Bukkit.getServer().getWorlds().get(0)); + + for (String configName : config.getKeys("arenas")) + { + String arenaPath = "arenas." + configName + "."; + String worldName = config.getString(arenaPath + "settings.world"); + World world; + if (worldName == null) + { + System.out.println("[MobArena] ERROR! Could not find the world for arena '" + configName + "'. Using default world! Check the config-file!"); + world = Bukkit.getServer().getWorlds().get(0); + } + else + { + world = Bukkit.getServer().getWorld(worldName); + } + + Arena arena = new Arena(MAUtils.nameConfigToArena(configName), world); + arena.load(config); + arenas.add(arena); + } + + arenaMap = new HashMap(); + selectedArena = arenas.get(0); + } + + public Arena createArenaNode(String configName, World world) + { + config.setProperty("arenas." + configName + ".settings.world", world.getName()); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.enabled", true); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.protect", true); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.entry-fee", ""); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.logging", false); + config.setProperty("arenas." + configName + ".settings.clear-wave-before-next", false); + config.setProperty("arenas." + configName + ".settings.detonate-creepers", false); + config.setProperty("arenas." + configName + ".settings.detonate-damage", false); + config.setProperty("arenas." + configName + ".settings.lightning", true); + config.setProperty("arenas." + configName + ".settings.auto-equip-armor", true); + config.setProperty("arenas." + configName + ".settings.force-restore", false); + config.setProperty("arenas." + configName + ".settings.soft-restore", false); + config.setProperty("arenas." + configName + ".settings.soft-restore-drops", false); + config.setProperty("arenas." + configName + ".settings.require-empty-inv-join", true); + config.setProperty("arenas." + configName + ".settings.require-empty-inv-spec", true); + config.setProperty("arenas." + configName + ".settings.hellhounds", false); + config.setProperty("arenas." + configName + ".settings.pvp-enabled", false); + config.setProperty("arenas." + configName + ".settings.monster-infight", false); + config.setProperty("arenas." + configName + ".settings.allow-teleporting", false); + config.setProperty("arenas." + configName + ".settings.spectate-on-death", true); + config.setProperty("arenas." + configName + ".settings.share-items-in-arena", true); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.player-limit", 0); + config.setProperty("arenas." + configName + ".settings.max-join-distance", 0); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.repair-delay", 5); + config.setProperty("arenas." + configName + ".settings.first-wave-delay", 5); + config.setProperty("arenas." + configName + ".settings.wave-interval", 20); + config.setProperty("arenas." + configName + ".settings.special-modulo", 4); + config.setProperty("arenas." + configName + ".settings.max-idle-time", 0); + config.save(); + config.load(); + + Arena arena = new Arena(MAUtils.nameConfigToArena(configName), world); + arena.load(config); + return arena; + } + + public void removeArenaNode(String configName) + { + config.removeProperty("arenas." + configName); + config.save(); + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Update and serialization methods + // + /////////////////////////////////////////////////////////////////////////*/ + + /** + * Update one, two or all three of global settings, classes + * and arenas (arenas with deserialization). + */ + public void update(boolean settings, boolean classes, boolean arenalist) + { + boolean tmp = enabled; + enabled = false; + + for (Arena arena : arenas) + arena.forceEnd(); + + config.load(); + if (settings) loadSettings(); + if (classes) loadClasses(); + if (arenalist) deserializeArenas(); + config.save(); + + enabled = tmp; + } + + /** + * Serialize the global settings. + */ + public void serializeSettings() + { + String settings = "global-settings."; + config.setProperty(settings + "enabled", enabled); + config.save(); + } + + /** + * Serialize all arena configs. + */ + public void serializeArenas() + { + for (Arena arena : arenas) + arena.serializeConfig(); + } + + /** + * Deserialize all arena configs. Updates the arena list to + * include only the current arenas (not ones added in the + * actual file) that are also in the config-file. + */ + public void deserializeArenas() + { + // Get only the arenas in the config. + List strings = config.getKeys("arenas"); + if (strings == null) + return; + + // Get their Arena objects. + List configArenas = new LinkedList(); + for (String s : strings) + if (getArenaWithName(s) != null) + configArenas.add(getArenaWithName(s)); + + // Remove all Arenas no longer in the config. + arenas.retainAll(configArenas); + + for (Arena arena : arenas) + arena.deserializeConfig(); + + // Make sure to update the selected arena to a valid one. + if (!arenas.contains(selectedArena) && arenas.size() >= 1) + selectedArena = arenas.get(0); + } + + public void updateSettings() { update(true, false, false); } + public void updateClasses() { update(false, true, false); } + public void updateArenas() { update(false, false, true); } + public void updateAll() { update(true, true, true); } +} diff --git a/src/com/garbagemule/MobArena/EntityPosition.java b/src/com/garbagemule/MobArena/EntityPosition.java new file mode 100644 index 0000000..5ee96bb --- /dev/null +++ b/src/com/garbagemule/MobArena/EntityPosition.java @@ -0,0 +1,89 @@ +package com.garbagemule.MobArena; + +import java.io.Serializable; +import org.bukkit.Location; +import org.bukkit.World; + +/** + * NOTE: I (garbagemule) DID NOT WRITE THIS CLASS (notice the author below) + * @author creadri + */ +@SuppressWarnings("serial") +public class EntityPosition implements Serializable{ + private double x; + private double y; + private double z; + private String world; + private float yaw; + private float pitch; + + public EntityPosition(double x, double y, double z, String world, float yaw, float pitch) { + this.x = x; + this.y = y; + this.z = z; + this.world = world; + this.yaw = yaw; + this.pitch = pitch; + } + + public EntityPosition(Location location) { + this.x = location.getX(); + this.y = location.getY(); + this.z = location.getZ(); + this.world = location.getWorld().getName(); + this.yaw = location.getYaw(); + this.pitch = location.getPitch(); + } + + public Location getLocation(World world) { + return new Location(world, x, y, z, yaw, pitch); + } + + public float getPitch() { + return pitch; + } + + public void setPitch(float pitch) { + this.pitch = pitch; + } + + public String getWorld() { + return world; + } + + public void setWorld(String world) { + this.world = world; + } + + public double getX() { + return x; + } + + public void setX(double x) { + this.x = x; + } + + public double getY() { + return y; + } + + public void setY(double y) { + this.y = y; + } + + public float getYaw() { + return yaw; + } + + public void setYaw(float yaw) { + this.yaw = yaw; + } + + public double getZ() { + return z; + } + + public void setZ(double z) { + this.z = z; + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/Lobby.java b/src/com/garbagemule/MobArena/Lobby.java new file mode 100644 index 0000000..6740175 --- /dev/null +++ b/src/com/garbagemule/MobArena/Lobby.java @@ -0,0 +1,26 @@ +package com.garbagemule.MobArena; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class Lobby +{ + protected Arena arena; + protected ArenaMaster am; + protected Location warp, l1, l2; + + public Lobby(Arena arena) + { + this.arena = arena; + } + public Lobby() + { + this(null); + } + + public void playerJoin(Player p) + { + p.teleport(warp); + } +} diff --git a/src/com/garbagemule/MobArena/MABlockListener.java b/src/com/garbagemule/MobArena/MABlockListener.java new file mode 100644 index 0000000..fef7a65 --- /dev/null +++ b/src/com/garbagemule/MobArena/MABlockListener.java @@ -0,0 +1,27 @@ +package com.garbagemule.MobArena; + +import org.bukkit.event.block.BlockListener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; + +public class MABlockListener extends BlockListener +{ + private ArenaMaster am; + + public MABlockListener(ArenaMaster am) + { + this.am = am; + } + + public void onBlockBreak(BlockBreakEvent event) + { + for (Arena arena : am.arenas) + arena.onBlockBreak(event); + } + + public void onBlockPlace(BlockPlaceEvent event) + { + for (Arena arena : am.arenas) + arena.onBlockPlace(event); + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MACommands.java b/src/com/garbagemule/MobArena/MACommands.java new file mode 100644 index 0000000..d13fc5c --- /dev/null +++ b/src/com/garbagemule/MobArena/MACommands.java @@ -0,0 +1,1212 @@ +package com.garbagemule.MobArena; + +import java.util.List; +import java.util.LinkedList; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.ConsoleCommandSender; + +import com.garbagemule.MobArena.MAMessages.Msg; + +public class MACommands implements CommandExecutor +{ + public static List ALLOWED_COMMANDS = new LinkedList(); + public static final List COMMANDS = new LinkedList(); + static + { + COMMANDS.add("j"); // Join + COMMANDS.add("join"); // Join + COMMANDS.add("l"); // Leave + COMMANDS.add("leave"); // Leave + COMMANDS.add("notready"); // List of players who aren't ready + COMMANDS.add("spec"); // Watch arena + COMMANDS.add("spectate"); // Watch arena + COMMANDS.add("arenas"); // List of arenas + COMMANDS.add("list"); // List of players + COMMANDS.add("players"); // List of players + COMMANDS.add("info"); // Info/help + COMMANDS.add("help"); // Info/help + COMMANDS.add("restore"); // Restore inventory + COMMANDS.add("enable"); // Enabling + COMMANDS.add("disable"); // Disabling + COMMANDS.add("protect"); // Protection on/off + COMMANDS.add("force"); // Force start/end + COMMANDS.add("config"); // Reload config + COMMANDS.add("arena"); // Current arena + COMMANDS.add("setarena"); // Set current arena + COMMANDS.add("addarena"); // Add a new arena + COMMANDS.add("delarena"); // Delete current aren + COMMANDS.add("editarena"); // Editing + COMMANDS.add("setregion"); // Set a region point + COMMANDS.add("expandregion"); // Expand the region + COMMANDS.add("showregion"); // Show the region + COMMANDS.add("setlobbyregion"); // Set a region point + COMMANDS.add("expandlobbyregion"); // Expand the region + COMMANDS.add("setwarp"); // Set arena/lobby/spec + COMMANDS.add("spawnpoints"); // List spawnpoints + COMMANDS.add("addspawn"); // Add a spawnpoint + COMMANDS.add("delspawn"); // Delete a spawnpoint + COMMANDS.add("reset"); // Reset arena coordinates + COMMANDS.add("auto-generate"); // Auto-generate arena + COMMANDS.add("auto-degenerate"); // Restore cuboid + } + private boolean meanAdmins, showingRegion; + private Server server; + private MobArena plugin; + private ArenaMaster am; + + public MACommands(MobArena plugin, ArenaMaster am) + { + this.plugin = plugin; + this.am = am; + server = Bukkit.getServer(); + meanAdmins = (server.getPluginManager().getPlugin("Mean Admins") != null); + ALLOWED_COMMANDS = MAUtils.getAllowedCommands(plugin.getConfig()); + } + + /** + * Handles all command parsing. + * Unrecognized commands return false, giving the sender a list of + * valid commands (from plugin.yml). + */ + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) + { + // Play nice with Mean Admins. + if (meanAdmins && !COMMANDS.contains(args[0].toLowerCase())) + { + server.getPluginManager().getPlugin("Mean Admins").onCommand(sender, command, label, args); + return true; + } + + // Determine if the sender is a player (and an op), or the console. + boolean player = (sender instanceof Player); + boolean op = player && ((Player) sender).isOp(); + boolean console = (sender instanceof ConsoleCommandSender); + + // Cast the sender to Player if possible. + Player p = (player) ? (Player)sender : null; + + if (args.length == 0) + return false; + + // Grab the command base and any arguments. + String base = args[0].toLowerCase(); + String arg1 = (args.length > 1) ? args[1].toLowerCase() : ""; + String arg2 = (args.length > 2) ? args[2].toLowerCase() : ""; + String arg3 = (args.length > 3) ? args[3].toLowerCase() : ""; + + + + /*//////////////////////////////////////////////////////////////// + // + // Basics + // + ////////////////////////////////////////////////////////////////*/ + + /* + * Player join + */ + if (base.equals("join") || base.equals("j")) + { + if (!player || !plugin.has(p, "mobarena.use.join")) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + List arenas = am.getEnabledArenas(); + if (!am.enabled || arenas.size() < 1) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_NOT_ENABLED)); + return true; + } + + boolean error; + Arena arena; + + if (!arg1.isEmpty()) + arena = am.getArenaWithName(arg1); + else if (arenas.size() == 1) + arena = arenas.get(0); + else + arena = null; + + if (arenas.size() > 1 && arg1.isEmpty()) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARG_NEEDED)); + else if (arena == null) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + //else if (am.arenaMap.containsKey(p) && am.arenaMap.get(p).livePlayers.contains(p)) + else if (am.arenaMap.containsKey(p) && (am.arenaMap.get(p).arenaPlayers.contains(p) || am.arenaMap.get(p).lobbyPlayers.contains(p))) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_IN_OTHER_ARENA)); + else if (!arena.enabled) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_NOT_ENABLED)); + else if (!arena.setup || arena.edit) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_NOT_SETUP)); + else if (arena.running && arena.waitPlayers.add(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_IS_RUNNING)); + //else if (arena.livePlayers.contains(p)) + else if (arena.arenaPlayers.contains(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ALREADY_PLAYING)); + else if (!plugin.has(p, "mobarena.arenas." + arena.configName())) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_PERMISSION)); + else if (!arena.canAfford(p) || !arena.takeFee(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_FEE_REQUIRED, MAUtils.listToString(arena.entryFee, plugin))); + //else if (arena.playerLimit > 0 && arena.livePlayers.size() >= arena.playerLimit) + else if (arena.playerLimit > 0 && arena.lobbyPlayers.size() >= arena.playerLimit) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_PLAYER_LIMIT_REACHED)); + else if (arena.emptyInvJoin && !MAUtils.hasEmptyInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_EMPTY_INV)); + else if (!arena.emptyInvJoin && !MAUtils.storeInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_STORE_INV_FAIL)); + else if (arena.joinDistance > 0 && !arena.inRegionRadius(p.getLocation(), arena.joinDistance)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_TOO_FAR)); + else error = false; + + // If there was an error, don't join. + if (error) + { + if (arena != null) + arena.refund(p); + return true; + } + + // If player is in a boat/minecart, eject! + if (p.isInsideVehicle()) + p.leaveVehicle(); + + am.arenaMap.put(p,arena); + arena.playerJoin(p, p.getLocation()); + + MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_PLAYER_JOINED)); + if (!arena.entryFee.isEmpty()) + MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_FEE_PAID, MAUtils.listToString(arena.entryFee, plugin))); + + return true; + } + + /* + * Player leave + */ + if (base.equals("leave") || base.equals("l")) + { + if (!player || !plugin.has(p, "mobarena.use.leave")) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!am.arenaMap.containsKey(p)) + { + Arena arena = am.getArenaWithSpectator(p); + if (arena != null) + { + arena.playerLeave(p); + MAUtils.tellPlayer(p, MAMessages.get(Msg.LEAVE_PLAYER_LEFT)); + return true; + } + + MAUtils.tellPlayer(p, MAMessages.get(Msg.LEAVE_NOT_PLAYING)); + return true; + } + + Arena arena = am.arenaMap.remove(p); + arena.playerLeave(p); + MAUtils.tellPlayer(p, MAMessages.get(Msg.LEAVE_PLAYER_LEFT)); + return true; + } + + /* + * Player spectate + */ + if (base.equals("spectate") || base.equals("spec")) + { + if (!player || !plugin.has(p, "mobarena.use.spectate")) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + List arenas = am.getEnabledArenas(); + if (!am.enabled || arenas.size() < 1) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_NOT_ENABLED)); + return true; + } + + boolean error; + Arena arena; + + if (!arg1.isEmpty()) + arena = am.getArenaWithName(arg1); + else if (arenas.size() == 1) + arena = arenas.get(0); + else + arena = null; + + if (arenas.size() > 1 && arg1.isEmpty()) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARG_NEEDED)); + else if (arena == null) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + //else if (am.arenaMap.containsKey(p) && am.arenaMap.get(p).livePlayers.contains(p)) + else if (am.arenaMap.containsKey(p) && (am.arenaMap.get(p).arenaPlayers.contains(p) || am.arenaMap.get(p).lobbyPlayers.contains(p))) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_IN_OTHER_ARENA)); + else if (!arena.enabled) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_NOT_ENABLED)); + else if (!arena.setup || arena.edit) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_NOT_SETUP)); + //else if (arena.livePlayers.contains(p)) + else if (arena.arenaPlayers.contains(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.SPEC_ALREADY_PLAYING)); + else if (arena.emptyInvSpec && !MAUtils.hasEmptyInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.SPEC_EMPTY_INV)); + else if (arena.joinDistance > 0 && !arena.inRegionRadius(p.getLocation(), arena.joinDistance)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_TOO_FAR)); + else error = false; + + // If there was an error, don't spec. + if (error) + return true; + + // If player is in a boat/minecart, eject! + if (p.isInsideVehicle()) + p.leaveVehicle(); + + am.arenaMap.put(p,arena); + arena.playerSpec(p, p.getLocation()); + + MAUtils.tellPlayer(p, MAMessages.get(Msg.SPEC_PLAYER_SPECTATE)); + return true; + } + + /* + * Prints a list of all arenas. + */ + if (base.equals("arenas")) + { + String list = MAUtils.listToString(am.arenas, plugin); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_LIST_ARENAS, list)); + return true; + } + + /* + * Prints a list of all live players in all arenas, or live players in a specific arena. + */ + if (base.equals("players") || base.equals("list")) + { + if (!arg1.isEmpty()) + { + Arena arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + String list = MAUtils.listToString(arena.getLivingPlayers(), plugin); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_LIST_PLAYERS, list)); + } + else + { + StringBuffer buffy = new StringBuffer(); + List players = new LinkedList(); + for (Arena arena : am.arenas) + players.addAll(arena.getLivingPlayers()); + buffy.append(MAUtils.listToString(players, plugin)); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_LIST_PLAYERS, buffy.toString())); + } + return true; + } + + /* + * Prints a list of all non-ready players in current arena, or non-ready players in a specific arena. + */ + if (base.equals("notready")) + { + Arena arena; + if (!arg1.isEmpty()) + { + arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + } + else if (player) + { + arena = am.getArenaWithPlayer(p); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.LEAVE_NOT_PLAYING)); + return true; + } + } + else + { + MAUtils.tellPlayer(sender, "Usage: /ma notready "); + return true; + } + + String list = MAUtils.listToString(arena.getNonreadyPlayers(), plugin); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_LIST_PLAYERS, list)); + return true; + } + + + + /*//////////////////////////////////////////////////////////////// + // + // Setup & Reload + // + ////////////////////////////////////////////////////////////////*/ + + /* + * Enable or disable arena(s) + */ + if ((base.equals("enable") || base.equals("disable"))) + { + if (!console && !(player && plugin.has(p, "mobarena.admin.enable")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!arg1.isEmpty()) + { + Arena arena = am.getArenaWithName(arg1); + if (arena != null) + { + arena.enabled = base.equals("enable"); + arena.serializeConfig(); + MAUtils.tellPlayer(sender, "Arena '" + arena.configName() + "' " + ((arena.enabled) ? ChatColor.GREEN : ChatColor.RED) + base + "d"); + } + else + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + } + } + else + { + am.enabled = base.equals("enable"); + am.serializeSettings(); + MAUtils.tellPlayer(sender, "All arenas " + ((am.enabled) ? ChatColor.GREEN : ChatColor.RED) + base + "d"); + } + return true; + } + + /* + * Kick player from whichever arena they are in. + */ + if (base.equals("kick")) + { + if (!console && !(player && plugin.has(p, "mobarena.admin.kick")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma kick "); + return true; + } + + Arena arena = am.getArenaWithPlayer(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, "That player is not in an arena."); + return true; + } + else + { + Player pl = server.getPlayer(arg1); + am.arenaMap.remove(pl); + arena.playerLeave(pl); + MAUtils.tellPlayer(sender, "Player '" + arg1 + "' was kicked from arena '" + arena.configName() + "'."); + MAUtils.tellPlayer(pl, "You were kicked by " + ((player) ? p.getName() : "the server.")); + return true; + } + } + + /* + * Restore a player's inventory. + */ + if (base.equals("restore")) + { + if (!console && !(player && plugin.has(p, "mobarena.admin.restore")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!arg1.isEmpty()) + { + if (am.getArenaWithPlayer(arg1) != null) + { + MAUtils.tellPlayer(sender, "Player is currently in an arena."); + return true; + } + + if (MAUtils.restoreInventory(Bukkit.getServer().getPlayer(arg1))); + MAUtils.tellPlayer(sender, "Restored " + arg1 + "'s inventory!"); + return true; + } + } + + /* + * Force start/end arenas. + */ + if (base.equals("force")) + { + if (arg1.equals("end")) + { + if (!console && !(player && plugin.has(p, "mobarena.admin.force.end")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (arg2.isEmpty()) + { + for (Arena arena : am.arenas) + arena.forceEnd(); + + am.arenaMap.clear(); + return true; + } + + Arena arena = am.getArenaWithName(arg2); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + //if (arena.livePlayers.isEmpty()) + if (arena.arenaPlayers.isEmpty()) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_END_EMPTY)); + return true; + } + + arena.forceEnd(); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_END_ENDED)); + return true; + } + else if (arg1.equals("start")) + { + if (!console && !(player && plugin.has(p, "mobarena.admin.force.start")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (arg2.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma force start "); + return true; + } + + Arena arena = am.getArenaWithName(arg2); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + if (arena.running) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_START_RUNNING)); + return true; + } + if (arena.readyPlayers.isEmpty()) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_START_NOT_READY)); + return true; + } + + arena.forceStart(); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_START_STARTED)); + return true; + } + else + { + MAUtils.tellPlayer(sender, "Usage: /ma force [start|end] ()"); + return true; + } + } + + /* + * Reload the config-file. + */ + if (base.equals("config")) + { + if (!console && !(player && plugin.has(p, "mobarena.admin.config.reload")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!arg1.equals("reload")) + { + MAUtils.tellPlayer(sender, "Usage: /ma config reload"); + return true; + } + + am.updateAll(); + MAUtils.tellPlayer(sender, "Config reloaded."); + return true; + } + + /* + * Get the current arena, and list all other arenas. + */ + if (base.equals("arena")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.arena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + MAUtils.tellPlayer(sender, "Currently selected arena: " + ChatColor.GREEN + am.selectedArena.configName()); + + StringBuffer buffy = new StringBuffer(); + if (am.arenas.size() > 1) + { + for (Arena arena : am.arenas) + if (!arena.equals(am.selectedArena)) + buffy.append(arena.configName() + " "); + } + else buffy.append(MAMessages.get(Msg.MISC_NONE)); + + MAUtils.tellPlayer(sender, "Other arenas: " + buffy.toString()); + return true; + } + + /* + * Set the current arena + */ + if (base.equals("setarena")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.setarena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma setarena "); + return true; + } + + Arena arena = am.getArenaWithName(arg1); + if (arena != null) + { + am.selectedArena = arena; + MAUtils.tellPlayer(sender, "Currently selected arena: " + arena.configName()); + } + else + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + } + return true; + } + + /* + * Create a new arena, and set the current arena to this new arena. + */ + if (base.equals("addarena")) + { + if (!(player && plugin.has(p, "mobarena.setup.addarena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma addarena "); + return true; + } + + Arena arena = am.getArenaWithName(arg1); + if (arena != null) + { + MAUtils.tellPlayer(sender, "An arena with that name already exists."); + return true; + } + + arena = am.createArenaNode(arg1, p.getWorld()); + am.arenas.add(arena); + am.selectedArena = arena; + + MAUtils.tellPlayer(sender, "New arena with name '" + arg1 + "' created!"); + return true; + } + + if (base.equals("delarena")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.delarena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma delarena "); + return true; + } + if (am.arenas.size() < 2) + { + MAUtils.tellPlayer(sender, "At least one arena must exist."); + return true; + } + + Arena arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, "There is no arena with that name."); + return true; + } + + am.removeArenaNode(arg1); + am.arenas.remove(arena); + am.selectedArena = (am.selectedArena.equals(arena)) ? am.arenas.get(0) : am.selectedArena; + + MAUtils.tellPlayer(sender, "Arena '" + arena.configName() + "' deleted."); + return true; + } + + /* + * Enable or disable protection + */ + if (base.equals("protect")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.protect")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + Arena arena; + + // No arguments + if (arg1.isEmpty()) + { + arena = am.selectedArena; + arena.protect = !arena.protect; + } + + // One argument + else if (arg2.isEmpty()) + { + // true/false + if (arg1.equals("true") || arg1.equals("false")) + { + arena = am.selectedArena; + arena.protect = arg1.equals("true"); + } + // Arena name + else + { + arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, "There is no arena with that name."); + MAUtils.tellPlayer(sender, "Usage: /ma protect ([true|false])"); + MAUtils.tellPlayer(sender, " or /ma protect ([true|false])"); + return true; + } + arena.protect = !arena.protect; + } + } + + // Two arguments + else + { + if (!(arg2.equals("true") || arg2.equals("false"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma protect ([true|false])"); + MAUtils.tellPlayer(sender, " or /ma protect ([true|false])"); + return true; + } + arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, "There is no arena with that name."); + MAUtils.tellPlayer(sender, "Usage: /ma protect ([true|false])"); + MAUtils.tellPlayer(sender, " or /ma protect ([true|false])"); + return true; + } + arena.protect = arg2.equals("true"); + } + + arena.serializeConfig(); + MAUtils.tellPlayer(sender, "Protection for arena '" + arena.configName() + "': " + ((arena.protect) ? ChatColor.GREEN + "on" : ChatColor.RED + "off")); + return true; + } + + if (base.equals("editarena")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.editarena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + Arena arena; + + // No arguments. + if (arg1.isEmpty()) + { + arena = am.selectedArena; + arena.edit = !arena.edit; + } + + // One argument. + else if (arg2.isEmpty()) + { + // Argument is [true|false] + if (arg1.equals("true") || arg1.equals("false")) + { + arena = am.selectedArena; + arena.edit = arg1.equals("true"); + } + // Argument is + else + { + arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, "There is no arena with that name."); + MAUtils.tellPlayer(sender, "Usage: /ma editarena ([true|false])"); + MAUtils.tellPlayer(sender, " or /ma editarena ([true|false])"); + return true; + } + arena.edit = !arena.edit; + } + } + + // Two arguments + else + { + if (!(arg2.equals("true") || arg2.equals("false"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma editarena ([true|false])"); + MAUtils.tellPlayer(sender, " or /ma editarena ([true|false])"); + return true; + } + arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, "There is no arena with that name."); + MAUtils.tellPlayer(sender, "Usage: /ma editarena ([true|false])"); + MAUtils.tellPlayer(sender, " or /ma editarena ([true|false])"); + return true; + } + arena.edit = arg2.equals("true"); + } + + MAUtils.tellPlayer(sender, "Edit mode for arena '" + arena.configName() + "': " + ((arena.edit) ? ChatColor.GREEN + "true" : ChatColor.RED + "false")); + if (arena.edit) MAUtils.tellPlayer(sender, "Remember to turn it back off after editing!"); + return true; + } + + /* + * Set region points [p1|p2] for the current arena. + */ + if (base.equals("setregion")) + { + if (!(player && plugin.has(p, "mobarena.setup.setregion")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!(arg1.equals("p1") || arg1.equals("p2"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma setregion [p1|p2]"); + return true; + } + + MAUtils.setArenaCoord(plugin.getConfig(), am.selectedArena, arg1, p.getLocation()); + MAUtils.tellPlayer(sender, "Set region point " + arg1 + " for arena '" + am.selectedArena.configName() + "'"); + return true; + } + + /* + * Expand the region (arg1) [up|down|out] + */ + if (base.equals("expandregion")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.expandregion")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (args.length != 3 || !arg1.matches("[0-9]+")) + { + MAUtils.tellPlayer(sender, "Usage: /ma expandregion [up|down|out]"); + return true; + } + if (am.selectedArena.p1 == null || am.selectedArena.p2 == null) + { + MAUtils.tellPlayer(sender, "You must first define p1 and p2"); + return true; + } + + if (arg2.equals("up")) + { + am.selectedArena.p2.setY(Math.min(127, am.selectedArena.p2.getY() + Integer.parseInt(arg1))); + } + else if (arg2.equals("down")) + { + am.selectedArena.p1.setY(Math.max(0, am.selectedArena.p1.getY() - Integer.parseInt(arg1))); + } + else if (arg2.equals("out")) + { + am.selectedArena.p1.setX(am.selectedArena.p1.getX() - Integer.parseInt(arg1)); + am.selectedArena.p1.setZ(am.selectedArena.p1.getZ() - Integer.parseInt(arg1)); + am.selectedArena.p2.setX(am.selectedArena.p2.getX() + Integer.parseInt(arg1)); + am.selectedArena.p2.setZ(am.selectedArena.p2.getZ() + Integer.parseInt(arg1)); + } + else + { + MAUtils.tellPlayer(sender, "Usage: /ma expandregion [up|down|out]"); + return true; + } + + MAUtils.tellPlayer(sender, "Region for '" + am.selectedArena.configName() + "' expanded " + arg2 + " by " + arg1 + " blocks."); + am.selectedArena.serializeConfig(); + am.selectedArena.load(plugin.getConfig()); + return true; + } + + if (base.equals("showregion")) + { + if (!(player && plugin.has(p, "mobarena.setup.showregion")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (am.selectedArena.p1 == null || am.selectedArena.p2 == null) + { + MAUtils.tellPlayer(sender, "The region is not defined for the selected arena."); + return true; + } + if (showingRegion || !am.selectedArena.edit) + { + MAUtils.tellPlayer(sender, "Must be in edit mode."); + return true; + } + + Material mat = Material.WOOL; + byte color = (byte)0; + + if (arg1.equals("glowstone")) + mat = Material.GLOWSTONE; + else if (arg1.equals("white") || arg1.equals("red") || arg1.equals("blue")) + color = DyeColor.valueOf(arg1.toUpperCase()).getData(); + else if (arg1.equals("green")) // Dark green sucks + color = 0x5; + else + mat = Material.GLASS; + + // Set the variable so we don't overwrite the region. + showingRegion = true; + + // Show the frame. + final World world = am.selectedArena.world; + final Set blocks = MAUtils.showRegion(world, am.selectedArena.p1, am.selectedArena.p2, mat.getId(), color); + + // And hide the frame. + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + for (int[] buffer : blocks) + world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeIdAndData(buffer[3], (byte) 0, false); + showingRegion = false; + } + }, 2*20); + + return true; + } + + if (base.equals("setlobbyregion")) + { + if (!(player && plugin.has(p, "mobarena.setup.setlobbyregion")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!(arg1.equals("l1") || arg1.equals("l2"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma setlobbyregion [l1|l2]"); + return true; + } + + MAUtils.setArenaCoord(plugin.getConfig(), am.selectedArena, arg1, p.getLocation()); + MAUtils.tellPlayer(sender, "Set lobby point " + arg1 + " for arena '" + am.selectedArena.configName() + "'"); + return true; + } + + if (base.equals("expandlobbyregion")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.expandlobbyregion")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (args.length != 3 || !arg1.matches("[0-9]+")) + { + MAUtils.tellPlayer(sender, "Usage: /ma expandlobbyregion [up|down|out]"); + return true; + } + if (am.selectedArena.l1 == null || am.selectedArena.l2 == null) + { + MAUtils.tellPlayer(sender, "You must first define l1 and l2"); + return true; + } + + if (arg2.equals("up")) + { + am.selectedArena.l2.setY(Math.min(127, am.selectedArena.l2.getY() + Integer.parseInt(arg1))); + } + else if (arg2.equals("down")) + { + am.selectedArena.l1.setY(Math.max(0, am.selectedArena.l1.getY() - Integer.parseInt(arg1))); + } + else if (arg2.equals("out")) + { + am.selectedArena.l1.setX(am.selectedArena.l1.getX() - Integer.parseInt(arg1)); + am.selectedArena.l1.setZ(am.selectedArena.l1.getZ() - Integer.parseInt(arg1)); + am.selectedArena.l2.setX(am.selectedArena.l2.getX() + Integer.parseInt(arg1)); + am.selectedArena.l2.setZ(am.selectedArena.l2.getZ() + Integer.parseInt(arg1)); + } + else + { + MAUtils.tellPlayer(sender, "Usage: /ma expandlobbyregion [up|down|out]"); + return true; + } + + MAUtils.tellPlayer(sender, "Lobby region for '" + am.selectedArena.configName() + "' expanded " + arg2 + " by " + arg1 + " blocks."); + am.selectedArena.serializeConfig(); + am.selectedArena.load(plugin.getConfig()); + return true; + } + + /* + * Set warp points [arena|lobby|spectator] for the current arena. + */ + if (base.equals("setwarp")) + { + if (!(player && plugin.has(p, "mobarena.setup.setwarp")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (!(arg1.equals("arena") || arg1.equals("lobby") || arg1.equals("spectator"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma setwarp [arena|lobby|spectator]"); + return true; + } + + MAUtils.setArenaCoord(plugin.getConfig(), am.selectedArena, arg1, p.getLocation()); + MAUtils.tellPlayer(sender, "Set warp point " + arg1 + " for arena '" + am.selectedArena.configName() + "'"); + return true; + } + + /* + * List all the current spawnpoints for the current arena. + */ + if (base.equals("spawnpoints")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.spawnpoints")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + StringBuffer buffy = new StringBuffer(); + List spawnpoints = plugin.getConfig().getKeys("arenas." + am.selectedArena.configName() + ".coords.spawnpoints"); + + if (spawnpoints != null) + { + for (String s : spawnpoints) + { + buffy.append(s); + buffy.append(" "); + } + } + else + { + buffy.append(MAMessages.get(Msg.MISC_NONE)); + } + + MAUtils.tellPlayer(sender, "Spawnpoints for arena '" + am.selectedArena.configName() + "': " + buffy.toString()); + return true; + } + + /* + * Add a spawnpoint for the current arena. + */ + if (base.equals("addspawn")) + { + if (!(player && plugin.has(p, "mobarena.setup.addspawn")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1 == null || !arg1.matches("^[a-zA-Z][a-zA-Z0-9]*$")) + { + MAUtils.tellPlayer(sender, "Usage: /ma addspawn "); + return true; + } + + MAUtils.setArenaCoord(plugin.getConfig(), am.selectedArena, "spawnpoints." + arg1, p.getLocation()); + MAUtils.tellPlayer(sender, "Added spawnpoint " + arg1 + " for arena \"" + am.selectedArena.configName() + "\""); + return true; + } + + /* + * Delete a spawnpoint for the current arena. + */ + if (base.equals("delspawn")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.delspawn")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1 == null || !arg1.matches("^[a-zA-Z][a-zA-Z0-9]*$")) + { + MAUtils.tellPlayer(sender, "Usage: /ma delspawn "); + return true; + } + + if (MAUtils.delArenaCoord(plugin.getConfig(), am.selectedArena, "spawnpoints." + arg1)) + MAUtils.tellPlayer(sender, "Deleted spawnpoint " + arg1 + " for arena '" + am.selectedArena.configName() + "'"); + else + MAUtils.tellPlayer(sender, "Could not find the spawnpoint " + arg1 + "for the arena '" + am.selectedArena.configName() + "'"); + return true; + } + + if (base.equals("auto-generate")) + { + if (!(player && plugin.has(p, "mobarena.setup.autogenerate")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1 == null || !arg1.matches("^[a-zA-Z][a-zA-Z0-9]*$")) + { + MAUtils.tellPlayer(sender, "Usage: /ma autogenerate "); + return true; + } + if (am.getArenaWithName(arg1) != null) + { + MAUtils.tellPlayer(sender, "An arena with that name already exists."); + return true; + } + + if (MAUtils.doooooItHippieMonster(p.getLocation(), 13, arg1, plugin)) + MAUtils.tellPlayer(sender, "Arena with name '" + arg1 + "' generated."); + else + MAUtils.tellPlayer(sender, "Could not auto-generate arena."); + return true; + } + + if (base.equals("auto-degenerate")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.autodegenerate")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma auto-degenerate "); + return true; + } + if (am.arenas.size() < 2) + { + MAUtils.tellPlayer(sender, "At least one arena must exist!"); + return true; + } + if (am.getArenaWithName(arg1) == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + if (MAUtils.undoItHippieMonster(arg1, plugin, true)) + MAUtils.tellPlayer(sender, "Arena with name '" + arg1 + "' degenerated."); + else + MAUtils.tellPlayer(sender, "Could not degenerate arena."); + return true; + } + + if (base.equals("dooooo") && arg1.equals("it") && arg2.equals("hippie") && arg3.equals("monster")) + { + if (!(player && plugin.has(p, "mobarena.setup.autogenerate")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + String name = "a0"; + do name = name.substring(0,1) + (Integer.parseInt(name.substring(1,2)) + 1); + while (am.getArenaWithName(name) != null); + + if (MAUtils.doooooItHippieMonster(p.getLocation(), 13, name, plugin)) + MAUtils.tellPlayer(sender, "Arena with name '" + name + "' generated."); + else + MAUtils.tellPlayer(sender, "Could not auto-generate arena."); + return true; + } + + if (base.equals("undo") && arg1.equals("it") && arg2.equals("hippie") && arg3.equals("monster")) + { + if (!(player && plugin.has(p, "mobarena.setup.autodegenerate")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (am.arenas.size() < 2) + { + MAUtils.tellPlayer(sender, "At least one arena must exist!"); + return true; + } + if (am.getArenaWithName("a1") == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + String name = "a1"; + while (am.getArenaWithName(name) != null) + name = name.substring(0,1) + (Integer.parseInt(name.substring(1,2)) + 1); + name = name.substring(0,1) + (Integer.parseInt(name.substring(1,2)) - 1); + + if (MAUtils.undoItHippieMonster(name, plugin, true)) + MAUtils.tellPlayer(sender, "Arena with name '" + name + "' degenerated."); + else + MAUtils.tellPlayer(sender, "Could not degenerate arena."); + return true; + } + + MAUtils.tellPlayer(sender, "Command not found."); + return true; + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAEntityListener.java b/src/com/garbagemule/MobArena/MAEntityListener.java new file mode 100644 index 0000000..d51e118 --- /dev/null +++ b/src/com/garbagemule/MobArena/MAEntityListener.java @@ -0,0 +1,65 @@ +package com.garbagemule.MobArena; + +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityListener; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityTargetEvent; + +import com.garbagemule.MobArena.Arena; +import com.garbagemule.MobArena.ArenaMaster; + +public class MAEntityListener extends EntityListener +{ + private ArenaMaster am; + + public MAEntityListener(ArenaMaster am) + { + this.am = am; + } + + public void onEntityRegainHealth(EntityRegainHealthEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityRegainHealth(event); + } + + public void onEntityDeath(EntityDeathEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityDeath(event); + } + + public void onEntityDamage(EntityDamageEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityDamage(event); + } + + public void onCreatureSpawn(CreatureSpawnEvent event) + { + for (Arena arena : am.arenas) + arena.onCreatureSpawn(event); + } + + public void onEntityExplode(EntityExplodeEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityExplode(event); + } + + public void onEntityCombust(EntityCombustEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityCombust(event); + } + + public void onEntityTarget(EntityTargetEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityTarget(event); + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAInventoryItem.java b/src/com/garbagemule/MobArena/MAInventoryItem.java new file mode 100644 index 0000000..ad33c45 --- /dev/null +++ b/src/com/garbagemule/MobArena/MAInventoryItem.java @@ -0,0 +1,22 @@ +package com.garbagemule.MobArena; + +import java.io.Serializable; + +public class MAInventoryItem implements Serializable +{ + private static final long serialVersionUID = 739709220350581510L; + private int typeId; + private int amount; + private short durability; + + public MAInventoryItem(int typeId, int amount, short durability) + { + this.typeId = typeId; + this.amount = amount; + this.durability = durability; + } + + public int getTypeId() { return typeId; } + public int getAmount() { return amount; } + public short getDurability() { return durability; } +} diff --git a/src/com/garbagemule/MobArena/MAMessages.java b/src/com/garbagemule/MobArena/MAMessages.java new file mode 100644 index 0000000..71e5015 --- /dev/null +++ b/src/com/garbagemule/MobArena/MAMessages.java @@ -0,0 +1,244 @@ +package com.garbagemule.MobArena; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; + +public class MAMessages +{ + protected static Map msgMap; + private static Map defaults = new HashMap(); + protected static enum Msg + { + ARENA_START, + ARENA_END, + ARENA_DOES_NOT_EXIST, + JOIN_PLAYER_JOINED, + JOIN_NOT_ENABLED, + JOIN_IN_OTHER_ARENA, + JOIN_ARENA_NOT_ENABLED, + JOIN_ARENA_NOT_SETUP, + JOIN_ARENA_PERMISSION, + JOIN_FEE_REQUIRED, + JOIN_FEE_PAID, + JOIN_ARENA_IS_RUNNING, + JOIN_ALREADY_PLAYING, + JOIN_ARG_NEEDED, + JOIN_TOO_FAR, + JOIN_EMPTY_INV, + JOIN_PLAYER_LIMIT_REACHED, + JOIN_STORE_INV_FAIL, + LEAVE_PLAYER_LEFT, + LEAVE_NOT_PLAYING, + PLAYER_DIED, + SPEC_PLAYER_SPECTATE, + SPEC_NOT_RUNNING, + SPEC_ARG_NEEDED, + SPEC_EMPTY_INV, + SPEC_ALREADY_PLAYING, + NOT_READY_PLAYERS, + FORCE_START_STARTED, + FORCE_START_RUNNING, + FORCE_START_NOT_READY, + FORCE_END_ENDED, + FORCE_END_EMPTY, + FORCE_END_IDLE, + REWARDS_GIVE, + LOBBY_CLASS_PICKED, + LOBBY_CLASS_RANDOM, + LOBBY_CLASS_PERMISSION, + LOBBY_PLAYER_READY, + LOBBY_DROP_ITEM, + LOBBY_PICK_CLASS, + LOBBY_RIGHT_CLICK, + WARP_TO_ARENA, + WARP_FROM_ARENA, + WAVE_DEFAULT, + WAVE_SPECIAL, + WAVE_REWARD, + MISC_LIST_ARENAS, + MISC_LIST_PLAYERS, + MISC_COMMAND_NOT_ALLOWED, + MISC_NO_ACCESS, + MISC_NONE + } + + // Populate the defaults map. + static + { + defaults.put(Msg.ARENA_START, "Let the slaughter begin!"); + defaults.put(Msg.ARENA_END, "Arena finished."); + defaults.put(Msg.ARENA_DOES_NOT_EXIST, "That arena does not exist. Type /ma arenas for a list."); + defaults.put(Msg.JOIN_NOT_ENABLED, "MobArena is not enabled."); + defaults.put(Msg.JOIN_IN_OTHER_ARENA, "You are already in an arena! Leave that one first."); + defaults.put(Msg.JOIN_ARENA_NOT_ENABLED, "This arena is not enabled."); + defaults.put(Msg.JOIN_ARENA_NOT_SETUP, "This arena has not been set up yet."); + defaults.put(Msg.JOIN_ARENA_PERMISSION, "You don't have permission to join this arena."); + defaults.put(Msg.JOIN_FEE_REQUIRED, "Insufficient funds. Price: %"); + defaults.put(Msg.JOIN_FEE_PAID, "Price to join was: %"); + defaults.put(Msg.JOIN_ARENA_IS_RUNNING, "This arena is in already progress."); + defaults.put(Msg.JOIN_ALREADY_PLAYING, "You are already playing!"); + defaults.put(Msg.JOIN_ARG_NEEDED, "You must specify an arena. Type /ma arenas for a list."); + defaults.put(Msg.JOIN_TOO_FAR, "You are too far away from the arena to join/spectate."); + defaults.put(Msg.JOIN_EMPTY_INV, "You must empty your inventory to join the arena."); + defaults.put(Msg.JOIN_PLAYER_LIMIT_REACHED, "The player limit of this arena has been reached."); + defaults.put(Msg.JOIN_STORE_INV_FAIL, "Failed to store inventory. Try again."); + defaults.put(Msg.JOIN_PLAYER_JOINED, "You joined the arena. Have fun!"); + defaults.put(Msg.LEAVE_NOT_PLAYING, "You are not in the arena."); + defaults.put(Msg.LEAVE_PLAYER_LEFT, "You left the arena. Thanks for playing!"); + defaults.put(Msg.PLAYER_DIED, "% died!"); + defaults.put(Msg.SPEC_PLAYER_SPECTATE, "Enjoy the show!"); + defaults.put(Msg.SPEC_NOT_RUNNING, "This arena isn't running."); + defaults.put(Msg.SPEC_ARG_NEEDED, "You must specify an arena. Type /ma arenas for a list."); + defaults.put(Msg.SPEC_EMPTY_INV, "Empty your inventory first!"); + defaults.put(Msg.SPEC_ALREADY_PLAYING, "Can't spectate when in the arena!"); + defaults.put(Msg.NOT_READY_PLAYERS, "Not ready: %"); + defaults.put(Msg.FORCE_START_RUNNING, "Arena has already started."); + defaults.put(Msg.FORCE_START_NOT_READY, "Can't force start, no players are ready."); + defaults.put(Msg.FORCE_START_STARTED, "Forced arena start."); + defaults.put(Msg.FORCE_END_EMPTY, "No one is in the arena."); + defaults.put(Msg.FORCE_END_ENDED, "Forced arena end."); + defaults.put(Msg.FORCE_END_IDLE, "You weren't quick enough!"); + defaults.put(Msg.REWARDS_GIVE, "Here are all of your rewards!"); + defaults.put(Msg.LOBBY_DROP_ITEM, "No sharing allowed at this time!"); + defaults.put(Msg.LOBBY_PLAYER_READY, "You have been flagged as ready!"); + defaults.put(Msg.LOBBY_PICK_CLASS, "You must first pick a class!"); + defaults.put(Msg.LOBBY_RIGHT_CLICK, "Punch the sign. Don't right-click."); + defaults.put(Msg.LOBBY_CLASS_PICKED, "You have chosen % as your class!"); + defaults.put(Msg.LOBBY_CLASS_RANDOM, "You will get a random class on arena start."); + defaults.put(Msg.LOBBY_CLASS_PERMISSION, "You don't have permission to use this class!"); + defaults.put(Msg.WARP_TO_ARENA, "Can't warp to the arena during battle!"); + defaults.put(Msg.WARP_FROM_ARENA, "Warping not allowed in the arena!"); + defaults.put(Msg.WAVE_DEFAULT, "Get ready for wave #%!"); + defaults.put(Msg.WAVE_SPECIAL, "Get ready for wave #%! [SPECIAL]"); + defaults.put(Msg.WAVE_REWARD, "You just earned a reward: %"); + defaults.put(Msg.MISC_LIST_PLAYERS, "Live players: %"); + defaults.put(Msg.MISC_LIST_ARENAS, "Available arenas: %"); + defaults.put(Msg.MISC_COMMAND_NOT_ALLOWED, "You can't use that command in the arena!"); + defaults.put(Msg.MISC_NO_ACCESS, "You don't have access to this command."); + defaults.put(Msg.MISC_NONE, ""); + } + + /** + * Initializes the msgMap by reading from the announcements-file. + */ + public static void init(MobArena plugin, boolean update) + { + // Use defaults in case of any errors. + msgMap = defaults; + + // Grab the announcements-file. + File msgFile; + try + { + msgFile = new File(plugin.getDataFolder(), "announcements.properties"); + + // If it doesn't exist, create it. + if (!msgFile.exists()) + { + System.out.println("[MobArena] Announcements-file not found. Creating one..."); + msgFile.createNewFile(); + + BufferedWriter bw = new BufferedWriter(new FileWriter(msgFile)); + for (Msg m : Msg.values()) + { + bw.write(m.toString() + "=" + defaults.get(m)); + bw.newLine(); + } + bw.close(); + + return; + } + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR! Couldn't initialize announcements-file. Using defaults."); + return; + } + + // If the file was found, populate the msgMap. + try + { + BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(msgFile), "UTF-8")); + + // Check for BOM character. + br.mark(1); int bom = br.read(); + if (bom != 65279) br.reset(); + + String s; + while ((s = br.readLine()) != null) + process(s); + + br.close(); + } + catch (Exception e) + { + e.printStackTrace(); + System.out.println("[MobArena] ERROR! Problem with announcements-file. Using defaults."); + return; + } + } + + public static void init(MobArena plugin) + { + init(plugin, false); + } + + /** + * Grabs the announcement from the msgMap, and in case of + * s not being null, replaces the % with s. + */ + public static String get(Msg msg, String s) + { + // If p is null, just return the announcement as is. + if (s == null) + return msgMap.get(msg); + + // Otherwise, replace the % with the input string. + return msgMap.get(msg).replace("%", s); + } + + /** + * Grabs the announcement from the msgMap. + */ + public static String get(Msg msg) + { + return get(msg, null); + } + + /** + * Helper-method for parsing the strings from the + * announcements-file. + */ + private static void process(String s) + { + // Split the string by the equals-sign. + String[] split = s.split("="); + if (split.length != 2) + { + System.out.println("[MobArena] ERROR! Couldn't parse \"" + s + "\". Check announcements-file."); + return; + } + + // For simplicity... + String key = split[0]; + String val = split[1]; + Msg msg; + + try + { + msg = Msg.valueOf(key); + msgMap.put(msg, val); + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR! " + key + " is not a valid key. Check announcements-file."); + return; + } + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAPlayerListener.java b/src/com/garbagemule/MobArena/MAPlayerListener.java new file mode 100644 index 0000000..71d9720 --- /dev/null +++ b/src/com/garbagemule/MobArena/MAPlayerListener.java @@ -0,0 +1,87 @@ +package com.garbagemule.MobArena; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerListener; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; + +public class MAPlayerListener extends PlayerListener +{ + private MobArena plugin; + private ArenaMaster am; + + public MAPlayerListener(MobArena plugin, ArenaMaster am) + { + this.plugin = plugin; + this.am = am; + } + + public void onPlayerInteract(PlayerInteractEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerInteract(event); + } + + public void onPlayerDropItem(PlayerDropItemEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerDropItem(event); + } + + public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerBucketEmpty(event); + } + + public void onPlayerTeleport(PlayerTeleportEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerTeleport(event); + } + + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerCommandPreprocess(event); + } + + public void onPlayerQuit(PlayerQuitEvent event) + { + for (Arena arena : am.arenas) + arena.onPlayerQuit(event); + } + + public void onPlayerKick(PlayerKickEvent event) + { + for (Arena arena : am.arenas) + arena.onPlayerKick(event); + } + + public void onPlayerJoin(PlayerJoinEvent event) + { + if (!am.updateNotify || !event.getPlayer().isOp()) return; + + final Player p = event.getPlayer(); + Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + MAUtils.checkForUpdates(plugin, p, false); + } + }, 100); + } +} diff --git a/src/com/garbagemule/MobArena/MASpawnThread.java b/src/com/garbagemule/MobArena/MASpawnThread.java new file mode 100644 index 0000000..1baaba0 --- /dev/null +++ b/src/com/garbagemule/MobArena/MASpawnThread.java @@ -0,0 +1,402 @@ +package com.garbagemule.MobArena; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.entity.Wolf; +import org.bukkit.entity.Ghast; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Creeper; +import org.bukkit.entity.Player; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.CreatureType; +import org.bukkit.inventory.ItemStack; + +import com.garbagemule.MobArena.MAMessages.Msg; + +/** + * Core class for handling wave spawning. + * Currently, every 4th wave is a special wave, and all other waves + * are default waves. The distribution coefficients are used to spread + * out the distribution of each default monster however the server + * host chooses. It is possible to create default waves that consist of + * only one type of monster, or ones that have no creepers, for example. + */ +// TODO: Allow custom special wave monsters. +// TODO: Allow additional "default" waves. +public class MASpawnThread implements Runnable +{ + protected int wave, previousSize, taskId; + private int ran, noOfPlayers, modulo; + private int dZombies, dSkeletons, dSpiders, dCreepers, dWolves; + private int dPoweredCreepers, dPigZombies, dSlimes, dMonsters, dAngryWolves, dGiants, dGhasts; + private Random random; + private MobArena plugin; + private Arena arena; + + public MASpawnThread(MobArena plugin, Arena arena) + { + this.plugin = plugin; + this.arena = arena; + modulo = arena.specialModulo; + if (modulo <= 0) modulo = -32768; + + taskId = -32768; + + //noOfPlayers = arena.livePlayers.size(); + noOfPlayers = arena.arenaPlayers.size(); + wave = 1; + random = new Random(); + + // Set up the distribution variables for the random spawner. + // Note: Updating these means MAUtils.getArenaDistributions() must also be updated! + dZombies = arena.distDefault.get("zombies"); + dSkeletons = dZombies + arena.distDefault.get("skeletons"); + dSpiders = dSkeletons + arena.distDefault.get("spiders"); + dCreepers = dSpiders + arena.distDefault.get("creepers"); + dWolves = dCreepers + arena.distDefault.get("wolves"); + + dPoweredCreepers = arena.distSpecial.get("powered-creepers"); + dPigZombies = dPoweredCreepers + arena.distSpecial.get("zombie-pigmen"); + dSlimes = dPigZombies + arena.distSpecial.get("slimes"); + dMonsters = dSlimes + arena.distSpecial.get("humans"); + dAngryWolves = dMonsters + arena.distSpecial.get("angry-wolves"); + dGiants = dAngryWolves + arena.distSpecial.get("giants"); + dGhasts = dGiants + arena.distSpecial.get("ghasts"); + } + + public void run() + { + List tmp = new LinkedList(arena.monsters); + for (Entity e : tmp) + if (e.isDead()) + arena.monsters.remove(e); + + // Check if wave needs to be cleared first. If so, return! + if (arena.waveClear && wave > 1) + { + if (!arena.monsters.isEmpty()) + return; + } + + // Check if we need to grant more rewards with the recurrent waves. + for (Map.Entry> entry : arena.everyWaveMap.entrySet()) + if (wave % entry.getKey() == 0) + addReward(entry.getValue()); + + // Same deal, this time with the one-time waves. + if (arena.afterWaveMap.containsKey(wave)) + addReward(arena.afterWaveMap.get(wave)); + + // Check if this is a special wave. + if (wave % modulo == 0) + { + MAUtils.tellAll(arena, MAMessages.get(Msg.WAVE_SPECIAL, ""+wave)); + detonateCreepers(arena.detCreepers); + specialWave(); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onSpecialWave(wave, wave/modulo); + } + else + { + MAUtils.tellAll(arena, MAMessages.get(Msg.WAVE_DEFAULT, ""+wave)); + detonateCreepers(arena.detCreepers); + defaultWave(); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onDefaultWave(wave); + } + + wave++; + if (arena.maxIdleTime > 0 && arena.monsters.isEmpty()) arena.resetIdleTimer(); + } + + /** + * Rewards all players with an item from the input String. + */ + private void addReward(List rewards) + { + //for (Player p : arena.livePlayers) + for (Player p : arena.arenaPlayers) + { + if (arena.rewardMap.get(p) == null) + continue; + + ItemStack reward = MAUtils.getRandomReward(rewards); + arena.rewardMap.get(p).add(reward); + + if (reward == null) + { + MAUtils.tellPlayer(p, "ERROR! Problem with economy rewards. Notify server host!"); + System.out.println("[MobArena] ERROR! Could not add null reward. Please check the config-file!"); + } + else if (reward.getTypeId() == MobArena.ECONOMY_MONEY_ID) + { + if (plugin.Methods.hasMethod()) + MAUtils.tellPlayer(p, MAMessages.get(Msg.WAVE_REWARD, plugin.Method.format(reward.getAmount()))); + else System.out.println("[MobArena] ERROR! No economy plugin detected!"); + } + else + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.WAVE_REWARD, MAUtils.toCamelCase(reward.getType().toString()) + ":" + reward.getAmount())); + } + } + } + + /** + * Spawns a default wave of monsters. + */ + private void defaultWave() + { + Location loc; + List spawnpoints = getValidSpawnpoints(); + int noOfSpawnpoints = spawnpoints.size(); + int count = wave + noOfPlayers; + CreatureType mob; + + for (int i = 0; i < count; i++) + { + loc = spawnpoints.get(i % noOfSpawnpoints); + ran = random.nextInt(dWolves); + + /* Because of the nature of the if-elseif-else statement, + * we're able to evaluate the random number in this way. + * If dSpiders = 0, then dSpiders = dSkeletons, which + * means if the random number is below that value, we will + * spawn a skeleton and break out of the statement. */ + if (ran < dZombies) mob = CreatureType.ZOMBIE; + else if (ran < dSkeletons) mob = CreatureType.SKELETON; + else if (ran < dSpiders) mob = CreatureType.SPIDER; + else if (ran < dCreepers) mob = CreatureType.CREEPER; + else if (ran < dWolves) mob = CreatureType.WOLF; + else continue; + + LivingEntity e = arena.world.spawnCreature(loc,mob); + arena.monsters.add(e); + + if (mob == CreatureType.WOLF) + ((Wolf)e).setOwner(null); + + // Grab a random target. + Creature c = (Creature) e; + c.setTarget(getClosestPlayer(e)); + } + } + + /** + * Spawns a special wave of monsters. + */ + private void specialWave() + { + Location loc; + List spawnpoints = getValidSpawnpoints(); + int noOfSpawnpoints = spawnpoints.size(); + CreatureType mob; + ran = random.nextInt(dGhasts); + + int count; + boolean slime = false; + boolean wolf = false; + boolean ghast = false; + boolean creeper = false; + + if (ran < dPoweredCreepers) mob = CreatureType.CREEPER; + else if (ran < dPigZombies) mob = CreatureType.PIG_ZOMBIE; + else if (ran < dSlimes) mob = CreatureType.SLIME; + else if (ran < dMonsters) mob = CreatureType.MONSTER; + else if (ran < dAngryWolves) mob = CreatureType.WOLF; + else if (ran < dGiants) mob = CreatureType.GIANT; + else if (ran < dGhasts) mob = CreatureType.GHAST; + else return; + + switch(mob) + { + case CREEPER: + count = noOfPlayers * 3; + creeper = true; + break; + case PIG_ZOMBIE: + count = noOfPlayers * 2; + break; + case SLIME: + count = noOfPlayers * 4; + slime = true; + break; + case MONSTER: + count = noOfPlayers + 1; + break; + case WOLF: + count = noOfPlayers * 3; + wolf = true; + break; + case GIANT: + count = 1; + break; + case GHAST: + count = 2; + ghast = true; + break; + default: + count = 50; + break; + } + + // Spawn the hippie monsters. + for (int i = 0; i < count; i++) + { + loc = spawnpoints.get(i % noOfSpawnpoints); + + LivingEntity e = arena.world.spawnCreature(loc,mob); + arena.monsters.add(e); + + if (slime) ((Slime)e).setSize(2); + if (wolf) { ((Wolf)e).setAngry(true); ((Wolf)e).setOwner(null); } + if (ghast) ((Ghast)e).setHealth(Math.min(noOfPlayers*25, 200)); + if (creeper) ((Creeper)e).setPowered(true); + + // Slimes can't have targets, apparently. + if (!(e instanceof Creature)) + continue; + + // Grab a random target. + Creature c = (Creature) e; + c.setTarget(getClosestPlayer(e)); + } + + if (!arena.lightning) + return; + + // Lightning, just for effect ;) + for (Location spawn : arena.spawnpoints.values()) + arena.world.strikeLightningEffect(spawn); + } + + /** + * "Detonates" all the Creepers in the monsterSet. + */ + public void detonateCreepers(boolean really) + { + if (!really) + return; + + Set tmp = new HashSet(); + for (Entity e : arena.monsters) + { + if (!(e instanceof Creeper) || e.isDead()) + continue; + + tmp.add(e); + } + + Location loc; + for (Entity e : tmp) + { + arena.monsters.remove(e); + loc = e.getLocation().getBlock().getRelative(0,2,0).getLocation(); + arena.world.createExplosion(loc, 2); + e.remove(); + } + } + + /** + * Get all the spawnpoints that have players nearby. + */ + public List getValidSpawnpoints() + { + List result = new ArrayList(); + + for (Location s : arena.spawnpoints.values()) + { + //for (Player p : arena.livePlayers) + for (Player p : arena.arenaPlayers) + { + if (!arena.world.equals(p.getWorld())) + { + System.out.println("[MobArena] MASpawnThread:291: Player '" + p.getName() + "' is not in the right world. Force leaving..."); + arena.playerLeave(p); + MAUtils.tellPlayer(p, "You warped out of the arena world."); + continue; + } + + if (s.distanceSquared(p.getLocation()) > MobArena.MIN_PLAYER_DISTANCE) + continue; + + result.add(s); + break; + } + } + + // If no players are in range, just use all the spawnpoints. + if (result.isEmpty()) + result.addAll(arena.spawnpoints.values()); + + return result; + } + + /** + * Get the player closest to the input entity. + */ + // TODO: Move this into MAUtils + public Player getClosestPlayer(Entity e) + { + // Set up the comparison variable and the result. + double dist = 0; + double current = Double.POSITIVE_INFINITY; + Player result = null; + + /* Iterate through the ArrayList, and update current and result every + * time a squared distance smaller than current is found. */ + //for (Player p : arena.livePlayers) + for (Player p : arena.arenaPlayers) + { + if (!arena.world.equals(p.getWorld())) + { + System.out.println("[MobArena] MASpawnThread:329: Player '" + p.getName() + "' is not in the right world. Force leaving..."); + arena.playerLeave(p); + MAUtils.tellPlayer(p, "You warped out of the arena world."); + continue; + } + dist = p.getLocation().distanceSquared(e.getLocation()); + if (dist < current && dist < MobArena.MIN_PLAYER_DISTANCE) + { + current = dist; + result = p; + } + } + return result; + } + + /** + * Update the targets of all monsters, if their targets aren't alive. + */ + public void updateTargets() + { + Creature c; + Entity target; + for (Entity e : arena.monsters) + { + if (!(e instanceof Creature)) + continue; + + c = (Creature) e; + target = c.getTarget(); + + //if (target instanceof Player && arena.livePlayers.contains(target)) + if (target instanceof Player && arena.arenaPlayers.contains(target)) + continue; + + c.setTarget(getClosestPlayer(e)); + } + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAUtils.java b/src/com/garbagemule/MobArena/MAUtils.java new file mode 100644 index 0000000..b4b0a7f --- /dev/null +++ b/src/com/garbagemule/MobArena/MAUtils.java @@ -0,0 +1,1400 @@ +package com.garbagemule.MobArena; + +import java.net.URI; +import java.net.HttpURLConnection; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.LinkedList; +import java.util.Map; +import java.util.HashMap; +import java.util.Random; +import java.util.Set; + +import net.minecraft.server.WorldServer; + +import org.bukkit.block.Sign; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.World; +import org.bukkit.Material; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.util.config.Configuration; + +import com.garbagemule.MobArena.MAMessages.Msg; + +public class MAUtils +{ + public static final String sep = File.separator; + // Weapons + public static final List WEAPONS_TYPE = new LinkedList(); + public static final List SWORDS_TYPE = new LinkedList(); + public static final List AXES_TYPE = new LinkedList(); + public static final List PICKAXES_TYPE = new LinkedList(); + public static final List SPADES_TYPE = new LinkedList(); + public static final List HOES_TYPE = new LinkedList(); + // Armor + public static final List ARMORS_TYPE = new LinkedList(); + public static final List HELMETS_TYPE = new LinkedList(); + public static final List CHESTPLATES_TYPE = new LinkedList(); + public static final List LEGGINGS_TYPE = new LinkedList(); + public static final List BOOTS_TYPE = new LinkedList(); + static + { + // Weapons + SWORDS_TYPE.add(Material.WOOD_SWORD); + SWORDS_TYPE.add(Material.STONE_SWORD); + SWORDS_TYPE.add(Material.GOLD_SWORD); + SWORDS_TYPE.add(Material.IRON_SWORD); + SWORDS_TYPE.add(Material.DIAMOND_SWORD); + + AXES_TYPE.add(Material.WOOD_AXE); + AXES_TYPE.add(Material.STONE_AXE); + AXES_TYPE.add(Material.GOLD_AXE); + AXES_TYPE.add(Material.IRON_AXE); + AXES_TYPE.add(Material.DIAMOND_AXE); + + PICKAXES_TYPE.add(Material.WOOD_PICKAXE); + PICKAXES_TYPE.add(Material.STONE_PICKAXE); + PICKAXES_TYPE.add(Material.GOLD_PICKAXE); + PICKAXES_TYPE.add(Material.IRON_PICKAXE); + PICKAXES_TYPE.add(Material.DIAMOND_PICKAXE); + + SPADES_TYPE.add(Material.WOOD_SPADE); + SPADES_TYPE.add(Material.STONE_SPADE); + SPADES_TYPE.add(Material.GOLD_SPADE); + SPADES_TYPE.add(Material.IRON_SPADE); + SPADES_TYPE.add(Material.DIAMOND_SPADE); + + HOES_TYPE.add(Material.WOOD_HOE); + HOES_TYPE.add(Material.STONE_HOE); + HOES_TYPE.add(Material.GOLD_HOE); + HOES_TYPE.add(Material.IRON_HOE); + HOES_TYPE.add(Material.DIAMOND_HOE); + + WEAPONS_TYPE.addAll(SWORDS_TYPE); + WEAPONS_TYPE.addAll(AXES_TYPE); + WEAPONS_TYPE.addAll(PICKAXES_TYPE); + WEAPONS_TYPE.addAll(SPADES_TYPE); + WEAPONS_TYPE.addAll(HOES_TYPE); + + // Armor + HELMETS_TYPE.add(Material.LEATHER_HELMET); + HELMETS_TYPE.add(Material.GOLD_HELMET); + HELMETS_TYPE.add(Material.CHAINMAIL_HELMET); + HELMETS_TYPE.add(Material.IRON_HELMET); + HELMETS_TYPE.add(Material.DIAMOND_HELMET); + HELMETS_TYPE.add(Material.PUMPKIN); + + CHESTPLATES_TYPE.add(Material.LEATHER_CHESTPLATE); + CHESTPLATES_TYPE.add(Material.GOLD_CHESTPLATE); + CHESTPLATES_TYPE.add(Material.CHAINMAIL_CHESTPLATE); + CHESTPLATES_TYPE.add(Material.IRON_CHESTPLATE); + CHESTPLATES_TYPE.add(Material.DIAMOND_CHESTPLATE); + + LEGGINGS_TYPE.add(Material.LEATHER_LEGGINGS); + LEGGINGS_TYPE.add(Material.GOLD_LEGGINGS); + LEGGINGS_TYPE.add(Material.CHAINMAIL_LEGGINGS); + LEGGINGS_TYPE.add(Material.IRON_LEGGINGS); + LEGGINGS_TYPE.add(Material.DIAMOND_LEGGINGS); + + BOOTS_TYPE.add(Material.LEATHER_BOOTS); + BOOTS_TYPE.add(Material.GOLD_BOOTS); + BOOTS_TYPE.add(Material.CHAINMAIL_BOOTS); + BOOTS_TYPE.add(Material.IRON_BOOTS); + BOOTS_TYPE.add(Material.DIAMOND_BOOTS); + + ARMORS_TYPE.addAll(HELMETS_TYPE); + ARMORS_TYPE.addAll(CHESTPLATES_TYPE); + ARMORS_TYPE.addAll(LEGGINGS_TYPE); + ARMORS_TYPE.addAll(BOOTS_TYPE); + } + + + + /* ///////////////////////////////////////////////////////////////////// // + + INITIALIZATION METHODS + + // ///////////////////////////////////////////////////////////////////// */ + + /** + * Grab all the spawnpoints for a specific arena. + */ + public static Map getArenaSpawnpoints(Configuration config, World world, String arena) + { + Map spawnpoints = new HashMap(); + String arenaPath = "arenas." + arena + ".coords.spawnpoints"; + + if (config.getKeys(arenaPath) == null) + return spawnpoints; + + for (String point : config.getKeys(arenaPath)) + spawnpoints.put(point, makeLocation(world, config.getString(arenaPath + "." + point))); + + return spawnpoints; + } + + /** + * Returns a map of classnames mapped to lists of ItemStacks. + */ + public static Map> getClassItems(Configuration config, String type) + { + Map> result = new HashMap>(); + + for (String className : config.getKeys("classes")) + result.put(className, makeItemStackList(config.getString("classes." + className + "." + type))); + + return result; + } + + public static List getEntryFee(Configuration config, String arena) + { + return makeItemStackList(config.getString("arenas." + arena + ".settings.entry-fee", null)); + } + + /** + * Takes a comma-separated list of items in the : format and + * returns a list of ItemStacks created from that data. + */ + public static List makeItemStackList(String string) + { + List result = new LinkedList(); + if (string == null || string.isEmpty()) return result; + + // Trim commas and whitespace, and split items by commas + string = string.trim(); + if (string.endsWith(",")) + string = string.substring(0, string.length()-1); + String[] items = string.split(","); + + for (String item : items) + { + // Trim whitespace and split by colons. + item = item.trim(); + String[] parts = item.split(":"); + + // Grab the amount. + int amount = 1; + if (parts.length == 1 && parts[0].matches("\\$[0-9]+")) + amount = Integer.parseInt(parts[0].substring(1, parts[0].length())); + else if (parts.length == 2 && parts[1].matches("(-)?[0-9]+")) + amount = Integer.parseInt(parts[1]); + else if (parts.length == 3 && parts[2].matches("(-)?[0-9]+")) + amount = Integer.parseInt(parts[2]); + + + // Make the ItemStack. + ItemStack stack = (parts.length == 3) ? + makeItemStack(parts[0], amount, parts[1]) : + makeItemStack(parts[0], amount); + + if (stack != null) + result.add(stack); + } + return result; + } + + /** + * Generates a map of wave numbers and rewards based on the + * type of wave ("after" or "every") and the config-file. If + * no keys exist in the config-file, an empty map is returned. + */ + public static Map> getArenaRewardMap(Configuration config, String arena, String type) + { + String arenaPath = "arenas." + arena + ".rewards.waves."; + Map> result = new HashMap>(); + + if (config.getKeys(arenaPath + type) == null) + { + if (type.equals("every")) + { + config.setProperty(arenaPath + "every.3", "feather, bone, stick"); + config.setProperty(arenaPath + "every.5", "dirt:4, gravel:4, stone:4"); + config.setProperty(arenaPath + "every.10", "iron_ingot:10, gold_ingot:8"); + } + else if (type.equals("after")) + { + config.setProperty(arenaPath + "after.7", "minecart, storage_minecart, powered_minecart"); + config.setProperty(arenaPath + "after.13", "iron_sword, iron_pickaxe, iron_spade"); + config.setProperty(arenaPath + "after.16", "diamond_sword"); + } + } + + List waves = config.getKeys(arenaPath + type); + if (waves == null) return result; + + for (String n : waves) + { + if (!n.matches("[0-9]+")) + continue; + + int wave = Integer.parseInt(n); + String rewards = config.getString(arenaPath + type + "." + n); + + result.put(wave, makeItemStackList(rewards)); + } + return result; + } + + /** + * Grabs the distribution coefficients from the config-file. If + * no coefficients are found, defaults (10) are added. + */ + public static Map getArenaDistributions(Configuration config, String arena, String wave) + { + String arenaPath = "arenas." + arena + ".waves." + wave; + Map result = new HashMap(); + List dists = (config.getKeys(arenaPath) != null) ? config.getKeys(arenaPath) : new LinkedList(); + + String[] monsters = (wave.equals("default")) ? new String[]{"zombies", "skeletons", "spiders", "creepers", "wolves"} + : new String[]{"powered-creepers", "zombie-pigmen", "slimes", "humans", "angry-wolves", "giants", "ghasts"}; + boolean update = false; + for (String monster : monsters) + { + if (dists.contains(monster)) + continue; + + //if (config.getInt(arenaPath + "." + m, -1) == -1) + config.setProperty(arenaPath + "." + monster, (monster.equals("giants") || monster.equals("ghasts")) ? 0 : 10); + update = true; + } + + if (update) + { + config.save(); + dists = config.getKeys(arenaPath); + } + + for (String monster : dists) + { + int value = config.getInt(arenaPath + "." + monster, -1); + + // If no distribution value was found, set one. + if (value == -1) + { + value = 10; + if (monster.equals("giant") || monster.equals("ghast")) + value = 0; + + config.setProperty(arenaPath + "." + monster, value); + } + config.save(); + + result.put(monster, value); + } + return result; + } + + public static List getAllowedCommands(Configuration config) + { + String commands = config.getString("global-settings.allowed-commands"); + if (commands == null) + { + config.setProperty("global-settings.allowed-commands", "/list, /pl"); + config.save(); + commands = config.getString("global-settings.allowed-commands"); + } + + return stringToList(commands); + } + + + + /* ///////////////////////////////////////////////////////////////////// // + + INVENTORY AND REWARD METHODS + + // ///////////////////////////////////////////////////////////////////// */ + + /* Clears the players inventory and armor slots. */ + public static PlayerInventory clearInventory(Player p) + { + PlayerInventory inv = p.getInventory(); + inv.clear(); + inv.setHelmet(null); + inv.setChestplate(null); + inv.setLeggings(null); + inv.setBoots(null); + return inv; + } + + public static boolean storeInventory(Player p) + { + // Grab the contents. + ItemStack[] armor = p.getInventory().getArmorContents(); + ItemStack[] items = p.getInventory().getContents(); + + String invPath = "plugins" + sep + "MobArena" + sep + "inventories"; + new File(invPath).mkdir(); + File backupFile = new File(invPath + sep + p.getName() + ".inv"); + + try + { + if (backupFile.exists() && !restoreInventory(p)) + return false; + + backupFile.createNewFile(); + + MAInventoryItem[] inv = new MAInventoryItem[armor.length + items.length]; + for (int i = 0; i < armor.length; i++) + inv[i] = stackToItem(armor[i]); + for (int i = 0; i < items.length; i++) + inv[armor.length + i] = stackToItem(items[i]); + + FileOutputStream fos = new FileOutputStream(backupFile); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(inv); + oos.close(); + } + catch (Exception e) + { + e.printStackTrace(); + System.out.println("[MobArena] ERROR! Could not create backup file for " + p.getName() + "."); + return false; + } + + clearInventory(p); + return true; + } + + public static boolean restoreInventory(Player p) + { + String invPath = "plugins" + sep + "MobArena" + sep + "inventories"; + File backupFile = new File(invPath + sep + p.getName() + ".inv"); + + try + { + // If the backup-file couldn't be found, return. + if (!backupFile.exists()) + return false; + + // Grab the MAInventoryItem array from the backup-file. + FileInputStream fis = new FileInputStream(backupFile); + ObjectInputStream ois = new ObjectInputStream(fis); + MAInventoryItem[] fromFile = (MAInventoryItem[]) ois.readObject(); + ois.close(); + + // Split that shit. + ItemStack[] armor = new ItemStack[4]; + ItemStack[] items = new ItemStack[fromFile.length-4]; + + for (int i = 0; i < 4; i++) + armor[i] = itemToStack(fromFile[i]); + for (int i = 4; i < fromFile.length; i++) + items[i - 4] = itemToStack(fromFile[i]); + + // Restore the inventory. + PlayerInventory inv = p.getInventory(); + inv.setArmorContents(armor); + for (ItemStack stack : items) + if (stack != null) + inv.addItem(stack); + + // Remove the backup-file. + backupFile.delete(); + } + catch (Exception e) + { + e.printStackTrace(); + System.out.println("[MobArena] ERROR! Could not restore inventory for " + p.getName()); + return false; + } + + return true; + } + + private static MAInventoryItem stackToItem(ItemStack stack) + { + if (stack == null) + return new MAInventoryItem(-1, -1, (short)0); + return new MAInventoryItem(stack.getTypeId(), stack.getAmount(), stack.getDurability()); + } + + private static ItemStack itemToStack(MAInventoryItem item) + { + if (item.getTypeId() == -1) + return null; + return new ItemStack(item.getTypeId(), item.getAmount(), item.getDurability()); + } + + /* Checks if all inventory and armor slots are empty. */ + public static boolean hasEmptyInventory(Player p) + { + ItemStack[] inventory = p.getInventory().getContents(); + ItemStack[] armor = p.getInventory().getArmorContents(); + + // For inventory, check for null + for (ItemStack stack : inventory) + if (stack != null) return false; + + // For armor, check for id 0, or AIR + for (ItemStack stack : armor) + if (stack.getTypeId() != 0) return false; + + return true; + } + + /** + * Gives the player all of the items in the list of ItemStacks. + */ + public static void giveItems(Player p, List stacks, boolean autoEquip, boolean rewards, MobArena plugin) + { + if (stacks == null) + return; + + PlayerInventory inv = p.getInventory(); + for (ItemStack stack : stacks) + { + if (stack == null) + continue; + + // If this is money, don't add to inventory. + if (stack.getTypeId() == MobArena.ECONOMY_MONEY_ID) + { + if (plugin != null && plugin.Methods.hasMethod()) + plugin.Method.getAccount(p.getName()).add(stack.getAmount()); + + continue; + } + + // If these are rewards, don't tamper with them. + if (rewards) + { + inv.addItem(stack); + continue; + } + + // If this is an armor piece, equip it. + if (autoEquip && ARMORS_TYPE.contains(stack.getType())) + { + equipArmorPiece(stack, inv); + continue; + } + + // If this is a weapon, set its durability to "unlimited". + if (WEAPONS_TYPE.contains(stack.getType())) + stack.setDurability((short) -32768); + + inv.addItem(stack); + } + } + public static void giveRewards(Player p, List stacks, MobArena plugin) + { + giveItems(p, stacks, false, true, plugin); + } + + public static void giveItems(Player p, List stacks, boolean autoEquip, MobArena plugin) + { + giveItems(p, stacks, autoEquip, false, plugin); + } + + public static int getPetAmount(Player p) + { + int result = 0; + + for (ItemStack stack : p.getInventory().getContents()) + { + if (stack == null || stack.getTypeId() != 352) + continue; + + result += stack.getAmount(); + } + + return result; + } + + /* Helper method for equipping armor pieces. */ + public static void equipArmorPiece(ItemStack stack, PlayerInventory inv) + { + Material type = stack.getType(); + + if (HELMETS_TYPE.contains(type)) + inv.setHelmet(stack); + else if (CHESTPLATES_TYPE.contains(type)) + inv.setChestplate(stack); + else if (LEGGINGS_TYPE.contains(type)) + inv.setLeggings(stack); + else if (BOOTS_TYPE.contains(type)) + inv.setBoots(stack); + } + + /* Helper methods for making ItemStacks out of strings and ints */ + public static ItemStack makeItemStack(String name, int amount, String data) + { + // If this is economy money, create a dummy ItemStack. + if (name.matches("\\$[0-9]+")) + return new ItemStack(MobArena.ECONOMY_MONEY_ID, amount); + + try + { + byte offset = 0; + + Material material = (name.matches("[0-9]+")) ? + Material.getMaterial(Integer.parseInt(name)) : + Material.valueOf(name.toUpperCase()); + + if (material == Material.INK_SACK) + offset = 15; + + DyeColor dye = (data.matches("[0-9]+")) ? + DyeColor.getByData((byte) Math.abs(offset - Integer.parseInt(data))) : + DyeColor.valueOf(data.toUpperCase()); + + //return new ItemStack(material, amount, (byte) Math.abs((offset - dye.getData()))); + return new ItemStack(material, amount, (byte) Math.abs(offset - dye.getData())); + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR! Could not create item \"" + name + "\". Check config.yml"); + return null; + } + } + public static ItemStack makeItemStack(String name, int amount) + { + return makeItemStack(name, amount, "0"); + } + + /* Helper method for grabbing a random reward */ + public static ItemStack getRandomReward(List rewards) + { + if (rewards.isEmpty()) + return null; + + Random ran = new Random(); + return rewards.get(ran.nextInt(rewards.size())); + } + + + + /* ///////////////////////////////////////////////////////////////////// // + + PET CLASS METHODS + + // ///////////////////////////////////////////////////////////////////// */ + + /** + * Makes all nearby wolves sit if their owner is the given player. + */ + public static void sitPets(Player p) + { + if (p == null) + { + System.out.println("Player is null!"); + return; + } + + List entities = p.getNearbyEntities(80, 40, 80); + for (Entity e : entities) + { + if (!(e instanceof Wolf)) + continue; + + Wolf w = (Wolf) e; + if (w.isTamed() && w.getOwner() != null && w.getOwner().equals(p)) + w.setSitting(true); + } + } + + /** + * Removes all the pets belonging to this player. + *//* + public static void clearPets(Arena arena, Player p) + { + for (Wolf w : arena.pets) + { + if (w.getOwner().equals(p)) + w.remove(); + } + }*/ + + + + /* ///////////////////////////////////////////////////////////////////// // + + REGION METHODS + + // ///////////////////////////////////////////////////////////////////// */ + + /** + * Create a frame spanned by the two input coordinates. + * @return An int arry holding x,y,z and the original type IDs of each block. + */ + public static Set showRegion(World world, Location p1, Location p2, int id, byte color) + { + Set result = new HashSet(); + + int x1 = p1.getBlockX(); int y1 = p1.getBlockY(); int z1 = p1.getBlockZ(); + int x2 = p2.getBlockX(); int y2 = p2.getBlockY(); int z2 = p2.getBlockZ(); + + int[] buffer; + + for (int i = x1; i <= x2; i++) + { + buffer = new int[] {i, y1, z1, world.getBlockTypeIdAt(i, y1, z1)}; + result.add(buffer); + world.getBlockAt(i, y1, z1).setTypeIdAndData(id, color, false); + + buffer = new int[] {i, y2, z1, world.getBlockTypeIdAt(i, y2, z1)}; + result.add(buffer); + world.getBlockAt(i, y2, z1).setTypeIdAndData(id, color, false); + + buffer = new int[] {i, y1, z2, world.getBlockTypeIdAt(i, y1, z2)}; + result.add(buffer); + world.getBlockAt(i, y1, z2).setTypeIdAndData(id, color, false); + + buffer = new int[] {i, y2, z2, world.getBlockTypeIdAt(i, y2, z2)}; + result.add(buffer); + world.getBlockAt(i, y2, z2).setTypeIdAndData(id, color, false); + } + for (int j = y1+1; j <= y2-1; j++) + { + buffer = new int[] {x1, j, z1, world.getBlockTypeIdAt(x1, j, z1)}; + result.add(buffer); + world.getBlockAt(x1, j, z1).setTypeIdAndData(id, color, false); + + buffer = new int[] {x2, j, z1, world.getBlockTypeIdAt(x2, j, z1)}; + result.add(buffer); + world.getBlockAt(x2, j, z1).setTypeIdAndData(id, color, false); + + buffer = new int[] {x1, j, z2, world.getBlockTypeIdAt(x1, j, z2)}; + result.add(buffer); + world.getBlockAt(x1, j, z2).setTypeIdAndData(id, color, false); + + buffer = new int[] {x2, j, z2, world.getBlockTypeIdAt(x2, j, z2)}; + result.add(buffer); + world.getBlockAt(x2, j, z2).setTypeIdAndData(id, color, false); + } + for (int k = z1+1; k <= z2-1; k++) + { + buffer = new int[] {x1, y1, k, world.getBlockTypeIdAt(x1, y1, k)}; + result.add(buffer); + world.getBlockAt(x1, y1, k).setTypeIdAndData(id, color, false); + + buffer = new int[] {x2, y1, k, world.getBlockTypeIdAt(x2, y1, k)}; + result.add(buffer); + world.getBlockAt(x2, y1, k).setTypeIdAndData(id, color, false); + + buffer = new int[] {x1, y2, k, world.getBlockTypeIdAt(x1, y2, k)}; + result.add(buffer); + world.getBlockAt(x1, y2, k).setTypeIdAndData(id, color, false); + + buffer = new int[] {x2, y2, k, world.getBlockTypeIdAt(x2, y2, k)}; + result.add(buffer); + world.getBlockAt(x2, y2, k).setTypeIdAndData(id, color, false); + } + + return result; + } + + public static Set showRegion(World world, Location p1, Location p2, int id) + { + return showRegion(world, p1, p2, id, (byte) 0); + } + + /** + * Take all the blocks with coordinates (buffer[0], buffer[1], buffer[2]) and set + * their type ID to buffer[3]. Used to hide regions shown by showRegion. + */ + public static void hideRegion(int[] buffer) + { + + } + + /** + * Create a Location object from the config-file. + */ + public static Location getArenaCoord(Configuration config, World world, String arena, String coord) + { + //config.load(); + String str = config.getString("arenas." + arena + ".coords." + coord); + if (str == null) + return null; + return makeLocation(world, str); + } + + /** + * Save an arena location to the Configuration. + */ + public static void setArenaCoord(Configuration config, Arena arena, String coord, Location loc) + { + if (coord.equals("arena") || coord.equals("lobby") || coord.equals("spectator")) + loc.setY(loc.getY() + 1); + + config.setProperty("arenas." + arena.configName() + ".coords." + coord, makeCoord(loc)); + config.save(); + arena.load(config); + + if (coord.equals("p1") || coord.equals("p2")) + fixRegion(config, loc.getWorld(), arena); + if (coord.equals("l1") || coord.equals("l2")) + fixLobby(config, loc.getWorld(), arena); + } + + public static boolean delArenaCoord(Configuration config, Arena arena, String coord) + { + if (config.getString("arenas." + arena.configName() + ".coords." + coord) == null) + return false; + + config.removeProperty("arenas." + arena.configName() + ".coords." + coord); + config.save(); + arena.load(config); + return true; + } + + private static void fixRegion(Configuration config, World world, Arena arena) + { + if (arena.p1 == null || arena.p2 == null) + return; + + if (arena.p1.getX() > arena.p2.getX()) + { + double tmp = arena.p1.getX(); + arena.p1.setX(arena.p2.getX()); + arena.p2.setX(tmp); + } + + if (arena.p1.getZ() > arena.p2.getZ()) + { + double tmp = arena.p1.getZ(); + arena.p1.setZ(arena.p2.getZ()); + arena.p2.setZ(tmp); + } + + if (arena.p1.getY() > arena.p2.getY()) + { + double tmp = arena.p1.getY(); + arena.p1.setY(arena.p2.getY()); + arena.p2.setY(tmp); + } + arena.serializeConfig(); + arena.load(config); + } + + private static void fixLobby(Configuration config, World world, Arena arena) + { + if (arena.l1 == null || arena.l2 == null) + return; + + if (arena.l1.getX() > arena.l2.getX()) + { + double tmp = arena.l1.getX(); + arena.l1.setX(arena.l2.getX()); + arena.l2.setX(tmp); + } + + if (arena.l1.getZ() > arena.l2.getZ()) + { + double tmp = arena.l1.getZ(); + arena.l1.setZ(arena.l2.getZ()); + arena.l2.setZ(tmp); + } + + if (arena.l1.getY() > arena.l2.getY()) + { + double tmp = arena.l1.getY(); + arena.l1.setY(arena.l2.getY()); + arena.l2.setY(tmp); + } + arena.serializeConfig(); + arena.load(config); + } + + /** + * Create a Location from the input String in the input World. + */ + public static Location makeLocation(World world, String str, boolean extras) + { + String[] parts = str.split(","); + + double x = Double.parseDouble(parts[0].trim()); + double y = Double.parseDouble(parts[1].trim()); + double z = Double.parseDouble(parts[2].trim()); + + if (extras && parts.length > 3) + { + float yaw = Float.parseFloat(parts[3].trim()); + float pitch = Float.parseFloat(parts[4].trim()); + return new Location(world, x, y, z, yaw, pitch); + } + + return new Location(world, x, y, z); + } + + public static Location makeLocation(World world, String str) + { + return makeLocation(world, str, true); + } + + /** + * Create a location String from the input Location. + */ + public static String makeCoord(Location loc, boolean extras) + { + int x = loc.getBlockX(); + int y = loc.getBlockY(); + int z = loc.getBlockZ(); + + if (extras) + { + float yaw = loc.getYaw(); + float pitch = loc.getPitch(); + return x + "," + y + "," + z + "," + yaw + "," + pitch; + } + + return x + "," + y + "," + z; + } + + public static String makeCoord(Location loc) + { + return makeCoord(loc, true); + } + + /** + * Check if a location is within any arena region. + */ + public static boolean inRegions(Location loc, Arena... arenas) + { + for (Arena arena : arenas) + { + if (arena.inRegion(loc)) + return true; + } + + return false; + } + + + + /* ///////////////////////////////////////////////////////////////////// // + + MISC METHODS + + // ///////////////////////////////////////////////////////////////////// */ + + /** + * Sends a message to a player. + */ + public static boolean tellPlayer(CommandSender p, String msg) + { + if (p == null) + return false; + + p.sendMessage(ChatColor.GREEN + "[MobArena] " + ChatColor.WHITE + msg); + return true; + } + + /** + * Sends a message to all players in and around the arena. + */ + public static void tellAll(Arena arena, String msg) { tellAll(arena, msg, false); } + public static void tellAll(Arena arena, String msg, boolean waitPlayers) + { + Set tmp = new HashSet(); + //tmp.addAll(arena.livePlayers); + tmp.addAll(arena.arenaPlayers); + tmp.addAll(arena.lobbyPlayers); + tmp.addAll(arena.deadPlayers); + tmp.addAll(arena.specPlayers); + tmp.addAll(arena.readyPlayers); + if (waitPlayers) tmp.addAll(arena.waitPlayers); + for (Player p : tmp) + tellPlayer(p, msg); + } + + public static Player getClosestPlayer(Entity e, Arena arena) + { + // Set up the comparison variable and the result. + double current = Double.POSITIVE_INFINITY; + Player result = null; + + /* Iterate through the ArrayList, and update current and result every + * time a squared distance smaller than current is found. */ + //for (Player p : arena.livePlayers) + for (Player p : arena.arenaPlayers) + { + if (!arena.world.equals(p.getWorld())) + { + System.out.println("[MobArena] MAUtils:908: Player '" + p.getName() + "' is not in the right world. Force leaving..."); + arena.playerLeave(p); + tellPlayer(p, "You warped out of the arena world."); + continue; + } + + double dist = p.getLocation().distanceSquared(e.getLocation()); + if (dist < current && dist < 256) + { + current = dist; + result = p; + } + } + return result; + } + + /** + * Convert a proper arena name to a config-file name. + * All spaces are replaced by underscores, and the whole String is + * lowercased. + */ + public static String nameArenaToConfig(String name) + { + String tmp = name.replace(" ", "_"); + return tmp.toLowerCase(); + } + + /** + * Convert a config-name to a proper spaced and capsed arena name. + * The input String is split around all underscores, and every part + * of the String array is properly capsed. + */ + public static String nameConfigToArena(String name) + { + String[] parts = name.split("_"); + if (parts.length == 1) + return toCamelCase(parts[0]); + + String separator = " "; + StringBuffer buffy = new StringBuffer(name.length()); + for (String part : parts) + { + buffy.append(toCamelCase(part)); + buffy.append(separator); + } + buffy.replace(buffy.length()-1, buffy.length(), ""); + + return buffy.toString(); + } + + /** + * Returns the input String with a capital first letter, and all the + * other letters become lower case. + */ + public static String toCamelCase(String name) + { + return name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase(); + } + + /** + * Turn a list into a space-separated string-representation of the list. + */ + public static String listToString(List list, boolean none, MobArena plugin) + { + if (list == null || list.isEmpty()) + { + if (none) + return MAMessages.get(Msg.MISC_NONE); + else + return ""; + } + + StringBuffer buffy = new StringBuffer(); + int trimLength = 0; + + E type = list.get(0); + if (type instanceof Player) + { + for (E e : list) + { + buffy.append(((Player) e).getName()); + buffy.append(" "); + } + } + else if (type instanceof ItemStack) + { + trimLength = 2; + ItemStack stack; + for (E e : list) + { + stack = (ItemStack) e; + if (stack.getTypeId() == MobArena.ECONOMY_MONEY_ID) + { + if (plugin.Methods.hasMethod()) + { + buffy.append(plugin.Method.format(stack.getAmount())); + buffy.append(", "); + } + continue; + } + + buffy.append(stack.getType().toString().toLowerCase()); + buffy.append(":"); + buffy.append(stack.getAmount()); + buffy.append(", "); + } + } + else + { + for (E e : list) + { + buffy.append(e.toString()); + buffy.append(" "); + } + } + return buffy.toString().substring(0, buffy.length() - trimLength); + } + public static String listToString(List list, MobArena plugin) { return listToString(list, true, plugin); } + + /** + * Returns a String-list version of a comma-separated list. + */ + public static List stringToList(String list) + { + List result = new LinkedList(); + if (list == null) return result; + + String[] parts = list.trim().split(","); + + for (String part : parts) + result.add(part.trim()); + + return result; + } + + /** + * Turns the current set of players into an array, and grabs a random + * element out of it. + */ + public static Player getRandomPlayer(Arena arena) + { + Random random = new Random(); + //Player[] array = (Player[]) arena.livePlayers.toArray(); + Player[] array = (Player[]) arena.arenaPlayers.toArray(); + return array[random.nextInt(array.length)]; + } + + /** + * Verifies that all important variables are declared. Returns true + * if, and only if, the warppoints, region, distribution coefficients, + * and spawnpoints are all set up. + */ + public static boolean verifyData(Arena arena) + { + return ((arena.arenaLoc != null) && + (arena.lobbyLoc != null) && + (arena.spectatorLoc != null) && + (arena.p1 != null) && + (arena.p2 != null) && + (arena.spawnpoints.size() > 0)); + } + + public static boolean verifyLobby(Arena arena) + { + return ((arena.l1 != null) && + (arena.l2 != null)); + } + + /** + * Checks if there is a new update of MobArena and notifies the + * player if the boolean specified is true + */ + public static void checkForUpdates(MobArena plugin, final Player p, boolean response) + { + String site = "http://forums.bukkit.org/threads/19144/"; + try + { + // Make a URI of the site address + URI baseURI = new URI(site); + + // Open the connection and don't redirect. + HttpURLConnection con = (HttpURLConnection) baseURI.toURL().openConnection(); + con.setInstanceFollowRedirects(false); + + String header = con.getHeaderField("Location"); + + // If something's wrong with the connection... + if (header == null) + { + tellPlayer(p, "Couldn't connect to the MobArena thread."); + return; + } + + // Otherwise, grab the location header to get the real URI. + String url = new URI(con.getHeaderField("Location")).toString(); + + // If the current version is the same as the thread version. + if (url.contains(plugin.getDescription().getVersion().replace(".", "-"))) + { + if (!response) + return; + + tellPlayer(p, "Your version of MobArena is up to date!"); + return; + } + + // Otherwise, notify the player that there is a new version. + tellPlayer(p, "There is a new version of MobArena available!");; + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public static void setSpawnFlags(MobArena plugin, World world, int spawnMonsters, boolean allowMonsters, boolean allowAnimals) + { + for (Arena arena : plugin.getAM().getArenasInWorld(world)) + if (arena.running) + return; + + WorldServer ws = ((CraftWorld) world).getHandle(); + ws.spawnMonsters = spawnMonsters; + ws.allowMonsters = allowMonsters; + ws.allowAnimals = allowAnimals; + } + + public static String getDuration(long duration) + { + long seconds = duration / 1000; + long secs = seconds % 60; + long mins = (seconds - secs) / 60 % 60; + long hrs = ((seconds - secs) - (mins * 60)) / 60 / 60; + return hrs + ":" + ((mins < 10) ? "0" + mins : mins) + ":" + ((secs < 10) ? "0" + secs : secs); + } + + public static String padRight(String s, int length) { return padRight(s, length, ' '); } + public static String padRight(String s, int length, char pad) + { + StringBuffer buffy = new StringBuffer(); + buffy.append(s); + for (int i = s.length(); i < length; i++) + buffy.append(pad); + return buffy.toString(); + } + + public static String padLeft(String s, int length) { return padLeft(s, length, ' '); } + public static String padLeft(String s, int length, char pad) + { + StringBuffer buffy = new StringBuffer(); + for (int i = 0; i < length - s.length(); i++) + buffy.append(pad); + buffy.append(s); + return buffy.toString(); + } + + + /** + * Stand back, I'm going to try science! + */ + public static boolean doooooItHippieMonster(Location loc, int radius, String name, MobArena plugin) + { + // Try to restore the old patch first. + undoItHippieMonster(name, plugin, false); + + // Grab the Configuration and ArenaMaster + ArenaMaster am = plugin.getAM(); + + // Create the arena node in the config-file. + World world = loc.getWorld(); + Arena arena = am.createArenaNode(name, world); + am.arenas.add(arena); + am.selectedArena = arena; + + // Get the hippie bounds. + int x1 = (int)loc.getX() - radius; + int x2 = (int)loc.getX() + radius; + int y1 = (int)loc.getY() - 9; + int y2 = (int)loc.getY() - 1; + int z1 = (int)loc.getZ() - radius; + int z2 = (int)loc.getZ() + radius; + + int lx1 = x1; + int lx2 = x1 + am.classes.size() + 3; + int ly1 = y1-6; + int ly2 = y1-2; + int lz1 = z1; + int lz2 = z1 + 6; + + // Save the precious patch + HashMap preciousPatch = new HashMap(); + Location lo; + int id; + for (int i = x1; i <= x2; i++) + { + for (int j = ly1; j <= y2; j++) + { + for (int k = z1; k <= z2; k++) + { + lo = world.getBlockAt(i,j,k).getLocation(); + id = world.getBlockAt(i,j,k).getTypeId(); + preciousPatch.put(new EntityPosition(lo),id); + } + } + } + try + { + new File("plugins" + sep + "MobArena" + sep + "agbackup").mkdir(); + FileOutputStream fos = new FileOutputStream("plugins" + sep + "MobArena" + sep + "agbackup" + sep + name + ".tmp"); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(preciousPatch); + oos.close(); + } + catch (Exception e) + { + e.printStackTrace(); + System.out.println("[MobArena] ERROR! Couldn't create backup file. Aborting auto-generate..."); + return false; + } + + // Build some monster walls. + for (int i = x1; i <= x2; i++) + { + for (int j = y1; j <= y2; j++) + { + world.getBlockAt(i,j,z1).setTypeId(24); + world.getBlockAt(i,j,z2).setTypeId(24); + } + } + for (int k = z1; k <= z2; k++) + { + for (int j = y1; j <= y2; j++) + { + world.getBlockAt(x1,j,k).setTypeId(24); + world.getBlockAt(x2,j,k).setTypeId(24); + } + } + + // Add some hippie light. + for (int i = x1; i <= x2; i++) + { + world.getBlockAt(i,y1+2,z1).setTypeId(89); + world.getBlockAt(i,y1+2,z2).setTypeId(89); + } + for (int k = z1; k <= z2; k++) + { + world.getBlockAt(x1,y1+2,k).setTypeId(89); + world.getBlockAt(x2,y1+2,k).setTypeId(89); + } + + // Build a monster floor, and some Obsidian foundation. + for (int i = x1; i <= x2; i++) + { + for (int k = z1; k <= z2; k++) + { + world.getBlockAt(i,y1,k).setTypeId(24); + world.getBlockAt(i,y1-1,k).setTypeId(49); + } + } + + // Make a hippie roof. + for (int i = x1; i <= x2; i++) + { + for (int k = z1; k <= z2; k++) + world.getBlockAt(i,y2,k).setTypeId(20); + } + + // Monster bulldoze + for (int i = x1+1; i < x2; i++) + for (int j = y1+1; j < y2; j++) + for (int k = z1+1; k < z2; k++) + world.getBlockAt(i,j,k).setTypeId(0); + + // Build a hippie lobby + for (int i = lx1; i <= lx2; i++) // Walls + { + for (int j = ly1; j <= ly2; j++) + { + world.getBlockAt(i,j,lz1).setTypeId(24); + world.getBlockAt(i,j,lz2).setTypeId(24); + } + } + for (int k = lz1; k <= lz2; k++) // Walls + { + for (int j = ly1; j <= ly2; j++) + { + world.getBlockAt(lx1,j,k).setTypeId(24); + world.getBlockAt(lx2,j,k).setTypeId(24); + } + } + for (int k = lz1; k <= lz2; k++) // Lights + { + world.getBlockAt(lx1,ly1+2,k).setTypeId(89); + world.getBlockAt(lx2,ly1+2,k).setTypeId(89); + world.getBlockAt(lx1,ly1+3,k).setTypeId(89); + world.getBlockAt(lx2,ly1+3,k).setTypeId(89); + } + for (int i = lx1; i <= lx2; i++) // Floor + { + for (int k = lz1; k <= lz2; k++) + world.getBlockAt(i,ly1,k).setTypeId(24); + } + for (int i = x1+1; i < lx2; i++) // Bulldoze + for (int j = ly1+1; j <= ly2; j++) + for (int k = lz1+1; k < lz2; k++) + world.getBlockAt(i,j,k).setTypeId(0); + + // Place the hippie signs + Iterator iterator = am.classes.iterator(); + for (int i = lx1+2; i <= lx2-2; i++) // Signs + { + world.getBlockAt(i,ly1+1,lz2-1).setTypeIdAndData(63, (byte)0x8, false); + Sign sign = (Sign) world.getBlockAt(i,ly1+1,lz2-1).getState(); + sign.setLine(0, (String)iterator.next()); + } + world.getBlockAt(lx2-2,ly1+1,lz1+2).setType(Material.IRON_BLOCK); + + // Set up the monster points. + MAUtils.setArenaCoord(plugin.getConfig(), arena, "p1", new Location(world, x1, ly1, z1)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "p2", new Location(world, x2, y2+1, z2)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "arena", new Location(world, loc.getX(), y1+1, loc.getZ())); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "lobby", new Location(world, x1+2, ly1+1, z1+2)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spectator", new Location(world, loc.getX(), y2+1, loc.getZ())); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spawnpoints.s1", new Location(world, x1+3, y1+2, z1+3)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spawnpoints.s2", new Location(world, x1+3, y1+2, z2-3)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spawnpoints.s3", new Location(world, x2-3, y1+2, z1+3)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spawnpoints.s4", new Location(world, x2-3, y1+2, z2-3)); + + am.updateAll(); + return true; + } + + /** + * This fixes everything! + */ + @SuppressWarnings("unchecked") + public static boolean undoItHippieMonster(String name, MobArena plugin, boolean error) + { + File file = new File("plugins" + sep + "MobArena" + sep + "agbackup" + sep + name + ".tmp"); + HashMap preciousPatch; + try + { + FileInputStream fis = new FileInputStream(file); + ObjectInputStream ois = new ObjectInputStream(fis); + preciousPatch = (HashMap) ois.readObject(); + ois.close(); + } + catch (Exception e) + { + if (error) System.out.println("[MobArena] ERROR! Couldn't find backup file for arena '" + name + "'"); + return false; + } + + World world = Bukkit.getServer().getWorld(preciousPatch.keySet().iterator().next().getWorld()); + + for (Map.Entry entry : preciousPatch.entrySet()) + { + world.getBlockAt(entry.getKey().getLocation(world)).setTypeId(entry.getValue()); + } + + Configuration config = plugin.getConfig(); + config.removeProperty("arenas." + name); + config.save(); + + file.delete(); + + plugin.getAM().updateAll(); + return true; + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MobArena.java b/src/com/garbagemule/MobArena/MobArena.java new file mode 100644 index 0000000..be9a23d --- /dev/null +++ b/src/com/garbagemule/MobArena/MobArena.java @@ -0,0 +1,276 @@ +package com.garbagemule.MobArena; + +import java.io.File; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.Event.Priority; +import org.bukkit.event.block.BlockListener; +import org.bukkit.event.player.PlayerListener; +import org.bukkit.event.entity.EntityListener; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.util.config.Configuration; + +import com.nijiko.permissions.PermissionHandler; +import com.nijikokun.bukkit.Permissions.Permissions; +import com.garbagemule.register.payment.Method; +import com.garbagemule.register.payment.Methods; + +/** + * MobArena + * @author garbagemule + */ +public class MobArena extends JavaPlugin +{ + private Configuration config; + private ArenaMaster am; + + // Permissions stuff + private PermissionHandler permissionHandler; + + // Economy stuff + protected Methods Methods; + protected Method Method; + + // Global variables + protected static final double MIN_PLAYER_DISTANCE = 256.0; + protected static final int ECONOMY_MONEY_ID = -29; + + public void onEnable() + { + PluginDescriptionFile pdfFile = this.getDescription(); + + // Config, messages and ArenaMaster initialization + loadConfig(); + MAMessages.init(this); + am = new ArenaMaster(this); + am.initialize(); + + // Permissions + setupPermissions(); + + // Economy + Methods = new Methods(); + if (!Methods.hasMethod() && Methods.setMethod(this)) + { + Method = Methods.getMethod(); + System.out.println("[MobArena] Payment method found (" + Method.getName() + " version: " + Method.getVersion() + ")"); + } + + // Bind the /ma, /marena, and /mobarena commands to MACommands. + MACommands commandExecutor = new MACommands(this, am); + getCommand("ma").setExecutor(commandExecutor); + getCommand("marena").setExecutor(commandExecutor); + getCommand("mobarena").setExecutor(commandExecutor); + + // Create event listeners. + PluginManager pm = getServer().getPluginManager(); + PlayerListener playerListener = new MAPlayerListener(this, am); + EntityListener entityListener = new MAEntityListener(am); + BlockListener blockListener = new MABlockListener(am); + + // Register events. + pm.registerEvent(Event.Type.PLAYER_INTERACT, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_DROP_ITEM, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_BUCKET_EMPTY, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_TELEPORT, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_KICK, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_JOIN, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Highest, this); + pm.registerEvent(Event.Type.BLOCK_PLACE, blockListener, Priority.Highest, this); + pm.registerEvent(Event.Type.ENTITY_DAMAGE, entityListener, Priority.High, this); // mcMMO is "Highest" + pm.registerEvent(Event.Type.ENTITY_DEATH, entityListener, Priority.Lowest, this); // Lowest because of Tombstone + pm.registerEvent(Event.Type.ENTITY_REGAIN_HEALTH, entityListener, Priority.Normal, this); + pm.registerEvent(Event.Type.ENTITY_EXPLODE, entityListener, Priority.Highest, this); + pm.registerEvent(Event.Type.ENTITY_COMBUST, entityListener, Priority.Normal, this); + pm.registerEvent(Event.Type.ENTITY_TARGET, entityListener, Priority.Normal, this); + pm.registerEvent(Event.Type.CREATURE_SPAWN, entityListener, Priority.Highest, this); + pm.registerEvent(Event.Type.PLAYER_COMMAND_PREPROCESS, playerListener, Priority.Monitor, this); + + System.out.println("[MobArena] v" + pdfFile.getVersion() + " enabled." ); + } + + public void onDisable() + { + // Force all arenas to end. + for (Arena arena : am.arenas) + arena.forceEnd(); + am.arenaMap.clear(); + + // Permissions & Economy + permissionHandler = null; + if (Methods != null && Methods.hasMethod()) + { + Methods = null; + System.out.println("[MobArena] Payment method was disabled. No longer accepting payments."); + } + + System.out.println("[MobArena] disabled."); + } + + /** + * Load the config-file and initialize the Configuration object. + */ + private void loadConfig() + { + File file = new File(this.getDataFolder(), "config.yml"); + if (!file.exists()) + { + try + { + this.getDataFolder().mkdir(); + file.createNewFile(); + } + catch (Exception e) + { + e.printStackTrace(); + return; + } + } + // TODO: Remove in v1.0 + else + { + Configuration tmp = new Configuration(file); + tmp.load(); + if (tmp.getKeys("global-settings") == null) + { + file.renameTo(new File(this.getDataFolder(), "config_OLD.yml")); + file = new File(this.getDataFolder(), "config.yml"); + try + { + this.getDataFolder().mkdir(); + file.createNewFile(); + } + catch (Exception e) + { + e.printStackTrace(); + return; + } + + config = new Configuration(file); + config.load(); + fixConfig(); + config.setHeader("# MobArena Configuration-file\r\n# Please go to https://github.com/garbagemule/MobArena/wiki/Installing-MobArena for more details."); + config.save(); + } + } + + config = new Configuration(file); + config.load(); + config.setHeader("# MobArena Configuration-file\r\n# Please go to https://github.com/garbagemule/MobArena/wiki/Installing-MobArena for more details."); + config.save(); + } + + // Permissions stuff + public boolean has(Player p, String s) + { + //return (permissionHandler != null && permissionHandler.has(p, s)); + return (permissionHandler == null || permissionHandler.has(p, s)); + } + + public boolean hasDefTrue(Player p, String s) + { + return (permissionHandler == null || permissionHandler.has(p, s)); + } + + private void setupPermissions() + { + if (permissionHandler != null) + return; + + Plugin permissionsPlugin = this.getServer().getPluginManager().getPlugin("Permissions"); + if (permissionsPlugin == null) return; + + permissionHandler = ((Permissions) permissionsPlugin).getHandler(); + } + + public Configuration getConfig() { return config; } + public ArenaMaster getAM() { return am; } // More convenient. + public ArenaMaster getArenaMaster() { return am; } + + // TODO: Remove in v1.0 + private void fixConfig() + { + // If global-settings is sorted, don't do anything. + if (config.getKeys("global-settings") != null) + return; + + File oldFile = new File(this.getDataFolder(), "config_OLD.yml"); + if (!oldFile.exists()) + return; + + System.out.println("[MobArena] Config-file appears to be old. Trying to fix it..."); + + Configuration oldConfig = new Configuration(oldFile); + oldConfig.load(); + + config.setProperty("global-settings.enabled", true); + config.save(); + config.load(); + config.setProperty("global-settings.update-notification", true); + config.save(); + config.load(); + + // Copy classes + for (String s : oldConfig.getKeys("classes")) + { + config.setProperty("classes." + s + ".items", oldConfig.getString("classes." + s + ".items")); + config.setProperty("classes." + s + ".armor", oldConfig.getString("classes." + s + ".armor")); + } + config.save(); + + // Make the default arena node. + config.setProperty("arenas.default.settings.enabled", true); + config.save(); + config.load(); + config.setProperty("arenas.default.settings.world", oldConfig.getString("settings.world")); + config.save(); + config.load(); + + // Copy the coords. + for (String s : oldConfig.getKeys("coords")) + { + if (s.equals("spawnpoints")) + continue; + + StringBuffer buffy = new StringBuffer(); + buffy.append(oldConfig.getString("coords." + s + ".x")); + buffy.append(","); + buffy.append(oldConfig.getString("coords." + s + ".y")); + buffy.append(","); + buffy.append(oldConfig.getString("coords." + s + ".z")); + buffy.append(","); + buffy.append(oldConfig.getString("coords." + s + ".yaw")); + buffy.append(","); + buffy.append(oldConfig.getString("coords." + s + ".pitch")); + + config.setProperty("arenas.default.coords." + s, buffy.toString()); + } + config.save(); + config.load(); + + for (String s : oldConfig.getKeys("coords.spawnpoints")) + { + StringBuffer buffy = new StringBuffer(); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".x")); + buffy.append(","); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".y")); + buffy.append(","); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".z")); + buffy.append(","); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".yaw")); + buffy.append(","); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".pitch")); + + config.setProperty("arenas.default.coords.spawnpoints." + s, buffy.toString()); + } + config.save(); + config.load(); + + System.out.println("[MobArena] Updated the config-file!"); + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MobArenaHandler.java b/src/com/garbagemule/MobArena/MobArenaHandler.java new file mode 100644 index 0000000..e399183 --- /dev/null +++ b/src/com/garbagemule/MobArena/MobArenaHandler.java @@ -0,0 +1,126 @@ +package com.garbagemule.MobArena; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +public class MobArenaHandler +{ + MobArena plugin; + boolean ma = false; + + /** + * Primary constructor. + * The boolean 'ma' is flagged true, and the field 'plugin' is initalized, if the server is running MobArena. + */ + public MobArenaHandler() + { + Plugin maPlugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); + + if (maPlugin == null) + return; + + ma = true; + plugin = (MobArena) maPlugin; + } + + /** + * Check if a Location is inside of an arena region. + * @param loc A location. + * @return true, if the Location is inside of any arena region. + */ + public boolean inRegion(Location loc) + { + // If the plugin doesn't exist, always return false. + if (!ma || plugin.getAM() == null) return false; + + // Return true if location is within just one arena's region. + for (Arena arena : plugin.getAM().arenas) + if (arena.inRegion(loc)) + return true; + + return false; + } + + /** + * Check if a Location is inside of a specific arena region. + * @param arena An Arena object + * @param loc A location + * @return true, if the Location is inside of the arena region. + */ + public boolean inRegion(Arena arena, Location loc) { return (ma && arena != null && arena.inRegion(loc)); } + + /** + * Check if a Location is inside of the region of an arena that is currently running. + * @param loc A location. + * @return true, if the Location is inside of the region of an arena that is currently running. + */ + public boolean inRunningRegion(Location loc) { return inRegion(loc, false, true); } + + /** + * Check if a Location is inside of the region of an arena that is currently enabled. + * @param loc A location. + * @return true, if the Location is inside of the region of an arena that is currently enabled. + */ + public boolean inEnabledRegion(Location loc) { return inRegion(loc, true, false); } + + /** + * Private helper method for inRunningRegion and inEnabledRegion + * @param loc A location + * @param enabled if true, the method will check if the arena is enabled + * @param running if true, the method will check if the arena is running, overrides enabled + * @return true, if the location is inside of the region of an arena that is currently enabled/running, depending on the parameters. + */ + private boolean inRegion(Location loc, boolean enabled, boolean running) + { + // If the plugin doesn't exist, always return false. + if (!ma || plugin.getAM() == null) return false; + + // Return true if location is within just one arena's region. + for (Arena arena : plugin.getAM().arenas) + if (arena.inRegion(loc)) + if ((running && arena.running) || (enabled && arena.enabled)) + return true; + + return false; + } + + /** + * Get an Arena object at the given location. + * @param loc A location + * @return an Arena object, or null + */ + public Arena getArenaAtLocation(Location loc) { return (ma) ? plugin.getAM().getArenaAtLocation(loc) : null; } + + /** + * Get the Arena object that the given player is currently in. + * @param p A player + * @return an Arena object, or null + */ + public Arena getArenaWithPlayer(Player p) { return (ma) ? plugin.getAM().getArenaWithPlayer(p) : null; } + + /** + * Get the Arena object that the given pet is currently in. + * @param wolf A pet wolf + * @return an Arena object, or null + */ + public Arena getArenaWithPet(Entity wolf) { return (ma) ? plugin.getAM().getArenaWithPet(wolf) : null; } + + /** + * Get the Arena object that the given monster is currently in. + * @param monster A monster + * @return an Arena object, or null + */ + public Arena getArenaWithMonster(Entity monster) { return (ma) ? plugin.getAM().getArenaWithMonster(monster) : null; } + + /** + * Check if the server is running MobArena. + * @return true, if MobArena exists on the server. + */ + public boolean hasMA() + { + return ma; + } +} diff --git a/src/com/garbagemule/MobArena/MobArenaListener.java b/src/com/garbagemule/MobArena/MobArenaListener.java new file mode 100644 index 0000000..1613774 --- /dev/null +++ b/src/com/garbagemule/MobArena/MobArenaListener.java @@ -0,0 +1,23 @@ +package com.garbagemule.MobArena; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public class MobArenaListener +{ + protected MobArena plugin; + + public MobArenaListener() + { + plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); + plugin.getAM().listeners.add(this); + } + + public void onArenaStart() {} + public void onArenaEnd() {} + public void onDefaultWave(int waveNumber) {} + public void onSpecialWave(int waveNumber, int specialwaveNumber) {} + public void onPlayerJoin(Player p) {} + public void onPlayerLeave(Player p) {} + public void onPlayerDeath(Player p) {} +} diff --git a/src/com/garbagemule/register/payment/Method.java b/src/com/garbagemule/register/payment/Method.java new file mode 100644 index 0000000..921b9cf --- /dev/null +++ b/src/com/garbagemule/register/payment/Method.java @@ -0,0 +1,62 @@ +package com.garbagemule.register.payment; + +import org.bukkit.plugin.Plugin; + +/** + * Method.java + * Interface for all sub-methods for payment. + * + * @author: Nijikokun (@nijikokun) + * @copyright: Copyright (C) 2011 + * @license: GNUv3 Affero License + */ +public interface Method { + public Object getPlugin(); + public String getName(); + public String getVersion(); + public String format(double amount); + public boolean hasBanks(); + public boolean hasBank(String bank); + public boolean hasAccount(String name); + public boolean hasBankAccount(String bank, String name); + public MethodAccount getAccount(String name); + public MethodBankAccount getBankAccount(String bank, String name); + public boolean isCompatible(Plugin plugin); + public void setPlugin(Plugin plugin); + + public interface MethodAccount { + public double balance(); + public boolean set(double amount); + public boolean add(double amount); + public boolean subtract(double amount); + public boolean multiply(double amount); + public boolean divide(double amount); + public boolean hasEnough(double amount); + public boolean hasOver(double amount); + public boolean hasUnder(double amount); + public boolean isNegative(); + public boolean remove(); + + @Override + public String toString(); + } + + public interface MethodBankAccount { + public double balance(); + public String getBankName(); + public int getBankId(); + public boolean set(double amount); + public boolean add(double amount); + public boolean subtract(double amount); + public boolean multiply(double amount); + public boolean divide(double amount); + public boolean hasEnough(double amount); + public boolean hasOver(double amount); + public boolean hasUnder(double amount); + public boolean isNegative(); + public boolean remove(); + + @Override + public String toString(); + } +} diff --git a/src/com/garbagemule/register/payment/Methods.java b/src/com/garbagemule/register/payment/Methods.java new file mode 100644 index 0000000..a8eb99f --- /dev/null +++ b/src/com/garbagemule/register/payment/Methods.java @@ -0,0 +1,141 @@ +package com.garbagemule.register.payment; + +import com.garbagemule.register.payment.methods.BOSE6; +import com.garbagemule.register.payment.methods.BOSE7; + +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; + +import java.util.HashSet; +import java.util.Set; + +/** + * Methods.java + * Controls the getting / setting of methods & the method of payment used. + * + * @author: Nijikokun (@nijikokun) + * @copyright: Copyright (C) 2011 + * @license: GNUv3 Affero License + */ +public class Methods { + private boolean self = false; + private Method Method = null; + private String preferred = ""; + private Set Methods = new HashSet(); + private Set Dependencies = new HashSet(); + private Set Attachables = new HashSet(); + + public Methods() { + this._init(); + } + + /** + * Allows you to set which economy plugin is most preferred. + * + * @param preferred - preferred economy plugin + */ + public Methods(String preferred) { + this._init(); + + if(this.Dependencies.contains(preferred)) { + this.preferred = preferred; + } + } + + private void _init() { + this.addMethod("iConomy", new com.garbagemule.register.payment.methods.iCo4()); + this.addMethod("iConomy", new com.garbagemule.register.payment.methods.iCo5()); + this.addMethod("BOSEconomy", new BOSE6()); + this.addMethod("BOSEconomy", new BOSE7()); + this.addMethod("Essentials", new com.garbagemule.register.payment.methods.EE17()); + } + + public Set getDependencies() { + return Dependencies; + } + + public Method createMethod(Plugin plugin) { + for (Method method: Methods) { + if (method.isCompatible(plugin)) { + method.setPlugin(plugin); + return method; + } + } + + return null; + } + + private void addMethod(String name, Method method) { + Dependencies.add(name); + Methods.add(method); + } + + public boolean hasMethod() { + return (Method != null); + } + + public boolean setMethod(Plugin method) { + if(hasMethod()) return true; + if(self) { self = false; return false; } + + int count = 0; + boolean match = false; + Plugin plugin; + PluginManager manager = method.getServer().getPluginManager(); + + for(String name: this.getDependencies()) { + if(hasMethod()) break; + if(method.getDescription().getName().equals(name)) plugin = method; else plugin = manager.getPlugin(name); + if(plugin == null) continue; + + Method current = this.createMethod(plugin); + if(current == null) continue; + + if(this.preferred.isEmpty()) + this.Method = current; + else { + this.Attachables.add(current); + } + } + + if(!this.preferred.isEmpty()) { + do { + if(hasMethod()) { + match = true; + } else { + for(Method attached: this.Attachables) { + if(attached == null) continue; + + if(hasMethod()) { + match = true; + break; + } + + if(this.preferred.isEmpty()) this.Method = attached; + + if(count == 0) { + if(this.preferred.equalsIgnoreCase(attached.getName())) + this.Method = attached; + } else { + this.Method = attached; + } + } + + count++; + } + } while(!match); + } + + return hasMethod(); + } + + public Method getMethod() { + return Method; + } + + public boolean checkDisabled(Plugin method) { + if(!hasMethod()) return true; + if (Method.isCompatible(method)) Method = null; + return (Method == null); + } +} diff --git a/src/com/garbagemule/register/payment/methods/BOSE.java b/src/com/garbagemule/register/payment/methods/BOSE.java new file mode 100644 index 0000000..1b73443 --- /dev/null +++ b/src/com/garbagemule/register/payment/methods/BOSE.java @@ -0,0 +1,196 @@ +package com.garbagemule.register.payment.methods; + +import com.garbagemule.register.payment.Method; + +import cosine.boseconomy.BOSEconomy; +import org.bukkit.plugin.Plugin; + +public class BOSE implements Method { + private BOSEconomy BOSEconomy; + + public BOSEconomy getPlugin() { + return this.BOSEconomy; + } + + public String getName() { + return "BOSEconomy"; + } + + public String getVersion() { + return "0.6.2"; + } + + public String format(double amount) { + String currency = this.BOSEconomy.getMoneyNamePlural(); + if(amount == 1) currency = this.BOSEconomy.getMoneyName(); + return amount + " " + currency; + } + + public boolean hasBanks() { + return true; + } + + public boolean hasBank(String bank) { + return this.BOSEconomy.bankExists(bank); + } + + public boolean hasAccount(String name) { + return this.BOSEconomy.playerRegistered(name, false); + } + + public boolean hasBankAccount(String bank, String name) { + return this.BOSEconomy.isBankOwner(bank, name); + } + + public MethodAccount getAccount(String name) { + if(!hasAccount(name)) return null; + return new BOSEAccount(name, this.BOSEconomy); + } + + public MethodBankAccount getBankAccount(String bank, String name) { + return new BOSEBankAccount(bank, name, BOSEconomy); + } + + public boolean isCompatible(Plugin plugin) { + return plugin.getDescription().getName().equalsIgnoreCase("boseconomy") && plugin instanceof BOSEconomy; + } + + public void setPlugin(Plugin plugin) { + BOSEconomy = (BOSEconomy)plugin; + } + + public class BOSEAccount implements MethodAccount { + private String name; + private BOSEconomy BOSEconomy; + + public BOSEAccount(String name, BOSEconomy bOSEconomy) { + this.name = name; + this.BOSEconomy = bOSEconomy; + } + + public double balance() { + return Double.valueOf(this.BOSEconomy.getPlayerMoney(this.name)); + } + + public boolean set(double amount) { + int IntAmount = (int)Math.ceil(amount); + return this.BOSEconomy.setPlayerMoney(this.name, IntAmount, false); + } + + public boolean add(double amount) { + int IntAmount = (int)Math.ceil(amount); + return this.BOSEconomy.addPlayerMoney(this.name, IntAmount, false); + } + + public boolean subtract(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance - IntAmount), false); + } + + public boolean multiply(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance * IntAmount), false); + } + + public boolean divide(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance / IntAmount), false); + } + + public boolean hasEnough(double amount) { + return (this.balance() >= amount); + } + + public boolean hasOver(double amount) { + return (this.balance() > amount); + } + + public boolean hasUnder(double amount) { + return (this.balance() < amount); + } + + public boolean isNegative() { + return (this.balance() < 0); + } + + public boolean remove() { + return false; + } + } + + public class BOSEBankAccount implements MethodBankAccount { + private String bank; + private String name; + private BOSEconomy BOSEconomy; + + public BOSEBankAccount(String bank, String name, BOSEconomy bOSEconomy) { + this.name = name; + this.bank = bank; + this.BOSEconomy = bOSEconomy; + } + + public String getBankName() { + return this.bank; + } + + public int getBankId() { + return -1; + } + + public double balance() { + return Double.valueOf(this.BOSEconomy.getBankMoney(name)); + } + + public boolean set(double amount) { + int IntAmount = (int)Math.ceil(amount); + return this.BOSEconomy.setBankMoney(name, IntAmount, true); + } + + public boolean add(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setBankMoney(this.name, (balance + IntAmount), false); + } + + public boolean subtract(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setBankMoney(this.name, (balance - IntAmount), false); + } + + public boolean multiply(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setBankMoney(this.name, (balance * IntAmount), false); + } + + public boolean divide(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setBankMoney(this.name, (balance / IntAmount), false); + } + + public boolean hasEnough(double amount) { + return (this.balance() >= amount); + } + + public boolean hasOver(double amount) { + return (this.balance() > amount); + } + + public boolean hasUnder(double amount) { + return (this.balance() < amount); + } + + public boolean isNegative() { + return (this.balance() < 0); + } + + public boolean remove() { + return this.BOSEconomy.removeBank(bank); + } + } +} \ No newline at end of file diff --git a/src/com/garbagemule/register/payment/methods/BOSE6.java b/src/com/garbagemule/register/payment/methods/BOSE6.java new file mode 100644 index 0000000..3ca97f6 --- /dev/null +++ b/src/com/garbagemule/register/payment/methods/BOSE6.java @@ -0,0 +1,195 @@ +package com.garbagemule.register.payment.methods; + +import com.garbagemule.register.payment.Method; + +import cosine.boseconomy.BOSEconomy; +import org.bukkit.plugin.Plugin; + +public class BOSE6 implements Method { + private BOSEconomy BOSEconomy; + + public BOSEconomy getPlugin() { + return this.BOSEconomy; + } + + public String getName() { + return "BOSEconomy"; + } + + public String getVersion() { + return "0.6.2"; + } + + public String format(double amount) { + String currency = this.BOSEconomy.getMoneyNamePlural(); + if(amount == 1) currency = this.BOSEconomy.getMoneyName(); + return amount + " " + currency; + } + + public boolean hasBanks() { + return true; + } + + public boolean hasBank(String bank) { + return this.BOSEconomy.bankExists(bank); + } + + public boolean hasAccount(String name) { + return this.BOSEconomy.playerRegistered(name, false); + } + + public boolean hasBankAccount(String bank, String name) { + return this.BOSEconomy.isBankOwner(bank, name) || this.BOSEconomy.isBankMember(bank, name); + } + + public MethodAccount getAccount(String name) { + if(!hasAccount(name)) return null; + return new BOSEAccount(name, this.BOSEconomy); + } + + public MethodBankAccount getBankAccount(String bank, String name) { + if(!hasBankAccount(bank, name)) return null; + return new BOSEBankAccount(bank, BOSEconomy); + } + + public boolean isCompatible(Plugin plugin) { + return plugin.getDescription().getName().equalsIgnoreCase("boseconomy") && plugin instanceof BOSEconomy && plugin.getDescription().getVersion().equals("0.6.2"); + } + + public void setPlugin(Plugin plugin) { + BOSEconomy = (BOSEconomy)plugin; + } + + public class BOSEAccount implements MethodAccount { + private String name; + private BOSEconomy BOSEconomy; + + public BOSEAccount(String name, BOSEconomy bOSEconomy) { + this.name = name; + this.BOSEconomy = bOSEconomy; + } + + public double balance() { + return Double.valueOf(this.BOSEconomy.getPlayerMoney(this.name)); + } + + public boolean set(double amount) { + int IntAmount = (int)Math.ceil(amount); + return this.BOSEconomy.setPlayerMoney(this.name, IntAmount, false); + } + + public boolean add(double amount) { + int IntAmount = (int)Math.ceil(amount); + return this.BOSEconomy.addPlayerMoney(this.name, IntAmount, false); + } + + public boolean subtract(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance - IntAmount), false); + } + + public boolean multiply(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance * IntAmount), false); + } + + public boolean divide(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance / IntAmount), false); + } + + public boolean hasEnough(double amount) { + return (this.balance() >= amount); + } + + public boolean hasOver(double amount) { + return (this.balance() > amount); + } + + public boolean hasUnder(double amount) { + return (this.balance() < amount); + } + + public boolean isNegative() { + return (this.balance() < 0); + } + + public boolean remove() { + return false; + } + } + + public class BOSEBankAccount implements MethodBankAccount { + private String bank; + private BOSEconomy BOSEconomy; + + public BOSEBankAccount(String bank, BOSEconomy bOSEconomy) { + this.bank = bank; + this.BOSEconomy = bOSEconomy; + } + + public String getBankName() { + return this.bank; + } + + public int getBankId() { + return -1; + } + + public double balance() { + return Double.valueOf(this.BOSEconomy.getBankMoney(bank)); + } + + public boolean set(double amount) { + int IntAmount = (int)Math.ceil(amount); + return this.BOSEconomy.setBankMoney(bank, IntAmount, true); + } + + public boolean add(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance + IntAmount), false); + } + + public boolean subtract(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance - IntAmount), false); + } + + public boolean multiply(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance * IntAmount), false); + } + + public boolean divide(double amount) { + int IntAmount = (int)Math.ceil(amount); + int balance = (int)this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance / IntAmount), false); + } + + public boolean hasEnough(double amount) { + return (this.balance() >= amount); + } + + public boolean hasOver(double amount) { + return (this.balance() > amount); + } + + public boolean hasUnder(double amount) { + return (this.balance() < amount); + } + + public boolean isNegative() { + return (this.balance() < 0); + } + + public boolean remove() { + return this.BOSEconomy.removeBank(bank); + } + } +} \ No newline at end of file diff --git a/src/com/garbagemule/register/payment/methods/BOSE7.java b/src/com/garbagemule/register/payment/methods/BOSE7.java new file mode 100644 index 0000000..18e98fa --- /dev/null +++ b/src/com/garbagemule/register/payment/methods/BOSE7.java @@ -0,0 +1,189 @@ +package com.garbagemule.register.payment.methods; + +import com.garbagemule.register.payment.Method; + +import cosine.boseconomy.BOSEconomy; +import org.bukkit.plugin.Plugin; + +/** + * @author Acrobot + */ + +public class BOSE7 implements Method { + private BOSEconomy BOSEconomy; + + public BOSEconomy getPlugin() { + return this.BOSEconomy; + } + + public String getName() { + return "BOSEconomy"; + } + + public String getVersion() { + return "0.7.0"; + } + + public String format(double amount) { + String currency = this.BOSEconomy.getMoneyNamePlural(); + if(amount == 1) currency = this.BOSEconomy.getMoneyName(); + return amount + " " + currency; + } + + public boolean hasBanks() { + return true; + } + + public boolean hasBank(String bank) { + return this.BOSEconomy.bankExists(bank); + } + + public boolean hasAccount(String name) { + return this.BOSEconomy.playerRegistered(name, false); + } + + public boolean hasBankAccount(String bank, String name) { + return this.BOSEconomy.isBankOwner(bank, name) || this.BOSEconomy.isBankMember(bank, name); + } + + public MethodAccount getAccount(String name) { + if(!hasAccount(name)) return null; + return new BOSEAccount(name, this.BOSEconomy); + } + + public MethodBankAccount getBankAccount(String bank, String name) { + if(!hasBankAccount(bank, name)) return null; + return new BOSEBankAccount(bank, BOSEconomy); + } + + public boolean isCompatible(Plugin plugin) { + return plugin.getDescription().getName().equalsIgnoreCase("boseconomy") && plugin instanceof BOSEconomy && !plugin.getDescription().getVersion().equals("0.6.2"); + } + + public void setPlugin(Plugin plugin) { + BOSEconomy = (BOSEconomy)plugin; + } + + public class BOSEAccount implements MethodAccount { + private String name; + private BOSEconomy BOSEconomy; + + public BOSEAccount(String name, BOSEconomy bOSEconomy) { + this.name = name; + this.BOSEconomy = bOSEconomy; + } + + public double balance() { + return this.BOSEconomy.getPlayerMoneyDouble(this.name); + } + + public boolean set(double amount) { + return this.BOSEconomy.setPlayerMoney(this.name, amount, false); + } + + public boolean add(double amount) { + return this.BOSEconomy.addPlayerMoney(this.name, amount, false); + } + + public boolean subtract(double amount) { + double balance = this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance - amount), false); + } + + public boolean multiply(double amount) { + double balance = this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance * amount), false); + } + + public boolean divide(double amount) { + double balance = this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance / amount), false); + } + + public boolean hasEnough(double amount) { + return (this.balance() >= amount); + } + + public boolean hasOver(double amount) { + return (this.balance() > amount); + } + + public boolean hasUnder(double amount) { + return (this.balance() < amount); + } + + public boolean isNegative() { + return (this.balance() < 0); + } + + public boolean remove() { + return false; + } + } + + public class BOSEBankAccount implements MethodBankAccount { + private String bank; + private BOSEconomy BOSEconomy; + + public BOSEBankAccount(String bank, BOSEconomy bOSEconomy) { + this.bank = bank; + this.BOSEconomy = bOSEconomy; + } + + public String getBankName() { + return this.bank; + } + + public int getBankId() { + return -1; + } + + public double balance() { + return this.BOSEconomy.getBankMoneyDouble(bank); + } + + public boolean set(double amount) { + return this.BOSEconomy.setBankMoney(bank, amount, true); + } + + public boolean add(double amount) { + double balance = this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance + amount), false); + } + + public boolean subtract(double amount) { + double balance = this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance - amount), false); + } + + public boolean multiply(double amount) { + double balance = this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance * amount), false); + } + + public boolean divide(double amount) { + double balance = this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance / amount), false); + } + + public boolean hasEnough(double amount) { + return (this.balance() >= amount); + } + + public boolean hasOver(double amount) { + return (this.balance() > amount); + } + + public boolean hasUnder(double amount) { + return (this.balance() < amount); + } + + public boolean isNegative() { + return (this.balance() < 0); + } + + public boolean remove() { + return this.BOSEconomy.removeBank(bank); + } + } +} \ No newline at end of file diff --git a/src/com/garbagemule/register/payment/methods/EE17.java b/src/com/garbagemule/register/payment/methods/EE17.java new file mode 100644 index 0000000..388483f --- /dev/null +++ b/src/com/garbagemule/register/payment/methods/EE17.java @@ -0,0 +1,200 @@ +package com.garbagemule.register.payment.methods; + +import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.api.Economy; +import com.earth2me.essentials.api.NoLoanPermittedException; +import com.earth2me.essentials.api.UserDoesNotExistException; +import com.garbagemule.register.payment.Method; + + +import org.bukkit.plugin.Plugin; + +public class EE17 implements Method { + private Essentials Essentials; + + public Essentials getPlugin() { + return this.Essentials; + } + + public String getName() { + return "Essentials"; + } + + public String getVersion() { + return "2.2"; + } + + public String format(double amount) { + return Economy.format(amount); + } + + public boolean hasBanks() { + return false; + } + + public boolean hasBank(String bank) { + return false; + } + + public boolean hasAccount(String name) { + return Economy.playerExists(name); + } + + public boolean hasBankAccount(String bank, String name) { + return false; + } + + public MethodAccount getAccount(String name) { + if(!hasAccount(name)) return null; + return new EEcoAccount(name); + } + + public MethodBankAccount getBankAccount(String bank, String name) { + return null; + } + + public boolean isCompatible(Plugin plugin) { + try { Class.forName("com.earth2me.essentials.api.Economy"); } + catch(Exception e) { return false; } + + return plugin.getDescription().getName().equalsIgnoreCase("essentials") && plugin instanceof Essentials; + } + + public void setPlugin(Plugin plugin) { + Essentials = (Essentials)plugin; + } + + public class EEcoAccount implements MethodAccount { + private String name; + + public EEcoAccount(String name) { + this.name = name; + } + + public double balance() { + Double balance = 0.0; + + try { + balance = Economy.getMoney(this.name); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] Failed to grab balance in Essentials Economy: " + ex.getMessage()); + } + + return balance; + } + + public boolean set(double amount) { + try { + Economy.setMoney(name, amount); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + return false; + } catch (NoLoanPermittedException ex) { + System.out.println("[REGISTER] No loan permitted in Essentials Economy: " + ex.getMessage()); + return false; + } + + return true; + } + + public boolean add(double amount) { + try { + Economy.add(name, amount); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + return false; + } catch (NoLoanPermittedException ex) { + System.out.println("[REGISTER] No loan permitted in Essentials Economy: " + ex.getMessage()); + return false; + } + + return true; + } + + public boolean subtract(double amount) { + try { + Economy.subtract(name, amount); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + return false; + } catch (NoLoanPermittedException ex) { + System.out.println("[REGISTER] No loan permitted in Essentials Economy: " + ex.getMessage()); + return false; + } + + return true; + } + + public boolean multiply(double amount) { + try { + Economy.multiply(name, amount); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + return false; + } catch (NoLoanPermittedException ex) { + System.out.println("[REGISTER] No loan permitted in Essentials Economy: " + ex.getMessage()); + return false; + } + + return true; + } + + public boolean divide(double amount) { + try { + Economy.divide(name, amount); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + return false; + } catch (NoLoanPermittedException ex) { + System.out.println("[REGISTER] No loan permitted in Essentials Economy: " + ex.getMessage()); + return false; + } + + return true; + } + + public boolean hasEnough(double amount) { + try { + return Economy.hasEnough(name, amount); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + } + + return false; + } + + public boolean hasOver(double amount) { + try { + return Economy.hasMore(name, amount); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + } + + return false; + } + + public boolean hasUnder(double amount) { + try { + return Economy.hasLess(name, amount); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + } + + return false; + } + + public boolean isNegative() { + try { + return Economy.isNegative(name); + } catch (UserDoesNotExistException ex) { + System.out.println("[REGISTER] User does not exist in Essentials Economy: " + ex.getMessage()); + } + + return false; + } + + public boolean remove() { + return false; + } + } +} \ No newline at end of file diff --git a/src/com/garbagemule/register/payment/methods/iCo4.java b/src/com/garbagemule/register/payment/methods/iCo4.java new file mode 100644 index 0000000..2c96115 --- /dev/null +++ b/src/com/garbagemule/register/payment/methods/iCo4.java @@ -0,0 +1,128 @@ +package com.garbagemule.register.payment.methods; + +import com.garbagemule.register.payment.Method; +import com.nijiko.coelho.iConomy.iConomy; +import com.nijiko.coelho.iConomy.system.Account; + + +import org.bukkit.plugin.Plugin; + +public class iCo4 implements Method { + private iConomy iConomy; + + public iConomy getPlugin() { + return this.iConomy; + } + + public String getName() { + return "iConomy"; + } + + public String getVersion() { + return "4"; + } + + public String format(double amount) { + return this.iConomy.getBank().format(amount); + } + + public boolean hasBanks() { + return false; + } + + public boolean hasBank(String bank) { + return false; + } + + public boolean hasAccount(String name) { + return this.iConomy.getBank().hasAccount(name); + } + + public boolean hasBankAccount(String bank, String name) { + return false; + } + + public MethodAccount getAccount(String name) { + return new iCoAccount(this.iConomy.getBank().getAccount(name)); + } + + public MethodBankAccount getBankAccount(String bank, String name) { + return null; + } + + public boolean isCompatible(Plugin plugin) { + return plugin.getDescription().getName().equalsIgnoreCase("iconomy") && !plugin.getClass().getName().equals("com.iConomy.iConomy") && plugin instanceof iConomy; + } + + public void setPlugin(Plugin plugin) { + iConomy = (iConomy)plugin; + } + + public class iCoAccount implements MethodAccount { + private Account account; + + public iCoAccount(Account account) { + this.account = account; + } + + public Account getiCoAccount() { + return account; + } + + public double balance() { + return this.account.getBalance(); + } + + public boolean set(double amount) { + if(this.account == null) return false; + this.account.setBalance(amount); + return true; + } + + public boolean add(double amount) { + if(this.account == null) return false; + this.account.add(amount); + return true; + } + + public boolean subtract(double amount) { + if(this.account == null) return false; + this.account.subtract(amount); + return true; + } + + public boolean multiply(double amount) { + if(this.account == null) return false; + this.account.multiply(amount); + return true; + } + + public boolean divide(double amount) { + if(this.account == null) return false; + this.account.divide(amount); + return true; + } + + public boolean hasEnough(double amount) { + return this.account.hasEnough(amount); + } + + public boolean hasOver(double amount) { + return this.account.hasOver(amount); + } + + public boolean hasUnder(double amount) { + return (this.balance() < amount); + } + + public boolean isNegative() { + return this.account.isNegative(); + } + + public boolean remove() { + if(this.account == null) return false; + this.account.remove(); + return true; + } + } +} diff --git a/src/com/garbagemule/register/payment/methods/iCo5.java b/src/com/garbagemule/register/payment/methods/iCo5.java new file mode 100644 index 0000000..2e0ede8 --- /dev/null +++ b/src/com/garbagemule/register/payment/methods/iCo5.java @@ -0,0 +1,211 @@ +package com.garbagemule.register.payment.methods; + +import com.garbagemule.register.payment.Method; +import com.iConomy.iConomy; +import com.iConomy.system.Account; +import com.iConomy.system.BankAccount; +import com.iConomy.system.Holdings; +import com.iConomy.util.Constants; + + +import org.bukkit.plugin.Plugin; + +public class iCo5 implements Method { + private iConomy iConomy; + + public iConomy getPlugin() { + return this.iConomy; + } + + public String getName() { + return "iConomy"; + } + + public String getVersion() { + return "5"; + } + + public String format(double amount) { + return this.iConomy.format(amount); + } + + public boolean hasBanks() { + return Constants.Banking; + } + + public boolean hasBank(String bank) { + return (!hasBanks()) ? false : this.iConomy.Banks.exists(bank); + } + + public boolean hasAccount(String name) { + return this.iConomy.hasAccount(name); + } + + public boolean hasBankAccount(String bank, String name) { + return (!hasBank(bank)) ? false : this.iConomy.getBank(bank).hasAccount(name); + } + + public MethodAccount getAccount(String name) { + return new iCoAccount(this.iConomy.getAccount(name)); + } + + public MethodBankAccount getBankAccount(String bank, String name) { + return new iCoBankAccount(this.iConomy.getBank(bank).getAccount(name)); + } + + public boolean isCompatible(Plugin plugin) { + return plugin.getDescription().getName().equalsIgnoreCase("iconomy") && plugin.getClass().getName().equals("com.iConomy.iConomy") && plugin instanceof iConomy; + } + + public void setPlugin(Plugin plugin) { + iConomy = (iConomy)plugin; + } + + public class iCoAccount implements MethodAccount { + private Account account; + private Holdings holdings; + + public iCoAccount(Account account) { + this.account = account; + this.holdings = account.getHoldings(); + } + + public Account getiCoAccount() { + return account; + } + + public double balance() { + return this.holdings.balance(); + } + + public boolean set(double amount) { + if(this.holdings == null) return false; + this.holdings.set(amount); + return true; + } + + public boolean add(double amount) { + if(this.holdings == null) return false; + this.holdings.add(amount); + return true; + } + + public boolean subtract(double amount) { + if(this.holdings == null) return false; + this.holdings.subtract(amount); + return true; + } + + public boolean multiply(double amount) { + if(this.holdings == null) return false; + this.holdings.multiply(amount); + return true; + } + + public boolean divide(double amount) { + if(this.holdings == null) return false; + this.holdings.divide(amount); + return true; + } + + public boolean hasEnough(double amount) { + return this.holdings.hasEnough(amount); + } + + public boolean hasOver(double amount) { + return this.holdings.hasOver(amount); + } + + public boolean hasUnder(double amount) { + return this.holdings.hasUnder(amount); + } + + public boolean isNegative() { + return this.holdings.isNegative(); + } + + public boolean remove() { + if(this.account == null) return false; + this.account.remove(); + return true; + } + } + + public class iCoBankAccount implements MethodBankAccount { + private BankAccount account; + private Holdings holdings; + + public iCoBankAccount(BankAccount account) { + this.account = account; + this.holdings = account.getHoldings(); + } + + public BankAccount getiCoBankAccount() { + return account; + } + + public String getBankName() { + return this.account.getBankName(); + } + + public int getBankId() { + return this.account.getBankId(); + } + + public double balance() { + return this.holdings.balance(); + } + + public boolean set(double amount) { + if(this.holdings == null) return false; + this.holdings.set(amount); + return true; + } + + public boolean add(double amount) { + if(this.holdings == null) return false; + this.holdings.add(amount); + return true; + } + + public boolean subtract(double amount) { + if(this.holdings == null) return false; + this.holdings.subtract(amount); + return true; + } + + public boolean multiply(double amount) { + if(this.holdings == null) return false; + this.holdings.multiply(amount); + return true; + } + + public boolean divide(double amount) { + if(this.holdings == null) return false; + this.holdings.divide(amount); + return true; + } + + public boolean hasEnough(double amount) { + return this.holdings.hasEnough(amount); + } + + public boolean hasOver(double amount) { + return this.holdings.hasOver(amount); + } + + public boolean hasUnder(double amount) { + return this.holdings.hasUnder(amount); + } + + public boolean isNegative() { + return this.holdings.isNegative(); + } + + public boolean remove() { + if(this.account == null) return false; + this.account.remove(); + return true; + } + } +}