Preparations for customizable waves..
This commit is contained in:
+14
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
|
<classpathentry kind="lib" path="S:/Java/Minecraft/lib/craftbukkit-0.0.1-SNAPSHOT.jar"/>
|
||||||
|
<classpathentry kind="lib" path="S:/Java/Minecraft/lib/Permissions.jar"/>
|
||||||
|
<classpathentry kind="lib" path="S:/Java/Minecraft/lib/BOSEconomy7.jar"/>
|
||||||
|
<classpathentry kind="lib" path="S:/Java/Minecraft/lib/Essentials.jar"/>
|
||||||
|
<classpathentry kind="lib" path="S:/Java/Minecraft/lib/iCo4.jar"/>
|
||||||
|
<classpathentry kind="lib" path="S:/Java/Minecraft/lib/iCo5.jar"/>
|
||||||
|
<classpathentry kind="lib" path="MobArena.jar"/>
|
||||||
|
<classpathentry kind="lib" path="S:/Java/Minecraft/lib/jdom.jar"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>MobArena</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project name="MobArena" default="dist" basedir=".">
|
||||||
|
<property name="pluginname" value="MobArena"/>
|
||||||
|
<property name="server" location="S:\Minecraft Server\plugins"/>
|
||||||
|
|
||||||
|
<property name="src" location="src"/>
|
||||||
|
<property name="bin" location="bin"/>
|
||||||
|
<property name="lib" location="../lib"/>
|
||||||
|
<property name="res" location="resources"/>
|
||||||
|
<path id="classpath">
|
||||||
|
<fileset dir="${lib}" includes="**/*.jar"/>
|
||||||
|
<fileset dir="${res}" includes="**/*.*"/>
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<target name="init">
|
||||||
|
<mkdir dir="${bin}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- Compile the source and put in the bin-folder -->
|
||||||
|
<target name="compile" depends="init">
|
||||||
|
<javac srcdir="${src}" destdir="${bin}" includeantruntime="false" classpathref="classpath"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- Build a .jar and copy to server's plugins-folder -->
|
||||||
|
<target name="dist" depends="compile">
|
||||||
|
<delete file="${pluginname}.jar"/>
|
||||||
|
<jar jarfile="${pluginname}.jar">
|
||||||
|
<!-- Include the class-files (bin) and the resources (res) -->
|
||||||
|
<fileset dir="${bin}"/>
|
||||||
|
<fileset dir="${res}"/>
|
||||||
|
<!-- Set up the classpath so MobArena can find JDOM if needed -->
|
||||||
|
<manifest>
|
||||||
|
<attribute name="Main-Class" value="com.garbagemule.MobArena.MobArena"/>
|
||||||
|
<attribute name="Class-Path" value="plugins/MobArena/lib/jdom.jar MobArena/lib/jdom.jar"/>
|
||||||
|
</manifest>
|
||||||
|
</jar>
|
||||||
|
<!-- Copy to server and clean up -->
|
||||||
|
<copy file="${pluginname}.jar" tofile="${server}/${pluginname}.jar"/>
|
||||||
|
<delete dir="${bin}"/>
|
||||||
|
</target>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
name: MobArena
|
||||||
|
main: com.garbagemule.MobArena.MobArena
|
||||||
|
version: 0.93.4
|
||||||
|
softdepend: [MultiVerse,XcraftGate,Towny]
|
||||||
|
commands:
|
||||||
|
ma:
|
||||||
|
description: Base command for MobArena
|
||||||
|
usage: |
|
||||||
|
/ma join - Join the arena.
|
||||||
|
/ma leave - Leave the arena.
|
||||||
|
/ma notready - List of players who aren't ready.
|
||||||
|
/ma spectate - Warp to the spectator area.
|
||||||
|
marena:
|
||||||
|
description: Base command for MobArena
|
||||||
|
usage: |
|
||||||
|
/marena join - Join the arena.
|
||||||
|
/marena leave - Leave the arena.
|
||||||
|
/marena notready - List of players who aren't ready.
|
||||||
|
/marena spectate - Warp to the spectator area.
|
||||||
|
mobarena:
|
||||||
|
description: Base command for MobArena
|
||||||
|
usage: |
|
||||||
|
/mobarena join - Join the arena.
|
||||||
|
/mobarena leave - Leave the arena.
|
||||||
|
/mobarena notready - List of players who aren't ready.
|
||||||
|
/mobarena spectate - Warp to the spectator area.
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
ARENA_START=Let the slaughter begin!
|
||||||
|
ARENA_END=Arena finished.
|
||||||
|
ARENA_DOES_NOT_EXIST=That arena does not exist. Type /ma arenas for a list.
|
||||||
|
JOIN_PLAYER_JOINED=
|
||||||
|
JOIN_NOT_ENABLED=MobArena is not enabled.
|
||||||
|
JOIN_IN_OTHER_ARENA=You are already in an arena! Leave that one first.
|
||||||
|
JOIN_ARENA_NOT_ENABLED=This arena is not enabled.
|
||||||
|
JOIN_ARENA_NOT_SETUP=This arena has not been set up yet.
|
||||||
|
JOIN_ARENA_PERMISSION=You don't have permission to join this arena.
|
||||||
|
JOIN_FEE_REQUIRED=Insufficient funds. Price: %
|
||||||
|
JOIN_FEE_PAID=Price to join was: %
|
||||||
|
JOIN_ARENA_IS_RUNNING=This arena is in already progress.
|
||||||
|
JOIN_ALREADY_PLAYING=You are already playing!
|
||||||
|
JOIN_ARG_NEEDED=You must specify an arena. Type /ma arenas for a list.
|
||||||
|
JOIN_TOO_FAR=You are too far away from the arena to join/spectate.
|
||||||
|
JOIN_EMPTY_INV=You must empty your inventory to join the arena.
|
||||||
|
JOIN_PLAYER_LIMIT_REACHED=The player limit of this arena has been reached.
|
||||||
|
JOIN_STORE_INV_FAIL=Failed to store inventory. Try again.
|
||||||
|
LEAVE_PLAYER_LEFT=You left the arena. Thanks for playing!
|
||||||
|
LEAVE_NOT_PLAYING=You are not in the arena.
|
||||||
|
PLAYER_DIED=% died!
|
||||||
|
SPEC_PLAYER_SPECTATE=Enjoy the show!
|
||||||
|
SPEC_NOT_RUNNING=This arena isn't running.
|
||||||
|
SPEC_ARG_NEEDED=You must specify an arena. Type /ma arenas for a list.
|
||||||
|
SPEC_EMPTY_INV=Empty your inventory first!
|
||||||
|
SPEC_ALREADY_PLAYING=Can't spectate when in the arena!
|
||||||
|
NOT_READY_PLAYERS=Not ready: %
|
||||||
|
FORCE_START_STARTED=Forced arena start.
|
||||||
|
FORCE_START_RUNNING=Arena has already started.
|
||||||
|
FORCE_START_NOT_READY=Can't force start, no players are ready.
|
||||||
|
FORCE_END_ENDED=Forced arena end.
|
||||||
|
FORCE_END_EMPTY=No one is in the arena.
|
||||||
|
FORCE_END_IDLE=You weren't quick enough!
|
||||||
|
REWARDS_GIVE=Here are all of your rewards!
|
||||||
|
LOBBY_CLASS_PICKED=You have chosen % as your class!
|
||||||
|
LOBBY_CLASS_RANDOM=You will get a random class on arena start.
|
||||||
|
LOBBY_CLASS_PERMISSION=You don't have permission to use this class!
|
||||||
|
LOBBY_PLAYER_READY=You have been flagged as ready!
|
||||||
|
LOBBY_DROP_ITEM=No sharing before the arena starts!
|
||||||
|
LOBBY_PICK_CLASS=You must first pick a class!
|
||||||
|
LOBBY_RIGHT_CLICK=Punch the sign. Don't right-click.
|
||||||
|
WARP_TO_ARENA=Can't warp to the arena during battle!
|
||||||
|
WARP_FROM_ARENA=Warping not allowed in the arena!
|
||||||
|
WAVE_DEFAULT=Get ready for wave #%!
|
||||||
|
WAVE_SPECIAL=Get ready for wave #%! [SPECIAL]
|
||||||
|
WAVE_REWARD=You just earned a reward: %
|
||||||
|
MISC_LIST_ARENAS=Available arenas: %
|
||||||
|
MISC_LIST_PLAYERS=Live players: %
|
||||||
|
MISC_COMMAND_NOT_ALLOWED=You can't use that command in the arena!
|
||||||
|
MISC_NO_ACCESS=You don't have access to this command.
|
||||||
|
MISC_NONE=<none>
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
### MobArena Configuration File
|
||||||
|
### Please visit the MobArena Wiki here: http://goo.gl/F5TTc for more details
|
||||||
|
### on how to set up this file.
|
||||||
|
### Note that you CAN'T use tabs in this file! Always use spaces!
|
||||||
|
|
||||||
|
### GLOBAL SETTINGS
|
||||||
|
# These settings are arena-independent and count in all arenas. Note that if
|
||||||
|
# enabled: false in the global settings, MobArena is disabled globally, and
|
||||||
|
# arena-specific enabled-values do not matter. If true, however, the per-arena
|
||||||
|
# enabled-values count.
|
||||||
|
global-settings:
|
||||||
|
enabled: true
|
||||||
|
allowed-commands: /list, /pl
|
||||||
|
update-notification: true
|
||||||
|
|
||||||
|
### CLASS SETUP
|
||||||
|
# Items can be written as either their data value (numbers) or their Material
|
||||||
|
# type (names); check the Wiki for links to lists of both.
|
||||||
|
# The notation is <item>:<amount>. If no amount is given, 1 is assumed. Sub-
|
||||||
|
# types can be created
|
||||||
|
# Item SUBTYPES (wool/dye colors) are written as <item>:<subtype>:<amount>,
|
||||||
|
# but here, the amount is REQUIRED, even if it is just 1.
|
||||||
|
# Note: If you want to specify only one item, but apostrophes around that one
|
||||||
|
# item, e.g.: items: '278'
|
||||||
|
# Note: For every bone a class has, one PET WOLF will spawn upon arena start,
|
||||||
|
# which will assist the player in the arena session.
|
||||||
|
classes:
|
||||||
|
Knight:
|
||||||
|
items: diamond_sword, grilled_pork:2
|
||||||
|
armor: 306,307,308,309
|
||||||
|
Tank:
|
||||||
|
items: iron_sword, grilled_pork:3, apple
|
||||||
|
armor: 310,311,312,313
|
||||||
|
Archer:
|
||||||
|
items: wood_sword, bow, arrow:64, arrow:64, grilled_pork, bone:2
|
||||||
|
armor: 298,299,300,301
|
||||||
|
Chef:
|
||||||
|
items: stone_sword, bread:6, grilled_pork:4, mushroom_soup, cake:5
|
||||||
|
armor: 314,315,316,317
|
||||||
|
Oddjob:
|
||||||
|
items: stone_sword, flint_and_steel, netherrack:2, tnt:4, pork:3
|
||||||
|
armor: 298,299,300,301
|
||||||
|
|
||||||
|
### ARENA SETUP
|
||||||
|
# The arena setup is split into 4 different sections per arena: settings,
|
||||||
|
# waves, rewards and coords (not shown until coords are set up).
|
||||||
|
# Please refer to the Wiki for descriptions of all these settings.
|
||||||
|
# Note: The REWARDS use the same notation as the items in the CLASS SETUP
|
||||||
|
# section. However, only -one- item from the list is picked (at random) when
|
||||||
|
# the rewards are given.
|
||||||
|
arenas:
|
||||||
|
default:
|
||||||
|
settings:
|
||||||
|
world: ''
|
||||||
|
enabled: true
|
||||||
|
protect: true
|
||||||
|
entry-fee: ''
|
||||||
|
logging: true
|
||||||
|
clear-wave-before-next: false
|
||||||
|
detonate-creepers: false
|
||||||
|
detonate-damage: false
|
||||||
|
lightning: true
|
||||||
|
auto-equip-armor: true
|
||||||
|
force-restore: false
|
||||||
|
soft-restore: false
|
||||||
|
soft-restore-drops: false
|
||||||
|
require-empty-inv-join: false
|
||||||
|
require-empty-inv-spec: false
|
||||||
|
hellhounds: false
|
||||||
|
pvp-enabled: false
|
||||||
|
monster-infight: false
|
||||||
|
allow-teleporting: false
|
||||||
|
spectate-on-death: true
|
||||||
|
share-items-in-arena: true
|
||||||
|
min-players: 0
|
||||||
|
max-players: 0
|
||||||
|
max-join-distance: 0
|
||||||
|
repair-delay: 5
|
||||||
|
first-wave-delay: 5
|
||||||
|
wave-interval: 20
|
||||||
|
special-modulo: 4
|
||||||
|
max-idle-time: 0
|
||||||
|
waves:
|
||||||
|
default:
|
||||||
|
zombies: 10
|
||||||
|
skeletons: 10
|
||||||
|
spiders: 10
|
||||||
|
creepers: 10
|
||||||
|
wolves: 10
|
||||||
|
special:
|
||||||
|
powered-creepers: 10
|
||||||
|
zombie-pigmen: 10
|
||||||
|
angry-wolves: 10
|
||||||
|
slimes: 10
|
||||||
|
humans: 10
|
||||||
|
giants: 0
|
||||||
|
ghasts: 0
|
||||||
|
rewards:
|
||||||
|
waves:
|
||||||
|
every:
|
||||||
|
'3': feather, bone, stick
|
||||||
|
'5': dirt:4, gravel:4, stone:4
|
||||||
|
'10': iron_ingot:10, gold_ingot:8
|
||||||
|
after:
|
||||||
|
'7': minecart, storage_minecart, powered_minecart
|
||||||
|
'13': iron_sword, iron_pickaxe, iron_spade
|
||||||
|
'16': diamond_sword
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
### General data
|
||||||
|
### Statistics for overall information about the arena, such as
|
||||||
|
### times played, durations, max players seen, total kills, etc.
|
||||||
|
general-info:
|
||||||
|
total-games-played: 0
|
||||||
|
total-duration: 0:00:00
|
||||||
|
longest-session-duration: 0:00:00
|
||||||
|
most-players: 0
|
||||||
|
highest-wave-reached: 0
|
||||||
|
total-monsters-killed: 0
|
||||||
|
|
||||||
|
### Class specific data
|
||||||
|
### How many times has each class been played, and how many kills, how
|
||||||
|
### much damage, etc. does the class make/do/take.
|
||||||
|
classes:
|
||||||
|
overall-distribution:
|
||||||
|
# Percentages can be calculated with <classname> / total-count * 100.
|
||||||
|
total-count: 0
|
||||||
|
|
||||||
|
#classes:
|
||||||
|
# overall-distribution:
|
||||||
|
# total-count: 0
|
||||||
|
# archer:
|
||||||
|
# kills:
|
||||||
|
# damage-done:
|
||||||
|
# damage-taken:
|
||||||
|
# accuracy:
|
||||||
|
# knight:
|
||||||
|
# kills:
|
||||||
|
# damage-done:
|
||||||
|
# damage-taken:
|
||||||
|
# accuracy:
|
||||||
|
# ...
|
||||||
|
### Reward data
|
||||||
|
### Totals for all rewards given, perhaps good for balancing?
|
||||||
|
rewards:
|
||||||
|
total-given:
|
||||||
|
# This might be useless information, I don't know.
|
||||||
|
# Might have to make it data values instead of Material names?
|
||||||
|
money: 0
|
||||||
|
|
||||||
|
### Player data
|
||||||
|
### Total games played, kills, damage, swings and hits (for accuracy), and how
|
||||||
|
### many times the player has played as each class.
|
||||||
|
players: {}
|
||||||
|
# garbagemule:
|
||||||
|
# games-played: 5
|
||||||
|
# kills: 4
|
||||||
|
# damage-done: 251
|
||||||
|
# damage-taken: 102
|
||||||
|
# swings: 1820
|
||||||
|
# hits: 1214
|
||||||
|
# classes-played:
|
||||||
|
# archer: 2
|
||||||
|
# ...
|
||||||
|
# Agnate:
|
||||||
|
# ...
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
### General data
|
||||||
|
### Statistics for overall information about the arena, such as
|
||||||
|
### times played, durations, max players seen, total kills, etc.
|
||||||
|
general-info:
|
||||||
|
total-games-played: 0
|
||||||
|
total-duration: 0:00:00
|
||||||
|
longest-session-duration: 0:00:00
|
||||||
|
most-players: 0
|
||||||
|
highest-wave-reached: 0
|
||||||
|
total-monsters-killed: 0
|
||||||
|
|
||||||
|
### Class specific data
|
||||||
|
### How many times has each class been played, and how many kills, how
|
||||||
|
### much damage, etc. does the class make/do/take.
|
||||||
|
classes:
|
||||||
|
overall-distribution:
|
||||||
|
# Percentages can be calculated with <classname> / total-count * 100.
|
||||||
|
total-count: 0
|
||||||
|
|
||||||
|
#classes:
|
||||||
|
# overall-distribution:
|
||||||
|
# total-count: 0
|
||||||
|
# archer:
|
||||||
|
# kills:
|
||||||
|
# damage-done:
|
||||||
|
# damage-taken:
|
||||||
|
# accuracy:
|
||||||
|
# knight:
|
||||||
|
# kills:
|
||||||
|
# damage-done:
|
||||||
|
# damage-taken:
|
||||||
|
# accuracy:
|
||||||
|
# ...
|
||||||
|
### Reward data
|
||||||
|
### Totals for all rewards given, perhaps good for balancing?
|
||||||
|
rewards:
|
||||||
|
total-given:
|
||||||
|
# This might be useless information, I don't know.
|
||||||
|
# Might have to make it data values instead of Material names?
|
||||||
|
money: 0
|
||||||
|
|
||||||
|
### Player data
|
||||||
|
### Total games played, kills, damage, swings and hits (for accuracy), and how
|
||||||
|
### many times the player has played as each class.
|
||||||
|
players: {}
|
||||||
|
# garbagemule:
|
||||||
|
# games-played: 5
|
||||||
|
# kills: 4
|
||||||
|
# damage-done: 251
|
||||||
|
# damage-taken: 102
|
||||||
|
# swings: 1820
|
||||||
|
# hits: 1214
|
||||||
|
# classes-played:
|
||||||
|
# archer: 2
|
||||||
|
# ...
|
||||||
|
# Agnate:
|
||||||
|
# ...
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.garbagemule.MobArena;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class ArenaPlayer
|
||||||
|
{
|
||||||
|
public MobArena plugin;
|
||||||
|
public Player player;
|
||||||
|
public String className;
|
||||||
|
public Arena arena;
|
||||||
|
public List<ItemStack> rewards;
|
||||||
|
|
||||||
|
protected boolean inArena, inLobby, inSpec, isReady;
|
||||||
|
|
||||||
|
// Session fields.
|
||||||
|
public int kills, dmgDone, dmgTaken, swings, hits, deaths, lastWave;
|
||||||
|
public int flagCaps, flagAttempts, flagReturns; // BG: Capture the Pumpkin
|
||||||
|
public int baseCaps; // BG: Domination
|
||||||
|
|
||||||
|
// All-time fields.
|
||||||
|
protected int totalKills, totalDmgDone, totalDmgTaken, totalSwings, totalHits, totalDeaths;
|
||||||
|
protected int totalFlagCaps, totalFlagAttempts, totalFlagReturns; // BG: Capture the Pumpkin
|
||||||
|
protected int totalBaseCaps; // BG: Domination
|
||||||
|
|
||||||
|
public ArenaPlayer(Player player, Arena arena, MobArena plugin)
|
||||||
|
{
|
||||||
|
this.player = player;
|
||||||
|
this.arena = arena;
|
||||||
|
this.plugin = plugin;
|
||||||
|
|
||||||
|
className = arena.classMap.get(player);
|
||||||
|
rewards = new LinkedList<ItemStack>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() { return player; }
|
||||||
|
public Arena getArena() { return arena; }
|
||||||
|
public String getClassName() { return className; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
package com.garbagemule.MobArena.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bukkit.util.config.Configuration;
|
||||||
|
|
||||||
|
import com.garbagemule.MobArena.MobArena;
|
||||||
|
|
||||||
|
public class FileUtils
|
||||||
|
{
|
||||||
|
public static enum Libs
|
||||||
|
{
|
||||||
|
xml("jdom.jar", "http://mirrors.ibiblio.org/pub/mirrors/maven2/org/jdom/jdom/1.1/jdom-1.1.jar");
|
||||||
|
|
||||||
|
public String url, filename;
|
||||||
|
private Libs(String filename, String url)
|
||||||
|
{
|
||||||
|
this.filename = filename;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Libs getLib(String filename)
|
||||||
|
{
|
||||||
|
for (Libs l : Libs.values())
|
||||||
|
if (l.filename.equals(filename))
|
||||||
|
return l;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create default files from the res/ directory, if they exist.
|
||||||
|
* @param filenames Files to be created.
|
||||||
|
*/
|
||||||
|
public static void extractDefaults(String... filenames)
|
||||||
|
{
|
||||||
|
for (String filename : filenames)
|
||||||
|
extractFile(MobArena.dir, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void extractFile(File dir, String filename)
|
||||||
|
{
|
||||||
|
// Skip if file exists
|
||||||
|
File file = new File(dir, filename);
|
||||||
|
if (file.exists()) return;
|
||||||
|
|
||||||
|
// Skip if there is no resource with that name
|
||||||
|
InputStream in = MobArena.class.getResourceAsStream("/res/" + filename);
|
||||||
|
if (in == null) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Set up an output stream
|
||||||
|
FileOutputStream out = new FileOutputStream(file);
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
// Write the resource data to the file
|
||||||
|
while ((length = in.read(buffer)) > 0)
|
||||||
|
out.write(buffer, 0, length);
|
||||||
|
|
||||||
|
if (in != null) in.close();
|
||||||
|
if (out != null) out.close();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
System.out.println("[MobArena] ERROR! Problem creating file '" + filename + "'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download all necessary libraries.
|
||||||
|
* @param config The MobArena config-file
|
||||||
|
*/
|
||||||
|
public static void fetchLibs(Configuration config)
|
||||||
|
{
|
||||||
|
// Get all arenas
|
||||||
|
List<String> arenas = config.getKeys("arenas");
|
||||||
|
if (arenas == null) return;
|
||||||
|
|
||||||
|
// Add all the logging types
|
||||||
|
Set<String> libs = new HashSet<String>();
|
||||||
|
for (String a : arenas)
|
||||||
|
{
|
||||||
|
String type = config.getString("arenas." + a + ".settings.logging", "").toLowerCase();
|
||||||
|
if (type.equals("xml"))
|
||||||
|
libs.add(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download all libraries
|
||||||
|
for (String lib : libs)
|
||||||
|
{
|
||||||
|
if (download(Libs.valueOf(lib)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If a library couldn't be downloaded, default to false.
|
||||||
|
for (String a : arenas)
|
||||||
|
{
|
||||||
|
if (!config.getString("arenas." + a + ".settings.logging", "").equalsIgnoreCase(lib))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
System.out.println("[MobArena] ERROR! Unrecognized format for arena '" + a + "': " + lib + ". Logging disabled.");
|
||||||
|
config.setProperty("arenas." + a + ".logging", "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static synchronized boolean download(Libs lib)
|
||||||
|
{
|
||||||
|
if (lib == null) return false;
|
||||||
|
|
||||||
|
InputStream in = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URLConnection con = new URL(lib.url).openConnection();
|
||||||
|
con.setUseCaches(false);
|
||||||
|
|
||||||
|
// Library folder: plugin/MobArena/lib
|
||||||
|
File libdir = new File(MobArena.dir, "lib");
|
||||||
|
libdir.mkdir();
|
||||||
|
|
||||||
|
// Create the file if it doesn't exist, if it does, return
|
||||||
|
File file = new File(libdir, lib.filename);
|
||||||
|
if (file.exists()) return true;
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
System.out.println("[MobArena] Downloading library: " + lib.filename + "...");
|
||||||
|
|
||||||
|
// Set up the streams
|
||||||
|
in = con.getInputStream();
|
||||||
|
out = new FileOutputStream(file);
|
||||||
|
if (in == null || out == null) return false;
|
||||||
|
|
||||||
|
byte[] buffer = new byte[65536];
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
// Write the library to disk
|
||||||
|
while ((length = in.read(buffer)) > 0)
|
||||||
|
out.write(buffer, 0, length);
|
||||||
|
|
||||||
|
System.out.println("[MobArena] " + lib.filename + " downloaded in " + ((System.currentTimeMillis()-startTime)/1000.0) + " seconds.");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
System.out.println("[MobArena] ERROR! Couldn't download library: " + lib.filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (in != null) in.close();
|
||||||
|
if (out != null) out.close();
|
||||||
|
}
|
||||||
|
catch (Exception e) { e.printStackTrace(); }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getMostRecent(String folder)
|
||||||
|
{
|
||||||
|
return getMostRecent(new File(folder));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getMostRecent(File dir)
|
||||||
|
{
|
||||||
|
if (!dir.exists()) dir.mkdir();
|
||||||
|
if (!dir.isDirectory()) return null;
|
||||||
|
|
||||||
|
long mostRecent = 0;
|
||||||
|
File result = null;
|
||||||
|
|
||||||
|
for (File file : dir.listFiles())
|
||||||
|
{
|
||||||
|
if (file.isDirectory() || file.lastModified() > mostRecent)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
result = file;
|
||||||
|
mostRecent = file.lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Configuration parseXML(File file)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Configuration parseCSV(File file)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Configuration parsePlainText(File file)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.garbagemule.MobArena.util;
|
||||||
|
|
||||||
|
public class TextUtils
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Add character padding on the right side of a String.
|
||||||
|
* @param s String to add padding to
|
||||||
|
* @param length Total amount of characters in the returned String
|
||||||
|
* @param pad The padding character
|
||||||
|
* @return A padded String with the input length
|
||||||
|
*/
|
||||||
|
public static String padRight(String s, int length, char pad)
|
||||||
|
{
|
||||||
|
StringBuffer buffy = new StringBuffer();
|
||||||
|
buffy.append(s);
|
||||||
|
for (int i = s.length(); i < length; i++)
|
||||||
|
buffy.append(pad);
|
||||||
|
return buffy.toString();
|
||||||
|
}
|
||||||
|
public static String padRight(String s, int length) { return padRight(s, length, ' '); }
|
||||||
|
public static String padRight(int s, int length) { return padRight(Integer.toString(s), length, ' '); }
|
||||||
|
public static String padRight(double s, int length) { return padRight(Double.toString(s), length, ' '); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add character padding on the left side of a String.
|
||||||
|
* @param s String to add padding to
|
||||||
|
* @param length Total amount of characters in the returned String
|
||||||
|
* @param pad The padding character
|
||||||
|
* @return A padded String with the input length
|
||||||
|
*/
|
||||||
|
public static String padLeft(String s, int length, char pad)
|
||||||
|
{
|
||||||
|
StringBuffer buffy = new StringBuffer();
|
||||||
|
for (int i = 0; i < length - s.length(); i++)
|
||||||
|
buffy.append(pad);
|
||||||
|
buffy.append(s);
|
||||||
|
return buffy.toString();
|
||||||
|
}
|
||||||
|
public static String padLeft(String s, int length) { return padLeft(s, length, ' '); }
|
||||||
|
public static String padLeft(int s, int length) { return padLeft(Integer.toString(s), length, ' '); }
|
||||||
|
public static String padLeft(double s, int length) { return padLeft(Double.toString(s), length, ' '); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,534 @@
|
|||||||
|
package com.garbagemule.MobArena.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.CreatureType;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.config.Configuration;
|
||||||
|
|
||||||
|
import com.garbagemule.MobArena.MAUtils;
|
||||||
|
import com.garbagemule.MobArena.MobArena;
|
||||||
|
import com.garbagemule.MobArena.waves.RecurrentWave;
|
||||||
|
import com.garbagemule.MobArena.waves.SingleWave;
|
||||||
|
import com.garbagemule.MobArena.waves.Wave;
|
||||||
|
import com.garbagemule.MobArena.waves.Wave.BossAbility;
|
||||||
|
import com.garbagemule.MobArena.waves.Wave.BossHealth;
|
||||||
|
import com.garbagemule.MobArena.waves.Wave.SwarmAmount;
|
||||||
|
import com.garbagemule.MobArena.waves.Wave.WaveBranch;
|
||||||
|
import com.garbagemule.MobArena.waves.Wave.WaveGrowth;
|
||||||
|
import com.garbagemule.MobArena.waves.Wave.WaveType;
|
||||||
|
|
||||||
|
public class WaveUtils
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get all the spawnpoints that have players nearby.
|
||||||
|
*/
|
||||||
|
public static List<Location> getValidSpawnpoints(Collection<Location> spawnpoints, Collection<Player> players)
|
||||||
|
{
|
||||||
|
List<Location> result = new ArrayList<Location>();
|
||||||
|
|
||||||
|
for (Location s : spawnpoints)
|
||||||
|
{
|
||||||
|
for (Player p : players)
|
||||||
|
{
|
||||||
|
// If the player somehow got out of the arena world, kick him.
|
||||||
|
if (!s.getWorld().getName().equals(p.getWorld().getName()))
|
||||||
|
{
|
||||||
|
System.out.println("[MobArena] 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;
|
||||||
|
|
||||||
|
result.add(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no players are in range, just use all the spawnpoints.
|
||||||
|
if (result.isEmpty())
|
||||||
|
result.addAll(spawnpoints);
|
||||||
|
|
||||||
|
// Else, return the valid spawnpoints.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grab and process all the waves in the config-file for the arena.
|
||||||
|
*/
|
||||||
|
public static TreeSet<Wave> getWaves(Configuration config, String arena, WaveBranch branch)
|
||||||
|
{
|
||||||
|
// Determine the branch type of the wave, and grab the appropriate comparator
|
||||||
|
String b = branch.toString().toLowerCase();
|
||||||
|
TreeSet<Wave> result = new TreeSet<Wave>(getComparator(branch));
|
||||||
|
|
||||||
|
// Grab the waves from the config-file
|
||||||
|
String path = "arenas." + arena + ".waves." + b;
|
||||||
|
List<String> waves = config.getKeys(path);
|
||||||
|
|
||||||
|
// If there are any waves, process them
|
||||||
|
if (waves != null)
|
||||||
|
{
|
||||||
|
Wave wave;
|
||||||
|
for (String w : waves)
|
||||||
|
{
|
||||||
|
// path argument becomes: "arenas.<arena>.waves.<branch>.<wave>."
|
||||||
|
wave = getWave(config, path + "." + w + ".", w, branch);
|
||||||
|
if (wave != null) result.add(wave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no waves and the type is 'recurrent', add a default wave.
|
||||||
|
if (branch == WaveBranch.RECURRENT && (result.isEmpty() || waves == null))
|
||||||
|
{
|
||||||
|
RecurrentWave def = new RecurrentWave("DEF_WAVE_AUTO", 1, 1, 1);
|
||||||
|
def.setType(WaveType.DEFAULT);
|
||||||
|
def.setGrowth(WaveGrowth.MEDIUM);
|
||||||
|
def.setDefault(true);
|
||||||
|
|
||||||
|
result.add(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a single wave based on the config-file, the path, and branch
|
||||||
|
* @return A Wave object if it is well defined, null otherwise.
|
||||||
|
*/
|
||||||
|
private static Wave getWave(Configuration config, String path, String name, WaveBranch branch)
|
||||||
|
{
|
||||||
|
// Grab the wave type, if null, return null
|
||||||
|
WaveType type = WaveType.fromString(config.getString(path + "type"));
|
||||||
|
if (type == null || !isWaveWellDefined(config, path, branch, type))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// TODO: Generate waves properly. These are place-holders!
|
||||||
|
Wave result;
|
||||||
|
if (branch == WaveBranch.RECURRENT)
|
||||||
|
{
|
||||||
|
int frequency = config.getInt(path + "frequency", 0);
|
||||||
|
int priority = config.getInt(path + "priority", 0);
|
||||||
|
int wave = config.getInt(path + "wave", frequency);
|
||||||
|
result = new RecurrentWave(name, wave, frequency, priority);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int wave = config.getInt(path + "wave", 0);
|
||||||
|
result = new SingleWave(name, wave);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
public static RecurrentWave getRecurrentWave(Configuration config, String arena, String w)
|
||||||
|
{
|
||||||
|
// Grab the path
|
||||||
|
String path = "arenas." + arena + ".waves.recurrent." + w + ".";
|
||||||
|
|
||||||
|
// Ensure that frequency and priority exist, otherwise return null
|
||||||
|
int frequency = config.getInt(path + "frequency", 0);
|
||||||
|
int priority = config.getInt(path + "priority", 0);
|
||||||
|
if (frequency == 0 || priority == 0) return null;
|
||||||
|
|
||||||
|
// Grab other variables
|
||||||
|
int wave = config.getInt(path + "wave", frequency);
|
||||||
|
WaveType type = WaveType.fromString(config.getString(path + "type", "default"));
|
||||||
|
WaveGrowth growth = WaveGrowth.fromString(config.getString(path + "growth", "medium"));
|
||||||
|
|
||||||
|
// Grab monster distribution
|
||||||
|
//Map<CreatureType,Integer> monsters = getWaveMonsters(config, arena, path, type);
|
||||||
|
|
||||||
|
// Create the wave
|
||||||
|
RecurrentWave result = new RecurrentWave(w, wave, frequency, priority, type, growth);
|
||||||
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SingleWave getSingleWave(Configuration config, String arena, String w)
|
||||||
|
{
|
||||||
|
// Grab the path
|
||||||
|
String path = "arenas." + arena + ".waves.single." + w + ".";
|
||||||
|
|
||||||
|
// Ensure that the wave number exists, otherwise return null
|
||||||
|
int wave = config.getInt(path + "wave", 0);
|
||||||
|
if (wave == 0) return null;
|
||||||
|
|
||||||
|
// Grab other variables
|
||||||
|
|
||||||
|
SingleWave result = new SingleWave(w, wave);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<CreatureType,Integer> getWaveMonsters(Configuration config, String arena, String path, String type)
|
||||||
|
{
|
||||||
|
Map<CreatureType,Integer> result = new HashMap<CreatureType,Integer>();
|
||||||
|
|
||||||
|
List<String> monsters = config.getKeys(path + "monsters");
|
||||||
|
|
||||||
|
// If no monsters specified, make sure to add some
|
||||||
|
if (monsters == null)
|
||||||
|
{
|
||||||
|
if (type.equals("default"))
|
||||||
|
{
|
||||||
|
result.put(CreatureType.ZOMBIE, 10);
|
||||||
|
result.put(CreatureType.SKELETON, 10);
|
||||||
|
result.put(CreatureType.SPIDER, 10);
|
||||||
|
result.put(CreatureType.CREEPER, 10);
|
||||||
|
result.put(CreatureType.WOLF, 10);
|
||||||
|
}
|
||||||
|
else if (type.equals("default"))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Comparators
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a comparator based on the WaveBranch parameter.
|
||||||
|
*/
|
||||||
|
public static Comparator<Wave> getComparator(WaveBranch branch)
|
||||||
|
{
|
||||||
|
if (branch == WaveBranch.SINGLE)
|
||||||
|
return getSingleComparator();
|
||||||
|
else if (branch == WaveBranch.RECURRENT)
|
||||||
|
return getRecurrentComparator();
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a Comparator that compares Wave objects by wave number.
|
||||||
|
* If the wave numbers are equal, the waves are equal. This is to
|
||||||
|
* DISALLOW "duplicates" in the SINGLE WAVES collection.
|
||||||
|
* @return Comparator whose compare()-method compares wave numbers.
|
||||||
|
*/
|
||||||
|
public static Comparator<Wave> getSingleComparator()
|
||||||
|
{
|
||||||
|
return new Comparator<Wave>()
|
||||||
|
{
|
||||||
|
public int compare(Wave w1, Wave w2)
|
||||||
|
{
|
||||||
|
if (w1.getWave() < w2.getWave())
|
||||||
|
return -1;
|
||||||
|
else if (w1.getWave() > w2.getWave())
|
||||||
|
return 1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a Comparator that compares Wave objects by priority.
|
||||||
|
* If the priorities are equal, the names are compared. This is to
|
||||||
|
* ALLOW "duplicates" in the RECURRENT WAVES collection.
|
||||||
|
* @return Comparator whose compare()-method compares wave priorities.
|
||||||
|
*/
|
||||||
|
public static Comparator<Wave> getRecurrentComparator()
|
||||||
|
{
|
||||||
|
return new Comparator<Wave>()
|
||||||
|
{
|
||||||
|
public int compare(Wave w1, Wave w2)
|
||||||
|
{
|
||||||
|
if (w1.getPriority() < w2.getPriority())
|
||||||
|
return -1;
|
||||||
|
else if (w1.getPriority() > w2.getPriority())
|
||||||
|
return 1;
|
||||||
|
else return w1.getName().compareTo(w2.getName());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the single waves for the given arena.
|
||||||
|
*/
|
||||||
|
/*public static TreeSet<SingleWave> getSingleWaves(Configuration config, String arena)
|
||||||
|
{
|
||||||
|
TreeSet<SingleWave> result = new TreeSet<SingleWave>();
|
||||||
|
|
||||||
|
List<String> waves = config.getKeys("arenas." + arena + ".waves.single");
|
||||||
|
if (waves != null)
|
||||||
|
{
|
||||||
|
int wave;
|
||||||
|
|
||||||
|
for (String w : waves)
|
||||||
|
{
|
||||||
|
wave = config.getInt("arenas." + arena + ".waves.single." + w + ".wave", 0);
|
||||||
|
if (wave == 0) continue;
|
||||||
|
result.add(new SingleWave(w, wave));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the recurrent waves for the given arena.
|
||||||
|
* If no waves are found, a default wave is added. This ensures that
|
||||||
|
* the arena always has monsters spawning, regardless of how badly the
|
||||||
|
* user messes up the config-file.
|
||||||
|
*/
|
||||||
|
/*public static TreeSet<RecurrentWave> getRecurrentWaves(Configuration config, String arena)
|
||||||
|
{
|
||||||
|
TreeSet<RecurrentWave> result = new TreeSet<RecurrentWave>();
|
||||||
|
|
||||||
|
List<String> waves = config.getKeys("arenas." + arena + ".waves.recurrent");
|
||||||
|
if (waves != null)
|
||||||
|
{
|
||||||
|
int wave, frequency, priority;
|
||||||
|
|
||||||
|
for (String w : waves)
|
||||||
|
{
|
||||||
|
frequency = config.getInt("arenas." + arena + ".waves.recurrent." + w + ".frequency", 0);
|
||||||
|
priority = config.getInt("arenas." + arena + ".waves.recurrent." + w + ".priority", 0);
|
||||||
|
if (frequency == 0 || priority == 0) continue;
|
||||||
|
|
||||||
|
wave = config.getInt("arenas." + arena + ".waves.single." + w + ".wave", frequency);
|
||||||
|
result.add(new RecurrentWave(w, wave, frequency, priority));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RecurrentWave def = new RecurrentWave("DEF_WAVE_AUTO", 1, 1, 1);
|
||||||
|
def.setType(WaveType.DEFAULT);
|
||||||
|
def.setGrowth(WaveGrowth.MEDIUM);
|
||||||
|
|
||||||
|
RecurrentWave spec = new RecurrentWave("SPEC_WAVE_AUTO", 4, 4, 4);
|
||||||
|
spec.setType(WaveType.SPECIAL);
|
||||||
|
|
||||||
|
result.add(def);
|
||||||
|
result.add(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Well definedness checks
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a wave in the config-file is well-defined.
|
||||||
|
* The method first checks if the wave is well-defined according to
|
||||||
|
* the branch-specific requirements. Recurrent waves must have the
|
||||||
|
* two nodes 'priority' and 'frequency', and single waves must have
|
||||||
|
* the node 'wave'.
|
||||||
|
* Any other requirements are type-specific, and thus we check if the
|
||||||
|
* type is well-defined.
|
||||||
|
* @param config Config-file Configuration
|
||||||
|
* @param path The absolute path of the wave
|
||||||
|
* @param branch The branch of the wave
|
||||||
|
* @param type The wave type
|
||||||
|
* @return true, if the wave is well-defined, false otherwise
|
||||||
|
*/
|
||||||
|
private static boolean isWaveWellDefined(Configuration config, String path, WaveBranch branch, WaveType type)
|
||||||
|
{
|
||||||
|
if (branch == WaveBranch.RECURRENT)
|
||||||
|
{
|
||||||
|
// REQUIRED: Priority and frequency
|
||||||
|
int priority = config.getInt(path + "priority", 0);
|
||||||
|
int frequency = config.getInt(path + "frequency", 0);
|
||||||
|
if (priority == 0 || frequency == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// TODO: OPTIONAL: Wave growth, others?
|
||||||
|
}
|
||||||
|
else if (branch == WaveBranch.SINGLE)
|
||||||
|
{
|
||||||
|
// REQUIRED: Wave number
|
||||||
|
int wave = config.getInt(path + "wave", 0);
|
||||||
|
if (wave == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
|
||||||
|
// Passed branch-checks; check type
|
||||||
|
return isTypeWellDefined(config, path, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a wave type in the config-file is well-defined.
|
||||||
|
* The method calls the appropriate sub-method to check if the type
|
||||||
|
* is well-defined.
|
||||||
|
* @param config Config-file Configuration
|
||||||
|
* @param path The absolute path of the wave
|
||||||
|
* @param type The wave type
|
||||||
|
* @return true, if the wave type is well-defined, false otherwise
|
||||||
|
*/
|
||||||
|
private static boolean isTypeWellDefined(Configuration config, String path, WaveType type)
|
||||||
|
{
|
||||||
|
if (type == WaveType.DEFAULT || type == WaveType.SPECIAL)
|
||||||
|
return isNormalWaveWellDefined(config, path);
|
||||||
|
else if (type == WaveType.BOSS)
|
||||||
|
return isBossWaveWellDefined(config, path);
|
||||||
|
else if (type == WaveType.SWARM)
|
||||||
|
return isSwarmWaveWellDefined(config, path);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a default or special wave is well-defined.
|
||||||
|
* There are no REQUIRED nodes for default or special wave types, besides
|
||||||
|
* the ones for the branch they belong to.
|
||||||
|
* The only OPTIONAL node is (currently) 'monsters'
|
||||||
|
* @param config Config-file Configuration
|
||||||
|
* @param path The absolute path of the wave
|
||||||
|
* @return true, if the wave type is well-defined, false otherwise
|
||||||
|
*/
|
||||||
|
private static boolean isNormalWaveWellDefined(Configuration config, String path)
|
||||||
|
{
|
||||||
|
// OPTIONAL: Monsters
|
||||||
|
List<String> monsters = config.getKeys(path + "monsters");
|
||||||
|
if (monsters == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (String monster : monsters)
|
||||||
|
{
|
||||||
|
if (getEnumFromString(CreatureType.class, monster) != null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
MAUtils.error("Invalid monster type '" + monster + "' in " + path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a swarm wave is well defined
|
||||||
|
* @param config Config-file Configuration
|
||||||
|
* @param path The absolute path of the wave
|
||||||
|
* @return true, if the wave type is well-defined, false otherwise
|
||||||
|
*/
|
||||||
|
private static boolean isSwarmWaveWellDefined(Configuration config, String path)
|
||||||
|
{
|
||||||
|
// REQUIRED: Monster type
|
||||||
|
String monster = config.getString(path + "monster");
|
||||||
|
if (monster == null)
|
||||||
|
{
|
||||||
|
MAUtils.error("Missing monster type in '" + path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (getEnumFromString(CreatureType.class, monster) == null)
|
||||||
|
{
|
||||||
|
MAUtils.error("Invalid monster type '" + monster + "' in " + path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPTIONAL: Amount
|
||||||
|
String amount = config.getString(path + "amount");
|
||||||
|
if (amount != null && SwarmAmount.fromString(amount) == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a boss wave is well defined.
|
||||||
|
* @param config Config-file Configuration
|
||||||
|
* @param path The absolute path of the wave
|
||||||
|
* @return true, if the wave type is well-defined, false otherwise
|
||||||
|
*/
|
||||||
|
private static boolean isBossWaveWellDefined(Configuration config, String path)
|
||||||
|
{
|
||||||
|
// REQUIRED: Monster type
|
||||||
|
String monster = config.getString(path + "monster");
|
||||||
|
if (monster == null)
|
||||||
|
{
|
||||||
|
MAUtils.error("Missing monster type in '" + path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (getEnumFromString(CreatureType.class, monster) == null)
|
||||||
|
{
|
||||||
|
MAUtils.error("Invalid monster type '" + monster + "' in " + path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPTIONAL: Abilities
|
||||||
|
String abilities = config.getString(path + "abilities");
|
||||||
|
if (abilities != null)
|
||||||
|
{
|
||||||
|
for (String ability : abilities.split(","))
|
||||||
|
{
|
||||||
|
if (BossAbility.fromString(ability.trim().toUpperCase()) != null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
MAUtils.error("Invalid boss ability '" + ability + "' in " + path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: OPTIONAL: Adds
|
||||||
|
// Unsure about config-file implementation...
|
||||||
|
|
||||||
|
// OPTIONAL: Health
|
||||||
|
String health = config.getString(path + "health");
|
||||||
|
if (health != null && BossHealth.fromString(health) == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Misc - Perhaps move into MAUtils?
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the num value of a string, def if it doesn't exist.
|
||||||
|
*/
|
||||||
|
public static <T extends Enum<T>> T getEnumFromString(Class<T> c, String string, T def)
|
||||||
|
{
|
||||||
|
if (c != null && string != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Enum.valueOf(c, string.trim().toUpperCase());
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ex) { }
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the enum value of a string, null if it doesn't exist.
|
||||||
|
*/
|
||||||
|
public static <T extends Enum<T>> T getEnumFromString(Class<T> c, String string)
|
||||||
|
{
|
||||||
|
if(c != null && string != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Enum.valueOf(c, string.trim().toUpperCase());
|
||||||
|
}
|
||||||
|
catch(IllegalArgumentException ex) { }
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
package com.garbagemule.MobArena.util.data;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import com.garbagemule.MobArena.ArenaLog;
|
||||||
|
import com.garbagemule.MobArena.ArenaPlayer;
|
||||||
|
import com.garbagemule.MobArena.MAUtils;
|
||||||
|
import com.garbagemule.MobArena.MobArena;
|
||||||
|
import com.garbagemule.MobArena.util.TextUtils;
|
||||||
|
|
||||||
|
public class PlainText
|
||||||
|
{
|
||||||
|
public static void saveSessionData(ArenaLog log)
|
||||||
|
{
|
||||||
|
File dir = new File(MobArena.arenaDir, log.getArena().configName());
|
||||||
|
if (!dir.exists()) dir.mkdirs();
|
||||||
|
|
||||||
|
// General information
|
||||||
|
List<String> toWrite = new LinkedList<String>();
|
||||||
|
toWrite.add("Start: " + log.getStartTime());
|
||||||
|
toWrite.add("End: " + log.getEndTime());
|
||||||
|
toWrite.add("Duration: " + log.getDuration());
|
||||||
|
toWrite.add("Last wave: " + log.getLastWave());
|
||||||
|
toWrite.add(" ");
|
||||||
|
|
||||||
|
int classLength = longestClassName(log.distribution.keySet());
|
||||||
|
int classCount = log.distribution.keySet().size();
|
||||||
|
int playerCount = log.players.keySet().size();
|
||||||
|
|
||||||
|
// Class distribution
|
||||||
|
toWrite.add("Class Distribution: " + classCount + " classes");
|
||||||
|
toWrite.addAll(getClassDistribution(log.distribution, playerCount, classLength));
|
||||||
|
toWrite.add(" ");
|
||||||
|
|
||||||
|
// Player data
|
||||||
|
toWrite.add("Player Data: " + playerCount + " players");
|
||||||
|
toWrite.addAll(getPlayerData(log.players, classLength));
|
||||||
|
|
||||||
|
// Serialize!
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File file = new File(dir, "lastsession.txt");
|
||||||
|
if (!file.exists()) file.createNewFile();
|
||||||
|
|
||||||
|
FileWriter fw = new FileWriter(file);
|
||||||
|
for (String s : toWrite)
|
||||||
|
{
|
||||||
|
fw.write(s);
|
||||||
|
fw.write(System.getProperty("line.separator"));
|
||||||
|
}
|
||||||
|
fw.close();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
System.out.println("[MobArena] ERROR! Problem saving session data for arena '" + log.getArena().configName() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateArenaTotals(ArenaLog log)
|
||||||
|
{
|
||||||
|
// Grab the Configuration
|
||||||
|
//Configuration totals = Totals.getArenaTotals(log.arena);
|
||||||
|
|
||||||
|
// Parse shit
|
||||||
|
|
||||||
|
// Serialize
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public static void updateTotals(ArenaLog log, MobArena plugin)
|
||||||
|
{
|
||||||
|
File dir = new File(MobArena.arenaDir, log.getArena().configName());
|
||||||
|
if (!dir.exists()) dir.mkdir();
|
||||||
|
} */
|
||||||
|
|
||||||
|
private static List<String> getClassDistribution(Map<String,Integer> map, int playerCount, int classLength)
|
||||||
|
{
|
||||||
|
List<String> result = new LinkedList<String>();
|
||||||
|
|
||||||
|
// Add each entry - class: # (percentage%)
|
||||||
|
for (Map.Entry<String,Integer> entry : map.entrySet())
|
||||||
|
{
|
||||||
|
StringBuffer buffy = new StringBuffer(classLength + 15);
|
||||||
|
|
||||||
|
buffy.append("- ");
|
||||||
|
buffy.append(TextUtils.padRight(entry.getKey() + ":", classLength + 3)); // <classname>:
|
||||||
|
buffy.append(TextUtils.padLeft(entry.getValue().toString(), 2)); // <count>
|
||||||
|
buffy.append("(" + (entry.getValue()*100/playerCount) + "%)"); // (<count/playerCount>%)
|
||||||
|
|
||||||
|
result.add(buffy.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> getPlayerData(Map<Player,ArenaPlayer> map, int classLength)
|
||||||
|
{
|
||||||
|
List<String> result = new LinkedList<String>();
|
||||||
|
String pad = " ";
|
||||||
|
|
||||||
|
// Padding variables; +2 for extra padding
|
||||||
|
int NAME = 12, CLASS = classLength, WAVE = 4, KILLS = 5, DMGDONE = 7, DMGTAKEN = 8, ACCURACY = 8;
|
||||||
|
result.add(" " + TextUtils.padRight("NAME", NAME+2) +
|
||||||
|
TextUtils.padRight("CLASS", CLASS+2) +
|
||||||
|
TextUtils.padRight("WAVE", WAVE+2) +
|
||||||
|
TextUtils.padRight("KILLS", KILLS+2) +
|
||||||
|
TextUtils.padRight("DMGDONE", DMGDONE+2) +
|
||||||
|
TextUtils.padRight("DMGTAKEN", DMGTAKEN+2) +
|
||||||
|
TextUtils.padRight("ACCURACY", ACCURACY+2) +
|
||||||
|
"REWARDS");
|
||||||
|
|
||||||
|
// Add each player - name class wave dmgdone dmgtaken accuracy rewards
|
||||||
|
for (Map.Entry<Player,ArenaPlayer> entry : map.entrySet())
|
||||||
|
{
|
||||||
|
Player p = entry.getKey();
|
||||||
|
ArenaPlayer ap = entry.getValue();
|
||||||
|
StringBuffer buffy = new StringBuffer(80);
|
||||||
|
|
||||||
|
String name = (p.getName().length() <= NAME) ? p.getName() : p.getName().substring(0, NAME+1);
|
||||||
|
buffy.append("- ");
|
||||||
|
buffy.append(TextUtils.padRight(name, NAME)); buffy.append(pad);
|
||||||
|
buffy.append(TextUtils.padRight(ap.getClassName(), CLASS)); buffy.append(pad);
|
||||||
|
buffy.append(TextUtils.padLeft(ap.lastWave, WAVE)); buffy.append(pad);
|
||||||
|
buffy.append(TextUtils.padLeft(ap.kills, KILLS)); buffy.append(pad);
|
||||||
|
buffy.append(TextUtils.padLeft(ap.dmgDone, DMGDONE)); buffy.append(pad);
|
||||||
|
buffy.append(TextUtils.padLeft(ap.dmgTaken, DMGTAKEN)); buffy.append(pad);
|
||||||
|
buffy.append(TextUtils.padLeft(((ap.swings != 0) ? ap.hits*100/ap.swings : 0), ACCURACY-1)); buffy.append("%"); buffy.append(pad);
|
||||||
|
buffy.append(MAUtils.listToString(ap.rewards));
|
||||||
|
|
||||||
|
result.add(buffy.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int longestClassName(Collection<String> names)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (String c : names)
|
||||||
|
if (c.length() > result)
|
||||||
|
result = c.length();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package com.garbagemule.MobArena.util.data;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.bukkit.util.config.Configuration;
|
||||||
|
|
||||||
|
import com.garbagemule.MobArena.Arena;
|
||||||
|
import com.garbagemule.MobArena.ArenaLog;
|
||||||
|
import com.garbagemule.MobArena.ArenaPlayer;
|
||||||
|
import com.garbagemule.MobArena.MAUtils;
|
||||||
|
import com.garbagemule.MobArena.MobArena;
|
||||||
|
import com.garbagemule.MobArena.util.FileUtils;
|
||||||
|
|
||||||
|
public class Totals
|
||||||
|
{
|
||||||
|
private static final String totals_yml = "totals.yml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the totals-file with the session data from the ArenaLog object
|
||||||
|
* @param log ArenaLog to update with
|
||||||
|
*/
|
||||||
|
public static void updateArenaTotals(ArenaLog log)
|
||||||
|
{
|
||||||
|
// Grab the configuration
|
||||||
|
Configuration totals = getArenaTotals(log.arena);
|
||||||
|
totals.load();
|
||||||
|
|
||||||
|
// General data
|
||||||
|
updateInt(totals, "general-info.total-games-played", 1, true);
|
||||||
|
updateInt(totals, "general-info.most-players", log.players.keySet().size(), false);
|
||||||
|
updateInt(totals, "general-info.highest-wave-reached", log.lastWave, false);
|
||||||
|
updateInt(totals, "general-info.total-monsters-killed", countKills(log), true);
|
||||||
|
updateDuration(totals, "general-info.total-duration", log.getDurationLong(), true);
|
||||||
|
updateDuration(totals, "general-info.longest-session-duration", log.getDurationLong(), false);
|
||||||
|
|
||||||
|
// Classes
|
||||||
|
updateInt(totals, "classes.overall-distribution.total-count", log.players.keySet().size(), true);
|
||||||
|
for (String c : log.arena.getClasses())
|
||||||
|
{
|
||||||
|
// Array {kills, dmgDone, dmgTaken}
|
||||||
|
int[] a = getKillsAndDamageByClass(log, c);
|
||||||
|
updateInt(totals,"classes." + c + ".kills", a[0],true);
|
||||||
|
updateInt(totals,"classes." + c + ".damage-done", a[1],true);
|
||||||
|
updateInt(totals,"classes." + c + ".damage-taken",a[2],true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewards
|
||||||
|
|
||||||
|
// Players
|
||||||
|
for (ArenaPlayer ap : log.players.values())
|
||||||
|
{
|
||||||
|
// Basic values
|
||||||
|
updateInt(totals,"players." + ap.player.getName() + ".games-played", 1, true);
|
||||||
|
updateInt(totals,"players." + ap.player.getName() + ".kills", ap.kills, true);
|
||||||
|
updateInt(totals,"players." + ap.player.getName() + ".damage-done", ap.dmgDone, true);
|
||||||
|
updateInt(totals,"players." + ap.player.getName() + ".damage-taken", ap.dmgTaken, true);
|
||||||
|
updateInt(totals,"players." + ap.player.getName() + ".swings", ap.swings, true);
|
||||||
|
updateInt(totals,"players." + ap.player.getName() + ".hits", ap.hits, true);
|
||||||
|
|
||||||
|
// Class count
|
||||||
|
updateInt(totals,"players." + ap.player.getName() + ".classes." + ap.className,1,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save everything
|
||||||
|
totals.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a Configuration from the totals-file
|
||||||
|
* @param arena Arena to get or create a Configuration for
|
||||||
|
* @return Configuration from the arena's totals-file
|
||||||
|
*/
|
||||||
|
public static Configuration getArenaTotals(Arena arena)
|
||||||
|
{
|
||||||
|
// Create the folder if it doesn't exist.
|
||||||
|
File dir = new File(MobArena.arenaDir, arena.configName());
|
||||||
|
if (!dir.exists()) dir.mkdirs();
|
||||||
|
|
||||||
|
File file = new File(dir, totals_yml);
|
||||||
|
if (!file.exists()) FileUtils.extractFile(dir, totals_yml);
|
||||||
|
|
||||||
|
// Grab the totals-file and return the Configuration
|
||||||
|
return new Configuration(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an integer in a config-file
|
||||||
|
* @param totals Configuration to alter
|
||||||
|
* @param node Node to alter
|
||||||
|
* @param b Integer for comparison
|
||||||
|
* @param increment If true, the node will be incremented by b, otherwise overwritten if greater
|
||||||
|
*/
|
||||||
|
private static void updateInt(Configuration totals, String node, int b, boolean increment)
|
||||||
|
{
|
||||||
|
int a = totals.getInt(node, 0);
|
||||||
|
|
||||||
|
if (increment) totals.setProperty(node, a+b);
|
||||||
|
else if (b > a) totals.setProperty(node, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a duration in a config-file
|
||||||
|
* @param totals Configuration to alter
|
||||||
|
* @param node Node to alter
|
||||||
|
* @param b Duration for comparison. This is a java.sql.Timestamp.getTime() long
|
||||||
|
* @param increment If true, the node will be incremented by b, otherwise overwritten if greater
|
||||||
|
*/
|
||||||
|
private static void updateDuration(Configuration totals, String node, long b, boolean increment)
|
||||||
|
{
|
||||||
|
long a = MAUtils.parseDuration(totals.getString(node, "0:00:00"));
|
||||||
|
|
||||||
|
if (increment) totals.setProperty(node, MAUtils.getDuration(a+b));
|
||||||
|
else if (b > a) totals.setProperty(node, MAUtils.getDuration(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get total kills from an arena session
|
||||||
|
* @param log The ArenaLog to count kills in
|
||||||
|
* @return Total kills
|
||||||
|
*/
|
||||||
|
private static int countKills(ArenaLog log)
|
||||||
|
{
|
||||||
|
int kills = 0;
|
||||||
|
for (ArenaPlayer ap : log.players.values())
|
||||||
|
kills += ap.kills;
|
||||||
|
return kills;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
private static int getKillsByClass(ArenaLog log, String className)
|
||||||
|
{
|
||||||
|
int kills = 0;
|
||||||
|
for (ArenaPlayer ap : log.players.values())
|
||||||
|
if (ap.className.equals(className))
|
||||||
|
kills += ap.kills;
|
||||||
|
return kills;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a (dirty) int-array in the form {kills, damage done, damage taken} for a class
|
||||||
|
* @param log ArenaLog to count kills, damage done/taken from
|
||||||
|
* @param className The class to count for
|
||||||
|
* @return Resulting kills, damage done and damage taken in an int-array
|
||||||
|
*/
|
||||||
|
private static int[] getKillsAndDamageByClass(ArenaLog log, String className)
|
||||||
|
{
|
||||||
|
int kills = 0, dmgDone = 0, dmgTaken = 0;
|
||||||
|
for (ArenaPlayer ap : log.players.values())
|
||||||
|
{
|
||||||
|
if (!ap.className.equals(className))
|
||||||
|
continue;
|
||||||
|
kills += ap.kills;
|
||||||
|
dmgDone += ap.dmgDone;
|
||||||
|
dmgTaken += ap.dmgTaken;
|
||||||
|
}
|
||||||
|
return new int[]{kills, dmgDone, dmgTaken};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.garbagemule.MobArena.util.data;
|
||||||
|
|
||||||
|
public class XML
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.garbagemule.MobArena.waves;
|
||||||
|
|
||||||
|
public abstract class AbstractWave implements Wave
|
||||||
|
{
|
||||||
|
private String name;
|
||||||
|
private int wave, frequency, priority;
|
||||||
|
private WaveType type;
|
||||||
|
private WaveGrowth growth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic wave constructor.
|
||||||
|
* Constructs a wave with an initial wave number, a wave frequency, and
|
||||||
|
* a wave priority.
|
||||||
|
* @param wave Initial wave number. This is the first wave number this wave can spawn at.
|
||||||
|
* @param frequency How often the wave can spawn.
|
||||||
|
* @param priority The priority of the wave.
|
||||||
|
*/
|
||||||
|
public AbstractWave(String name, int wave, int frequency, int priority)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.wave = wave;
|
||||||
|
this.frequency = frequency;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default wave constructor.
|
||||||
|
* Constructs a basic wave with additional information in the type of
|
||||||
|
* wave and the wave growth.
|
||||||
|
* @param wave Initial wave number. This is the first wave number this wave can spawn at.
|
||||||
|
* @param frequency How often the wave can spawn.
|
||||||
|
* @param priority The priority of the wave.
|
||||||
|
* @param type The type of wave.
|
||||||
|
* @param growth The growth rate of the wave.
|
||||||
|
*/
|
||||||
|
public AbstractWave(String name, int wave, int frequency, int priority, WaveType type, WaveGrowth growth)
|
||||||
|
{
|
||||||
|
this(name, wave, frequency, priority);
|
||||||
|
this.type = type;
|
||||||
|
this.growth = growth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WaveType getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(WaveType type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WaveGrowth getGrowth()
|
||||||
|
{
|
||||||
|
return growth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGrowth(WaveGrowth growth)
|
||||||
|
{
|
||||||
|
this.growth = growth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWave()
|
||||||
|
{
|
||||||
|
return wave;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFrequency()
|
||||||
|
{
|
||||||
|
return frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPriority()
|
||||||
|
{
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "[name=" + name +
|
||||||
|
", wave=" + wave +
|
||||||
|
", frequency=" + frequency +
|
||||||
|
", priority=" + priority + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.garbagemule.MobArena.waves;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Creature;
|
||||||
|
|
||||||
|
import com.garbagemule.MobArena.waves.Wave.BossAbility;
|
||||||
|
|
||||||
|
public class BossWave
|
||||||
|
{
|
||||||
|
private Creature boss;
|
||||||
|
private Set<BossAbility> abilities;
|
||||||
|
private Set<Creature> adds;
|
||||||
|
private int health;
|
||||||
|
|
||||||
|
public BossWave(Creature boss)
|
||||||
|
{
|
||||||
|
this.boss = boss;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAbility(BossAbility ability)
|
||||||
|
{
|
||||||
|
abilities.add(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAdds(Creature creature)
|
||||||
|
{
|
||||||
|
adds.add(creature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHealth(int health)
|
||||||
|
{
|
||||||
|
this.health = health;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.garbagemule.MobArena.waves;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
public class RecurrentWave extends AbstractWave
|
||||||
|
{
|
||||||
|
public RecurrentWave(String name, int wave, int frequency, int priority)
|
||||||
|
{
|
||||||
|
super(name, wave, frequency, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecurrentWave(String name, int wave, int frequency, int priority, WaveType type, WaveGrowth growth)
|
||||||
|
{
|
||||||
|
super(name, wave, frequency, priority, type, growth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawn(int wave, Collection<Location> spawnpoints)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefault(boolean def)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(int wave)
|
||||||
|
{
|
||||||
|
return wave % getWave() + getFrequency() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recurrent waves are sorted by their priorities.
|
||||||
|
* If the priorities are equal, the names are compared. This is to
|
||||||
|
* ALLOW "duplicates" in the RECURRENT WAVES collection.
|
||||||
|
*/
|
||||||
|
public int compareTo(Wave w)
|
||||||
|
{
|
||||||
|
if (getPriority() < w.getPriority())
|
||||||
|
return -1;
|
||||||
|
else if (getPriority() > w.getPriority())
|
||||||
|
return 1;
|
||||||
|
else return getName().compareTo(w.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.garbagemule.MobArena.waves;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
public class SingleWave extends AbstractWave
|
||||||
|
{
|
||||||
|
public SingleWave(String name, int wave)
|
||||||
|
{
|
||||||
|
super(name, wave, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawn(int wave, Collection<Location> spawnpoints)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(int wave)
|
||||||
|
{
|
||||||
|
return getWave() == wave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single waves are compared by their wave numbers.
|
||||||
|
* If the wave numbers are equal, the waves are equal. This is to
|
||||||
|
* DISALLOW "duplicates" in the SINGLE WAVES collection.
|
||||||
|
*/
|
||||||
|
public int compareTo(Wave w)
|
||||||
|
{
|
||||||
|
if (this.getWave() < w.getWave())
|
||||||
|
return -1;
|
||||||
|
else if (this.getWave() > w.getWave())
|
||||||
|
return 1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package com.garbagemule.MobArena.waves;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
import com.garbagemule.MobArena.util.WaveUtils;
|
||||||
|
|
||||||
|
public interface Wave extends Comparable<Wave>
|
||||||
|
{
|
||||||
|
public enum WaveBranch
|
||||||
|
{
|
||||||
|
SINGLE, RECURRENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum WaveType
|
||||||
|
{
|
||||||
|
DEFAULT, SPECIAL, SWARM, BOSS;
|
||||||
|
|
||||||
|
public static WaveType fromString(String string)
|
||||||
|
{
|
||||||
|
return WaveUtils.getEnumFromString(WaveType.class, string, DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum WaveGrowth
|
||||||
|
{
|
||||||
|
SLOW, MEDIUM, FAST;
|
||||||
|
|
||||||
|
public static WaveGrowth fromString(String string)
|
||||||
|
{
|
||||||
|
return WaveUtils.getEnumFromString(WaveGrowth.class, string, MEDIUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BossAbility
|
||||||
|
{
|
||||||
|
ARROWS, FIREBALLS, RING_OF_FIRE;
|
||||||
|
|
||||||
|
public static BossAbility fromString(String string)
|
||||||
|
{
|
||||||
|
return WaveUtils.getEnumFromString(BossAbility.class, string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BossHealth
|
||||||
|
{
|
||||||
|
LOW, MEDIUM, HIGH;
|
||||||
|
|
||||||
|
public static BossHealth fromString(String string)
|
||||||
|
{
|
||||||
|
return WaveUtils.getEnumFromString(BossHealth.class, string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SwarmAmount
|
||||||
|
{
|
||||||
|
LOW, MEDIUM, HIGH, PSYCHO;
|
||||||
|
|
||||||
|
public static SwarmAmount fromString(String string)
|
||||||
|
{
|
||||||
|
return WaveUtils.getEnumFromString(SwarmAmount.class, string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The spawn() method must spawn one or more monsters in
|
||||||
|
* the arena. The monster count, damage, health, etc. can
|
||||||
|
* be modified by the wave parameter.
|
||||||
|
* @param wave Wave number
|
||||||
|
*/
|
||||||
|
public void spawn(int wave, Collection<Location> spawnpoints);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of wave.
|
||||||
|
* @return The WaveType of this Wave.
|
||||||
|
*/
|
||||||
|
public WaveType getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the growth rate of this wave.
|
||||||
|
* @return The growth rate
|
||||||
|
*/
|
||||||
|
public WaveGrowth getGrowth();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first wave number for this wave
|
||||||
|
* @return The wave number
|
||||||
|
*/
|
||||||
|
public int getWave();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the wave's frequency, i.e. wave number "modulo"
|
||||||
|
* @return The wave's frequency
|
||||||
|
*/
|
||||||
|
public int getFrequency();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the wave's priority value.
|
||||||
|
* @return The priority
|
||||||
|
*/
|
||||||
|
public int getPriority();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the wave's name.
|
||||||
|
* @return The name
|
||||||
|
*/
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this wave matches the wave number.
|
||||||
|
* The SingleWave class does a simple check if its wave == the parameter.
|
||||||
|
* The RecurrentWave class is more complex in that it needs to do some
|
||||||
|
* calculations based on the initial wave and the frequency.
|
||||||
|
* @param wave The current wave number
|
||||||
|
* @return true, if the wave should spawn, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean matches(int wave);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user