diff --git a/MobArena.jar b/MobArena.jar index 405fb89..532713b 100644 Binary files a/MobArena.jar and b/MobArena.jar differ diff --git a/src/com/garbagemule/ArenaPlugin/Arena.java b/src/com/garbagemule/ArenaPlugin/Arena.java new file mode 100644 index 0000000..883ee9f --- /dev/null +++ b/src/com/garbagemule/ArenaPlugin/Arena.java @@ -0,0 +1,116 @@ +package com.garbagemule.ArenaPlugin; + +import org.bukkit.entity.Player; + +public interface Arena +{ + /** + * 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 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 void endArena(); + + /** + * Force the arena to start. + * If some players are ready, this method will force all non-ready players to leave, + * and the arena will start with only the currently ready players. + * @return true, if the arena was successfully started, false otherwise + */ + public boolean forceStart(); + + /** + * Force the arena to end. + * Returns all players to their entry locations, distributes rewards, cleans the arena + * floor, as well as all lists, sets and maps. Calling this method will return the + * arena to the state it would be in right after MobArena has loaded. + * @return true, if the session was successfully ended. + */ + public boolean forceEnd(); + + /** + * Player joins the arena/lobby. + * The player should either enter with an empty inventory, or have their inventory + * stored upon entering, such that the classes in the lobby/arena will be the only + * means of equipment. The player's previous location and health is also stored. + * @param p A player + * @precondition Calling canJoin(p) for the given player must return true. + */ + public void playerJoin(Player p); + + /** + * Player leaves the arena or lobby. + * Upon leaving, the player will have their inventory restored (if it was stored + * on join), as well as their health. They will be completely discarded/cleared from + * the arena, such that they no longer reside in any collections. + * @param p A player + * @precondition Calling canLeave(p) for the given player must return true. + */ + public void playerLeave(Player p); + + /** + * Player joins the spectator area. + * The player takes a spectator role, meaning they cannot participate in the arena + * in any way. The player's location and health is stored upon spectating, and of + * course restored upon leaving. + * @param p A player + * @precondition Calling canSpec(p) for the given player must return true. + */ + public void playerSpec(Player p); + + /** + * Player dies in the arena. + */ + public void playerDeath(Player p); + + /** + * Player signals that they are ready. + */ + public void playerReady(Player p); + + /** + * Check if a player can join the arena. + * @param p A player + * @return true, if the player is eligible to join the arena. + */ + public boolean canJoin(Player p); + + /** + * Check if a player can leave the arena. + * @param p A player + * @return true, if the player is eligible to leave the arena. + */ + public boolean canLeave(Player p); + + /** + * Check if a player can spectate the arena. + * @param p A player + * @return true, if the player is eligible for spectating. + */ + public boolean canSpec(Player p); + + /** + * Check if the arena is enabled. + * @return true, if the arena is enabled. + */ + public boolean isEnabled(); + + /** + * Check if the arena is set up and ready for use. + * @return true, if the arena is ready for use. + */ + public boolean isSetup(); + + /** + * Check if the arena is running. + * @return true, if the arena is running. + */ + public boolean isRunning(); +} diff --git a/src/com/garbagemule/ArenaPlugin/ArenaPlugin.java b/src/com/garbagemule/ArenaPlugin/ArenaPlugin.java new file mode 100644 index 0000000..b751cb4 --- /dev/null +++ b/src/com/garbagemule/ArenaPlugin/ArenaPlugin.java @@ -0,0 +1,6 @@ +package com.garbagemule.ArenaPlugin; + +public interface ArenaPlugin +{ + public Master getMaster(); +} diff --git a/src/com/garbagemule/ArenaPlugin/Master.java b/src/com/garbagemule/ArenaPlugin/Master.java new file mode 100644 index 0000000..6a66c99 --- /dev/null +++ b/src/com/garbagemule/ArenaPlugin/Master.java @@ -0,0 +1,16 @@ +package com.garbagemule.ArenaPlugin; + +import java.util.List; + +import org.bukkit.entity.Player; + +public interface Master +{ + //public List getArenas(); + + //public List getEnabledArenas(); + + //public List getPermittedArenas(Player p); + + +} diff --git a/src/com/garbagemule/MobArena/AbstractArena.java b/src/com/garbagemule/MobArena/AbstractArena.java index 1af1abc..f9d7670 100644 --- a/src/com/garbagemule/MobArena/AbstractArena.java +++ b/src/com/garbagemule/MobArena/AbstractArena.java @@ -1,65 +1,44 @@ package com.garbagemule.MobArena; -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.Player; -import org.bukkit.inventory.ItemStack; -public abstract class AbstractArena implements Arenaz +import com.garbagemule.ArenaPlugin.ArenaPlugin; + +public abstract class AbstractArena implements ArenaInterface { - - private String name; - private World world; - private MobArena plugin; + private String name; + private World world; + private ArenaPlugin plugin; private boolean enabled, setup, running; private Set arenaPlayers, lobbyPlayers, readyPlayers, specPlayers; private Map playerClassMap; private Map locations; - private Map healthMap; + private Map healths; - /** - * 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 AbstractArena(String name, World world, ArenaPlugin plugin) + { + if (world == null) + throw new NullPointerException("[" + plugin.getClass().getSimpleName() + "] ERROR! World for arena '" + name + "' does not exist!"); + + this.name = name; + this.world = world; + this.plugin = plugin; + } + 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, false otherwise - */ public abstract void endArena(); - - /** - * Force the arena to start. - * If some players are ready, this method will force all non-ready players to leave, - * and the arena will start with only the currently ready players. - * @return true, if the arena was successfully started, false otherwise - */ + public abstract boolean forceStart(); - - /** - * Force the arena to end. - * Returns all players to their entry locations, distributes rewards, cleans the arena - * floor, as well as all lists, sets and maps. Calling this method will return the - * arena to the state it would be in right after MobArena has loaded. - * @return true, if the session was successfully ended. - */ + public abstract boolean forceEnd(); - - /** - * Player joins the arena/lobby. - * @param p A player - * @precondition Calling canJoin(p) for the given player must return true. - */ +/* public void playerJoin(Player p) { storePlayerData(p, p.getLocation()); @@ -67,12 +46,7 @@ public abstract class AbstractArena implements Arenaz p.setHealth(20); movePlayerToLobby(p); } - - /** - * Player leaves the arena or lobby. - * @param p A player - * @precondition Calling canLeave(p) for the given player must return true. - */ +*/ /* public void playerLeave(Player p) { @@ -86,66 +60,29 @@ public abstract class AbstractArena implements Arenaz endArena(); }*/ - /** - * Player joins the spectator area. - * @param p A player - * @precondition Calling canSpec(p) for the given player must return true. - */ + public abstract void playerSpec(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); - - /** - * Check if a player can join the arena. - * @param p A player - * @return true, if the player is eligible to join the arena. - */ + public abstract boolean canJoin(Player p); - - /** - * Check if a player can leave the arena. - * @param p A player - * @return true, if the player is eligible to leave the arena. - */ + public abstract boolean canLeave(Player p); - - /** - * Check if a player can spectate the arena. - * @param p A player - * @return true, if the player is eligible for spectating. - */ + public abstract boolean canSpec(Player p); - - /** - * Check if the arena is enabled. - * @return true, if the arena is enabled. - */ + public boolean isEnabled() { return enabled; } - - /** - * Check if the arena is set up and ready for use. - * @return true, if the arena is ready for use. - */ + public boolean isSetup() { return setup; } - - /** - * Check if the arena is running. - * @return true, if the arena is running. - */ + public boolean isRunning() { return running; @@ -159,15 +96,21 @@ public abstract class AbstractArena implements Arenaz if (!locations.containsKey(p)) locations.put(p, loc); - if (!healthMap.containsKey(p)) - healthMap.put(p, p.getHealth()); + if (!healths.containsKey(p)) + healths.put(p, p.getHealth()); } public abstract void movePlayerToLobby(Player p); public abstract void movePlayerToSpec(Player p); - public abstract void movePlayerToEntry(Player p); + public void movePlayerToEntry(Player p) + { + Location entry = locations.get(p); + if (entry == null) return; + + p.teleport(entry); + } public abstract void restoreInvAndGiveRewards(final Player p); } diff --git a/src/com/garbagemule/MobArena/Arena.java b/src/com/garbagemule/MobArena/Arena.java index e39566b..ad168c9 100644 --- a/src/com/garbagemule/MobArena/Arena.java +++ b/src/com/garbagemule/MobArena/Arena.java @@ -47,6 +47,7 @@ import com.garbagemule.MobArena.MAMessages.Msg; import com.garbagemule.MobArena.repairable.Repairable; import com.garbagemule.MobArena.repairable.RepairableComparator; import com.garbagemule.MobArena.repairable.RepairableContainer; +import com.garbagemule.MobArena.util.InventoryItem; import com.garbagemule.MobArena.util.WaveUtils; import com.garbagemule.MobArena.waves.BossWave; import com.garbagemule.MobArena.waves.Wave; @@ -63,7 +64,7 @@ public class Arena protected boolean edit, waveClear, detCreepers, detDamage, lightning, hellhounds, specOnDeath, shareInArena; protected Location p1, p2, l1, l2, arenaLoc, lobbyLoc, spectatorLoc; - protected Map spawnpoints; + protected Map spawnpoints, containers; protected String logging; // Wave/reward/entryfee fields @@ -89,7 +90,7 @@ public class Arena protected Set blocks; protected Set pets; protected Map petMap; - protected LinkedList repairables, containers; + protected LinkedList repairables, containables; // Spawn overriding protected int spawnMonsters; @@ -137,7 +138,7 @@ public class Arena classMap = new HashMap(); randoms = new HashSet(); repairables = new LinkedList(); - containers = new LinkedList(); + containables = new LinkedList(); running = false; edit = false; @@ -179,7 +180,10 @@ public class Arena p.setHealth(20); } - // Spawn pets. + // Set the boolean. + running = true; + + // Spawn pets (must happen after 'running = true;') spawnPets(); // Copy the singleWaves Set. @@ -193,9 +197,6 @@ public class Arena log = new ArenaLog(plugin, this); log.start(); - // Set the boolean. - running = true; - // Announce and notify. MAUtils.tellAll(this, Msg.ARENA_START.get()); for (MobArenaListener listener : plugin.getAM().listeners) @@ -339,7 +340,6 @@ public class Arena if (specOnDeath) { - //resetPlayer(p); clearPlayer(p); movePlayerToSpec(p); } @@ -353,13 +353,14 @@ public class Arena spawnThread.updateTargets(); MAUtils.tellAll(this, Msg.PLAYER_DIED.get(p.getName())); - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() - { - public void run() + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() { - endArena(); - } - }); + public void run() + { + endArena(); + } + }); // Notify listeners. for (MobArenaListener listener : plugin.getAM().listeners) @@ -520,14 +521,12 @@ public class Arena { public void run() { - for (int x = p1.getBlockX(); x <= p2.getBlockX(); x++) - for (int y = p1.getBlockY(); y <= p2.getBlockY(); y++) - for (int z = p1.getBlockZ(); z <= p2.getBlockZ(); z++) - { - BlockState state = world.getBlockAt(x,y,z).getState(); - if (state instanceof ContainerBlock) - containers.add(new RepairableContainer(state, false)); - } + for (Location loc : containers.values()) + { + BlockState state = world.getBlockAt(loc).getState(); + if (state instanceof ContainerBlock) + containables.add(new RepairableContainer(state, false)); + } } }); } @@ -539,7 +538,7 @@ public class Arena { public void run() { - for (Repairable r : containers) + for (Repairable r : containables) r.repair(); } }); @@ -807,6 +806,7 @@ public class Arena lobbyLoc = MAUtils.getArenaCoord(config, world, configName, "lobby"); spectatorLoc = MAUtils.getArenaCoord(config, world, configName, "spectator"); spawnpoints = MAUtils.getArenaSpawnpoints(config, world, configName); + containers = MAUtils.getArenaContainers(config, world, configName); // NEW WAVES singleWaves = WaveUtils.getWaves(this, config, WaveBranch.SINGLE); @@ -1025,12 +1025,12 @@ public class Arena return classes; } - public Collection getAllSpawnpoints() + public List getAllSpawnpoints() { - return spawnpoints.values(); + return new ArrayList(spawnpoints.values()); } - public Collection getSpawnpoints() + public List getSpawnpoints() { List result = new ArrayList(spawnpoints.size()); @@ -1040,7 +1040,7 @@ public class Arena result.add(entry.getValue()); } - return !result.isEmpty() ? result : spawnpoints.values(); + return !result.isEmpty() ? result : new ArrayList(spawnpoints.values()); } public Location getBossSpawnpoint() @@ -1200,54 +1200,25 @@ public class Arena 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; - } + InventoryItem[] items = InventoryItem.parseItemStacks(inv.getContents()); + InventoryItem[] fee = InventoryItem.parseItemStacks(entryFee); - // 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); - } - } - } - } + // Take some economy money + for (InventoryItem item : InventoryItem.extractAllFromArray(MobArena.ECONOMY_MONEY_ID, fee)) + if (plugin.Methods.hasMethod()) + plugin.Method.getAccount(p.getName()).subtract(item.getAmount()); + + // Take any other items + for (InventoryItem item : fee) + InventoryItem.removeItemFromArray(item, items); - hasPaid.add(p); + // Turn everything back into ItemStacks + for (int i = 0; i < items.length; i++) + inv.setItem(i, items[i].toItemStack()); + return true; } - public void refund(Player p) - { - if (!hasPaid.contains(p)) - return; - - MAUtils.giveItems(p, entryFee, false, plugin); - hasPaid.remove(p); - } - public boolean canJoin(Player p) { if (!enabled) @@ -1266,12 +1237,14 @@ public class Arena MAUtils.tellPlayer(p, Msg.JOIN_PLAYER_LIMIT_REACHED); else if (joinDistance > 0 && !inRegionRadius(p.getLocation(), joinDistance)) MAUtils.tellPlayer(p, Msg.JOIN_TOO_FAR); - else if (!canAfford(p) || !takeFee(p)) + else if (emptyInvJoin && !MAUtils.hasEmptyInventory(p)) + MAUtils.tellPlayer(p, Msg.JOIN_EMPTY_INV); + /*else if (!canAfford(p) || !takeFee(p)) MAUtils.tellPlayer(p, Msg.JOIN_FEE_REQUIRED, MAUtils.listToString(entryFee, plugin)); else if (emptyInvJoin && !MAUtils.hasEmptyInventory(p)) MAUtils.tellPlayer(p, Msg.JOIN_EMPTY_INV); else if (!emptyInvJoin && !MAUtils.storeInventory(p)) - MAUtils.tellPlayer(p, Msg.JOIN_STORE_INV_FAIL); + MAUtils.tellPlayer(p, Msg.JOIN_STORE_INV_FAIL);*/ else return true; return false; diff --git a/src/com/garbagemule/MobArena/ArenaInterface.java b/src/com/garbagemule/MobArena/ArenaInterface.java new file mode 100644 index 0000000..d10255b --- /dev/null +++ b/src/com/garbagemule/MobArena/ArenaInterface.java @@ -0,0 +1,116 @@ +package com.garbagemule.MobArena; + +import org.bukkit.entity.Player; + +public interface ArenaInterface +{ + /** + * 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 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 void endArena(); + + /** + * Force the arena to start. + * If some players are ready, this method will force all non-ready players to leave, + * and the arena will start with only the currently ready players. + * @return true, if the arena was successfully started, false otherwise + */ + public boolean forceStart(); + + /** + * Force the arena to end. + * Returns all players to their entry locations, distributes rewards, cleans the arena + * floor, as well as all lists, sets and maps. Calling this method will return the + * arena to the state it would be in right after MobArena has loaded. + * @return true, if the session was successfully ended. + */ + public boolean forceEnd(); + + /** + * Player joins the arena/lobby. + * The player should either enter with an empty inventory, or have their inventory + * stored upon entering, such that the classes in the lobby/arena will be the only + * means of equipment. The player's previous location and health is also stored. + * @param p A player + * @precondition Calling canJoin(p) for the given player must return true. + */ + public void playerJoin(Player p); + + /** + * Player leaves the arena or lobby. + * Upon leaving, the player will have their inventory restored (if it was stored + * on join), as well as their health. They will be completely discarded/cleared from + * the arena, such that they no longer reside in any collections. + * @param p A player + * @precondition Calling canLeave(p) for the given player must return true. + */ + public void playerLeave(Player p); + + /** + * Player joins the spectator area. + * The player takes a spectator role, meaning they cannot participate in the arena + * in any way. The player's location and health is stored upon spectating, and of + * course restored upon leaving. + * @param p A player + * @precondition Calling canSpec(p) for the given player must return true. + */ + public void playerSpec(Player p); + + /** + * Player dies in the arena. + */ + public void playerDeath(Player p); + + /** + * Player signals that they are ready. + */ + public void playerReady(Player p); + + /** + * Check if a player can join the arena. + * @param p A player + * @return true, if the player is eligible to join the arena. + */ + public boolean canJoin(Player p); + + /** + * Check if a player can leave the arena. + * @param p A player + * @return true, if the player is eligible to leave the arena. + */ + public boolean canLeave(Player p); + + /** + * Check if a player can spectate the arena. + * @param p A player + * @return true, if the player is eligible for spectating. + */ + public boolean canSpec(Player p); + + /** + * Check if the arena is enabled. + * @return true, if the arena is enabled. + */ + public boolean isEnabled(); + + /** + * Check if the arena is set up and ready for use. + * @return true, if the arena is ready for use. + */ + public boolean isSetup(); + + /** + * Check if the arena is running. + * @return true, if the arena is running. + */ + public boolean isRunning(); +} diff --git a/src/com/garbagemule/MobArena/ArenaMaster.java b/src/com/garbagemule/MobArena/ArenaMaster.java index 1cc7cba..fd16e62 100644 --- a/src/com/garbagemule/MobArena/ArenaMaster.java +++ b/src/com/garbagemule/MobArena/ArenaMaster.java @@ -15,7 +15,9 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.util.config.Configuration; -public class ArenaMaster +import com.garbagemule.ArenaPlugin.Master; + +public class ArenaMaster implements Master { private MobArena plugin; private Configuration config; diff --git a/src/com/garbagemule/MobArena/ArenaPlayer.java b/src/com/garbagemule/MobArena/ArenaPlayer.java index c4efe41..fc3b215 100644 --- a/src/com/garbagemule/MobArena/ArenaPlayer.java +++ b/src/com/garbagemule/MobArena/ArenaPlayer.java @@ -3,6 +3,7 @@ package com.garbagemule.MobArena; import java.util.LinkedList; import java.util.List; +import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -13,6 +14,7 @@ public class ArenaPlayer public String className; public Arena arena; public List rewards; + public List blocks; protected boolean inArena, inLobby, inSpec, isReady; @@ -34,6 +36,7 @@ public class ArenaPlayer className = arena.classMap.get(player); rewards = new LinkedList(); + blocks = new LinkedList(); } public Player getPlayer() { return player; } diff --git a/src/com/garbagemule/MobArena/MABlockListener.java b/src/com/garbagemule/MobArena/MABlockListener.java index 109eab1..93fdd0a 100644 --- a/src/com/garbagemule/MobArena/MABlockListener.java +++ b/src/com/garbagemule/MobArena/MABlockListener.java @@ -1,8 +1,10 @@ package com.garbagemule.MobArena; +import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.block.BlockListener; import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPlaceEvent; public class MABlockListener extends BlockListener @@ -19,6 +21,12 @@ public class MABlockListener extends BlockListener for (Arena arena : am.arenas) arena.eventListener.onBlockBreak(event); } + + public void onBlockBurn(BlockBurnEvent event) + { + for (Arena arena : am.arenas) + arena.eventListener.onBlockBurn(event); + } public void onBlockPlace(BlockPlaceEvent event) { @@ -31,4 +39,10 @@ public class MABlockListener extends BlockListener for (Arena arena : am.arenas) arena.eventListener.onBlockIgnite(event); } + + public void onBlockPhysics(BlockPhysicsEvent event) + { + for (Arena arena : am.arenas) + arena.eventListener.onBlockPhysics(event); + } } \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MACommands.java b/src/com/garbagemule/MobArena/MACommands.java index 602dbaa..dcfea9a 100644 --- a/src/com/garbagemule/MobArena/MACommands.java +++ b/src/com/garbagemule/MobArena/MACommands.java @@ -11,6 +11,7 @@ import org.bukkit.Material; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.entity.Player; +import org.bukkit.block.ContainerBlock; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.CommandExecutor; @@ -55,14 +56,16 @@ public class MACommands implements CommandExecutor 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("delspawn"); // Delete a spawnpoint + COMMANDS.add("containers"); // List containers + COMMANDS.add("addcontainer"); // Add a container block + COMMANDS.add("delcontainer"); // Delete a container block COMMANDS.add("reset"); // Reset arena coordinates COMMANDS.add("addclass"); // Add a new class COMMANDS.add("delclass"); // Delete a class COMMANDS.add("checkdata"); // Check arena well formedness COMMANDS.add("auto-generate"); // Auto-generate arena COMMANDS.add("auto-degenerate"); // Restore cuboid - COMMANDS.add("lol"); } private boolean meanAdmins, showingRegion; private Server server; @@ -155,6 +158,10 @@ public class MACommands implements CommandExecutor if (p.isInsideVehicle()) p.leaveVehicle(); + // Take entry fee and store inventory + arena.takeFee(p); + if (!arena.emptyInvJoin) MAUtils.storeInventory(p); + // If player is in a bed, unbed! if (p.isSleeping()) { @@ -1070,6 +1077,77 @@ public class MACommands implements CommandExecutor return true; } + if (base.equals("containers")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.containers")) && !op) + { + MAUtils.tellPlayer(sender, Msg.MISC_NO_ACCESS); + return true; + } + + StringBuffer buffy = new StringBuffer(); + List containers = plugin.getConfig().getKeys("arenas." + am.selectedArena.configName() + ".coords.containers"); + + if (containers != null) + { + for (String s : containers) + { + buffy.append(s); + buffy.append(" "); + } + } + else + { + buffy.append(Msg.MISC_NONE); + } + + MAUtils.tellPlayer(sender, "Containers for arena '" + am.selectedArena.configName() + "': " + buffy.toString()); + return true; + } + + if (base.equals("addcontainer")) + { + if (!(player && plugin.has(p, "mobarena.setup.addchest")) && !op) + { + MAUtils.tellPlayer(sender, Msg.MISC_NO_ACCESS); + return true; + } + if (arg1 == null || !arg1.matches("^[a-zA-Z][a-zA-Z0-9]*$")) + { + MAUtils.tellPlayer(sender, "Usage: /ma addchest "); + return true; + } + if (!(p.getTargetBlock(null, 50).getState() instanceof ContainerBlock)) + { + MAUtils.tellPlayer(sender, "You must look at container."); + return true; + } + + MAUtils.setArenaCoord(plugin.getConfig(), am.selectedArena, "containers." + arg1, p.getTargetBlock(null, 50).getLocation()); + MAUtils.tellPlayer(sender, "Container '" + arg1 + "' added for arena \"" + am.selectedArena.configName() + "\""); + return true; + } + + if (base.equals("delcontainer")) + { + if (!console && !(player && plugin.has(p, "mobarena.setup.delcontainer")) && !op) + { + MAUtils.tellPlayer(sender, Msg.MISC_NO_ACCESS); + return true; + } + if (arg1 == null || !arg1.matches("^[a-zA-Z][a-zA-Z0-9]*$")) + { + MAUtils.tellPlayer(sender, "Usage: /ma delcontainer "); + return true; + } + + if (MAUtils.delArenaCoord(plugin.getConfig(), am.selectedArena, "containers." + arg1)) + MAUtils.tellPlayer(sender, "Container '" + arg1 + "' deleted for arena '" + am.selectedArena.configName() + "'"); + else + MAUtils.tellPlayer(sender, "Could not find the container '" + arg1 + "' for arena '" + am.selectedArena.configName() + "'"); + return true; + } + if (base.equals("checkdata")) { if (!console && !(player && plugin.has(p, "mobarena.setup.checkdata")) && !op) diff --git a/src/com/garbagemule/MobArena/MAListener.java b/src/com/garbagemule/MobArena/MAListener.java index eeba802..5b46fd8 100644 --- a/src/com/garbagemule/MobArena/MAListener.java +++ b/src/com/garbagemule/MobArena/MAListener.java @@ -11,12 +11,15 @@ import org.bukkit.block.Sign; import org.bukkit.entity.Entity; 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.BlockBurnEvent; +import org.bukkit.event.block.BlockEvent; import org.bukkit.event.block.BlockIgniteEvent; -import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; +import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityCombustEvent; @@ -41,6 +44,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.material.Attachable; import org.bukkit.material.Bed; import org.bukkit.material.Door; +import org.bukkit.material.MaterialData; import org.bukkit.material.Redstone; import com.garbagemule.MobArena.MAMessages.Msg; @@ -57,14 +61,40 @@ public class MAListener implements ArenaListener this.plugin = plugin; } + public void onBlockPhysics(BlockPhysicsEvent event) + { + if (!arena.inRegion(event.getBlock().getLocation()) || arena.softRestore) + return; + + MaterialData data = event.getBlock().getState().getData(); + if (data instanceof Attachable || data instanceof Bed || data instanceof Door || data instanceof Redstone) + event.setCancelled(true); + } + public void onBlockBreak(BlockBreakEvent event) { - if (!arena.inRegion(event.getBlock().getLocation()) || arena.edit || (!arena.protect && arena.running)) + if (onBlockDestroy(event)) return; + event.setCancelled(true); + } + + public void onBlockBurn(BlockBurnEvent event) + { + if (onBlockDestroy(event)) + return; + + event.setCancelled(true); + } + + private boolean onBlockDestroy(BlockEvent event) + { + if (!arena.inRegion(event.getBlock().getLocation()) || arena.edit || (!arena.protect && arena.running)) + return true; + Block b = event.getBlock(); if (arena.blocks.remove(b) || b.getType() == Material.TNT) - return; + return true; if (arena.softRestore && arena.running) { @@ -85,10 +115,10 @@ public class MAListener implements ArenaListener if (!arena.softRestoreDrops) b.setTypeId(0); - return; + return true; } - event.setCancelled(true); + return false; } public void onBlockPlace(BlockPlaceEvent event) @@ -104,6 +134,7 @@ public class MAListener implements ArenaListener if (mat == Material.WOODEN_DOOR || mat == Material.IRON_DOOR_BLOCK) arena.blocks.add(b.getRelative(0,1,0)); + return; } @@ -116,8 +147,21 @@ public class MAListener implements ArenaListener if (!arena.inRegion(event.getBlock().getLocation())) return; - if (event.getCause() == IgniteCause.LIGHTNING) - event.setCancelled(true); + switch (event.getCause()) + { + case LIGHTNING: + event.setCancelled(true); + break; + case SPREAD: + case FLINT_AND_STEEL: + if (arena.running) + arena.blocks.add(event.getBlock()); + else + event.setCancelled(true); + break; + default: + break; + } } public void onCreatureSpawn(CreatureSpawnEvent event) @@ -125,8 +169,12 @@ public class MAListener implements ArenaListener if (!arena.inRegion(event.getLocation())) // || event.getSpawnReason() == SpawnReason.CUSTOM) return; - // If running == true, setCancelled(false), and vice versa. - event.setCancelled(!arena.running); + LivingEntity entity = (LivingEntity) event.getEntity(); + if (arena.running && entity instanceof Slime) + arena.monsters.add(entity); + else + // If running == true, setCancelled(false), and vice versa. + event.setCancelled(!arena.running); } public void onEntityExplode(EntityExplodeEvent event) @@ -532,7 +580,7 @@ public class MAListener implements ArenaListener public void onPlayerTeleport(PlayerTeleportEvent event) { - if (arena.edit || !arena.enabled || !arena.setup || arena.allowWarp) + if (!arena.running || arena.edit || !arena.enabled || !arena.setup || arena.allowWarp) return; if (!arena.inRegion(event.getTo()) && !arena.inRegion(event.getFrom())) diff --git a/src/com/garbagemule/MobArena/MAMessages.java b/src/com/garbagemule/MobArena/MAMessages.java index c3a57f1..828ff5a 100644 --- a/src/com/garbagemule/MobArena/MAMessages.java +++ b/src/com/garbagemule/MobArena/MAMessages.java @@ -106,6 +106,11 @@ public class MAMessages { m.msg = msg; } + + public String toString() + { + return msg; + } } /** diff --git a/src/com/garbagemule/MobArena/MAPlayerListener.java b/src/com/garbagemule/MobArena/MAPlayerListener.java index 635e411..478c8a1 100644 --- a/src/com/garbagemule/MobArena/MAPlayerListener.java +++ b/src/com/garbagemule/MobArena/MAPlayerListener.java @@ -13,6 +13,7 @@ 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; @@ -90,6 +91,6 @@ public class MAPlayerListener extends PlayerListener { MAUtils.checkForUpdates(plugin, p, false); } - }, 100); + }, 60); } } diff --git a/src/com/garbagemule/MobArena/MASpawnThread.java b/src/com/garbagemule/MobArena/MASpawnThread.java index 6127b27..df0da9c 100644 --- a/src/com/garbagemule/MobArena/MASpawnThread.java +++ b/src/com/garbagemule/MobArena/MASpawnThread.java @@ -64,6 +64,10 @@ public class MASpawnThread implements Runnable if (arena.waveClear && wave > 1 && !arena.monsters.isEmpty()) return; + // Check if we're on a boss wave + if (!arena.waveClear && arena.bossWave != null) + return; + // Grant rewards (if any) for this wave grantRewards(wave); @@ -82,7 +86,7 @@ public class MASpawnThread implements Runnable { List tmp = new LinkedList(arena.monsters); for (Entity e : tmp) - if (e.isDead()) + if (e.isDead() || !arena.inRegion(e.getLocation())) arena.monsters.remove(e); } diff --git a/src/com/garbagemule/MobArena/MAUtils.java b/src/com/garbagemule/MobArena/MAUtils.java index 73b8706..13ddc69 100644 --- a/src/com/garbagemule/MobArena/MAUtils.java +++ b/src/com/garbagemule/MobArena/MAUtils.java @@ -15,6 +15,8 @@ import java.util.Map; import java.util.HashMap; import java.util.Random; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import net.minecraft.server.WorldServer; @@ -36,7 +38,7 @@ import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.MAMessages.Msg; import com.garbagemule.MobArena.util.EntityPosition; -import com.garbagemule.MobArena.util.MAInventoryItem; +import com.garbagemule.MobArena.util.InventoryItem; public class MAUtils { @@ -133,6 +135,20 @@ public class MAUtils // ///////////////////////////////////////////////////////////////////// */ + public static Map getArenaContainers(Configuration config, World world, String arena) + { + Map containers = new HashMap(); + String arenaPath = "arenas." + arena + ".coords.containers"; + + if (config.getKeys(arenaPath) == null) + return containers; + + for (String point : config.getKeys(arenaPath)) + containers.put(point, makeLocation(world, config.getString(arenaPath + "." + point))); + + return containers; + } + /** * Grab all the spawnpoints for a specific arena. */ @@ -353,11 +369,11 @@ public class MAUtils { backupFile.createNewFile(); - MAInventoryItem[] inv = new MAInventoryItem[armor.length + items.length]; + InventoryItem[] inv = new InventoryItem[armor.length + items.length]; for (int i = 0; i < armor.length; i++) - inv[i] = stackToItem(armor[i]); + inv[i] = InventoryItem.parseItemStack(armor[i]); for (int i = 0; i < items.length; i++) - inv[armor.length + i] = stackToItem(items[i]); + inv[armor.length + i] = InventoryItem.parseItemStack(items[i]); FileOutputStream fos = new FileOutputStream(backupFile); ObjectOutputStream oos = new ObjectOutputStream(fos); @@ -389,7 +405,7 @@ public class MAUtils // Grab the MAInventoryItem array from the backup-file. FileInputStream fis = new FileInputStream(backupFile); ObjectInputStream ois = new ObjectInputStream(fis); - MAInventoryItem[] fromFile = (MAInventoryItem[]) ois.readObject(); + InventoryItem[] fromFile = (InventoryItem[]) ois.readObject(); ois.close(); // Split that shit. @@ -397,17 +413,20 @@ public class MAUtils ItemStack[] items = new ItemStack[fromFile.length-4]; for (int i = 0; i < 4; i++) - armor[i] = itemToStack(fromFile[i]); + armor[i] = InventoryItem.toItemStack(fromFile[i]); for (int i = 4; i < fromFile.length; i++) - items[i - 4] = itemToStack(fromFile[i]); + items[i - 4] = InventoryItem.toItemStack(fromFile[i]); // Restore the inventory. PlayerInventory inv = p.getInventory(); inv.setArmorContents(armor); + for (int i = 0; i < items.length; i++) + inv.setItem(i, items[i]); + /* for (ItemStack stack : items) if (stack != null) inv.addItem(stack); - + */ // Remove the backup-file. backupFile.delete(); } @@ -421,20 +440,6 @@ public class MAUtils 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) { @@ -636,6 +641,20 @@ public class MAUtils // ///////////////////////////////////////////////////////////////////// */ + /** + * Check if a Location is inside two points (x1,y1,z1) (x2,y2,z2) + */ + public static boolean inRegion(Location loc, double x1, double y1, double z1, double x2, double y2, double z2) + { + double x = loc.getBlockX(); + double y = loc.getBlockY(); + double z = loc.getBlockZ(); + + return x >= x1 && x <= x2 && + y >= y1 && y <= y2 && + z >= z1 && z <= z2; + } + /** * 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. @@ -1153,6 +1172,7 @@ public class MAUtils // Open the connection and don't redirect. HttpURLConnection con = (HttpURLConnection) baseURI.toURL().openConnection(); + con.setConnectTimeout(5000); con.setInstanceFollowRedirects(false); String header = con.getHeaderField("Location"); @@ -1167,18 +1187,27 @@ public class MAUtils // 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!"); + // Set up the regex and matcher + Pattern regex = Pattern.compile("v([0-9]+-)*[0-9]+"); + Matcher matcher = regex.matcher(url); + if (!matcher.find()) return; + + // Split the version strings + String[] forumVersion = matcher.group().substring(1).split("-"); + String[] thisVersion = plugin.getDescription().getVersion().split("\\."); + + // If the current version is older than the forum version, notify. + for (int i = 0; i < Math.min(forumVersion.length, thisVersion.length); i++) + { + if (Integer.parseInt(forumVersion[i]) > Integer.parseInt(thisVersion[i])) + { + tellPlayer(p, "There is a new version of MobArena available!");; + return; + } } - // Otherwise, notify the player that there is a new version. - tellPlayer(p, "There is a new version of MobArena available!");; + if (response) tellPlayer(p, "Your version of MobArena is up to date!"); } catch (Exception e) { diff --git a/src/com/garbagemule/MobArena/MobArena.java b/src/com/garbagemule/MobArena/MobArena.java index dacad15..62a239b 100644 --- a/src/com/garbagemule/MobArena/MobArena.java +++ b/src/com/garbagemule/MobArena/MobArena.java @@ -1,6 +1,7 @@ package com.garbagemule.MobArena; import java.io.File; +import java.util.Random; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -20,12 +21,14 @@ import com.nijikokun.bukkit.Permissions.Permissions; import com.garbagemule.MobArena.util.FileUtils; import com.garbagemule.register.payment.Method; import com.garbagemule.register.payment.Methods; +import com.garbagemule.ArenaPlugin.ArenaPlugin; +import com.garbagemule.ArenaPlugin.Master; /** * MobArena * @author garbagemule */ -public class MobArena extends JavaPlugin +public class MobArena extends JavaPlugin implements ArenaPlugin { private Configuration config; private ArenaMaster am; @@ -40,8 +43,10 @@ public class MobArena extends JavaPlugin // Global variables public static PluginDescriptionFile desc; public static File dir, arenaDir; - public static final double MIN_PLAYER_DISTANCE = 256.0; + public static final double MIN_PLAYER_DISTANCE = 15.0; + public static final double MIN_PLAYER_DISTANCE_SQUARED = MIN_PLAYER_DISTANCE * MIN_PLAYER_DISTANCE; public static final int ECONOMY_MONEY_ID = -29; + public static Random random = new Random(); public void onEnable() { @@ -109,8 +114,10 @@ public class MobArena extends JavaPlugin // Register events. pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Highest, this); + pm.registerEvent(Event.Type.BLOCK_BURN, blockListener, Priority.Highest, this); pm.registerEvent(Event.Type.BLOCK_PLACE, blockListener, Priority.Highest, this); - pm.registerEvent(Event.Type.BLOCK_IGNITE, blockListener, Priority.Normal, this); + pm.registerEvent(Event.Type.BLOCK_PHYSICS, blockListener, Priority.Normal, this); + pm.registerEvent(Event.Type.BLOCK_IGNITE, blockListener, Priority.Highest, this); 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); @@ -174,6 +181,11 @@ public class MobArena extends JavaPlugin public ArenaMaster getAM() { return am; } // More convenient. public ArenaMaster getArenaMaster() { return am; } + public Master getMaster() + { + return am; + } + private String getHeader() { String sep = System.getProperty("line.separator"); diff --git a/src/com/garbagemule/MobArena/MobArenaHandler.java b/src/com/garbagemule/MobArena/MobArenaHandler.java index e399183..1b429f8 100644 --- a/src/com/garbagemule/MobArena/MobArenaHandler.java +++ b/src/com/garbagemule/MobArena/MobArenaHandler.java @@ -3,13 +3,12 @@ package com.garbagemule.MobArena; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; public class MobArenaHandler { - MobArena plugin; - boolean ma = false; + private MobArena plugin; /** * Primary constructor. @@ -17,26 +16,24 @@ public class MobArenaHandler */ public MobArenaHandler() { - Plugin maPlugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); - - if (maPlugin == null) - return; - - ma = true; - plugin = (MobArena) maPlugin; + plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); } + + + /*////////////////////////////////////////////////////////////////// + + REGION/LOCATION METHODS + + //////////////////////////////////////////////////////////////////*/ + /** - * Check if a Location is inside of an arena region. + * Check if a Location is inside of any 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; @@ -45,26 +42,50 @@ public class MobArenaHandler } /** - * Check if a Location is inside of a specific arena region. + * Check if a Location is inside of a specific arena region (by arena object). * @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)); } + public boolean inRegion(Arena arena, Location loc) + { + return (arena != null && arena.inRegion(loc)); + } + + /** + * Check if a Location is inside of a specific arena region (by arena name). + * @param arenaName The name of an arena + * @param loc A location + * @return true, if the Location is inside of the arena region. + */ + public boolean inRegion(String arenaName, Location loc) + { + Arena arena = plugin.getAM().getArenaWithName(arenaName); + if (arena == null) + throw new NullPointerException("There is no arena with that name"); + + return 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); } + 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); } + public boolean inEnabledRegion(Location loc) + { + return inRegion(loc, true, false); + } /** * Private helper method for inRunningRegion and inEnabledRegion @@ -76,7 +97,7 @@ public class MobArenaHandler 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; + if (plugin.getAM() == null) return false; // Return true if location is within just one arena's region. for (Arena arena : plugin.getAM().arenas) @@ -87,40 +108,124 @@ public class MobArenaHandler return false; } + + + /*////////////////////////////////////////////////////////////////// + + PLAYER/MONSTER/PET METHODS + + //////////////////////////////////////////////////////////////////*/ + + /** + * Check if a player is in a MobArena arena (by Player). + * @param player The player + * @return true, if the player is in an arena + */ + public boolean isPlayerInArena(Player player) + { + return (plugin.getAM().getArenaWithPlayer(player) != null); + } + + /** + * Check if a player is in a MobArena arena (by name). + * @param playerName The name of the player + * @return true, if the player is in an arena + */ + public boolean isPlayerInArena(String playerName) + { + return (plugin.getAM().getArenaWithPlayer(playerName) != null); + } + + /** + * Get the MobArena class of a given player. + * @param player The player + * @return The class name of the player if the player is in the arena, null otherwise + */ + public String getPlayerClass(Player player) + { + Arena arena = plugin.getAM().getArenaWithPlayer(player); + if (arena == null) return null; + + return arena.classMap.get(player); + } + + /** + * Get the MobArena class of a given player in a given arena. + * This method is faster than the above method, granted the Arena object is known. + * @param arena The MobArena arena to check in + * @param player The player to look up + * @return The class name of the player, if the player is in the arena, null otherwise + */ + public String getPlayerClass(Arena arena, Player player) + { + return arena.classMap.get(player); + } + + /** + * Check if a monster is in a MobArena arena. + * @param entity The monster entity + * @return true, if the monster is in an arena + */ + public boolean isMonsterInArena(LivingEntity entity) + { + return plugin.getAM().getArenaWithMonster(entity) != null; + } + + /** + * Check if a pet is in a MobArena arena. + * @param wolf The pet wolf + * @return true, if the pet is in an arena + */ + public boolean isPetInArena(LivingEntity wolf) + { + return plugin.getAM().getArenaWithPet(wolf) != null; + } + + + + /*////////////////////////////////////////////////////////////////// + + ARENA GETTERS + + //////////////////////////////////////////////////////////////////*/ + /** * 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; } + public Arena getArenaAtLocation(Location loc) + { + return plugin.getAM().getArenaAtLocation(loc); + } /** * 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; } + public Arena getArenaWithPlayer(Player p) + { + return plugin.getAM().getArenaWithPlayer(p); + } /** * 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; } + public Arena getArenaWithPet(Entity wolf) + { + return plugin.getAM().getArenaWithPet(wolf); + } /** * 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() + public Arena getArenaWithMonster(Entity monster) { - return ma; + return plugin.getAM().getArenaWithMonster(monster); } } diff --git a/src/com/garbagemule/MobArena/repairable/RepairableContainer.java b/src/com/garbagemule/MobArena/repairable/RepairableContainer.java index 958fb25..f4b8245 100644 --- a/src/com/garbagemule/MobArena/repairable/RepairableContainer.java +++ b/src/com/garbagemule/MobArena/repairable/RepairableContainer.java @@ -5,17 +5,28 @@ import org.bukkit.block.ContainerBlock; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import com.garbagemule.MobArena.util.InventoryItem; + public class RepairableContainer extends RepairableBlock { - private ItemStack[] contents; + private InventoryItem[] items; public RepairableContainer(BlockState state, boolean clear) { super(state); - + + // Grab the inventory and its contents Inventory inv = ((ContainerBlock) state).getInventory(); - contents = inv.getContents().clone(); + ItemStack[] contents = inv.getContents(); + // Initialize the items array + items = new InventoryItem[contents.length]; + + // Turn every ItemStack into an InventoryItem + for (int i = 0; i < items.length; i++) + items[i] = InventoryItem.parseItemStack(contents[i]); + + // Clear the inventory if prompted if (clear) inv.clear(); } @@ -31,7 +42,15 @@ public class RepairableContainer extends RepairableBlock { super.repair(); + // Grab the inventory ContainerBlock cb = (ContainerBlock) getWorld().getBlockAt(getX(),getY(),getZ()).getState(); - cb.getInventory().setContents(contents); + Inventory inv = cb.getInventory(); + + // Turn every InventoryItem into an ItemStack + for (int i = 0; i < items.length; i++) + { + InventoryItem item = items[i]; + inv.setItem(i, item != null ? item.toItemStack() : null); + } } } diff --git a/src/com/garbagemule/MobArena/util/InventoryItem.java b/src/com/garbagemule/MobArena/util/InventoryItem.java new file mode 100644 index 0000000..160bf84 --- /dev/null +++ b/src/com/garbagemule/MobArena/util/InventoryItem.java @@ -0,0 +1,259 @@ +package com.garbagemule.MobArena.util; + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; + +public class InventoryItem implements Serializable +{ + private static final long serialVersionUID = 739709220350581510L; + private int id; + private int amount; + private Byte data; + private short durability; + + /** + * Default constructor. + * @param id The data value/type id of the ItemStack + * @param amount The amount of the stack + * @param data The MaterialData (possibly null) of the stack + * @param durability The durability of the stack + */ + public InventoryItem(int id, int amount, Byte data, short durability) + { + this.id = id; + this.amount = amount; + this.data = data; + this.durability = durability; + } + + /** + * ItemStack constructor. + * @param stack The ItemStack to base the InventoryItem off of. + */ + public InventoryItem(ItemStack stack) + { + if (stack == null) + id = -1; + + id = stack.getTypeId(); + amount = stack.getAmount(); + + // In case of "odd" items, don't attempt to get data and durability + if (id < 0) return; + + data = stack.getData() == null ? null : stack.getData().getData(); + durability = stack.getDurability(); + } + + /** + * Static method for turning a (possibly null) InventoryItem into an ItemStack. + * The method is useful if it is unknown whether an InventoryItem object is + * null or not. + * @param item The Inventory item to convert + * @return An ItemStack representation of the InventoryItem, or null + */ + public static ItemStack toItemStack(InventoryItem item) + { + if (item == null) + return null; + + return item.toItemStack(); + } + + /** + * Static method for converting an ItemStack to an InventoryItems. + * @param stack The ItemStack to convert + * @return An InventoryItem representation of the ItemStack, or null + */ + public static InventoryItem parseItemStack(ItemStack stack) + { + if (stack == null) + return new InventoryItem(-1, -1, null, (short) 0); + + return new InventoryItem(stack); + } + + /** + * Static method for converting an ItemStack array to an InventoryItem array. + * @param stacks The ItemStack array + * @return An InventoryItem array + */ + public static InventoryItem[] parseItemStacks(ItemStack[] stacks) + { + InventoryItem[] items = new InventoryItem[stacks.length]; + + for (int i = 0; i < items.length; i++) + items[i] = parseItemStack(stacks[i]); + + return items; + } + + /** + * Convert a list of ItemStacks into an array of InventoryItems + * @param stacks List of ItemStacks to convert + * @return An InventoryItem array + */ + public static InventoryItem[] parseItemStacks(List stacks) + { + InventoryItem[] items = new InventoryItem[stacks.size()]; + + for (int i = 0; i < items.length; i++) + items[i] = parseItemStack(stacks.get(i)); + + return items; + } + + /** + * Static method for extracting all InventoryItems from an InventoryItem array. + * @param id The type id of the items to extract + * @param items The InventoryItem array + * @return A list of all InventoryItems removed + */ + public static List extractAllFromArray(int id, InventoryItem[] items) + { + List list = new LinkedList(); + + for (int i = 0; i < items.length; i++) + { + if (items[i].getTypeId() == id) + { + list.add(items[i]); + items[i].setTypeId(-1); + } + } + + return list; + } + + /** + * Static method for removing an InventoryItem from an InventoryItem array. + * @param item The InventoryItem to remove + * @param items The InventoryItem array to remove from + * @return true, if the item was removed successfully, false otherwise + */ + public static boolean removeItemFromArray(InventoryItem item, InventoryItem[] items) + { + // Grab the total amount to remove + int leftToRemove = item.getAmount(); + + for (int i = 0; i < items.length; i++) + { + if (items[i].getTypeId() != item.getTypeId()) + continue; + + // Grab the amount + int amount = items[i].getAmount(); + + // Reduce amount/nullify item + if (amount > leftToRemove) + { + items[i].setAmount(amount - leftToRemove); + leftToRemove = 0; + } + else + { + items[i].setTypeId(-1); + leftToRemove -= amount; + } + + // If nothing left to remove, return true. + if (leftToRemove == 0) + return true; + } + + return false; + } + + /** + * Get the data value/type id of the item + * @return A type id + */ + public int getTypeId() + { + return id; + } + + /** + * Set the data value/type id of the item + * @param id A type id + */ + public void setTypeId(int id) + { + this.id = id; + } + + /** + * Get the amount of the item + * @return An amount + */ + public int getAmount() + { + return amount; + } + + /** + * Set the amount of the item + * @param amount An amount + */ + public void setAmount(int amount) + { + this.amount = amount; + } + + /** + * Get the MaterialData of the item + * @return A MaterialData + */ + public MaterialData getData() + { + return new MaterialData(id, data == null ? (byte) 0 : data); + } + + /** + * Set the MaterialData of the item + * @param data A MaterialData + */ + public void setData(MaterialData data) + { + this.data = data.getData(); + } + + /** + * Get the durability of the item + * @return The item durability + */ + public short getDurability() + { + return durability; + } + + /** + * Set the durability of the item + * @param durability An item durability + */ + public void setDurability(short durability) + { + this.durability = durability; + } + + /** + * Convert this InventoryItem to an ItemStack representation + * @return An ItemStack representation of this InventoryItem, or null if the type id is -1 + */ + public ItemStack toItemStack() + { + if (id == -1) + return null; + + ItemStack stack = new ItemStack(id, amount, durability); + + if (data != null) + stack.setData(getData()); + + return stack; + } +} diff --git a/src/com/garbagemule/MobArena/util/WaveUtils.java b/src/com/garbagemule/MobArena/util/WaveUtils.java index 9321a8c..f9c53a3 100644 --- a/src/com/garbagemule/MobArena/util/WaveUtils.java +++ b/src/com/garbagemule/MobArena/util/WaveUtils.java @@ -12,6 +12,7 @@ import org.bukkit.entity.Player; import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; +import com.garbagemule.MobArena.MAUtils; import com.garbagemule.MobArena.MobArena; import com.garbagemule.MobArena.waves.*; import com.garbagemule.MobArena.waves.Wave.*; @@ -20,36 +21,56 @@ public class WaveUtils { /** * Get all the spawnpoints that have players nearby. - */ + */ public static List getValidSpawnpoints(Arena arena, Collection players) { + long start = System.nanoTime(); List result = new ArrayList(); + + double x1 = Double.NaN, y1 = Double.NaN, z1 = Double.NaN, // Bottom + x2 = Double.NaN, y2 = Double.NaN, z2 = Double.NaN; // Top + + // Get the region that the players span. + for (Player p : players) + { + double x = p.getLocation().getBlockX(); + double y = p.getLocation().getBlockY(); + double z = p.getLocation().getBlockZ(); + + // Initialize the coordinates if they aren't already. + if (Double.isNaN(x1)) + { + x1 = x; y1 = y; z1 = z; // Bottom + x2 = x; y2 = y; z2 = z; // Top + continue; + } + + // Update x + if (x < x1) x1 = x; + else if (x > x2) x2 = x; + + // Update y + if (y < y1) y1 = y; + else if (y > y2) y2 = y; + + // Update z + if (z < z1) z1 = z; + else if (z > z2) z2 = z; + } + + // Expand by the minimum player distance. + x1 -= MobArena.MIN_PLAYER_DISTANCE; y1 -= MobArena.MIN_PLAYER_DISTANCE; z1 -= MobArena.MIN_PLAYER_DISTANCE; + x2 += MobArena.MIN_PLAYER_DISTANCE; y2 += MobArena.MIN_PLAYER_DISTANCE; z2 += MobArena.MIN_PLAYER_DISTANCE; for (Location s : arena.getAllSpawnpoints()) - { - for (Player p : players) - { - // If the player somehow got out of the arena world, kick him. - if (!s.getWorld().getName().equals(p.getWorld().getName())) - { - MobArena.info("Player '" + p.getName() + "' is not in the right world. Kicking..."); - p.kickPlayer("[MobArena] Cheater! (Warped out of the arena world.)"); - continue; - } - - if (s.distanceSquared(p.getLocation()) > MobArena.MIN_PLAYER_DISTANCE) - continue; - + if (MAUtils.inRegion(s, x1, y1, z1, x2, y2, z2)) result.add(s); - break; - } - } // If no players are in range, just use all the spawnpoints. if (result.isEmpty()) { MobArena.warning("Spawnpoints of arena '" + arena.configName() + "' may be too far apart!"); - result.addAll(arena.getAllSpawnpoints()); + return arena.getAllSpawnpoints();//result.addAll(arena.getAllSpawnpoints()); } // Else, return the valid spawnpoints. @@ -75,7 +96,7 @@ public class WaveUtils } dist = p.getLocation().distanceSquared(e.getLocation()); - if (dist < current && dist < MobArena.MIN_PLAYER_DISTANCE) + if (dist < current && dist < MobArena.MIN_PLAYER_DISTANCE_SQUARED) { current = dist; result = p; diff --git a/src/com/garbagemule/MobArena/waves/BossAbility.java b/src/com/garbagemule/MobArena/waves/BossAbility.java new file mode 100644 index 0000000..6e66b2b --- /dev/null +++ b/src/com/garbagemule/MobArena/waves/BossAbility.java @@ -0,0 +1,316 @@ +package com.garbagemule.MobArena.waves; + +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Fireball; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import com.garbagemule.MobArena.Arena; +import com.garbagemule.MobArena.util.WaveUtils; + + +public enum BossAbility +{ + ARROWS("Arrow") + { + public void run(Arena arena, LivingEntity boss) + { + boss.shootArrow(); + } + }, + FIREBALLS("Fireball") + { + public void run(Arena arena, LivingEntity boss) + { + Location bLoc = boss.getLocation(); + Location loc = bLoc.add(bLoc.getDirection().normalize().multiply(2).toLocation(boss.getWorld(), bLoc.getYaw(), bLoc.getPitch())); + Fireball fireball = boss.getWorld().spawn(loc, Fireball.class); + fireball.setIsIncendiary(false); + } + }, + FIREAURA("Fire Aura") + { + public void run(Arena arena, LivingEntity boss) + { + for (Player p : getNearbyPlayers(arena, boss, 5)) + p.setFireTicks(20); + } + }, + LIGHTNINGAURA("Lightning Aura") + { + public void run(Arena arena, LivingEntity boss) + { + Location base = boss.getLocation(); + Location ne = base.getBlock().getRelative( 2, 0, 2).getLocation(); + Location nw = base.getBlock().getRelative(-2, 0, 2).getLocation(); + Location se = base.getBlock().getRelative( 2, 0, -2).getLocation(); + Location sw = base.getBlock().getRelative(-2, 0, -2).getLocation(); + + arena.getWorld().strikeLightning(ne); + arena.getWorld().strikeLightning(nw); + arena.getWorld().strikeLightning(se); + arena.getWorld().strikeLightning(sw); + } + }, + DISORIENTTARGET("Disorient Target") + { + public void run(Arena arena, LivingEntity boss) + { + LivingEntity target = getTarget(boss); + if (target == null) return; + + Location loc = target.getLocation(); + loc.setYaw(target.getLocation().getYaw() + 45 + (new Random()).nextInt(270)); + target.teleport(loc); + } + }, + ROOTTARGET("Root Target") + { + public void run(final Arena arena, LivingEntity boss) + { + final LivingEntity target = getTarget(boss); + if (target == null) return; + + final Location loc = target.getLocation(); + final int freezeTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(arena.getPlugin(), + new Runnable() + { + public void run() + { + if (arena.getLivingPlayers().contains(target)) + target.teleport(loc); + } + }, 3, 3); + + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(arena.getPlugin(), + new Runnable() + { + public void run() + { + Bukkit.getServer().getScheduler().cancelTask(freezeTaskId); + } + }, 45); + } + }, + LIVINGBOMB("Living Bomb") + { + public void run(final Arena arena, LivingEntity boss) + { + final LivingEntity target = getTarget(boss); + if (target == null) return; + + // Set the target on fire + target.setFireTicks(60); + + // Create an explosion after 3 seconds + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(arena.getPlugin(), + new Runnable() + { + public void run() + { + if (!arena.getLivingPlayers().contains(target)) + return; + + arena.getWorld().createExplosion(target.getLocation(), 2F); + for(Player p : getNearbyPlayers(arena, target, 3)) + p.setFireTicks(40); + } + }, 61); + } + }, + CHAINLIGHTNING("Chain Lightning") + { + public void run(Arena arena, LivingEntity boss) + { + final LivingEntity target = getTarget(boss); + if (target == null) return; + + strikeLightning(arena, (Player) target, new LinkedList()); + } + + private void strikeLightning(final Arena arena, final Player p, final List done) + { + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(arena.getPlugin(), + new Runnable() + { + public void run() + { + if (!arena.getLivingPlayers().contains(p)) + return; + + // Smite the target + arena.getWorld().strikeLightning(p.getLocation()); + done.add(p); + + // Grab all nearby players + List nearby = getNearbyPlayers(arena, p, 4); + + // Remove all that are "done", and return if empty + nearby.removeAll(done); + if (nearby.isEmpty()) return; + + // Otherwise, smite the next target! + strikeLightning(arena, nearby.get(0), done); + } + }, 8); + } + }, + WARPTOPLAYER("Warp") + { + public void run(Arena arena, LivingEntity boss) + { + List list = arena.getLivingPlayers(); + boss.teleport(list.get((new Random()).nextInt(list.size()))); + } + }, + THROWTARGET("Throw Target") + { + public void run(Arena arena, LivingEntity boss) + { + LivingEntity target = getTarget(boss); + if (target == null) return; + + Location bLoc = boss.getLocation(); + Location loc = target.getLocation(); + Vector v = new Vector(loc.getX() - bLoc.getX(), 0, loc.getZ() - bLoc.getZ()); + target.setVelocity(v.normalize().setY(0.8)); + } + }, + THROWNEARBY("Throw Nearby Players") + { + public void run(Arena arena, LivingEntity boss) + { + for (Player p : getNearbyPlayers(arena, boss, 5)) + { + Location bLoc = boss.getLocation(); + Location loc = p.getLocation(); + Vector v = new Vector(loc.getX() - bLoc.getX(), 0, loc.getZ() - bLoc.getZ()); + p.setVelocity(v.normalize().setY(0.8)); + } + } + }, + THROWDISTANT("Throw Distant Players") + { + public void run(Arena arena, LivingEntity boss) + { + for (Player p : getDistantPlayers(arena, boss, 8)) + { + Location bLoc = boss.getLocation(); + Location loc = p.getLocation(); + Vector v = new Vector(loc.getX() - bLoc.getX(), 0, loc.getZ() - bLoc.getZ()); + p.setVelocity(v.normalize().setY(0.8)); + } + } + }, + FETCHTARGET("Fetch Target") + { + public void run(Arena arena, LivingEntity boss) + { + LivingEntity target = getTarget(boss); + if (target != null) target.teleport(boss); + } + }, + FETCHNEARBY("Fetch Nearby Players") + { + public void run(Arena arena, LivingEntity boss) + { + for (Player p : getNearbyPlayers(arena, boss, 5)) + p.teleport(boss); + } + }, + FETCHDISTANT("Fetch Distant Players") + { + public void run(Arena arena, LivingEntity boss) + { + for (Player p : getDistantPlayers(arena, boss, 8)) + p.teleport(boss); + } + }; + + private String name; + + private BossAbility(String name) + { + this.name = name; + } + + /** + * The run-method that all boss abilities must define. + * The method is called in the ability cycle for the given boss. + * @param arena The Arena the boss is in + * @param boss The boss entity + */ + public abstract void run(Arena arena, LivingEntity boss); + + /** + * Get the target player of the LivingEntity if possible. + * @param entity The entity whose target to get + * @return The target player, or null + */ + protected LivingEntity getTarget(LivingEntity entity) + { + if (entity instanceof Creature) + { + LivingEntity target = null; + try + { + target = ((Creature) entity).getTarget(); + } + catch (Exception e) {} + + if (target instanceof Player) + return target; + } + return null; + } + + /** + * Get a list of nearby players + * @param arena The arena + * @param boss The boss + * @param x The 'radius' in which to grab players + * @return A list of nearby players + */ + protected List getNearbyPlayers(Arena arena, Entity boss, int x) + { + List result = new LinkedList(); + for (Entity e : boss.getNearbyEntities(x, x, x)) + if (arena.getLivingPlayers().contains(e)) + result.add((Player) e); + return result; + } + + /** + * Get a list of distant players + * @param arena The arena + * @param boss The boss + * @param x The 'radius' in which to exclude players + * @return A list of distant players + */ + protected List getDistantPlayers(Arena arena, Entity boss, int x) + { + List result = new LinkedList(); + for (Player p : arena.getLivingPlayers()) + if (p.getLocation().distanceSquared(boss.getLocation()) > x*x) + result.add(p); + return result; + } + + public static BossAbility fromString(String string) + { + return WaveUtils.getEnumFromString(BossAbility.class, string); + } + + public String toString() + { + return name; + } +} diff --git a/src/com/garbagemule/MobArena/waves/DefaultWave.java b/src/com/garbagemule/MobArena/waves/DefaultWave.java index d647ef9..01e09b7 100644 --- a/src/com/garbagemule/MobArena/waves/DefaultWave.java +++ b/src/com/garbagemule/MobArena/waves/DefaultWave.java @@ -9,8 +9,8 @@ import org.bukkit.Location; import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; -import com.garbagemule.MobArena.MAMessages.Msg; import com.garbagemule.MobArena.MAUtils; +import com.garbagemule.MobArena.MAMessages.Msg; import com.garbagemule.MobArena.util.WaveUtils; public class DefaultWave extends NormalWave diff --git a/src/com/garbagemule/MobArena/waves/MACreature.java b/src/com/garbagemule/MobArena/waves/MACreature.java index 4456787..ab7e274 100644 --- a/src/com/garbagemule/MobArena/waves/MACreature.java +++ b/src/com/garbagemule/MobArena/waves/MACreature.java @@ -9,6 +9,7 @@ import org.bukkit.entity.Slime; import org.bukkit.entity.Wolf; import com.garbagemule.MobArena.Arena; +import com.garbagemule.MobArena.MobArena; import com.garbagemule.MobArena.util.WaveUtils; public enum MACreature @@ -25,7 +26,6 @@ public enum MACreature POWERED_CREEPER(CreatureType.CREEPER), POWERED_CREEPERS(CreatureType.CREEPER), ANGRY_WOLF(CreatureType.WOLF), ANGRY_WOLVES(CreatureType.WOLF), HUMAN(CreatureType.MONSTER), HUMANS(CreatureType.MONSTER), - SLIME(CreatureType.SLIME), SLIMES(CreatureType.SLIME), GIANT(CreatureType.GIANT), GIANTS(CreatureType.GIANT), GHAST(CreatureType.GHAST), GHASTS(CreatureType.GHAST), @@ -33,7 +33,18 @@ public enum MACreature CHICKEN(CreatureType.CHICKEN), CHICKENS(CreatureType.CHICKEN), COW(CreatureType.COW), COWS(CreatureType.COW), PIG(CreatureType.PIG), PIGS(CreatureType.PIG), - SHEEP(CreatureType.SHEEP), EXPLODING_SHEEP(CreatureType.SHEEP); + SHEEP(CreatureType.SHEEP), + SQUID(CreatureType.SQUID), SQUIDS(CreatureType.SQUID), + + // Extended creatures + EXPLODING_SHEEP(CreatureType.SHEEP), + + // Slimes + SLIME(CreatureType.SLIME), SLIMES(CreatureType.SLIME), + SLIME_TINY(CreatureType.SLIME), SLIMES_TINY(CreatureType.SLIME), + SLIME_SMALL(CreatureType.SLIME), SLIMES_SMALL(CreatureType.SLIME), + SLIME_BIG(CreatureType.SLIME), SLIMES_BIG(CreatureType.SLIME), + SLIME_HUGE(CreatureType.SLIME), SLIMES_HUGE(CreatureType.SLIME); private CreatureType type; @@ -68,31 +79,26 @@ public enum MACreature case ANGRY_WOLVES: ((Wolf) e).setAngry(true); break; + case SLIME: case SLIMES: + ((Slime) e).setSize( (1 + MobArena.random.nextInt(3)) ); + break; + case SLIME_TINY: + case SLIMES_TINY: + ((Slime) e).setSize(1); + break; + case SLIME_SMALL: + case SLIMES_SMALL: ((Slime) e).setSize(2); - break; - default: break; - } - - return e; - } - - public static LivingEntity spawn(MACreature creature, World world, Location loc) - { - LivingEntity e = world.spawnCreature(loc, creature.type); - - switch (creature) - { - case POWERED_CREEPERS: - ((Creeper) e).setPowered(true); + case SLIME_BIG: + case SLIMES_BIG: + ((Slime) e).setSize(3); break; - case ANGRY_WOLVES: - ((Wolf) e).setAngry(true); + case SLIME_HUGE: + case SLIMES_HUGE: + ((Slime) e).setSize(4); break; - case SLIMES: - ((Slime) e).setSize(2); - break; default: break; } diff --git a/src/com/garbagemule/MobArena/waves/Wave.java b/src/com/garbagemule/MobArena/waves/Wave.java index e148289..e6d2690 100644 --- a/src/com/garbagemule/MobArena/waves/Wave.java +++ b/src/com/garbagemule/MobArena/waves/Wave.java @@ -1,18 +1,5 @@ package com.garbagemule.MobArena.waves; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Fireball; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.util.Vector; - import com.garbagemule.MobArena.Arena; import com.garbagemule.MobArena.util.WaveUtils; @@ -59,246 +46,10 @@ public interface Wave return (int) ( base * Math.pow(w, exp) ); } } - - public enum BossAbility - { - ARROWS("Arrow") - { - public void run(Arena arena, LivingEntity boss) - { - boss.shootArrow(); - } - }, - FIREBALLS("Fireball") - { - public void run(Arena arena, LivingEntity boss) - { - Location bLoc = boss.getLocation(); - Location loc = bLoc.add(bLoc.getDirection().normalize().multiply(2).toLocation(boss.getWorld(), bLoc.getYaw(), bLoc.getPitch())); - Fireball fireball = boss.getWorld().spawn(loc, Fireball.class); - fireball.setIsIncendiary(false); - } - }, - FIREAURA("Fire aura") - { - public void run(Arena arena, LivingEntity boss) - { - for (Player p : getNearbyPlayers(arena, boss, 5)) - p.setFireTicks(20); - } - }, - LIGHTNINGAURA("Lightning aura") - { - public void run(Arena arena, LivingEntity boss) - { - Location base = boss.getLocation(); - Location ne = base.getBlock().getRelative( 2, 0, 2).getLocation(); - Location nw = base.getBlock().getRelative(-2, 0, 2).getLocation(); - Location se = base.getBlock().getRelative( 2, 0, -2).getLocation(); - Location sw = base.getBlock().getRelative(-2, 0, -2).getLocation(); - arena.getWorld().strikeLightning(ne); - arena.getWorld().strikeLightning(nw); - arena.getWorld().strikeLightning(se); - arena.getWorld().strikeLightning(sw); - } - }, - DISORIENTTARGET("Disorient target") - { - public void run(Arena arena, LivingEntity boss) - { - LivingEntity target = getTarget(boss); - if (target == null) return; - - Location loc = target.getLocation(); - loc.setYaw(target.getLocation().getYaw() + 45 + (new Random()).nextInt(270)); - target.teleport(loc); - } - }, - ROOTTARGET("Root target") - { - public void run(final Arena arena, LivingEntity boss) - { - final LivingEntity target = getTarget(boss); - if (target == null) return; - - final Location loc = target.getLocation(); - final int freezeTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(arena.getPlugin(), - new Runnable() - { - public void run() - { - if (arena.getLivingPlayers().contains(target)) - target.teleport(loc); - } - }, 3, 3); - - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(arena.getPlugin(), - new Runnable() - { - public void run() - { - Bukkit.getServer().getScheduler().cancelTask(freezeTaskId); - } - }, 45); - } - }, - WARPTOPLAYER("Warp to player") - { - public void run(Arena arena, LivingEntity boss) - { - List list = arena.getLivingPlayers(); - boss.teleport(list.get((new Random()).nextInt(list.size()))); - } - }, - THROWTARGET("Throw target") - { - public void run(Arena arena, LivingEntity boss) - { - System.out.println("Throw target"); - LivingEntity target = getTarget(boss); - if (target == null) return; - - Location bLoc = boss.getLocation(); - Location loc = target.getLocation(); - Vector v = new Vector(loc.getX() - bLoc.getX(), 0, loc.getZ() - bLoc.getZ()); - target.setVelocity(v.normalize().setY(0.8)); - } - }, - THROWNEARBY("Throw nearby players") - { - public void run(Arena arena, LivingEntity boss) - { - for (Player p : getNearbyPlayers(arena, boss, 5)) - { - Location bLoc = boss.getLocation(); - Location loc = p.getLocation(); - Vector v = new Vector(loc.getX() - bLoc.getX(), 0, loc.getZ() - bLoc.getZ()); - p.setVelocity(v.normalize().setY(0.8)); - } - } - }, - THROWDISTANT("Throw distant players") - { - public void run(Arena arena, LivingEntity boss) - { - for (Player p : getDistantPlayers(arena, boss, 8)) - { - Location bLoc = boss.getLocation(); - Location loc = p.getLocation(); - Vector v = new Vector(loc.getX() - bLoc.getX(), 0, loc.getZ() - bLoc.getZ()); - p.setVelocity(v.normalize().setY(0.8)); - } - } - }, - FETCHTARGET("Fetch target") - { - public void run(Arena arena, LivingEntity boss) - { - LivingEntity target = getTarget(boss); - if (target != null) target.teleport(boss); - } - }, - FETCHNEARBY("Fetch nearby players") - { - public void run(Arena arena, LivingEntity boss) - { - for (Player p : getNearbyPlayers(arena, boss, 5)) - p.teleport(boss); - } - }, - FETCHDISTANT("Fetch distant players") - { - public void run(Arena arena, LivingEntity boss) - { - for (Player p : getDistantPlayers(arena, boss, 8)) - p.teleport(boss); - } - }; - - private String name; - - private BossAbility(String name) - { - this.name = name; - } - - /** - * The run-method that all boss abilities must define. - * The method is called in the ability cycle for the given boss. - * @param arena The Arena the boss is in - * @param boss The boss entity - */ - public abstract void run(Arena arena, LivingEntity boss); - - /** - * Get the target player of the LivingEntity if possible. - * @param entity The entity whose target to get - * @return The target player, or null - */ - protected LivingEntity getTarget(LivingEntity entity) - { - if (entity instanceof Creature) - { - LivingEntity target = null; - try - { - target = ((Creature) entity).getTarget(); - } - catch (Exception e) {} - - if (target instanceof Player) - return target; - } - return null; - } - - /** - * Get a list of nearby players - * @param arena The arena - * @param boss The boss - * @param x The 'radius' in which to grab players - * @return A list of nearby players - */ - protected List getNearbyPlayers(Arena arena, Entity boss, int x) - { - List result = new LinkedList(); - for (Entity e : boss.getNearbyEntities(x, x, x)) - if (arena.getLivingPlayers().contains(e)) - result.add((Player) e); - return result; - } - - /** - * Get a list of distant players - * @param arena The arena - * @param boss The boss - * @param x The 'radius' in which to exclude players - * @return A list of distant players - */ - protected List getDistantPlayers(Arena arena, Entity boss, int x) - { - List result = new LinkedList(); - for (Player p : arena.getLivingPlayers()) - if (p.getLocation().distanceSquared(boss.getLocation()) > x*x) - result.add(p); - return result; - } - - public static BossAbility fromString(String string) - { - return WaveUtils.getEnumFromString(BossAbility.class, string); - } - - public String toString() - { - return name; - } - } - public enum BossHealth { - LOW(5), MEDIUM(9), HIGH(14), PSYCHO(25); + LOW(8), MEDIUM(15), HIGH(25), PSYCHO(40); private int multiplier; private BossHealth(int multiplier)