From 5096d3d39912a162c3986ddc63fbdee8f28cb910 Mon Sep 17 00:00:00 2001 From: Nathan Braun Date: Sun, 23 Oct 2016 23:23:02 -0700 Subject: [PATCH] Implemented new collision detection system (#636) --- .../projectkorra/GeneralMethods.java | 4 + .../projectkorra/ProjectKorra.java | 6 + .../projectkorra/ability/AirAbility.java | 25 ++ .../projectkorra/ability/CoreAbility.java | 294 ++++++++++++------ .../projectkorra/ability/EarthAbility.java | 11 + .../projectkorra/ability/FireAbility.java | 15 + .../projectkorra/ability/WaterAbility.java | 20 ++ .../projectkorra/ability/util/Collision.java | 86 +++++ .../ability/util/CollisionInitializer.java | 176 +++++++++++ .../ability/util/CollisionManager.java | 245 +++++++++++++++ .../ability/util/ComboManager.java | 64 ++-- .../projectkorra/airbending/AirBlast.java | 39 ++- .../projectkorra/airbending/AirBubble.java | 30 +- .../projectkorra/airbending/AirBurst.java | 41 ++- .../projectkorra/airbending/AirCombo.java | 165 ++++++---- .../projectkorra/airbending/AirScooter.java | 60 ++-- .../projectkorra/airbending/AirShield.java | 54 ++-- .../projectkorra/airbending/AirSpout.java | 63 +++- .../projectkorra/airbending/AirSuction.java | 26 +- .../projectkorra/airbending/AirSwipe.java | 115 +++---- .../projectkorra/airbending/Suffocate.java | 80 +++-- .../projectkorra/airbending/Tornado.java | 11 +- .../projectkorra/chiblocking/ChiCombo.java | 2 +- .../configuration/ConfigManager.java | 10 +- .../projectkorra/earthbending/Collapse.java | 21 +- .../projectkorra/earthbending/EarthBlast.java | 123 ++++---- .../projectkorra/earthbending/EarthSmash.java | 149 +++++---- .../earthbending/EarthTunnel.java | 39 ++- .../projectkorra/earthbending/LavaFlow.java | 77 ++--- .../projectkorra/earthbending/RaiseEarth.java | 11 + .../projectkorra/earthbending/Ripple.java | 25 +- .../projectkorra/earthbending/SandSpout.java | 28 +- .../projectkorra/earthbending/Shockwave.java | 2 +- .../event/AbilityCollisionEvent.java | 42 +++ .../projectkorra/firebending/Combustion.java | 11 + .../projectkorra/firebending/FireBlast.java | 53 ++-- .../firebending/FireBlastCharged.java | 16 +- .../projectkorra/firebending/FireBurst.java | 2 +- .../projectkorra/firebending/FireCombo.java | 228 ++++++++------ .../projectkorra/firebending/FireShield.java | 60 ++-- .../projectkorra/firebending/Lightning.java | 32 +- .../projectkorra/firebending/WallOfFire.java | 17 +- .../waterbending/Bloodbending.java | 15 +- .../waterbending/HealingWaters.java | 2 +- .../projectkorra/waterbending/IceBlast.java | 14 +- .../waterbending/IceSpikeBlast.java | 68 ++-- .../waterbending/OctopusForm.java | 5 + .../projectkorra/waterbending/PlantArmor.java | 12 +- .../projectkorra/waterbending/SurgeWall.java | 38 ++- .../projectkorra/waterbending/SurgeWave.java | 42 ++- .../projectkorra/waterbending/Torrent.java | 17 + .../waterbending/TorrentWave.java | 10 + .../projectkorra/waterbending/WaterCombo.java | 156 +++++++--- .../waterbending/WaterManipulation.java | 50 ++- .../projectkorra/waterbending/WaterSpout.java | 26 +- .../waterbending/WaterSpoutWave.java | 13 + 56 files changed, 2098 insertions(+), 948 deletions(-) create mode 100644 src/com/projectkorra/projectkorra/ability/util/Collision.java create mode 100644 src/com/projectkorra/projectkorra/ability/util/CollisionInitializer.java create mode 100644 src/com/projectkorra/projectkorra/ability/util/CollisionManager.java create mode 100644 src/com/projectkorra/projectkorra/event/AbilityCollisionEvent.java diff --git a/src/com/projectkorra/projectkorra/GeneralMethods.java b/src/com/projectkorra/projectkorra/GeneralMethods.java index f92c3115..556e2ad4 100644 --- a/src/com/projectkorra/projectkorra/GeneralMethods.java +++ b/src/com/projectkorra/projectkorra/GeneralMethods.java @@ -211,11 +211,15 @@ public class GeneralMethods { } /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + *

* Cycles through a list of ability names to check if any instances of the * abilities exist at a specific location. If an instance of the ability is * found then it will be removed, with the exception FireShield, and * AirShield. */ + @Deprecated public static boolean blockAbilities(Player player, List abilitiesToBlock, Location loc, double radius) { boolean hasBlocked = false; for (String ability : abilitiesToBlock) { diff --git a/src/com/projectkorra/projectkorra/ProjectKorra.java b/src/com/projectkorra/projectkorra/ProjectKorra.java index 789a78ac..4953a641 100644 --- a/src/com/projectkorra/projectkorra/ProjectKorra.java +++ b/src/com/projectkorra/projectkorra/ProjectKorra.java @@ -11,6 +11,8 @@ import org.bukkit.plugin.java.JavaPlugin; import com.bekvon.bukkit.residence.protection.FlagPermissions; import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.ability.util.CollisionInitializer; +import com.projectkorra.projectkorra.ability.util.CollisionManager; import com.projectkorra.projectkorra.ability.util.ComboManager; import com.projectkorra.projectkorra.ability.util.MultiAbilityManager; import com.projectkorra.projectkorra.airbending.AirbendingManager; @@ -33,6 +35,7 @@ public class ProjectKorra extends JavaPlugin { public static ProjectKorra plugin; public static Logger log; public static PKLogHandler handler; + public static CollisionManager collisionManager; public static long time_step = 1; public Updater updater; @@ -59,6 +62,9 @@ public class ProjectKorra extends JavaPlugin { new MultiAbilityManager(); new ComboManager(); CoreAbility.registerAbilities(); + collisionManager = new CollisionManager(); + new CollisionInitializer(collisionManager).initializeCollisions(); + collisionManager.startCollisionDetection(); Preset.loadExternalPresets(); diff --git a/src/com/projectkorra/projectkorra/ability/AirAbility.java b/src/com/projectkorra/projectkorra/ability/AirAbility.java index 132037fb..675b02b4 100644 --- a/src/com/projectkorra/projectkorra/ability/AirAbility.java +++ b/src/com/projectkorra/projectkorra/ability/AirAbility.java @@ -2,11 +2,14 @@ package com.projectkorra.projectkorra.ability; import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.airbending.AirSpout; import com.projectkorra.projectkorra.airbending.Suffocate; import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.ParticleEffect.ParticleData; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -34,6 +37,16 @@ public abstract class AirAbility extends ElementalAbility { public Element getElement() { return Element.AIR; } + + @Override + public void handleCollision(Collision collision) { + super.handleCollision(collision); + if (collision.isRemovingFirst()) { + ParticleData particleData = (ParticleEffect.ParticleData) new ParticleEffect.BlockData(Material.WOOL, (byte) 0); + ParticleEffect.BLOCK_CRACK.display(particleData, 1F, 1F, 1F, 0.1F, 10, collision.getLocationFirst(), 50); + } + } + /** * Breaks a breathbendng hold on an entity or one a player is inflicting on an entity. @@ -77,11 +90,15 @@ public abstract class AirAbility extends ElementalAbility { } /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + *

* Checks whether a location is within an AirShield. * * @param loc The location to check * @return true If the location is inside an AirShield. */ + @Deprecated public static boolean isWithinAirShield(Location loc) { List list = new ArrayList(); list.add("AirShield"); @@ -124,22 +141,30 @@ public abstract class AirAbility extends ElementalAbility { } /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + *

* Removes all air spouts in a location within a certain radius. * * @param loc The location to use * @param radius The radius around the location to remove spouts in * @param source The player causing the removal */ + @Deprecated public static void removeAirSpouts(Location loc, double radius, Player source) { AirSpout.removeSpouts(loc, radius, source); } /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + *

* Removes all air spouts in a location with a radius of 1.5. * * @param loc The location to use * @param source The player causing the removal */ + @Deprecated public static void removeAirSpouts(Location loc, Player source) { removeAirSpouts(loc, 1.5, source); } diff --git a/src/com/projectkorra/projectkorra/ability/CoreAbility.java b/src/com/projectkorra/projectkorra/ability/CoreAbility.java index 3efde921..1536c899 100644 --- a/src/com/projectkorra/projectkorra/ability/CoreAbility.java +++ b/src/com/projectkorra/projectkorra/ability/CoreAbility.java @@ -18,6 +18,7 @@ import java.util.concurrent.ConcurrentSkipListMap; import java.util.jar.JarFile; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -29,6 +30,8 @@ import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.Element.SubElement; import com.projectkorra.projectkorra.ProjectKorra; import com.projectkorra.projectkorra.ability.util.AbilityLoader; +import com.projectkorra.projectkorra.ability.util.Collision; +import com.projectkorra.projectkorra.ability.util.CollisionManager; import com.projectkorra.projectkorra.ability.util.ComboManager; import com.projectkorra.projectkorra.ability.util.MultiAbilityManager; import com.projectkorra.projectkorra.ability.util.MultiAbilityManager.MultiAbilityInfo; @@ -40,9 +43,14 @@ import com.projectkorra.projectkorra.event.AbilityStartEvent; import sun.reflect.ReflectionFactory; /** - * CoreAbility provides default implementation of an Ability, including methods to control - * the life cycle of a specific instance. CoreAbility also provides a system to load CoreAbilities - * within a {@link JavaPlugin}, or located in an external {@link JarFile}. + * CoreAbility provides default implementation of an Ability, including methods + * to control the life cycle of a specific instance. CoreAbility also provides a + * system to load CoreAbilities within a {@link JavaPlugin}, or located in an + * external {@link JarFile}. + *

+ * For {@link CollisionManager} and {@link Collision}, a CoreAbility may need to + * override {@link #isCollidable()}, {@link #getCollisionRadius()}, + * {@link #handleCollision(Collision)}, and {@link #getLocations()}. * * @see #start() * @see #progress() @@ -51,35 +59,41 @@ import sun.reflect.ReflectionFactory; * @see #registerPluginAbilities(JavaPlugin, String) */ public abstract class CoreAbility implements Ability { - + private static final Map, Map>> INSTANCES = new ConcurrentHashMap<>(); private static final Map, Set> INSTANCES_BY_CLASS = new ConcurrentHashMap<>(); - private static final Map ABILITIES_BY_NAME = new ConcurrentSkipListMap<>(); - + private static final Map ABILITIES_BY_NAME = new ConcurrentSkipListMap<>(); // preserves ordering + private static final Map, CoreAbility> ABILITIES_BY_CLASS = new ConcurrentHashMap<>(); + private static final double DEFAULT_COLLISION_RADIUS = 0.3; + private static int idCounter; - protected long startTime; protected Player player; protected BendingPlayer bPlayer; - + private boolean started; private boolean removed; private int id; + private long startTime; + private long startTick; static { idCounter = Integer.MIN_VALUE; } - + /** - * The default constructor is needed to create a fake instance of each CoreAbility via reflection - * in {@link #registerAbilities()}. More specifically, {@link #registerPluginAbilities} calls - * getDeclaredConstructor which is only usable with a public default constructor. Reflection lets us - * create a list of all of the plugin's abilities when the plugin first loads. + * The default constructor is needed to create a fake instance of each + * CoreAbility via reflection in {@link #registerAbilities()}. More + * specifically, {@link #registerPluginAbilities} calls + * getDeclaredConstructor which is only usable with a public default + * constructor. Reflection lets us create a list of all of the plugin's + * abilities when the plugin first loads. * * @see #ABILITIES_BY_NAME * @see #getAbility(String) */ - public CoreAbility() {} + public CoreAbility() { + } /** * Creates a new CoreAbility instance but does not start it. @@ -91,13 +105,14 @@ public abstract class CoreAbility implements Ability { if (player == null) { return; } - + this.player = player; this.bPlayer = BendingPlayer.getBendingPlayer(player); this.startTime = System.currentTimeMillis(); this.started = false; this.id = CoreAbility.idCounter; - + this.startTick = getCurrentTick(); + if (idCounter == Integer.MAX_VALUE) { idCounter = Integer.MIN_VALUE; } else { @@ -106,9 +121,10 @@ public abstract class CoreAbility implements Ability { } /** - * Causes the ability to begin updating every tick by calling {@link #progress()} - * until {@link #remove()} is called. This method cannot be overridden, and any code - * that needs to be performed before start should be handled in the constructor. + * Causes the ability to begin updating every tick by calling + * {@link #progress()} until {@link #remove()} is called. This method cannot + * be overridden, and any code that needs to be performed before start + * should be handled in the constructor. * * @see #getStartTime() * @see #isStarted() @@ -120,7 +136,7 @@ public abstract class CoreAbility implements Ability { } AbilityStartEvent event = new AbilityStartEvent(this); Bukkit.getServer().getPluginManager().callEvent(event); - if(event.isCancelled()) { + if (event.isCancelled()) { remove(); return; } @@ -144,11 +160,12 @@ public abstract class CoreAbility implements Ability { } /** - * Causes this CoreAbility instance to be removed, and {@link #progress} will no longer - * be called every tick. If this method is overridden then the new method must call - * super.remove(). + * Causes this CoreAbility instance to be removed, and {@link #progress} + * will no longer be called every tick. If this method is overridden then + * the new method must call super.remove(). * * {@inheritDoc} + * * @see #isRemoved() */ @Override @@ -156,10 +173,10 @@ public abstract class CoreAbility implements Ability { if (player == null) { return; } - + Bukkit.getServer().getPluginManager().callEvent(new AbilityEndEvent(this)); removed = true; - + Map> classMap = INSTANCES.get(getClass()); if (classMap != null) { Map playerMap = classMap.get(player.getUniqueId()); @@ -169,7 +186,7 @@ public abstract class CoreAbility implements Ability { classMap.remove(player.getUniqueId()); } } - + if (classMap.size() == 0) { INSTANCES.remove(getClass()); } @@ -194,7 +211,8 @@ public abstract class CoreAbility implements Ability { } /** - * Removes every CoreAbility instance that has been started but not yet removed. + * Removes every CoreAbility instance that has been started but not yet + * removed. */ public static void removeAll() { for (Set setAbils : INSTANCES_BY_CLASS.values()) { @@ -202,7 +220,7 @@ public abstract class CoreAbility implements Ability { abil.remove(); } } - + for (CoreAbility coreAbility : ABILITIES_BY_NAME.values()) { if (coreAbility instanceof AddonAbility) { AddonAbility addon = (AddonAbility) coreAbility; @@ -212,8 +230,8 @@ public abstract class CoreAbility implements Ability { } /** - * Returns any T CoreAbility that has been started and not yet removed. May return null if - * no such ability exists. + * Returns any T CoreAbility that has been started and not yet removed. May + * return null if no such ability exists. * * @param player the player that created the CoreAbility instance * @param clazz the class of the type of CoreAbility @@ -226,16 +244,18 @@ public abstract class CoreAbility implements Ability { } return null; } - + /** - * Returns a "fake" instance for the CoreAbility represented by abilityName. This method - * does not look into CoreAbility instances that were created by Players, instead this - * method looks at the CoreAbilities that were created via Reflection by {@link #registerAbilities()} - * when the plugin was first loaded. + * Returns a "fake" instance for the CoreAbility represented by abilityName. + * This method does not look into CoreAbility instances that were created by + * Players, instead this method looks at the CoreAbilities that were created + * via Reflection by {@link #registerAbilities()} when the plugin was first + * loaded. * - *

These "fake" instances have a null player, but methods such as - * {@link Ability#getName()}, and {@link Ability#getElement()} will still work, as will checking - * the type of the ability with instanceof. + *

+ * These "fake" instances have a null player, but methods such as + * {@link Ability#getName()}, and {@link Ability#getElement()} will still + * work, as will checking the type of the ability with instanceof. * *

* CoreAbility coreAbil = getAbility(someString);
@@ -247,16 +267,28 @@ public abstract class CoreAbility implements Ability { public static CoreAbility getAbility(String abilityName) { return abilityName != null ? ABILITIES_BY_NAME.get(abilityName.toLowerCase()) : null; } - + /** - * Returns a list of "fake" instances for each ability that was loaded by {@link #registerAbilities()} + * Returns a "fake" instance for a CoreAbility with the specific class. + * + * @param clazz the class for the type of CoreAbility to be returned + * @return a "fake" CoreAbility instance or null + */ + public static CoreAbility getAbility(Class clazz) { + return clazz != null ? ABILITIES_BY_CLASS.get(clazz) : null; + } + + /** + * @return a list of "fake" instances for each ability that was loaded by + * {@link #registerAbilities()} */ public static ArrayList getAbilities() { return new ArrayList(ABILITIES_BY_NAME.values()); } /** - * Returns a Collection of all of the player created instances for a specific type of CoreAbility. + * Returns a Collection of all of the player created instances for a + * specific type of CoreAbility. * * @param clazz the class for the type of CoreAbilities * @return a Collection of real instances @@ -270,7 +302,8 @@ public abstract class CoreAbility implements Ability { } /** - * Returns a Collection of specific CoreAbility instances that were created by the specified player. + * Returns a Collection of specific CoreAbility instances that were created + * by the specified player. * * @param player the player that created the instances * @param clazz the class for the type of CoreAbilities @@ -283,9 +316,10 @@ public abstract class CoreAbility implements Ability { } return (Collection) INSTANCES.get(clazz).get(player.getUniqueId()).values(); } - + /** - * Returns an List of fake instances that were loaded by {@link #registerAbilities()} filtered by Element. + * Returns an List of fake instances that were loaded by + * {@link #registerAbilities()} filtered by Element. * * @param element the Element of the loaded abilities * @return a list of fake CoreAbility instances @@ -306,7 +340,7 @@ public abstract class CoreAbility implements Ability { } return abilities; } - + /** * Returns true if the player has an active CoreAbility instance of type T. * @@ -316,9 +350,10 @@ public abstract class CoreAbility implements Ability { public static boolean hasAbility(Player player, Class clazz) { return getAbility(player, clazz) != null; } - + /** - * Returns a Set of all of the players that currently have an active instance of clazz. + * Returns a Set of all of the players that currently have an active + * instance of clazz. * * @param clazz the clazz for the type of CoreAbility */ @@ -337,10 +372,10 @@ public abstract class CoreAbility implements Ability { } return players; } - + /** - * Scans and loads plugin CoreAbilities, and Addon CoreAbilities that are located - * in a Jar file inside of the /ProjectKorra/Abilities/ folder. + * Scans and loads plugin CoreAbilities, and Addon CoreAbilities that are + * located in a Jar file inside of the /ProjectKorra/Abilities/ folder. */ public static void registerAbilities() { ABILITIES_BY_NAME.clear(); @@ -350,9 +385,10 @@ public abstract class CoreAbility implements Ability { /** * Scans a JavaPlugin and registers CoreAbility class files. - * + * * @param plugin a JavaPlugin containing CoreAbility class files - * @param packagePrefix a prefix of the package name, used to increase performance + * @param packagePrefix a prefix of the package name, used to increase + * performance * @see #getAbilities() * @see #getAbility(String) */ @@ -361,26 +397,26 @@ public abstract class CoreAbility implements Ability { if (plugin == null) { return; } - + Class pluginClass = plugin.getClass(); ClassLoader loader = pluginClass.getClassLoader(); ReflectionFactory rf = ReflectionFactory.getReflectionFactory(); - + try { for (final ClassInfo info : ClassPath.from(loader).getAllClasses()) { if (!info.getPackageName().startsWith(packagePrefix)) { continue; } - + Class clazz = null; try { clazz = info.load(); if (!CoreAbility.class.isAssignableFrom(clazz) || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { continue; } - + Constructor objDef = CoreAbility.class.getDeclaredConstructor(); - Constructor intConstr = rf.newConstructorForSerialization(clazz, objDef);; + Constructor intConstr = rf.newConstructorForSerialization(clazz, objDef); CoreAbility ability = (CoreAbility) clazz.cast(intConstr.newInstance()); if (ability == null || ability.getName() == null) { @@ -393,6 +429,7 @@ public abstract class CoreAbility implements Ability { String name = ability.getName(); ABILITIES_BY_NAME.put(ability.getName().toLowerCase(), ability); + ABILITIES_BY_CLASS.put(ability.getClass(), ability); if (ability instanceof ComboAbility) { ComboAbility combo = (ComboAbility) ability; @@ -407,25 +444,28 @@ public abstract class CoreAbility implements Ability { ComboManager.getAuthors().put(name, author); } } - + if (ability instanceof MultiAbility) { MultiAbility multiAbil = (MultiAbility) ability; MultiAbilityManager.multiAbilityList.add(new MultiAbilityInfo(name, multiAbil.getMultiAbilities())); } - + if (ability instanceof AddonAbility) { AddonAbility addon = (AddonAbility) ability; addon.load(); } - } catch (Exception e) { - } catch (Error e) { + } + catch (Exception e) { + } + catch (Error e) { } } - } catch (IOException e) { + } + catch (IOException e) { e.printStackTrace(); } } - + /** * Scans all of the Jar files inside of /ProjectKorra/folder and registers * all of the CoreAbility class files that were found. @@ -441,10 +481,10 @@ public abstract class CoreAbility implements Ability { path.mkdir(); return; } - + AbilityLoader abilityLoader = new AbilityLoader(plugin, path); List loadedAbilities = abilityLoader.load(CoreAbility.class, CoreAbility.class); - + for (CoreAbility coreAbil : loadedAbilities) { if (!(coreAbil instanceof AddonAbility)) { plugin.getLogger().warning(coreAbil.getName() + " is an addon ability and must implement the AddonAbility interface"); @@ -453,14 +493,14 @@ public abstract class CoreAbility implements Ability { plugin.getLogger().info(coreAbil.getName() + " is disabled"); continue; } - + AddonAbility addon = (AddonAbility) coreAbil; String name = coreAbil.getName(); - + try { addon.load(); ABILITIES_BY_NAME.put(name.toLowerCase(), coreAbil); - + if (coreAbil instanceof ComboAbility) { ComboAbility combo = (ComboAbility) coreAbil; if (combo.getCombination() != null) { @@ -470,28 +510,37 @@ public abstract class CoreAbility implements Ability { ComboManager.getAuthors().put(name, addon.getAuthor()); } } - + if (coreAbil instanceof MultiAbility) { MultiAbility multiAbil = (MultiAbility) coreAbil; MultiAbilityManager.multiAbilityList.add(new MultiAbilityInfo(name, multiAbil.getMultiAbilities())); } - } catch (Exception | Error e) { + } + catch (Exception | Error e) { plugin.getLogger().warning("The ability " + coreAbil.getName() + " was not able to load, if this message shows again please remove it!"); e.printStackTrace(); addon.stop(); - ABILITIES_BY_NAME.remove(name.toLowerCase()); + ABILITIES_BY_NAME.remove(name.toLowerCase()); } } } - + public long getStartTime() { return startTime; } + public long getStartTick() { + return startTick; + } + + public long getCurrentTick() { + return player.getWorld().getFullTime(); + } + public boolean isStarted() { return started; } - + public boolean isRemoved() { return removed; } @@ -503,37 +552,37 @@ public abstract class CoreAbility implements Ability { public int getId() { return id; } - + @Override public boolean isHiddenAbility() { return false; } - + @Override public boolean isEnabled() { if (this instanceof AddonAbility) { return true; } - + String elementName = getElement().getName(); if (getElement() instanceof SubElement) { elementName = ((SubElement) getElement()).getParentElement().getName(); } - + String tag = null; if (this instanceof ComboAbility) { - tag = "Abilities." + elementName + "." + elementName + "Combo." + getName() + ".Enabled"; + tag = "Abilities." + elementName + "." + elementName + "Combo." + getName() + ".Enabled"; } else { tag = "Abilities." + elementName + "." + getName() + ".Enabled"; } - + if (getConfig().isBoolean(tag)) { return getConfig().getBoolean(tag); } else { return true; } } - + @Override public String getDescription() { String elementName = getElement().getName(); @@ -547,36 +596,98 @@ public abstract class CoreAbility implements Ability { public Player getPlayer() { return player; } - + + /** + * Used by the CollisionManager to check if two instances can collide with + * each other. For example, an EarthBlast is not collidable right when the + * person selects a source block, but it is collidable once the block begins + * traveling. + * + * @return true if the instance is currently collidable + * @see CollisionManager + */ + public boolean isCollidable() { + return true; + } + + /** + * The radius for collision of the ability instance. Some circular abilities + * are better represented with 1 single Location with a small or large + * radius, such as AirShield, FireShield, EarthSmash, WaterManipulation, + * EarthBlast, etc. Some abilities consist of multiple Locations with small + * radiuses, such as AirSpout, WaterSpout, Torrent, RaiseEarth, AirSwipe, + * FireKick, etc. + * + * @return the radius for a location returned by {@link #getLocations()} + * @see CollisionManager + */ + public double getCollisionRadius() { + return DEFAULT_COLLISION_RADIUS; + } + + /** + * Called when this ability instance collides with another. Some abilities + * may want advanced behavior on a Collision; e.g. FireCombos only remove + * the stream that was hit rather than the entire ability. + *

+ * collision.getAbilitySecond() - the ability that we are colliding with + * collision.isRemovingFirst() - if this ability should be removed + *

+ * This ability should only worry about itself because handleCollision will + * be called for the other ability instance as well. + * + * @param collision with data about the other ability instance + * @see CollisionManager + */ + public void handleCollision(Collision collision) { + if (collision.isRemovingFirst()) { + remove(); + } + } + + /** + * A List of Locations used to represent the ability. Some abilities might + * just be 1 Location with a radius, while some might be multiple Locations + * with small radiuses. + * + * @return a List of the ability's locations + * @see CollisionManager + */ + public List getLocations() { + ArrayList locations = new ArrayList<>(); + locations.add(getLocation()); + return locations; + } + /** * @return the current FileConfiguration for the plugin */ public static FileConfiguration getConfig() { return ConfigManager.getConfig(); } - + /** * @return the language.yml for the plugin */ public static FileConfiguration getLanguageConfig() { return ConfigManager.languageConfig.get(); } - + /** - * Returns a String used to debug potential CoreAbility memory that can be caused - * by a developer forgetting to call {@link #remove()} + * Returns a String used to debug potential CoreAbility memory that can be + * caused by a developer forgetting to call {@link #remove()} */ public static String getDebugString() { StringBuilder sb = new StringBuilder(); int playerCounter = 0; HashMap classCounter = new HashMap<>(); - + for (Map> map1 : INSTANCES.values()) { playerCounter++; for (Map map2 : map1.values()) { for (CoreAbility coreAbil : map2.values()) { String simpleName = coreAbil.getClass().getSimpleName(); - + if (classCounter.containsKey(simpleName)) { classCounter.put(simpleName, classCounter.get(simpleName) + 1); } else { @@ -585,7 +696,7 @@ public abstract class CoreAbility implements Ability { } } } - + for (Set set : INSTANCES_BY_CLASS.values()) { for (CoreAbility coreAbil : set) { String simpleName = coreAbil.getClass().getSimpleName(); @@ -596,7 +707,7 @@ public abstract class CoreAbility implements Ability { } } } - + sb.append("Class->UUID's in memory: " + playerCounter + "\n"); sb.append("Abilities in memory:\n"); for (String className : classCounter.keySet()) { @@ -604,4 +715,9 @@ public abstract class CoreAbility implements Ability { } return sb.toString(); } + + public static double getDefaultCollisionRadius() { + return DEFAULT_COLLISION_RADIUS; + } + } diff --git a/src/com/projectkorra/projectkorra/ability/EarthAbility.java b/src/com/projectkorra/projectkorra/ability/EarthAbility.java index e3f7a0e0..c62bd0f6 100644 --- a/src/com/projectkorra/projectkorra/ability/EarthAbility.java +++ b/src/com/projectkorra/projectkorra/ability/EarthAbility.java @@ -21,6 +21,7 @@ import org.bukkit.util.Vector; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.configuration.ConfigManager; import com.projectkorra.projectkorra.earthbending.EarthPassive; import com.projectkorra.projectkorra.earthbending.LavaFlow; @@ -30,6 +31,7 @@ import com.projectkorra.projectkorra.firebending.Illumination; import com.projectkorra.projectkorra.util.BlockSource; import com.projectkorra.projectkorra.util.Information; import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.ParticleEffect.ParticleData; import com.projectkorra.projectkorra.util.TempBlock; public abstract class EarthAbility extends ElementalAbility { @@ -82,6 +84,15 @@ public abstract class EarthAbility extends ElementalAbility { return false; } + @Override + public void handleCollision(Collision collision) { + super.handleCollision(collision); + if (collision.isRemovingFirst()) { + ParticleData particleData = (ParticleEffect.ParticleData) new ParticleEffect.BlockData(Material.DIRT, (byte) 0); + ParticleEffect.BLOCK_CRACK.display(particleData, 1F, 1F, 1F, 0.1F, 10, collision.getLocationFirst(), 50); + } + } + public static boolean isEarthbendable(Material material) { return isEarth(material) || isMetal(material) || isSand(material) || isLava(material); } diff --git a/src/com/projectkorra/projectkorra/ability/FireAbility.java b/src/com/projectkorra/projectkorra/ability/FireAbility.java index b5d2af58..dbfcdfde 100644 --- a/src/com/projectkorra/projectkorra/ability/FireAbility.java +++ b/src/com/projectkorra/projectkorra/ability/FireAbility.java @@ -19,11 +19,13 @@ import org.bukkit.inventory.ItemStack; import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.configuration.ConfigManager; import com.projectkorra.projectkorra.firebending.BlazeArc; import com.projectkorra.projectkorra.firebending.HeatControl; import com.projectkorra.projectkorra.util.Information; import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.ParticleEffect.ParticleData; import com.projectkorra.rpg.RPGMethods; public abstract class FireAbility extends ElementalAbility { @@ -60,6 +62,15 @@ public abstract class FireAbility extends ElementalAbility { public Element getElement() { return Element.FIRE; } + + @Override + public void handleCollision(Collision collision) { + super.handleCollision(collision); + if (collision.isRemovingFirst()) { + ParticleData particleData = (ParticleEffect.ParticleData) new ParticleEffect.BlockData(Material.FIRE, (byte) 0); + ParticleEffect.BLOCK_CRACK.display(particleData, 1F, 1F, 1F, 0.1F, 10, collision.getLocationFirst(), 50); + } + } public double getDayFactor(double value) { return player != null ? getDayFactor(value, player.getWorld()) : 1; @@ -140,11 +151,15 @@ public abstract class FireAbility extends ElementalAbility { } /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + *

* Checks whether a location is within a FireShield. * * @param loc The location to check * @return true If the location is inside a FireShield. */ + @Deprecated public static boolean isWithinFireShield(Location loc) { List list = new ArrayList(); list.add("FireShield"); diff --git a/src/com/projectkorra/projectkorra/ability/WaterAbility.java b/src/com/projectkorra/projectkorra/ability/WaterAbility.java index ff5fe1cc..740518f5 100644 --- a/src/com/projectkorra/projectkorra/ability/WaterAbility.java +++ b/src/com/projectkorra/projectkorra/ability/WaterAbility.java @@ -3,8 +3,11 @@ package com.projectkorra.projectkorra.ability; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.Element; import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.util.BlockSource; +import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; +import com.projectkorra.projectkorra.util.ParticleEffect.ParticleData; import com.projectkorra.projectkorra.waterbending.PhaseChangeFreeze; import com.projectkorra.projectkorra.waterbending.PhaseChangeMelt; import com.projectkorra.projectkorra.waterbending.SurgeWall; @@ -75,6 +78,15 @@ public abstract class WaterAbility extends ElementalAbility { return false; } + @Override + public void handleCollision(Collision collision) { + super.handleCollision(collision); + if (collision.isRemovingFirst()) { + ParticleData particleData = (ParticleEffect.ParticleData) new ParticleEffect.BlockData(Material.WATER, (byte) 0); + ParticleEffect.BLOCK_CRACK.display(particleData, 1F, 1F, 1F, 0.1F, 10, collision.getLocationFirst(), 50); + } + } + public boolean isIcebendable(Block block) { return isIcebendable(block.getType()); } @@ -301,22 +313,30 @@ public abstract class WaterAbility extends ElementalAbility { } /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + *

* Removes all water spouts in a location within a certain radius. * * @param loc The location to use * @param radius The radius around the location to remove spouts in * @param source The player causing the removal */ + @Deprecated public static void removeWaterSpouts(Location loc, double radius, Player source) { WaterSpout.removeSpouts(loc, radius, source); } /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + *

* Removes all water spouts in a location with a radius of 1.5. * * @param loc The location to use * @param source The player causing the removal */ + @Deprecated public static void removeWaterSpouts(Location loc, Player source) { removeWaterSpouts(loc, 1.5, source); } diff --git a/src/com/projectkorra/projectkorra/ability/util/Collision.java b/src/com/projectkorra/projectkorra/ability/util/Collision.java new file mode 100644 index 00000000..837cfbf1 --- /dev/null +++ b/src/com/projectkorra/projectkorra/ability/util/Collision.java @@ -0,0 +1,86 @@ +package com.projectkorra.projectkorra.ability.util; + +import org.bukkit.Location; + +import com.projectkorra.projectkorra.ability.CoreAbility; + +/** + * A Collision is used to represent the collision between two CoreAbility + * objects. + * + * @see CollisionManager + */ +public class Collision { + private CoreAbility abilityFirst; + private CoreAbility abilitySecond; + private boolean removingFirst; + private boolean removingSecond; + private Location locationFirst; + private Location locationSecond; + + public Collision(CoreAbility abilityFirst, CoreAbility abilitySecond, boolean removingFirst, boolean removingSecond, Location locationFirst, Location locationSecond) { + if (abilityFirst == null || abilitySecond == null) { + return; + } + + this.abilityFirst = abilityFirst; + this.abilitySecond = abilitySecond; + this.removingFirst = removingFirst; + this.removingSecond = removingSecond; + this.locationFirst = locationFirst; + this.locationSecond = locationSecond; + } + + public Collision(CoreAbility abilityFirst, CoreAbility abilitySecond, boolean removingFirst, boolean removingSecond) { + this(abilityFirst, abilitySecond, removingFirst, removingSecond, null, null); + } + + public CoreAbility getAbilityFirst() { + return abilityFirst; + } + + public void setAbilityFirst(CoreAbility abilityFirst) { + this.abilityFirst = abilityFirst; + } + + public CoreAbility getAbilitySecond() { + return abilitySecond; + } + + public void setAbilitySecond(CoreAbility abilitySecond) { + this.abilitySecond = abilitySecond; + } + + public boolean isRemovingFirst() { + return removingFirst; + } + + public void setRemovingFirst(boolean removingFirst) { + this.removingFirst = removingFirst; + } + + public boolean isRemovingSecond() { + return removingSecond; + } + + public void setRemovingSecond(boolean removingSecond) { + this.removingSecond = removingSecond; + } + + public Location getLocationFirst() { + return locationFirst; + } + + public void setLocationFirst(Location locationFirst) { + this.locationFirst = locationFirst; + } + + public Location getLocationSecond() { + return locationSecond; + } + + public void setLocationSecond(Location locationSecond) { + this.locationSecond = locationSecond; + } + +} diff --git a/src/com/projectkorra/projectkorra/ability/util/CollisionInitializer.java b/src/com/projectkorra/projectkorra/ability/util/CollisionInitializer.java new file mode 100644 index 00000000..d3057c1f --- /dev/null +++ b/src/com/projectkorra/projectkorra/ability/util/CollisionInitializer.java @@ -0,0 +1,176 @@ +package com.projectkorra.projectkorra.ability.util; + +import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.airbending.AirBlast; +import com.projectkorra.projectkorra.airbending.AirBubble; +import com.projectkorra.projectkorra.airbending.AirCombo; +import com.projectkorra.projectkorra.airbending.AirCombo.AirStream; +import com.projectkorra.projectkorra.airbending.AirCombo.AirSweep; +import com.projectkorra.projectkorra.airbending.AirFlight; +import com.projectkorra.projectkorra.airbending.AirScooter; +import com.projectkorra.projectkorra.airbending.AirShield; +import com.projectkorra.projectkorra.airbending.AirSpout; +import com.projectkorra.projectkorra.airbending.AirSuction; +import com.projectkorra.projectkorra.airbending.AirSwipe; +import com.projectkorra.projectkorra.airbending.Suffocate; +import com.projectkorra.projectkorra.airbending.Tornado; +import com.projectkorra.projectkorra.earthbending.Catapult; +import com.projectkorra.projectkorra.earthbending.Collapse; +import com.projectkorra.projectkorra.earthbending.EarthArmor; +import com.projectkorra.projectkorra.earthbending.EarthBlast; +import com.projectkorra.projectkorra.earthbending.EarthSmash; +import com.projectkorra.projectkorra.earthbending.EarthTunnel; +import com.projectkorra.projectkorra.earthbending.LavaFlow; +import com.projectkorra.projectkorra.earthbending.RaiseEarth; +import com.projectkorra.projectkorra.earthbending.Ripple; +import com.projectkorra.projectkorra.earthbending.SandSpout; +import com.projectkorra.projectkorra.firebending.BlazeArc; +import com.projectkorra.projectkorra.firebending.Combustion; +import com.projectkorra.projectkorra.firebending.FireBlast; +import com.projectkorra.projectkorra.firebending.FireBlastCharged; +import com.projectkorra.projectkorra.firebending.FireCombo; +import com.projectkorra.projectkorra.firebending.FireCombo.FireKick; +import com.projectkorra.projectkorra.firebending.FireCombo.FireSpin; +import com.projectkorra.projectkorra.firebending.FireCombo.FireWheel; +import com.projectkorra.projectkorra.firebending.FireJet; +import com.projectkorra.projectkorra.firebending.FireShield; +import com.projectkorra.projectkorra.firebending.Lightning; +import com.projectkorra.projectkorra.firebending.WallOfFire; +import com.projectkorra.projectkorra.waterbending.Bloodbending; +import com.projectkorra.projectkorra.waterbending.HealingWaters; +import com.projectkorra.projectkorra.waterbending.IceBlast; +import com.projectkorra.projectkorra.waterbending.IceSpikeBlast; +import com.projectkorra.projectkorra.waterbending.OctopusForm; +import com.projectkorra.projectkorra.waterbending.PlantArmor; +import com.projectkorra.projectkorra.waterbending.SurgeWall; +import com.projectkorra.projectkorra.waterbending.SurgeWave; +import com.projectkorra.projectkorra.waterbending.Torrent; +import com.projectkorra.projectkorra.waterbending.TorrentWave; +import com.projectkorra.projectkorra.waterbending.WaterBubble; +import com.projectkorra.projectkorra.waterbending.WaterCombo; +import com.projectkorra.projectkorra.waterbending.WaterCombo.IceBullet; +import com.projectkorra.projectkorra.waterbending.WaterCombo.IceWave; +import com.projectkorra.projectkorra.waterbending.WaterManipulation; +import com.projectkorra.projectkorra.waterbending.WaterSpout; +import com.projectkorra.projectkorra.waterbending.WaterSpoutWave; + +/** + * CollisionInitializer is used to create the default Collisions for a given + * CollisionManager. + * + * @see Collision + * @see CollisionManager + */ +public class CollisionInitializer { + + private CollisionManager cm; + + public CollisionInitializer(CollisionManager cm) { + this.cm = cm; + } + + @SuppressWarnings("unused") + public void initializeCollisions() { + CoreAbility airBlast = CoreAbility.getAbility(AirBlast.class); + CoreAbility airBubble = CoreAbility.getAbility(AirBubble.class); + CoreAbility airCombo = CoreAbility.getAbility(AirCombo.class); + CoreAbility airFlight = CoreAbility.getAbility(AirFlight.class); + CoreAbility airScooter = CoreAbility.getAbility(AirScooter.class); + CoreAbility airShield = CoreAbility.getAbility(AirShield.class); + CoreAbility airSpout = CoreAbility.getAbility(AirSpout.class); + CoreAbility airStream = CoreAbility.getAbility(AirStream.class); + CoreAbility airSuction = CoreAbility.getAbility(AirSuction.class); + CoreAbility airSweep = CoreAbility.getAbility(AirSweep.class); + CoreAbility airSwipe = CoreAbility.getAbility(AirSwipe.class); + CoreAbility suffocate = CoreAbility.getAbility(Suffocate.class); + CoreAbility tornado = CoreAbility.getAbility(Tornado.class); + + CoreAbility catapult = CoreAbility.getAbility(Catapult.class); + CoreAbility collapse = CoreAbility.getAbility(Collapse.class); + CoreAbility earthArmor = CoreAbility.getAbility(EarthArmor.class); + CoreAbility earthBlast = CoreAbility.getAbility(EarthBlast.class); + CoreAbility earthSmash = CoreAbility.getAbility(EarthSmash.class); + CoreAbility earthTunnel = CoreAbility.getAbility(EarthTunnel.class); + CoreAbility lavaFlow = CoreAbility.getAbility(LavaFlow.class); + CoreAbility raiseEarth = CoreAbility.getAbility(RaiseEarth.class); + CoreAbility ripple = CoreAbility.getAbility(Ripple.class); + CoreAbility sandSpout = CoreAbility.getAbility(SandSpout.class); + + CoreAbility blazeArc = CoreAbility.getAbility(BlazeArc.class); + CoreAbility combustion = CoreAbility.getAbility(Combustion.class); + CoreAbility fireBlast = CoreAbility.getAbility(FireBlast.class); + CoreAbility fireBlastCharged = CoreAbility.getAbility(FireBlastCharged.class); + CoreAbility fireCombo = CoreAbility.getAbility(FireCombo.class); + CoreAbility fireJet = CoreAbility.getAbility(FireJet.class); + CoreAbility fireKick = CoreAbility.getAbility(FireKick.class); + CoreAbility fireSpin = CoreAbility.getAbility(FireSpin.class); + CoreAbility fireWheel = CoreAbility.getAbility(FireWheel.class); + CoreAbility fireShield = CoreAbility.getAbility(FireShield.class); + CoreAbility lightning = CoreAbility.getAbility(Lightning.class); + CoreAbility wallOfFire = CoreAbility.getAbility(WallOfFire.class); + + CoreAbility bloodbending = CoreAbility.getAbility(Bloodbending.class); + CoreAbility healingWaters = CoreAbility.getAbility(HealingWaters.class); + CoreAbility iceBlast = CoreAbility.getAbility(IceBlast.class); + CoreAbility iceBullet = CoreAbility.getAbility(IceBullet.class); + CoreAbility iceWave = CoreAbility.getAbility(IceWave.class); + CoreAbility iceSpikeBlast = CoreAbility.getAbility(IceSpikeBlast.class); + CoreAbility octopusForm = CoreAbility.getAbility(OctopusForm.class); + CoreAbility plantArmor = CoreAbility.getAbility(PlantArmor.class); + CoreAbility surgeWall = CoreAbility.getAbility(SurgeWall.class); + CoreAbility surgeWave = CoreAbility.getAbility(SurgeWave.class); + CoreAbility torrent = CoreAbility.getAbility(Torrent.class); + CoreAbility torrentWave = CoreAbility.getAbility(TorrentWave.class); + CoreAbility waterBubble = CoreAbility.getAbility(WaterBubble.class); + CoreAbility waterCombo = CoreAbility.getAbility(WaterCombo.class); + CoreAbility waterManipulation = CoreAbility.getAbility(WaterManipulation.class); + CoreAbility waterSpout = CoreAbility.getAbility(WaterSpout.class); + CoreAbility waterSpoutWave = CoreAbility.getAbility(WaterSpoutWave.class); + + CoreAbility[] smallDamageAbils = { airSwipe, earthBlast, waterManipulation, fireBlast, combustion, blazeArc }; + CoreAbility[] abilitiesThatRemoveSmall = { earthSmash, airShield, airCombo, fireCombo, waterCombo, fireBlastCharged }; + CoreAbility[] abilsThatRemoveSpouts = { airSwipe, earthBlast, waterManipulation, fireBlast, fireBlastCharged, earthSmash, fireCombo, airCombo, waterCombo }; + CoreAbility[] damageComboAbils = { fireKick, fireSpin, fireWheel, airSweep, iceBullet }; + + // All small damaging abilities block each other + for (int i = 0; i < smallDamageAbils.length; i++) { + for (int j = i; j < smallDamageAbils.length; j++) { + cm.add(new Collision(smallDamageAbils[i], smallDamageAbils[j], true, true)); + } + } + + // All combos block each other + for (int i = 0; i < damageComboAbils.length; i++) { + for (int j = i; j < damageComboAbils.length; j++) { + cm.add(new Collision(damageComboAbils[i], damageComboAbils[j], true, true)); + } + } + + // These abilities remove all small damaging abilities + for (CoreAbility abilThatRemoves : abilitiesThatRemoveSmall) { + for (CoreAbility smallDamageAbil : smallDamageAbils) { + cm.add(new Collision(abilThatRemoves, smallDamageAbil, false, true)); + } + } + + for (CoreAbility spoutDestroyAbil : abilsThatRemoveSpouts) { + cm.add(new Collision(spoutDestroyAbil, airSpout, false, true)); + cm.add(new Collision(spoutDestroyAbil, waterSpout, false, true)); + cm.add(new Collision(spoutDestroyAbil, sandSpout, false, true)); + } + + cm.add(new Collision(airShield, airBlast, false, true)); + cm.add(new Collision(airShield, airSuction, false, true)); + cm.add(new Collision(airShield, airStream, false, true)); + for (CoreAbility comboAbil : damageComboAbils) { + cm.add(new Collision(airShield, comboAbil, false, true)); + } + + cm.add(new Collision(fireShield, fireBlast, false, true)); + cm.add(new Collision(fireShield, fireBlastCharged, false, true)); + cm.add(new Collision(fireShield, waterManipulation, false, true)); + cm.add(new Collision(fireShield, earthBlast, false, true)); + cm.add(new Collision(fireShield, airSweep, false, true)); + } + +} diff --git a/src/com/projectkorra/projectkorra/ability/util/CollisionManager.java b/src/com/projectkorra/projectkorra/ability/util/CollisionManager.java new file mode 100644 index 00000000..5a7d6ba8 --- /dev/null +++ b/src/com/projectkorra/projectkorra/ability/util/CollisionManager.java @@ -0,0 +1,245 @@ +package com.projectkorra.projectkorra.ability.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.scheduler.BukkitRunnable; + +import com.projectkorra.projectkorra.ProjectKorra; +import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.event.AbilityCollisionEvent; + +/** + * A CollisionManager is used to monitor possible collisions between all + * CoreAbilities. Use {@link #add(Collision)} to begin monitoring for collision + * between two abilities, as shown in {@link CollisionInitializer}. + *

+ * For a CoreAbility to collide properly, the {@link CoreAbility#isCollidable()} + * , {@link CoreAbility#getCollisionRadius()}, + * {@link CoreAbility#getLocations()}, and {@link CoreAbility#handleCollision()} + * should be overridden if necessary. + *

+ * During a Collision the {@link AbilityCollisionEvent} is called, then if not + * cancelled, abilityFirst.handleCollision, and finally + * abilitySecond.handleCollision. + */ +public class CollisionManager { + + /* + * If true an ability instance can remove multiple other instances on a + * single tick. e.g. 3 Colliding WaterManipulations can all be removed + * instantly, rather than just 2. + */ + private boolean removeMultipleInstances; + + /* + * The amount of ticks in between checking for collisions. Higher values + * reduce lag but are less accurate in detection. + */ + private long detectionDelay; + + /* + * The amount of ticks that an ability must be alive before considered as + * collidable. Some CoreAbilities are started even though they will be + * removed on the next tick in progress, in these cases we do not want to + * consider those abilities for collision. + */ + private long minAbilityTickAlive; + + /* + * Used for efficiency. The distance that we can guarantee that two + * abilities will not collide so that we can stop comparing locations early. + * For example, two Torrents that are thousands of blocks apart should not + * be fully checked. + */ + private double certainNoCollisionDistance; + + private ArrayList collisions; + private BukkitRunnable detectionRunnable; + + public CollisionManager() { + this.removeMultipleInstances = true; + this.detectionDelay = 1; + this.minAbilityTickAlive = 3; + this.certainNoCollisionDistance = 100; + collisions = new ArrayList<>(); + } + + private void detectCollisions() { + HashMap> locationsCache = new HashMap<>(); + + for (Collision collision : collisions) { + Collection instancesFirst = CoreAbility.getAbilities(collision.getAbilityFirst().getClass()); + Collection instancesSecond = CoreAbility.getAbilities(collision.getAbilitySecond().getClass()); + HashSet alreadyCollided = new HashSet(); + double certainNoCollisionDistSquared = Math.pow(certainNoCollisionDistance, 2); + + for (CoreAbility abilityFirst : instancesFirst) { + if (abilityFirst.getPlayer() == null || alreadyCollided.contains(abilityFirst) || !abilityFirst.isCollidable() || abilityFirst.getCurrentTick() - abilityFirst.getStartTick() < minAbilityTickAlive) { + continue; + } + + if (!locationsCache.containsKey(abilityFirst)) { + locationsCache.put(abilityFirst, abilityFirst.getLocations()); + } + List locationsFirst = locationsCache.get(abilityFirst); + if (locationsFirst == null) { + continue; + } + + for (CoreAbility abilitySecond : instancesSecond) { + if (abilitySecond.getPlayer() == null || alreadyCollided.contains(abilitySecond) || !abilitySecond.isCollidable() || abilitySecond.getCurrentTick() - abilitySecond.getStartTick() < minAbilityTickAlive) { + continue; + } else if (abilityFirst.getPlayer().equals(abilitySecond.getPlayer())) { + continue; + } + + if (!locationsCache.containsKey(abilitySecond)) { + locationsCache.put(abilitySecond, abilitySecond.getLocations()); + } + List locationsSecond = locationsCache.get(abilitySecond); + if (locationsSecond == null) { + continue; + } + + boolean collided = false; + boolean certainNoCollision = false; // Used for efficiency + Location locationFirst = null; + Location locationSecond = null; + double requiredDist = abilityFirst.getCollisionRadius() + abilitySecond.getCollisionRadius(); + double requiredDistSquared = Math.pow(requiredDist, 2); + + for (int i = 0; i < locationsFirst.size(); i++) { + locationFirst = locationsFirst.get(i); + if (locationFirst == null) { + continue; + } + for (int j = 0; j < locationsSecond.size(); j++) { + locationSecond = locationsSecond.get(j); + if (locationSecond == null) { + continue; + } + + double distSquared = locationFirst.distanceSquared(locationSecond); + if (distSquared <= requiredDistSquared) { + collided = true; + break; + } else if (distSquared >= certainNoCollisionDistSquared) { + certainNoCollision = true; + break; + } + } + if (collided || certainNoCollision) { + break; + } + } + + if (collided) { + Collision forwardCollision = new Collision(abilityFirst, abilitySecond, collision.isRemovingFirst(), collision.isRemovingSecond(), locationFirst, locationSecond); + Collision reverseCollision = new Collision(abilitySecond, abilityFirst, collision.isRemovingSecond(), collision.isRemovingFirst(), locationSecond, locationFirst); + AbilityCollisionEvent event = new AbilityCollisionEvent(forwardCollision); + Bukkit.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + continue; + } + abilityFirst.handleCollision(forwardCollision); + abilitySecond.handleCollision(reverseCollision); + if (!removeMultipleInstances) { + alreadyCollided.add(abilityFirst); + alreadyCollided.add(abilitySecond); + break; + } + } + } + } + } + } + + /** + * Adds a new Collision to the CollisionManager so that two abilities can be + * checked for collisions. + * + * @param collision a Collision containing two CoreAbility classes + */ + public void add(Collision collision) { + collisions.add(collision); + } + + /** + * Begins a BukkitRunnable to check for Collisions. + */ + public void startCollisionDetection() { + stopCollisionDetection(); + detectionRunnable = new BukkitRunnable() { + @Override + public void run() { + detectCollisions(); + } + }; + detectionRunnable.runTaskTimer(ProjectKorra.plugin, 0L, detectionDelay); + } + + /** + * Stops the collision detecting BukkitRunnable. + */ + public void stopCollisionDetection() { + if (detectionRunnable != null) { + detectionRunnable.cancel(); + detectionRunnable = null; + } + } + + public boolean isRemoveMultipleInstances() { + return removeMultipleInstances; + } + + public void setRemoveMultipleInstances(boolean removeMultipleInstances) { + this.removeMultipleInstances = removeMultipleInstances; + } + + public long getDetectionDelay() { + return detectionDelay; + } + + public void setDetectionDelay(long detectionDelay) { + this.detectionDelay = detectionDelay; + } + + public long getMinAbilityTickAlive() { + return minAbilityTickAlive; + } + + public void setMinAbilityTickAlive(long minAbilityTickAlive) { + this.minAbilityTickAlive = minAbilityTickAlive; + } + + public double getCertainNoCollisionDistance() { + return certainNoCollisionDistance; + } + + public void setCertainNoCollisionDistance(double certainNoCollisionDistance) { + this.certainNoCollisionDistance = certainNoCollisionDistance; + } + + public ArrayList getCollisions() { + return collisions; + } + + public void setCollisions(ArrayList collisions) { + this.collisions = collisions; + } + + public BukkitRunnable getDetectionRunnable() { + return detectionRunnable; + } + + public void setDetectionRunnable(BukkitRunnable detectionRunnable) { + this.detectionRunnable = detectionRunnable; + } + +} diff --git a/src/com/projectkorra/projectkorra/ability/util/ComboManager.java b/src/com/projectkorra/projectkorra/ability/util/ComboManager.java index 613c30c0..874c1f96 100644 --- a/src/com/projectkorra/projectkorra/ability/util/ComboManager.java +++ b/src/com/projectkorra/projectkorra/ability/util/ComboManager.java @@ -15,12 +15,22 @@ import com.projectkorra.projectkorra.Element.SubElement; import com.projectkorra.projectkorra.ProjectKorra; import com.projectkorra.projectkorra.ability.ComboAbility; import com.projectkorra.projectkorra.ability.CoreAbility; -import com.projectkorra.projectkorra.airbending.AirCombo; -import com.projectkorra.projectkorra.chiblocking.ChiCombo; +import com.projectkorra.projectkorra.airbending.AirCombo.AirStream; +import com.projectkorra.projectkorra.airbending.AirCombo.AirSweep; +import com.projectkorra.projectkorra.airbending.AirCombo.Twister; +import com.projectkorra.projectkorra.chiblocking.ChiCombo.Immobilize; import com.projectkorra.projectkorra.configuration.ConfigManager; -import com.projectkorra.projectkorra.firebending.FireCombo; +import com.projectkorra.projectkorra.firebending.FireCombo.FireKick; +import com.projectkorra.projectkorra.firebending.FireCombo.FireSpin; +import com.projectkorra.projectkorra.firebending.FireCombo.FireWheel; +import com.projectkorra.projectkorra.firebending.FireCombo.JetBlast; +import com.projectkorra.projectkorra.firebending.FireCombo.JetBlaze; import com.projectkorra.projectkorra.util.ClickType; -import com.projectkorra.projectkorra.waterbending.WaterCombo; +import com.projectkorra.projectkorra.util.ReflectionHandler; +import com.projectkorra.projectkorra.waterbending.WaterCombo.IceBullet; +import com.projectkorra.projectkorra.waterbending.WaterCombo.IceBulletLeftClick; +import com.projectkorra.projectkorra.waterbending.WaterCombo.IceBulletRightClick; +import com.projectkorra.projectkorra.waterbending.WaterCombo.IceWave; public class ComboManager { @@ -42,7 +52,7 @@ public class ComboManager { fireKick.add(new AbilityInformation("FireBlast", ClickType.LEFT_CLICK)); fireKick.add(new AbilityInformation("FireBlast", ClickType.SHIFT_DOWN)); fireKick.add(new AbilityInformation("FireBlast", ClickType.LEFT_CLICK)); - COMBO_ABILITIES.put("FireKick", new ComboAbilityInfo("FireKick", fireKick, FireCombo.class)); + COMBO_ABILITIES.put("FireKick", new ComboAbilityInfo("FireKick", fireKick, FireKick.class)); DESCRIPTIONS.put("FireKick", ConfigManager.languageConfig.get().getString("Abilities.Fire.Combo.FireKick.Description")); INSTRUCTIONS.put("FireKick", "FireBlast > FireBlast > (Hold Shift) > FireBlast."); } @@ -54,7 +64,7 @@ public class ComboManager { fireSpin.add(new AbilityInformation("FireShield", ClickType.LEFT_CLICK)); fireSpin.add(new AbilityInformation("FireShield", ClickType.SHIFT_DOWN)); fireSpin.add(new AbilityInformation("FireShield", ClickType.SHIFT_UP)); - COMBO_ABILITIES.put("FireSpin", new ComboAbilityInfo("FireSpin", fireSpin, FireCombo.class)); + COMBO_ABILITIES.put("FireSpin", new ComboAbilityInfo("FireSpin", fireSpin, FireSpin.class)); DESCRIPTIONS.put("FireSpin", ConfigManager.languageConfig.get().getString("Abilities.Fire.Combo.FireSpin.Description")); INSTRUCTIONS.put("FireSpin", "FireBlast > FireBlast > FireShield > (Tap Shift)."); } @@ -68,7 +78,7 @@ public class ComboManager { jetBlast.add(new AbilityInformation("FireShield", ClickType.SHIFT_DOWN)); jetBlast.add(new AbilityInformation("FireShield", ClickType.SHIFT_UP)); jetBlast.add(new AbilityInformation("FireJet", ClickType.LEFT_CLICK)); - COMBO_ABILITIES.put("JetBlast", new ComboAbilityInfo("JetBlast", jetBlast, FireCombo.class)); + COMBO_ABILITIES.put("JetBlast", new ComboAbilityInfo("JetBlast", jetBlast, JetBlast.class)); DESCRIPTIONS.put("JetBlast", ConfigManager.languageConfig.get().getString("Abilities.Fire.Combo.JetBlast.Description")); INSTRUCTIONS.put("JetBlast", "FireJet (Tap Shift) > FireJet (Tap Shift) > FireShield (Tap Shift) > FireJet."); } @@ -82,7 +92,7 @@ public class ComboManager { jetBlaze.add(new AbilityInformation("Blaze", ClickType.SHIFT_DOWN)); jetBlaze.add(new AbilityInformation("Blaze", ClickType.SHIFT_UP)); jetBlaze.add(new AbilityInformation("FireJet", ClickType.LEFT_CLICK)); - COMBO_ABILITIES.put("JetBlaze", new ComboAbilityInfo("JetBlaze", jetBlaze, FireCombo.class)); + COMBO_ABILITIES.put("JetBlaze", new ComboAbilityInfo("JetBlaze", jetBlaze, JetBlaze.class)); DESCRIPTIONS.put("JetBlaze", ConfigManager.languageConfig.get().getString("Abilities.Fire.Combo.JetBlaze.Description")); INSTRUCTIONS.put("JetBlaze", "FireJet (Tap Shift) > FireJet (Tap Shift) > Blaze (Tap Shift) > FireJet."); } @@ -93,7 +103,7 @@ public class ComboManager { fireWheel.add(new AbilityInformation("FireShield", ClickType.RIGHT_CLICK_BLOCK)); fireWheel.add(new AbilityInformation("FireShield", ClickType.RIGHT_CLICK_BLOCK)); fireWheel.add(new AbilityInformation("Blaze", ClickType.SHIFT_UP)); - COMBO_ABILITIES.put("FireWheel", new ComboAbilityInfo("FireWheel", fireWheel, FireCombo.class)); + COMBO_ABILITIES.put("FireWheel", new ComboAbilityInfo("FireWheel", fireWheel, FireWheel.class)); DESCRIPTIONS.put("FireWheel", ConfigManager.languageConfig.get().getString("Abilities.Fire.Combo.FireWheel.Description")); INSTRUCTIONS.put("FireWheel", "FireShield (Hold Shift) > Right Click a block in front of you twice > Switch to Blaze > Release Shift."); } @@ -104,7 +114,7 @@ public class ComboManager { twister.add(new AbilityInformation("AirShield", ClickType.SHIFT_UP)); twister.add(new AbilityInformation("Tornado", ClickType.SHIFT_DOWN)); twister.add(new AbilityInformation("AirBlast", ClickType.LEFT_CLICK)); - COMBO_ABILITIES.put("Twister", new ComboAbilityInfo("Twister", twister, AirCombo.class)); + COMBO_ABILITIES.put("Twister", new ComboAbilityInfo("Twister", twister, Twister.class)); DESCRIPTIONS.put("Twister", ConfigManager.languageConfig.get().getString("Abilities.Air.Combo.Twister.Description")); INSTRUCTIONS.put("Twister", "AirShield (Tap Shift) > Tornado (Hold Shift) > AirBlast (Left Click)"); } @@ -114,7 +124,7 @@ public class ComboManager { airStream.add(new AbilityInformation("AirShield", ClickType.SHIFT_DOWN)); airStream.add(new AbilityInformation("AirSuction", ClickType.LEFT_CLICK)); airStream.add(new AbilityInformation("AirBlast", ClickType.LEFT_CLICK)); - COMBO_ABILITIES.put("AirStream", new ComboAbilityInfo("AirStream", airStream, AirCombo.class)); + COMBO_ABILITIES.put("AirStream", new ComboAbilityInfo("AirStream", airStream, AirStream.class)); DESCRIPTIONS.put("AirStream", ConfigManager.languageConfig.get().getString("Abilities.Air.Combo.AirStream.Description")); INSTRUCTIONS.put("AirStream", "AirShield (Hold Shift) > AirSuction (Left Click) > AirBlast (Left Click)"); } @@ -125,7 +135,7 @@ public class ComboManager { airSweep.add(new AbilityInformation("AirSwipe", ClickType.LEFT_CLICK)); airSweep.add(new AbilityInformation("AirBurst", ClickType.SHIFT_DOWN)); airSweep.add(new AbilityInformation("AirBurst", ClickType.LEFT_CLICK)); - COMBO_ABILITIES.put("AirSweep", new ComboAbilityInfo("AirSweep", airSweep, AirCombo.class)); + COMBO_ABILITIES.put("AirSweep", new ComboAbilityInfo("AirSweep", airSweep, AirSweep.class)); DESCRIPTIONS.put("AirSweep", ConfigManager.languageConfig.get().getString("Abilities.Air.Combo.AirSweep.Description")); INSTRUCTIONS.put("AirSweep", "AirSwipe (Left Click) > AirSwipe (Left Click) > AirBurst (Hold Shift) > AirBurst (Left Click)"); } @@ -134,7 +144,7 @@ public class ComboManager { ArrayList iceWave = new ArrayList<>(); iceWave.add(new AbilityInformation("WaterSpout", ClickType.SHIFT_UP)); iceWave.add(new AbilityInformation("PhaseChange", ClickType.LEFT_CLICK)); - COMBO_ABILITIES.put("IceWave", new ComboAbilityInfo("IceWave", iceWave, WaterCombo.class)); + COMBO_ABILITIES.put("IceWave", new ComboAbilityInfo("IceWave", iceWave, IceWave.class)); DESCRIPTIONS.put("IceWave", ConfigManager.languageConfig.get().getString("Abilities.Water.Combo.IceWave.Description")); INSTRUCTIONS.put("IceWave", "Create a WaterSpout Wave > PhaseChange (Left Click)"); } @@ -144,16 +154,16 @@ public class ComboManager { iceBullet.add(new AbilityInformation("WaterBubble", ClickType.SHIFT_DOWN)); iceBullet.add(new AbilityInformation("WaterBubble", ClickType.SHIFT_UP)); iceBullet.add(new AbilityInformation("IceBlast", ClickType.SHIFT_DOWN)); - COMBO_ABILITIES.put("IceBullet", new ComboAbilityInfo("IceBullet", iceBullet, WaterCombo.class)); + COMBO_ABILITIES.put("IceBullet", new ComboAbilityInfo("IceBullet", iceBullet, IceBullet.class)); DESCRIPTIONS.put("IceBullet", ConfigManager.languageConfig.get().getString("Abilities.Water.Combo.IceBullet.Description")); INSTRUCTIONS.put("IceBullet", "WaterBubble (Tap Shift) > IceBlast (Hold Shift) > Wait for ice to Form > Then alternate between Left and Right click with IceBlast"); ArrayList iceBulletLeft = new ArrayList<>(); iceBulletLeft.add(new AbilityInformation("IceBlast", ClickType.LEFT_CLICK)); - COMBO_ABILITIES.put("IceBulletLeftClick", new ComboAbilityInfo("IceBulletLeftClick", iceBulletLeft, WaterCombo.class)); + COMBO_ABILITIES.put("IceBulletLeftClick", new ComboAbilityInfo("IceBulletLeftClick", iceBulletLeft, IceBulletLeftClick.class)); ArrayList iceBulletRight = new ArrayList<>(); iceBulletRight.add(new AbilityInformation("IceBlast", ClickType.RIGHT_CLICK_BLOCK)); - COMBO_ABILITIES.put("IceBulletRightClick", new ComboAbilityInfo("IceBulletRightClick", iceBulletRight, WaterCombo.class)); + COMBO_ABILITIES.put("IceBulletRightClick", new ComboAbilityInfo("IceBulletRightClick", iceBulletRight, IceBulletRightClick.class)); } if (ConfigManager.defaultConfig.get().getBoolean("Abilities.Chi.ChiCombo.Immobilize.Enabled")) { @@ -162,7 +172,7 @@ public class ComboManager { immobilize.add(new AbilityInformation("SwiftKick", ClickType.LEFT_CLICK_ENTITY)); immobilize.add(new AbilityInformation("QuickStrike", ClickType.LEFT_CLICK_ENTITY)); immobilize.add(new AbilityInformation("QuickStrike", ClickType.LEFT_CLICK_ENTITY)); - COMBO_ABILITIES.put("Immobilize", new ComboAbilityInfo("Immobilize", immobilize, ChiCombo.class)); + COMBO_ABILITIES.put("Immobilize", new ComboAbilityInfo("Immobilize", immobilize, Immobilize.class)); DESCRIPTIONS.put("Immobilize", ConfigManager.languageConfig.get().getString("Abilities.Chi.Combo.Immobilize.Description")); INSTRUCTIONS.put("Immobilize", "QuickStrike (Left Click) > SwiftKick (Left Click) > QuickStrike (Left Click) > QuickStrike (Left Click)"); } @@ -191,17 +201,15 @@ public class ComboManager { } new BukkitRunnable() { - @Override public void run() { - if (comboAbil.getComboType().equals(FireCombo.class)) { - new FireCombo(player, comboAbil.getName()); - } else if (comboAbil.getComboType().equals(AirCombo.class)) { - new AirCombo(player, comboAbil.getName()); - } else if (comboAbil.getComboType().equals(WaterCombo.class)) { - new WaterCombo(player, comboAbil.getName()); - } else if (comboAbil.getComboType().equals(ChiCombo.class)) { - new ChiCombo(player, comboAbil.getName()); + if (comboAbil.getComboType() instanceof Class) { + Class clazz = (Class) comboAbil.getComboType(); + try { + ReflectionHandler.instantiateObject(clazz, player); + } catch (Exception e) { + e.printStackTrace(); + } } else { if (comboAbil.getComboType() instanceof ComboAbility) { ((ComboAbility) comboAbil.getComboType()).createNewComboInstance(player); @@ -209,10 +217,8 @@ public class ComboManager { } } } - + }.runTaskLater(ProjectKorra.plugin, 1L); - - } /** diff --git a/src/com/projectkorra/projectkorra/airbending/AirBlast.java b/src/com/projectkorra/projectkorra/airbending/AirBlast.java index 7ff6deaa..3210074b 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirBlast.java +++ b/src/com/projectkorra/projectkorra/airbending/AirBlast.java @@ -26,6 +26,7 @@ import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ProjectKorra; import com.projectkorra.projectkorra.ability.AirAbility; import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.avatar.AvatarState; import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.object.HorizontalVelocityTracker; @@ -80,7 +81,7 @@ public class AirBlast extends AirAbility { if (entity != null) { this.direction = GeneralMethods.getDirection(origin, entity.getLocation()).normalize(); } else { - this.direction = GeneralMethods.getDirection(origin, GeneralMethods.getTargetedLocation(player, range)) .normalize(); + this.direction = GeneralMethods.getDirection(origin, GeneralMethods.getTargetedLocation(player, range)).normalize(); } } else { origin = player.getEyeLocation(); @@ -126,7 +127,7 @@ public class AirBlast extends AirAbility { this.canOpenDoors = getConfig().getBoolean("Abilities.Air.AirBlast.CanOpenDoors"); this.canPressButtons = getConfig().getBoolean("Abilities.Air.AirBlast.CanPressButtons"); this.canCoolLava = getConfig().getBoolean("Abilities.Air.AirBlast.CanCoolLava"); - + this.isFromOtherOrigin = false; this.showParticles = true; this.random = new Random(); @@ -172,7 +173,7 @@ public class AirBlast extends AirAbility { } ORIGINS.put(player, location); - + } private void advanceLocation() { @@ -207,7 +208,7 @@ public class AirBlast extends AirAbility { push.setY(max); } } - if(location.getWorld().equals(origin.getWorld())) { + if (location.getWorld().equals(origin.getWorld())) { factor *= 1 - location.distance(origin) / (2 * range); } @@ -291,8 +292,7 @@ public class AirBlast extends AirAbility { continue; } - Material doorTypes[] = { Material.WOODEN_DOOR, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, - Material.ACACIA_DOOR, Material.DARK_OAK_DOOR }; + Material doorTypes[] = { Material.WOODEN_DOOR, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR }; if (Arrays.asList(doorTypes).contains(block.getType()) && canOpenDoors) { if (block.getData() >= 8) { block = block.getRelative(BlockFace.DOWN); @@ -400,12 +400,13 @@ public class AirBlast extends AirAbility { } /* - * If a player presses shift and AirBlasts straight down then the AirBlast's location gets - * messed up and reading the distance returns Double.NaN. If we don't remove this instance - * then the AirBlast will never be removed. + * If a player presses shift and AirBlasts straight down then the + * AirBlast's location gets messed up and reading the distance returns + * Double.NaN. If we don't remove this instance then the AirBlast will + * never be removed. */ double dist = 0; - if(location.getWorld().equals(origin.getWorld())) { + if (location.getWorld().equals(origin.getWorld())) { dist = location.distance(origin); } if (Double.isNaN(dist) || dist > range) { @@ -421,6 +422,11 @@ public class AirBlast extends AirAbility { return; } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean removeAirBlastsAroundPoint(Location location, double radius) { boolean removed = false; for (AirBlast airBlast : getAbilities(AirBlast.class)) { @@ -449,7 +455,7 @@ public class AirBlast extends AirAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -460,6 +466,11 @@ public class AirBlast extends AirAbility { return false; } + @Override + public double getCollisionRadius() { + return getRadius(); + } + public Location getOrigin() { return origin; } @@ -619,13 +630,13 @@ public class AirBlast extends AirAbility { public void setParticles(int particles) { this.particles = particles; } - + public static int getSelectParticles() { return getConfig().getInt("Abilities.Air.AirBlast.SelectParticles"); } - + public static double getSelectRange() { return getConfig().getInt("Abilities.Air.AirBlast.SelectRange"); } - + } diff --git a/src/com/projectkorra/projectkorra/airbending/AirBubble.java b/src/com/projectkorra/projectkorra/airbending/AirBubble.java index 5c929612..3c600293 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirBubble.java +++ b/src/com/projectkorra/projectkorra/airbending/AirBubble.java @@ -1,11 +1,7 @@ package com.projectkorra.projectkorra.airbending; -import com.projectkorra.projectkorra.BendingPlayer; -import com.projectkorra.projectkorra.Element; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.WaterAbility; -import com.projectkorra.projectkorra.waterbending.WaterManipulation; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -14,8 +10,11 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Player; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import com.projectkorra.projectkorra.BendingPlayer; +import com.projectkorra.projectkorra.Element; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.waterbending.WaterManipulation; public class AirBubble extends AirAbility { @@ -27,7 +26,7 @@ public class AirBubble extends AirAbility { public AirBubble(Player player) { super(player); - + this.radius = 0; this.airRadius = getConfig().getDouble("Abilities.Air.AirBubble.Radius"); this.waterRadius = getConfig().getDouble("Abilities.Water.WaterBubble.Radius"); @@ -50,7 +49,7 @@ public class AirBubble extends AirAbility { if (bPlayer == null) { continue; } - + String name = bPlayer.getBoundAbilityName(); if (name.equalsIgnoreCase("AirBubble") | name.equalsIgnoreCase("WaterBubble")) { if (!hasAbility(player, AirBubble.class) && player.isSneaking()) { @@ -94,7 +93,7 @@ public class AirBubble extends AirAbility { } else { radius = waterRadius; } - + if (airRadius > radius && bPlayer.hasElement(Element.AIR)) { radius = airRadius; } @@ -129,8 +128,6 @@ public class AirBubble extends AirAbility { } } } - - WaterAbility.removeWaterSpouts(location, radius, player); } @Override @@ -157,7 +154,7 @@ public class AirBubble extends AirAbility { public long getCooldown() { return 0; } - + @Override public boolean isSneakAbility() { return true; @@ -168,6 +165,11 @@ public class AirBubble extends AirAbility { return false; } + @Override + public double getCollisionRadius() { + return getRadius(); + } + public boolean isWaterBubble() { return waterBubble; } diff --git a/src/com/projectkorra/projectkorra/airbending/AirBurst.java b/src/com/projectkorra/projectkorra/airbending/AirBurst.java index 615fc50e..5fc6c4be 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirBurst.java +++ b/src/com/projectkorra/projectkorra/airbending/AirBurst.java @@ -1,8 +1,7 @@ package com.projectkorra.projectkorra.airbending; -import com.projectkorra.projectkorra.ProjectKorra; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.avatar.AvatarState; +import java.util.ArrayList; +import java.util.List; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -10,7 +9,9 @@ import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; -import java.util.ArrayList; +import com.projectkorra.projectkorra.ProjectKorra; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.avatar.AvatarState; public class AirBurst extends AirAbility { @@ -27,7 +28,7 @@ public class AirBurst extends AirAbility { private double particlePercentage; private ArrayList blasts; private ArrayList affectedEntities; - + public AirBurst(Player player, boolean isFallBurst) { super(player); if (bPlayer.isOnCooldown(this)) { @@ -76,7 +77,7 @@ public class AirBurst extends AirAbility { return; } - if (System.currentTimeMillis() > startTime + chargeTime && !isCharged) { + if (System.currentTimeMillis() > getStartTime() + chargeTime && !isCharged) { isCharged = true; } @@ -99,7 +100,7 @@ public class AirBurst extends AirAbility { if (bPlayer.isOnCooldown("AirBurst")) { return; } - + Location location = player.getLocation(); double x, y, z; double r = 1; @@ -109,11 +110,11 @@ public class AirBurst extends AirAbility { for (double phi = 0; phi < 360; phi += dphi) { double rphi = Math.toRadians(phi); double rtheta = Math.toRadians(theta); - + x = r * Math.cos(rphi) * Math.sin(rtheta); y = r * Math.sin(rphi) * Math.sin(rtheta); z = r * Math.cos(rtheta); - + Vector direction = new Vector(x, z, y); AirBlast blast = new AirBlast(player, location, direction.normalize(), pushFactor, this); blast.setDamage(damage); @@ -136,17 +137,17 @@ public class AirBurst extends AirAbility { double angle = Math.toRadians(30); double x, y, z; double r = 1; - + for (double theta = 0; theta <= 180; theta += blastAngleTheta) { double dphi = blastAnglePhi / Math.sin(Math.toRadians(theta)); for (double phi = 0; phi < 360; phi += dphi) { double rphi = Math.toRadians(phi); double rtheta = Math.toRadians(theta); - + x = r * Math.cos(rphi) * Math.sin(rtheta); y = r * Math.sin(rphi) * Math.sin(rtheta); z = r * Math.cos(rtheta); - + Vector direction = new Vector(x, z, y); if (direction.angle(vector) <= angle) { AirBlast blast = new AirBlast(player, location, direction.normalize(), pushFactor, this); @@ -185,14 +186,14 @@ public class AirBurst extends AirAbility { for (double phi = 0; phi < 360; phi += dphi) { double rphi = Math.toRadians(phi); double rtheta = Math.toRadians(theta); - + x = r * Math.cos(rphi) * Math.sin(rtheta); y = r * Math.sin(rphi) * Math.sin(rtheta); z = r * Math.cos(rtheta); - + Vector direction = new Vector(x, z, y); AirBlast blast = new AirBlast(player, location, direction.normalize(), pushFactor, this); - + blast.setDamage(damage); blast.setShowParticles(false); blasts.add(blast); @@ -216,7 +217,7 @@ public class AirBurst extends AirAbility { public long getCooldown() { return 0; } - + @Override public boolean isSneakAbility() { return true; @@ -227,6 +228,14 @@ public class AirBurst extends AirAbility { return false; } + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (AirBlast blast : blasts) { + locations.add(blast.getLocation()); + } + return locations; + } public void addAffectedEntity(Entity entity) { affectedEntities.add(entity); diff --git a/src/com/projectkorra/projectkorra/airbending/AirCombo.java b/src/com/projectkorra/projectkorra/airbending/AirCombo.java index e36acac2..6f1e91e4 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirCombo.java +++ b/src/com/projectkorra/projectkorra/airbending/AirCombo.java @@ -1,19 +1,7 @@ package com.projectkorra.projectkorra.airbending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ProjectKorra; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.ComboAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; -import com.projectkorra.projectkorra.ability.FireAbility; -import com.projectkorra.projectkorra.ability.WaterAbility; -import com.projectkorra.projectkorra.ability.util.ComboManager.AbilityInformation; -import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.command.Commands; -import com.projectkorra.projectkorra.firebending.FireCombo; -import com.projectkorra.projectkorra.firebending.FireCombo.FireComboStream; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.Flight; +import java.util.ArrayList; +import java.util.List; import org.bukkit.Location; import org.bukkit.block.Block; @@ -23,12 +11,22 @@ import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; -import java.util.ArrayList; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ProjectKorra; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.ComboAbility; +import com.projectkorra.projectkorra.ability.util.Collision; +import com.projectkorra.projectkorra.ability.util.ComboManager.AbilityInformation; +import com.projectkorra.projectkorra.avatar.AvatarState; +import com.projectkorra.projectkorra.command.Commands; +import com.projectkorra.projectkorra.firebending.FireCombo.FireComboStream; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.Flight; /* - * TODO: Combo classes should eventually be rewritten so that each combo is treated - * as an individual ability. In the mean time, we will just place "fake" - * classes so that CoreAbility will register each ability. + * TODO: Combo classes should eventually be rewritten so that each combo is + * treated as an individual ability. In the mean time, we will just place "fake" + * classes so that CoreAbility will register each ability. */ public class AirCombo extends AirAbility implements ComboAbility { @@ -62,7 +60,7 @@ public class AirCombo extends AirAbility implements ComboAbility { public AirCombo(Player player, String ability) { super(player); - + this.abilityName = ability; this.affectedEntities = new ArrayList<>(); this.tasks = new ArrayList<>(); @@ -71,7 +69,7 @@ public class AirCombo extends AirAbility implements ComboAbility { if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { return; } - + if (bPlayer.isOnCooldown(ability)) { return; } @@ -98,7 +96,7 @@ public class AirCombo extends AirAbility implements ComboAbility { this.knockback = getConfig().getDouble("Abilities.Air.AirCombo.AirSweep.Knockback"); this.cooldown = getConfig().getLong("Abilities.Air.AirCombo.AirSweep.Cooldown"); } - + if (bPlayer.isAvatarState()) { this.cooldown = 0; this.damage = AvatarState.getValue(damage); @@ -201,7 +199,7 @@ public class AirCombo extends AirAbility implements ComboAbility { direction = GeneralMethods.getDirection(currentLoc, destination).normalize(); currentLoc.add(direction.clone().multiply(speed)); - + if (player.getWorld() != currentLoc.getWorld()) { remove(); return; @@ -223,12 +221,6 @@ public class AirCombo extends AirAbility implements ComboAbility { } else if (GeneralMethods.isRegionProtectedFromBuild(this, currentLoc)) { remove(); return; - } else if (FireAbility.isWithinFireShield(currentLoc)) { - remove(); - return; - } else if (isWithinAirShield(currentLoc)) { - remove(); - return; } else if (!isTransparent(currentLoc.getBlock())) { currentLoc.subtract(direction.clone().multiply(speed)); } @@ -280,8 +272,7 @@ public class AirCombo extends AirAbility implements ComboAbility { destination = player.getLocation().add(player.getEyeLocation().getDirection().normalize().multiply(10)); Vector origToDest = GeneralMethods.getDirection(origin, destination); for (double i = 0; i < 30; i++) { - Vector vec = GeneralMethods.getDirection(player.getLocation(), - origin.clone().add(origToDest.clone().multiply(i / 30))); + Vector vec = GeneralMethods.getDirection(player.getLocation(), origin.clone().add(origToDest.clone().multiply(i / 30))); FireComboStream fs = new FireComboStream(null, vec, player.getLocation(), range, speed, "AirSweep"); fs.setDensity(1); @@ -316,7 +307,7 @@ public class AirCombo extends AirAbility implements ComboAbility { fstream.remove(); return; } - + if (!isTransparent(loc.getBlock())) { if (!isTransparent(loc.clone().add(0, 0.2, 0).getBlock())) { fstream.remove(); @@ -346,12 +337,6 @@ public class AirCombo extends AirAbility implements ComboAbility { } } } - - if (GeneralMethods.blockAbilities(player, FireCombo.getBlockableAbilities(), loc, 1)) { - fstream.remove(); - } else AirAbility.removeAirSpouts(loc, player); - WaterAbility.removeWaterSpouts(loc, player); - EarthAbility.removeSandSpouts(loc, player); } } } @@ -368,6 +353,11 @@ public class AirCombo extends AirAbility implements ComboAbility { } } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean removeAroundPoint(Player player, String ability, Location loc, double radius) { boolean removed = false; for (AirCombo combo : getAbilities(AirCombo.class)) { @@ -386,8 +376,7 @@ public class AirCombo extends AirAbility implements ComboAbility { } else if (ability.equalsIgnoreCase("AirSweep") && combo.abilityName.equalsIgnoreCase("AirSweep")) { for (int j = 0; j < combo.tasks.size(); j++) { FireComboStream fs = (FireComboStream) combo.tasks.get(j); - if (fs.getLocation() != null && fs.getLocation().getWorld().equals(loc.getWorld()) - && Math.abs(fs.getLocation().distance(loc)) <= radius) { + if (fs.getLocation() != null && fs.getLocation().getWorld().equals(loc.getWorld()) && Math.abs(fs.getLocation().distance(loc)) <= radius) { fs.remove(); removed = true; } @@ -423,7 +412,7 @@ public class AirCombo extends AirAbility implements ComboAbility { public boolean isHiddenAbility() { return true; } - + @Override public boolean isSneakAbility() { return true; @@ -433,7 +422,13 @@ public class AirCombo extends AirAbility implements ComboAbility { public boolean isHarmlessAbility() { return false; } - + + @Override + public boolean isCollidable() { + // Override in subclasses + return false; + } + @Override public String getInstructions() { return null; @@ -449,7 +444,6 @@ public class AirCombo extends AirAbility implements ComboAbility { return null; } - public String getAbilityName() { return abilityName; } @@ -609,6 +603,10 @@ public class AirCombo extends AirAbility implements ComboAbility { public ArrayList getTasks() { return tasks; } + + public void setTasks(ArrayList tasks) { + this.tasks = tasks; + } public ArrayList getFlights() { return flights; @@ -617,44 +615,91 @@ public class AirCombo extends AirAbility implements ComboAbility { public void setCooldown(long cooldown) { this.cooldown = cooldown; } - - public class AirStream extends AirCombo { - public AirStream(Player player, String name) { + // Combo subclasses need to be static to be reflectively called in ComboManager + public static class AirStream extends AirCombo { + + public AirStream(Player player) { super(player, "AirStream"); } - + @Override public String getName() { return "AirStream"; } - - } - - public class AirSweep extends AirCombo { - public AirSweep(Player player, String name) { + @Override + public boolean isCollidable() { + return true; + } + + } + + public static class AirSweep extends AirCombo { + + public AirSweep(Player player) { super(player, "AirSweep"); } - + @Override public String getName() { return "AirSweep"; } - - } - - public class Twister extends AirCombo { - public Twister(Player player, String name) { - super(player, "Twister"); + @Override + public boolean isCollidable() { + return true; } + @Override + public void handleCollision(Collision collision) { + if (collision.isRemovingFirst()) { + ArrayList newTasks = new ArrayList<>(); + double collisionDistanceSquared = Math.pow(getCollisionRadius() + collision.getAbilitySecond().getCollisionRadius(), 2); + // Remove all of the streams that are by this specific ourLocation. + // Don't just do a single stream at a time or this algorithm becomes O(n^2) with + // Collision's detection algorithm. + for (BukkitRunnable task : getTasks()) { + if (task instanceof FireComboStream) { + FireComboStream stream = (FireComboStream) task; + if (stream.getLocation().distanceSquared(collision.getLocationSecond()) > collisionDistanceSquared) { + newTasks.add(stream); + } else { + stream.cancel(); + } + } else { + newTasks.add(task); + } + } + setTasks(newTasks); + } + } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (BukkitRunnable task : getTasks()) { + if (task instanceof FireComboStream) { + FireComboStream stream = (FireComboStream) task; + locations.add(stream.getLocation()); + } + } + return locations; + } + + } + + public static class Twister extends AirCombo { + + public Twister(Player player) { + super(player, "Twister"); + } + @Override public String getName() { return "Twister"; } - + } - + } diff --git a/src/com/projectkorra/projectkorra/airbending/AirScooter.java b/src/com/projectkorra/projectkorra/airbending/AirScooter.java index 3748f3fb..719d2e74 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirScooter.java +++ b/src/com/projectkorra/projectkorra/airbending/AirScooter.java @@ -25,18 +25,17 @@ public class AirScooter extends AirAbility { private Block floorblock; private Random random; private ArrayList angles; - + private boolean canFly; private boolean hadFly; private double phi = 0; - + public AirScooter(Player player) { super(player); - - if (check(player)) + + if (check(player)) return; - else if (!player.isSprinting() || GeneralMethods.isSolid(player.getEyeLocation().getBlock()) - || player.getEyeLocation().getBlock().isLiquid()) + else if (!player.isSprinting() || GeneralMethods.isSolid(player.getEyeLocation().getBlock()) || player.getEyeLocation().getBlock().isLiquid()) return; else if (GeneralMethods.isSolid(player.getLocation().add(0, -.5, 0).getBlock())) return; @@ -52,7 +51,7 @@ public class AirScooter extends AirAbility { this.angles = new ArrayList<>(); canFly = player.getAllowFlight(); hadFly = player.isFlying(); - + new Flight(player); player.setAllowFlight(true); player.setFlying(true); @@ -82,8 +81,8 @@ public class AirScooter extends AirAbility { } /* - * Looks for a block under the player and sets "floorBlock" to a block - * under the player if it within the maximum height + * Looks for a block under the player and sets "floorBlock" to a block under + * the player if it within the maximum height */ private void getFloor() { floorblock = null; @@ -102,7 +101,7 @@ public class AirScooter extends AirAbility { remove(); return; } - + getFloor(); if (floorblock == null) { remove(); @@ -114,7 +113,7 @@ public class AirScooter extends AirAbility { /* * checks the players speed and ends the move if they are going too slow */ - if (System.currentTimeMillis() > startTime + interval) { + if (System.currentTimeMillis() > getStartTime() + interval) { if (player.getVelocity().length() < speed * 0.3) { remove(); return; @@ -122,8 +121,8 @@ public class AirScooter extends AirAbility { spinScooter(); } /* - * Checks for how far the ground is away from the player - * it elevates or lowers the player based on their distance from the ground. + * Checks for how far the ground is away from the player it elevates or + * lowers the player based on their distance from the ground. */ double distance = player.getLocation().getY() - (double) floorblock.getY(); double dx = Math.abs(distance - 2.4); @@ -141,7 +140,7 @@ public class AirScooter extends AirAbility { } else { return; } - + player.setSprinting(false); player.removePotionEffect(PotionEffectType.SPEED); player.setVelocity(velocity); @@ -163,36 +162,33 @@ public class AirScooter extends AirAbility { } /* - * The particles used for AirScooter - * phi = how many rings of particles the sphere has. - * theta = how dense the rings are. - * r = Radius of the sphere + * The particles used for AirScooter phi = how many rings of particles the + * sphere has. theta = how dense the rings are. r = Radius of the sphere */ private void spinScooter() { Location origin = player.getLocation(); Location origin2 = player.getLocation(); - phi += Math.PI/10*4; - for(double theta = 0; theta <= 2*Math.PI; theta += Math.PI/10) { + phi += Math.PI / 10 * 4; + for (double theta = 0; theta <= 2 * Math.PI; theta += Math.PI / 10) { double r = 0.6; - double x = r*Math.cos(theta)*Math.sin(phi); - double y = r*Math.cos(phi); - double z = r*Math.sin(theta)*Math.sin(phi); + double x = r * Math.cos(theta) * Math.sin(phi); + double y = r * Math.cos(phi); + double z = r * Math.sin(theta) * Math.sin(phi); origin.add(x, y, z); playAirbendingParticles(origin, 1, 0F, 0F, 0F); origin.subtract(x, y, z); } - for(double theta = 0; theta <= 2*Math.PI; theta += Math.PI/10) { + for (double theta = 0; theta <= 2 * Math.PI; theta += Math.PI / 10) { double r = 0.6; - double x = r*Math.cos(theta)*Math.sin(phi); - double y = r*Math.cos(phi); - double z = r*Math.sin(theta)*Math.sin(phi); + double x = r * Math.cos(theta) * Math.sin(phi); + double y = r * Math.cos(phi); + double z = r * Math.sin(theta) * Math.sin(phi); origin2.subtract(x, y, z); playAirbendingParticles(origin2, 1, 0F, 0F, 0F); origin2.add(x, y, z); } } - @Override public String getName() { return "AirScooter"; @@ -207,7 +203,7 @@ public class AirScooter extends AirAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return false; @@ -218,6 +214,10 @@ public class AirScooter extends AirAbility { return true; } + @Override + public double getCollisionRadius() { + return getRadius(); + } public double getSpeed() { return speed; @@ -258,7 +258,7 @@ public class AirScooter extends AirAbility { public void setFloorblock(Block floorblock) { this.floorblock = floorblock; } - + public void setCooldown(long cooldown) { this.cooldown = cooldown; } diff --git a/src/com/projectkorra/projectkorra/airbending/AirShield.java b/src/com/projectkorra/projectkorra/airbending/AirShield.java index 16a217fc..c28a4b8a 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirShield.java +++ b/src/com/projectkorra/projectkorra/airbending/AirShield.java @@ -1,16 +1,8 @@ package com.projectkorra.projectkorra.airbending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.command.Commands; -import com.projectkorra.projectkorra.earthbending.EarthBlast; -import com.projectkorra.projectkorra.earthbending.SandSpout; -import com.projectkorra.projectkorra.firebending.BlazeArc; -import com.projectkorra.projectkorra.firebending.Combustion; -import com.projectkorra.projectkorra.firebending.FireBlast; -import com.projectkorra.projectkorra.waterbending.WaterManipulation; -import com.projectkorra.projectkorra.waterbending.WaterSpout; +import java.util.HashMap; +import java.util.Random; +import java.util.Set; import org.bukkit.Effect; import org.bukkit.Location; @@ -20,9 +12,11 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.HashMap; -import java.util.Random; -import java.util.Set; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.util.Collision; +import com.projectkorra.projectkorra.avatar.AvatarState; +import com.projectkorra.projectkorra.command.Commands; public class AirShield extends AirAbility { @@ -34,16 +28,16 @@ public class AirShield extends AirAbility { private int particles; private Random random; private HashMap angles; - + public AirShield(Player player) { super(player); this.maxRadius = getConfig().getDouble("Abilities.Air.AirShield.Radius"); this.isToggledByAvatarState = getConfig().getBoolean("Abilities.Air.AirShield.IsAvatarStateToggle"); this.radius = this.maxRadius; - this.speed = getConfig().getDouble("Abilities.Air.AirShield.Speed"); + this.speed = getConfig().getDouble("Abilities.Air.AirShield.Speed"); this.streams = getConfig().getInt("Abilities.Air.AirShield.Streams"); - this.particles = getConfig().getInt("Abilities.Air.AirShield.Particles"); + this.particles = getConfig().getInt("Abilities.Air.AirShield.Particles"); this.random = new Random(); this.angles = new HashMap<>(); @@ -61,10 +55,15 @@ public class AirShield extends AirAbility { angle = 0; } } - + start(); } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean isWithinShield(Location loc) { for (AirShield ashield : getAbilities(AirShield.class)) { if (!ashield.player.getWorld().equals(loc.getWorld())) { @@ -96,16 +95,6 @@ public class AirShield extends AirAbility { private void rotateShield() { Location origin = player.getLocation(); - FireBlast.removeFireBlastsAroundPoint(origin, radius); - Combustion.removeAroundPoint(origin, radius); - BlazeArc.removeAroundPoint(origin, radius); - AirBlast.removeAirBlastsAroundPoint(origin, radius); - AirSuction.removeAirSuctionsAroundPoint(origin, radius); - EarthBlast.removeAroundPoint(origin, radius); - SandSpout.removeSpouts(origin, radius, player); - WaterSpout.removeSpouts(origin, radius, player); - WaterManipulation.removeAroundPoint(origin, radius); - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(origin, radius)) { if (GeneralMethods.isRegionProtectedFromBuild(player, "AirShield", entity.getLocation())) { continue; @@ -181,7 +170,7 @@ public class AirShield extends AirAbility { radius = maxRadius; } } - + @Override public String getName() { return "AirShield"; @@ -196,7 +185,7 @@ public class AirShield extends AirAbility { public long getCooldown() { return 0; } - + @Override public boolean isSneakAbility() { return true; @@ -207,6 +196,11 @@ public class AirShield extends AirAbility { return false; } + @Override + public double getCollisionRadius() { + return getRadius(); + } + public boolean isToggledByAvatarState() { return isToggledByAvatarState; } diff --git a/src/com/projectkorra/projectkorra/airbending/AirSpout.java b/src/com/projectkorra/projectkorra/airbending/AirSpout.java index 7ce7ad99..45c00acd 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirSpout.java +++ b/src/com/projectkorra/projectkorra/airbending/AirSpout.java @@ -1,5 +1,7 @@ package com.projectkorra.projectkorra.airbending; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import org.bukkit.Location; @@ -9,26 +11,28 @@ import org.bukkit.entity.Player; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.util.Flight; public class AirSpout extends AirAbility { - private static final Integer[] DIRECTIONS = {0, 1, 2, 3, 5, 6, 7, 8}; + private static final Integer[] DIRECTIONS = { 0, 1, 2, 3, 5, 6, 7, 8 }; private int angle; + private long animTime; private long interval; private long cooldown; private double height; public AirSpout(Player player) { super(player); - + AirSpout spout = getAbility(player, AirSpout.class); if (spout != null) { spout.remove(); return; } - + if (!bPlayer.canBend(this)) { remove(); return; @@ -36,6 +40,7 @@ public class AirSpout extends AirAbility { this.angle = 0; this.cooldown = 0; + this.animTime = System.currentTimeMillis(); this.interval = getConfig().getLong("Abilities.Air.AirSpout.Interval"); this.height = getConfig().getDouble("Abilities.Air.AirSpout.Height"); @@ -43,12 +48,17 @@ public class AirSpout extends AirAbility { if (!isWithinMaxSpoutHeight(heightRemoveThreshold)) { return; } - + new Flight(player); start(); bPlayer.addCooldown(this); } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean removeSpouts(Location loc0, double radius, Player sourceplayer) { boolean removed = false; for (AirSpout spout : getAbilities(AirSpout.class)) { @@ -74,7 +84,7 @@ public class AirSpout extends AirAbility { player.setAllowFlight(true); player.setFlying(true); } - + private boolean isWithinMaxSpoutHeight(double threshold) { Block ground = getGround(); if (ground == null) { @@ -100,21 +110,18 @@ public class AirSpout extends AirAbility { @Override public void progress() { - if (player.isDead() - || !player.isOnline() - || !bPlayer.canBendIgnoreBindsCooldowns(this) - || !bPlayer.canBind(this)) { + if (player.isDead() || !player.isOnline() || !bPlayer.canBendIgnoreBindsCooldowns(this) || !bPlayer.canBind(this)) { remove(); return; } - + double heightRemoveThreshold = 2; if (!isWithinMaxSpoutHeight(heightRemoveThreshold)) { remove(); return; } - - if(!bPlayer.canBind(this)) { + + if (!bPlayer.canBind(this)) { remove(); return; } @@ -159,8 +166,8 @@ public class AirSpout extends AirAbility { if (!player.getWorld().equals(block.getWorld())) { return; } - if (System.currentTimeMillis() >= startTime + interval) { - startTime = System.currentTimeMillis(); + if (System.currentTimeMillis() >= animTime + interval) { + animTime = System.currentTimeMillis(); Location location = block.getLocation(); Location playerloc = player.getLocation(); location = new Location(location.getWorld(), playerloc.getX(), location.getY(), playerloc.getZ()); @@ -191,7 +198,7 @@ public class AirSpout extends AirAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return false; @@ -202,6 +209,22 @@ public class AirSpout extends AirAbility { return true; } + @Override + public boolean isCollidable() { + return true; + } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + Location topLoc = player.getLocation().getBlock().getLocation(); + double ySpacing = 3; + for (double i = 0; i <= height; i += ySpacing) { + locations.add(topLoc.clone().add(0, -i, 0)); + } + return locations; + } + public int getAngle() { return angle; } @@ -210,6 +233,14 @@ public class AirSpout extends AirAbility { this.angle = angle; } + public long getAnimTime() { + return animTime; + } + + public void setAnimTime(long animTime) { + this.animTime = animTime; + } + public long getInterval() { return interval; } @@ -229,5 +260,5 @@ public class AirSpout extends AirAbility { public void setCooldown(long cooldown) { this.cooldown = cooldown; } - + } diff --git a/src/com/projectkorra/projectkorra/airbending/AirSuction.java b/src/com/projectkorra/projectkorra/airbending/AirSuction.java index e4c469ad..ced2dcab 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirSuction.java +++ b/src/com/projectkorra/projectkorra/airbending/AirSuction.java @@ -14,6 +14,7 @@ import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ProjectKorra; import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.avatar.AvatarState; import com.projectkorra.projectkorra.command.Commands; import com.projectkorra.projectkorra.object.HorizontalVelocityTracker; @@ -24,7 +25,7 @@ public class AirSuction extends AirAbility { private static final int MAX_TICKS = 10000; private static final Map ORIGINS = new ConcurrentHashMap<>(); - + private boolean hasOtherOrigin; private int ticks; private int particleCount; @@ -37,10 +38,10 @@ public class AirSuction extends AirAbility { private Location location; private Location origin; private Vector direction; - + public AirSuction(Player player) { super(player); - + if (bPlayer.isOnCooldown(this)) { return; } else if (player.getEyeLocation().getBlock().isLiquid()) { @@ -133,8 +134,7 @@ public class AirSuction extends AirAbility { Location location = origin.clone(); for (double i = 1; i <= range; i++) { location = origin.clone().add(direction.clone().multiply(i)); - if (!isTransparent(location.getBlock()) - || GeneralMethods.isRegionProtectedFromBuild(this, location)) { + if (!isTransparent(location.getBlock()) || GeneralMethods.isRegionProtectedFromBuild(this, location)) { return origin.clone().add(direction.clone().multiply(i - 1)); } } @@ -178,7 +178,7 @@ public class AirSuction extends AirAbility { push.setY(max); } } - if(location.getWorld().equals(origin.getWorld())) { + if (location.getWorld().equals(origin.getWorld())) { factor *= 1 - location.distance(origin) / (2 * range); } @@ -216,6 +216,11 @@ public class AirSuction extends AirAbility { advanceLocation(); } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean removeAirSuctionsAroundPoint(Location location, double radius) { boolean removed = false; for (AirSuction airSuction : getAbilities(AirSuction.class)) { @@ -244,7 +249,7 @@ public class AirSuction extends AirAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -255,6 +260,11 @@ public class AirSuction extends AirAbility { return false; } + @Override + public double getCollisionRadius() { + return getRadius(); + } + public Location getOrigin() { return origin; } @@ -346,5 +356,5 @@ public class AirSuction extends AirAbility { public static double getSelectRange() { return getConfig().getDouble("Abilities.Air.AirSuction.SelectRange"); } - + } diff --git a/src/com/projectkorra/projectkorra/airbending/AirSwipe.java b/src/com/projectkorra/projectkorra/airbending/AirSwipe.java index af09fa27..42212042 100644 --- a/src/com/projectkorra/projectkorra/airbending/AirSwipe.java +++ b/src/com/projectkorra/projectkorra/airbending/AirSwipe.java @@ -1,20 +1,11 @@ package com.projectkorra.projectkorra.airbending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ProjectKorra; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.CoreAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; -import com.projectkorra.projectkorra.ability.WaterAbility; -import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.command.Commands; -import com.projectkorra.projectkorra.earthbending.EarthBlast; -import com.projectkorra.projectkorra.firebending.Combustion; -import com.projectkorra.projectkorra.firebending.FireBlast; -import com.projectkorra.projectkorra.firebending.Illumination; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.Flight; -import com.projectkorra.projectkorra.waterbending.WaterManipulation; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Location; import org.bukkit.Material; @@ -25,19 +16,24 @@ import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ProjectKorra; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.CoreAbility; +import com.projectkorra.projectkorra.ability.EarthAbility; +import com.projectkorra.projectkorra.ability.util.Collision; +import com.projectkorra.projectkorra.avatar.AvatarState; +import com.projectkorra.projectkorra.command.Commands; +import com.projectkorra.projectkorra.firebending.Illumination; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.Flight; public class AirSwipe extends AirAbility { // Limiting the entities reduces the risk of crashing private static final int MAX_AFFECTABLE_ENTITIES = 10; - private static final Integer[] BREAKABLES = {6, 31, 32, 37, 38, 39, 40, 59, 81, 83, 106, 175}; - + private static final Integer[] BREAKABLES = { 6, 31, 32, 37, 38, 39, 40, 59, 81, 83, 106, 175 }; + private boolean charging; private int arc; private int particles; @@ -54,14 +50,14 @@ public class AirSwipe extends AirAbility { private Random random; private Map elements; private ArrayList affectedEntities; - + public AirSwipe(Player player) { this(player, false); } public AirSwipe(Player player, boolean charging) { super(player); - + if (CoreAbility.hasAbility(player, AirSwipe.class)) { for (AirSwipe ability : CoreAbility.getAbilities(player, AirSwipe.class)) { if (ability.charging) { @@ -71,7 +67,7 @@ public class AirSwipe extends AirAbility { } } } - + this.charging = charging; this.origin = player.getEyeLocation(); this.particles = getConfig().getInt("Abilities.Air.AirSwipe.Particles"); @@ -88,23 +84,28 @@ public class AirSwipe extends AirAbility { this.random = new Random(); this.elements = new ConcurrentHashMap<>(); this.affectedEntities = new ArrayList<>(); - + if (bPlayer.isOnCooldown(this) || player.getEyeLocation().getBlock().isLiquid()) { remove(); return; } - + if (!bPlayer.canBend(this)) { remove(); return; } - + if (!charging) { launch(); } start(); } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean removeSwipesAroundPoint(Location loc, double radius) { boolean removed = false; for (AirSwipe aswipe : getAbilities(AirSwipe.class)) { @@ -130,31 +131,15 @@ public class AirSwipe extends AirAbility { location = location.clone().add(direction.clone().multiply(speed)); elements.put(direction, location); - if (location.distanceSquared(origin) > range * range - || GeneralMethods.isRegionProtectedFromBuild(this, location)) { + if (location.distanceSquared(origin) > range * range || GeneralMethods.isRegionProtectedFromBuild(this, location)) { elements.remove(direction); } else { - removeAirSpouts(location, player); - WaterAbility.removeWaterSpouts(location, player); - EarthAbility.removeSandSpouts(location, player); - - - if (EarthBlast.annihilateBlasts(location, radius, player) - || WaterManipulation.annihilateBlasts(location, radius, player) - || FireBlast.annihilateBlasts(location, radius, player) - || Combustion.removeAroundPoint(location, radius)) { - elements.remove(direction); - damage = 0; - remove(); - continue; - } - Block block = location.getBlock(); if (!EarthAbility.isTransparent(player, block)) { remove(); return; } - + for (Block testblock : GeneralMethods.getBlocksAroundPoint(location, radius)) { if (testblock.getType() == Material.FIRE) { testblock.setType(Material.AIR); @@ -193,9 +178,6 @@ public class AirSwipe extends AirAbility { } private void affectPeople(Location location, Vector direction) { - WaterAbility.removeWaterSpouts(location, player); - removeAirSpouts(location, player); - removeAirSpouts(location, player); final List entities = GeneralMethods.getEntitiesAroundPoint(location, radius); final Vector fDirection = direction; @@ -280,12 +262,12 @@ public class AirSwipe extends AirAbility { remove(); return; } - + if (player.isDead() || !player.isOnline()) { remove(); return; } - + if (!charging) { if (elements.isEmpty()) { remove(); @@ -295,12 +277,12 @@ public class AirSwipe extends AirAbility { } else { if (!player.isSneaking()) { double factor = 1; - if (System.currentTimeMillis() >= startTime + maxChargeTime) { + if (System.currentTimeMillis() >= getStartTime() + maxChargeTime) { factor = maxChargeFactor; } else if (bPlayer.isAvatarState()) { factor = AvatarState.getValue(factor); } else { - factor = maxChargeFactor * (double) (System.currentTimeMillis() - startTime) / (double) maxChargeTime; + factor = maxChargeFactor * (double) (System.currentTimeMillis() - getStartTime()) / (double) maxChargeTime; } charging = false; @@ -308,7 +290,7 @@ public class AirSwipe extends AirAbility { factor = Math.max(1, factor); damage *= factor; pushFactor *= factor; - } else if (System.currentTimeMillis() >= startTime + maxChargeTime) { + } else if (System.currentTimeMillis() >= getStartTime() + maxChargeTime) { playAirbendingParticles(player.getEyeLocation(), particles); } } @@ -328,7 +310,7 @@ public class AirSwipe extends AirAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -339,6 +321,25 @@ public class AirSwipe extends AirAbility { return false; } + @Override + public boolean isCollidable() { + return origin != null; + } + + @Override + public double getCollisionRadius() { + return getRadius(); + } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (Location swipeLoc : elements.values()) { + locations.add(swipeLoc); + } + return locations; + } + public Location getOrigin() { return origin; } @@ -454,5 +455,5 @@ public class AirSwipe extends AirAbility { public void setStepSize(int stepSize) { this.stepSize = stepSize; } - + } diff --git a/src/com/projectkorra/projectkorra/airbending/Suffocate.java b/src/com/projectkorra/projectkorra/airbending/Suffocate.java index 3539721b..832c32dc 100644 --- a/src/com/projectkorra/projectkorra/airbending/Suffocate.java +++ b/src/com/projectkorra/projectkorra/airbending/Suffocate.java @@ -20,10 +20,11 @@ import com.projectkorra.projectkorra.util.DamageHandler; /** * Suffocate * - * Suffocate is an air ability that causes entities to be surrounded by a sphere air that causes - * constant damage after a configurable delay. Suffocate also causes Blinding and Slowing affects to - * entities depending on how the ability is configured. While in AvatarState this ability can be - * used on multiple entities within a large radius. If the user is damaged while performing this + * Suffocate is an air ability that causes entities to be surrounded by a sphere + * air that causes constant damage after a configurable delay. Suffocate also + * causes Blinding and Slowing affects to entities depending on how the ability + * is configured. While in AvatarState this ability can be used on multiple + * entities within a large radius. If the user is damaged while performing this * ability then the ability is removed. */ public class Suffocate extends AirAbility { @@ -54,7 +55,7 @@ public class Suffocate extends AirAbility { private Suffocate ability; private ArrayList tasks; private ArrayList targets; - + public Suffocate(Player player) { super(player); ability = this; @@ -131,7 +132,7 @@ public class Suffocate extends AirAbility { targets.add((LivingEntity) target); } } - + if (!canSuffocateUndead) { for (int i = 0; i < targets.size(); i++) { LivingEntity target = targets.get(i); @@ -150,10 +151,7 @@ public class Suffocate extends AirAbility { public void progress() { for (int i = 0; i < targets.size(); i++) { LivingEntity target = targets.get(i); - if (target.isDead() - || !target.getWorld().equals(player.getWorld()) - || target.getLocation().distanceSquared(player.getEyeLocation()) > range * range - || GeneralMethods.isRegionProtectedFromBuild(this, target.getLocation())) { + if (target.isDead() || !target.getWorld().equals(player.getWorld()) || target.getLocation().distanceSquared(player.getEyeLocation()) > range * range || GeneralMethods.isRegionProtectedFromBuild(this, target.getLocation())) { breakSuffocateLocal(target); i--; } else if (target instanceof Player) { @@ -171,11 +169,10 @@ public class Suffocate extends AirAbility { if (requireConstantAim) { double dist = 0; - if(player.getWorld().equals(targets.get(0).getWorld())) { + if (player.getWorld().equals(targets.get(0).getWorld())) { dist = player.getEyeLocation().distance(targets.get(0).getEyeLocation()); } - Location targetLoc = player.getEyeLocation().clone() - .add(player.getEyeLocation().getDirection().normalize().multiply(dist)); + Location targetLoc = player.getEyeLocation().clone().add(player.getEyeLocation().getDirection().normalize().multiply(dist)); List ents = GeneralMethods.getEntitiesAroundPoint(targetLoc, constantAimRadius); for (int i = 0; i < targets.size(); i++) { @@ -191,7 +188,7 @@ public class Suffocate extends AirAbility { } } - if (System.currentTimeMillis() - startTime < chargeTime) { + if (System.currentTimeMillis() - getStartTime() < chargeTime) { return; } else if (!started) { started = true; @@ -257,7 +254,8 @@ public class Suffocate extends AirAbility { } /** - * Removes an instance of Suffocate if player is the one suffocating entities + * Removes an instance of Suffocate if player is the one suffocating + * entities **/ public static void remove(Player player) { Suffocate suff = getAbility(player, Suffocate.class); @@ -267,9 +265,9 @@ public class Suffocate extends AirAbility { } /** - * Removes all instances of Suffocate at loc within the radius threshold. The location of a - * Suffocate is defined at the benders location, not the location of the entities being - * suffocated. + * Removes all instances of Suffocate at loc within the radius threshold. + * The location of a Suffocate is defined at the benders location, not the + * location of the entities being suffocated. * * @param causer The player causing this instance to be removed **/ @@ -290,13 +288,14 @@ public class Suffocate extends AirAbility { } /** - * Animates this instance of the Suffocate ability. Depending on the specific time (dt) the - * ability will create a different set of SuffocationSpirals. + * Animates this instance of the Suffocate ability. Depending on the + * specific time (dt) the ability will create a different set of + * SuffocationSpirals. */ public void animate() { int steps = 8 * particleCount; long curTime = System.currentTimeMillis(); - long dt = curTime - startTime - chargeTime; + long dt = curTime - getStartTime() - chargeTime; long delay = 2 / particleCount; long t1 = (long) (1500 * animationSpeed); long t2 = (long) (2500 * animationSpeed); @@ -305,10 +304,8 @@ public class Suffocate extends AirAbility { for (LivingEntity lent : targets) { final LivingEntity target = lent; if (dt < t1) { - new SuffocateSpiral(target, steps, radius, delay, 0, 0.25 - (0.25 * (double) dt / (double) t1), 0, - SpiralType.HORIZONTAL1); - new SuffocateSpiral(target, steps, radius, delay, 0, 0.25 - (0.25 * (double) dt / (double) t1), 0, - SpiralType.HORIZONTAL2); + new SuffocateSpiral(target, steps, radius, delay, 0, 0.25 - (0.25 * (double) dt / (double) t1), 0, SpiralType.HORIZONTAL1); + new SuffocateSpiral(target, steps, radius, delay, 0, 0.25 - (0.25 * (double) dt / (double) t1), 0, SpiralType.HORIZONTAL2); } else if (dt < t2) { new SuffocateSpiral(target, steps, radius, delay, 0, 0, 0, SpiralType.HORIZONTAL1); new SuffocateSpiral(target, steps * 2, radius, delay, 0, 0, 0, SpiralType.VERTICAL1); @@ -318,15 +315,9 @@ public class Suffocate extends AirAbility { new SuffocateSpiral(target, steps, radius, delay, 0, 0, 0, SpiralType.VERTICAL1); new SuffocateSpiral(target, steps, radius, delay, 0, 0, 0, SpiralType.VERTICAL2); } else if (dt < t4) { - new SuffocateSpiral(target, steps, radius - - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double) (dt - t3) / (double) (t4 - t3)))), delay, 0, 0, - 0, SpiralType.HORIZONTAL1); - new SuffocateSpiral(target, steps, radius - - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double) (dt - t3) / (double) (t4 - t3)))), delay, 0, 0, - 0, SpiralType.VERTICAL1); - new SuffocateSpiral(target, steps, radius - - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double) (dt - t3) / (double) (t4 - t3)))), delay, 0, 0, - 0, SpiralType.VERTICAL2); + new SuffocateSpiral(target, steps, radius - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double) (dt - t3) / (double) (t4 - t3)))), delay, 0, 0, 0, SpiralType.HORIZONTAL1); + new SuffocateSpiral(target, steps, radius - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double) (dt - t3) / (double) (t4 - t3)))), delay, 0, 0, 0, SpiralType.VERTICAL1); + new SuffocateSpiral(target, steps, radius - Math.min(radius * 3 / 4, (radius * 3.0 / 4 * ((double) (dt - t3) / (double) (t4 - t3)))), delay, 0, 0, 0, SpiralType.VERTICAL2); } else { new SuffocateSpiral(target, steps, radius - (radius * 3.0 / 4.0), delay, 0, 0, 0, SpiralType.HORIZONTAL1); new SuffocateSpiral(target, steps, radius - (radius * 3.0 / 4.0), delay, 0, 0, 0, SpiralType.VERTICAL1); @@ -354,9 +345,9 @@ public class Suffocate extends AirAbility { } /** - * ** Animates a Spiral of air particles around a location or a targetted entity. The direction - * of the spiral is determined by SpiralType, and each type is calculated independently from one - * another. + * Animates a Spiral of air particles around a location or a targetted + * entity. The direction of the spiral is determined by SpiralType, and each + * type is calculated independently from one another. */ public class SuffocateSpiral extends BukkitRunnable { private Location startLoc; @@ -378,8 +369,7 @@ public class Suffocate extends AirAbility { * @param dz z offset * @param type Spiral animation direction */ - public SuffocateSpiral(LivingEntity lent, int totalSteps, double radius, long interval, double dx, double dy, double dz, - SpiralType type) { + public SuffocateSpiral(LivingEntity lent, int totalSteps, double radius, long interval, double dx, double dy, double dz, SpiralType type) { this.target = lent; this.totalSteps = totalSteps; this.radius = radius; @@ -403,8 +393,7 @@ public class Suffocate extends AirAbility { * @param dz z offset * @param type Spiral animation direction */ - public SuffocateSpiral(Location startLoc, int totalSteps, double radius, long interval, double dx, double dy, double dz, - SpiralType type) { + public SuffocateSpiral(Location startLoc, int totalSteps, double radius, long interval, double dx, double dy, double dz, SpiralType type) { this.startLoc = startLoc; this.totalSteps = totalSteps; this.radius = radius; @@ -483,7 +472,7 @@ public class Suffocate extends AirAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -494,6 +483,13 @@ public class Suffocate extends AirAbility { return false; } + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + locations.add(player.getLocation()); + return locations; + } + public boolean isStarted() { return started; } diff --git a/src/com/projectkorra/projectkorra/airbending/Tornado.java b/src/com/projectkorra/projectkorra/airbending/Tornado.java index 72823cdb..d764de0d 100644 --- a/src/com/projectkorra/projectkorra/airbending/Tornado.java +++ b/src/com/projectkorra/projectkorra/airbending/Tornado.java @@ -36,7 +36,7 @@ public class Tornado extends AirAbility { public Tornado(Player player) { super(player); - + this.range = getConfig().getDouble("Abilities.Air.Tornado.Range"); this.origin = player.getTargetBlock((HashSet) null, (int) range).getLocation(); this.origin.setY(origin.getY() - 1.0 / 10.0 * currentHeight); @@ -77,7 +77,7 @@ public class Tornado extends AirAbility { } rotateTornado(); } - + @Override public void remove() { super.remove(); @@ -199,7 +199,7 @@ public class Tornado extends AirAbility { public long getCooldown() { return 0; } - + @Override public boolean isSneakAbility() { return true; @@ -210,6 +210,11 @@ public class Tornado extends AirAbility { return false; } + @Override + public double getCollisionRadius() { + return getRadius(); + } + public Location getOrigin() { return origin; } diff --git a/src/com/projectkorra/projectkorra/chiblocking/ChiCombo.java b/src/com/projectkorra/projectkorra/chiblocking/ChiCombo.java index 7a521b06..66f49a5d 100644 --- a/src/com/projectkorra/projectkorra/chiblocking/ChiCombo.java +++ b/src/com/projectkorra/projectkorra/chiblocking/ChiCombo.java @@ -192,7 +192,7 @@ public class ChiCombo extends ChiAbility implements ComboAbility { public class Immobilize extends ChiCombo { - public Immobilize(Player player, String name) { + public Immobilize(Player player) { super(player, "Immobilize"); } diff --git a/src/com/projectkorra/projectkorra/configuration/ConfigManager.java b/src/com/projectkorra/projectkorra/configuration/ConfigManager.java index 51e73b7b..7d191c1a 100644 --- a/src/com/projectkorra/projectkorra/configuration/ConfigManager.java +++ b/src/com/projectkorra/projectkorra/configuration/ConfigManager.java @@ -630,7 +630,7 @@ public class ConfigManager { config.addDefault("Abilities.Water.IceBlast.Damage", 3); config.addDefault("Abilities.Water.IceBlast.Range", 20); config.addDefault("Abilities.Water.IceBlast.DeflectRange", 3); - config.addDefault("Abilities.Water.IceBlast.CollisionRadius", 2); + config.addDefault("Abilities.Water.IceBlast.CollisionRadius", 0.5); config.addDefault("Abilities.Water.IceBlast.Interval", 20); config.addDefault("Abilities.Water.IceBlast.Cooldown", 1500); @@ -650,7 +650,7 @@ public class ConfigManager { config.addDefault("Abilities.Water.IceSpike.Field.Cooldown", 2000); config.addDefault("Abilities.Water.IceSpike.Blast.Range", 20); config.addDefault("Abilities.Water.IceSpike.Blast.Damage", 1); - config.addDefault("Abilities.Water.IceSpike.Blast.CollisionRadius", 2); + config.addDefault("Abilities.Water.IceSpike.Blast.CollisionRadius", 0.5); config.addDefault("Abilities.Water.IceSpike.Blast.DeflectRange", 3); config.addDefault("Abilities.Water.IceSpike.Blast.Cooldown", 500); config.addDefault("Abilities.Water.IceSpike.Blast.SlowCooldown", 5000); @@ -775,7 +775,7 @@ public class ConfigManager { config.addDefault("Abilities.Water.WaterManipulation.Damage", 3.0); config.addDefault("Abilities.Water.WaterManipulation.Range", 25); config.addDefault("Abilities.Water.WaterManipulation.SelectRange", 16); - config.addDefault("Abilities.Water.WaterManipulation.CollisionRadius", 2); + config.addDefault("Abilities.Water.WaterManipulation.CollisionRadius", 0.5); config.addDefault("Abilities.Water.WaterManipulation.DeflectRange", 3); config.addDefault("Abilities.Water.WaterManipulation.Speed", 35); config.addDefault("Abilities.Water.WaterManipulation.Push", 0.3); @@ -844,7 +844,7 @@ public class ConfigManager { config.addDefault("Abilities.Earth.EarthBlast.Push", 0.3); config.addDefault("Abilities.Earth.EarthBlast.Cooldown", 500); config.addDefault("Abilities.Earth.EarthBlast.DeflectRange", 3); - config.addDefault("Abilities.Earth.EarthBlast.CollisionRadius", 2); + config.addDefault("Abilities.Earth.EarthBlast.CollisionRadius", 0.5); config.addDefault("Abilities.Earth.EarthGrab.Enabled", true); config.addDefault("Abilities.Earth.EarthGrab.SelectRange", 20); @@ -974,7 +974,7 @@ public class ConfigManager { config.addDefault("Abilities.Fire.FireBlast.Enabled", true); config.addDefault("Abilities.Fire.FireBlast.Speed", 20); config.addDefault("Abilities.Fire.FireBlast.Range", 20); - config.addDefault("Abilities.Fire.FireBlast.CollisionRadius", 2); + config.addDefault("Abilities.Fire.FireBlast.CollisionRadius", 0.5); config.addDefault("Abilities.Fire.FireBlast.Push", 0.3); config.addDefault("Abilities.Fire.FireBlast.Damage", 3); config.addDefault("Abilities.Fire.FireBlast.Cooldown", 1500); diff --git a/src/com/projectkorra/projectkorra/earthbending/Collapse.java b/src/com/projectkorra/projectkorra/earthbending/Collapse.java index a0c636d0..57abf294 100644 --- a/src/com/projectkorra/projectkorra/earthbending/Collapse.java +++ b/src/com/projectkorra/projectkorra/earthbending/Collapse.java @@ -1,5 +1,7 @@ package com.projectkorra.projectkorra.earthbending; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -25,15 +27,15 @@ public class Collapse extends EarthAbility { private Vector direction; private Block block; private Map affectedBlocks; - + public Collapse(Player player) { super(player); setFields(); - + if (!bPlayer.canBend(this) || bPlayer.isOnCooldown("CollapsePillar")) { return; } - + block = BlockSource.getEarthSourceBlock(player, selectRange, ClickType.LEFT_CLICK); if (block == null) { return; @@ -83,7 +85,7 @@ public class Collapse extends EarthAbility { private void loadAffectedBlocks() { affectedBlocks.clear(); Block thisBlock; - + for (int i = 0; i <= distance; i++) { thisBlock = block.getWorld().getBlockAt(location.clone().add(direction.clone().multiply(-i))); affectedBlocks.put(thisBlock, thisBlock); @@ -125,7 +127,7 @@ public class Collapse extends EarthAbility { if (distance == 0) { return false; } - + moveEarth(block, direction, distance); loadAffectedBlocks(); return location.distanceSquared(origin) < distance * distance; @@ -156,6 +158,15 @@ public class Collapse extends EarthAbility { return false; } + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (Block block : affectedBlocks.values()) { + locations.add(block.getLocation()); + } + return locations; + } + public Location getOrigin() { return origin; } diff --git a/src/com/projectkorra/projectkorra/earthbending/EarthBlast.java b/src/com/projectkorra/projectkorra/earthbending/EarthBlast.java index f7fad93d..6acbc361 100644 --- a/src/com/projectkorra/projectkorra/earthbending/EarthBlast.java +++ b/src/com/projectkorra/projectkorra/earthbending/EarthBlast.java @@ -1,16 +1,6 @@ package com.projectkorra.projectkorra.earthbending; -import com.projectkorra.projectkorra.BendingPlayer; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; -import com.projectkorra.projectkorra.ability.WaterAbility; -import com.projectkorra.projectkorra.firebending.Combustion; -import com.projectkorra.projectkorra.firebending.FireBlast; -import com.projectkorra.projectkorra.util.BlockSource; -import com.projectkorra.projectkorra.util.ClickType; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.waterbending.WaterManipulation; +import java.util.ArrayList; import org.bukkit.Location; import org.bukkit.Material; @@ -20,7 +10,14 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.ArrayList; +import com.projectkorra.projectkorra.BendingPlayer; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.EarthAbility; +import com.projectkorra.projectkorra.ability.util.Collision; +import com.projectkorra.projectkorra.util.BlockSource; +import com.projectkorra.projectkorra.util.ClickType; +import com.projectkorra.projectkorra.util.DamageHandler; public class EarthBlast extends EarthAbility { @@ -47,7 +44,7 @@ public class EarthBlast extends EarthAbility { public EarthBlast(Player player) { super(player); - + this.isProgressing = false; this.isAtDestination = false; this.isSettingUp = true; @@ -59,10 +56,10 @@ public class EarthBlast extends EarthAbility { this.damage = getConfig().getDouble("Abilities.Earth.EarthBlast.Damage"); this.speed = getConfig().getDouble("Abilities.Earth.EarthBlast.Speed"); this.pushFactor = getConfig().getDouble("Abilities.Earth.EarthBlast.Push"); - this.selectRange = getConfig().getDouble("Abilities.Earth.EarthBlast.SelectRange"); + this.selectRange = getConfig().getDouble("Abilities.Earth.EarthBlast.SelectRange"); this.time = System.currentTimeMillis(); this.interval = (long) (1000.0 / speed); - + if (prepare()) { start(); time = System.currentTimeMillis(); @@ -84,9 +81,7 @@ public class EarthBlast extends EarthAbility { Location location = player.getEyeLocation(); Vector vector = location.getDirection(); Location mloc = blast.location; - if (mloc.distanceSquared(location) <= range * range - && GeneralMethods.getDistanceFromLine(vector, location, blast.location) < deflectRange - && mloc.distanceSquared(location.clone().add(vector)) < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) { + if (mloc.distanceSquared(location) <= range * range && GeneralMethods.getDistanceFromLine(vector, location, blast.location) < deflectRange && mloc.distanceSquared(location.clone().add(vector)) < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) { blast.remove(); remove(); return; @@ -99,7 +94,7 @@ public class EarthBlast extends EarthAbility { if (EarthPassive.isPassiveSand(sourceBlock)) { EarthPassive.revertSand(sourceBlock); } - + sourceData = sourceBlock.getData(); if (sourceBlock.getType() == Material.SAND) { sourceType = Material.SAND; @@ -107,7 +102,7 @@ public class EarthBlast extends EarthAbility { sourceBlock.setType(Material.RED_SANDSTONE); } else { sourceBlock.setType(Material.SANDSTONE); - } + } } else if (sourceBlock.getType() == Material.STEP) { sourceBlock.setType(Material.STEP); sourceType = Material.STEP; @@ -125,7 +120,7 @@ public class EarthBlast extends EarthAbility { private Location getTargetLocation() { Entity target = GeneralMethods.getTargetedEntity(player, range, new ArrayList()); Location location; - + if (target == null) { location = GeneralMethods.getTargetedLocation(player, range); } else { @@ -139,7 +134,7 @@ public class EarthBlast extends EarthAbility { if (block == null || !isEarthbendable(block)) { return false; } - + boolean selectedABlockInUse = false; for (EarthBlast blast : getAbilities(player, EarthBlast.class)) { if (!blast.isProgressing) { @@ -148,11 +143,11 @@ public class EarthBlast extends EarthAbility { selectedABlockInUse = true; } } - + if (selectedABlockInUse) { return false; } - + checkForCollision(); if (block.getLocation().distanceSquared(player.getLocation()) > selectRange * selectRange) { return false; @@ -169,7 +164,7 @@ public class EarthBlast extends EarthAbility { remove(); return; } - + if (System.currentTimeMillis() - time >= interval) { time = System.currentTimeMillis(); @@ -213,8 +208,8 @@ public class EarthBlast extends EarthAbility { } location = location.clone().add(direction); - Block block = location.getBlock(); - + Block block = location.getBlock(); + if (block.getLocation().equals(sourceBlock.getLocation())) { location = location.clone().add(direction); block = location.getBlock(); @@ -229,19 +224,6 @@ public class EarthBlast extends EarthAbility { location = location.clone().subtract(direction); direction = GeneralMethods.getDirection(location, destination).normalize(); location = location.clone().add(direction); - - WaterAbility.removeWaterSpouts(location, player); - AirAbility.removeAirSpouts(location, player); - EarthAbility.removeSandSpouts(location, player); - - if (EarthBlast.annihilateBlasts(location, collisionRadius, player) - || WaterManipulation.annihilateBlasts(location, collisionRadius, player) - || FireBlast.annihilateBlasts(location, collisionRadius, player)) { - remove(); - return; - } - - Combustion.removeAroundPoint(location, collisionRadius); Block block2 = location.getBlock(); if (block2.getLocation().equals(sourceBlock.getLocation())) { @@ -263,12 +245,12 @@ public class EarthBlast extends EarthAbility { } if (entity instanceof LivingEntity && (entity.getEntityId() != player.getEntityId() || canHitSelf)) { AirAbility.breakBreathbendingHold(entity); - + Location location = player.getEyeLocation(); Vector vector = location.getDirection(); entity.setVelocity(vector.normalize().multiply(pushFactor)); - double damage = this.damage; - + double damage = this.damage; + if (isMetal(sourceBlock) && bPlayer.canMetalbend()) { damage = getMetalAugment(damage); } @@ -290,7 +272,7 @@ public class EarthBlast extends EarthAbility { } moveEarthBlock(sourceBlock, block); - + if (block.getType() == Material.SAND) { block.setType(Material.SANDSTONE); } @@ -311,8 +293,7 @@ public class EarthBlast extends EarthAbility { sourceType = Material.SAND; sourceBlock.setType(sourceType); sourceBlock.setData((byte) 0x1); - } - else { + } else { sourceBlock.setType(sourceType); } } @@ -338,7 +319,7 @@ public class EarthBlast extends EarthAbility { @Override public void remove() { super.remove(); - if(destination != null && sourceBlock != null) { + if (destination != null && sourceBlock != null) { sourceBlock.setType(Material.AIR); } else if (sourceBlock != null) { if (sourceBlock.getType() == Material.SAND) { @@ -360,13 +341,13 @@ public class EarthBlast extends EarthAbility { if (sourceBlock == null || !sourceBlock.getWorld().equals(player.getWorld())) { return; } - + if (getMovedEarth().containsKey(sourceBlock)) { if (!isEarthRevertOn()) { removeRevertIndex(sourceBlock); } } - + Entity target = GeneralMethods.getTargetedEntity(player, range, new ArrayList()); if (target == null) { destination = getTargetEarthBlock((int) range).getLocation(); @@ -378,12 +359,12 @@ public class EarthBlast extends EarthAbility { firstDestination.setY(destination.getY()); destination = GeneralMethods.getPointOnLine(firstDestination, destination, range); } - + if (destination.distanceSquared(location) <= 1) { isProgressing = false; destination = null; } else { - isProgressing = true; + isProgressing = true; playEarthbendingSound(sourceBlock.getLocation()); Material currentType = sourceBlock.getType(); @@ -393,11 +374,16 @@ public class EarthBlast extends EarthAbility { addTempAirBlock(sourceBlock); } else { sourceBlock.breakNaturally(); - } + } sourceBlock.setType(currentType); } } - + + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean annihilateBlasts(Location location, double radius, Player source) { boolean broke = false; for (EarthBlast blast : getAbilities(EarthBlast.class)) { @@ -409,7 +395,7 @@ public class EarthBlast extends EarthAbility { } } return broke; - } + } public static ArrayList getAroundPoint(Location location, double radius) { ArrayList list = new ArrayList(); @@ -447,11 +433,8 @@ public class EarthBlast extends EarthAbility { Location location = player.getEyeLocation(); Vector vector = location.getDirection(); Location mloc = blast.location; - - if (mloc.distanceSquared(location) <= blast.range * blast.range - && GeneralMethods.getDistanceFromLine(vector, location, blast.location) < blast.deflectRange - && mloc.distanceSquared(location.clone().add(vector)) - < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) { + + if (mloc.distanceSquared(location) <= blast.range * blast.range && GeneralMethods.getDistanceFromLine(vector, location, blast.location) < blast.deflectRange && mloc.distanceSquared(location.clone().add(vector)) < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) { blast.redirect(player, blast.getTargetLocation()); } @@ -472,11 +455,11 @@ public class EarthBlast extends EarthAbility { ArrayList ignore = new ArrayList(); BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); EarthBlast earthBlast = null; - + if (bPlayer == null) { return; } - + for (EarthBlast blast : getAbilities(player, EarthBlast.class)) { if (!blast.isProgressing && bPlayer.canBend(blast)) { blast.throwEarth(); @@ -505,7 +488,7 @@ public class EarthBlast extends EarthAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -516,6 +499,16 @@ public class EarthBlast extends EarthAbility { return false; } + @Override + public boolean isCollidable() { + return isProgressing; + } + + @Override + public double getCollisionRadius() { + return collisionRadius; + } + public boolean isProgressing() { return isProgressing; } @@ -612,10 +605,6 @@ public class EarthBlast extends EarthAbility { this.deflectRange = deflectRange; } - public double getCollisionRadius() { - return collisionRadius; - } - public void setCollisionRadius(double collisionRadius) { this.collisionRadius = collisionRadius; } @@ -660,4 +649,4 @@ public class EarthBlast extends EarthAbility { this.location = location; } -} \ No newline at end of file +} diff --git a/src/com/projectkorra/projectkorra/earthbending/EarthSmash.java b/src/com/projectkorra/projectkorra/earthbending/EarthSmash.java index 0d37afb7..0f93e0da 100644 --- a/src/com/projectkorra/projectkorra/earthbending/EarthSmash.java +++ b/src/com/projectkorra/projectkorra/earthbending/EarthSmash.java @@ -1,14 +1,8 @@ package com.projectkorra.projectkorra.earthbending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; -import com.projectkorra.projectkorra.ability.WaterAbility; -import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.util.ClickType; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; -import com.projectkorra.projectkorra.util.TempBlock; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; import org.bukkit.Effect; import org.bukkit.Location; @@ -19,12 +13,16 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.EarthAbility; +import com.projectkorra.projectkorra.avatar.AvatarState; +import com.projectkorra.projectkorra.util.ClickType; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.util.TempBlock; public class EarthSmash extends EarthAbility { - + public static enum State { START, LIFTING, LIFTED, GRABBED, SHOT, FLYING, REMOVED } @@ -64,7 +62,7 @@ public class EarthSmash extends EarthAbility { public EarthSmash(Player player, ClickType type) { super(player); - + this.state = State.START; this.requiredBendableBlocks = getConfig().getInt("Abilities.Earth.EarthSmash.RequiredBendableBlocks"); this.maxBlocksToPassThrough = getConfig().getInt("Abilities.Earth.EarthSmash.MaxBlocksToPassThrough"); @@ -89,7 +87,7 @@ public class EarthSmash extends EarthAbility { this.affectedEntities = new ArrayList<>(); this.currentBlocks = new ArrayList<>(); this.affectedBlocks = new ArrayList<>(); - + if (type == ClickType.SHIFT_DOWN || type == ClickType.SHIFT_UP && !player.isSneaking()) { if (bPlayer.isAvatarState()) { selectRange = AvatarState.getValue(selectRange); @@ -119,17 +117,17 @@ public class EarthSmash extends EarthAbility { } grabbedSmash = aimingAtSmashCheck(player, State.SHOT); } - + if (grabbedSmash != null) { grabbedSmash.state = State.GRABBED; grabbedSmash.grabbedDistance = 0; - if(grabbedSmash.location.getWorld().equals(player.getWorld())) { + if (grabbedSmash.location.getWorld().equals(player.getWorld())) { grabbedSmash.grabbedDistance = grabbedSmash.location.distance(player.getEyeLocation()); } grabbedSmash.player = player; return; } - + start(); } else if (type == ClickType.LEFT_CLICK && player.isSneaking()) { for (EarthSmash smash : getAbilities(EarthSmash.class)) { @@ -155,11 +153,11 @@ public class EarthSmash extends EarthAbility { @Override public void progress() { progressCounter++; - if (state == State.LIFTED && removeTimer > 0 && System.currentTimeMillis() - startTime > removeTimer) { + if (state == State.LIFTED && removeTimer > 0 && System.currentTimeMillis() - getStartTime() > removeTimer) { remove(); return; } - + if (state == State.START) { if (!bPlayer.canBend(this)) { remove(); @@ -174,7 +172,7 @@ public class EarthSmash extends EarthAbility { if (state == State.START && progressCounter > 1) { if (!player.isSneaking()) { - if (System.currentTimeMillis() - startTime >= chargeTime) { + if (System.currentTimeMillis() - getStartTime() >= chargeTime) { origin = getEarthSourceBlock(selectRange); if (origin == null) { remove(); @@ -187,7 +185,7 @@ public class EarthSmash extends EarthAbility { remove(); return; } - } else if (System.currentTimeMillis() - startTime > chargeTime) { + } else if (System.currentTimeMillis() - getStartTime() > chargeTime) { Location tempLoc = player.getEyeLocation().add(player.getEyeLocation().getDirection().normalize().multiply(1.2)); tempLoc.add(0, 0.3, 0); ParticleEffect.SMOKE.display(tempLoc, 0.3F, 0.1F, 0.3F, 0, 4); @@ -210,10 +208,7 @@ public class EarthSmash extends EarthAbility { break; } } - - WaterAbility.removeWaterSpouts(location, 2, player); - AirAbility.removeAirSpouts(location, 2, player); - EarthAbility.removeSandSpouts(location, player); + draw(); return; } else { @@ -227,20 +222,18 @@ public class EarthSmash extends EarthAbility { remove(); return; } - + revert(); location.add(GeneralMethods.getDirection(location, destination).normalize().multiply(1)); if (location.distanceSquared(destination) < 4) { remove(); return; } - + // If an earthsmash runs into too many blocks we should remove it int badBlocksFound = 0; for (Block block : getBlocks()) { - if (block.getType() != Material.AIR && (!isTransparent(block) - || block.getType() == Material.WATER - || block.getType() == Material.STATIONARY_WATER)) { + if (block.getType() != Material.AIR && (!isTransparent(block) || block.getType() == Material.WATER || block.getType() == Material.STATIONARY_WATER)) { badBlocksFound++; } } @@ -249,8 +242,6 @@ public class EarthSmash extends EarthAbility { remove(); return; } - WaterAbility.removeWaterSpouts(location, 2, player); - AirAbility.removeAirSpouts(location, 2, player); shootingCollisionDetection(); draw(); smashToSmashCollisionDetection(); @@ -298,10 +289,10 @@ public class EarthSmash extends EarthAbility { /** * Begins animating the EarthSmash from the ground. The lift animation - * consists of 3 steps, and each one has to design the shape in the - * ground that removes the Earthbendable material. We also need to make - * sure that there is a clear path for the EarthSmash to rise, and that - * there is enough Earthbendable material for it to be created. + * consists of 3 steps, and each one has to design the shape in the ground + * that removes the Earthbendable material. We also need to make sure that + * there is a clear path for the EarthSmash to rise, and that there is + * enough Earthbendable material for it to be created. */ @SuppressWarnings("deprecation") public void animateLift() { @@ -368,7 +359,7 @@ public class EarthSmash extends EarthAbility { } } } - + /* * We needed to calculate all of the blocks based on the * location being 1 above the initial bending block, however we @@ -424,14 +415,13 @@ public class EarthSmash extends EarthAbility { } /** - * Checks to see which of the blocks are still attached to the - * EarthSmash, remember that blocks can be broken or used in other - * abilities so we need to double check and remove any that are not - * still attached. + * Checks to see which of the blocks are still attached to the EarthSmash, + * remember that blocks can be broken or used in other abilities so we need + * to double check and remove any that are not still attached. * - * Also when we remove the blocks from instances, movedearth, or tempair - * we should do it on a delay because tempair takes a couple seconds - * before the block shows up in that map. + * Also when we remove the blocks from instances, movedearth, or tempair we + * should do it on a delay because tempair takes a couple seconds before the + * block shows up in that map. */ public void checkRemainingBlocks() { for (int i = 0; i < currentBlocks.size(); i++) { @@ -452,9 +442,8 @@ public class EarthSmash extends EarthAbility { } /** - * Gets the blocks surrounding the EarthSmash's loc. This method ignores - * the blocks that should be Air, and only returns the ones that are - * dirt. + * Gets the blocks surrounding the EarthSmash's loc. This method ignores the + * blocks that should be Air, and only returns the ones that are dirt. */ public List getBlocks() { List blocks = new ArrayList(); @@ -473,8 +462,8 @@ public class EarthSmash extends EarthAbility { } /** - * Gets the blocks surrounding the EarthSmash's loc. This method returns - * all the blocks surrounding the loc, including dirt and air. + * Gets the blocks surrounding the EarthSmash's loc. This method returns all + * the blocks surrounding the loc, including dirt and air. */ public List getBlocksIncludingInner() { List blocks = new ArrayList(); @@ -489,7 +478,7 @@ public class EarthSmash extends EarthAbility { } return blocks; } - + /** * Switches the Sand Material and Gravel to SandStone and stone * respectively, since gravel and sand cannot be bent due to gravity. @@ -516,17 +505,16 @@ public class EarthSmash extends EarthAbility { } return tempMat; } - + /** * Determines if a player is trying to grab an EarthSmash. A player is - * trying to grab an EarthSmash if they are staring at it and holding - * shift. + * trying to grab an EarthSmash if they are staring at it and holding shift. */ private EarthSmash aimingAtSmashCheck(Player player, State reqState) { if (!allowGrab) { return null; } - + List blocks = GeneralMethods.getBlocksAroundPoint(GeneralMethods.getTargetedLocation(player, grabRange, GeneralMethods.NON_OPAQUE), 1); for (EarthSmash smash : getAbilities(EarthSmash.class)) { if (reqState == null || smash.state == reqState) { @@ -534,8 +522,7 @@ public class EarthSmash extends EarthAbility { if (block == null || smash.getLocation() == null) { continue; } - if (block.getLocation().getWorld() == smash.location.getWorld() - && block.getLocation().distanceSquared(smash.location) <= Math.pow(grabDetectionRadius, 2)) { + if (block.getLocation().getWorld() == smash.location.getWorld() && block.getLocation().distanceSquared(smash.location) <= Math.pow(grabDetectionRadius, 2)) { return smash; } } @@ -546,8 +533,8 @@ public class EarthSmash extends EarthAbility { /** * This method handles any collision between an EarthSmash and the - * surrounding entities, the method only applies to earthsmashes that - * have already been shot. + * surrounding entities, the method only applies to earthsmashes that have + * already been shot. */ public void shootingCollisionDetection() { List entities = GeneralMethods.getEntitiesAroundPoint(location, flightDetectionRadius); @@ -561,28 +548,27 @@ public class EarthSmash extends EarthAbility { } } } - + /** * EarthSmash to EarthSmash collision can only happen when one of the - * Smashes have been shot by a player. If we find out that one of them - * have collided then we want to return since a smash can only remove 1 - * at a time. + * Smashes have been shot by a player. If we find out that one of them have + * collided then we want to return since a smash can only remove 1 at a + * time. */ public void smashToSmashCollisionDetection() { for (EarthSmash smash : getAbilities(EarthSmash.class)) { - if (smash.location != null && smash != this && smash.location.getWorld() == location.getWorld() - && smash.location.distanceSquared(location) < Math.pow(flightDetectionRadius, 2)) { + if (smash.location != null && smash != this && smash.location.getWorld() == location.getWorld() && smash.location.distanceSquared(location) < Math.pow(flightDetectionRadius, 2)) { smash.remove(); remove(); return; } } } - + /** * Determines whether or not a player is trying to fly ontop of an - * EarthSmash. A player is considered "flying" if they are standing - * ontop of the earthsmash and holding shift. + * EarthSmash. A player is considered "flying" if they are standing ontop of + * the earthsmash and holding shift. */ private static EarthSmash flyingInSmashCheck(Player player) { for (EarthSmash smash : getAbilities(EarthSmash.class)) { @@ -591,8 +577,7 @@ public class EarthSmash extends EarthAbility { } //Check to see if the player is standing on top of the smash. if (smash.state == State.LIFTED) { - if (smash.location.getWorld().equals(player.getWorld()) - && smash.location.clone().add(0, 2, 0).distanceSquared(player.getLocation()) <= Math.pow(smash.flightDetectionRadius, 2)) { + if (smash.location.getWorld().equals(player.getWorld()) && smash.location.clone().add(0, 2, 0).distanceSquared(player.getLocation()) <= Math.pow(smash.flightDetectionRadius, 2)) { return smash; } } @@ -601,12 +586,11 @@ public class EarthSmash extends EarthAbility { } /** - * A BlockRepresenter is used to keep track of each of the individual - * types of blocks that are attached to an EarthSmash. Without the - * representer then an EarthSmash can only be made up of 1 material at a - * time. For example, an ESmash that is entirely dirt, coalore, or - * sandstone. Using the representer will allow all the materials to be - * mixed together. + * A BlockRepresenter is used to keep track of each of the individual types + * of blocks that are attached to an EarthSmash. Without the representer + * then an EarthSmash can only be made up of 1 material at a time. For + * example, an ESmash that is entirely dirt, coalore, or sandstone. Using + * the representer will allow all the materials to be mixed together. */ public class BlockRepresenter { private int x, y, z; @@ -706,7 +690,7 @@ public class EarthSmash extends EarthAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -717,6 +701,15 @@ public class EarthSmash extends EarthAbility { return false; } + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (TempBlock tblock : affectedBlocks) { + locations.add(tblock.getLocation()); + } + return locations; + } + public boolean isAllowGrab() { return allowGrab; } @@ -836,7 +829,7 @@ public class EarthSmash extends EarthAbility { public void setGrabRange(double grabRange) { this.grabRange = grabRange; } - + public double getSelectRange() { return selectRange; } diff --git a/src/com/projectkorra/projectkorra/earthbending/EarthTunnel.java b/src/com/projectkorra/projectkorra/earthbending/EarthTunnel.java index cdea4f58..c1a8e375 100644 --- a/src/com/projectkorra/projectkorra/earthbending/EarthTunnel.java +++ b/src/com/projectkorra/projectkorra/earthbending/EarthTunnel.java @@ -1,6 +1,8 @@ package com.projectkorra.projectkorra.earthbending; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -16,7 +18,7 @@ import com.projectkorra.projectkorra.configuration.ConfigManager; import com.projectkorra.projectkorra.util.TempBlock; public class EarthTunnel extends EarthAbility { - + private long interval; private long time; private double depth; @@ -32,10 +34,10 @@ public class EarthTunnel extends EarthAbility { private Vector direction; public static Map airBlocks = new ConcurrentHashMap(); - + public EarthTunnel(Player player) { super(player); - + this.maxRadius = getConfig().getDouble("Abilities.Earth.EarthTunnel.MaxRadius"); this.range = getConfig().getDouble("Abilities.Earth.EarthTunnel.Range"); this.radius = getConfig().getDouble("Abilities.Earth.EarthTunnel.Radius"); @@ -43,21 +45,21 @@ public class EarthTunnel extends EarthAbility { this.revert = getConfig().getBoolean("Abilities.Earth.EarthTunnel.Revert"); this.radiusIncrement = radius; this.time = System.currentTimeMillis(); - + this.location = player.getEyeLocation().clone(); this.origin = player.getTargetBlock((HashSet) null, (int) range).getLocation(); this.block = origin.getBlock(); this.direction = location.getDirection().clone().normalize(); this.depth = 0; - if(origin.getWorld().equals(location.getWorld())) { - this.depth = Math.max(0, origin.distance(location) - 1); + if (origin.getWorld().equals(location.getWorld())) { + this.depth = Math.max(0, origin.distance(location) - 1); } this.angle = 0; if (!bPlayer.canBend(this)) { return; } - + start(); } @@ -67,7 +69,7 @@ public class EarthTunnel extends EarthAbility { remove(); return; } - + if (System.currentTimeMillis() - time >= interval) { time = System.currentTimeMillis(); if (Math.abs(Math.toDegrees(player.getEyeLocation().getDirection().angle(direction))) > 20 || !player.isSneaking()) { @@ -79,7 +81,7 @@ public class EarthTunnel extends EarthAbility { remove(); return; } - + if (angle >= 360) { angle = 0; if (radius >= maxRadius) { @@ -96,11 +98,11 @@ public class EarthTunnel extends EarthAbility { } else { angle += 20; } - + Vector vec = GeneralMethods.getOrthogonalVector(direction, angle, radius); block = location.clone().add(direction.clone().normalize().multiply(depth)).add(vec).getBlock(); } - + if (revert) { if (getMovedEarth().containsKey(block)) { block.setType(Material.AIR); @@ -128,7 +130,7 @@ public class EarthTunnel extends EarthAbility { public long getCooldown() { return 0; } - + @Override public boolean isSneakAbility() { return true; @@ -139,6 +141,15 @@ public class EarthTunnel extends EarthAbility { return false; } + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (TempBlock tblock : airBlocks.keySet()) { + locations.add(tblock.getLocation()); + } + return locations; + } + public long getInterval() { return interval; } @@ -230,7 +241,7 @@ public class EarthTunnel extends EarthAbility { public void setLocation(Location location) { this.location = location; } - + public static void revertAirBlocks() { if (ConfigManager.defaultConfig.get().getBoolean("Abilities.Earth.EarthTunnel.Revert")) { for (TempBlock tempBlock : EarthTunnel.airBlocks.keySet()) { @@ -241,5 +252,5 @@ public class EarthTunnel extends EarthAbility { } } } - + } diff --git a/src/com/projectkorra/projectkorra/earthbending/LavaFlow.java b/src/com/projectkorra/projectkorra/earthbending/LavaFlow.java index 093db5df..c056f401 100644 --- a/src/com/projectkorra/projectkorra/earthbending/LavaFlow.java +++ b/src/com/projectkorra/projectkorra/earthbending/LavaFlow.java @@ -18,12 +18,13 @@ import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; public class LavaFlow extends LavaAbility { - + public static enum AbilityType { SHIFT, CLICK } @@ -31,7 +32,7 @@ public class LavaFlow extends LavaAbility { private static final Map TEMP_LAVA_BLOCKS = new ConcurrentHashMap<>(); private static final Map TEMP_LAND_BLOCKS = new ConcurrentHashMap<>(); private static final Map TEMP_AIR_BLOCKS = new ConcurrentHashMap<>(); - + private boolean removing; private boolean makeLava; private boolean clickIsFinished; @@ -66,7 +67,7 @@ public class LavaFlow extends LavaAbility { private ArrayList affectedBlocks; private ArrayList tasks; private Material revertMaterial; - + /** * Creates a new LavaFlow ability and initializes all of the variables and * cooldowns. The ability is not guaranteed to continue, it may be the case @@ -155,7 +156,7 @@ public class LavaFlow extends LavaAbility { remove(); return; } - + long cooldown = makeLava ? clickLavaCooldown : clickLandCooldown; origin = sourceBlock.getLocation(); makeLava = !isLava(sourceBlock); @@ -187,7 +188,7 @@ public class LavaFlow extends LavaAbility { } Random random = new Random(); - + if (type == AbilityType.SHIFT) { if (System.currentTimeMillis() - time > shiftRemoveDelay) { remove(); @@ -249,23 +250,20 @@ public class LavaFlow extends LavaAbility { createLava(block); } } - + } - } else if (Math.random() < particleDensity - && dSquared < Math.pow(currentRadius + particleDensity, 2) - && currentRadius + particleDensity < shiftMaxRadius - && random.nextInt(3) == 0) { + } else if (Math.random() < particleDensity && dSquared < Math.pow(currentRadius + particleDensity, 2) && currentRadius + particleDensity < shiftMaxRadius && random.nextInt(3) == 0) { ParticleEffect.LAVA.display(loc, (float) Math.random(), (float) Math.random(), (float) Math.random(), 0, 1); } } } - - if(!shiftIsFinished) { + + if (!shiftIsFinished) { if (random.nextInt(10) == 0) { ParticleEffect.LAVA.display(player.getLocation(), (float) Math.random(), (float) Math.random(), (float) Math.random(), 0, 1); } } - + currentRadius += shiftFlowSpeed; if (currentRadius > shiftMaxRadius) { currentRadius = shiftMaxRadius; @@ -274,16 +272,17 @@ public class LavaFlow extends LavaAbility { } } else if (type == AbilityType.CLICK) { /* - * The variable makeLava refers to whether or not the ability is trying - * to remove land in place of lava or if makeLava = false then lava is - * being replaced with land. + * The variable makeLava refers to whether or not the ability is + * trying to remove land in place of lava or if makeLava = false + * then lava is being replaced with land. * - * Notice we have separate variables between both versions, because most - * of the time making lava will have longer delays and longer cooldowns. + * Notice we have separate variables between both versions, because + * most of the time making lava will have longer delays and longer + * cooldowns. */ long curTime = System.currentTimeMillis() - time; double delay = makeLava ? clickLavaDelay : clickLandDelay; - + if (makeLava && curTime > clickLavaCleanupDelay) { remove(); return; @@ -297,9 +296,8 @@ public class LavaFlow extends LavaAbility { for (double z = -clickLavaRadius; z <= clickLavaRadius; z++) { Location loc = origin.clone().add(x, 0, z); Block tempBlock = GeneralMethods.getTopBlock(loc, upwardFlow, downwardFlow); - - if (tempBlock != null && !isLava(tempBlock) && Math.random() < particleDensity - && tempBlock.getLocation().distanceSquared(origin) <= Math.pow(clickLavaRadius, 2)) { + + if (tempBlock != null && !isLava(tempBlock) && Math.random() < particleDensity && tempBlock.getLocation().distanceSquared(origin) <= Math.pow(clickLavaRadius, 2)) { if (random.nextInt(3) == 0) { ParticleEffect.LAVA.display(loc, (float) Math.random(), (float) Math.random(), (float) Math.random(), 0, 1); } @@ -317,7 +315,7 @@ public class LavaFlow extends LavaAbility { if (!clickIsFinished) { clickIsFinished = true; double radius = makeLava ? clickLavaRadius : clickLandRadius; - + for (double x = -radius; x <= radius; x++) { for (double z = -radius; z <= radius; z++) { Location loc = origin.clone().add(x, 0, z); @@ -398,14 +396,15 @@ public class LavaFlow extends LavaAbility { TempBlock tb = new TempBlock(above, Material.AIR, (byte) 0); TEMP_AIR_BLOCKS.put(above, tb); affectedBlocks.add(tb); - } else return; - } + } else + return; + } TempBlock tblock = new TempBlock(block, Material.LAVA, (byte) 0); TEMP_LAVA_BLOCKS.put(block, tblock); affectedBlocks.add(tblock); - + if (allowNaturalFlow) { -// ProjectKorra.plugin.getLogger().info("Flow free!"); + // ProjectKorra.plugin.getLogger().info("Flow free!"); TempBlock.removeBlock(block); } } @@ -469,7 +468,7 @@ public class LavaFlow extends LavaAbility { tblock.getBlock().getRelative(BlockFace.UP).setType(Material.DOUBLE_PLANT); tblock.getBlock().getRelative(BlockFace.UP).setData((byte) (tblock.getState().getRawData() + 8)); } - + } }.runTaskLater(ProjectKorra.plugin, (long) (i / shiftRemoveSpeed)); @@ -515,7 +514,6 @@ public class LavaFlow extends LavaAbility { task.cancel(); } } - /** * Returns a list of all the Lava blocks that are adjacent to the block at @@ -546,7 +544,7 @@ public class LavaFlow extends LavaAbility { public static ArrayList getAdjacentBlocks(Location loc) { ArrayList list = new ArrayList(); Block block = loc.getBlock(); - + for (int x = -1; x <= 1; x++) { for (int y = -2; y <= 1; y++) { for (int z = -1; z <= 1; z++) { @@ -594,18 +592,18 @@ public class LavaFlow extends LavaAbility { } return list; } - + public static Material getRevertMaterial() { Material m = Material.STONE; LavaFlow lf = (LavaFlow) CoreAbility.getAbility("LavaFlow"); m = lf.revertMaterial; return m; } - + public static Map getTempLandBlocks() { return TEMP_LAND_BLOCKS; } - + public static Map getTempLavaBlocks() { return TEMP_LAVA_BLOCKS; } @@ -629,7 +627,7 @@ public class LavaFlow extends LavaAbility { public long getCooldown() { return type == AbilityType.CLICK ? clickLandCooldown : shiftCooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -640,6 +638,15 @@ public class LavaFlow extends LavaAbility { return false; } + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (TempBlock tblock : affectedBlocks) { + locations.add(tblock.getLocation()); + } + return locations; + } + public boolean isRemoving() { return removing; } @@ -895,5 +902,5 @@ public class LavaFlow extends LavaAbility { public ArrayList getTasks() { return tasks; } - + } diff --git a/src/com/projectkorra/projectkorra/earthbending/RaiseEarth.java b/src/com/projectkorra/projectkorra/earthbending/RaiseEarth.java index 0b8eccb3..20220128 100644 --- a/src/com/projectkorra/projectkorra/earthbending/RaiseEarth.java +++ b/src/com/projectkorra/projectkorra/earthbending/RaiseEarth.java @@ -13,6 +13,8 @@ import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.util.Vector; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -178,6 +180,15 @@ public class RaiseEarth extends EarthAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (Block block : affectedBlocks.values()) { + locations.add(block.getLocation()); + } + return locations; + } public int getDistance() { return distance; diff --git a/src/com/projectkorra/projectkorra/earthbending/Ripple.java b/src/com/projectkorra/projectkorra/earthbending/Ripple.java index 04ee67d1..9ada5849 100644 --- a/src/com/projectkorra/projectkorra/earthbending/Ripple.java +++ b/src/com/projectkorra/projectkorra/earthbending/Ripple.java @@ -1,10 +1,8 @@ package com.projectkorra.projectkorra.earthbending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; -import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.util.DamageHandler; +import java.util.ArrayList; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Location; import org.bukkit.Material; @@ -16,9 +14,11 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.EarthAbility; +import com.projectkorra.projectkorra.avatar.AvatarState; +import com.projectkorra.projectkorra.util.DamageHandler; public class Ripple extends EarthAbility { @@ -328,6 +328,11 @@ public class Ripple extends EarthAbility { return false; } + @Override + public ArrayList getLocations() { + return locations; + } + public int getStep() { return step; } @@ -416,10 +421,6 @@ public class Ripple extends EarthAbility { this.block4 = block4; } - public ArrayList getLocations() { - return locations; - } - public ArrayList getEntities() { return entities; } diff --git a/src/com/projectkorra/projectkorra/earthbending/SandSpout.java b/src/com/projectkorra/projectkorra/earthbending/SandSpout.java index 1925f6ac..57d81b63 100644 --- a/src/com/projectkorra/projectkorra/earthbending/SandSpout.java +++ b/src/com/projectkorra/projectkorra/earthbending/SandSpout.java @@ -1,9 +1,9 @@ package com.projectkorra.projectkorra.earthbending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.SandAbility; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.Flight; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; import org.bukkit.Location; import org.bukkit.Material; @@ -13,8 +13,10 @@ import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import java.util.Collection; -import java.util.Random; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.SandAbility; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.Flight; public class SandSpout extends SandAbility { @@ -259,6 +261,20 @@ public class SandSpout extends SandAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + if (player == null) { + return locations; + } + Location top = player.getLocation(); + double ySpacing = 2; + for (double i = 0; i < this.getHeight(); i += ySpacing) { + locations.add(top.clone().add(0, -i, 0)); + } + return locations; + } public boolean isCanSpiral() { return canSpiral; diff --git a/src/com/projectkorra/projectkorra/earthbending/Shockwave.java b/src/com/projectkorra/projectkorra/earthbending/Shockwave.java index a4053149..9c828a45 100644 --- a/src/com/projectkorra/projectkorra/earthbending/Shockwave.java +++ b/src/com/projectkorra/projectkorra/earthbending/Shockwave.java @@ -64,7 +64,7 @@ public class Shockwave extends EarthAbility { return; } - if (System.currentTimeMillis() > startTime + chargeTime && !charged) { + if (System.currentTimeMillis() > getStartTime() + chargeTime && !charged) { charged = true; } diff --git a/src/com/projectkorra/projectkorra/event/AbilityCollisionEvent.java b/src/com/projectkorra/projectkorra/event/AbilityCollisionEvent.java new file mode 100644 index 00000000..82deed93 --- /dev/null +++ b/src/com/projectkorra/projectkorra/event/AbilityCollisionEvent.java @@ -0,0 +1,42 @@ +package com.projectkorra.projectkorra.event; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import com.projectkorra.projectkorra.ability.util.Collision; + +public class AbilityCollisionEvent extends Event implements Cancellable { + + private static final HandlerList HANDLERS = new HandlerList(); + + private boolean cancelled; + private Collision collision; + + public AbilityCollisionEvent(Collision collision) { + this.collision = collision; + this.cancelled = false; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + public Collision getCollision() { + return collision; + } + + public void setCollision(Collision collision) { + this.collision = collision; + } + + @Override + public HandlerList getHandlers() { + return HANDLERS; + } + +} diff --git a/src/com/projectkorra/projectkorra/firebending/Combustion.java b/src/com/projectkorra/projectkorra/firebending/Combustion.java index 47d90909..b42f113c 100644 --- a/src/com/projectkorra/projectkorra/firebending/Combustion.java +++ b/src/com/projectkorra/projectkorra/firebending/Combustion.java @@ -4,6 +4,7 @@ import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ProjectKorra; import com.projectkorra.projectkorra.ability.AirAbility; import com.projectkorra.projectkorra.ability.CombustionAbility; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.avatar.AvatarState; import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; @@ -77,6 +78,11 @@ public class Combustion extends CombustionAbility { } } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean removeAroundPoint(Location loc, double radius) { for (Combustion combustion : getAbilities(Combustion.class)) { if (combustion.location.getWorld().equals(loc.getWorld())) { @@ -176,6 +182,11 @@ public class Combustion extends CombustionAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public double getCollisionRadius() { + return getRadius(); + } public boolean isBreakBlocks() { return breakBlocks; diff --git a/src/com/projectkorra/projectkorra/firebending/FireBlast.java b/src/com/projectkorra/projectkorra/firebending/FireBlast.java index 2c165f54..4b7015fd 100644 --- a/src/com/projectkorra/projectkorra/firebending/FireBlast.java +++ b/src/com/projectkorra/projectkorra/firebending/FireBlast.java @@ -1,17 +1,8 @@ package com.projectkorra.projectkorra.firebending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ProjectKorra; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; -import com.projectkorra.projectkorra.ability.FireAbility; -import com.projectkorra.projectkorra.ability.WaterAbility; -import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.earthbending.EarthBlast; -import com.projectkorra.projectkorra.util.DamageHandler; -import com.projectkorra.projectkorra.util.ParticleEffect; -import com.projectkorra.projectkorra.waterbending.PlantRegrowth; -import com.projectkorra.projectkorra.waterbending.WaterManipulation; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; import org.bukkit.Location; import org.bukkit.Material; @@ -23,9 +14,15 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ProjectKorra; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.FireAbility; +import com.projectkorra.projectkorra.ability.util.Collision; +import com.projectkorra.projectkorra.avatar.AvatarState; +import com.projectkorra.projectkorra.util.DamageHandler; +import com.projectkorra.projectkorra.util.ParticleEffect; +import com.projectkorra.projectkorra.waterbending.PlantRegrowth; public class FireBlast extends FireAbility { @@ -196,18 +193,6 @@ public class FireBlast extends FireAbility { return; } - WaterAbility.removeWaterSpouts(location, player); - AirAbility.removeAirSpouts(location, player); - EarthAbility.removeSandSpouts(location, player); - - Player source = player; - if (EarthBlast.annihilateBlasts(location, collisionRadius, source) - || WaterManipulation.annihilateBlasts(location, collisionRadius, source) - || FireBlast.annihilateBlasts(location, collisionRadius, source)) { - remove(); - return; - } - for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, collisionRadius)) { affect(entity); if (entity instanceof LivingEntity) { @@ -218,6 +203,11 @@ public class FireBlast extends FireAbility { advanceLocation(); } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean annihilateBlasts(Location location, double radius, Player source) { boolean broke = false; for (FireBlast blast : getAbilities(FireBlast.class)) { @@ -284,6 +274,11 @@ public class FireBlast extends FireAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public double getCollisionRadius() { + return collisionRadius; + } public boolean isPowerFurnace() { return powerFurnace; @@ -349,10 +344,6 @@ public class FireBlast extends FireAbility { this.speed = speed; } - public double getCollisionRadius() { - return collisionRadius; - } - public void setCollisionRadius(double collisionRadius) { this.collisionRadius = collisionRadius; } diff --git a/src/com/projectkorra/projectkorra/firebending/FireBlastCharged.java b/src/com/projectkorra/projectkorra/firebending/FireBlastCharged.java index 6466290b..45012a1a 100644 --- a/src/com/projectkorra/projectkorra/firebending/FireBlastCharged.java +++ b/src/com/projectkorra/projectkorra/firebending/FireBlastCharged.java @@ -252,7 +252,7 @@ public class FireBlastCharged extends FireAbility { return; } - if (System.currentTimeMillis() > startTime + chargeTime) { + if (System.currentTimeMillis() > getStartTime() + chargeTime) { charged = true; } if (!player.isSneaking() && !launched) { @@ -320,6 +320,16 @@ public class FireBlastCharged extends FireAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public boolean isCollidable() { + return this.launched; + } + + @Override + public double getCollisionRadius() { + return collisionRadius; + } public boolean isCharged() { return charged; @@ -393,10 +403,6 @@ public class FireBlastCharged extends FireAbility { this.range = range; } - public double getCollisionRadius() { - return collisionRadius; - } - public void setCollisionRadius(double collisionRadius) { this.collisionRadius = collisionRadius; } diff --git a/src/com/projectkorra/projectkorra/firebending/FireBurst.java b/src/com/projectkorra/projectkorra/firebending/FireBurst.java index 7a9b1bbb..b5751018 100644 --- a/src/com/projectkorra/projectkorra/firebending/FireBurst.java +++ b/src/com/projectkorra/projectkorra/firebending/FireBurst.java @@ -117,7 +117,7 @@ public class FireBurst extends FireAbility { return; } - if (System.currentTimeMillis() > startTime + chargeTime && !charged) { + if (System.currentTimeMillis() > getStartTime() + chargeTime && !charged) { charged = true; } diff --git a/src/com/projectkorra/projectkorra/firebending/FireCombo.java b/src/com/projectkorra/projectkorra/firebending/FireCombo.java index 0a42b803..9c50454b 100644 --- a/src/com/projectkorra/projectkorra/firebending/FireCombo.java +++ b/src/com/projectkorra/projectkorra/firebending/FireCombo.java @@ -1,6 +1,7 @@ package com.projectkorra.projectkorra.firebending; import java.util.ArrayList; +import java.util.List; import org.bukkit.Effect; import org.bukkit.Location; @@ -16,12 +17,11 @@ import org.bukkit.util.Vector; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ProjectKorra; -import com.projectkorra.projectkorra.ability.AirAbility; import com.projectkorra.projectkorra.ability.ComboAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.ElementalAbility; import com.projectkorra.projectkorra.ability.FireAbility; import com.projectkorra.projectkorra.ability.WaterAbility; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.ability.util.ComboManager.AbilityInformation; import com.projectkorra.projectkorra.avatar.AvatarState; import com.projectkorra.projectkorra.command.Commands; @@ -30,26 +30,11 @@ import com.projectkorra.projectkorra.util.DamageHandler; import com.projectkorra.projectkorra.util.ParticleEffect; /* - * TODO: Combo classes should eventually be rewritten so that each combo is treated - * as an individual ability. In the mean time, we will just place "fake" - * classes so that CoreAbility will register each ability. + * TODO: Combo classes should eventually be rewritten so that each combo is + * treated as an individual ability. In the mean time, we will just place "fake" + * classes so that CoreAbility will register each ability. */ public class FireCombo extends FireAbility implements ComboAbility { - - private static final ArrayList BLOCKABLE_ABILITIES = new ArrayList() { - private static final long serialVersionUID = 0; { - add("AirShield"); - add("FireShield"); - add("AirSwipe"); - add("FireBlast"); - add("EarthBlast"); - add("WaterManipulation"); - add("Combustion"); - add("FireKick"); - add("FireSpin"); - add("AirSweep"); - } - }; private boolean firstTime; private int progressCounter; @@ -70,20 +55,20 @@ public class FireCombo extends FireAbility implements ComboAbility { private Vector direction; private ArrayList affectedEntities; private ArrayList tasks; - + public FireCombo(Player player, String ability) { super(player); this.ability = ability; - + if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { return; } - + this.firstTime = true; this.time = System.currentTimeMillis(); this.affectedEntities = new ArrayList<>(); this.tasks = new ArrayList<>(); - + if (ability.equalsIgnoreCase("FireKick")) { this.damage = getConfig().getDouble("Abilities.Fire.FireCombo.FireKick.Damage"); this.range = getConfig().getDouble("Abilities.Fire.FireCombo.FireKick.Range"); @@ -112,7 +97,7 @@ public class FireCombo extends FireAbility implements ComboAbility { this.cooldown = getConfig().getLong("Abilities.Fire.FireCombo.JetBlaze.Cooldown"); this.fireTicks = getConfig().getDouble("Abilities.Fire.FireCombo.JetBlaze.FireTicks"); } - + if (bPlayer.isAvatarState()) { this.cooldown = 0; this.damage = AvatarState.getValue(damage); @@ -121,10 +106,9 @@ public class FireCombo extends FireAbility implements ComboAbility { start(); } - /** - * Returns all of the FireCombos created by a specific player but filters the abilities based on - * shift or click. + * Returns all of the FireCombos created by a specific player but filters + * the abilities based on shift or click. */ public static ArrayList getFireCombo(Player player, ClickType type) { ArrayList list = new ArrayList(); @@ -136,6 +120,11 @@ public class FireCombo extends FireAbility implements ComboAbility { return list; } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean removeAroundPoint(Player player, String ability, Location loc, double radius) { boolean removed = false; for (FireCombo combo : getAbilities(FireCombo.class)) { @@ -145,8 +134,7 @@ public class FireCombo extends FireAbility implements ComboAbility { if (ability.equalsIgnoreCase("FireKick") && combo.ability.equalsIgnoreCase("FireKick")) { for (FireComboStream fs : combo.tasks) { - if (fs.getLocation() != null && fs.getLocation().getWorld() == loc.getWorld() - && Math.abs(fs.getLocation().distanceSquared(loc)) <= radius * radius) { + if (fs.getLocation() != null && fs.getLocation().getWorld() == loc.getWorld() && Math.abs(fs.getLocation().distanceSquared(loc)) <= radius * radius) { fs.remove(); removed = true; } @@ -160,9 +148,7 @@ public class FireCombo extends FireAbility implements ComboAbility { } } } - } - - else if (ability.equalsIgnoreCase("FireWheel") && combo.ability.equalsIgnoreCase("FireWheel")) { + } else if (ability.equalsIgnoreCase("FireWheel") && combo.ability.equalsIgnoreCase("FireWheel")) { if (combo.location != null && Math.abs(combo.location.distanceSquared(loc)) <= radius * radius) { combo.remove(); removed = true; @@ -227,7 +213,7 @@ public class FireCombo extends FireAbility implements ComboAbility { } } } - + if (!bPlayer.canBendIgnoreBindsCooldowns(this)) { remove(); return; @@ -239,7 +225,7 @@ public class FireCombo extends FireAbility implements ComboAbility { remove(); return; } - + bPlayer.addCooldown("FireKick", cooldown); Vector eyeDir = player.getEyeLocation().getDirection().normalize().multiply(range); destination = player.getEyeLocation().add(eyeDir); @@ -262,17 +248,10 @@ public class FireCombo extends FireAbility implements ComboAbility { player.getWorld().playSound(player.getLocation(), Sound.ITEM_FLINTANDSTEEL_USE, 0.5f, 1f); } location = tasks.get(0).getLocation(); - for (FireComboStream stream : tasks) { - if (GeneralMethods.blockAbilities(player, BLOCKABLE_ABILITIES, stream.location, 2)) { - stream.remove(); - } - } } else if (tasks.size() == 0) { remove(); return; - } AirAbility.removeAirSpouts(location, player); - WaterAbility.removeWaterSpouts(location, player); - EarthAbility.removeSandSpouts(location, player); + } } else if (ability.equalsIgnoreCase("FireSpin")) { if (destination == null) { if (bPlayer.isOnCooldown("FireSpin") && !bPlayer.isAvatarState()) { @@ -299,20 +278,11 @@ public class FireCombo extends FireAbility implements ComboAbility { tasks.add(fs); } } - + if (tasks.size() == 0) { remove(); return; } - - for (FireComboStream stream : tasks) { - if (isWithinFireShield(stream.getLocation())) { - stream.remove(); - } - if (AirAbility.isWithinAirShield(stream.getLocation())) { - stream.remove(); - } - } } else if (ability.equalsIgnoreCase("JetBlast")) { if (System.currentTimeMillis() - time > 5000) { remove(); @@ -323,7 +293,7 @@ public class FireCombo extends FireAbility implements ComboAbility { remove(); return; } - + bPlayer.addCooldown("JetBlast", cooldown); firstTime = false; float spread = 0F; @@ -332,9 +302,8 @@ public class FireCombo extends FireAbility implements ComboAbility { } FireJet fj = getAbility(player, FireJet.class); fj.setSpeed(speed); - FireComboStream fs = new FireComboStream(this, - player.getVelocity().clone().multiply(-1), player.getLocation(), 3, 0.5, "JetBlast"); - + FireComboStream fs = new FireComboStream(this, player.getVelocity().clone().multiply(-1), player.getLocation(), 3, 0.5, "JetBlast"); + fs.setDensity(1); fs.setSpread(0.9F); fs.setUseNewParticles(true); @@ -404,7 +373,7 @@ public class FireCombo extends FireAbility implements ComboAbility { } location.setY(topBlock.getY() + height); FireComboStream fs = new FireComboStream(this, direction, location.clone().add(0, -1, 0), 5, 1, "FireWheel"); - + fs.setDensity(0); fs.setSinglePoint(true); fs.setCollisionRadius(1.5); @@ -422,16 +391,12 @@ public class FireCombo extends FireAbility implements ComboAbility { location = location.add(direction.clone().multiply(speed)); location.getWorld().playSound(location, Sound.BLOCK_FIRE_AMBIENT, 1, 1); - if (GeneralMethods.blockAbilities(player, BLOCKABLE_ABILITIES, location, 2)) { - remove(); - return; - } } } /** - * Removes this instance of FireCombo, cleans up any blocks that are remaining in totalBlocks, - * and cancels any remaining tasks. + * Removes this instance of FireCombo, cleans up any blocks that are + * remaining in totalBlocks, and cancels any remaining tasks. */ @Override public void remove() { @@ -470,7 +435,7 @@ public class FireCombo extends FireAbility implements ComboAbility { this.checkCollisionCounter = 0; this.spread = 0; this.collisionRadius = 2; - this.particleEffect = ParticleEffect.FLAME; + this.particleEffect = ParticleEffect.FLAME; this.fireCombo = fireCombo; this.direction = direction; this.speed = speed; @@ -479,7 +444,7 @@ public class FireCombo extends FireAbility implements ComboAbility { this.distance = distance; this.ability = ability; } - + @Override public void run() { Block block = location.getBlock(); @@ -506,7 +471,7 @@ public class FireCombo extends FireAbility implements ComboAbility { } } } - + checkCollisionCounter++; if (singlePoint) { remove(); @@ -586,7 +551,7 @@ public class FireCombo extends FireAbility implements ComboAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -596,7 +561,22 @@ public class FireCombo extends FireAbility implements ComboAbility { public boolean isHarmlessAbility() { return false; } - + + @Override + public boolean isCollidable() { + // Override in subclasses + return false; + } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (FireComboStream stream : tasks) { + locations.add(stream.getLocation()); + } + return locations; + } + @Override public String getInstructions() { return null; @@ -611,7 +591,25 @@ public class FireCombo extends FireAbility implements ComboAbility { public ArrayList getCombination() { return null; } - + + public void handleCollisionFireStreams(Collision collision) { + if (collision.isRemovingFirst()) { + ArrayList newTasks = new ArrayList<>(); + double collisionDistanceSquared = Math.pow(getCollisionRadius() + collision.getAbilitySecond().getCollisionRadius(), 2); + // Remove all of the streams that are by this specific ourLocation. + // Don't just do a single stream at a time or this algorithm becomes O(n^2) with + // Collision's detection algorithm. + for (FireComboStream stream : tasks) { + if (stream.getLocation().distanceSquared(collision.getLocationSecond()) > collisionDistanceSquared) { + newTasks.add(stream); + } else { + stream.cancel(); + } + } + tasks = newTasks; + } + } + public boolean isHiddenAbility() { return true; } @@ -736,10 +734,6 @@ public class FireCombo extends FireAbility implements ComboAbility { this.direction = direction; } - public static ArrayList getBlockableAbilities() { - return BLOCKABLE_ABILITIES; - } - public ArrayList getAffectedEntities() { return affectedEntities; } @@ -748,6 +742,10 @@ public class FireCombo extends FireAbility implements ComboAbility { return tasks; } + public void setTasks(ArrayList tasks) { + this.tasks = tasks; + } + public void setCooldown(long cooldown) { this.cooldown = cooldown; } @@ -755,65 +753,91 @@ public class FireCombo extends FireAbility implements ComboAbility { public void setLocation(Location location) { this.location = location; } - - public class FireKick extends FireCombo { - public FireKick(Player player, String name) { + // Combo subclasses need to be static to be reflectively called in ComboManager + public static class FireKick extends FireCombo { + + public FireKick(Player player) { super(player, "FireKick"); } - + @Override public String getName() { return "FireKick"; } - - } - - public class FireSpin extends FireCombo { - public FireSpin(Player player, String name) { + @Override + public boolean isCollidable() { + return true; + } + + @Override + public void handleCollision(Collision collision) { + handleCollisionFireStreams(collision); + } + + } + + public static class FireSpin extends FireCombo { + + public FireSpin(Player player) { super(player, "FireSpin"); } - + @Override public String getName() { return "FireSpin"; } - - } - - public class FireWheel extends FireCombo { - public FireWheel(Player player, String name) { + @Override + public boolean isCollidable() { + return true; + } + + @Override + public void handleCollision(Collision collision) { + handleCollisionFireStreams(collision); + } + + } + + public static class FireWheel extends FireCombo { + + public FireWheel(Player player) { super(player, "FireWheel"); } - + @Override public String getName() { return "FireWheel"; } - - } - - public class JetBlast extends FireCombo { - public JetBlast(Player player, String name) { + @Override + public boolean isCollidable() { + return true; + } + + } + + public static class JetBlast extends FireCombo { + + public JetBlast(Player player) { super(player, "JetBlast"); } - + @Override public String getName() { return "JetBlast"; } - - } - - public class JetBlaze extends FireCombo { - public JetBlaze(Player player, String name) { + } + + public static class JetBlaze extends FireCombo { + + public JetBlaze(Player player) { super(player, "JetBlaze"); } - + @Override public String getName() { return "JetBlaze"; diff --git a/src/com/projectkorra/projectkorra/firebending/FireShield.java b/src/com/projectkorra/projectkorra/firebending/FireShield.java index c92c0df9..6b2018f2 100644 --- a/src/com/projectkorra/projectkorra/firebending/FireShield.java +++ b/src/com/projectkorra/projectkorra/firebending/FireShield.java @@ -1,10 +1,7 @@ package com.projectkorra.projectkorra.firebending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.FireAbility; -import com.projectkorra.projectkorra.earthbending.EarthBlast; -import com.projectkorra.projectkorra.util.ParticleEffect; -import com.projectkorra.projectkorra.waterbending.WaterManipulation; +import java.util.ArrayList; +import java.util.Random; import org.bukkit.Effect; import org.bukkit.Location; @@ -16,11 +13,13 @@ import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.Random; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.FireAbility; +import com.projectkorra.projectkorra.ability.util.Collision; +import com.projectkorra.projectkorra.util.ParticleEffect; public class FireShield extends FireAbility { - + private boolean shield; private boolean ignite; private long time; @@ -30,6 +29,7 @@ public class FireShield extends FireAbility { private double radius; private double discRadius; private double fireTicks; + private Location location; private Random random; public FireShield(Player player) { @@ -38,7 +38,7 @@ public class FireShield extends FireAbility { public FireShield(Player player, boolean shield) { super(player); - + this.shield = shield; this.ignite = true; this.interval = getConfig().getLong("Abilities.Fire.FireShield.Interval"); @@ -48,7 +48,7 @@ public class FireShield extends FireAbility { this.discRadius = getConfig().getDouble("Abilities.Fire.FireShield.DiscRadius"); this.fireTicks = getConfig().getDouble("Abilities.Fire.FireShield.FireTicks"); this.random = new Random(); - + if (hasAbility(player, FireShield.class) || bPlayer.isOnCooldown("FireShield")) { return; } else if (!player.getEyeLocation().getBlock().isLiquid()) { @@ -60,6 +60,11 @@ public class FireShield extends FireAbility { } } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean isWithinShield(Location loc) { for (FireShield fshield : getAbilities(FireShield.class)) { Location playerLoc = fshield.player.getLocation(); @@ -74,7 +79,8 @@ public class FireShield extends FireAbility { Location tempLoc = playerLoc.clone().add(playerLoc.multiply(fshield.discRadius)); if (!tempLoc.getWorld().equals(loc.getWorld())) { return false; - } else if (tempLoc.getWorld().equals(loc.getWorld()) && tempLoc.distance(loc) <= fshield.discRadius * fshield.discRadius) { + } else if (tempLoc.getWorld().equals(loc.getWorld()) + && tempLoc.distance(loc) <= fshield.discRadius * fshield.discRadius) { return true; } } @@ -90,7 +96,7 @@ public class FireShield extends FireAbility { } else if (!player.isSneaking() && shield) { remove(); return; - } else if (System.currentTimeMillis() > startTime + duration && !shield) { + } else if (System.currentTimeMillis() > getStartTime() + duration && !shield) { remove(); return; } @@ -100,15 +106,15 @@ public class FireShield extends FireAbility { if (shield) { ArrayList blocks = new ArrayList<>(); - Location location = player.getEyeLocation().clone(); + location = player.getEyeLocation().clone(); for (double theta = 0; theta < 180; theta += 20) { for (double phi = 0; phi < 360; phi += 20) { double rphi = Math.toRadians(phi); double rtheta = Math.toRadians(theta); - - Block block = location .clone() .add(radius * Math.cos(rphi) * Math.sin(rtheta), radius * Math.cos(rtheta), - radius * Math.sin(rphi) * Math.sin(rtheta)).getBlock(); + + Block block = location.clone().add(radius * Math.cos(rphi) * Math.sin(rtheta), radius * Math.cos(rtheta), + radius * Math.sin(rphi) * Math.sin(rtheta)).getBlock(); if (!blocks.contains(block) && !GeneralMethods.isSolid(block) && !block.isLiquid()) { blocks.add(block); } @@ -142,13 +148,9 @@ public class FireShield extends FireAbility { new FireDamageTimer(entity, player); } } - - FireBlast.removeFireBlastsAroundPoint(location, radius + 1); - BlazeArc.removeAroundPoint(location, radius + 1); - Combustion.removeAroundPoint(location, radius + 1); } else { ArrayList blocks = new ArrayList<>(); - Location location = player.getEyeLocation().clone(); + location = player.getEyeLocation().clone(); Vector direction = location.getDirection(); location = location.clone().add(direction.multiply(radius)); @@ -184,11 +186,6 @@ public class FireShield extends FireAbility { } } - FireBlast.removeFireBlastsAroundPoint(location, discRadius); - WaterManipulation.removeAroundPoint(location, discRadius); - EarthBlast.removeAroundPoint(location, discRadius); - BlazeArc.removeAroundPoint(location, discRadius); - Combustion.removeAroundPoint(location, discRadius); for (Entity entity : GeneralMethods.getEntitiesAroundPoint(location, discRadius)) { if (entity instanceof Projectile) { entity.remove(); @@ -205,14 +202,14 @@ public class FireShield extends FireAbility { @Override public Location getLocation() { - return player != null ? player.getLocation() : null; + return location; } @Override public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -222,6 +219,11 @@ public class FireShield extends FireAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public double getCollisionRadius() { + return shield ? radius : discRadius; + } public boolean isShield() { return shield; @@ -290,5 +292,5 @@ public class FireShield extends FireAbility { public void setCooldown(long cooldown) { this.cooldown = cooldown; } - + } diff --git a/src/com/projectkorra/projectkorra/firebending/Lightning.java b/src/com/projectkorra/projectkorra/firebending/Lightning.java index 4412ae6d..dcdf3154 100644 --- a/src/com/projectkorra/projectkorra/firebending/Lightning.java +++ b/src/com/projectkorra/projectkorra/firebending/Lightning.java @@ -1,10 +1,7 @@ package com.projectkorra.projectkorra.firebending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ProjectKorra; -import com.projectkorra.projectkorra.ability.LightningAbility; -import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.util.DamageHandler; +import java.util.ArrayList; +import java.util.List; import org.bukkit.Location; import org.bukkit.Sound; @@ -15,7 +12,11 @@ import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; -import java.util.ArrayList; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ProjectKorra; +import com.projectkorra.projectkorra.ability.LightningAbility; +import com.projectkorra.projectkorra.avatar.AvatarState; +import com.projectkorra.projectkorra.util.DamageHandler; public class Lightning extends LightningAbility { @@ -52,6 +53,7 @@ public class Lightning extends LightningAbility { private ArrayList affectedEntities; private ArrayList arcs; private ArrayList tasks; + private ArrayList locations; public Lightning(Player player) { super(player); @@ -73,6 +75,7 @@ public class Lightning extends LightningAbility { this.affectedEntities = new ArrayList<>(); this.arcs = new ArrayList<>(); this.tasks = new ArrayList<>(); + this.locations = new ArrayList<>(); this.selfHitWater = getConfig().getBoolean("Abilities.Fire.Lightning.SelfHitWater"); this.selfHitClose = getConfig().getBoolean("Abilities.Fire.Lightning.SelfHitClose"); @@ -191,6 +194,8 @@ public class Lightning extends LightningAbility { return; } + locations.clear(); + if (state == State.START) { if (bPlayer.isOnCooldown(this)) { remove(); @@ -504,6 +509,11 @@ public class Lightning extends LightningAbility { return; } Block block = location.getBlock(); + // We only want to consider this particle as part of the location + // on the its first tick, when it actually does the electrocution. + // The later ticks are just for visual purposes. + locations.add(block.getLocation()); + // Handle Water electrocution if (!hitWater && (isWater(block) || (arcOnIce && isIce(block)))) { hitWater = true; @@ -636,6 +646,16 @@ public class Lightning extends LightningAbility { return false; } + @Override + public boolean isCollidable() { + return arcs.size() > 0; + } + + @Override + public List getLocations() { + return locations; + } + public boolean isCharged() { return charged; } diff --git a/src/com/projectkorra/projectkorra/firebending/WallOfFire.java b/src/com/projectkorra/projectkorra/firebending/WallOfFire.java index 3a3f0e6f..95ff386d 100644 --- a/src/com/projectkorra/projectkorra/firebending/WallOfFire.java +++ b/src/com/projectkorra/projectkorra/firebending/WallOfFire.java @@ -173,22 +173,22 @@ public class WallOfFire extends FireAbility { public void progress() { time = System.currentTimeMillis(); - if (time - startTime > cooldown) { + if (time - getStartTime() > cooldown) { remove(); return; } else if (!active) { return; - } else if (time - startTime > duration) { + } else if (time - getStartTime() > duration) { active = false; return; } - if (time - startTime > intervalTick * interval) { + if (time - getStartTime() > intervalTick * interval) { intervalTick++; display(); } - if (time - startTime > damageTick * damageInterval) { + if (time - getStartTime() > damageTick * damageInterval) { damageTick++; damage(); } @@ -218,6 +218,15 @@ public class WallOfFire extends FireAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (Block block : blocks) { + locations.add(block.getLocation()); + } + return locations; + } public boolean isActive() { return active; diff --git a/src/com/projectkorra/projectkorra/waterbending/Bloodbending.java b/src/com/projectkorra/projectkorra/waterbending/Bloodbending.java index ddf39f29..d70fb42f 100644 --- a/src/com/projectkorra/projectkorra/waterbending/Bloodbending.java +++ b/src/com/projectkorra/projectkorra/waterbending/Bloodbending.java @@ -283,7 +283,7 @@ public class Bloodbending extends BloodAbility { @Override public void remove() { if (!bPlayer.isAvatarState() && target != null) { - if (System.currentTimeMillis() < this.startTime + 1200) { + if (System.currentTimeMillis() < getStartTime() + 1200) { bPlayer.addCooldown(this); //Prevents spamming } } @@ -311,6 +311,9 @@ public class Bloodbending extends BloodAbility { @Override public Location getLocation() { + if (target != null) { + return target.getLocation(); + } return player != null ? player.getLocation() : null; } @@ -328,6 +331,16 @@ public class Bloodbending extends BloodAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public List getLocations() { + // for collision purposes we only care about the player's location + ArrayList locations = new ArrayList<>(); + if (player != null) { + locations.add(player.getLocation()); + } + return locations; + } public boolean isCanOnlyBeUsedAtNight() { return canOnlyBeUsedAtNight; diff --git a/src/com/projectkorra/projectkorra/waterbending/HealingWaters.java b/src/com/projectkorra/projectkorra/waterbending/HealingWaters.java index fbc053d2..b21a29a2 100644 --- a/src/com/projectkorra/projectkorra/waterbending/HealingWaters.java +++ b/src/com/projectkorra/projectkorra/waterbending/HealingWaters.java @@ -105,7 +105,7 @@ public class HealingWaters extends HealingAbility { } // If ability is is charged, set charged = true. If not, play charging particles. - if (System.currentTimeMillis() >= startTime + chargeTime) { + if (System.currentTimeMillis() >= getStartTime() + chargeTime) { if (!charged) { this.charged = true; WaterReturn.emptyWaterBottle(player); diff --git a/src/com/projectkorra/projectkorra/waterbending/IceBlast.java b/src/com/projectkorra/projectkorra/waterbending/IceBlast.java index 5960bd02..8a9f14c2 100644 --- a/src/com/projectkorra/projectkorra/waterbending/IceBlast.java +++ b/src/com/projectkorra/projectkorra/waterbending/IceBlast.java @@ -338,6 +338,16 @@ public class IceBlast extends IceAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public boolean isCollidable() { + return progressing; + } + + @Override + public double getCollisionRadius() { + return collisionRadius; + } public boolean isPrepared() { return prepared; @@ -403,10 +413,6 @@ public class IceBlast extends IceAbility { this.damage = damage; } - public double getCollisionRadius() { - return collisionRadius; - } - public void setCollisionRadius(double collisionRadius) { this.collisionRadius = collisionRadius; } diff --git a/src/com/projectkorra/projectkorra/waterbending/IceSpikeBlast.java b/src/com/projectkorra/projectkorra/waterbending/IceSpikeBlast.java index c68084e0..968650c0 100644 --- a/src/com/projectkorra/projectkorra/waterbending/IceSpikeBlast.java +++ b/src/com/projectkorra/projectkorra/waterbending/IceSpikeBlast.java @@ -45,11 +45,11 @@ public class IceSpikeBlast extends IceAbility { public IceSpikeBlast(Player player) { super(player); - + if (bPlayer.isOnCooldown("IceSpikeBlast")) { return; } - + this.data = 0; this.interval = getConfig().getLong("Abilities.Water.IceSpike.Blast.Interval"); this.slowCooldown = getConfig().getLong("Abilities.Water.IceSpike.Blast.SlowCooldown"); @@ -60,12 +60,12 @@ public class IceSpikeBlast extends IceAbility { this.cooldown = getConfig().getLong("Abilities.Water.IceSpike.Blast.Cooldown"); this.slowPower = getConfig().getInt("Abilities.Water.IceSpike.Blast.SlowPower"); this.slowDuration = getConfig().getInt("Abilities.Water.IceSpike.Blast.SlowDuration"); - + if (!bPlayer.canBend(this) || !bPlayer.canIcebend()) { return; } - block(player); + block(player); this.range = getNightFactor(range); this.damage = getNightFactor(damage); this.slowPower = (int) getNightFactor(slowPower); @@ -109,7 +109,7 @@ public class IceSpikeBlast extends IceAbility { iceSpike.remove(); } } - + sourceBlock = block; location = sourceBlock.getLocation(); prepared = true; @@ -232,7 +232,7 @@ public class IceSpikeBlast extends IceAbility { if (!prepared) { return; } - + LivingEntity target = (LivingEntity) GeneralMethods.getTargetedEntity(player, range); if (target == null) { destination = GeneralMethods.getTargetedLocation(player, range, getTransparentMaterial()); @@ -247,14 +247,14 @@ public class IceSpikeBlast extends IceAbility { if (destination.distanceSquared(location) < 1) { return; } - + firstDestination = location.clone(); if (destination.getY() - location.getY() > 2) { firstDestination.setY(destination.getY() - 1); } else { firstDestination.add(0, 2, 0); } - + destination = GeneralMethods.getPointOnLine(firstDestination, destination, range); progressing = true; settingUp = true; @@ -265,22 +265,21 @@ public class IceSpikeBlast extends IceAbility { sourceBlock.setType(Material.AIR); } - } public static void activate(Player player) { redirect(player); boolean activate = false; BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player); - + if (bPlayer == null) { return; } - + if (bPlayer.isOnCooldown("IceSpikeBlast")) { return; } - + for (IceSpikeBlast ice : getAbilities(player, IceSpikeBlast.class)) { if (ice.prepared) { ice.throwIce(); @@ -288,7 +287,7 @@ public class IceSpikeBlast extends IceAbility { activate = true; } } - + if (!activate && !getPlayers(IceSpikeBlast.class).contains(player)) { IceSpikePillar spike = new IceSpikePillar(player); if (!spike.isStarted()) { @@ -305,16 +304,15 @@ public class IceSpikeBlast extends IceAbility { continue; } else if (!iceSpike.progressing) { continue; - } if (GeneralMethods.isRegionProtectedFromBuild(iceSpike, iceSpike.location)) { + } + if (GeneralMethods.isRegionProtectedFromBuild(iceSpike, iceSpike.location)) { continue; } Location location = player.getEyeLocation(); Vector vector = location.getDirection(); Location mloc = iceSpike.location; - if (mloc.distanceSquared(location) <= iceSpike.range * iceSpike.range - && GeneralMethods.getDistanceFromLine(vector, location, iceSpike.location) < iceSpike.deflectRange - && mloc.distanceSquared(location.clone().add(vector)) < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) { + if (mloc.distanceSquared(location) <= iceSpike.range * iceSpike.range && GeneralMethods.getDistanceFromLine(vector, location, iceSpike.location) < iceSpike.deflectRange && mloc.distanceSquared(location.clone().add(vector)) < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) { iceSpike.remove(); } } @@ -343,12 +341,10 @@ public class IceSpikeBlast extends IceAbility { Location location = player.getEyeLocation(); Vector vector = location.getDirection(); Location mloc = iceSpike.location; - + if (GeneralMethods.isRegionProtectedFromBuild(iceSpike, mloc)) { continue; - } else if (mloc.distanceSquared(location) <= iceSpike.range * iceSpike.range - && GeneralMethods.getDistanceFromLine(vector, location, iceSpike.location) < iceSpike.deflectRange - && mloc.distanceSquared(location.clone().add(vector)) < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) { + } else if (mloc.distanceSquared(location) <= iceSpike.range * iceSpike.range && GeneralMethods.getDistanceFromLine(vector, location, iceSpike.location) < iceSpike.deflectRange && mloc.distanceSquared(location.clone().add(vector)) < mloc.distanceSquared(location.clone().add(vector.clone().multiply(-1)))) { Location loc; Entity target = GeneralMethods.getTargetedEntity(player, iceSpike.range); if (target == null) { @@ -366,15 +362,15 @@ public class IceSpikeBlast extends IceAbility { @SuppressWarnings("deprecation") private static void waterBottle(Player player) { long range = getConfig().getLong("Abilities.Water.IceSpike.Projectile.Range"); - + if (WaterReturn.hasWaterBottle(player)) { Location eyeLoc = player.getEyeLocation(); Block block = eyeLoc.add(eyeLoc.getDirection().normalize()).getBlock(); - + if (isTransparent(player, block) && isTransparent(player, eyeLoc.getBlock())) { LivingEntity target = (LivingEntity) GeneralMethods.getTargetedEntity(player, range); Location destination; - + if (target == null) { destination = GeneralMethods.getTargetedLocation(player, range, getTransparentMaterial()); } else { @@ -387,17 +383,17 @@ public class IceSpikeBlast extends IceAbility { MaterialData data = block.getState().getData(); block.setType(Material.WATER); - block.setData((byte)0); + block.setData((byte) 0); IceSpikeBlast iceSpike = new IceSpikeBlast(player); iceSpike.throwIce(); iceSpike.sourceBlock = null; if (iceSpike.progressing) { WaterReturn.emptyWaterBottle(player); - } + } block.setType(data.getItemType()); block.setData(data.getData()); - + } } } @@ -421,7 +417,7 @@ public class IceSpikeBlast extends IceAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isSneakAbility() { return true; @@ -432,6 +428,16 @@ public class IceSpikeBlast extends IceAbility { return false; } + @Override + public boolean isCollidable() { + return progressing; + } + + @Override + public double getCollisionRadius() { + return collisionRadius; + } + public boolean isPrepared() { return prepared; } @@ -520,10 +526,6 @@ public class IceSpikeBlast extends IceAbility { this.damage = damage; } - public double getCollisionRadius() { - return collisionRadius; - } - public void setCollisionRadius(double collisionRadius) { this.collisionRadius = collisionRadius; } @@ -575,5 +577,5 @@ public class IceSpikeBlast extends IceAbility { public void setLocation(Location location) { this.location = location; } - + } diff --git a/src/com/projectkorra/projectkorra/waterbending/OctopusForm.java b/src/com/projectkorra/projectkorra/waterbending/OctopusForm.java index 8e48d019..e6f9ffd2 100644 --- a/src/com/projectkorra/projectkorra/waterbending/OctopusForm.java +++ b/src/com/projectkorra/projectkorra/waterbending/OctopusForm.java @@ -475,6 +475,11 @@ public class OctopusForm extends WaterAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public double getCollisionRadius() { + return getRadius(); + } public boolean isSourceSelected() { return sourceSelected; diff --git a/src/com/projectkorra/projectkorra/waterbending/PlantArmor.java b/src/com/projectkorra/projectkorra/waterbending/PlantArmor.java index f3dfa534..c7208549 100644 --- a/src/com/projectkorra/projectkorra/waterbending/PlantArmor.java +++ b/src/com/projectkorra/projectkorra/waterbending/PlantArmor.java @@ -23,6 +23,7 @@ public class PlantArmor extends PlantAbility { private int resistance; private long duration; private long cooldown; + private long tickTime; private double range; private Material blockType; private Block block; @@ -39,6 +40,7 @@ public class PlantArmor extends PlantAbility { this.range = getNightFactor(range); this.duration = (long) getNightFactor(duration); + this.tickTime = System.currentTimeMillis(); if (hasAbility(player, PlantArmor.class)) { return; @@ -97,7 +99,7 @@ public class PlantArmor extends PlantAbility { new TempArmor(player, this, new ItemStack[] {boots, leggings, chestplate, helmet}); formed = true; - startTime = System.currentTimeMillis(); + tickTime = System.currentTimeMillis(); } private boolean inPosition() { @@ -125,7 +127,7 @@ public class PlantArmor extends PlantAbility { if (formed) { PassiveHandler.checkArmorPassives(player); - if (System.currentTimeMillis() > startTime + duration) { + if (System.currentTimeMillis() > tickTime + duration) { remove(); bPlayer.addCooldown(this); return; @@ -166,7 +168,7 @@ public class PlantArmor extends PlantAbility { public static boolean canRemoveArmor(Player player) { PlantArmor plantArmor = getAbility(player, PlantArmor.class); if (plantArmor != null) { - if (System.currentTimeMillis() < plantArmor.startTime + plantArmor.duration) { + if (System.currentTimeMillis() < plantArmor.tickTime + plantArmor.duration) { return false; } } @@ -188,10 +190,8 @@ public class PlantArmor extends PlantAbility { @Override public Location getLocation() { - if (location != null) { + if (!formed) { return location; - } else if (block != null) { - return block.getLocation(); } return player != null ? player.getLocation() : null; } diff --git a/src/com/projectkorra/projectkorra/waterbending/SurgeWall.java b/src/com/projectkorra/projectkorra/waterbending/SurgeWall.java index dec17863..dfe42bb0 100644 --- a/src/com/projectkorra/projectkorra/waterbending/SurgeWall.java +++ b/src/com/projectkorra/projectkorra/waterbending/SurgeWall.java @@ -1,5 +1,19 @@ package com.projectkorra.projectkorra.waterbending; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; + +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.WaterAbility; @@ -9,19 +23,6 @@ import com.projectkorra.projectkorra.util.BlockSource; import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.TempBlock; -import org.bukkit.Effect; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.util.Vector; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; - public class SurgeWall extends WaterAbility { private static final byte FULL = 0x0; @@ -42,6 +43,7 @@ public class SurgeWall extends WaterAbility { private Location location; private Location firstDestination; private Location targetDestination; + private ArrayList locations; private Vector firstDirection; private Vector targetDirection; @@ -53,6 +55,7 @@ public class SurgeWall extends WaterAbility { this.cooldown = getConfig().getLong("Abilities.Water.Surge.Wall.Cooldown"); this.range = getConfig().getDouble(RANGE_CONFIG); this.radius = getConfig().getDouble("Abilities.Water.Surge.Wall.Radius"); + this.locations = new ArrayList<>(); SurgeWave wave = getAbility(player, SurgeWave.class); if (wave != null && !wave.isProgressing()) { @@ -214,7 +217,8 @@ public class SurgeWall extends WaterAbility { remove(); return; } - + locations.clear(); + if (System.currentTimeMillis() - time >= interval) { time = System.currentTimeMillis(); boolean matchesName = bPlayer.getBoundAbilityName().equalsIgnoreCase(getName()); @@ -258,6 +262,7 @@ public class SurgeWall extends WaterAbility { WALL_BLOCKS.put(block, player); addWallBlock(block); blocks.add(block); + locations.add(block.getLocation()); FireBlast.removeFireBlastsAroundPoint(block.getLocation(), 2); } } @@ -483,6 +488,11 @@ public class SurgeWall extends WaterAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public List getLocations() { + return locations; + } public boolean isProgressing() { return progressing; diff --git a/src/com/projectkorra/projectkorra/waterbending/SurgeWave.java b/src/com/projectkorra/projectkorra/waterbending/SurgeWave.java index 6004738b..b4931c5b 100644 --- a/src/com/projectkorra/projectkorra/waterbending/SurgeWave.java +++ b/src/com/projectkorra/projectkorra/waterbending/SurgeWave.java @@ -1,13 +1,10 @@ package com.projectkorra.projectkorra.waterbending; -import com.projectkorra.projectkorra.GeneralMethods; -import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.WaterAbility; -import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.firebending.FireBlast; -import com.projectkorra.projectkorra.util.BlockSource; -import com.projectkorra.projectkorra.util.ClickType; -import com.projectkorra.projectkorra.util.TempBlock; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Effect; import org.bukkit.Location; @@ -18,10 +15,14 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; +import com.projectkorra.projectkorra.GeneralMethods; +import com.projectkorra.projectkorra.ability.AirAbility; +import com.projectkorra.projectkorra.ability.WaterAbility; +import com.projectkorra.projectkorra.avatar.AvatarState; +import com.projectkorra.projectkorra.firebending.FireBlast; +import com.projectkorra.projectkorra.util.BlockSource; +import com.projectkorra.projectkorra.util.ClickType; +import com.projectkorra.projectkorra.util.TempBlock; public class SurgeWave extends WaterAbility { @@ -439,6 +440,23 @@ public class SurgeWave extends WaterAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public boolean isCollidable() { + return progressing || activateFreeze; + } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (Block block : waveBlocks.keySet()) { + locations.add(block.getLocation()); + } + for (Block block : frozenBlocks.keySet()) { + locations.add(block.getLocation()); + } + return locations; + } public boolean isFreezing() { return freezing; diff --git a/src/com/projectkorra/projectkorra/waterbending/Torrent.java b/src/com/projectkorra/projectkorra/waterbending/Torrent.java index 935a6a87..bb753126 100644 --- a/src/com/projectkorra/projectkorra/waterbending/Torrent.java +++ b/src/com/projectkorra/projectkorra/waterbending/Torrent.java @@ -655,6 +655,23 @@ public class Torrent extends WaterAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public boolean isCollidable() { + return forming || formed || launch || launching; + } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (TempBlock tblock : blocks) { + locations.add(tblock.getLocation()); + } + for (TempBlock tblock : launchedBlocks) { + locations.add(tblock.getLocation()); + } + return locations; + } public boolean isSourceSelected() { return sourceSelected; diff --git a/src/com/projectkorra/projectkorra/waterbending/TorrentWave.java b/src/com/projectkorra/projectkorra/waterbending/TorrentWave.java index 58c199db..9e3c34ae 100644 --- a/src/com/projectkorra/projectkorra/waterbending/TorrentWave.java +++ b/src/com/projectkorra/projectkorra/waterbending/TorrentWave.java @@ -12,6 +12,7 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; @@ -216,6 +217,15 @@ public class TorrentWave extends WaterAbility { return false; } + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (TempBlock tblock : blocks) { + locations.add(tblock.getLocation()); + } + return locations; + } + public long getTime() { return time; } diff --git a/src/com/projectkorra/projectkorra/waterbending/WaterCombo.java b/src/com/projectkorra/projectkorra/waterbending/WaterCombo.java index 9d0a54db..2db8490c 100644 --- a/src/com/projectkorra/projectkorra/waterbending/WaterCombo.java +++ b/src/com/projectkorra/projectkorra/waterbending/WaterCombo.java @@ -1,7 +1,9 @@ package com.projectkorra.projectkorra.waterbending; import java.util.ArrayList; +import java.util.Collection; import java.util.Enumeration; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -17,10 +19,11 @@ import org.bukkit.util.Vector; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ProjectKorra; import com.projectkorra.projectkorra.ability.ComboAbility; +import com.projectkorra.projectkorra.ability.CoreAbility; import com.projectkorra.projectkorra.ability.IceAbility; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.ability.util.ComboManager.AbilityInformation; import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.firebending.FireCombo; import com.projectkorra.projectkorra.firebending.FireCombo.FireComboStream; import com.projectkorra.projectkorra.util.BlockSource; import com.projectkorra.projectkorra.util.ClickType; @@ -29,9 +32,9 @@ import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; /* - * TODO: Combo classes should eventually be rewritten so that each combo is treated - * as an individual ability. In the mean time, we will just place "fake" - * classes so that CoreAbility will register each ability. + * TODO: Combo classes should eventually be rewritten so that each combo is + * treated as an individual ability. In the mean time, we will just place "fake" + * classes so that CoreAbility will register each ability. */ public class WaterCombo extends IceAbility implements ComboAbility { @@ -76,12 +79,11 @@ public class WaterCombo extends IceAbility implements ComboAbility { } if (name.equalsIgnoreCase("IceWave")) { - if (bPlayer.isOnCooldown("IceWave") && !bPlayer.isAvatarState()) { remove(); return; } - + this.cooldown = getConfig().getLong("Abilities.Water.WaterCombo.IceWave.Cooldown"); } else if (name.equalsIgnoreCase("IceBullet")) { this.damage = getConfig().getDouble("Abilities.Water.WaterCombo.IceBullet.Damage"); @@ -93,7 +95,7 @@ public class WaterCombo extends IceAbility implements ComboAbility { this.animationSpeed = getConfig().getDouble("Abilities.Water.WaterCombo.IceBullet.AnimationSpeed"); this.speed = 1; } - + double aug = getNightFactor(player.getWorld()); if (aug > 1) { aug = 1 + (aug - 1) / 3; @@ -115,7 +117,7 @@ public class WaterCombo extends IceAbility implements ComboAbility { } if (name.equalsIgnoreCase("IceBulletLeftClick") || name.equalsIgnoreCase("IceBulletRightClick")) { - ArrayList bullets = getWaterCombo(player, "IceBullet"); + Collection bullets = CoreAbility.getAbilities(player, IceBullet.class); if (bullets.size() == 0) { return; } @@ -130,7 +132,7 @@ public class WaterCombo extends IceAbility implements ComboAbility { } return; } - + start(); } @@ -149,13 +151,13 @@ public class WaterCombo extends IceAbility implements ComboAbility { public void drawWaterCircle(Location loc, double theta, double increment, double radius, Material mat, byte data) { double rotateSpeed = theta; direction = GeneralMethods.rotateXZ(direction, rotateSpeed); - + for (double i = 0; i < theta; i += increment) { Vector dir = GeneralMethods.rotateXZ(direction, i - theta / 2).normalize().multiply(radius); dir.setY(0); Block block = loc.clone().add(dir).getBlock(); location = block.getLocation(); - + if (block.getType() == Material.AIR && !GeneralMethods.isRegionProtectedFromBuild(player, "WaterManipulation", block.getLocation())) { createBlock(block, mat, data); } @@ -169,7 +171,7 @@ public class WaterCombo extends IceAbility implements ComboAbility { i--; } } - + for (int i = 0; i < tasks.size(); i++) { FireComboStream fstream = (FireComboStream) tasks.get(i); Location loc = fstream.getLocation(); @@ -197,10 +199,6 @@ public class WaterCombo extends IceAbility implements ComboAbility { } } } - - if (GeneralMethods.blockAbilities(player, FireCombo.getBlockableAbilities(), loc, 1)) { - fstream.remove(); - } } } } @@ -214,7 +212,7 @@ public class WaterCombo extends IceAbility implements ComboAbility { if (origin == null && WaterSpoutWave.containsType(player, WaterSpoutWave.AbilityType.RELEASE)) { bPlayer.addCooldown("IceWave", cooldown); origin = player.getLocation(); - + WaterSpoutWave wave = WaterSpoutWave.getType(player, WaterSpoutWave.AbilityType.RELEASE).get(0); wave.setIceWave(true); } else if (!WaterSpoutWave.containsType(player, WaterSpoutWave.AbilityType.RELEASE)) { @@ -226,19 +224,19 @@ public class WaterCombo extends IceAbility implements ComboAbility { remove(); return; } - + if (origin == null) { if (bPlayer.isOnCooldown("IceBullet") && !bPlayer.isAvatarState()) { remove(); return; } - + Block waterBlock = BlockSource.getWaterSourceBlock(player, range, ClickType.LEFT_CLICK, true, true, bPlayer.canPlantbend()); if (waterBlock == null) { remove(); return; } - + time = 0; origin = waterBlock.getLocation(); location = origin.clone(); @@ -253,7 +251,7 @@ public class WaterCombo extends IceAbility implements ComboAbility { if (this.time == 0) { this.time = System.currentTimeMillis(); } - + long timeDiff = System.currentTimeMillis() - this.time; if (this.state == AbilityState.ICE_BULLET_FORMING) { if (timeDiff < 1000 * animationSpeed) { @@ -277,7 +275,7 @@ public class WaterCombo extends IceAbility implements ComboAbility { Vector vec = player.getEyeLocation().getDirection().normalize(); Location loc = player.getEyeLocation().add(vec.clone().multiply(radius + 1.3)); FireComboStream fs = new FireComboStream(null, vec, loc, range, speed, "IceBullet"); - + fs.setDensity(10); fs.setSpread(0.1F); fs.setUseNewParticles(true); @@ -308,9 +306,9 @@ public class WaterCombo extends IceAbility implements ComboAbility { if (waterGrabber != null) { waterGrabber.remove(); } - + bPlayer.addCooldown(this); - + if (name == "IceWave") { bPlayer.addCooldown("WaterWave", getConfig().getLong("Abilities.Water.WaterSpout.Wave.Cooldown")); } @@ -363,12 +361,12 @@ public class WaterCombo extends IceAbility implements ComboAbility { public long getCooldown() { return cooldown; } - + @Override public boolean isHiddenAbility() { return true; } - + @Override public boolean isSneakAbility() { return true; @@ -378,7 +376,13 @@ public class WaterCombo extends IceAbility implements ComboAbility { public boolean isHarmlessAbility() { return false; } - + + @Override + public boolean isCollidable() { + // Override in subclasses + return false; + } + @Override public String getInstructions() { return null; @@ -526,6 +530,10 @@ public class WaterCombo extends IceAbility implements ComboAbility { return tasks; } + public void setTasks(ArrayList tasks) { + this.tasks = tasks; + } + public static Map getFrozenBlocks() { return FROZEN_BLOCKS; } @@ -545,31 +553,99 @@ public class WaterCombo extends IceAbility implements ComboAbility { public void setLocation(Location location) { this.location = location; } - - public class IceWave extends WaterCombo { - public IceWave(Player player, String name) { + // Combo subclasses need to be static to be reflectively called in ComboManager + public static class IceWave extends WaterCombo { + + public IceWave(Player player) { super(player, "IceWave"); } - + @Override public String getName() { return "IceWave"; } - - } - - public class IceBullet extends WaterCombo { - public IceBullet(Player player, String name) { + } + + public static class IceBullet extends WaterCombo { + + public IceBullet(Player player) { super(player, "IceBullet"); } - + @Override public String getName() { return "IceBullet"; } - + + @Override + public boolean isCollidable() { + return true; + } + + @Override + public void handleCollision(Collision collision) { + if (collision.isRemovingFirst()) { + ArrayList newTasks = new ArrayList<>(); + double collisionDistanceSquared = Math.pow(getCollisionRadius() + collision.getAbilitySecond().getCollisionRadius(), 2); + // Remove all of the streams that are by this specific ourLocation. + // Don't just do a single stream at a time or this algorithm becomes O(n^2) with + // Collision's detection algorithm. + for (BukkitRunnable task : getTasks()) { + if (task instanceof FireComboStream) { + FireComboStream stream = (FireComboStream) task; + if (stream.getLocation().distanceSquared(collision.getLocationSecond()) > collisionDistanceSquared) { + newTasks.add(stream); + } else { + stream.cancel(); + } + } else { + newTasks.add(task); + } + } + setTasks(newTasks); + } + } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + for (BukkitRunnable task : getTasks()) { + if (task instanceof FireComboStream) { + FireComboStream stream = (FireComboStream) task; + locations.add(stream.getLocation()); + } + } + return locations; + } + } - -} \ No newline at end of file + + public static class IceBulletLeftClick extends WaterCombo { + + public IceBulletLeftClick(Player player) { + super(player, "IceBulletLeftClick"); + } + + @Override + public String getName() { + return "IceBullet"; + } + + } + + public static class IceBulletRightClick extends WaterCombo { + + public IceBulletRightClick(Player player) { + super(player, "IceBulletRightClick"); + } + + @Override + public String getName() { + return "IceBullet"; + } + + } + +} diff --git a/src/com/projectkorra/projectkorra/waterbending/WaterManipulation.java b/src/com/projectkorra/projectkorra/waterbending/WaterManipulation.java index 2f4872c8..7c78df81 100644 --- a/src/com/projectkorra/projectkorra/waterbending/WaterManipulation.java +++ b/src/com/projectkorra/projectkorra/waterbending/WaterManipulation.java @@ -18,12 +18,9 @@ import org.bukkit.util.Vector; import com.projectkorra.projectkorra.BendingPlayer; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.AirAbility; -import com.projectkorra.projectkorra.ability.EarthAbility; import com.projectkorra.projectkorra.ability.WaterAbility; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.avatar.AvatarState; -import com.projectkorra.projectkorra.earthbending.EarthBlast; -import com.projectkorra.projectkorra.firebending.Combustion; -import com.projectkorra.projectkorra.firebending.FireBlast; import com.projectkorra.projectkorra.util.BlockSource; import com.projectkorra.projectkorra.util.ClickType; import com.projectkorra.projectkorra.util.DamageHandler; @@ -230,27 +227,9 @@ public class WaterManipulation extends WaterAbility { } } } else { - WaterAbility.removeWaterSpouts(location, player); - AirAbility.removeAirSpouts(location, player); - EarthAbility.removeSandSpouts(location, player); - if ((new Random()).nextInt(4) == 0) { playWaterbendingSound(location); } - - double radius = collisionRadius; - Player source = player; - if (!(location == null)) { - if (EarthBlast.annihilateBlasts(location, radius, source) - || WaterManipulation.annihilateBlasts(location, radius, source) - || FireBlast.annihilateBlasts(location, radius, source)) { - remove(); - new WaterReturn(player, sourceBlock); - return; - } - Combustion.removeAroundPoint(location, radius); - } - location = location.clone().add(direction); block = location.getBlock(); if (block.getLocation().equals(sourceBlock.getLocation())) { @@ -386,6 +365,11 @@ public class WaterManipulation extends WaterAbility { } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean annihilateBlasts(Location location, double radius, Player player) { boolean broke = false; for (WaterManipulation manip : getAbilities(WaterManipulation.class)) { @@ -596,6 +580,24 @@ public class WaterManipulation extends WaterAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public boolean isCollidable() { + return progressing; + } + + @Override + public double getCollisionRadius() { + return collisionRadius; + } + + @Override + public void handleCollision(Collision collision) { + super.handleCollision(collision); + if (collision.isRemovingFirst()) { + new WaterReturn(player, sourceBlock); + } + } public boolean isProgressing() { return progressing; @@ -781,10 +783,6 @@ public class WaterManipulation extends WaterAbility { this.location = location; } - public double getCollisionRadius() { - return collisionRadius; - } - public void setCollisionRadius(double collisionRadius) { this.collisionRadius = collisionRadius; } diff --git a/src/com/projectkorra/projectkorra/waterbending/WaterSpout.java b/src/com/projectkorra/projectkorra/waterbending/WaterSpout.java index b3318a5f..ef485c7f 100644 --- a/src/com/projectkorra/projectkorra/waterbending/WaterSpout.java +++ b/src/com/projectkorra/projectkorra/waterbending/WaterSpout.java @@ -14,6 +14,7 @@ import org.bukkit.potion.PotionEffectType; import com.projectkorra.projectkorra.GeneralMethods; import com.projectkorra.projectkorra.ability.WaterAbility; +import com.projectkorra.projectkorra.ability.util.Collision; import com.projectkorra.projectkorra.util.Flight; import com.projectkorra.projectkorra.util.ParticleEffect; import com.projectkorra.projectkorra.util.TempBlock; @@ -289,6 +290,11 @@ public class WaterSpout extends WaterAbility { return -1; } + /** + * This method was used for the old collision detection system. Please see + * {@link Collision} for the new system. + */ + @Deprecated public static boolean removeSpouts(Location loc0, double radius, Player sourcePlayer) { boolean removed = false; for (WaterSpout spout : getAbilities(WaterSpout.class)) { @@ -332,6 +338,24 @@ public class WaterSpout extends WaterAbility { public boolean isHarmlessAbility() { return true; } + + @Override + public boolean isCollidable() { + return true; + } + + @Override + public List getLocations() { + ArrayList locations = new ArrayList<>(); + Location top = this.getLocation(); + Location iterLoc = getBase().getLocation(); + double ySpacing = 2; + while (iterLoc.getY() <= top.getY()) { + locations.add(iterLoc.clone()); + iterLoc.add(0, ySpacing, 0); + } + return locations; + } public boolean isCanBendOnPackedIce() { return canBendOnPackedIce; @@ -416,5 +440,5 @@ public class WaterSpout extends WaterAbility { public static Map getAffectedBlocks() { return AFFECTED_BLOCKS; } - + } \ No newline at end of file diff --git a/src/com/projectkorra/projectkorra/waterbending/WaterSpoutWave.java b/src/com/projectkorra/projectkorra/waterbending/WaterSpoutWave.java index af7698c2..c19e50c3 100644 --- a/src/com/projectkorra/projectkorra/waterbending/WaterSpoutWave.java +++ b/src/com/projectkorra/projectkorra/waterbending/WaterSpoutWave.java @@ -42,6 +42,7 @@ public class WaterSpoutWave extends WaterAbility { private boolean iceOnly; private boolean moving; private boolean plant; + private boolean collidable; private int progressCounter; private long time; private long cooldown; @@ -68,6 +69,7 @@ public class WaterSpoutWave extends WaterAbility { this.charging = false; this.iceWave = false; this.iceOnly = false; + this.collidable = false; this.plant = getConfig().getBoolean("Abilities.Water.WaterSpout.Wave.AllowPlantSource"); this.radius = getConfig().getDouble("Abilities.Water.WaterSpout.Wave.Radius"); this.waveRadius = getConfig().getDouble("Abilities.Water.WaterSpout.Wave.WaveRadius"); @@ -241,6 +243,7 @@ public class WaterSpoutWave extends WaterAbility { } } else { moving = true; + collidable = true; if ((System.currentTimeMillis() - time > flightTime && !bPlayer.isAvatarState()) || player.isSneaking()) { remove(); return; @@ -473,6 +476,16 @@ public class WaterSpoutWave extends WaterAbility { public boolean isHarmlessAbility() { return false; } + + @Override + public boolean isCollidable() { + return collidable; + } + + @Override + public double getCollisionRadius() { + return getRadius(); + } public double getRadius() { return radius;