diff --git a/MobArena.jar b/MobArena.jar index 44542fc..2794e4c 100644 Binary files a/MobArena.jar and b/MobArena.jar differ diff --git a/src/com/garbagemule/MobArena/ArenaManager.java b/src/com/garbagemule/MobArena/ArenaManager.java index a42a3b4..f3e38ed 100644 --- a/src/com/garbagemule/MobArena/ArenaManager.java +++ b/src/com/garbagemule/MobArena/ArenaManager.java @@ -386,7 +386,7 @@ public class ArenaManager String r = rewardMap.get(p); if (r.equals("")) continue; - tellPlayer(p, "You're gonna get some shit now, so be happy!"); + tellPlayer(p, "Here are all of your rewards!"); MAUtils.giveItems(p, r); } diff --git a/src/com/garbagemule/MobArena/MABlockListener.java b/src/com/garbagemule/MobArena/MABlockListener.java index cd67412..98dda83 100644 --- a/src/com/garbagemule/MobArena/MABlockListener.java +++ b/src/com/garbagemule/MobArena/MABlockListener.java @@ -1,5 +1,7 @@ package com.garbagemule.MobArena; +import org.bukkit.Material; +import org.bukkit.block.Block; import org.bukkit.event.block.BlockListener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; @@ -26,22 +28,26 @@ public class MABlockListener extends BlockListener if (!ArenaManager.isSetup || !ArenaManager.isProtected) return; - if (ArenaManager.blockSet.contains(event.getBlock())) + Block b = event.getBlock(); + + if (ArenaManager.blockSet.contains(b)) return; - if (MAUtils.inRegion(event.getBlock().getLocation())) + if (MAUtils.inRegion(b.getLocation())) event.setCancelled(true); } public void onBlockBreak(BlockBreakEvent event) - { + { if (!ArenaManager.isSetup || !ArenaManager.isProtected) return; - if (ArenaManager.blockSet.contains(event.getBlock())) + Block b = event.getBlock(); + + if (ArenaManager.blockSet.contains(b)) return; - if (MAUtils.inRegion(event.getBlock().getLocation())) + if (MAUtils.inRegion(b.getLocation())) event.setCancelled(true); } @@ -50,11 +56,13 @@ public class MABlockListener extends BlockListener if (!ArenaManager.isSetup || !ArenaManager.isProtected) return; - if (MAUtils.inRegion(event.getBlock().getLocation())) + Block b = event.getBlock(); + + if (MAUtils.inRegion(b.getLocation())) { if (ArenaManager.isRunning && ArenaManager.playerSet.contains(event.getPlayer())) { - ArenaManager.blockSet.add(event.getBlock()); + ArenaManager.blockSet.add(b); return; } diff --git a/src/com/garbagemule/MobArena/MACommands.java b/src/com/garbagemule/MobArena/MACommands.java index c9cc02d..ffd8b17 100644 --- a/src/com/garbagemule/MobArena/MACommands.java +++ b/src/com/garbagemule/MobArena/MACommands.java @@ -5,6 +5,9 @@ import org.bukkit.entity.Player; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.CommandExecutor; +import org.bukkit.entity.Creature; +import org.bukkit.entity.CreatureType; +import org.bukkit.entity.LivingEntity; public class MACommands implements CommandExecutor { @@ -55,19 +58,19 @@ public class MACommands implements CommandExecutor return true; } - if (cmd.equalsIgnoreCase("leave") || cmd.equalsIgnoreCase("l")) + if (cmd.equals("leave") || cmd.equals("l")) { ArenaManager.playerLeave(p); return true; } - if (cmd.equalsIgnoreCase("list") || cmd.equalsIgnoreCase("who")) + if (cmd.equals("list") || cmd.equals("who")) { ArenaManager.playerList(p); return true; } - if (cmd.equalsIgnoreCase("spectate") || cmd.equalsIgnoreCase("spec")) + if (cmd.equals("spectate") || cmd.equals("spec")) { ArenaManager.playerSpectate(p); return true; diff --git a/src/com/garbagemule/MobArena/MACreeperListener.java b/src/com/garbagemule/MobArena/MACreeperListener.java deleted file mode 100644 index 369c213..0000000 --- a/src/com/garbagemule/MobArena/MACreeperListener.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.garbagemule.MobArena; - -import org.bukkit.event.entity.EntityListener; -import org.bukkit.event.entity.EntityExplodeEvent; - -/** - * Very simple listener for preventing Creeper explosions from - * damaging the blocks of the arena. - */ -public class MACreeperListener extends EntityListener -{ - private MobArena plugin; - - public MACreeperListener(MobArena instance) - { - plugin = instance; - } - - public void onEntityExplode(EntityExplodeEvent event) - { - if (MAUtils.inRegion(event.getLocation())) - event.setCancelled(true); - } -} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MADisconnectListener.java b/src/com/garbagemule/MobArena/MADisconnectListener.java new file mode 100644 index 0000000..13a58df --- /dev/null +++ b/src/com/garbagemule/MobArena/MADisconnectListener.java @@ -0,0 +1,40 @@ +package com.garbagemule.MobArena; + +import java.util.List; +import java.util.Arrays; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerListener; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerKickEvent; + +/** + * This listener acts when a player is kicked or disconnected + * from the server. If 15 seconds pass, and the player hasn't + * reconnected, the player is forced to leave the arena. + */ +public class MADisconnectListener extends PlayerListener +{ + private MobArena plugin; + + public MADisconnectListener(MobArena instance) + { + plugin = instance; + } + + public void onPlayerQuit(PlayerQuitEvent event) + { + Player p = event.getPlayer(); + + if (ArenaManager.playerSet.contains(p)) + ArenaManager.playerLeave(p); + } + + public void onPlayerKick(PlayerKickEvent event) + { + Player p = event.getPlayer(); + + if (ArenaManager.playerSet.contains(p)) + ArenaManager.playerLeave(p); + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAMonsterListener.java b/src/com/garbagemule/MobArena/MAMonsterListener.java new file mode 100644 index 0000000..b4b878d --- /dev/null +++ b/src/com/garbagemule/MobArena/MAMonsterListener.java @@ -0,0 +1,77 @@ +package com.garbagemule.MobArena; + +import java.util.HashMap; +import org.bukkit.block.Block; +import org.bukkit.entity.Spider; +import org.bukkit.event.entity.EntityListener; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.event.entity.EntityTargetEvent.TargetReason; + +/** + * Prevents Creeper explosions from damaging the blocks of the + * arena, zombies and skeletons from burning in the sun, and + * monsters (mostly spiders) from losing their targets. + */ +public class MAMonsterListener extends EntityListener +{ + private MobArena plugin; + + public MAMonsterListener(MobArena instance) + { + plugin = instance; + } + + // Creeper explosions + public void onEntityExplode(EntityExplodeEvent event) + { + /* This could be done by simply cancelling the event, but that + * also cancels the explosion animation. This is a workaround. */ + if (MAUtils.inRegion(event.getLocation())) + { + // Don't drop any blocks. + event.setYield(0); + + // Store the blocks and their values. + final HashMap blockMap = new HashMap(); + for (Block b : event.blockList()) + { + blockMap.put(b, b.getTypeId()); + } + + // Wait a couple of ticks, then rebuild the blocks. + ArenaManager.server.getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + for (Block b : blockMap.keySet()) + { + b.getLocation().getBlock().setTypeId(blockMap.get(b)); + } + } + }, 3); + } + } + + // Zombie/skeleton combustion from the sun. + public void onEntityCombust(EntityCombustEvent event) + { + if (ArenaManager.monsterSet.contains(event.getEntity())) + event.setCancelled(true); + } + + // Monsters losing their targets. + public void onEntityTarget(EntityTargetEvent event) + { + if (!ArenaManager.isRunning) + return; + + if (!ArenaManager.monsterSet.contains(event.getEntity())) + return; + + if (event.getReason() == TargetReason.FORGOT_TARGET) + event.setCancelled(true); + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MASpawnThread.java b/src/com/garbagemule/MobArena/MASpawnThread.java index 124193f..58f3947 100644 --- a/src/com/garbagemule/MobArena/MASpawnThread.java +++ b/src/com/garbagemule/MobArena/MASpawnThread.java @@ -3,6 +3,7 @@ package com.garbagemule.MobArena; import java.util.List; import java.util.Random; import org.bukkit.Location; +import org.bukkit.entity.Wolf; import org.bukkit.entity.Slime; import org.bukkit.entity.Player; import org.bukkit.entity.Creature; @@ -17,10 +18,9 @@ import org.bukkit.entity.CreatureType; * host chooses. It is possible to create default waves that consist of * only one type of monster, or ones that have no creepers, for example. */ -// TO-DO: Allow custom special wave modulus. +// TO-DO: Allow custom special wave interval. // TO-DO: Allow custom special wave monsters. // TO-DO: Allow additional "default" waves. -// TO-DO: public class MASpawnThread implements Runnable { private int wave, noOfSpawnPoints, noOfPlayers; @@ -48,6 +48,7 @@ public class MASpawnThread implements Runnable public void run() { + long start = System.nanoTime(); // Check if we need to grant more rewards with the recurrent waves. for (Integer i : ArenaManager.everyWaveMap.keySet()) { @@ -91,6 +92,7 @@ public class MASpawnThread implements Runnable } wave++; + System.out.println("Spawns and rewards took " + (System.nanoTime() - start) + " ns"); } /** @@ -124,7 +126,8 @@ public class MASpawnThread implements Runnable // Grab a random target. ran = random.nextInt(noOfPlayers); Creature c = (Creature) e; - c.setTarget((Player)playerArray[ran]); + c.setTarget(MAUtils.getRandomPlayer()); + //c.setTarget((Player)playerArray[ran]); // This is faster, but unstable } } @@ -137,15 +140,15 @@ public class MASpawnThread implements Runnable CreatureType mob; int ran, count; - boolean lightning = false; - boolean slime = false; + boolean slime = false; + boolean wolf = false; - switch (random.nextInt(4)) + // 5 on purpose - Ghasts act weird in Overworld. + switch (random.nextInt(5)) { case 0: mob = CreatureType.CREEPER; count = noOfPlayers * 3; - lightning = true; break; case 1: mob = CreatureType.PIG_ZOMBIE; @@ -153,14 +156,19 @@ public class MASpawnThread implements Runnable break; case 2: mob = CreatureType.SLIME; - count = noOfPlayers * 5; + count = noOfPlayers * 4; slime = true; break; case 3: mob = CreatureType.MONSTER; - count = Math.max(2, noOfPlayers); + count = noOfPlayers + 1; break; case 4: + mob = CreatureType.WOLF; + count = noOfPlayers * 2; + wolf = true; + break; + case 5: mob = CreatureType.GHAST; count = Math.max(1, noOfPlayers - 2); break; @@ -178,6 +186,7 @@ public class MASpawnThread implements Runnable ArenaManager.monsterSet.add(e); if (slime) ((Slime)e).setSize(2); + if (wolf) ((Wolf)e).setAngry(true); // Slimes can't have targets, apparently. if (!(e instanceof Creature)) @@ -186,7 +195,8 @@ public class MASpawnThread implements Runnable // Grab a random target. ran = random.nextInt(noOfPlayers); Creature c = (Creature) e; - c.setTarget((Player)playerArray[ran]); + c.setTarget(MAUtils.getRandomPlayer()); + //c.setTarget((Player)playerArray[ran]); // This is faster, but unstable } // Lightning, just for effect ;) diff --git a/src/com/garbagemule/MobArena/MAUtils.java b/src/com/garbagemule/MobArena/MAUtils.java index 64f336f..18ef44d 100644 --- a/src/com/garbagemule/MobArena/MAUtils.java +++ b/src/com/garbagemule/MobArena/MAUtils.java @@ -459,7 +459,7 @@ public class MAUtils /* ///////////////////////////////////////////////////////////////////// // - VERIFICATION METHODS + MISC METHODS // ///////////////////////////////////////////////////////////////////// */ @@ -493,4 +493,15 @@ public class MAUtils ArenaManager.tellPlayer(p, "MobArena is set up and ready to roll!"); } } + + /** + * Turns the current set of players into an array, and grabs a random + * element out of it. + */ + public static Player getRandomPlayer() + { + Random random = new Random(); + Object[] array = ArenaManager.playerSet.toArray(); + return (Player) array[random.nextInt(array.length)]; + } } \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MobArena.java b/src/com/garbagemule/MobArena/MobArena.java index 6fe8b63..5412e0b 100644 --- a/src/com/garbagemule/MobArena/MobArena.java +++ b/src/com/garbagemule/MobArena/MobArena.java @@ -38,10 +38,10 @@ public class MobArena extends JavaPlugin PlayerListener dropListener = new MADropListener(this); PlayerListener readyListener = new MAReadyListener(this); PlayerListener teleportListener = new MATeleportListener(this); + PlayerListener discListener = new MADisconnectListener(this); BlockListener blockListener = new MABlockListener(this); - EntityListener creeperListener = new MACreeperListener(this); EntityListener damageListener = new MADamageListener(this); - // TO-DO: PlayerListener to check for player logout during battle. + EntityListener monsterListener = new MAMonsterListener(this); // TO-DO: PlayerListener to check for kills/deaths. // Register events. @@ -49,11 +49,15 @@ public class MobArena extends JavaPlugin pm.registerEvent(Event.Type.PLAYER_DROP_ITEM, dropListener, Priority.Normal, this); pm.registerEvent(Event.Type.PLAYER_INTERACT, readyListener, Priority.Normal, this); pm.registerEvent(Event.Type.PLAYER_TELEPORT, teleportListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_QUIT, discListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_KICK, discListener, Priority.Normal, this); pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Normal, this); pm.registerEvent(Event.Type.BLOCK_DAMAGE, blockListener, Priority.Normal, this); pm.registerEvent(Event.Type.BLOCK_PLACE, blockListener, Priority.Normal, this); - pm.registerEvent(Event.Type.ENTITY_EXPLODE, creeperListener, Priority.Normal, this); pm.registerEvent(Event.Type.ENTITY_DAMAGE, damageListener, Priority.Normal, this); + pm.registerEvent(Event.Type.ENTITY_EXPLODE, monsterListener, Priority.Normal, this); + pm.registerEvent(Event.Type.ENTITY_COMBUST, monsterListener, Priority.Normal, this); + pm.registerEvent(Event.Type.ENTITY_TARGET, monsterListener, Priority.Normal, this); System.out.println(pdfFile.getName() + " v" + pdfFile.getVersion() + " initialized." ); }