Revamped valid spawnpoint algorithm.

This commit is contained in:
Garbage Mule 2011-08-18 16:56:09 +02:00
parent 32f722d733
commit 4ffee1630b
25 changed files with 1388 additions and 545 deletions

Binary file not shown.

View File

@ -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();
}

View File

@ -0,0 +1,6 @@
package com.garbagemule.ArenaPlugin;
public interface ArenaPlugin
{
public Master getMaster();
}

View File

@ -0,0 +1,16 @@
package com.garbagemule.ArenaPlugin;
import java.util.List;
import org.bukkit.entity.Player;
public interface Master
{
//public List<Arena> getArenas();
//public List<Arena> getEnabledArenas();
//public List<Arena> getPermittedArenas(Player p);
}

View File

@ -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<Player> arenaPlayers, lobbyPlayers, readyPlayers, specPlayers;
private Map<Player,String> playerClassMap;
private Map<Player,Location> locations;
private Map<Player,Integer> healthMap;
private Map<Player,Integer> 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);
}

View File

@ -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<String,Location> spawnpoints;
protected Map<String,Location> spawnpoints, containers;
protected String logging;
// Wave/reward/entryfee fields
@ -89,7 +90,7 @@ public class Arena
protected Set<Block> blocks;
protected Set<Wolf> pets;
protected Map<Player,Integer> petMap;
protected LinkedList<Repairable> repairables, containers;
protected LinkedList<Repairable> repairables, containables;
// Spawn overriding
protected int spawnMonsters;
@ -137,7 +138,7 @@ public class Arena
classMap = new HashMap<Player,String>();
randoms = new HashSet<Player>();
repairables = new LinkedList<Repairable>();
containers = new LinkedList<Repairable>();
containables = new LinkedList<Repairable>();
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<Location> getAllSpawnpoints()
public List<Location> getAllSpawnpoints()
{
return spawnpoints.values();
return new ArrayList<Location>(spawnpoints.values());
}
public Collection<Location> getSpawnpoints()
public List<Location> getSpawnpoints()
{
List<Location> result = new ArrayList<Location>(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<Location>(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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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<ItemStack> rewards;
public List<Block> blocks;
protected boolean inArena, inLobby, inSpec, isReady;
@ -34,6 +36,7 @@ public class ArenaPlayer
className = arena.classMap.get(player);
rewards = new LinkedList<ItemStack>();
blocks = new LinkedList<Block>();
}
public Player getPlayer() { return player; }

View File

@ -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);
}
}

View File

@ -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<String> 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 <container name>");
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 <container name>");
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)

View File

@ -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()))

View File

@ -106,6 +106,11 @@ public class MAMessages
{
m.msg = msg;
}
public String toString()
{
return msg;
}
}
/**

View File

@ -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);
}
}

View File

@ -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<Entity> tmp = new LinkedList<Entity>(arena.monsters);
for (Entity e : tmp)
if (e.isDead())
if (e.isDead() || !arena.inRegion(e.getLocation()))
arena.monsters.remove(e);
}

View File

@ -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<String,Location> getArenaContainers(Configuration config, World world, String arena)
{
Map<String,Location> containers = new HashMap<String,Location>();
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)
{

View File

@ -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");

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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<ItemStack> 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<InventoryItem> extractAllFromArray(int id, InventoryItem[] items)
{
List<InventoryItem> list = new LinkedList<InventoryItem>();
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;
}
}

View File

@ -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<Location> getValidSpawnpoints(Arena arena, Collection<Player> players)
{
long start = System.nanoTime();
List<Location> result = new ArrayList<Location>();
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;

View File

@ -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<Player>());
}
private void strikeLightning(final Arena arena, final Player p, final List<Player> 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<Player> 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<Player> 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<Player> getNearbyPlayers(Arena arena, Entity boss, int x)
{
List<Player> result = new LinkedList<Player>();
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<Player> getDistantPlayers(Arena arena, Entity boss, int x)
{
List<Player> result = new LinkedList<Player>();
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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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<Player> 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<Player> getNearbyPlayers(Arena arena, Entity boss, int x)
{
List<Player> result = new LinkedList<Player>();
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<Player> getDistantPlayers(Arena arena, Entity boss, int x)
{
List<Player> result = new LinkedList<Player>();
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)