diff --git a/MobArena.jar b/MobArena.jar index caddbbf..f2dc2fb 100644 Binary files a/MobArena.jar and b/MobArena.jar differ diff --git a/src/com/garbagemule/MobArena/AbstractArena.java b/src/com/garbagemule/MobArena/AbstractArena.java index 92e1b3d..1af1abc 100644 --- a/src/com/garbagemule/MobArena/AbstractArena.java +++ b/src/com/garbagemule/MobArena/AbstractArena.java @@ -1,9 +1,29 @@ package com.garbagemule.MobArena; -import org.bukkit.entity.Player; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; -public abstract class AbstractArena -{ +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 +{ + + private String name; + private World world; + private MobArena plugin; + + private boolean enabled, setup, running; + private Set arenaPlayers, lobbyPlayers, readyPlayers, specPlayers; + private Map playerClassMap; + private Map locations; + private Map healthMap; + /** * Start the arena session. * This method should warp all players to their respective warp points, start all @@ -40,14 +60,31 @@ public abstract class AbstractArena * @param p A player * @precondition Calling canJoin(p) for the given player must return true. */ - public abstract void playerJoin(Player p); + public void playerJoin(Player p) + { + storePlayerData(p, p.getLocation()); + MAUtils.sitPets(p); + 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 abstract void playerLeave(Player p); + /* + public void playerLeave(Player p) + { + if (arenaPlayers.contains(p) || lobbyPlayers.contains(p)) + finishArenaPlayer(p); + + movePlayerToEntry(p); + discardPlayer(p); + + // End arena if possible. + endArena(); + }*/ /** * Player joins the spectator area. @@ -91,17 +128,46 @@ public abstract class AbstractArena * Check if the arena is enabled. * @return true, if the arena is enabled. */ - public abstract boolean isEnabled(); + 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 abstract boolean isSetup(); + public boolean isSetup() + { + return setup; + } /** * Check if the arena is running. * @return true, if the arena is running. */ - public abstract boolean isRunning(); + public boolean isRunning() + { + return running; + } + + public void storePlayerData(Player p, Location loc) + { + // TODO: Get this sorted out + //plugin.getAM().arenaMap.put(p, this); + + if (!locations.containsKey(p)) + locations.put(p, loc); + + if (!healthMap.containsKey(p)) + healthMap.put(p, p.getHealth()); + } + + public abstract void movePlayerToLobby(Player p); + + public abstract void movePlayerToSpec(Player p); + + public abstract void movePlayerToEntry(Player p); + + public abstract void restoreInvAndGiveRewards(final Player p); } diff --git a/src/com/garbagemule/MobArena/Arena.java b/src/com/garbagemule/MobArena/Arena.java index 3c84fbd..4338e58 100644 --- a/src/com/garbagemule/MobArena/Arena.java +++ b/src/com/garbagemule/MobArena/Arena.java @@ -5,6 +5,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -65,7 +66,6 @@ public class Arena protected Map distDefault, distSpecial; protected Map classMap; protected Map> classItems, classArmor; - protected Map>> classBonuses; protected List entryFee; // NEW IMPLEMENTATION @@ -76,7 +76,7 @@ public class Arena // Wave stuff //protected TreeSet singleWaves; //protected TreeSet recurrentWaves; - protected TreeSet singleWaves; + protected TreeSet singleWaves, singleWavesInstance; protected TreeSet recurrentWaves; protected BossWave bossWave; // @@ -176,6 +176,9 @@ public class Arena // Spawn pets. spawnPets(); + // Copy the singleWaves Set. + singleWavesInstance = new TreeSet(singleWaves); + // Start spawning monsters. startSpawning(); startBouncingSheep(); @@ -190,7 +193,7 @@ public class Arena // Announce and notify. MAUtils.tellAll(this, Msg.ARENA_START.get()); for (MobArenaListener listener : plugin.getAM().listeners) - listener.onArenaStart(); + listener.onArenaStart(this); return true; } @@ -211,6 +214,7 @@ public class Arena log.saveSessionData(); log.updateArenaTotals(); } + log.clearSessionData(); // Stop spawning. stopSpawning(); @@ -235,7 +239,7 @@ public class Arena // Notify listeners. for (MobArenaListener listener : plugin.getAM().listeners) - listener.onArenaEnd(); + listener.onArenaEnd(this); return true; } @@ -288,6 +292,10 @@ public class Arena MAUtils.sitPets(p); p.setHealth(20); movePlayerToLobby(p); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerJoin(this, p); } public void playerReady(Player p) @@ -304,14 +312,16 @@ public class Arena } public void playerLeave(Player p) - { - if (arenaPlayers.contains(p) || lobbyPlayers.contains(p)) - finishArenaPlayer(p); - //else if (lobbyPlayers.contains(p)) - // MAUtils.clearInventory(p); - + { + finishArenaPlayer(p); movePlayerToEntry(p); discardPlayer(p); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerLeave(this, p); + + // End arena if possible. endArena(); } @@ -321,7 +331,8 @@ public class Arena if (specOnDeath) { - resetPlayer(p); + //resetPlayer(p); + clearPlayer(p); movePlayerToSpec(p); } else @@ -334,9 +345,17 @@ public class Arena spawnThread.updateTargets(); MAUtils.tellAll(this, Msg.PLAYER_DIED.get(p.getName())); - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { public void run() { - endArena(); - }}); + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() + { + public void run() + { + endArena(); + } + }); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerDeath(this, p); } public void playerSpec(Player p, Location loc) @@ -451,7 +470,7 @@ public class Arena public void restoreInvAndGiveRewards(final Player p) { - final List rewards = log != null ? log.players.get(p).rewards : new LinkedList(); + final List rewards = log != null && log.players.get(p) != null ? log.players.get(p).rewards : new LinkedList(); final boolean hadRewards = rewardedPlayers.contains(p); Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, @@ -506,7 +525,8 @@ public class Arena p.teleport(entry); } - private void resetPlayer(Player p) + private void clearPlayer(Player p) + //private void resetPlayer(Player p) { if (healthMap.containsKey(p)) p.setHealth(healthMap.remove(p)); @@ -532,7 +552,8 @@ public class Arena { locations.remove(p); plugin.getAM().arenaMap.remove(p); - resetPlayer(p); + //resetPlayer(p); + clearPlayer(p); } /** @@ -542,6 +563,9 @@ public class Arena */ private void finishArenaPlayer(Player p) { + if (!arenaPlayers.contains(p) && !lobbyPlayers.contains(p)) + return; + MAUtils.clearInventory(p); restoreInvAndGiveRewards(p); @@ -948,11 +972,24 @@ public class Arena return classes; } - public Collection getSpawnpoints() + public Collection getAllSpawnpoints() { return spawnpoints.values(); } + public Collection getSpawnpoints() + { + List result = new ArrayList(spawnpoints.size()); + + for (Map.Entry entry : spawnpoints.entrySet()) + { + if (entry.getKey().matches("^*boss*$")) continue; + result.add(entry.getValue()); + } + + return !result.isEmpty() ? result : spawnpoints.values(); + } + public Location getBossSpawnpoint() { Location result = null; @@ -1023,7 +1060,6 @@ public class Arena return; // Reset the previousSize, cancel the previous timer, and start the new timer. - //spawnThread.setPreviousSize(monsters.size()); spawnThread.setPreviousSize(getMonsters().size()); Bukkit.getServer().getScheduler().cancelTask(spawnThread.getTaskId()); int id = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, @@ -1038,7 +1074,7 @@ public class Arena monsters.remove(e); // Compare the current size with the previous size. - if (monsters.size() < spawnThread.getPreviousSize() || spawnThread.getPreviousSize() == 0) + if (monsters.size() < spawnThread.getPreviousSize() || spawnThread.getPreviousSize() == 0 || bossWave != null) { resetIdleTimer(); return; diff --git a/src/com/garbagemule/MobArena/ArenaListener.java b/src/com/garbagemule/MobArena/ArenaListener.java index 27a242d..877ae02 100644 --- a/src/com/garbagemule/MobArena/ArenaListener.java +++ b/src/com/garbagemule/MobArena/ArenaListener.java @@ -1,6 +1,7 @@ package com.garbagemule.MobArena; import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityCombustEvent; @@ -20,7 +21,8 @@ import org.bukkit.event.player.PlayerTeleportEvent; public interface ArenaListener { public void onBlockBreak(BlockBreakEvent event); - public void onBlockPlace(BlockPlaceEvent event); + public void onBlockPlace(BlockPlaceEvent event); + public void onBlockIgnite(BlockIgniteEvent event); public void onCreatureSpawn(CreatureSpawnEvent event); public void onEntityExplode(EntityExplodeEvent event); public void onEntityCombust(EntityCombustEvent event); diff --git a/src/com/garbagemule/MobArena/ArenaMaster.java b/src/com/garbagemule/MobArena/ArenaMaster.java index 1fcf436..1cc7cba 100644 --- a/src/com/garbagemule/MobArena/ArenaMaster.java +++ b/src/com/garbagemule/MobArena/ArenaMaster.java @@ -13,7 +13,6 @@ import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.permissions.Permission; import org.bukkit.util.config.Configuration; public class ArenaMaster diff --git a/src/com/garbagemule/MobArena/Arenaz.java b/src/com/garbagemule/MobArena/Arenaz.java new file mode 100644 index 0000000..31ef9f6 --- /dev/null +++ b/src/com/garbagemule/MobArena/Arenaz.java @@ -0,0 +1,108 @@ +package com.garbagemule.MobArena; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public interface Arenaz +{ + /** + * 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, false otherwise + */ + 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. + * @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. + * @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. + * @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/MAArena.java b/src/com/garbagemule/MobArena/MAArena.java new file mode 100644 index 0000000..a61b028 --- /dev/null +++ b/src/com/garbagemule/MobArena/MAArena.java @@ -0,0 +1,6 @@ +package com.garbagemule.MobArena; + +public class MAArena +{ + +} diff --git a/src/com/garbagemule/MobArena/MABlockListener.java b/src/com/garbagemule/MobArena/MABlockListener.java index 677c58a..109eab1 100644 --- a/src/com/garbagemule/MobArena/MABlockListener.java +++ b/src/com/garbagemule/MobArena/MABlockListener.java @@ -1,5 +1,6 @@ package com.garbagemule.MobArena; +import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.block.BlockListener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; @@ -24,4 +25,10 @@ public class MABlockListener extends BlockListener for (Arena arena : am.arenas) arena.eventListener.onBlockPlace(event); } + + public void onBlockIgnite(BlockIgniteEvent event) + { + for (Arena arena : am.arenas) + arena.eventListener.onBlockIgnite(event); + } } \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAListener.java b/src/com/garbagemule/MobArena/MAListener.java index a9b09b2..0dca14f 100644 --- a/src/com/garbagemule/MobArena/MAListener.java +++ b/src/com/garbagemule/MobArena/MAListener.java @@ -15,6 +15,8 @@ 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.BlockIgniteEvent; +import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; @@ -95,6 +97,15 @@ public class MAListener implements ArenaListener // If the arena isn't running, or if the player isn't in the arena, cancel. event.setCancelled(true); } + + public void onBlockIgnite(BlockIgniteEvent event) + { + if (!arena.inRegion(event.getBlock().getLocation())) + return; + + if (event.getCause() == IgniteCause.LIGHTNING) + event.setCancelled(true); + } public void onCreatureSpawn(CreatureSpawnEvent event) { @@ -189,62 +200,6 @@ public class MAListener implements ArenaListener }, arena.repairDelay); } - public void onEntityCombust(EntityCombustEvent event) - { - if (arena.monsters.contains(event.getEntity())) - event.setCancelled(true); - } - - public void onEntityTarget(EntityTargetEvent event) - { - if (!arena.running || event.isCancelled()) - return; - - if (arena.pets.contains(event.getEntity())) - { - if (event.getReason() != TargetReason.TARGET_ATTACKED_OWNER && event.getReason() != TargetReason.OWNER_ATTACKED_TARGET) - return; - - if (!(event.getTarget() instanceof Player)) - return; - - // If the target is a player, cancel. - event.setCancelled(true); - return; - } - - if (arena.monsters.contains(event.getEntity())) - { - if (event.getReason() == TargetReason.FORGOT_TARGET) - { - event.setTarget(MAUtils.getClosestPlayer(event.getEntity(), arena)); - return; - } - - if (event.getReason() == TargetReason.TARGET_DIED) - { - event.setTarget(MAUtils.getClosestPlayer(event.getEntity(), arena)); - return; - } - - if (event.getReason() == TargetReason.CLOSEST_PLAYER) - if (!arena.arenaPlayers.contains(event.getTarget())) - event.setCancelled(true); - return; - } - } - - public void onEntityRegainHealth(EntityRegainHealthEvent event) - { - if (!arena.running) return; - - if (!(event.getEntity() instanceof Player) || !arena.arenaPlayers.contains((Player)event.getEntity())) - return; - - if (event.getRegainReason() == RegainReason.REGEN) - event.setCancelled(true); - } - public void onEntityDeath(EntityDeathEvent event) { if (event.getEntity() instanceof Player) @@ -267,7 +222,7 @@ public class MAListener implements ArenaListener if (damager instanceof Player) arena.playerKill((Player) damager); - + event.getDrops().clear(); arena.resetIdleTimer(); return; @@ -345,6 +300,12 @@ public class MAListener implements ArenaListener // Boss if (arena.bossWave != null && damagee.equals(arena.bossWave.getEntity())) { + if (event.getCause() == DamageCause.LIGHTNING) + { + event.setCancelled(true); + return; + } + // Subtract boss health, and reset actual entity health arena.bossWave.subtractHealth(event.getDamage()); arena.bossWave.getEntity().setHealth(200); @@ -358,9 +319,70 @@ public class MAListener implements ArenaListener arena.bossWave.clear(); arena.bossWave = null; } + else if (arena.bossWave.getHealth() <= 100 && !arena.bossWave.isLowHealthAnnounced()) + { + MAUtils.tellAll(arena, Msg.WAVE_BOSS_LOW_HEALTH.get()); + arena.bossWave.setLowHealthAnnounced(true); + } } } } + + public void onEntityCombust(EntityCombustEvent event) + { + if (arena.monsters.contains(event.getEntity())) + event.setCancelled(true); + } + + public void onEntityTarget(EntityTargetEvent event) + { + if (!arena.running || event.isCancelled()) + return; + + if (arena.pets.contains(event.getEntity())) + { + if (event.getReason() != TargetReason.TARGET_ATTACKED_OWNER && event.getReason() != TargetReason.OWNER_ATTACKED_TARGET) + return; + + if (!(event.getTarget() instanceof Player)) + return; + + // If the target is a player, cancel. + event.setCancelled(true); + return; + } + + if (arena.monsters.contains(event.getEntity())) + { + if (event.getReason() == TargetReason.FORGOT_TARGET) + { + event.setTarget(MAUtils.getClosestPlayer(event.getEntity(), arena)); + return; + } + + if (event.getReason() == TargetReason.TARGET_DIED) + { + event.setTarget(MAUtils.getClosestPlayer(event.getEntity(), arena)); + return; + } + + if (event.getReason() == TargetReason.CLOSEST_PLAYER) + if (!arena.arenaPlayers.contains(event.getTarget())) + event.setCancelled(true); + return; + } + } + + public void onEntityRegainHealth(EntityRegainHealthEvent event) + { + if (!arena.running) return; + + if (!(event.getEntity() instanceof Player) || !arena.arenaPlayers.contains((Player)event.getEntity())) + return; + + if (event.getRegainReason() == RegainReason.REGEN) + event.setCancelled(true); + } public void onPlayerAnimation(PlayerAnimationEvent event) { diff --git a/src/com/garbagemule/MobArena/MAMessages.java b/src/com/garbagemule/MobArena/MAMessages.java index 4d58d67..03caf4a 100644 --- a/src/com/garbagemule/MobArena/MAMessages.java +++ b/src/com/garbagemule/MobArena/MAMessages.java @@ -61,6 +61,7 @@ public class MAMessages WAVE_SWARM("Wave #%! [SWARM]"), WAVE_BOSS("Wave #%! [BOSS]"), WAVE_BOSS_ABILITY("Boss used ability: %!"), + WAVE_BOSS_LOW_HEALTH("Boss is almost dead!"), WAVE_REWARD("You just earned a reward: %"), MISC_LIST_PLAYERS("Live players: %"), MISC_LIST_ARENAS("Available arenas: %"), diff --git a/src/com/garbagemule/MobArena/MASpawnThread.java b/src/com/garbagemule/MobArena/MASpawnThread.java index 61cc640..6127b27 100644 --- a/src/com/garbagemule/MobArena/MASpawnThread.java +++ b/src/com/garbagemule/MobArena/MASpawnThread.java @@ -43,7 +43,7 @@ public class MASpawnThread implements Runnable // WAVES defaultWave = arena.recurrentWaves.first(); recurrentWaves = arena.recurrentWaves; - singleWaves = arena.singleWaves; + singleWaves = new TreeSet(arena.singleWaves); this.plugin = plugin; this.arena = arena; @@ -111,6 +111,10 @@ public class MASpawnThread implements Runnable w = matches.isEmpty() ? defaultWave : matches.last(); } + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onWave(arena, wave, w.getName(), w.getBranch(), w.getType()); + w.spawn(wave); } diff --git a/src/com/garbagemule/MobArena/MobArena.java b/src/com/garbagemule/MobArena/MobArena.java index 298d802..7eaa922 100644 --- a/src/com/garbagemule/MobArena/MobArena.java +++ b/src/com/garbagemule/MobArena/MobArena.java @@ -1,7 +1,6 @@ package com.garbagemule.MobArena; import java.io.File; -import java.util.Map; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -10,7 +9,6 @@ import org.bukkit.event.Event.Priority; import org.bukkit.event.block.BlockListener; import org.bukkit.event.player.PlayerListener; import org.bukkit.event.entity.EntityListener; -import org.bukkit.permissions.Permission; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; @@ -87,7 +85,7 @@ public class MobArena extends JavaPlugin am.arenaMap.clear(); // Permissions & Economy - permissionHandler = null; + //permissionHandler = null; if (Methods != null && Methods.hasMethod()) { Methods = null; @@ -100,12 +98,6 @@ public class MobArena extends JavaPlugin private void loadConfig() { File file = new File(dir, "config.yml"); - if (!file.exists()) - { - error("Config-file could not be created!"); - return; - } - config = new Configuration(file); config.load(); config.setHeader(getHeader()); @@ -125,6 +117,9 @@ public class MobArena extends JavaPlugin BlockListener blockListener = new MABlockListener(am); // Register events. + pm.registerEvent(Event.Type.BLOCK_BREAK, 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.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); @@ -133,8 +128,6 @@ public class MobArena extends JavaPlugin pm.registerEvent(Event.Type.PLAYER_KICK, playerListener, Priority.Normal, this); pm.registerEvent(Event.Type.PLAYER_JOIN, playerListener, Priority.Normal, this); pm.registerEvent(Event.Type.PLAYER_ANIMATION, playerListener, Priority.Normal, this); - pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Highest, this); - pm.registerEvent(Event.Type.BLOCK_PLACE, blockListener, Priority.Highest, this); pm.registerEvent(Event.Type.ENTITY_DAMAGE, entityListener, Priority.High, this); // mcMMO is "Highest" pm.registerEvent(Event.Type.ENTITY_DEATH, entityListener, Priority.Lowest, this); // Lowest because of Tombstone pm.registerEvent(Event.Type.ENTITY_REGAIN_HEALTH, entityListener, Priority.Normal, this); @@ -168,11 +161,13 @@ public class MobArena extends JavaPlugin public static void warning(String msg) { Bukkit.getServer().getLogger().warning("[MobArena] " + msg); } public static void error(String msg) { Bukkit.getServer().getLogger().severe("[MobArena] " + msg); } + /* private void setupSuperPerms() { getServer().getPluginManager().addPermission(new Permission("mobarena.classes")); getServer().getPluginManager().addPermission(new Permission("mobarena.arenas")); } + */ private void setupPermissions() { diff --git a/src/com/garbagemule/MobArena/MobArenaListener.java b/src/com/garbagemule/MobArena/MobArenaListener.java index 1613774..5737773 100644 --- a/src/com/garbagemule/MobArena/MobArenaListener.java +++ b/src/com/garbagemule/MobArena/MobArenaListener.java @@ -3,6 +3,9 @@ package com.garbagemule.MobArena; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import com.garbagemule.MobArena.waves.Wave.WaveBranch; +import com.garbagemule.MobArena.waves.Wave.WaveType; + public class MobArenaListener { protected MobArena plugin; @@ -13,11 +16,10 @@ public class MobArenaListener plugin.getAM().listeners.add(this); } - public void onArenaStart() {} - public void onArenaEnd() {} - public void onDefaultWave(int waveNumber) {} - public void onSpecialWave(int waveNumber, int specialwaveNumber) {} - public void onPlayerJoin(Player p) {} - public void onPlayerLeave(Player p) {} - public void onPlayerDeath(Player p) {} + public void onArenaStart(Arena arena) {} + public void onArenaEnd(Arena arena) {} + public void onWave(Arena arena, int waveNumber, String waveName, WaveBranch waveBranch, WaveType waveType) {} + public void onPlayerJoin(Arena arena, Player p) {} + public void onPlayerLeave(Arena arena, Player p) {} + public void onPlayerDeath(Arena arena, Player p) {} } diff --git a/src/com/garbagemule/MobArena/util/WaveUtils.java b/src/com/garbagemule/MobArena/util/WaveUtils.java index 6fcb109..eae6358 100644 --- a/src/com/garbagemule/MobArena/util/WaveUtils.java +++ b/src/com/garbagemule/MobArena/util/WaveUtils.java @@ -375,7 +375,7 @@ public class WaveUtils { for (String ability : abilities.split(",")) { - if (BossAbility.fromString(ability.trim().replaceAll("-", "_").toUpperCase()) != null) + if (BossAbility.fromString(ability.trim().replaceAll("[-_\\.]", "").toUpperCase()) != null) continue; MobArena.warning("Invalid boss ability '" + ability + "' in " + path); diff --git a/src/com/garbagemule/MobArena/util/data/XML.java b/src/com/garbagemule/MobArena/util/data/XML.java index fdf00d8..2ca86ac 100644 --- a/src/com/garbagemule/MobArena/util/data/XML.java +++ b/src/com/garbagemule/MobArena/util/data/XML.java @@ -56,20 +56,11 @@ public class XML p.addContent(new Element("hits").addContent(ap.hits + "")); // Rewards - Element rewards = new Element("rewards"); + Element rw = new Element("rewards"); for (ItemStack stack : ap.rewards) - { - // TODO: Move this to a method - boolean money = stack.getTypeId() == MobArena.ECONOMY_MONEY_ID; - Element r = new Element("reward"); - r.setAttribute(new Attribute("id", stack.getTypeId() + "")); - r.setAttribute(new Attribute("material", money ? "money" : stack.getType().toString().toLowerCase())); - r.setAttribute(new Attribute("data", money || stack.getData() == null ? "0" : stack.getData().toString().toLowerCase())); - r.setAttribute(new Attribute("amount", stack.getAmount() + "")); - - rewards.addContent(r); - } - p.addContent(rewards); + rw.addContent(getReward(stack)); + + p.addContent(rw); pd.addContent(p); } @@ -115,20 +106,8 @@ public class XML // Rewards Element rw = new Element("rewards"); for (ArenaPlayer ap : log.players.values()) - { for (ItemStack stack : ap.rewards) - { - // TODO: Move this to a method - boolean money = stack.getTypeId() == MobArena.ECONOMY_MONEY_ID; - Element r = new Element("reward"); - r.setAttribute(new Attribute("id", stack.getTypeId() + "")); - r.setAttribute(new Attribute("material", money ? "money" : stack.getType().toString().toLowerCase())); - r.setAttribute(new Attribute("data", money || stack.getData() == null ? "0" : stack.getData().toString().toLowerCase())); - r.setAttribute(new Attribute("amount", stack.getAmount() + "")); - - rw.addContent(r); - } - } + rw.addContent(getReward(stack)); // Players Element pl = new Element("players"); @@ -172,6 +151,19 @@ public class XML serialize(log, dir, doc, "totals.xml"); } + private static Element getReward(ItemStack stack) + { + boolean money = stack.getTypeId() == MobArena.ECONOMY_MONEY_ID; + + Element result = new Element("reward"); + result.setAttribute(new Attribute("id", stack.getTypeId() + "")); + result.setAttribute(new Attribute("material", money ? "money" : stack.getType().toString().toLowerCase())); + result.setAttribute(new Attribute("data", money || stack.getData() == null ? "0" : stack.getData().toString().toLowerCase())); + result.setAttribute(new Attribute("amount", stack.getAmount() + "")); + + return result; + } + private static void serialize(ArenaLog log, File dir, Document doc, String filename) { try diff --git a/src/com/garbagemule/MobArena/waves/BossWave.java b/src/com/garbagemule/MobArena/waves/BossWave.java index 73a8ccd..31c6243 100644 --- a/src/com/garbagemule/MobArena/waves/BossWave.java +++ b/src/com/garbagemule/MobArena/waves/BossWave.java @@ -4,7 +4,12 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import net.minecraft.server.WorldServer; + import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.entity.Creature; import org.bukkit.entity.LivingEntity; import org.bukkit.util.config.Configuration; @@ -14,7 +19,7 @@ import com.garbagemule.MobArena.MAUtils; import com.garbagemule.MobArena.MAMessages.Msg; import com.garbagemule.MobArena.util.WaveUtils; -public class BossWave extends AbstractWave// TODO: implement/extend something? +public class BossWave extends AbstractWave { private MACreature boss; private LivingEntity bossCreature; @@ -23,6 +28,7 @@ public class BossWave extends AbstractWave// TODO: implement/extend something? private BossHealth bossHealth; private int healthAmount; private List taskList; + private boolean lowHealthAnnounced = false; // Recurrent public BossWave(Arena arena, String name, int wave, int frequency, int priority, Configuration config, String path) @@ -54,7 +60,7 @@ public class BossWave extends AbstractWave// TODO: implement/extend something? { for (String a : abilities.split(",")) { - String ability = a.trim().replaceAll("-", "_").toUpperCase(); + String ability = a.trim().replaceAll("[-_\\.]", "").toUpperCase(); addAbility(BossAbility.fromString(ability)); } } @@ -94,10 +100,10 @@ public class BossWave extends AbstractWave// TODO: implement/extend something? public void run() { // Announce ability - MAUtils.tellAll(getArena(), Msg.WAVE_BOSS_ABILITY.get(MAUtils.toCamelCase(ability.toString()))); + MAUtils.tellAll(getArena(), Msg.WAVE_BOSS_ABILITY.get(ability.toString())); // Activate! - ability.activate(getArena(), bossCreature); + ability.run(getArena(), bossCreature); } }, 50*i, 50*abilityCount); @@ -117,8 +123,14 @@ public class BossWave extends AbstractWave// TODO: implement/extend something? { cancelAbilityTasks(); getArena().setBossWave(null); - getWorld().createExplosion(bossCreature.getLocation(), 1); - bossCreature.damage(32768); + + CraftEntity ce = (CraftEntity) bossCreature; + CraftWorld cw = (CraftWorld) getWorld(); + WorldServer ws = cw.getHandle(); + Location l = bossCreature.getLocation(); + ws.createExplosion(ce.getHandle(), l.getX(), l.getY() + 1, l.getZ(), 1f, false); + + bossCreature.remove(); } public void addAbility(BossAbility ability) @@ -131,16 +143,16 @@ public class BossWave extends AbstractWave// TODO: implement/extend something? adds.add(creature); } - public int getHealth() - { - return healthAmount; - } - public LivingEntity getEntity() { return bossCreature; } + public int getHealth() + { + return healthAmount; + } + public void setHealth(int healthAmount) { this.healthAmount = healthAmount; @@ -150,4 +162,14 @@ public class BossWave extends AbstractWave// TODO: implement/extend something? { healthAmount -= amount; } + + public boolean isLowHealthAnnounced() + { + return lowHealthAnnounced; + } + + public void setLowHealthAnnounced(boolean value) + { + lowHealthAnnounced = value; + } } diff --git a/src/com/garbagemule/MobArena/waves/MACreature.java b/src/com/garbagemule/MobArena/waves/MACreature.java index 5e38e90..4456787 100644 --- a/src/com/garbagemule/MobArena/waves/MACreature.java +++ b/src/com/garbagemule/MobArena/waves/MACreature.java @@ -33,13 +33,7 @@ public enum MACreature CHICKEN(CreatureType.CHICKEN), CHICKENS(CreatureType.CHICKEN), COW(CreatureType.COW), COWS(CreatureType.COW), PIG(CreatureType.PIG), PIGS(CreatureType.PIG), - SHEEP(CreatureType.SHEEP); - - // Misc - // EXPLODING_SHEEP(CreatureType.SHEEP), // Explode (power: 1) when close enough to players - // PLAGUED_PIGS(CreatureType.PIG), // Damage "aura" (getNearbyEntities) - // MAD_COWS(CreatureType.COW); // Ram/throw players - // + SHEEP(CreatureType.SHEEP), EXPLODING_SHEEP(CreatureType.SHEEP); private CreatureType type; @@ -65,6 +59,7 @@ public enum MACreature switch (this) { case SHEEP: + case EXPLODING_SHEEP: arena.addExplodingSheep(e); break; case POWERED_CREEPERS: diff --git a/src/com/garbagemule/MobArena/waves/Wave.java b/src/com/garbagemule/MobArena/waves/Wave.java index eb6742c..22d54d6 100644 --- a/src/com/garbagemule/MobArena/waves/Wave.java +++ b/src/com/garbagemule/MobArena/waves/Wave.java @@ -2,7 +2,9 @@ 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; @@ -33,7 +35,7 @@ public interface Wave public enum WaveGrowth { - OLD(0), SLOW(0.5), MEDIUM(0.65), FAST(0.8), PSYCHO(1.1); + OLD(0), SLOW(0.5), MEDIUM(0.65), FAST(0.8), PSYCHO(1.2); private double exp; private WaveGrowth(double exp) @@ -60,86 +62,215 @@ public interface Wave public enum BossAbility { - ARROWS, FIREBALLS, FIRE_AURA, THROW_TARGET, THROW_NEARBY, FETCH_TARGET, FETCH_DISTANT; - - public static BossAbility fromString(String string) + ARROWS("Arrow") { - return WaveUtils.getEnumFromString(BossAbility.class, string); - } - - public void activate(Arena arena, LivingEntity boss) - { - LivingEntity target = getTarget(boss); - Location bLoc = boss.getLocation(); - Location loc; - - switch (this) + public void run(Arena arena, LivingEntity boss) { - // Fire an arrow in the direction the boss is facing. - case ARROWS: - System.out.println("Shooting arrow"); - boss.shootArrow(); - break; - // Hurl a fireball in the direction the boss is facing. - case FIREBALLS: - System.out.println("Shooting fireball"); - 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); - break; - // Set fire to all players nearby. - case FIRE_AURA: - System.out.println("Fire aura"); - for (Player p : getNearbyPlayers(arena, boss, 5)) - p.setFireTicks(20); - break; - // Throw target back - case THROW_TARGET: - System.out.println("Throw target"); - if (target != null) - { - loc = target.getLocation(); - Vector v = new Vector(loc.getX() - bLoc.getX(), 0, loc.getZ() - bLoc.getZ()); - target.setVelocity(v.normalize().setY(0.8)); - } - break; - // Throw nearby players back - case THROW_NEARBY: - System.out.println("Throw nearby"); - for (Player p : getNearbyPlayers(arena, boss, 5)) - { - loc = p.getLocation(); - Vector v = new Vector(loc.getX() - bLoc.getX(), 0, loc.getZ() - bLoc.getZ()); - p.setVelocity(v.normalize().setY(0.8)); - } - break; - // Warp target to boss - case FETCH_TARGET: - System.out.println("Fetch target"); - if (target != null) target.teleport(boss); - break; - // Warp nearby players to boss - case FETCH_DISTANT: - System.out.println("Fetch distant"); - for (Player p : getDistantPlayers(arena, boss, 8)) - p.teleport(boss); - default: - break; + System.out.println("Shooting arrow"); + boss.shootArrow(); } + }, + FIREBALLS("Fireball") + { + public void run(Arena arena, LivingEntity boss) + { + System.out.println("Shooting fireball"); + 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) + { + System.out.println("Fire aura"); + for (Player p : getNearbyPlayers(arena, boss, 5)) + p.setFireTicks(20); + } + }, + LIGHTNINGAURA("Lightning aura") + { + public void run(Arena arena, LivingEntity boss) + { + System.out.println("Lightning aura."); + 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) + { + System.out.println("Intimidate target"); + 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) + { + System.out.println("Throw nearby"); + 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) + { + System.out.println("Throw distant"); + 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) + { + System.out.println("Fetch target"); + LivingEntity target = getTarget(boss); + if (target != null) target.teleport(boss); + } + }, + FETCHNEARBY("Fetch nearby players") + { + public void run(Arena arena, LivingEntity boss) + { + System.out.println("Fetch nearby"); + for (Player p : getNearbyPlayers(arena, boss, 5)) + p.teleport(boss); + } + }, + FETCHDISTANT("Fetch distant players") + { + public void run(Arena arena, LivingEntity boss) + { + System.out.println("Fetch distant"); + for (Player p : getDistantPlayers(arena, boss, 8)) + p.teleport(boss); + } + }; + + private String name; + + private BossAbility(String name) + { + this.name = name; } - private LivingEntity getTarget(LivingEntity entity) + /** + * 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 = ((Creature) entity).getTarget(); + LivingEntity target = null; + try + { + target = ((Creature) entity).getTarget(); + } + catch (Exception e) {} + if (target instanceof Player) return target; } return null; } - private List getNearbyPlayers(Arena arena, Entity boss, int x) + /** + * 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)) @@ -148,7 +279,14 @@ public interface Wave return result; } - private List getDistantPlayers(Arena arena, Entity boss, int x) + /** + * 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()) @@ -156,11 +294,21 @@ public interface Wave 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(8), HIGH(12), PSYCHO(20); + LOW(5), MEDIUM(9), HIGH(14), PSYCHO(25); private int multiplier; private BossHealth(int multiplier) @@ -181,7 +329,7 @@ public interface Wave public enum SwarmAmount { - LOW(10), MEDIUM(20), HIGH(30), PSYCHO(50); + LOW(10), MEDIUM(20), HIGH(30), PSYCHO(60); private int multiplier; private SwarmAmount(int multiplier) @@ -213,6 +361,12 @@ public interface Wave * @return The WaveType of this Wave. */ public WaveType getType(); + + /** + * Get the branch type. + * @return The WaveBranch of this Wave. + */ + public WaveBranch getBranch(); /** * Get the growth rate of this wave.