diff --git a/MobArena.jar b/MobArena.jar index ba9f033..665d860 100644 Binary files a/MobArena.jar and b/MobArena.jar differ diff --git a/bin/plugin.yml b/bin/plugin.yml index e636dfd..e263597 100644 --- a/bin/plugin.yml +++ b/bin/plugin.yml @@ -1,6 +1,6 @@ name: MobArena main: com.garbagemule.MobArena.MobArena -version: 0.92.3 +version: 0.92.4 softdepend: [MultiVerse,XcraftGate] commands: ma: diff --git a/language files/announcements_da.properties b/language files/announcements_da.properties index ad2f9c4..f78db35 100644 --- a/language files/announcements_da.properties +++ b/language files/announcements_da.properties @@ -6,11 +6,13 @@ 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_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_PLAYER_LIMIT_REACHED=Der kan ikke være flere spillere i arenaen. +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. @@ -29,6 +31,7 @@ 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! diff --git a/language files/announcements_fr.properties b/language files/announcements_fr.properties index 1bd930f..2bfb9b3 100644 --- a/language files/announcements_fr.properties +++ b/language files/announcements_fr.properties @@ -6,11 +6,13 @@ 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_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_PLAYER_LIMIT_REACHED=La limite de joueur pour cette arène a été atteinte. +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. @@ -29,7 +31,8 @@ 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_PERMISSION=Vous n'avez pas les permissions pour utiliser cette 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 ! diff --git a/language files/announcements_pirate.properties b/language files/announcements_pirate.properties index 117473f..97100ee 100644 --- a/language files/announcements_pirate.properties +++ b/language files/announcements_pirate.properties @@ -6,11 +6,13 @@ 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_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_PLAYER_LIMIT_REACHED=Thar be too many men aboard this ship already, landlubber! +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! @@ -29,6 +31,7 @@ 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! diff --git a/src/com/garbagemule/MobArena/Arena.java b/src/com/garbagemule/MobArena/Arena.java index 2c87350..bf7a163 100644 --- a/src/com/garbagemule/MobArena/Arena.java +++ b/src/com/garbagemule/MobArena/Arena.java @@ -5,11 +5,13 @@ 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; @@ -62,7 +64,7 @@ public class Arena // Setup fields protected String name; protected World world; - protected boolean enabled, running, setup, lobbySetup, protect, autoEquip, forceRestore, softRestore, softRestoreDrops, emptyInvJoin, emptyInvSpec, pvp, monsterInfight, allowWarp; + 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; protected Location p1, p2, l1, l2, arenaLoc, lobbyLoc, spectatorLoc; protected Map spawnpoints; @@ -73,6 +75,7 @@ public class Arena protected Map> everyWaveMap, afterWaveMap; protected Map distDefault, distSpecial; protected Map classMap; + protected Set randoms; protected Map> classItems, classArmor; protected Map>> classBonuses; protected Map> rewardMap; @@ -83,7 +86,6 @@ public class Arena protected Set blocks; protected Set pets; protected Map petMap; - protected Map kills; protected List repairList; // Spawn overriding @@ -91,10 +93,19 @@ public class Arena protected boolean allowMonsters, allowAnimals; // Other settings - protected int repairDelay, playerLimit; + protected int repairDelay, playerLimit, joinDistance; protected List classes = new LinkedList(); protected Map locations = new HashMap(); + // Logging + protected ArenaLog log; + //protected List log = new LinkedList(); + 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. */ @@ -106,6 +117,7 @@ public class Arena this.name = name; this.world = world; plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); + log = new ArenaLog(plugin, this); livePlayers = new HashSet(); deadPlayers = new HashSet(); @@ -116,8 +128,8 @@ public class Arena pets = new HashSet(); petMap = new HashMap(); classMap = new HashMap(); + randoms = new HashSet(); rewardMap = new HashMap>(); - kills = new HashMap(); repairList = new LinkedList(); running = false; @@ -136,6 +148,11 @@ public class Arena 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, true, true); MAUtils.setSpawnFlags(plugin, world, 1, allowMonsters, allowAnimals); @@ -146,6 +163,8 @@ public class Arena p.teleport(arenaLoc); p.setHealth(20); rewardMap.put(p, new LinkedList()); + waveMap.put(p, 0); + killMap.put(p, 0); } running = true; @@ -174,6 +193,11 @@ public class Arena 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. @@ -188,6 +212,14 @@ public class Arena { running = false; + // Logging stuff + if (logging) + { + log.end(); + log.serialize(); + log.clear(); + } + // If the arena was actually ever started, cancel the spawnthread. if (spawnThread != null) { @@ -322,8 +354,16 @@ public class Arena specPlayers.remove(p); removePets(p); - if (clear) MAUtils.clearInventory(p); - if (!emptyInvJoin) MAUtils.restoreInventory(p); + // 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); if (running && livePlayers.isEmpty()) endArena(); @@ -376,9 +416,9 @@ public class Arena p.teleport(spectatorLoc); } - public void playerKill(Player p, LivingEntity e) + public void playerKill(Player p) { - kills.put(p, kills.get(p) + 1); + killMap.put(p, killMap.get(p) + 1); } @@ -393,7 +433,16 @@ public class Arena { 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); MAUtils.giveItems(p, classArmor.get(className), autoEquip); @@ -401,8 +450,29 @@ public class Arena if (pets > 0) petMap.put(p, pets); } - private void giveRewards() + 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 (!MobArena.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)); @@ -476,6 +546,7 @@ public class Arena 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); @@ -490,6 +561,7 @@ public class Arena pvp = config.getBoolean(arenaPath + "pvp-enabled", false); monsterInfight = config.getBoolean(arenaPath + "monster-infight", false); allowWarp = config.getBoolean(arenaPath + "allow-teleporting", false); + 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; @@ -689,7 +761,7 @@ public class Arena // Block Listener public void onBlockBreak(BlockBreakEvent event) { - if (!inRegion(event.getBlock().getLocation()) || edit) + if (!inRegion(event.getBlock().getLocation()) || edit || (!protect && running)) return; Block b = event.getBlock(); @@ -833,7 +905,8 @@ public class Arena public void onEntityTarget(EntityTargetEvent event) { - if (!running) return; + if (!running || event.isCancelled()) + return; if (pets.contains(event.getEntity())) { @@ -891,6 +964,7 @@ public class Arena return; event.getDrops().clear(); + waveMap.put(p, spawnThread.wave - 1); playerDeath(p); p.getInventory().clear(); // For TombStone return; @@ -898,6 +972,13 @@ public class Arena 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; @@ -1050,10 +1131,10 @@ public class Arena // Check if the first line of the sign is a class name. String className = sign.getLine(0); - if (!classes.contains(className)) + if (!classes.contains(className) && !className.equalsIgnoreCase("random")) return; - if (!MobArena.hasDefTrue(p, "mobarena.classes." + className)) + if (!MobArena.hasDefTrue(p, "mobarena.classes." + className) && !className.equalsIgnoreCase("random")) { MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_CLASS_PERMISSION)); return; @@ -1061,7 +1142,11 @@ public class Arena // Set the player's class. assignClass(p, className); - MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_CLASS_PICKED, 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; } } diff --git a/src/com/garbagemule/MobArena/ArenaLog.java b/src/com/garbagemule/MobArena/ArenaLog.java new file mode 100644 index 0000000..25394cf --- /dev/null +++ b/src/com/garbagemule/MobArena/ArenaLog.java @@ -0,0 +1,136 @@ +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; + 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))); + 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 index d5603c9..7dedf60 100644 --- a/src/com/garbagemule/MobArena/ArenaMaster.java +++ b/src/com/garbagemule/MobArena/ArenaMaster.java @@ -23,7 +23,7 @@ public class ArenaMaster //protected Lobby masterLobby; // Settings - protected boolean enabled, updateNotify, autoEquip, emptyInvs, hellhounds; + protected boolean enabled, updateNotify; // Classes protected List classes; @@ -257,6 +257,7 @@ public class ArenaMaster config.setProperty("arenas." + configName + ".settings.protect", true); 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); @@ -271,7 +272,10 @@ public class ArenaMaster 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.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); diff --git a/src/com/garbagemule/MobArena/MACommands.java b/src/com/garbagemule/MobArena/MACommands.java index 836f9f0..836c3f2 100644 --- a/src/com/garbagemule/MobArena/MACommands.java +++ b/src/com/garbagemule/MobArena/MACommands.java @@ -34,6 +34,8 @@ public class MACommands implements CommandExecutor 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 @@ -152,12 +154,16 @@ public class MACommands implements CommandExecutor error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_IS_RUNNING)); else if (arena.livePlayers.contains(p)) error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ALREADY_PLAYING)); + else if (!MobArena.has(p, "mobarena.arenas." + arena.configName())) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_PERMISSION)); else if (arena.playerLimit > 0 && arena.livePlayers.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. @@ -243,9 +249,11 @@ public class MACommands implements CommandExecutor 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 join. + // If there was an error, don't spec. if (error) return true; @@ -372,36 +380,6 @@ public class MACommands implements CommandExecutor return true; } - /* - * Enable or disable protection - */ - if (base.equals("protect")) - { - if (!console && !(player && MobArena.has(p, "mobarena.admin.protect")) && !op) - { - MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); - return true; - } - if (arg1.isEmpty() || !arg1.matches("^[a-zA-Z][a-zA-Z0-9_]*$") || !(arg2.equals("true") || arg2.equals("false"))) - { - MAUtils.tellPlayer(sender, "Usage: /ma protect [true|false]"); - return true; - } - - Arena arena = am.getArenaWithName(arg1); - if (arena == null) - { - MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); - return true; - } - - arena.protect = arg2.equals("true"); - arena.serializeConfig(); - arena.load(plugin.getConfig()); - MAUtils.tellPlayer(sender, "Protection for arena '" + arg1 + "' set to " + arg2); - return true; - } - /* * Restore a player's inventory. */ @@ -650,6 +628,75 @@ public class MACommands implements CommandExecutor return true; } + /* + * Enable or disable protection + */ + if (base.equals("protect")) + { + if (!console && !(player && MobArena.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 && MobArena.has(p, "mobarena.setup.editarena")) && !op) diff --git a/src/com/garbagemule/MobArena/MAMessages.java b/src/com/garbagemule/MobArena/MAMessages.java index a5979b7..1b8bfda 100644 --- a/src/com/garbagemule/MobArena/MAMessages.java +++ b/src/com/garbagemule/MobArena/MAMessages.java @@ -3,8 +3,9 @@ package com.garbagemule.MobArena; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileReader; +import java.io.FileInputStream; import java.io.FileWriter; +import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; @@ -22,11 +23,13 @@ public class MAMessages JOIN_IN_OTHER_ARENA, JOIN_ARENA_NOT_ENABLED, JOIN_ARENA_NOT_SETUP, + JOIN_ARENA_PERMISSION, JOIN_ARENA_IS_RUNNING, JOIN_ALREADY_PLAYING, JOIN_ARG_NEEDED, - JOIN_PLAYER_LIMIT_REACHED, + JOIN_TOO_FAR, JOIN_EMPTY_INV, + JOIN_PLAYER_LIMIT_REACHED, JOIN_STORE_INV_FAIL, LEAVE_PLAYER_LEFT, LEAVE_NOT_PLAYING, @@ -45,6 +48,7 @@ public class MAMessages FORCE_END_IDLE, REWARDS_GIVE, LOBBY_CLASS_PICKED, + LOBBY_CLASS_RANDOM, LOBBY_CLASS_PERMISSION, LOBBY_PLAYER_READY, LOBBY_DROP_ITEM, @@ -55,7 +59,6 @@ public class MAMessages WAVE_DEFAULT, WAVE_SPECIAL, WAVE_REWARD, - // Misc MISC_LIST_ARENAS, MISC_LIST_PLAYERS, MISC_COMMAND_NOT_ALLOWED, @@ -73,9 +76,11 @@ public class MAMessages 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_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."); @@ -101,6 +106,7 @@ public class MAMessages 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!"); @@ -134,10 +140,7 @@ public class MAMessages System.out.println("[MobArena] Announcements-file not found. Creating one..."); msgFile.createNewFile(); - FileWriter fw = new FileWriter(msgFile); - BufferedWriter bw = new BufferedWriter(fw); - - // Write default announcements to the file. + BufferedWriter bw = new BufferedWriter(new FileWriter(msgFile)); for (Msg m : Msg.values()) { bw.write(m.toString() + "=" + defaults.get(m)); @@ -150,26 +153,29 @@ public class MAMessages } catch (Exception e) { - System.out.println("[MobArena] ERROR: Couldn't initialize announcements-file. Using defaults."); + System.out.println("[MobArena] ERROR! Couldn't initialize announcements-file. Using defaults."); return; } // If the file was found, populate the msgMap. try { - FileReader fr = new FileReader(msgFile); - BufferedReader br = new BufferedReader(fr); + 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) { - System.out.println("[MobArena] ERROR: Problem with announcements-file. Using defaults."); + e.printStackTrace(); + System.out.println("[MobArena] ERROR! Problem with announcements-file. Using defaults."); return; } } @@ -211,7 +217,7 @@ public class MAMessages String[] split = s.split("="); if (split.length != 2) { - System.out.println("[MobArena] ERROR: Couldn't parse \"" + s + "\". Check announcements-file."); + System.out.println("[MobArena] ERROR! Couldn't parse \"" + s + "\". Check announcements-file."); return; } @@ -227,7 +233,7 @@ public class MAMessages } catch (Exception e) { - System.out.println("[MobArena] ERROR: " + key + " is not a valid key. Check announcements-file."); + System.out.println("[MobArena] ERROR! " + key + " is not a valid key. Check announcements-file."); return; } } diff --git a/src/com/garbagemule/MobArena/MAPlayerListener.java b/src/com/garbagemule/MobArena/MAPlayerListener.java index 9cb29dd..67341bc 100644 --- a/src/com/garbagemule/MobArena/MAPlayerListener.java +++ b/src/com/garbagemule/MobArena/MAPlayerListener.java @@ -75,7 +75,7 @@ public class MAPlayerListener extends PlayerListener if (!am.updateNotify || !event.getPlayer().isOp()) return; final Player p = event.getPlayer(); - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() { public void run() diff --git a/src/com/garbagemule/MobArena/MASpawnThread.java b/src/com/garbagemule/MobArena/MASpawnThread.java index abf9fce..049f908 100644 --- a/src/com/garbagemule/MobArena/MASpawnThread.java +++ b/src/com/garbagemule/MobArena/MASpawnThread.java @@ -75,14 +75,14 @@ public class MASpawnThread implements Runnable 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) - { - List tmp = new LinkedList(arena.monsters); - for (Entity e : tmp) - if (e.isDead()) - arena.monsters.remove(e); - + { if (!arena.monsters.isEmpty()) return; } @@ -119,7 +119,7 @@ public class MASpawnThread implements Runnable } wave++; - if (arena.maxIdleTime > 0) arena.resetIdleTimer(); + if (arena.maxIdleTime > 0 && arena.monsters.isEmpty()) arena.resetIdleTimer(); } /** diff --git a/src/com/garbagemule/MobArena/MAUtils.java b/src/com/garbagemule/MobArena/MAUtils.java index 563c5a2..9a45599 100644 --- a/src/com/garbagemule/MobArena/MAUtils.java +++ b/src/com/garbagemule/MobArena/MAUtils.java @@ -918,15 +918,6 @@ public class MAUtils return result; } - /*public static double distance(Location loc1, Location loc2) - { - double x = loc1.getX() - loc2.getX(); - double y = loc1.getY() - loc2.getY(); - double z = loc1.getZ() - loc2.getZ(); - - return x*x + y*y + z*z; - }*/ - /** * Convert a proper arena name to a config-file name. * All spaces are replaced by underscores, and the whole String is @@ -972,25 +963,51 @@ public class MAUtils /** * Turn a list into a space-separated string-representation of the list. - */ - public static String listToString(List list) - { - return listToString(list, true); - } - + */ public static String listToString(List list, boolean none) { - if (none && list.isEmpty()) - return MAMessages.get(Msg.MISC_NONE); + if (list.isEmpty()) + { + if (none) + return MAMessages.get(Msg.MISC_NONE); + else + return ""; + } StringBuffer buffy = new StringBuffer(); - for (E e : list) + + E type = list.get(0); + if (type instanceof Player) { - buffy.append((e instanceof Player) ? ((Player) e).getName() : e.toString()); - buffy.append(" "); + for (E e : list) + { + buffy.append(((Player) e).getName()); + buffy.append(" "); + } + } + else if (type instanceof ItemStack) + { + ItemStack stack; + for (E e : list) + { + stack = (ItemStack) e; + 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(); } + public static String listToString(List list) { return listToString(list, true); } /** * Returns a String-list version of a comma-separated list. @@ -1099,6 +1116,36 @@ public class MAUtils 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! */ @@ -1158,7 +1205,7 @@ public class MAUtils catch (Exception e) { e.printStackTrace(); - System.out.println("Couldn't create backup file. Aborting auto-generate..."); + System.out.println("[MobArena] ERROR! Couldn't create backup file. Aborting auto-generate..."); return false; } @@ -1291,7 +1338,7 @@ public class MAUtils } catch (Exception e) { - if (error) System.out.println("Couldn't find backup file for arena '" + name + "'"); + if (error) System.out.println("[MobArena] ERROR! Couldn't find backup file for arena '" + name + "'"); return false; }